Page MenuHomeSealhub

No OneTemporary

This file is larger than 256 KB, so syntax highlighting was skipped.
diff --git a/common_lib/response/collection-response.test.js b/common_lib/response/collection-response.test.ts
similarity index 72%
rename from common_lib/response/collection-response.test.js
rename to common_lib/response/collection-response.test.ts
index 4390e0b6..e8b1e5d5 100644
--- a/common_lib/response/collection-response.test.js
+++ b/common_lib/response/collection-response.test.ts
@@ -1,24 +1,24 @@
-const assert = require("assert");
-const { with_running_app } = require("../../test_utils/with-test-app.js");
+import assert from "assert";
+import { withRunningApp } from "../../test_utils/with-test-app";
describe("request multiple ids", () => {
it("returns proper length and empty status for empty response", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
const response = new app.Sealious.Responses.CollectionResponse({
items: [],
});
assert.equal(response.length, 0);
assert.equal(response.empty, true);
}));
it("returns proper length and empty status for nonempty response", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
const response = new app.Sealious.Responses.CollectionResponse({
items: [{}, {}],
});
assert.equal(response.length, 2);
assert.equal(response.empty, false);
}));
});
diff --git a/package-lock.json b/package-lock.json
index 19a65b85..89b6ca77 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,8404 +1,8399 @@
{
"name": "sealious",
"version": "0.10.11",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@3846masa/axios-cookiejar-support": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/@3846masa/axios-cookiejar-support/-/axios-cookiejar-support-0.1.4.tgz",
"integrity": "sha1-3vD02CFIYUCeJxiMuGvoRgsXle4=",
"requires": {
"@types/tough-cookie": "^2.3.1",
"pify": "3.0.0",
"tough-cookie": "2.3.3"
},
"dependencies": {
"pify": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
"integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
},
"tough-cookie": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
"integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
"requires": {
"punycode": "^1.4.1"
}
}
}
},
"@babel/cli": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/@babel/cli/-/cli-7.1.2.tgz",
"integrity": "sha512-K3WDlpBPGpoW11SLKFEBhMsITomPovsrZ/wnM3y+WStbytukDXC0OBic3yQp+j058QUw0+R/jfx2obwp1fOzcA==",
"dev": true,
"requires": {
"chokidar": "^2.0.3",
"commander": "^2.8.1",
"convert-source-map": "^1.1.0",
"fs-readdir-recursive": "^1.1.0",
"glob": "^7.0.0",
"lodash": "^4.17.10",
"mkdirp": "^0.5.1",
"output-file-sync": "^2.0.0",
"slash": "^2.0.0",
"source-map": "^0.5.0"
},
"dependencies": {
"anymatch": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
"integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
"dev": true,
"optional": true,
"requires": {
"micromatch": "^3.1.4",
"normalize-path": "^2.1.1"
}
},
"arr-diff": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
"integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
"dev": true,
"optional": true
},
"array-unique": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
"dev": true,
"optional": true
},
"braces": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
"integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
"dev": true,
"optional": true,
"requires": {
"arr-flatten": "^1.1.0",
"array-unique": "^0.3.2",
"extend-shallow": "^2.0.1",
"fill-range": "^4.0.0",
"isobject": "^3.0.1",
"repeat-element": "^1.1.2",
"snapdragon": "^0.8.1",
"snapdragon-node": "^2.0.1",
"split-string": "^3.0.2",
"to-regex": "^3.0.1"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"chokidar": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz",
"integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==",
"dev": true,
"optional": true,
"requires": {
"anymatch": "^2.0.0",
"async-each": "^1.0.0",
"braces": "^2.3.0",
"fsevents": "^1.2.2",
"glob-parent": "^3.1.0",
"inherits": "^2.0.1",
"is-binary-path": "^1.0.0",
"is-glob": "^4.0.0",
"lodash.debounce": "^4.0.8",
"normalize-path": "^2.1.1",
"path-is-absolute": "^1.0.0",
"readdirp": "^2.0.0",
"upath": "^1.0.5"
}
},
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"optional": true,
"requires": {
"ms": "2.0.0"
}
},
"expand-brackets": {
"version": "2.1.4",
"resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
"integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
"dev": true,
"optional": true,
"requires": {
"debug": "^2.3.3",
"define-property": "^0.2.5",
"extend-shallow": "^2.0.1",
"posix-character-classes": "^0.1.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.1"
},
"dependencies": {
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
"dev": true,
"optional": true,
"requires": {
"is-descriptor": "^0.1.0"
}
},
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"is-accessor-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
"integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2"
},
"dependencies": {
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
"optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
}
}
},
"is-data-descriptor": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
"integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2"
},
"dependencies": {
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
"optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
}
}
},
"is-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
"dev": true,
"optional": true,
"requires": {
"is-accessor-descriptor": "^0.1.6",
"is-data-descriptor": "^0.1.4",
"kind-of": "^5.0.0"
}
},
"kind-of": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
"integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
"dev": true,
"optional": true
}
}
},
"extglob": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
"integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
"dev": true,
"optional": true,
"requires": {
"array-unique": "^0.3.2",
"define-property": "^1.0.0",
"expand-brackets": "^2.1.4",
"extend-shallow": "^2.0.1",
"fragment-cache": "^0.2.1",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.1"
},
"dependencies": {
"define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
"integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
"dev": true,
"optional": true,
"requires": {
"is-descriptor": "^1.0.0"
}
},
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"fill-range": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
"integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
"dev": true,
"optional": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-number": "^3.0.0",
"repeat-string": "^1.6.1",
"to-regex-range": "^2.1.0"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"glob-parent": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
"integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
"dev": true,
"optional": true,
"requires": {
"is-glob": "^3.1.0",
"path-dirname": "^1.0.0"
},
"dependencies": {
"is-glob": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
"integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
"dev": true,
"optional": true,
"requires": {
"is-extglob": "^2.1.0"
}
}
}
},
"is-accessor-descriptor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
"integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^6.0.0"
}
},
"is-data-descriptor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
"integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^6.0.0"
}
},
"is-descriptor": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
"integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
"dev": true,
"optional": true,
"requires": {
"is-accessor-descriptor": "^1.0.0",
"is-data-descriptor": "^1.0.0",
"kind-of": "^6.0.2"
}
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
"dev": true,
"optional": true
},
"is-glob": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz",
"integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=",
"dev": true,
"optional": true,
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2"
},
"dependencies": {
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
"optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
}
}
},
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
},
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"dev": true,
"optional": true
},
"micromatch": {
"version": "3.1.10",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
"integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
"dev": true,
"optional": true,
"requires": {
"arr-diff": "^4.0.0",
"array-unique": "^0.3.2",
"braces": "^2.3.1",
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"extglob": "^2.0.4",
"fragment-cache": "^0.2.1",
"kind-of": "^6.0.2",
"nanomatch": "^1.2.9",
"object.pick": "^1.3.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.2"
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
"dev": true
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"dev": true,
"requires": {
"minimist": "^1.2.5"
}
},
"output-file-sync": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/output-file-sync/-/output-file-sync-2.0.1.tgz",
"integrity": "sha512-mDho4qm7WgIXIGf4eYU1RHN2UU5tPfVYVSRwDJw0uTmj35DQUt/eNp19N7v6T3SrR0ESTEf2up2CGO73qI35zQ==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.11",
"is-plain-obj": "^1.1.0",
"mkdirp": "^0.5.1"
}
},
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
"integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==",
"dev": true
}
}
},
"@babel/code-frame": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
"integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
"dev": true,
"requires": {
"@babel/highlight": "^7.0.0"
}
},
"@babel/core": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.1.2.tgz",
"integrity": "sha512-IFeSSnjXdhDaoysIlev//UzHZbdEmm7D0EIH2qtse9xK7mXEZQpYjs2P00XlP1qYsYvid79p+Zgg6tz1mp6iVw==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"@babel/generator": "^7.1.2",
"@babel/helpers": "^7.1.2",
"@babel/parser": "^7.1.2",
"@babel/template": "^7.1.2",
"@babel/traverse": "^7.1.0",
"@babel/types": "^7.1.2",
"convert-source-map": "^1.1.0",
"debug": "^3.1.0",
"json5": "^0.5.0",
"lodash": "^4.17.10",
"resolve": "^1.3.2",
"semver": "^5.4.1",
"source-map": "^0.5.0"
}
},
"@babel/generator": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.1.3.tgz",
"integrity": "sha512-ZoCZGcfIJFJuZBqxcY9OjC1KW2lWK64qrX1o4UYL3yshVhwKFYgzpWZ0vvtGMNJdTlvkw0W+HR1VnYN8q3QPFQ==",
"dev": true,
"requires": {
"@babel/types": "^7.1.3",
"jsesc": "^2.5.1",
"lodash": "^4.17.10",
"source-map": "^0.5.0",
"trim-right": "^1.0.1"
},
"dependencies": {
"jsesc": {
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.1.tgz",
"integrity": "sha1-5CGiqOINawgZ3yiQj3glJrlt0f4=",
"dev": true
}
}
},
"@babel/helper-annotate-as-pure": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz",
"integrity": "sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==",
"dev": true,
"requires": {
"@babel/types": "^7.0.0"
}
},
"@babel/helper-builder-binary-assignment-operator-visitor": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz",
"integrity": "sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==",
"dev": true,
"requires": {
"@babel/helper-explode-assignable-expression": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"@babel/helper-builder-react-jsx": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-builder-react-jsx/-/helper-builder-react-jsx-7.0.0.tgz",
"integrity": "sha512-ebJ2JM6NAKW0fQEqN8hOLxK84RbRz9OkUhGS/Xd5u56ejMfVbayJ4+LykERZCOUM6faa6Fp3SZNX3fcT16MKHw==",
"dev": true,
"requires": {
"@babel/types": "^7.0.0",
"esutils": "^2.0.0"
}
},
"@babel/helper-call-delegate": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-call-delegate/-/helper-call-delegate-7.1.0.tgz",
"integrity": "sha512-YEtYZrw3GUK6emQHKthltKNZwszBcHK58Ygcis+gVUrF4/FmTVr5CCqQNSfmvg2y+YDEANyYoaLz/SHsnusCwQ==",
"dev": true,
"requires": {
"@babel/helper-hoist-variables": "^7.0.0",
"@babel/traverse": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"@babel/helper-define-map": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.1.0.tgz",
"integrity": "sha512-yPPcW8dc3gZLN+U1mhYV91QU3n5uTbx7DUdf8NnPbjS0RMwBuHi9Xt2MUgppmNz7CJxTBWsGczTiEp1CSOTPRg==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.1.0",
"@babel/types": "^7.0.0",
"lodash": "^4.17.10"
}
},
"@babel/helper-explode-assignable-expression": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz",
"integrity": "sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==",
"dev": true,
"requires": {
"@babel/traverse": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"@babel/helper-function-name": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz",
"integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==",
"dev": true,
"requires": {
"@babel/helper-get-function-arity": "^7.0.0",
"@babel/template": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"@babel/helper-get-function-arity": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz",
"integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==",
"dev": true,
"requires": {
"@babel/types": "^7.0.0"
}
},
"@babel/helper-hoist-variables": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0.tgz",
"integrity": "sha512-Ggv5sldXUeSKsuzLkddtyhyHe2YantsxWKNi7A+7LeD12ExRDWTRk29JCXpaHPAbMaIPZSil7n+lq78WY2VY7w==",
"dev": true,
"requires": {
"@babel/types": "^7.0.0"
}
},
"@babel/helper-member-expression-to-functions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz",
"integrity": "sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==",
"dev": true,
"requires": {
"@babel/types": "^7.0.0"
}
},
"@babel/helper-module-imports": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz",
"integrity": "sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==",
"dev": true,
"requires": {
"@babel/types": "^7.0.0"
}
},
"@babel/helper-module-transforms": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.1.0.tgz",
"integrity": "sha512-0JZRd2yhawo79Rcm4w0LwSMILFmFXjugG3yqf+P/UsKsRS1mJCmMwwlHDlMg7Avr9LrvSpp4ZSULO9r8jpCzcw==",
"dev": true,
"requires": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/helper-simple-access": "^7.1.0",
"@babel/helper-split-export-declaration": "^7.0.0",
"@babel/template": "^7.1.0",
"@babel/types": "^7.0.0",
"lodash": "^4.17.10"
}
},
"@babel/helper-optimise-call-expression": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz",
"integrity": "sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==",
"dev": true,
"requires": {
"@babel/types": "^7.0.0"
}
},
"@babel/helper-plugin-utils": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz",
"integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==",
"dev": true
},
"@babel/helper-regex": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.0.0.tgz",
"integrity": "sha512-TR0/N0NDCcUIUEbqV6dCO+LptmmSQFQ7q70lfcEB4URsjD0E1HzicrwUH+ap6BAQ2jhCX9Q4UqZy4wilujWlkg==",
"dev": true,
"requires": {
"lodash": "^4.17.10"
}
},
"@babel/helper-remap-async-to-generator": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz",
"integrity": "sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.0.0",
"@babel/helper-wrap-function": "^7.1.0",
"@babel/template": "^7.1.0",
"@babel/traverse": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"@babel/helper-replace-supers": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.1.0.tgz",
"integrity": "sha512-BvcDWYZRWVuDeXTYZWxekQNO5D4kO55aArwZOTFXw6rlLQA8ZaDicJR1sO47h+HrnCiDFiww0fSPV0d713KBGQ==",
"dev": true,
"requires": {
"@babel/helper-member-expression-to-functions": "^7.0.0",
"@babel/helper-optimise-call-expression": "^7.0.0",
"@babel/traverse": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"@babel/helper-simple-access": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz",
"integrity": "sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==",
"dev": true,
"requires": {
"@babel/template": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"@babel/helper-split-export-declaration": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0.tgz",
"integrity": "sha512-MXkOJqva62dfC0w85mEf/LucPPS/1+04nmmRMPEBUB++hiiThQ2zPtX/mEWQ3mtzCEjIJvPY8nuwxXtQeQwUag==",
"dev": true,
"requires": {
"@babel/types": "^7.0.0"
}
},
"@babel/helper-wrap-function": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.1.0.tgz",
"integrity": "sha512-R6HU3dete+rwsdAfrOzTlE9Mcpk4RjU3aX3gi9grtmugQY0u79X7eogUvfXA5sI81Mfq1cn6AgxihfN33STjJA==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.1.0",
"@babel/template": "^7.1.0",
"@babel/traverse": "^7.1.0",
"@babel/types": "^7.0.0"
}
},
"@babel/helpers": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.1.2.tgz",
"integrity": "sha512-Myc3pUE8eswD73aWcartxB16K6CGmHDv9KxOmD2CeOs/FaEAQodr3VYGmlvOmog60vNQ2w8QbatuahepZwrHiA==",
"dev": true,
"requires": {
"@babel/template": "^7.1.2",
"@babel/traverse": "^7.1.0",
"@babel/types": "^7.1.2"
}
},
"@babel/highlight": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
"integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
"dev": true,
"requires": {
"chalk": "^2.0.0",
"esutils": "^2.0.2",
"js-tokens": "^4.0.0"
},
"dependencies": {
"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==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"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
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"@babel/parser": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.1.3.tgz",
"integrity": "sha512-gqmspPZOMW3MIRb9HlrnbZHXI1/KHTOroBwN1NcLL6pWxzqzEKGvRTq0W/PxS45OtQGbaFikSQpkS5zbnsQm2w==",
"dev": true
},
"@babel/plugin-proposal-async-generator-functions": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.1.0.tgz",
"integrity": "sha512-Fq803F3Jcxo20MXUSDdmZZXrPe6BWyGcWBPPNB/M7WaUYESKDeKMOGIxEzQOjGSmW/NWb6UaPZrtTB2ekhB/ew==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-remap-async-to-generator": "^7.1.0",
"@babel/plugin-syntax-async-generators": "^7.0.0"
}
},
"@babel/plugin-proposal-json-strings": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.0.0.tgz",
"integrity": "sha512-kfVdUkIAGJIVmHmtS/40i/fg/AGnw/rsZBCaapY5yjeO5RA9m165Xbw9KMOu2nqXP5dTFjEjHdfNdoVcHv133Q==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-json-strings": "^7.0.0"
}
},
"@babel/plugin-proposal-object-rest-spread": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0.tgz",
"integrity": "sha512-14fhfoPcNu7itSen7Py1iGN0gEm87hX/B+8nZPqkdmANyyYWYMY2pjA3r8WXbWVKMzfnSNS0xY8GVS0IjXi/iw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-object-rest-spread": "^7.0.0"
}
},
"@babel/plugin-proposal-optional-catch-binding": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0.tgz",
"integrity": "sha512-JPqAvLG1s13B/AuoBjdBYvn38RqW6n1TzrQO839/sIpqLpbnXKacsAgpZHzLD83Sm8SDXMkkrAvEnJ25+0yIpw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-optional-catch-binding": "^7.0.0"
}
},
"@babel/plugin-proposal-unicode-property-regex": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0.tgz",
"integrity": "sha512-tM3icA6GhC3ch2SkmSxv7J/hCWKISzwycub6eGsDrFDgukD4dZ/I+x81XgW0YslS6mzNuQ1Cbzh5osjIMgepPQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-regex": "^7.0.0",
"regexpu-core": "^4.2.0"
},
"dependencies": {
"jsesc": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
"dev": true
},
"regexpu-core": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz",
"integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==",
"dev": true,
"requires": {
"regenerate": "^1.4.0",
"regenerate-unicode-properties": "^7.0.0",
"regjsgen": "^0.4.0",
"regjsparser": "^0.3.0",
"unicode-match-property-ecmascript": "^1.0.4",
"unicode-match-property-value-ecmascript": "^1.0.2"
}
},
"regjsgen": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz",
"integrity": "sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA==",
"dev": true
},
"regjsparser": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz",
"integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==",
"dev": true,
"requires": {
"jsesc": "~0.5.0"
}
}
}
},
"@babel/plugin-syntax-async-generators": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0.tgz",
"integrity": "sha512-im7ged00ddGKAjcZgewXmp1vxSZQQywuQXe2B1A7kajjZmDeY/ekMPmWr9zJgveSaQH0k7BcGrojQhcK06l0zA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-syntax-json-strings": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.0.0.tgz",
"integrity": "sha512-UlSfNydC+XLj4bw7ijpldc1uZ/HB84vw+U6BTuqMdIEmz/LDe63w/GHtpQMdXWdqQZFeAI9PjnHe/vDhwirhKA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-syntax-jsx": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.0.0.tgz",
"integrity": "sha512-PdmL2AoPsCLWxhIr3kG2+F9v4WH06Q3z+NoGVpQgnUNGcagXHq5sB3OXxkSahKq9TLdNMN/AJzFYSOo8UKDMHg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-syntax-object-rest-spread": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0.tgz",
"integrity": "sha512-5A0n4p6bIiVe5OvQPxBnesezsgFJdHhSs3uFSvaPdMqtsovajLZ+G2vZyvNe10EzJBWWo3AcHGKhAFUxqwp2dw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-syntax-optional-catch-binding": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0.tgz",
"integrity": "sha512-Wc+HVvwjcq5qBg1w5RG9o9RVzmCaAg/Vp0erHCKpAYV8La6I94o4GQAmFYNmkzoMO6gzoOSulpKeSSz6mPEoZw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-arrow-functions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0.tgz",
"integrity": "sha512-2EZDBl1WIO/q4DIkIp4s86sdp4ZifL51MoIviLY/gG/mLSuOIEg7J8o6mhbxOTvUJkaN50n+8u41FVsr5KLy/w==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-async-to-generator": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.1.0.tgz",
"integrity": "sha512-rNmcmoQ78IrvNCIt/R9U+cixUHeYAzgusTFgIAv+wQb9HJU4szhpDD6e5GCACmj/JP5KxuCwM96bX3L9v4ZN/g==",
"dev": true,
"requires": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-remap-async-to-generator": "^7.1.0"
}
},
"@babel/plugin-transform-block-scoped-functions": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0.tgz",
"integrity": "sha512-AOBiyUp7vYTqz2Jibe1UaAWL0Hl9JUXEgjFvvvcSc9MVDItv46ViXFw2F7SVt1B5k+KWjl44eeXOAk3UDEaJjQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-block-scoping": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0.tgz",
"integrity": "sha512-GWEMCrmHQcYWISilUrk9GDqH4enf3UmhOEbNbNrlNAX1ssH3MsS1xLOS6rdjRVPgA7XXVPn87tRkdTEoA/dxEg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"lodash": "^4.17.10"
}
},
"@babel/plugin-transform-classes": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.1.0.tgz",
"integrity": "sha512-rNaqoD+4OCBZjM7VaskladgqnZ1LO6o2UxuWSDzljzW21pN1KXkB7BstAVweZdxQkHAujps5QMNOTWesBciKFg==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.0.0",
"@babel/helper-define-map": "^7.1.0",
"@babel/helper-function-name": "^7.1.0",
"@babel/helper-optimise-call-expression": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-replace-supers": "^7.1.0",
"@babel/helper-split-export-declaration": "^7.0.0",
"globals": "^11.1.0"
},
"dependencies": {
"globals": {
"version": "11.8.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz",
"integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==",
"dev": true
}
}
},
"@babel/plugin-transform-computed-properties": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0.tgz",
"integrity": "sha512-ubouZdChNAv4AAWAgU7QKbB93NU5sHwInEWfp+/OzJKA02E6Woh9RVoX4sZrbRwtybky/d7baTUqwFx+HgbvMA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-destructuring": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.1.3.tgz",
"integrity": "sha512-Mb9M4DGIOspH1ExHOUnn2UUXFOyVTiX84fXCd+6B5iWrQg/QMeeRmSwpZ9lnjYLSXtZwiw80ytVMr3zue0ucYw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-dotall-regex": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0.tgz",
"integrity": "sha512-00THs8eJxOJUFVx1w8i1MBF4XH4PsAjKjQ1eqN/uCH3YKwP21GCKfrn6YZFZswbOk9+0cw1zGQPHVc1KBlSxig==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-regex": "^7.0.0",
"regexpu-core": "^4.1.3"
},
"dependencies": {
"jsesc": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
"dev": true
},
"regexpu-core": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz",
"integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==",
"dev": true,
"requires": {
"regenerate": "^1.4.0",
"regenerate-unicode-properties": "^7.0.0",
"regjsgen": "^0.4.0",
"regjsparser": "^0.3.0",
"unicode-match-property-ecmascript": "^1.0.4",
"unicode-match-property-value-ecmascript": "^1.0.2"
}
},
"regjsgen": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz",
"integrity": "sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA==",
"dev": true
},
"regjsparser": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz",
"integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==",
"dev": true,
"requires": {
"jsesc": "~0.5.0"
}
}
}
},
"@babel/plugin-transform-duplicate-keys": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0.tgz",
"integrity": "sha512-w2vfPkMqRkdxx+C71ATLJG30PpwtTpW7DDdLqYt2acXU7YjztzeWW2Jk1T6hKqCLYCcEA5UQM/+xTAm+QCSnuQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-exponentiation-operator": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.1.0.tgz",
"integrity": "sha512-uZt9kD1Pp/JubkukOGQml9tqAeI8NkE98oZnHZ2qHRElmeKCodbTZgOEUtujSCSLhHSBWbzNiFSDIMC4/RBTLQ==",
"dev": true,
"requires": {
"@babel/helper-builder-binary-assignment-operator-visitor": "^7.1.0",
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-for-of": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0.tgz",
"integrity": "sha512-TlxKecN20X2tt2UEr2LNE6aqA0oPeMT1Y3cgz8k4Dn1j5ObT8M3nl9aA37LLklx0PBZKETC9ZAf9n/6SujTuXA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-function-name": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.1.0.tgz",
"integrity": "sha512-VxOa1TMlFMtqPW2IDYZQaHsFrq/dDoIjgN098NowhexhZcz3UGlvPgZXuE1jEvNygyWyxRacqDpCZt+par1FNg==",
"dev": true,
"requires": {
"@babel/helper-function-name": "^7.1.0",
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-literals": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0.tgz",
"integrity": "sha512-1NTDBWkeNXgpUcyoVFxbr9hS57EpZYXpje92zv0SUzjdu3enaRwF/l3cmyRnXLtIdyJASyiS6PtybK+CgKf7jA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-modules-amd": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.1.0.tgz",
"integrity": "sha512-wt8P+xQ85rrnGNr2x1iV3DW32W8zrB6ctuBkYBbf5/ZzJY99Ob4MFgsZDFgczNU76iy9PWsy4EuxOliDjdKw6A==",
"dev": true,
"requires": {
"@babel/helper-module-transforms": "^7.1.0",
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-modules-commonjs": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.1.0.tgz",
"integrity": "sha512-wtNwtMjn1XGwM0AXPspQgvmE6msSJP15CX2RVfpTSTNPLhKhaOjaIfBaVfj4iUZ/VrFSodcFedwtPg/NxwQlPA==",
"dev": true,
"requires": {
"@babel/helper-module-transforms": "^7.1.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-simple-access": "^7.1.0"
}
},
"@babel/plugin-transform-modules-systemjs": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.1.3.tgz",
"integrity": "sha512-PvTxgjxQAq4pvVUZF3mD5gEtVDuId8NtWkJsZLEJZMZAW3TvgQl1pmydLLN1bM8huHFVVU43lf0uvjQj9FRkKw==",
"dev": true,
"requires": {
"@babel/helper-hoist-variables": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-modules-umd": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.1.0.tgz",
"integrity": "sha512-enrRtn5TfRhMmbRwm7F8qOj0qEYByqUvTttPEGimcBH4CJHphjyK1Vg7sdU7JjeEmgSpM890IT/efS2nMHwYig==",
"dev": true,
"requires": {
"@babel/helper-module-transforms": "^7.1.0",
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-new-target": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0.tgz",
"integrity": "sha512-yin069FYjah+LbqfGeTfzIBODex/e++Yfa0rH0fpfam9uTbuEeEOx5GLGr210ggOV77mVRNoeqSYqeuaqSzVSw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-object-super": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.1.0.tgz",
"integrity": "sha512-/O02Je1CRTSk2SSJaq0xjwQ8hG4zhZGNjE8psTsSNPXyLRCODv7/PBozqT5AmQMzp7MI3ndvMhGdqp9c96tTEw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-replace-supers": "^7.1.0"
}
},
"@babel/plugin-transform-parameters": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.1.0.tgz",
"integrity": "sha512-vHV7oxkEJ8IHxTfRr3hNGzV446GAb+0hgbA7o/0Jd76s+YzccdWuTU296FOCOl/xweU4t/Ya4g41yWz80RFCRw==",
"dev": true,
"requires": {
"@babel/helper-call-delegate": "^7.1.0",
"@babel/helper-get-function-arity": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-react-display-name": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-display-name/-/plugin-transform-react-display-name-7.0.0.tgz",
"integrity": "sha512-BX8xKuQTO0HzINxT6j/GiCwoJB0AOMs0HmLbEnAvcte8U8rSkNa/eSCAY+l1OA4JnCVq2jw2p6U8QQryy2fTPg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-react-jsx": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx/-/plugin-transform-react-jsx-7.0.0.tgz",
"integrity": "sha512-0TMP21hXsSUjIQJmu/r7RiVxeFrXRcMUigbKu0BLegJK9PkYodHstaszcig7zxXfaBji2LYUdtqIkHs+hgYkJQ==",
"dev": true,
"requires": {
"@babel/helper-builder-react-jsx": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.0.0"
}
},
"@babel/plugin-transform-react-jsx-self": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.0.0.tgz",
"integrity": "sha512-pymy+AK12WO4safW1HmBpwagUQRl9cevNX+82AIAtU1pIdugqcH+nuYP03Ja6B+N4gliAaKWAegIBL/ymALPHA==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.0.0"
}
},
"@babel/plugin-transform-react-jsx-source": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.0.0.tgz",
"integrity": "sha512-OSeEpFJEH5dw/TtxTg4nijl4nHBbhqbKL94Xo/Y17WKIf2qJWeIk/QeXACF19lG1vMezkxqruwnTjVizaW7u7w==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.0.0"
}
},
"@babel/plugin-transform-regenerator": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0.tgz",
"integrity": "sha512-sj2qzsEx8KDVv1QuJc/dEfilkg3RRPvPYx/VnKLtItVQRWt1Wqf5eVCOLZm29CiGFfYYsA3VPjfizTCV0S0Dlw==",
"dev": true,
"requires": {
"regenerator-transform": "^0.13.3"
},
"dependencies": {
"regenerator-transform": {
"version": "0.13.3",
"resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.13.3.tgz",
"integrity": "sha512-5ipTrZFSq5vU2YoGoww4uaRVAK4wyYC4TSICibbfEPOruUu8FFP7ErV0BjmbIOEpn3O/k9na9UEdYR/3m7N6uA==",
"dev": true,
"requires": {
"private": "^0.1.6"
}
}
}
},
"@babel/plugin-transform-shorthand-properties": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0.tgz",
"integrity": "sha512-g/99LI4vm5iOf5r1Gdxq5Xmu91zvjhEG5+yZDJW268AZELAu4J1EiFLnkSG3yuUsZyOipVOVUKoGPYwfsTymhw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-spread": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0.tgz",
"integrity": "sha512-L702YFy2EvirrR4shTj0g2xQp7aNwZoWNCkNu2mcoU0uyzMl0XRwDSwzB/xp6DSUFiBmEXuyAyEN16LsgVqGGQ==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-sticky-regex": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0.tgz",
"integrity": "sha512-LFUToxiyS/WD+XEWpkx/XJBrUXKewSZpzX68s+yEOtIbdnsRjpryDw9U06gYc6klYEij/+KQVRnD3nz3AoKmjw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-regex": "^7.0.0"
}
},
"@babel/plugin-transform-template-literals": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0.tgz",
"integrity": "sha512-vA6rkTCabRZu7Nbl9DfLZE1imj4tzdWcg5vtdQGvj+OH9itNNB6hxuRMHuIY8SGnEt1T9g5foqs9LnrHzsqEFg==",
"dev": true,
"requires": {
"@babel/helper-annotate-as-pure": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-typeof-symbol": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0.tgz",
"integrity": "sha512-1r1X5DO78WnaAIvs5uC48t41LLckxsYklJrZjNKcevyz83sF2l4RHbw29qrCPr/6ksFsdfRpT/ZgxNWHXRnffg==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0"
}
},
"@babel/plugin-transform-unicode-regex": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0.tgz",
"integrity": "sha512-uJBrJhBOEa3D033P95nPHu3nbFwFE9ZgXsfEitzoIXIwqAZWk7uXcg06yFKXz9FSxBH5ucgU/cYdX0IV8ldHKw==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/helper-regex": "^7.0.0",
"regexpu-core": "^4.1.3"
},
"dependencies": {
"jsesc": {
"version": "0.5.0",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
"integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
"dev": true
},
"regexpu-core": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.2.0.tgz",
"integrity": "sha512-Z835VSnJJ46CNBttalHD/dB+Sj2ezmY6Xp38npwU87peK6mqOzOpV8eYktdkLTEkzzD+JsTcxd84ozd8I14+rw==",
"dev": true,
"requires": {
"regenerate": "^1.4.0",
"regenerate-unicode-properties": "^7.0.0",
"regjsgen": "^0.4.0",
"regjsparser": "^0.3.0",
"unicode-match-property-ecmascript": "^1.0.4",
"unicode-match-property-value-ecmascript": "^1.0.2"
}
},
"regjsgen": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.4.0.tgz",
"integrity": "sha512-X51Lte1gCYUdlwhF28+2YMO0U6WeN0GLpgpA7LK7mbdDnkQYiwvEpmpe0F/cv5L14EbxgrdayAG3JETBv0dbXA==",
"dev": true
},
"regjsparser": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.3.0.tgz",
"integrity": "sha512-zza72oZBBHzt64G7DxdqrOo/30bhHkwMUoT0WqfGu98XLd7N+1tsy5MJ96Bk4MD0y74n629RhmrGW6XlnLLwCA==",
"dev": true,
"requires": {
"jsesc": "~0.5.0"
}
}
}
},
"@babel/polyfill": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.0.0.tgz",
"integrity": "sha512-dnrMRkyyr74CRelJwvgnnSUDh2ge2NCTyHVwpOdvRMHtJUyxLtMAfhBN3s64pY41zdw0kgiLPh6S20eb1NcX6Q==",
"requires": {
"core-js": "^2.5.7",
"regenerator-runtime": "^0.11.1"
},
"dependencies": {
"core-js": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
}
}
},
"@babel/preset-env": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.1.0.tgz",
"integrity": "sha512-ZLVSynfAoDHB/34A17/JCZbyrzbQj59QC1Anyueb4Bwjh373nVPq5/HMph0z+tCmcDjXDe+DlKQq9ywQuvWrQg==",
"dev": true,
"requires": {
"@babel/helper-module-imports": "^7.0.0",
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-proposal-async-generator-functions": "^7.1.0",
"@babel/plugin-proposal-json-strings": "^7.0.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
"@babel/plugin-proposal-optional-catch-binding": "^7.0.0",
"@babel/plugin-proposal-unicode-property-regex": "^7.0.0",
"@babel/plugin-syntax-async-generators": "^7.0.0",
"@babel/plugin-syntax-object-rest-spread": "^7.0.0",
"@babel/plugin-syntax-optional-catch-binding": "^7.0.0",
"@babel/plugin-transform-arrow-functions": "^7.0.0",
"@babel/plugin-transform-async-to-generator": "^7.1.0",
"@babel/plugin-transform-block-scoped-functions": "^7.0.0",
"@babel/plugin-transform-block-scoping": "^7.0.0",
"@babel/plugin-transform-classes": "^7.1.0",
"@babel/plugin-transform-computed-properties": "^7.0.0",
"@babel/plugin-transform-destructuring": "^7.0.0",
"@babel/plugin-transform-dotall-regex": "^7.0.0",
"@babel/plugin-transform-duplicate-keys": "^7.0.0",
"@babel/plugin-transform-exponentiation-operator": "^7.1.0",
"@babel/plugin-transform-for-of": "^7.0.0",
"@babel/plugin-transform-function-name": "^7.1.0",
"@babel/plugin-transform-literals": "^7.0.0",
"@babel/plugin-transform-modules-amd": "^7.1.0",
"@babel/plugin-transform-modules-commonjs": "^7.1.0",
"@babel/plugin-transform-modules-systemjs": "^7.0.0",
"@babel/plugin-transform-modules-umd": "^7.1.0",
"@babel/plugin-transform-new-target": "^7.0.0",
"@babel/plugin-transform-object-super": "^7.1.0",
"@babel/plugin-transform-parameters": "^7.1.0",
"@babel/plugin-transform-regenerator": "^7.0.0",
"@babel/plugin-transform-shorthand-properties": "^7.0.0",
"@babel/plugin-transform-spread": "^7.0.0",
"@babel/plugin-transform-sticky-regex": "^7.0.0",
"@babel/plugin-transform-template-literals": "^7.0.0",
"@babel/plugin-transform-typeof-symbol": "^7.0.0",
"@babel/plugin-transform-unicode-regex": "^7.0.0",
"browserslist": "^4.1.0",
"invariant": "^2.2.2",
"js-levenshtein": "^1.1.3",
"semver": "^5.3.0"
},
"dependencies": {
"browserslist": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.2.1.tgz",
"integrity": "sha512-1oO0c7Zhejwd+LXihS89WqtKionSbz298rJZKJgfrHIZhrV8AC15gw553VcB0lcEugja7IhWD7iAlrsamfYVPA==",
"dev": true,
"requires": {
"caniuse-lite": "^1.0.30000890",
"electron-to-chromium": "^1.3.79",
"node-releases": "^1.0.0-alpha.14"
}
},
"caniuse-lite": {
"version": "1.0.30000892",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000892.tgz",
"integrity": "sha512-X9rxMaWZNbJB5qjkDqPtNv/yfViTeUL6ILk0QJNxLV3OhKC5Acn5vxsuUvllR6B48mog8lmS+whwHq/QIYSL9w==",
"dev": true
},
"electron-to-chromium": {
"version": "1.3.79",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.79.tgz",
"integrity": "sha512-LQdY3j4PxuUl6xfxiFruTSlCniTrTrzAd8/HfsLEMi0PUpaQ0Iy+Pr4N4VllDYjs0Hyu2lkTbvzqlG+PX9NsNw==",
"dev": true
}
}
},
"@babel/preset-react": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@babel/preset-react/-/preset-react-7.0.0.tgz",
"integrity": "sha512-oayxyPS4Zj+hF6Et11BwuBkmpgT/zMxyuZgFrMeZID6Hdh3dGlk4sHCAhdBCpuCKW2ppBfl2uCCetlrUIJRY3w==",
"dev": true,
"requires": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/plugin-transform-react-display-name": "^7.0.0",
"@babel/plugin-transform-react-jsx": "^7.0.0",
"@babel/plugin-transform-react-jsx-self": "^7.0.0",
"@babel/plugin-transform-react-jsx-source": "^7.0.0"
}
},
"@babel/runtime": {
"version": "7.9.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.9.2.tgz",
"integrity": "sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==",
"requires": {
"regenerator-runtime": "^0.13.4"
},
"dependencies": {
"regenerator-runtime": {
"version": "0.13.5",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz",
"integrity": "sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA=="
}
}
},
"@babel/template": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.1.2.tgz",
"integrity": "sha512-SY1MmplssORfFiLDcOETrW7fCLl+PavlwMh92rrGcikQaRq4iWPVH0MpwPpY3etVMx6RnDjXtr6VZYr/IbP/Ag==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"@babel/parser": "^7.1.2",
"@babel/types": "^7.1.2"
}
},
"@babel/traverse": {
"version": "7.1.4",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.1.4.tgz",
"integrity": "sha512-my9mdrAIGdDiSVBuMjpn/oXYpva0/EZwWL3sm3Wcy/AVWO2eXnsoZruOT9jOGNRXU8KbCIu5zsKnXcAJ6PcV6Q==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"@babel/generator": "^7.1.3",
"@babel/helper-function-name": "^7.1.0",
"@babel/helper-split-export-declaration": "^7.0.0",
"@babel/parser": "^7.1.3",
"@babel/types": "^7.1.3",
"debug": "^3.1.0",
"globals": "^11.1.0",
"lodash": "^4.17.10"
},
"dependencies": {
"globals": {
"version": "11.8.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-11.8.0.tgz",
"integrity": "sha512-io6LkyPVuzCHBSQV9fmOwxZkUk6nIaGmxheLDgmuFv89j0fm2aqDbIXKAGfzCMHqz3HLF2Zf8WSG6VqMh2qFmA==",
"dev": true
}
}
},
"@babel/types": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.1.3.tgz",
"integrity": "sha512-RpPOVfK+yatXyn8n4PB1NW6k9qjinrXrRR8ugBN8fD6hCy5RXI6PSbVqpOJBO9oSaY7Nom4ohj35feb0UR9hSA==",
"dev": true,
"requires": {
"esutils": "^2.0.2",
"lodash": "^4.17.10",
"to-fast-properties": "^2.0.0"
},
"dependencies": {
"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
}
}
},
"@sinonjs/commons": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz",
"integrity": "sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q==",
"dev": true,
"requires": {
"type-detect": "4.0.8"
}
},
"@sinonjs/fake-timers": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz",
"integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.0"
}
},
"@sinonjs/formatio": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@sinonjs/formatio/-/formatio-5.0.1.tgz",
"integrity": "sha512-KaiQ5pBf1MpS09MuA0kp6KBQt2JUOQycqVG1NZXvzeaXe5LGFqAKueIS0bw4w0P9r7KuBSVdUk5QjXsUdu2CxQ==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1",
"@sinonjs/samsam": "^5.0.2"
}
},
"@sinonjs/samsam": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-5.0.3.tgz",
"integrity": "sha512-QucHkc2uMJ0pFGjJUDP3F9dq5dx8QIaqISl9QgwLOh6P9yv877uONPGXh/OH/0zmM3tW1JjuJltAZV2l7zU+uQ==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.6.0",
"lodash.get": "^4.4.2",
"type-detect": "^4.0.8"
}
},
"@sinonjs/text-encoding": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz",
"integrity": "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ==",
"dev": true
},
"@types/bluebird": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@types/bluebird/-/bluebird-3.5.30.tgz",
"integrity": "sha512-8LhzvcjIoqoi1TghEkRMkbbmM+jhHnBokPGkJWjclMK+Ks0MxEBow3/p2/iFTZ+OIbJHQDSfpgdZEb+af3gfVw=="
},
"@types/boom": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/@types/boom/-/boom-7.3.0.tgz",
"integrity": "sha512-PH7bfkt1nu4pnlxz+Ws+wwJJF1HE12W3ia+Iace2JT7q56DLH3hbyjOJyNHJYRxk3PkKaC36fHfHKyeG1rMgCA==",
"dev": true
},
"@types/bson": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/@types/bson/-/bson-4.0.2.tgz",
"integrity": "sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/clone": {
"version": "0.1.30",
"resolved": "https://registry.npmjs.org/@types/clone/-/clone-0.1.30.tgz",
"integrity": "sha1-5zZWSMG0ITalnH1QQGN7O1yDthQ="
},
"@types/color": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@types/color/-/color-3.0.1.tgz",
"integrity": "sha512-oeUWVaAwI+xINDUx+3F2vJkl/vVB03VChFF/Gl3iQCdbcakjuoJyMOba+3BXRtnBhxZ7uBYqQBi9EpLnvSoztA==",
"requires": {
"@types/color-convert": "*"
}
},
"@types/color-convert": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/@types/color-convert/-/color-convert-1.9.0.tgz",
"integrity": "sha512-OKGEfULrvSL2VRbkl/gnjjgbbF7ycIlpSsX7Nkab4MOWi5XxmgBYvuiQ7lcCFY5cPDz7MUNaKgxte2VRmtr4Fg==",
"requires": {
"@types/color-name": "*"
}
},
"@types/color-name": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz",
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ=="
},
"@types/escape-html": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/escape-html/-/escape-html-1.0.0.tgz",
"integrity": "sha512-Ehe6irbxo5BSYwG03buglLJCmy3JqqtC69UvopsBWYf4hDa+ZODJ7BuZU6y+YE4U6MaoSruTxM2+uePfAHts9Q==",
"dev": true
},
"@types/mime": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.2.tgz",
"integrity": "sha512-4kPlzbljFcsttWEq6aBW0OZe6BDajAmyvr2xknBG92tejQnvdGtT9+kXSZ580DqpxY9qG2xeQVF9Dq0ymUTo5Q==",
"dev": true
},
"@types/mjml": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@types/mjml/-/mjml-4.0.4.tgz",
"integrity": "sha512-4PhI6iZ1zGXZ9X9W0bbmI7mS2xdxITURueqSWJ/cTeS5+tbAtOUDG1ww/fPbfcffWwR4NeOjyNcZiczafH/yfw==",
"dev": true
},
"@types/mocha": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz",
"integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==",
"dev": true
},
"@types/mongodb": {
"version": "3.5.20",
"resolved": "https://registry.npmjs.org/@types/mongodb/-/mongodb-3.5.20.tgz",
"integrity": "sha512-BN0wJn670DkivxiP7ZW0InX4qBtX01qITaucD+3A+sTgPQo4XUYay0Y+sGM4MJ9OyKDRlb3RQuVAlyeWzl/NoA==",
"dev": true,
"requires": {
"@types/bson": "*",
"@types/node": "*"
}
},
"@types/node": {
"version": "13.13.4",
"resolved": "https://registry.npmjs.org/@types/node/-/node-13.13.4.tgz",
"integrity": "sha512-x26ur3dSXgv5AwKS0lNfbjpCakGIduWU1DU91Zz58ONRWrIKGunmZBNv4P7N+e27sJkiGDsw/3fT4AtsqQBrBA=="
},
"@types/nodemailer": {
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-6.4.0.tgz",
"integrity": "sha512-KY7bFWB0MahRZvVW4CuW83qcCDny59pJJ0MQ5ifvfcjNwPlIT0vW4uARO4u1gtkYnWdhSvURegecY/tzcukJcA==",
"dev": true,
"requires": {
"@types/node": "*"
}
},
"@types/object-hash": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/@types/object-hash/-/object-hash-1.3.3.tgz",
"integrity": "sha512-75t+H8u2IU1zJPPqezkGLP4YxDlj8tx7H9SgYOT1G61NjJUUEELu1Lp7RKQKXhW+FL8nV7XyD/cNFAtrKGViYQ=="
},
"@types/semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ=="
},
"@types/sharp": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@types/sharp/-/sharp-0.25.0.tgz",
"integrity": "sha512-JIWCJN0OfHRjkiKyI0BXbym1ip+9KsZJgBsnwNVrJPzm400oO64WxHbyYQ3I5xAqkIrTw1KIqqBME57aOS6n6w==",
"requires": {
"@types/node": "*"
}
},
"@types/shortid": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/shortid/-/shortid-0.0.29.tgz",
"integrity": "sha1-gJPuBBam4r8qpjOBCRFLP7/6Dps=",
"dev": true
},
"@types/sinon": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-9.0.4.tgz",
"integrity": "sha512-sJmb32asJZY6Z2u09bl0G2wglSxDlROlAejCjsnor+LzBMz17gu8IU7vKC/vWDnv9zEq2wqADHVXFjf4eE8Gdw==",
"dev": true,
"requires": {
"@types/sinonjs__fake-timers": "*"
}
},
"@types/sinonjs__fake-timers": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-6.0.1.tgz",
"integrity": "sha512-yYezQwGWty8ziyYLdZjwxyMb0CZR49h8JALHGrxjQHWlqGgc8kLdHEgWrgL0uZ29DMvEVBDnHU2Wg36zKSIUtA==",
"dev": true
},
"@types/tough-cookie": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-2.3.2.tgz",
"integrity": "sha512-vOVmaruQG5EatOU/jM6yU2uCp3Lz6mK1P5Ztu4iJjfM4SVHU9XYktPUQtKlIXuahqXHdEyUarMrBEwg5Cwu+bA=="
},
"abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"acorn": {
"version": "5.7.4",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz",
"integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==",
"dev": true
},
"acorn-jsx": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
"integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
"dev": true,
"requires": {
"acorn": "^3.0.4"
},
"dependencies": {
"acorn": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
"integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
"dev": true
}
}
},
"ajv": {
"version": "5.5.2",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
"integrity": "sha1-c7Xuyj+rZT49P5Qis0GtQiBdyWU=",
"requires": {
"co": "^4.6.0",
"fast-deep-equal": "^1.0.0",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.3.0"
}
},
"ajv-keywords": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz",
"integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
"dev": true
},
"ammo": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ammo/-/ammo-3.0.1.tgz",
"integrity": "sha512-4UqoM8xQjwkQ78oiU4NbBK0UgYqeKMAKmwE4ec7Rz3rGU8ZEBFxzgF2sUYKOAlqIXExBDYLN6y1ShF5yQ4hwLQ==",
"requires": {
"hoek": "5.x.x"
},
"dependencies": {
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"ansi-escapes": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
"integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
"dev": true
},
"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": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
},
"are-we-there-yet": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
}
},
"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"
}
},
"arr-flatten": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
"integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
"dev": true,
"optional": true
},
"arr-union": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
"integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
"dev": true,
"optional": true
},
"array-parallel": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz",
"integrity": "sha1-j3hTCJJu1apHjEfmTRszS2wMlH0="
},
"array-series": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz",
"integrity": "sha1-3103v8XC7wdV4qpPkv6ufUtaly8="
},
"array-union": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
"integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=",
"dev": true,
"requires": {
"array-uniq": "^1.0.1"
}
},
"array-uniq": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
"integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
},
"arrify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
"integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
"dev": true
},
"asn1": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
"integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
"requires": {
"safer-buffer": "~2.1.0"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
},
"assign-symbols": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
"dev": true,
"optional": true
},
"async": {
"version": "2.6.3",
"resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz",
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
"requires": {
"lodash": "^4.17.14"
}
},
"async-each": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
"integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
"dev": true,
"optional": true
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
},
"atob": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
"integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
"dev": true,
"optional": true
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
},
"aws4": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
},
"axios": {
"version": "0.18.1",
"resolved": "https://registry.npmjs.org/axios/-/axios-0.18.1.tgz",
"integrity": "sha512-0BfJq4NSfQXd+SkFdrvFbG7addhYSBA2mQwISr46pD6E5iqkWg02RAs8vyTT/j0RTnoYmeXauBuSv1qKwR179g==",
"requires": {
"follow-redirects": "1.5.10",
"is-buffer": "^2.0.2"
},
"dependencies": {
"is-buffer": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
"integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A=="
}
}
},
"b64": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/b64/-/b64-4.0.0.tgz",
"integrity": "sha512-EhmUQodKB0sdzPPrbIWbGqA5cQeTWxYrAgNeeT1rLZWtD3tbNTnphz8J4vkXI3cPgBNlXBjzEbzDzq0Nwi4f9A=="
},
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
"dev": true,
"requires": {
"chalk": "^1.1.3",
"esutils": "^2.0.2",
"js-tokens": "^3.0.2"
}
},
"babel-runtime": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
"integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
"requires": {
"core-js": "^2.4.0",
"regenerator-runtime": "^0.11.0"
}
},
"balanced-match": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
},
"base": {
"version": "0.11.2",
"resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
"integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
"dev": true,
"optional": true,
"requires": {
"cache-base": "^1.0.1",
"class-utils": "^0.3.5",
"component-emitter": "^1.2.1",
"define-property": "^1.0.0",
"isobject": "^3.0.1",
"mixin-deep": "^1.2.0",
"pascalcase": "^0.1.1"
},
"dependencies": {
"define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
"integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
"dev": true,
"optional": true,
"requires": {
"is-descriptor": "^1.0.0"
}
},
"is-accessor-descriptor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
"integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^6.0.0"
}
},
"is-data-descriptor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
"integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^6.0.0"
}
},
"is-descriptor": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
"integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
"dev": true,
"optional": true,
"requires": {
"is-accessor-descriptor": "^1.0.0",
"is-data-descriptor": "^1.0.0",
"kind-of": "^6.0.2"
}
},
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
},
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"dev": true,
"optional": true
}
}
},
"base64-js": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz",
"integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g=="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
"requires": {
"tweetnacl": "^0.14.3"
}
},
"big-time": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/big-time/-/big-time-2.0.1.tgz",
"integrity": "sha1-aMffjcMPl+lT8lpnp2rJcTwWyd4="
},
"binary-extensions": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz",
"integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU=",
"dev": true,
"optional": true
},
"bluebird": {
"version": "3.5.1",
"resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
"integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
},
- "bluebird-events": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/bluebird-events/-/bluebird-events-3.0.1.tgz",
- "integrity": "sha512-BTIcypanLyctuGGh5h0AY6RItAqFS7/gih/m/l8f3dvMNaUBbA+KmamEjP/q3noZ3bbs8ssyiNOV3gZHOB7MtQ=="
- },
"boolbase": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
},
"boom": {
"version": "7.3.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-7.3.0.tgz",
"integrity": "sha512-Swpoyi2t5+GhOEGw8rEsKvTxFLIDiiKoUc2gsoV6Lyr43LHBIzch3k2MvYUs8RTROrIkVJ3Al0TkaOGjnb+B6A==",
"requires": {
"hoek": "6.x.x"
}
},
"bounce": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/bounce/-/bounce-1.2.0.tgz",
"integrity": "sha512-8syCGe8B2/WC53118/F/tFy5aW00j+eaGPXmAUP7iBhxc+EBZZxS1vKelWyBCH6IqojgS2t1gF0glH30qAJKEw==",
"requires": {
"boom": "7.x.x",
"hoek": "5.x.x"
},
"dependencies": {
"boom": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-7.2.0.tgz",
"integrity": "sha1-K/8kpVVldn/ehp7ICDF+sQxI6WY=",
"requires": {
"hoek": "5.x.x"
}
},
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
}
},
"browser-stdout": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz",
"integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==",
"dev": true
},
"bson": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/bson/-/bson-1.1.4.tgz",
"integrity": "sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q=="
},
"buffer": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/buffer/-/buffer-5.5.0.tgz",
"integrity": "sha512-9FTEDjLjwoAkEwyMGDjYJQN2gfRgOKBKRfiglhvibGbpeeU/pQn1bJxQqm32OD/AIeEuHxU9roxXxg34Byp/Ww==",
"requires": {
"base64-js": "^1.0.2",
"ieee754": "^1.1.4"
}
},
"buffer-from": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.0.0.tgz",
"integrity": "sha512-83apNb8KK0Se60UE1+4Ukbe3HbfELJ6UlI4ldtOGs7So4KD26orJM8hIY9lxdzP+UpItH1Yh/Y8GUvNFWFFRxA==",
"dev": true
},
"cache-base": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
"integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
"dev": true,
"optional": true,
"requires": {
"collection-visit": "^1.0.0",
"component-emitter": "^1.2.1",
"get-value": "^2.0.6",
"has-value": "^1.0.0",
"isobject": "^3.0.1",
"set-value": "^2.0.0",
"to-object-path": "^0.3.0",
"union-value": "^1.0.0",
"unset-value": "^1.0.0"
},
"dependencies": {
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
}
}
},
"caller-path": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
"integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
"dev": true,
"requires": {
"callsites": "^0.2.0"
}
},
"callsites": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
"integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
"dev": true
},
"camel-case": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
"integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
"requires": {
"no-case": "^2.2.0",
"upper-case": "^1.1.1"
}
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "^2.2.1",
"escape-string-regexp": "^1.0.2",
"has-ansi": "^2.0.0",
"strip-ansi": "^3.0.0",
"supports-color": "^2.0.0"
}
},
"cheerio": {
"version": "0.22.0",
"resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz",
"integrity": "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4=",
"requires": {
"css-select": "~1.2.0",
"dom-serializer": "~0.1.0",
"entities": "~1.1.1",
"htmlparser2": "^3.9.1",
"lodash.assignin": "^4.0.9",
"lodash.bind": "^4.1.4",
"lodash.defaults": "^4.0.1",
"lodash.filter": "^4.4.0",
"lodash.flatten": "^4.2.0",
"lodash.foreach": "^4.3.0",
"lodash.map": "^4.4.0",
"lodash.merge": "^4.4.0",
"lodash.pick": "^4.2.1",
"lodash.reduce": "^4.4.0",
"lodash.reject": "^4.4.0",
"lodash.some": "^4.4.0"
}
},
"chownr": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
},
"circular-json": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
"integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
"dev": true
},
"class-utils": {
"version": "0.3.6",
"resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
"integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
"dev": true,
"optional": true,
"requires": {
"arr-union": "^3.1.0",
"define-property": "^0.2.5",
"isobject": "^3.0.0",
"static-extend": "^0.1.1"
},
"dependencies": {
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
"dev": true,
"optional": true,
"requires": {
"is-descriptor": "^0.1.0"
}
},
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
}
}
},
"clean-css": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
"integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
"requires": {
"source-map": "~0.6.0"
},
"dependencies": {
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
"cli-cursor": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
"integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
"dev": true,
"requires": {
"restore-cursor": "^1.0.1"
}
},
"cli-width": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
"integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
"dev": true
},
"clone": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
},
"co": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
},
"code-point-at": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
},
"collection-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
"integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
"dev": true,
"optional": true,
"requires": {
"map-visit": "^1.0.0",
"object-visit": "^1.0.0"
}
},
"color": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz",
"integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==",
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
}
},
"color-convert": {
"version": "1.9.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz",
"integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==",
"requires": {
"color-name": "^1.1.1"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"color-string": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
"integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"colornames": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/colornames/-/colornames-1.1.1.tgz",
"integrity": "sha1-+IiQMGhcfE/54qVZ9Qd+t2qBb5Y="
},
"colors": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
"integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
},
"colorspace": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.2.tgz",
"integrity": "sha512-vt+OoIP2d76xLhjwbBaucYlNSpPsrJWPlBTtwCpQKIu6/CSMutyzX93O/Do0qzpH3YoHEes8YEFXyZ797rEhzQ==",
"requires": {
"color": "3.0.x",
"text-hex": "1.0.x"
},
"dependencies": {
"color": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/color/-/color-3.0.0.tgz",
"integrity": "sha512-jCpd5+s0s0t7p3pHQKpnJ0TpQKKdleP71LWcA0aqiljpiuAkOSUFN/dyH8ZwF0hRmFlrIuRhufds1QyEP9EB+w==",
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
}
}
}
},
"combined-stream": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz",
"integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"commander": {
"version": "2.15.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.15.1.tgz",
"integrity": "sha512-VlfT9F3V0v+jr4yxPc5gg9s62/fIVWsd2Bk2iD435um1NlGMYdVCq+MjcXnhYq2icNOizHr1kK+5TI6H0Hy0ag=="
},
"component-emitter": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
"integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=",
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
},
"concat-stream": {
"version": "1.6.2",
"resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
"dev": true,
"requires": {
"buffer-from": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^2.2.2",
"typedarray": "^0.0.6"
}
},
"config-chain": {
"version": "1.1.12",
"resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz",
"integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==",
"requires": {
"ini": "^1.3.4",
"proto-list": "~1.2.1"
}
},
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"content": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/content/-/content-4.0.5.tgz",
"integrity": "sha512-wDP6CTWDpwCf791fNxlCCkZGRkrNzSEU/8ju9Hnr3Uc5mF/gFR5W+fcoGm6zUSlVPdSXYn5pCbySADKj7YM4Cg==",
"requires": {
"boom": "7.x.x"
},
"dependencies": {
"boom": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-7.2.0.tgz",
"integrity": "sha1-K/8kpVVldn/ehp7ICDF+sQxI6WY=",
"requires": {
"hoek": "5.x.x"
}
},
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"convert-source-map": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
"integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
"dev": true
},
"copy-descriptor": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
"integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
"dev": true,
"optional": true
},
"core-js": {
"version": "2.5.7",
"resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.7.tgz",
"integrity": "sha512-RszJCAxg/PP6uzXVXL6BsxSXx/B05oJAQ2vkJRjyjrEcNVycaqOmNb5OTxZPE3xa5gwZduqza6L9JOCenh/Ecw=="
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
},
"cross-env": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-5.2.0.tgz",
"integrity": "sha512-jtdNFfFW1hB7sMhr/H6rW1Z45LFqyI431m3qU6bFXcQ3Eh7LtBuG3h74o7ohHZ3crrRkkqHlo4jYHFPcjroANg==",
"requires": {
"cross-spawn": "^6.0.5",
"is-windows": "^1.0.0"
},
"dependencies": {
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
}
}
},
"cross-spawn": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
"integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=",
"requires": {
"lru-cache": "^4.0.1",
"which": "^1.2.9"
}
},
"css-select": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
"integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
"requires": {
"boolbase": "~1.0.0",
"css-what": "2.1",
"domutils": "1.5.1",
"nth-check": "~1.0.1"
}
},
"css-what": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz",
"integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0="
},
"d": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
"integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
"dev": true,
"requires": {
"es5-ext": "^0.10.9"
}
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
"requires": {
"assert-plus": "^1.0.0"
}
},
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"decamelize": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
"dev": true,
"optional": true
},
"decompress-response": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz",
"integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=",
"requires": {
"mimic-response": "^1.0.0"
}
},
"deep-equal": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz",
"integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU="
},
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
"integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
"dev": true
},
"deepmerge": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
"integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
},
"define-property": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
"integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
"dev": true,
"optional": true,
"requires": {
"is-descriptor": "^1.0.2",
"isobject": "^3.0.1"
},
"dependencies": {
"is-accessor-descriptor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
"integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^6.0.0"
}
},
"is-data-descriptor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
"integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^6.0.0"
}
},
"is-descriptor": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
"integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
"dev": true,
"optional": true,
"requires": {
"is-accessor-descriptor": "^1.0.0",
"is-data-descriptor": "^1.0.0",
"kind-of": "^6.0.2"
}
},
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
},
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true,
"optional": true
}
}
},
"del": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz",
"integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=",
"dev": true,
"requires": {
"globby": "^5.0.0",
"is-path-cwd": "^1.0.0",
"is-path-in-cwd": "^1.0.0",
"object-assign": "^4.0.1",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0",
"rimraf": "^2.2.8"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
},
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
},
"denque": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz",
"integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ=="
},
"detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
},
"diagnostics": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/diagnostics/-/diagnostics-1.1.1.tgz",
"integrity": "sha512-8wn1PmdunLJ9Tqbx+Fx/ZEuHfJf4NKSN2ZBj7SJC/OWRWha843+WsTjqMe1B5E3p28jqBlp+mJ2fPVxPyNgYKQ==",
"requires": {
"colorspace": "1.1.x",
"enabled": "1.0.x",
"kuler": "1.0.x"
}
},
"diff": {
"version": "3.5.0",
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
"dev": true
},
"doctrine": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
"requires": {
"esutils": "^2.0.2"
}
},
"dom-serializer": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
"integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
"requires": {
"domelementtype": "~1.1.1",
"entities": "~1.1.1"
},
"dependencies": {
"domelementtype": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
"integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="
}
}
},
"domelementtype": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
"integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI="
},
"domhandler": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.1.tgz",
"integrity": "sha1-iS5HAAqZvlW783dP/qBWHYh5wlk=",
"requires": {
"domelementtype": "1"
}
},
"domutils": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
"integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"dot-prop": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz",
"integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==",
"requires": {
"is-obj": "^2.0.0"
}
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"editorconfig": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.2.tgz",
"integrity": "sha512-GWjSI19PVJAM9IZRGOS+YKI8LN+/sjkSjNyvxL5ucqP9/IqtYNXBaQ/6c/hkPNYQHyOHra2KoXZI/JVpuqwmcQ==",
"requires": {
"@types/node": "^10.11.7",
"@types/semver": "^5.5.0",
"commander": "^2.19.0",
"lru-cache": "^4.1.3",
"semver": "^5.6.0",
"sigmund": "^1.0.1"
},
"dependencies": {
"@types/node": {
"version": "10.17.21",
"resolved": "https://registry.npmjs.org/@types/node/-/node-10.17.21.tgz",
"integrity": "sha512-PQKsydPxYxF1DsAFWmunaxd3sOi3iMt6Zmx/tgaagHYmwJ/9cRH91hQkeJZaUGWbvn0K5HlSVEXkn5U/llWPpQ=="
},
"commander": {
"version": "2.19.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
"integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg=="
},
"lru-cache": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.3.tgz",
"integrity": "sha512-fFEhvcgzuIoJVUF8fYr5KR0YqxD238zgObTps31YdADwPPAp82a4M8TrckkWyx7ekNlf9aBcVn81cFwwXngrJA==",
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
}
},
"semver": {
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz",
"integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg=="
}
}
},
"emoji-regex": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz",
"integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA=="
},
"enabled": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/enabled/-/enabled-1.0.2.tgz",
"integrity": "sha1-ll9lE9LC0cX0ZStkouM5ZGf8L5M=",
"requires": {
"env-variable": "0.0.x"
}
},
"end-of-stream": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
"integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
"requires": {
"once": "^1.4.0"
}
},
"entities": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
"integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
},
"env-variable": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/env-variable/-/env-variable-0.0.6.tgz",
"integrity": "sha512-bHz59NlBbtS0NhftmR8+ExBEekE7br0e01jw+kk0NDro7TtZzBYZ5ScGPs3OmwnpyfHTHOtr1Y6uedCdrIldtg=="
},
"es5-ext": {
"version": "0.10.41",
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.41.tgz",
"integrity": "sha512-MYK02wXfwTMie5TEJWPolgOsXEmz7wKCQaGzgmRjZOoV6VLG8I5dSv2bn6AOClXhK64gnSQTQ9W9MKvx87J4gw==",
"dev": true,
"requires": {
"es6-iterator": "~2.0.3",
"es6-symbol": "~3.1.1",
"next-tick": "1"
}
},
"es6-iterator": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
"integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
"dev": true,
"requires": {
"d": "1",
"es5-ext": "^0.10.35",
"es6-symbol": "^3.1.1"
}
},
"es6-map": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
"integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
"dev": true,
"requires": {
"d": "1",
"es5-ext": "~0.10.14",
"es6-iterator": "~2.0.1",
"es6-set": "~0.1.5",
"es6-symbol": "~3.1.1",
"event-emitter": "~0.3.5"
}
},
"es6-set": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
"integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
"dev": true,
"requires": {
"d": "1",
"es5-ext": "~0.10.14",
"es6-iterator": "~2.0.1",
"es6-symbol": "3.1.1",
"event-emitter": "~0.3.5"
}
},
"es6-symbol": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
"integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
"dev": true,
"requires": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"es6-weak-map": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
"integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
"dev": true,
"requires": {
"d": "1",
"es5-ext": "^0.10.14",
"es6-iterator": "^2.0.1",
"es6-symbol": "^3.1.1"
}
},
"escape-html": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
"integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
},
"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="
},
"escope": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
"integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
"dev": true,
"requires": {
"es6-map": "^0.1.3",
"es6-weak-map": "^2.0.1",
"esrecurse": "^4.1.0",
"estraverse": "^4.1.1"
}
},
"eslint": {
"version": "3.19.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz",
"integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=",
"dev": true,
"requires": {
"babel-code-frame": "^6.16.0",
"chalk": "^1.1.3",
"concat-stream": "^1.5.2",
"debug": "^2.1.1",
"doctrine": "^2.0.0",
"escope": "^3.6.0",
"espree": "^3.4.0",
"esquery": "^1.0.0",
"estraverse": "^4.2.0",
"esutils": "^2.0.2",
"file-entry-cache": "^2.0.0",
"glob": "^7.0.3",
"globals": "^9.14.0",
"ignore": "^3.2.0",
"imurmurhash": "^0.1.4",
"inquirer": "^0.12.0",
"is-my-json-valid": "^2.10.0",
"is-resolvable": "^1.0.0",
"js-yaml": "^3.5.1",
"json-stable-stringify": "^1.0.0",
"levn": "^0.3.0",
"lodash": "^4.0.0",
"mkdirp": "^0.5.0",
"natural-compare": "^1.4.0",
"optionator": "^0.8.2",
"path-is-inside": "^1.0.1",
"pluralize": "^1.2.1",
"progress": "^1.1.8",
"require-uncached": "^1.0.2",
"shelljs": "^0.7.5",
"strip-bom": "^3.0.0",
"strip-json-comments": "~2.0.1",
"table": "^3.7.8",
"text-table": "~0.2.0",
"user-home": "^2.0.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"requires": {
"ms": "2.0.0"
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
}
}
},
"espree": {
"version": "3.5.4",
"resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
"integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
"dev": true,
"requires": {
"acorn": "^5.5.0",
"acorn-jsx": "^3.0.0"
}
},
"esprima": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
"integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==",
"dev": true
},
"esquery": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz",
"integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=",
"dev": true,
"requires": {
"estraverse": "^4.0.0"
}
},
"esrecurse": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
"integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
"dev": true,
"requires": {
"estraverse": "^4.1.0"
}
},
"estraverse": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
"dev": true
},
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
"dev": true
},
"event-emitter": {
"version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
"integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
"dev": true,
"requires": {
"d": "1",
"es5-ext": "~0.10.14"
}
},
"events": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/events/-/events-2.0.0.tgz",
"integrity": "sha512-r/M5YkNg9zwI8QbSf7tsDWWJvO3PGwZXyG7GpFAxtMASnHL2eblFd7iHiGPtyGKKFPZ59S63NeX10Ws6WqGDcg=="
},
"exit-hook": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
"integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
"dev": true
},
"expand-hash": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/expand-hash/-/expand-hash-1.0.1.tgz",
"integrity": "sha512-p0Sc7VRQFRB9TJhkVj5iNa/9KH+TuD8wTDgmwXaWFscWvfzQR9JPhnHDItbC6BwJhKkJjCStL+pmusjgWXQP2w=="
},
"expand-template": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"extend-shallow": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
"integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
"dev": true,
"optional": true,
"requires": {
"assign-symbols": "^1.0.0",
"is-extendable": "^1.0.1"
},
"dependencies": {
"is-extendable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
"dev": true,
"optional": true,
"requires": {
"is-plain-object": "^2.0.4"
}
}
}
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
},
"fast-deep-equal": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz",
"integrity": "sha1-wFNHeBfIa1HaqFPIHgWbcz0CNhQ="
},
"fast-json-stable-stringify": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
"integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
},
"fast-levenshtein": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
"integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
"dev": true
},
"fast-safe-stringify": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz",
"integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA=="
},
"fecha": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fecha/-/fecha-2.3.3.tgz",
"integrity": "sha512-lUGBnIamTAwk4znq5BcqsDaxSmZ9nDVJaij6NvRt/Tg4R69gERA+otPKbS86ROw9nxVMw2/mp1fnaiWqbs6Sdg=="
},
"figures": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
"integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
"dev": true,
"requires": {
"escape-string-regexp": "^1.0.5",
"object-assign": "^4.1.0"
}
},
"file-entry-cache": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
"integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
"dev": true,
"requires": {
"flat-cache": "^1.2.1",
"object-assign": "^4.0.1"
}
},
"flat-cache": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz",
"integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=",
"dev": true,
"requires": {
"circular-json": "^0.3.1",
"del": "^2.0.2",
"graceful-fs": "^4.1.2",
"write": "^0.2.1"
}
},
"follow-redirects": {
"version": "1.5.10",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.5.10.tgz",
"integrity": "sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==",
"requires": {
"debug": "=3.1.0"
}
},
"for-in": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
"integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
"dev": true,
"optional": true
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
},
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"fragment-cache": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
"integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
"dev": true,
"optional": true,
"requires": {
"map-cache": "^0.2.2"
}
},
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"fs-minipass": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
"integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
"requires": {
"minipass": "^2.2.1"
}
},
"fs-readdir-recursive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
"integrity": "sha512-GNanXlVr2pf02+sPN40XN8HG+ePaNcvM0q5mZBd668Obwb0yD5GiUbZOFgwn8kGMY6I3mdyDJzieUy3PTYyTRA==",
"dev": true
},
"fs.realpath": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
},
"fsevents": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.4.tgz",
"integrity": "sha512-z8H8/diyk76B7q5wg+Ud0+CqzcAF3mBBI/bA5ne5zrRUUIvNkJY//D3BqyH571KuAC4Nr7Rw7CjWX4r0y9DvNg==",
"dev": true,
"optional": true,
"requires": {
"nan": "^2.9.2",
"node-pre-gyp": "^0.10.0"
}
},
"gauge": {
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
"has-unicode": "^2.0.0",
"object-assign": "^4.1.0",
"signal-exit": "^3.0.0",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.1",
"wide-align": "^1.1.0"
},
"dependencies": {
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
}
}
},
"generate-function": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz",
"integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=",
"dev": true
},
"generate-object-property": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
"integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
"dev": true,
"requires": {
"is-property": "^1.0.0"
}
},
"get-value": {
"version": "2.0.6",
"resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
"integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
"dev": true,
"optional": true
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
"requires": {
"assert-plus": "^1.0.0"
}
},
"github-from-package": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4="
},
"glob": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
"integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
"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": "9.18.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
"integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
"dev": true
},
"globby": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
"integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=",
"dev": true,
"requires": {
"array-union": "^1.0.1",
"arrify": "^1.0.0",
"glob": "^7.0.3",
"object-assign": "^4.0.1",
"pify": "^2.0.0",
"pinkie-promise": "^2.0.0"
}
},
"gm": {
"version": "1.23.1",
"resolved": "https://registry.npmjs.org/gm/-/gm-1.23.1.tgz",
"integrity": "sha1-Lt7rlYCE0PjqeYjl2ZWxx9/BR3c=",
"requires": {
"array-parallel": "~0.1.3",
"array-series": "~0.1.5",
"cross-spawn": "^4.0.0",
"debug": "^3.1.0"
}
},
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true
},
"growl": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/growl/-/growl-1.10.3.tgz",
"integrity": "sha512-hKlsbA5Vu3xsh1Cg3J7jSmX/WaW6A5oBeqzM88oNbCRQFz+zUaXm6yxS4RVytp1scBoJzSYl4YAEOQIt6O8V1Q==",
"dev": true
},
"hapi": {
"version": "17.5.2",
"resolved": "https://registry.npmjs.org/hapi/-/hapi-17.5.2.tgz",
"integrity": "sha512-UxMKYzrjfXlcztJQPEB3os5rM3SKgSQVxoOym4KI3JdP4pxl5WUdZYF8it4Kga2OMTGwB+ZTy+DU9b/oDaQHRQ==",
"requires": {
"accept": "3.x.x",
"ammo": "3.x.x",
"boom": "7.x.x",
"bounce": "1.x.x",
"call": "5.x.x",
"catbox": "10.x.x",
"catbox-memory": "3.x.x",
"heavy": "6.x.x",
"hoek": "5.x.x",
"joi": "13.x.x",
"mimos": "4.x.x",
"podium": "3.x.x",
"shot": "4.x.x",
"statehood": "6.x.x",
"subtext": "6.x.x",
"teamwork": "3.x.x",
"topo": "3.x.x"
},
"dependencies": {
"accept": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/accept/-/accept-3.0.2.tgz",
"integrity": "sha512-bghLXFkCOsC1Y2TZ51etWfKDs6q249SAoHTZVfzWWdlZxoij+mgkj9AmUJWQpDY48TfnrTDIe43Xem4zdMe7mQ==",
"requires": {
"boom": "7.x.x",
"hoek": "5.x.x"
}
},
"ammo": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ammo/-/ammo-3.0.1.tgz",
"integrity": "sha512-4UqoM8xQjwkQ78oiU4NbBK0UgYqeKMAKmwE4ec7Rz3rGU8ZEBFxzgF2sUYKOAlqIXExBDYLN6y1ShF5yQ4hwLQ==",
"requires": {
"hoek": "5.x.x"
}
},
"boom": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-7.2.0.tgz",
"integrity": "sha1-K/8kpVVldn/ehp7ICDF+sQxI6WY=",
"requires": {
"hoek": "5.x.x"
}
},
"call": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/call/-/call-5.0.1.tgz",
"integrity": "sha512-ollfFPSshiuYLp7AsrmpkQJ/PxCi6AzV81rCjBwWhyF2QGyUY/vPDMzoh4aUcWyucheRglG2LaS5qkIEfLRh6A==",
"requires": {
"boom": "7.x.x",
"hoek": "5.x.x"
}
},
"catbox": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/catbox/-/catbox-10.0.2.tgz",
"integrity": "sha512-cTQTQeKMhWHU0lX8CADE3g1koGJu+AlcWFzAjMX/8P+XbkScGYw3tJsQpe2Oh8q68vOQbOLacz9k+6V/F3Z9DA==",
"requires": {
"boom": "7.x.x",
"bounce": "1.x.x",
"hoek": "5.x.x",
"joi": "13.x.x"
}
},
"catbox-memory": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/catbox-memory/-/catbox-memory-3.1.2.tgz",
"integrity": "sha512-lhWtutLVhsq3Mucxk2McxBPPibJ34WcHuWFz3xqub9u9Ve/IQYpZv3ijLhQXfQped9DXozURiaq9O3aZpP91eg==",
"requires": {
"big-time": "2.x.x",
"boom": "7.x.x",
"hoek": "5.x.x"
}
},
"cryptiles": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.2.tgz",
"integrity": "sha512-U2ALcoAHvA1oO2xOreyHvtkQ+IELqDG2WVWRI1GH/XEmmfGIOalnM5MU5Dd2ITyWfr3m6kNqXiy8XuYyd4wKJw==",
"requires": {
"boom": "7.x.x"
}
},
"heavy": {
"version": "6.1.0",
"resolved": "https://registry.npmjs.org/heavy/-/heavy-6.1.0.tgz",
"integrity": "sha512-TKS9DC9NOTGulHQI31Lx+bmeWmNOstbJbGMiN3pX6bF+Zc2GKSpbbym4oasNnB6yPGkqJ9TQXXYDGohqNSJRxA==",
"requires": {
"boom": "7.x.x",
"hoek": "5.x.x",
"joi": "13.x.x"
}
},
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
},
"joi": {
"version": "13.5.2",
"resolved": "https://registry.npmjs.org/joi/-/joi-13.5.2.tgz",
"integrity": "sha512-3HrFXLC57iU5CzYth3cJRdYEo4/Dr+tXmCQ+BHyiTTKnKxJ9ICkI/WJGPwUUXj3dWA4tO2hwZO5oCdBNhAYuRg==",
"requires": {
"hoek": "5.x.x",
"isemail": "3.x.x",
"topo": "3.x.x"
},
"dependencies": {
"isemail": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/isemail/-/isemail-3.1.3.tgz",
"integrity": "sha512-5xbsG5wYADIcB+mfLsd+nst1V/D+I7EU7LEZPo2GOIMu4JzfcRs5yQoypP4avA7QtUqgxYLKBYNv4IdzBmbhdw==",
"requires": {
"punycode": "2.x.x"
}
},
"moment": {
"version": "2.14.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.14.1.tgz",
"integrity": "sha1-s1snxH5X7S3ccAU9awe+zbKRdBw="
}
}
},
"mimos": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mimos/-/mimos-4.0.0.tgz",
"integrity": "sha512-JvlvRLqGIlk+AYypWrbrDmhsM+6JVx/xBM5S3AMwTBz1trPCEoPN/swO2L4Wu653fL7oJdgk8DMQyG/Gq3JkZg==",
"requires": {
"hoek": "5.x.x",
"mime-db": "1.x.x"
}
},
"podium": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/podium/-/podium-3.1.2.tgz",
"integrity": "sha512-18VrjJAduIdPv7d9zWsfmKxTj3cQTYC5Pv5gtKxcWujYBpGbV+mhNSPYhlHW5xeWoazYyKfB9FEsPT12r5rY1A==",
"requires": {
"hoek": "5.x.x",
"joi": "13.x.x"
}
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"shot": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/shot/-/shot-4.0.5.tgz",
"integrity": "sha1-x+dFXRHWD2ts08Q+FaO0McF+VWY=",
"requires": {
"hoek": "5.x.x",
"joi": "13.x.x"
}
},
"statehood": {
"version": "6.0.6",
"resolved": "https://registry.npmjs.org/statehood/-/statehood-6.0.6.tgz",
"integrity": "sha512-jR45n5ZMAkasw0xoE9j9TuLmJv4Sa3AkXe+6yIFT6a07kXYHgSbuD2OVGECdZGFxTmvNqLwL1iRIgvq6O6rq+A==",
"requires": {
"boom": "7.x.x",
"bounce": "1.x.x",
"cryptiles": "4.x.x",
"hoek": "5.x.x",
"iron": "5.x.x",
"joi": "13.x.x"
}
},
"subtext": {
"version": "6.0.7",
"resolved": "https://registry.npmjs.org/subtext/-/subtext-6.0.7.tgz",
"integrity": "sha512-IcJUvRjeR+NB437Iq+LORFNJW4L6Knqkj3oQrBrkdhIaS2VKJvx/9aYEq7vi+PEx5/OuehOL/40SkSZotLi/MA==",
"requires": {
"boom": "7.x.x",
"content": "4.x.x",
"hoek": "5.x.x",
"pez": "4.x.x",
"wreck": "14.x.x"
}
},
"topo": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/topo/-/topo-3.0.0.tgz",
"integrity": "sha512-Tlu1fGlR90iCdIPURqPiufqAlCZYzLjHYVVbcFWDMcX7+tK8hdZWAfsMrD/pBul9jqHHwFjNdf1WaxA9vTRRhw==",
"requires": {
"hoek": "5.x.x"
}
}
}
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
},
"har-validator": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.0.tgz",
"integrity": "sha512-+qnmNjI4OfH2ipQ9VQOw23bBd/ibtfbVdK2fYbY4acTDqKTW/YDp9McimZdDbG8iV9fZizUqQMD5xvriB146TA==",
"requires": {
"ajv": "^5.3.0",
"har-schema": "^2.0.0"
}
},
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
},
"has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
},
"has-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
"integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
"dev": true,
"optional": true,
"requires": {
"get-value": "^2.0.6",
"has-values": "^1.0.0",
"isobject": "^3.0.0"
},
"dependencies": {
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
}
}
},
"has-values": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
"integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
"dev": true,
"optional": true,
"requires": {
"is-number": "^3.0.0",
"kind-of": "^4.0.0"
},
"dependencies": {
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2"
},
"dependencies": {
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
"optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
}
}
},
"kind-of": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
"integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
"dev": true,
"optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
}
}
},
"he": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
"integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
},
"hoek": {
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-6.1.3.tgz",
"integrity": "sha512-YXXAAhmF9zpQbC7LEcREFtXfGq5K1fmd+4PHkBq8NUqmzW3G+Dq10bI/i0KucLRwss3YYFQ0fSfoxBZYiGUqtQ=="
},
"html-minifier": {
"version": "3.5.20",
"resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.20.tgz",
"integrity": "sha512-ZmgNLaTp54+HFKkONyLFEfs5dd/ZOtlquKaTnqIWFmx3Av5zG6ZPcV2d0o9XM2fXOTxxIf6eDcwzFFotke/5zA==",
"requires": {
"camel-case": "3.0.x",
"clean-css": "4.2.x",
"commander": "2.17.x",
"he": "1.1.x",
"param-case": "2.1.x",
"relateurl": "0.2.x",
"uglify-js": "3.4.x"
},
"dependencies": {
"commander": {
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
}
}
},
"htmlparser2": {
"version": "3.9.2",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.9.2.tgz",
"integrity": "sha1-G9+HrMoPP55T+k/M6w9LTLsAszg=",
"requires": {
"domelementtype": "^1.3.0",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^2.0.2"
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
}
},
"iconv-lite": {
"version": "0.4.19",
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
"integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==",
"dev": true,
"optional": true
},
"ieee754": {
"version": "1.1.13",
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
"integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg=="
},
"ignore": {
"version": "3.3.7",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz",
"integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==",
"dev": true
},
"ignore-walk": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
"integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
"dev": true,
"optional": true,
"requires": {
"minimatch": "^3.0.4"
}
},
"imurmurhash": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
"integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
"dev": true
},
"inert": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/inert/-/inert-5.1.0.tgz",
"integrity": "sha512-5rJZbezGEkBN4QrP/HEEwsQ0N+7YzqDZrvBZrE7B0CrNY6I4XKI434aL3UNLCmbI4HzPGQs7Ae/4h1tiTMJ6Wg==",
"requires": {
"ammo": "3.x.x",
"boom": "7.x.x",
"bounce": "1.x.x",
"hoek": "5.x.x",
"joi": "13.x.x",
"lru-cache": "4.1.x"
},
"dependencies": {
"boom": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-7.2.0.tgz",
"integrity": "sha1-K/8kpVVldn/ehp7ICDF+sQxI6WY=",
"requires": {
"hoek": "5.x.x"
}
},
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"inflight": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
"requires": {
"once": "^1.3.0",
"wrappy": "1"
}
},
"inherits": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
"integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
},
"ini": {
"version": "1.3.5",
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
},
"inquirer": {
"version": "0.12.0",
"resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
"integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=",
"dev": true,
"requires": {
"ansi-escapes": "^1.1.0",
"ansi-regex": "^2.0.0",
"chalk": "^1.0.0",
"cli-cursor": "^1.0.1",
"cli-width": "^2.0.0",
"figures": "^1.3.5",
"lodash": "^4.3.0",
"readline2": "^1.0.1",
"run-async": "^0.1.0",
"rx-lite": "^3.1.2",
"string-width": "^1.0.1",
"strip-ansi": "^3.0.0",
"through": "^2.3.6"
},
"dependencies": {
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
},
"string-width": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"strip-ansi": "^3.0.0"
}
}
}
},
"interpret": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz",
"integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=",
"dev": true
},
"invariant": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
"integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
"dev": true,
"requires": {
"loose-envify": "^1.0.0"
}
},
"iron": {
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/iron/-/iron-5.0.4.tgz",
"integrity": "sha512-7iQ5/xFMIYaNt9g2oiNiWdhrOTdRUMFaWENUd0KghxwPUhrIH8DUY8FEyLNTTzf75jaII+jMexLdY/2HfV61RQ==",
"requires": {
"boom": "7.x.x",
"cryptiles": "4.x.x",
"hoek": "5.x.x"
},
"dependencies": {
"boom": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-7.2.0.tgz",
"integrity": "sha1-K/8kpVVldn/ehp7ICDF+sQxI6WY=",
"requires": {
"hoek": "5.x.x"
}
},
"cryptiles": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-4.1.2.tgz",
"integrity": "sha512-U2ALcoAHvA1oO2xOreyHvtkQ+IELqDG2WVWRI1GH/XEmmfGIOalnM5MU5Dd2ITyWfr3m6kNqXiy8XuYyd4wKJw==",
"requires": {
"boom": "7.x.x"
}
},
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"is-accessor-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
"integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2"
}
},
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
},
"is-binary-path": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
"integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
"dev": true,
"optional": true,
"requires": {
"binary-extensions": "^1.0.0"
}
},
"is-buffer": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
"integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
"dev": true,
"optional": true
},
"is-data-descriptor": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
"integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2"
}
},
"is-descriptor": {
"version": "0.1.6",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
"integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
"dev": true,
"optional": true,
"requires": {
"is-accessor-descriptor": "^0.1.6",
"is-data-descriptor": "^0.1.4",
"kind-of": "^5.0.0"
},
"dependencies": {
"kind-of": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
"integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
"dev": true,
"optional": true
}
}
},
"is-extendable": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
"integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
"dev": true,
"optional": true
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"requires": {
"number-is-nan": "^1.0.0"
}
},
"is-my-ip-valid": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz",
"integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==",
"dev": true
},
"is-my-json-valid": {
"version": "2.17.2",
"resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.17.2.tgz",
"integrity": "sha512-IBhBslgngMQN8DDSppmgDv7RNrlFotuuDsKcrCP3+HbFaVivIBU7u9oiiErw8sH4ynx3+gOGQ3q2otkgiSi6kg==",
"dev": true,
"requires": {
"generate-function": "^2.0.0",
"generate-object-property": "^1.1.0",
"is-my-ip-valid": "^1.0.0",
"jsonpointer": "^4.0.0",
"xtend": "^4.0.0"
}
},
"is-obj": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz",
"integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w=="
},
"is-path-cwd": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz",
"integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=",
"dev": true
},
"is-path-in-cwd": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz",
"integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==",
"dev": true,
"requires": {
"is-path-inside": "^1.0.0"
}
},
"is-path-inside": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
"integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
"dev": true,
"requires": {
"path-is-inside": "^1.0.1"
}
},
"is-plain-obj": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
"integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
"dev": true
},
"is-plain-object": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
"integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
"dev": true,
"optional": true,
"requires": {
"isobject": "^3.0.1"
},
"dependencies": {
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
}
}
},
"is-property": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
"integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
"dev": true
},
"is-resolvable": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
"integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
"dev": true
},
"is-stream": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
"integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
},
"is-windows": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
"integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA=="
},
"isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
},
"isemail": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/isemail/-/isemail-3.1.3.tgz",
"integrity": "sha512-5xbsG5wYADIcB+mfLsd+nst1V/D+I7EU7LEZPo2GOIMu4JzfcRs5yQoypP4avA7QtUqgxYLKBYNv4IdzBmbhdw==",
"requires": {
"punycode": "2.x.x"
},
"dependencies": {
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
}
}
},
"isexe": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
},
"joi": {
"version": "13.5.2",
"resolved": "https://registry.npmjs.org/joi/-/joi-13.5.2.tgz",
"integrity": "sha512-3HrFXLC57iU5CzYth3cJRdYEo4/Dr+tXmCQ+BHyiTTKnKxJ9ICkI/WJGPwUUXj3dWA4tO2hwZO5oCdBNhAYuRg==",
"requires": {
"hoek": "5.x.x",
"isemail": "3.x.x",
"topo": "3.x.x"
},
"dependencies": {
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"js-beautify": {
"version": "1.8.8",
"resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.8.8.tgz",
"integrity": "sha512-qVNq7ZZ7ZbLdzorvSlRDadS0Rh5oyItaE95v6I4wbbuSiijxn7SnnsV6dvKlcXuO2jX7lK8tn9fBulx34K/Ejg==",
"requires": {
"config-chain": "~1.1.5",
"editorconfig": "^0.15.0",
"mkdirp": "~0.5.0",
"nopt": "~4.0.1"
}
},
"js-levenshtein": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.4.tgz",
"integrity": "sha512-PxfGzSs0ztShKrUYPIn5r0MtyAhYcCwmndozzpz8YObbPnD1jFxzlBGbRnX2mIu6Z13xN6+PTu05TQFnZFlzow==",
"dev": true
},
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
},
"js-yaml": {
"version": "3.13.1",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
"integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
"dev": true,
"requires": {
"argparse": "^1.0.7",
"esprima": "^4.0.0"
}
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
},
"json-schema": {
"version": "0.2.3",
"resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
"integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
},
"json-schema-traverse": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
"integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
},
"json-stable-stringify": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
"integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
"dev": true,
"requires": {
"jsonify": "~0.0.0"
}
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
},
"json5": {
"version": "0.5.1",
"resolved": "http://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
"integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
"dev": true
},
"jsonify": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
"dev": true
},
"jsonpointer": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
"integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
"dev": true
},
"jsprim": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
"integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.2.3",
"verror": "1.10.0"
}
},
"just-extend": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.1.0.tgz",
"integrity": "sha512-ApcjaOdVTJ7y4r08xI5wIqpvwS48Q0PBG4DJROcEkH1f8MdAiNFyFxz3xoL0LWAVwjrwPYZdVHHxhRHcx/uGLA==",
"dev": true
},
"kind-of": {
"version": "3.2.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
"integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
"dev": true,
"optional": true,
"requires": {
"is-buffer": "^1.1.5"
}
},
"kuler": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/kuler/-/kuler-1.0.1.tgz",
"integrity": "sha512-J9nVUucG1p/skKul6DU3PUZrhs0LPulNaeUOox0IyXDi8S4CztTHs1gQphhuZmzXG7VOQSf6NJfKuzteQLv9gQ==",
"requires": {
"colornames": "^1.1.1"
}
},
"levn": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
"integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
"dev": true,
"requires": {
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2"
}
},
"locreq": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/locreq/-/locreq-1.1.0.tgz",
"integrity": "sha1-ScNnuHT0wS6t+RpBC4xz8xntohY="
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
},
"lodash.assignin": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz",
"integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI="
},
"lodash.bind": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz",
"integrity": "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU="
},
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
},
"lodash.debounce": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
"integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=",
"dev": true,
"optional": true
},
"lodash.defaults": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
},
"lodash.escaperegexp": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz",
"integrity": "sha1-ZHYsSGGAglGKw99Mz11YhtriA0c="
},
"lodash.filter": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz",
"integrity": "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4="
},
"lodash.flatten": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
"integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8="
},
"lodash.foreach": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz",
"integrity": "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM="
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=",
"dev": true
},
"lodash.isplainobject": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
},
"lodash.isstring": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
"integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
},
"lodash.map": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz",
"integrity": "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM="
},
"lodash.merge": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
},
"lodash.mergewith": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
},
"lodash.pick": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz",
"integrity": "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM="
},
"lodash.reduce": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz",
"integrity": "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
},
"lodash.reject": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz",
"integrity": "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU="
},
"lodash.some": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz",
"integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0="
},
"lodash.unescape": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/lodash.unescape/-/lodash.unescape-4.0.1.tgz",
"integrity": "sha1-vyJJiGzlFM2hEvrpIYzcBlIR/Jw="
},
"logform": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/logform/-/logform-2.1.2.tgz",
"integrity": "sha512-+lZh4OpERDBLqjiwDLpAWNQu6KMjnlXH2ByZwCuSqVPJletw0kTWJf5CgSNAUKn1KUkv3m2cUz/LK8zyEy7wzQ==",
"requires": {
"colors": "^1.2.1",
"fast-safe-stringify": "^2.0.4",
"fecha": "^2.3.3",
"ms": "^2.1.1",
"triple-beam": "^1.3.0"
},
"dependencies": {
"ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
}
}
},
"loose-envify": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
"integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
"requires": {
"js-tokens": "^3.0.0"
}
},
"lower-case": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
"integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
},
"lru-cache": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.2.tgz",
"integrity": "sha512-wgeVXhrDwAWnIF/yZARsFnMBtdFXOg1b8RIrhilp+0iDYN4mdQcNZElDZ0e4B64BhaxeQ5zN7PMyvu7we1kPeQ==",
"requires": {
"pseudomap": "^1.0.2",
"yallist": "^2.1.2"
}
},
"map-cache": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
"integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
"dev": true,
"optional": true
},
"map-visit": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
"integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
"dev": true,
"optional": true,
"requires": {
"object-visit": "^1.0.0"
}
},
"memory-pager": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
"integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
"optional": true
},
"mensch": {
"version": "0.3.3",
"resolved": "https://registry.npmjs.org/mensch/-/mensch-0.3.3.tgz",
"integrity": "sha1-4gD/TdgjcX+OBWOzLj9UgfyiYrI="
},
"mime": {
"version": "2.4.6",
"resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz",
"integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA=="
},
"mime-db": {
"version": "1.33.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
"integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
},
"mime-types": {
"version": "2.1.18",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
"integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
"requires": {
"mime-db": "~1.33.0"
}
},
"mimic-response": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz",
"integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="
},
"minimatch": {
"version": "3.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
"requires": {
"brace-expansion": "^1.1.7"
}
},
"minimist": {
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
"dev": true
},
"minipass": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.4.tgz",
"integrity": "sha512-mlouk1OHlaUE8Odt1drMtG1bAJA4ZA6B/ehysgV0LUIrDHdKgo1KorZq3pK0b/7Z7LJIQ12MNM6aC+Tn6lUZ5w==",
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
},
"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=="
},
"yallist": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k="
}
}
},
"minizlib": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.1.0.tgz",
"integrity": "sha512-4T6Ur/GctZ27nHfpt9THOdRZNgyJ9FZchYO1ceg5S8Q3DNLCKYy44nCZzgCJgcvx2UM8czmqak5BCxJMrq37lA==",
"dev": true,
"optional": true,
"requires": {
"minipass": "^2.2.1"
}
},
"mixin-deep": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
"integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
"dev": true,
"optional": true,
"requires": {
"for-in": "^1.0.2",
"is-extendable": "^1.0.1"
},
"dependencies": {
"is-extendable": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
"integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
"dev": true,
"optional": true,
"requires": {
"is-plain-object": "^2.0.4"
}
}
}
},
"mjml": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/mjml/-/mjml-4.2.0.tgz",
"integrity": "sha512-+XvQWME94Ana3XKKAFXYnMP6lDtvxVGqaWrcZKEAJV+fMpb5eFX4urvpyMhC02mJEpQpKdE7UTFMnIdi9ilF9g==",
"requires": {
"cross-env": "^5.1.4",
"mjml-accordion": "^4.2.0",
"mjml-body": "^4.2.0",
"mjml-button": "^4.2.0",
"mjml-carousel": "^4.2.0",
"mjml-cli": "^4.2.0",
"mjml-column": "^4.2.0",
"mjml-core": "^4.2.0",
"mjml-divider": "^4.2.0",
"mjml-group": "^4.2.0",
"mjml-head": "^4.2.0",
"mjml-head-attributes": "^4.2.0",
"mjml-head-breakpoint": "^4.2.0",
"mjml-head-font": "^4.2.0",
"mjml-head-preview": "^4.2.0",
"mjml-head-style": "^4.2.0",
"mjml-head-title": "^4.2.0",
"mjml-hero": "^4.2.0",
"mjml-image": "^4.2.0",
"mjml-migrate": "^4.2.0",
"mjml-navbar": "^4.2.0",
"mjml-raw": "^4.2.0",
"mjml-section": "^4.2.0",
"mjml-social": "^4.2.0",
"mjml-spacer": "^4.2.0",
"mjml-table": "^4.2.0",
"mjml-text": "^4.2.0",
"mjml-validator": "^4.2.0",
"mjml-wrapper": "^4.2.0"
}
},
"mjml-accordion": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-accordion/-/mjml-accordion-4.6.2.tgz",
"integrity": "sha512-ex5kU3me1ggBw4jMzNce+gEA13DClkq5lTUd7Aec+9obHh0X9/hQJ/RT0kVDn5i1ZPMcMmI94Y8CliMBk9MIKg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-body": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-body/-/mjml-body-4.6.2.tgz",
"integrity": "sha512-6+ULwmSmEoqelTTHPgjbZ0LaoDChsDijolzoT5wy+QHcwkBGmEpB0/6yI8YWNvpUlfkrSOOkzWbjdHQFWoiJng==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-button": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-button/-/mjml-button-4.6.2.tgz",
"integrity": "sha512-jHQCuQqUyZ6bLpWcdqbGwNIelpAVMBrtkXlToYCqG6PSF4uj3CfPnqV621PHyOex3BV2qgKklzTuGICMHC5D8g==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-carousel": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-carousel/-/mjml-carousel-4.6.2.tgz",
"integrity": "sha512-w1L71B2mmFlPGK6OgGbZP6qRtg7NMH4cp/VFwww8PpAStN9tXRf2exMyEBdoitrmpMGWbgmkLQrQ49w9OYPBVw==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-cli": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-cli/-/mjml-cli-4.6.2.tgz",
"integrity": "sha512-Rxbv9YflBgaSU21dS95k8ar85VcCsK37LclIqupD13TMHbFNobIO/DVcK5+P/R5VZIblqK7HmTh1FQU4uGEplQ==",
"requires": {
"babel-runtime": "^6.26.0",
"chokidar": "^3.0.0",
"glob": "^7.1.1",
"lodash": "^4.17.15",
"mjml-core": "4.6.2",
"mjml-migrate": "4.6.0",
"mjml-parser-xml": "4.6.2",
"mjml-validator": "4.5.0",
"yargs": "^13.3.0"
},
"dependencies": {
"ansi-regex": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
"integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg=="
},
"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"
}
},
"anymatch": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz",
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
"requires": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
}
},
"async": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
"integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
},
"binary-extensions": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz",
"integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow=="
},
"braces": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
"requires": {
"fill-range": "^7.0.1"
}
},
"camelcase": {
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz",
"integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
},
"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"
}
},
"chokidar": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz",
"integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==",
"requires": {
"anymatch": "~3.1.1",
"braces": "~3.0.2",
"fsevents": "~2.1.2",
"glob-parent": "~5.1.0",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.3.0"
}
},
"cliui": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
"integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
"requires": {
"string-width": "^3.1.0",
"strip-ansi": "^5.2.0",
"wrap-ansi": "^5.1.0"
}
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"datauri": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/datauri/-/datauri-2.0.0.tgz",
"integrity": "sha512-zS2HSf9pI5XPlNZgIqJg/wCJpecgU/HA6E/uv2EfaWnW1EiTGLfy/EexTIsC9c99yoCOTXlqeeWk4FkCSuO3/g==",
"requires": {
"image-size": "^0.7.3",
"mimer": "^1.0.0"
}
},
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"dom-serializer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
"integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
"requires": {
"domelementtype": "^2.0.1",
"entities": "^2.0.0"
}
},
"domelementtype": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
},
"domhandler": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.0.0.tgz",
"integrity": "sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==",
"requires": {
"domelementtype": "^2.0.1"
}
},
"domutils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.0.0.tgz",
"integrity": "sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg==",
"requires": {
"dom-serializer": "^0.2.1",
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0"
}
},
"entities": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
},
"fill-range": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
"requires": {
"to-regex-range": "^5.0.1"
}
},
"find-up": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
"requires": {
"locate-path": "^3.0.0"
}
},
"fsevents": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz",
"integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==",
"optional": true
},
"get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
},
"glob-parent": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz",
"integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==",
"requires": {
"is-glob": "^4.0.1"
}
},
"htmlparser2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
"integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0",
"domutils": "^2.0.0",
"entities": "^2.0.0"
}
},
"image-size": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz",
"integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g=="
},
"is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"requires": {
"binary-extensions": "^2.0.0"
}
},
"is-extglob": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
"integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"is-glob": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
"requires": {
"is-extglob": "^2.1.1"
}
},
"is-number": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
},
"juice": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/juice/-/juice-5.2.0.tgz",
"integrity": "sha512-0l6GZmT3efexyaaay3SchKT5kG311N59TEFP5lfvEy0nz9SNqjx311plJ3b4jze7arsmDsiHQLh/xnAuk0HFTQ==",
"requires": {
"cheerio": "^0.22.0",
"commander": "^2.15.1",
"cross-spawn": "^6.0.5",
"deep-extend": "^0.6.0",
"mensch": "^0.3.3",
"slick": "^1.12.2",
"web-resource-inliner": "^4.3.1"
}
},
"locate-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
"requires": {
"p-locate": "^3.0.0",
"path-exists": "^3.0.0"
}
},
"mimer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mimer/-/mimer-1.0.0.tgz",
"integrity": "sha512-4ZJvCzfcwsBgPbkKXUzGoVZMWjv8IDIygkGzVc7uUYhgnK0t2LmGxxjdgH1i+pn0/KQfB5F/VKUJlfyTSOFQjg=="
},
"mjml-migrate": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.6.0.tgz",
"integrity": "sha512-2aVe/NgT5TbXG3Sqbnw1uvtztB1opVGmmPeDs9cKbOxmncspRehWdW7EUREa491RmFvC/8krcXum+wbV0IHkjw==",
"requires": {
"babel-runtime": "^6.26.0",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
},
"dependencies": {
"domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
},
"domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"requires": {
"domelementtype": "1"
}
},
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
},
"htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
"requires": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
},
"mjml-core": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.5.0.tgz",
"integrity": "sha512-/9M4Dt0f7zaVzP7OJZlqaVWS1ijkoEoF6dKKeiXqRQ3oTvyiTEATHGA5xeifsU4dOzDFhdfFbu54LJOmHdPlVw==",
"requires": {
"babel-runtime": "^6.26.0",
"html-minifier": "^3.5.3",
"js-beautify": "^1.6.14",
"juice": "^5.2.0",
"lodash": "^4.17.15",
"mjml-migrate": "4.5.0",
"mjml-parser-xml": "4.5.0",
"mjml-validator": "4.5.0"
},
"dependencies": {
"mjml-migrate": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.5.0.tgz",
"integrity": "sha512-zzAKSrGpF+OVoa3GHVS7O2A4WZPLBV/Nrc80MGaLS4hhBbuj2WeUdaugVlIMXRRuhQ+nP+k0fZSM8tonDDjd2w==",
"requires": {
"babel-runtime": "^6.26.0",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
}
}
}
},
"mjml-migrate": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.5.0.tgz",
"integrity": "sha512-zzAKSrGpF+OVoa3GHVS7O2A4WZPLBV/Nrc80MGaLS4hhBbuj2WeUdaugVlIMXRRuhQ+nP+k0fZSM8tonDDjd2w==",
"requires": {
"babel-runtime": "^6.26.0",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
}
},
"mjml-parser-xml": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.5.0.tgz",
"integrity": "sha512-9NK9TnkDSJ0M7lMv1vuGjZumi1rqdv4Iwr9rBDpBPUvfv9ay7MoJrQjK28cu6PKcamOK6CHAFXihlV9Q6fbYaA==",
"requires": {
"babel-runtime": "^6.26.0",
"htmlparser2": "^3.9.2",
"lodash": "^4.17.15"
}
}
}
},
"mjml-parser-xml": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.6.2.tgz",
"integrity": "sha512-d9QO/8szZE27xy+BwMHyjs4vIzRG6sQ/O/7PXsSfGgred3cDuk7PMwuC7rZefft6Un4vogk3/M+KR6KGVaEnbg==",
"requires": {
"babel-runtime": "^6.26.0",
"htmlparser2": "^3.9.2",
"lodash": "^4.17.15"
},
"dependencies": {
"domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
},
"domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"requires": {
"domelementtype": "1"
}
},
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
},
"htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
"requires": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
}
}
},
"mjml-validator": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.5.0.tgz",
"integrity": "sha512-Qbyf/VCk3U8ViLCu+VCwGYZVQaJAw5brKW/aXeRRHb10LdhaCF1S0JNIiNyutfnqn92QWdzYt6W+cbcEZIKa9A==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"warning": "^3.0.0"
}
},
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
},
"p-limit": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
"requires": {
"p-try": "^2.0.0"
}
},
"p-locate": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
"requires": {
"p-limit": "^2.0.0"
}
},
"p-try": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz",
"integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"readdirp": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz",
"integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==",
"requires": {
"picomatch": "^2.0.7"
}
},
"require-main-filename": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz",
"integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"string-width": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
"integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
"requires": {
"emoji-regex": "^7.0.1",
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^5.1.0"
}
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"strip-ansi": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
"integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
"requires": {
"ansi-regex": "^4.1.0"
}
},
"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-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
"requires": {
"is-number": "^7.0.0"
}
},
"valid-data-url": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-2.0.0.tgz",
"integrity": "sha512-dyCZnv3aCey7yfTgIqdZanKl7xWAEEKCbgmR7SKqyK6QT/Z07ROactrgD1eA37C69ODRj7rNOjzKWVPh0EUjBA=="
},
"web-resource-inliner": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-4.3.4.tgz",
"integrity": "sha512-agVAgRhOOi4GVlvKK34oM23tDgH8390HfLnZY2HZl8OFBwKNvUJkH7t89AT2iluQP8w9VHAAKX6Z8EN7/9tqKA==",
"requires": {
"async": "^3.1.0",
"chalk": "^2.4.2",
"datauri": "^2.0.0",
"htmlparser2": "^4.0.0",
"lodash.unescape": "^4.0.1",
"request": "^2.88.0",
"safer-buffer": "^2.1.2",
"valid-data-url": "^2.0.0",
"xtend": "^4.0.2"
}
},
"wrap-ansi": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
"integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
"requires": {
"ansi-styles": "^3.2.0",
"string-width": "^3.0.0",
"strip-ansi": "^5.0.0"
}
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
},
"y18n": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz",
"integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w=="
},
"yargs": {
"version": "13.3.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
"integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==",
"requires": {
"cliui": "^5.0.0",
"find-up": "^3.0.0",
"get-caller-file": "^2.0.1",
"require-directory": "^2.1.1",
"require-main-filename": "^2.0.0",
"set-blocking": "^2.0.0",
"string-width": "^3.0.0",
"which-module": "^2.0.0",
"y18n": "^4.0.0",
"yargs-parser": "^13.1.2"
}
},
"yargs-parser": {
"version": "13.1.2",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz",
"integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==",
"requires": {
"camelcase": "^5.0.0",
"decamelize": "^1.2.0"
}
}
}
},
"mjml-column": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-column/-/mjml-column-4.6.2.tgz",
"integrity": "sha512-5OHqUOQoJPx73VctXiDjDysuuIwDys1Rd8ezcGSawkwepYcY7afXa23mBgV/QkOfJmeowLBoLwcuy4TsWWHmbg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-core": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.6.2.tgz",
"integrity": "sha512-Rk5J+IRUgbtJ+acWWY/N1qqS+0qtQY5Vb+KwoOWPtGh2iHB01vNF02/qVEEocaaRHARP556kfO1RLSgsRH/iew==",
"requires": {
"babel-runtime": "^6.26.0",
"html-minifier": "^3.5.3",
"js-beautify": "^1.6.14",
"juice": "^5.2.0",
"lodash": "^4.17.15",
"mjml-migrate": "4.6.0",
"mjml-parser-xml": "4.6.2",
"mjml-validator": "4.5.0"
},
"dependencies": {
"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"
}
},
"async": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
"integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
},
"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"
}
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"datauri": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/datauri/-/datauri-2.0.0.tgz",
"integrity": "sha512-zS2HSf9pI5XPlNZgIqJg/wCJpecgU/HA6E/uv2EfaWnW1EiTGLfy/EexTIsC9c99yoCOTXlqeeWk4FkCSuO3/g==",
"requires": {
"image-size": "^0.7.3",
"mimer": "^1.0.0"
}
},
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"dom-serializer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
"integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
"requires": {
"domelementtype": "^2.0.1",
"entities": "^2.0.0"
}
},
"domelementtype": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
},
"domhandler": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.0.0.tgz",
"integrity": "sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==",
"requires": {
"domelementtype": "^2.0.1"
}
},
"domutils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.0.0.tgz",
"integrity": "sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg==",
"requires": {
"dom-serializer": "^0.2.1",
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0"
}
},
"entities": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
},
"htmlparser2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
"integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0",
"domutils": "^2.0.0",
"entities": "^2.0.0"
}
},
"image-size": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz",
"integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g=="
},
"juice": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/juice/-/juice-5.2.0.tgz",
"integrity": "sha512-0l6GZmT3efexyaaay3SchKT5kG311N59TEFP5lfvEy0nz9SNqjx311plJ3b4jze7arsmDsiHQLh/xnAuk0HFTQ==",
"requires": {
"cheerio": "^0.22.0",
"commander": "^2.15.1",
"cross-spawn": "^6.0.5",
"deep-extend": "^0.6.0",
"mensch": "^0.3.3",
"slick": "^1.12.2",
"web-resource-inliner": "^4.3.1"
}
},
"mimer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mimer/-/mimer-1.0.0.tgz",
"integrity": "sha512-4ZJvCzfcwsBgPbkKXUzGoVZMWjv8IDIygkGzVc7uUYhgnK0t2LmGxxjdgH1i+pn0/KQfB5F/VKUJlfyTSOFQjg=="
},
"mjml-core": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.5.0.tgz",
"integrity": "sha512-/9M4Dt0f7zaVzP7OJZlqaVWS1ijkoEoF6dKKeiXqRQ3oTvyiTEATHGA5xeifsU4dOzDFhdfFbu54LJOmHdPlVw==",
"dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"html-minifier": "^3.5.3",
"js-beautify": "^1.6.14",
"juice": "^5.2.0",
"lodash": "^4.17.15",
"mjml-migrate": "4.5.0",
"mjml-parser-xml": "4.5.0",
"mjml-validator": "4.5.0"
},
"dependencies": {
"domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
"dev": true
},
"domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"dev": true,
"requires": {
"domelementtype": "1"
}
},
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"dev": true,
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
"dev": true
},
"htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
"dev": true,
"requires": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
},
"mjml-migrate": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.5.0.tgz",
"integrity": "sha512-zzAKSrGpF+OVoa3GHVS7O2A4WZPLBV/Nrc80MGaLS4hhBbuj2WeUdaugVlIMXRRuhQ+nP+k0fZSM8tonDDjd2w==",
"dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
}
},
"mjml-parser-xml": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.5.0.tgz",
"integrity": "sha512-9NK9TnkDSJ0M7lMv1vuGjZumi1rqdv4Iwr9rBDpBPUvfv9ay7MoJrQjK28cu6PKcamOK6CHAFXihlV9Q6fbYaA==",
"dev": true,
"requires": {
"babel-runtime": "^6.26.0",
"htmlparser2": "^3.9.2",
"lodash": "^4.17.15"
}
}
}
},
"mjml-migrate": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.6.0.tgz",
"integrity": "sha512-2aVe/NgT5TbXG3Sqbnw1uvtztB1opVGmmPeDs9cKbOxmncspRehWdW7EUREa491RmFvC/8krcXum+wbV0IHkjw==",
"requires": {
"babel-runtime": "^6.26.0",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
},
"dependencies": {
"domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
},
"domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"requires": {
"domelementtype": "1"
}
},
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
},
"htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
"requires": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
},
"mjml-core": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.5.0.tgz",
"integrity": "sha512-/9M4Dt0f7zaVzP7OJZlqaVWS1ijkoEoF6dKKeiXqRQ3oTvyiTEATHGA5xeifsU4dOzDFhdfFbu54LJOmHdPlVw==",
"requires": {
"babel-runtime": "^6.26.0",
"html-minifier": "^3.5.3",
"js-beautify": "^1.6.14",
"juice": "^5.2.0",
"lodash": "^4.17.15",
"mjml-migrate": "4.5.0",
"mjml-parser-xml": "4.5.0",
"mjml-validator": "4.5.0"
},
"dependencies": {
"mjml-migrate": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.5.0.tgz",
"integrity": "sha512-zzAKSrGpF+OVoa3GHVS7O2A4WZPLBV/Nrc80MGaLS4hhBbuj2WeUdaugVlIMXRRuhQ+nP+k0fZSM8tonDDjd2w==",
"requires": {
"babel-runtime": "^6.26.0",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
}
}
}
},
"mjml-migrate": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.5.0.tgz",
"integrity": "sha512-zzAKSrGpF+OVoa3GHVS7O2A4WZPLBV/Nrc80MGaLS4hhBbuj2WeUdaugVlIMXRRuhQ+nP+k0fZSM8tonDDjd2w==",
"requires": {
"babel-runtime": "^6.26.0",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
}
},
"mjml-parser-xml": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.5.0.tgz",
"integrity": "sha512-9NK9TnkDSJ0M7lMv1vuGjZumi1rqdv4Iwr9rBDpBPUvfv9ay7MoJrQjK28cu6PKcamOK6CHAFXihlV9Q6fbYaA==",
"requires": {
"babel-runtime": "^6.26.0",
"htmlparser2": "^3.9.2",
"lodash": "^4.17.15"
}
}
}
},
"mjml-parser-xml": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.6.2.tgz",
"integrity": "sha512-d9QO/8szZE27xy+BwMHyjs4vIzRG6sQ/O/7PXsSfGgred3cDuk7PMwuC7rZefft6Un4vogk3/M+KR6KGVaEnbg==",
"requires": {
"babel-runtime": "^6.26.0",
"htmlparser2": "^3.9.2",
"lodash": "^4.17.15"
},
"dependencies": {
"domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
},
"domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"requires": {
"domelementtype": "1"
}
},
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
},
"htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
"requires": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
}
}
},
"mjml-validator": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.5.0.tgz",
"integrity": "sha512-Qbyf/VCk3U8ViLCu+VCwGYZVQaJAw5brKW/aXeRRHb10LdhaCF1S0JNIiNyutfnqn92QWdzYt6W+cbcEZIKa9A==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"warning": "^3.0.0"
}
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"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"
}
},
"valid-data-url": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-2.0.0.tgz",
"integrity": "sha512-dyCZnv3aCey7yfTgIqdZanKl7xWAEEKCbgmR7SKqyK6QT/Z07ROactrgD1eA37C69ODRj7rNOjzKWVPh0EUjBA=="
},
"web-resource-inliner": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-4.3.4.tgz",
"integrity": "sha512-agVAgRhOOi4GVlvKK34oM23tDgH8390HfLnZY2HZl8OFBwKNvUJkH7t89AT2iluQP8w9VHAAKX6Z8EN7/9tqKA==",
"requires": {
"async": "^3.1.0",
"chalk": "^2.4.2",
"datauri": "^2.0.0",
"htmlparser2": "^4.0.0",
"lodash.unescape": "^4.0.1",
"request": "^2.88.0",
"safer-buffer": "^2.1.2",
"valid-data-url": "^2.0.0",
"xtend": "^4.0.2"
}
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}
}
},
"mjml-divider": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-divider/-/mjml-divider-4.6.2.tgz",
"integrity": "sha512-dcMUk361US2s/XA7UuTDKrSSdGP46b4GVfKf0/9H3r78gSgDBph0r1g89ar7Dd4n+qvdTOL7O71dlmAlI/X7Dg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-group": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-group/-/mjml-group-4.6.2.tgz",
"integrity": "sha512-5c+MWKmeeTCKvPfrALHwOUVBedC6NwgAS7jCQeKZ1gJsS9bzdZRlkiYKd7XNLTrOT97XoAJ4DAP9B4x3OrXtBw==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-head": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-head/-/mjml-head-4.6.2.tgz",
"integrity": "sha512-UEa5OQEGJdqYThSTAbE+LJuinTnOMMrnJqm+dxb0ft7D50Bi7UH4y3Xs//SQQELz8ntlOQq2C/7g6BZ4yRNxhg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-head-attributes": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-head-attributes/-/mjml-head-attributes-4.6.2.tgz",
"integrity": "sha512-4r5exX6smeltj3Is6kd1lTxwqECAIFjQY7kkGhJeutbehmXM49iw84IbMnvYJ3FUwYx7efGdOwPFPTeM677RsA==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-head-breakpoint": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-head-breakpoint/-/mjml-head-breakpoint-4.6.2.tgz",
"integrity": "sha512-uzBqfjoLaHBi7QKUwmskydBdICSNoFKsft5aFTua1yFxCfwRd5LC8LUenlll24pJjnajPVxNuSLf2U7AWMyCSQ==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-head-font": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-head-font/-/mjml-head-font-4.6.2.tgz",
"integrity": "sha512-degQDrYY9sNjRlnNqJOkmiH2ZJ9nw05G9TXO08KMCfx6FS2sH4ry1eB3D+RZOIdhP/S5maqZ16KMVqkt+kEJjw==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-head-preview": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-head-preview/-/mjml-head-preview-4.6.2.tgz",
"integrity": "sha512-IXKJpUnYnpUpKlKz7VAWEmufiAU/dTv2s99Ns26mIFjY3aveTr+TysvUjjofQmk6+29Z8Zx63bGaGurwr9ykvA==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-head-style": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-head-style/-/mjml-head-style-4.6.2.tgz",
"integrity": "sha512-ZJuUcKUeklDrA1hhG0dAmB3ph1E9js3l0uWuMuWluZiA9ix29wsxsOu119oElyKEpYstd84cwmcuf66X3IyhTg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-head-title": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-head-title/-/mjml-head-title-4.6.2.tgz",
"integrity": "sha512-VjZKlt4GGNGozFlM+BQKGbbPq50COH+TOU2Hgdwm9w6XQyKBcxFcILWa9gEd2slKuDpvetN7ri2QHPii7n2yZg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-hero": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-hero/-/mjml-hero-4.6.2.tgz",
"integrity": "sha512-7IdSSOBQzC6apZwKNLr83k01kBRpTfZZ2oryVlye2E7kGLV+knONglOicWm8qfs/mBBP+FKoZDrOekyD3Lz5Yg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-image": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-image/-/mjml-image-4.6.2.tgz",
"integrity": "sha512-g2vtdy15K5BLd30Wf73FgTnjOdvVsR+DDHbJt5MRTBYeeZFAj/2Y1HSoCalYDGkee39a86j5JGlb2qnUjGVIpw==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-migrate": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.6.2.tgz",
"integrity": "sha512-UMBrYf4gud7o7sCrn9ypl2EM3LBCJ70iMC4CScPlrxKWqK9uFBryO35zj8kFTCk5QfMg5NS4Ep+n0YJtCq/bhg==",
"requires": {
"@babel/runtime": "^7.8.7",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
},
"dependencies": {
"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"
}
},
"async": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz",
"integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw=="
},
"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"
}
},
"cross-spawn": {
"version": "6.0.5",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
"integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
"requires": {
"nice-try": "^1.0.4",
"path-key": "^2.0.1",
"semver": "^5.5.0",
"shebang-command": "^1.2.0",
"which": "^1.2.9"
}
},
"datauri": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/datauri/-/datauri-2.0.0.tgz",
"integrity": "sha512-zS2HSf9pI5XPlNZgIqJg/wCJpecgU/HA6E/uv2EfaWnW1EiTGLfy/EexTIsC9c99yoCOTXlqeeWk4FkCSuO3/g==",
"requires": {
"image-size": "^0.7.3",
"mimer": "^1.0.0"
}
},
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"dom-serializer": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
"integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==",
"requires": {
"domelementtype": "^2.0.1",
"entities": "^2.0.0"
}
},
"domelementtype": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz",
"integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ=="
},
"domhandler": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-3.0.0.tgz",
"integrity": "sha512-eKLdI5v9m67kbXQbJSNn1zjh0SDzvzWVWtX+qEI3eMjZw8daH9k8rlj1FZY9memPwjiskQFbe7vHVVJIAqoEhw==",
"requires": {
"domelementtype": "^2.0.1"
}
},
"domutils": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-2.0.0.tgz",
"integrity": "sha512-n5SelJ1axbO636c2yUtOGia/IcJtVtlhQbFiVDBZHKV5ReJO1ViX7sFEemtuyoAnBxk5meNSYgA8V4s0271efg==",
"requires": {
"dom-serializer": "^0.2.1",
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0"
}
},
"entities": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz",
"integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw=="
},
"htmlparser2": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-4.1.0.tgz",
"integrity": "sha512-4zDq1a1zhE4gQso/c5LP1OtrhYTncXNSpvJYtWJBtXAETPlMfi3IFNjGuQbYLuVY4ZR0QMqRVvo4Pdy9KLyP8Q==",
"requires": {
"domelementtype": "^2.0.1",
"domhandler": "^3.0.0",
"domutils": "^2.0.0",
"entities": "^2.0.0"
}
},
"image-size": {
"version": "0.7.5",
"resolved": "https://registry.npmjs.org/image-size/-/image-size-0.7.5.tgz",
"integrity": "sha512-Hiyv+mXHfFEP7LzUL/llg9RwFxxY+o9N3JVLIeG5E7iFIFAalxvRU9UZthBdYDEVnzHMgjnKJPPpay5BWf1g9g=="
},
"juice": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/juice/-/juice-5.2.0.tgz",
"integrity": "sha512-0l6GZmT3efexyaaay3SchKT5kG311N59TEFP5lfvEy0nz9SNqjx311plJ3b4jze7arsmDsiHQLh/xnAuk0HFTQ==",
"requires": {
"cheerio": "^0.22.0",
"commander": "^2.15.1",
"cross-spawn": "^6.0.5",
"deep-extend": "^0.6.0",
"mensch": "^0.3.3",
"slick": "^1.12.2",
"web-resource-inliner": "^4.3.1"
}
},
"mimer": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/mimer/-/mimer-1.0.0.tgz",
"integrity": "sha512-4ZJvCzfcwsBgPbkKXUzGoVZMWjv8IDIygkGzVc7uUYhgnK0t2LmGxxjdgH1i+pn0/KQfB5F/VKUJlfyTSOFQjg=="
},
"mjml-core": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-core/-/mjml-core-4.5.0.tgz",
"integrity": "sha512-/9M4Dt0f7zaVzP7OJZlqaVWS1ijkoEoF6dKKeiXqRQ3oTvyiTEATHGA5xeifsU4dOzDFhdfFbu54LJOmHdPlVw==",
"requires": {
"babel-runtime": "^6.26.0",
"html-minifier": "^3.5.3",
"js-beautify": "^1.6.14",
"juice": "^5.2.0",
"lodash": "^4.17.15",
"mjml-migrate": "4.5.0",
"mjml-parser-xml": "4.5.0",
"mjml-validator": "4.5.0"
},
"dependencies": {
"mjml-migrate": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.5.0.tgz",
"integrity": "sha512-zzAKSrGpF+OVoa3GHVS7O2A4WZPLBV/Nrc80MGaLS4hhBbuj2WeUdaugVlIMXRRuhQ+nP+k0fZSM8tonDDjd2w==",
"requires": {
"babel-runtime": "^6.26.0",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
}
}
}
},
"mjml-migrate": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-migrate/-/mjml-migrate-4.5.0.tgz",
"integrity": "sha512-zzAKSrGpF+OVoa3GHVS7O2A4WZPLBV/Nrc80MGaLS4hhBbuj2WeUdaugVlIMXRRuhQ+nP+k0fZSM8tonDDjd2w==",
"requires": {
"babel-runtime": "^6.26.0",
"commander": "^2.11.0",
"js-beautify": "^1.6.14",
"lodash": "^4.17.15",
"mjml-core": "4.5.0",
"mjml-parser-xml": "4.5.0"
}
},
"mjml-parser-xml": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-parser-xml/-/mjml-parser-xml-4.5.0.tgz",
"integrity": "sha512-9NK9TnkDSJ0M7lMv1vuGjZumi1rqdv4Iwr9rBDpBPUvfv9ay7MoJrQjK28cu6PKcamOK6CHAFXihlV9Q6fbYaA==",
"requires": {
"babel-runtime": "^6.26.0",
"htmlparser2": "^3.9.2",
"lodash": "^4.17.15"
},
"dependencies": {
"domelementtype": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
},
"domhandler": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
"integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
"requires": {
"domelementtype": "1"
}
},
"domutils": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
"integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
"requires": {
"dom-serializer": "0",
"domelementtype": "1"
}
},
"entities": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
"integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
},
"htmlparser2": {
"version": "3.10.1",
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
"integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
"requires": {
"domelementtype": "^1.3.1",
"domhandler": "^2.3.0",
"domutils": "^1.5.1",
"entities": "^1.1.1",
"inherits": "^2.0.1",
"readable-stream": "^3.1.1"
}
}
}
},
"mjml-validator": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.5.0.tgz",
"integrity": "sha512-Qbyf/VCk3U8ViLCu+VCwGYZVQaJAw5brKW/aXeRRHb10LdhaCF1S0JNIiNyutfnqn92QWdzYt6W+cbcEZIKa9A==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"warning": "^3.0.0"
}
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"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"
}
},
"valid-data-url": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/valid-data-url/-/valid-data-url-2.0.0.tgz",
"integrity": "sha512-dyCZnv3aCey7yfTgIqdZanKl7xWAEEKCbgmR7SKqyK6QT/Z07ROactrgD1eA37C69ODRj7rNOjzKWVPh0EUjBA=="
},
"web-resource-inliner": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/web-resource-inliner/-/web-resource-inliner-4.3.4.tgz",
"integrity": "sha512-agVAgRhOOi4GVlvKK34oM23tDgH8390HfLnZY2HZl8OFBwKNvUJkH7t89AT2iluQP8w9VHAAKX6Z8EN7/9tqKA==",
"requires": {
"async": "^3.1.0",
"chalk": "^2.4.2",
"datauri": "^2.0.0",
"htmlparser2": "^4.0.0",
"lodash.unescape": "^4.0.1",
"request": "^2.88.0",
"safer-buffer": "^2.1.2",
"valid-data-url": "^2.0.0",
"xtend": "^4.0.2"
}
},
"xtend": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
}
}
},
"mjml-navbar": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-navbar/-/mjml-navbar-4.6.2.tgz",
"integrity": "sha512-9PWzcgytAd2GWSkZX7F7RZKQ5aS0QHIiOMtMSNGJbj/d8Xksqn0S+5vN0uBWqYv231SunQBjvBCClGHceqMW1w==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-raw": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-raw/-/mjml-raw-4.6.2.tgz",
"integrity": "sha512-u/+Ql1iBWF0D4XSgasJoRzmV5g5UlP7cjUnPeslRjtFnZXWGQdRw8BFBCmvXkjAokSk22sQ+GgHEjP9ebshtdg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-section": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-section/-/mjml-section-4.6.2.tgz",
"integrity": "sha512-bhKPdYq3vo8aaXwZ9HkG8CG4ss0vPFTGJ/kFkqnnvYIuxLJjILSBb4UoktvN0xCp15vXvEjHS0eJv4rZiAjzFQ==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-social": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-social/-/mjml-social-4.6.2.tgz",
"integrity": "sha512-m++Ml0uWUby//i2hGz7FAfEamdx3PjPKGBOslHzKCY2Lpf2kvnDNNGzG/apKjUBtWRvlMHkkiCL2uJ05rvWdYg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-spacer": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-spacer/-/mjml-spacer-4.6.2.tgz",
"integrity": "sha512-U8tQY2Hwtbuw7wuLiYxNSwX7cH0olqVKolFdLMJZJf+TD2shbq/4XaPj6JXiBu6+OVeIsePPJtTVmh46oE0Kqg==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-table": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-table/-/mjml-table-4.6.2.tgz",
"integrity": "sha512-ZIG48ZRke30G9fd++YmC2NZuSohs2//STb6ozRIjp8ZcNGu8TVM837zUDnoSe5/iJ7O1kqMgwDx3oe5s4OOjdA==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-text": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-text/-/mjml-text-4.6.2.tgz",
"integrity": "sha512-zXTHOLgt10cMvV0Ez9S/3F8K1yn2JbGAaHF97SHAQYMlLxk3z2PCATaBvfIimYdaYj1A6qf0KbznRUFG8ZPDUw==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2"
}
},
"mjml-validator": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/mjml-validator/-/mjml-validator-4.2.0.tgz",
"integrity": "sha512-5TI4DUM5Eb08wjflsT/aEiuyGs2mHKmT0zzlJQcRVNSAGK2dstmBxKgF5ndS4UgvawCypHsa75kOJpg+llNaFw==",
"requires": {
"babel-runtime": "^6.26.0",
"cross-env": "^5.1.4",
"lodash": "^4.17.2",
"warning": "^3.0.0"
}
},
"mjml-wrapper": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/mjml-wrapper/-/mjml-wrapper-4.6.2.tgz",
"integrity": "sha512-jRSR43SoR7DZvygednfRiiqs+qLjPf20FHT/2RirMFbere4N+wsYQcq6Kbmn1ejq+MPIjkVucNzUif1B/7tJnQ==",
"requires": {
"babel-runtime": "^6.26.0",
"lodash": "^4.17.15",
"mjml-core": "4.6.2",
"mjml-section": "4.6.2"
}
},
"mkdirp": {
"version": "0.5.5",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
"requires": {
"minimist": "^1.2.5"
},
"dependencies": {
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}
}
},
"mkdirp-classic": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.2.tgz",
"integrity": "sha512-ejdnDQcR75gwknmMw/tx02AuRs8jCtqFoFqDZMjiNxsu85sRIJVXDKHuLYvUUPRBUtV2FpSZa9bL1BUa3BdR2g=="
},
"mocha": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/mocha/-/mocha-5.0.5.tgz",
"integrity": "sha512-3MM3UjZ5p8EJrYpG7s+29HAI9G7sTzKEe4+w37Dg0QP7qL4XGsV+Q2xet2cE37AqdgN1OtYQB6Vl98YiPV3PgA==",
"dev": true,
"requires": {
"browser-stdout": "1.3.1",
"commander": "2.11.0",
"debug": "3.1.0",
"diff": "3.5.0",
"escape-string-regexp": "1.0.5",
"glob": "7.1.2",
"growl": "1.10.3",
"he": "1.1.1",
"mkdirp": "0.5.1",
"supports-color": "4.4.0"
},
"dependencies": {
"commander": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.11.0.tgz",
"integrity": "sha512-b0553uYA5YAEGgyYIGYROzKQ7X5RAqedkfjiZxwi0kL1g3bOaBNNZfYkzt/CL0umgD5wc9Jec2FbB98CjkMRvQ==",
"dev": true
},
"has-flag": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
"integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=",
"dev": true
},
"mkdirp": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
"integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
"dev": true,
"requires": {
"minimist": "0.0.8"
}
},
"supports-color": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.4.0.tgz",
"integrity": "sha512-rKC3+DyXWgK0ZLKwmRsrkyHVZAjNkfzeehuFWdGGcqGDTZFH73+RH6S/RDAAxl9GusSjZSUWYLmT9N5pzXFOXQ==",
"dev": true,
"requires": {
"has-flag": "^2.0.0"
}
}
}
},
"mongodb": {
"version": "3.5.5",
"resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.5.5.tgz",
"integrity": "sha512-GCjDxR3UOltDq00Zcpzql6dQo1sVry60OXJY3TDmFc2SWFY6c8Gn1Ardidc5jDirvJrx2GC3knGOImKphbSL3A==",
"requires": {
"bl": "^2.2.0",
"bson": "^1.1.1",
"denque": "^1.4.1",
"require_optional": "^1.0.1",
"safe-buffer": "^5.1.2",
"saslprep": "^1.0.0"
},
"dependencies": {
"bl": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz",
"integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==",
"requires": {
"readable-stream": "^2.3.5",
"safe-buffer": "^5.1.1"
}
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
}
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"mute-stream": {
"version": "0.0.5",
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
"integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
"dev": true
},
"nan": {
"version": "2.10.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.10.0.tgz",
"integrity": "sha512-bAdJv7fBLhWC+/Bls0Oza+mvTaNQtP+1RyhhhvD95pgUJz6XM5IzgmxOkItJ9tkoCiplvAnXI1tNmmUD/eScyA==",
"dev": true,
"optional": true
},
"nanomatch": {
"version": "1.2.13",
"resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
"integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
"dev": true,
"optional": true,
"requires": {
"arr-diff": "^4.0.0",
"array-unique": "^0.3.2",
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"fragment-cache": "^0.2.1",
"is-windows": "^1.0.2",
"kind-of": "^6.0.2",
"object.pick": "^1.3.0",
"regex-not": "^1.0.0",
"snapdragon": "^0.8.1",
"to-regex": "^3.0.1"
},
"dependencies": {
"arr-diff": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
"integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
"dev": true,
"optional": true
},
"array-unique": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
"integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
"dev": true,
"optional": true
},
"kind-of": {
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
"integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
"dev": true,
"optional": true
}
}
},
"napi-build-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz",
"integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA=="
},
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
"dev": true
},
"needle": {
"version": "2.2.4",
"resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz",
"integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==",
"dev": true,
"optional": true,
"requires": {
"debug": "^2.1.2",
"iconv-lite": "^0.4.4",
"sax": "^1.2.4"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"optional": true,
"requires": {
"ms": "2.0.0"
}
}
}
},
"next-tick": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
"integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
"dev": true
},
"nice-try": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"nigel": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/nigel/-/nigel-3.0.1.tgz",
"integrity": "sha512-kCVtUG9JyD//tsYrZY+/Y+2gUrANVSba8y23QkM5Znx0FOxlnl9Z4OVPBODmstKWTOvigfTO+Va1VPOu3eWSOQ==",
"requires": {
"hoek": "5.x.x",
"vise": "3.x.x"
},
"dependencies": {
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"nise": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/nise/-/nise-4.0.3.tgz",
"integrity": "sha512-EGlhjm7/4KvmmE6B/UFsKh7eHykRl9VH+au8dduHLCyWUO/hr7+N+WtTvDUwc9zHuM1IaIJs/0lQ6Ag1jDkQSg==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.0",
"@sinonjs/fake-timers": "^6.0.0",
"@sinonjs/text-encoding": "^0.7.1",
"just-extend": "^4.0.2",
"path-to-regexp": "^1.7.0"
}
},
"no-case": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
"integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
"requires": {
"lower-case": "^1.1.1"
}
},
"node-abi": {
"version": "2.11.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.11.0.tgz",
"integrity": "sha512-kuy/aEg75u40v378WRllQ4ZexaXJiCvB68D2scDXclp/I4cRq6togpbOoKhmN07tns9Zldu51NNERo0wehfX9g==",
"requires": {
"semver": "^5.4.1"
}
},
"node-pre-gyp": {
"version": "0.10.3",
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz",
"integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==",
"dev": true,
"optional": true,
"requires": {
"detect-libc": "^1.0.2",
"mkdirp": "^0.5.1",
"needle": "^2.2.1",
"nopt": "^4.0.1",
"npm-packlist": "^1.1.6",
"npmlog": "^4.0.2",
"rc": "^1.2.7",
"rimraf": "^2.6.1",
"semver": "^5.3.0",
"tar": "^4"
},
"dependencies": {
"nopt": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"dev": true,
"optional": true,
"requires": {
"abbrev": "1",
"osenv": "^0.1.4"
}
}
}
},
"node-releases": {
"version": "1.0.0-alpha.14",
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.0.0-alpha.14.tgz",
"integrity": "sha512-G8nnF9cP9QPP/jUmYWw/uUUhumHmkm+X/EarCugYFjYm2uXRMFeOD6CVT3RLdoyCvDUNy51nirGfUItKWs/S1g==",
"dev": true,
"requires": {
"semver": "^5.3.0"
}
},
"node-uuid": {
"version": "1.4.8",
"resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz",
"integrity": "sha1-sEDrCSOWivq/jTL7HxfxFn/auQc="
},
"nodemailer": {
"version": "6.4.6",
"resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.4.6.tgz",
"integrity": "sha512-/kJ+FYVEm2HuUlw87hjSqTss+GU35D4giOpdSfGp7DO+5h6RlJj7R94YaYHOkoxu1CSaM0d3WRBtCzwXrY6MKA=="
},
"noop-logger": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
"integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI="
},
"nopt": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
"integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
"requires": {
"abbrev": "1",
"osenv": "^0.1.4"
}
},
"normalize-path": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
"integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
"dev": true,
"optional": true,
"requires": {
"remove-trailing-separator": "^1.0.1"
}
},
"npm-bundled": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz",
"integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==",
"dev": true,
"optional": true
},
"npm-packlist": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.1.11.tgz",
"integrity": "sha512-CxKlZ24urLkJk+9kCm48RTQ7L4hsmgSVzEk0TLGPzzyuFxD7VNgy5Sl24tOLMzQv773a/NeJ1ce1DKeacqffEA==",
"dev": true,
"optional": true,
"requires": {
"ignore-walk": "^3.0.1",
"npm-bundled": "^1.0.1"
}
},
"npmlog": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
"gauge": "~2.7.3",
"set-blocking": "~2.0.0"
}
},
"nth-check": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
"integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=",
"requires": {
"boolbase": "~1.0.0"
}
},
"number-is-nan": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
"object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
},
"object-copy": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
"integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
"dev": true,
"optional": true,
"requires": {
"copy-descriptor": "^0.1.0",
"define-property": "^0.2.5",
"kind-of": "^3.0.3"
},
"dependencies": {
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
"dev": true,
"optional": true,
"requires": {
"is-descriptor": "^0.1.0"
}
}
}
},
"object-hash": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.0.3.tgz",
"integrity": "sha512-JPKn0GMu+Fa3zt3Bmr66JhokJU5BaNBIh4ZeTlaCBzrBsOeXzwcKKAK1tbLiPKgvwmPXsDvvLHoWh5Bm7ofIYg=="
},
"object-visit": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
"integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
"dev": true,
"optional": true,
"requires": {
"isobject": "^3.0.0"
},
"dependencies": {
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
}
}
},
"object.pick": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
"integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
"dev": true,
"optional": true,
"requires": {
"isobject": "^3.0.1"
},
"dependencies": {
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
}
}
},
"once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
"requires": {
"wrappy": "1"
}
},
"one-time": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/one-time/-/one-time-0.0.4.tgz",
"integrity": "sha1-+M33eISCb+Tf+T46nMN7HkSAdC4="
},
"onetime": {
"version": "1.1.0",
"resolved": "http://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
"integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
"dev": true
},
"optionator": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
"integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
"dev": true,
"requires": {
"deep-is": "~0.1.3",
"fast-levenshtein": "~2.0.4",
"levn": "~0.3.0",
"prelude-ls": "~1.1.2",
"type-check": "~0.3.2",
"wordwrap": "~1.0.0"
}
},
"os-homedir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
},
"os-tmpdir": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
},
"osenv": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
"requires": {
"os-homedir": "^1.0.0",
"os-tmpdir": "^1.0.0"
}
},
"param-case": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
"integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
"requires": {
"no-case": "^2.2.0"
}
},
"parse-ms": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-2.1.0.tgz",
"integrity": "sha512-kHt7kzLoS9VBZfUsiKjv43mr91ea+U05EyKkEtqp7vNbHxmaVuEqN7XxeEVnGrMtYOAxGrDElSi96K7EgO1zCA=="
},
"pascalcase": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
"integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
"dev": true,
"optional": true
},
"path-dirname": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
"integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
"dev": true,
"optional": true
},
"path-exists": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
"integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
},
"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="
},
"path-is-inside": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
"integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
"dev": true
},
"path-key": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
},
"path-parse": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
"integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
},
"path-to-regexp": {
"version": "1.8.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz",
"integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==",
"dev": true,
"requires": {
"isarray": "0.0.1"
},
"dependencies": {
"isarray": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
"integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=",
"dev": true
}
}
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
},
"pez": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/pez/-/pez-4.0.2.tgz",
"integrity": "sha512-HuPxmGxHsEFPWhdkwBs2gIrHhFqktIxMtudISTFN95RQ85ZZAOl8Ki6u3nnN/X8OUaGlIGldk/l8p2IR4/i76w==",
"requires": {
"b64": "4.x.x",
"boom": "7.x.x",
"content": "4.x.x",
"hoek": "5.x.x",
"nigel": "3.x.x"
},
"dependencies": {
"boom": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-7.2.0.tgz",
"integrity": "sha1-K/8kpVVldn/ehp7ICDF+sQxI6WY=",
"requires": {
"hoek": "5.x.x"
}
},
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"picomatch": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz",
"integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg=="
},
"pify": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
"dev": true
},
"pinkie": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
"integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
"dev": true
},
"pinkie-promise": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
"integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
"dev": true,
"requires": {
"pinkie": "^2.0.0"
}
},
"pluralize": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz",
"integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=",
"dev": true
},
"posix-character-classes": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
"integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
"dev": true,
"optional": true
},
"postcss": {
"version": "6.0.21",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.21.tgz",
"integrity": "sha512-y/bKfbQz2Nn/QBC08bwvYUxEFOVGfPIUOTsJ2CK5inzlXW9SdYR1x4pEsG9blRAF/PX+wRNdOah+gx/hv4q7dw==",
"requires": {
"chalk": "^2.3.2",
"source-map": "^0.6.1",
"supports-color": "^5.3.0"
},
"dependencies": {
"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"
}
},
"chalk": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
"integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
},
"supports-color": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz",
"integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"prebuild-install": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz",
"integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==",
"requires": {
"detect-libc": "^1.0.3",
"expand-template": "^2.0.3",
"github-from-package": "0.0.0",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"napi-build-utils": "^1.0.1",
"node-abi": "^2.7.0",
"noop-logger": "^0.1.1",
"npmlog": "^4.0.1",
"pump": "^3.0.0",
"rc": "^1.2.7",
"simple-get": "^3.0.3",
"tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0",
"which-pm-runs": "^1.0.0"
},
"dependencies": {
"bl": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz",
"integrity": "sha512-j4OH8f6Qg2bGuWfRiltT2HYGx0e1QcBTrK9KAHNMwMZdQnDZFk0ZSYIpADjYCB3U12nicC5tVJwSIhwOWjb4RQ==",
"requires": {
"buffer": "^5.5.0",
"inherits": "^2.0.4",
"readable-stream": "^3.4.0"
},
"dependencies": {
"inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
}
}
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
},
"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"
}
},
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
},
"tar-fs": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz",
"integrity": "sha512-6tzWDMeroL87uF/+lin46k+Q+46rAJ0SyPGz7OW7wTgblI273hsBqk2C1j0/xNadNLKDTUL9BukSjB7cwgmlPA==",
"requires": {
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
"pump": "^3.0.0",
"tar-stream": "^2.0.0"
}
},
"tar-stream": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz",
"integrity": "sha512-UaF6FoJ32WqALZGOIAApXx+OdxhekNMChu6axLJR85zMMjXKWFGjbIRe+J6P4UnRGg9rAwWvbTT0oI7hD/Un7Q==",
"requires": {
"bl": "^4.0.1",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
}
}
}
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
"integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
"dev": true
},
"prettier": {
- "version": "1.18.2",
- "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz",
- "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==",
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.0.5.tgz",
+ "integrity": "sha512-7PtVymN48hGcO4fGjybyBSIWDsLU4H4XlvOHfq91pz9kkGlonzwTfYkaIEwiRg/dAJF9YlbsduBAgtYLi+8cFg==",
"dev": true
},
"pretty-ms": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-7.0.0.tgz",
"integrity": "sha512-J3aPWiC5e9ZeZFuSeBraGxSkGMOvulSWsxDByOcbD1Pr75YL3LSNIKIb52WXbCLE1sS5s4inBBbryjF4Y05Ceg==",
"requires": {
"parse-ms": "^2.1.0"
}
},
"private": {
"version": "0.1.8",
"resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
"integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
"dev": true
},
"process-nextick-args": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
"integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
},
"progress": {
"version": "1.1.8",
"resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
"integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
"dev": true
},
"proto-list": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz",
"integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk="
},
"pseudomap": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
"integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
},
"psl": {
"version": "1.1.29",
"resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz",
"integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ=="
},
"punycode": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
"integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
},
"qs": {
"version": "6.5.1",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
"integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
},
"rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"requires": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"dependencies": {
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"minimist": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
}
}
},
"readable-stream": {
"version": "2.3.5",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.5.tgz",
"integrity": "sha512-tK0yDhrkygt/knjowCUiWP9YdV7c5R+8cR0r/kt9ZhBU906Fs6RpQJCEilamRJj1Nx2rWI6LkW9gKqjTkshhEw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.0.3",
"util-deprecate": "~1.0.1"
}
},
"readdirp": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
"integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
"dev": true,
"optional": true,
"requires": {
"graceful-fs": "^4.1.2",
"minimatch": "^3.0.2",
"readable-stream": "^2.0.2",
"set-immediate-shim": "^1.0.1"
}
},
"readline2": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
"integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
"dev": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
"mute-stream": "0.0.5"
}
},
"rechoir": {
"version": "0.6.2",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
"integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
"dev": true,
"requires": {
"resolve": "^1.1.6"
}
},
"regenerate": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
"integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==",
"dev": true
},
"regenerate-unicode-properties": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-7.0.0.tgz",
"integrity": "sha512-s5NGghCE4itSlUS+0WUj88G6cfMVMmH8boTPNvABf8od+2dhT9WDlWu8n01raQAJZMOK8Ch6jSexaRO7swd6aw==",
"dev": true,
"requires": {
"regenerate": "^1.4.0"
}
},
"regenerator-runtime": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
"integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
},
"regex-not": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
"integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
"dev": true,
"optional": true,
"requires": {
"extend-shallow": "^3.0.2",
"safe-regex": "^1.1.0"
}
},
"relateurl": {
"version": "0.2.7",
"resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
"integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
},
"remove-trailing-separator": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
"integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
"dev": true,
"optional": true
},
"repeat-element": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
"integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
"dev": true,
"optional": true
},
"repeat-string": {
"version": "1.6.1",
"resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
"integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
"dev": true,
"optional": true
},
"request": {
"version": "2.88.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
"integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.0",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.4.3",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
},
"dependencies": {
"mime-db": {
"version": "1.37.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz",
"integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg=="
},
"mime-types": {
"version": "2.1.21",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz",
"integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==",
"requires": {
"mime-db": "~1.37.0"
}
},
"qs": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
"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=="
},
"tough-cookie": {
"version": "2.4.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
"integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
"requires": {
"psl": "^1.1.24",
"punycode": "^1.4.1"
}
},
"uuid": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
}
}
},
"require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
},
"require-uncached": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
"integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
"dev": true,
"requires": {
"caller-path": "^0.1.0",
"resolve-from": "^1.0.0"
},
"dependencies": {
"resolve-from": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
"integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
"dev": true
}
}
},
"require_optional": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
"integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
"requires": {
"resolve-from": "^2.0.0",
"semver": "^5.1.0"
}
},
"resolve": {
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.6.0.tgz",
"integrity": "sha512-mw7JQNu5ExIkcw4LPih0owX/TZXjD/ZUF/ZQ/pDnkw3ZKhDcZZw5klmBlj6gVMwjQ3Pz5Jgu7F3d0jcDVuEWdw==",
"requires": {
"path-parse": "^1.0.5"
}
},
"resolve-from": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
"integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
},
"resolve-url": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
"integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
"dev": true,
"optional": true
},
"restore-cursor": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
"integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
"dev": true,
"requires": {
"exit-hook": "^1.0.0",
"onetime": "^1.0.0"
}
},
"ret": {
"version": "0.1.15",
"resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
"integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
"dev": true,
"optional": true
},
"rimraf": {
"version": "2.6.2",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
"integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
"dev": true,
"requires": {
"glob": "^7.0.5"
}
},
"run-async": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
"integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=",
"dev": true,
"requires": {
"once": "^1.3.0"
}
},
"rx-lite": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz",
"integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=",
"dev": true
},
"safe-buffer": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
"integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
},
"safe-regex": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
"integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
"dev": true,
"optional": true,
"requires": {
"ret": "~0.1.10"
}
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sanitize-html": {
"version": "1.18.2",
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-1.18.2.tgz",
"integrity": "sha512-52ThA+Z7h6BnvpSVbURwChl10XZrps5q7ytjTwWcIe9bmJwnVP6cpEVK2NvDOUhGupoqAvNbUz3cpnJDp4+/pg==",
"requires": {
"chalk": "^2.3.0",
"htmlparser2": "^3.9.0",
"lodash.clonedeep": "^4.5.0",
"lodash.escaperegexp": "^4.1.2",
"lodash.isplainobject": "^4.0.6",
"lodash.isstring": "^4.0.1",
"lodash.mergewith": "^4.6.0",
"postcss": "^6.0.14",
"srcset": "^1.0.0",
"xtend": "^4.0.0"
},
"dependencies": {
"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"
}
},
"chalk": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz",
"integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==",
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"supports-color": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz",
"integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==",
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"saslprep": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
"integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
"optional": true,
"requires": {
"sparse-bitfield": "^3.0.3"
}
},
"sax": {
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
"dev": true,
"optional": true
},
"semver": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz",
"integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA=="
},
"set-blocking": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
},
"set-immediate-shim": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
"integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
"dev": true,
"optional": true
},
"set-value": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
"integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
"dev": true,
"optional": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.3",
"split-string": "^3.0.1"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"sharp": {
"version": "0.23.0",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.23.0.tgz",
"integrity": "sha512-3+QlktTYDPO9CLmB3DUaBSj729ic3R9TO5Bz318F8WubUW10HR4os0Tm+GdYNcVg0layhMhP4Hf2SILwXVG2ig==",
"requires": {
"color": "^3.1.2",
"detect-libc": "^1.0.3",
"nan": "^2.14.0",
"npmlog": "^4.1.2",
"prebuild-install": "^5.3.0",
"semver": "^6.3.0",
"simple-get": "^3.0.3",
"tar": "^4.4.10",
"tunnel-agent": "^0.6.0"
},
"dependencies": {
"minipass": {
"version": "2.9.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
}
},
"minizlib": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
"requires": {
"minipass": "^2.9.0"
}
},
"nan": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
},
"tar": {
"version": "4.4.13",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
"integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
"requires": {
"chownr": "^1.1.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.8.6",
"minizlib": "^1.2.1",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.3"
}
},
"yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
}
}
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
"integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
"requires": {
"shebang-regex": "^1.0.0"
}
},
"shebang-regex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
"integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
},
"shelljs": {
"version": "0.7.8",
"resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
"integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
"dev": true,
"requires": {
"glob": "^7.0.0",
"interpret": "^1.0.0",
"rechoir": "^0.6.2"
}
},
"shortid": {
"version": "2.2.8",
"resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.8.tgz",
"integrity": "sha1-AzsRfWoul1gE9vCWnb59PQs1UTE="
},
"sigmund": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz",
"integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA="
},
"signal-exit": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"simple-concat": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
},
"simple-get": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.0.3.tgz",
"integrity": "sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw==",
"requires": {
"decompress-response": "^3.3.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"requires": {
"is-arrayish": "^0.3.1"
}
},
"sinon": {
"version": "9.0.2",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-9.0.2.tgz",
"integrity": "sha512-0uF8Q/QHkizNUmbK3LRFqx5cpTttEVXudywY9Uwzy8bTfZUhljZ7ARzSxnRHWYWtVTeh4Cw+tTb3iU21FQVO9A==",
"dev": true,
"requires": {
"@sinonjs/commons": "^1.7.2",
"@sinonjs/fake-timers": "^6.0.1",
"@sinonjs/formatio": "^5.0.1",
"@sinonjs/samsam": "^5.0.3",
"diff": "^4.0.2",
"nise": "^4.0.1",
"supports-color": "^7.1.0"
},
"dependencies": {
"diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true
},
"has-flag": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
"dev": true
},
"supports-color": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz",
"integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==",
"dev": true,
"requires": {
"has-flag": "^4.0.0"
}
}
}
},
"slice-ansi": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
"integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
"dev": true
},
"slick": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/slick/-/slick-1.12.2.tgz",
"integrity": "sha1-vQSN23TefRymkV+qSldXCzVQwtc="
},
"snapdragon": {
"version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
"integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
"dev": true,
"optional": true,
"requires": {
"base": "^0.11.1",
"debug": "^2.2.0",
"define-property": "^0.2.5",
"extend-shallow": "^2.0.1",
"map-cache": "^0.2.2",
"source-map": "^0.5.6",
"source-map-resolve": "^0.5.0",
"use": "^3.1.0"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"dev": true,
"optional": true,
"requires": {
"ms": "2.0.0"
}
},
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
"dev": true,
"optional": true,
"requires": {
"is-descriptor": "^0.1.0"
}
},
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
}
}
},
"snapdragon-node": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
"integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
"dev": true,
"optional": true,
"requires": {
"define-property": "^1.0.0",
"isobject": "^3.0.0",
"snapdragon-util": "^3.0.1"
},
"dependencies": {
"define-property": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
"integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
"dev": true,
"optional": true,
"requires": {
"is-descriptor": "^1.0.0"
}
},
"is-accessor-descriptor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
"integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^6.0.0"
}
},
"is-data-descriptor": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
"integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^6.0.0"
}
},
"is-descriptor": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
"integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
"dev": true,
"optional": true,
"requires": {
"is-accessor-descriptor": "^1.0.0",
"is-data-descriptor": "^1.0.0",
"kind-of": "^6.0.2"
}
},
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
},
"kind-of": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
"integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
"dev": true,
"optional": true
}
}
},
"snapdragon-util": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
"integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.2.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
},
"source-map-resolve": {
"version": "0.5.2",
"resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
"integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
"dev": true,
"optional": true,
"requires": {
"atob": "^2.1.1",
"decode-uri-component": "^0.2.0",
"resolve-url": "^0.2.1",
"source-map-url": "^0.4.0",
"urix": "^0.1.0"
}
},
"source-map-url": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
"integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
"dev": true,
"optional": true
},
"sparse-bitfield": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
"integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
"optional": true,
"requires": {
"memory-pager": "^1.0.2"
}
},
"split-string": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
"integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
"dev": true,
"optional": true,
"requires": {
"extend-shallow": "^3.0.0"
}
},
"sprintf-js": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
"dev": true
},
"srcset": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/srcset/-/srcset-1.0.0.tgz",
"integrity": "sha1-pWad4StC87HV6D7QPHEEb8SPQe8=",
"requires": {
"array-uniq": "^1.0.2",
"number-is-nan": "^1.0.0"
}
},
"sshpk": {
"version": "1.15.1",
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.1.tgz",
"integrity": "sha512-mSdgNUaidk+dRU5MhYtN9zebdzF2iG0cNPWy8HG+W8y+fT1JnSkh0fzzpjOa0L7P8i1Rscz38t0h4gPcKz43xA==",
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
}
},
"stack-trace": {
"version": "0.0.10",
"resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz",
"integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
},
"static-extend": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
"integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
"dev": true,
"optional": true,
"requires": {
"define-property": "^0.2.5",
"object-copy": "^0.1.0"
},
"dependencies": {
"define-property": {
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
"integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
"dev": true,
"optional": true,
"requires": {
"is-descriptor": "^0.1.0"
}
}
}
},
"string-width": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
"requires": {
"is-fullwidth-code-point": "^2.0.0",
"strip-ansi": "^4.0.0"
},
"dependencies": {
"ansi-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
},
"is-fullwidth-code-point": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
},
"strip-ansi": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
"requires": {
"ansi-regex": "^3.0.0"
}
}
}
},
"string_decoder": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
"integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
"requires": {
"safe-buffer": "~5.1.0"
}
},
"strip-ansi": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"requires": {
"ansi-regex": "^2.0.0"
}
},
"strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
"dev": true
},
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
},
"table": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
"integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
"dev": true,
"requires": {
"ajv": "^4.7.0",
"ajv-keywords": "^1.0.0",
"chalk": "^1.1.1",
"lodash": "^4.0.0",
"slice-ansi": "0.0.4",
"string-width": "^2.0.0"
},
"dependencies": {
"ajv": {
"version": "4.11.8",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
"integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
"dev": true,
"requires": {
"co": "^4.6.0",
"json-stable-stringify": "^1.0.1"
}
},
"lodash": {
"version": "4.17.15",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
"dev": true
}
}
},
"tar": {
"version": "4.4.6",
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.6.tgz",
"integrity": "sha512-tMkTnh9EdzxyfW+6GK6fCahagXsnYk6kE6S9Gr9pjVdys769+laCTbodXDhPAjzVtEBazRgP0gYqOjnk9dQzLg==",
"dev": true,
"optional": true,
"requires": {
"chownr": "^1.0.1",
"fs-minipass": "^1.2.5",
"minipass": "^2.3.3",
"minizlib": "^1.1.0",
"mkdirp": "^0.5.0",
"safe-buffer": "^5.1.2",
"yallist": "^3.0.2"
},
"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,
"optional": true
},
"yallist": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.2.tgz",
"integrity": "sha1-hFK0u36Dx8GI2AQcGoN8dz1ti7k=",
"dev": true,
"optional": true
}
}
},
"teamwork": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/teamwork/-/teamwork-3.0.1.tgz",
"integrity": "sha512-hEkJIpDOfOYe9NYaLFk00zQbzZeKNCY8T2pRH3I13Y1mJwxaSQ6NEsjY5rCp+11ezCiZpWGoGFTbOuhg4qKevQ=="
},
"text-hex": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz",
"integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="
},
"text-table": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
"integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
"dev": true
},
"through": {
"version": "2.3.8",
"resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
"integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=",
"dev": true
},
"to-object-path": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
"integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2"
}
},
"to-regex": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
"integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
"dev": true,
"optional": true,
"requires": {
"define-property": "^2.0.2",
"extend-shallow": "^3.0.2",
"regex-not": "^1.0.2",
"safe-regex": "^1.1.0"
}
},
"to-regex-range": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
"integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
"dev": true,
"optional": true,
"requires": {
"is-number": "^3.0.0",
"repeat-string": "^1.6.1"
},
"dependencies": {
"is-number": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
"integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
"dev": true,
"optional": true,
"requires": {
"kind-of": "^3.0.2"
}
}
}
},
"topo": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/topo/-/topo-3.0.0.tgz",
"integrity": "sha512-Tlu1fGlR90iCdIPURqPiufqAlCZYzLjHYVVbcFWDMcX7+tK8hdZWAfsMrD/pBul9jqHHwFjNdf1WaxA9vTRRhw==",
"requires": {
"hoek": "5.x.x"
},
"dependencies": {
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"tough-cookie": {
"version": "2.3.4",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz",
"integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==",
"requires": {
"punycode": "^1.4.1"
}
},
"trim-right": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
"integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
"dev": true
},
"triple-beam": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.3.0.tgz",
"integrity": "sha512-XrHUvV5HpdLmIj4uVMxHggLbFSZYIn7HEWsqePZcI50pco+MPqJ50wMGY794X7AOOhxOBAjbkqfAbEe/QMp2Lw=="
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
},
"type-check": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
"integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
"dev": true,
"requires": {
"prelude-ls": "~1.1.2"
}
},
"type-detect": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz",
"integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==",
"dev": true
},
"typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
"dev": true
},
"typescript": {
"version": "3.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-3.8.3.tgz",
"integrity": "sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w==",
"dev": true
},
"uglify-js": {
"version": "3.4.9",
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.9.tgz",
"integrity": "sha512-8CJsbKOtEbnJsTyv6LE6m6ZKniqMiFWmm9sRbopbkGs3gMPPfd3Fh8iIA4Ykv5MgaTbqHr4BaoGLJLZNhsrW1Q==",
"requires": {
"commander": "~2.17.1",
"source-map": "~0.6.1"
},
"dependencies": {
"commander": {
"version": "2.17.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
"integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg=="
},
"source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
}
}
},
"unicode-canonical-property-names-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz",
"integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==",
"dev": true
},
"unicode-match-property-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz",
"integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==",
"dev": true,
"requires": {
"unicode-canonical-property-names-ecmascript": "^1.0.4",
"unicode-property-aliases-ecmascript": "^1.0.4"
}
},
"unicode-match-property-value-ecmascript": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.0.2.tgz",
"integrity": "sha512-Rx7yODZC1L/T8XKo/2kNzVAQaRE88AaMvI1EF/Xnj3GW2wzN6fop9DDWuFAKUVFH7vozkz26DzP0qyWLKLIVPQ==",
"dev": true
},
"unicode-property-aliases-ecmascript": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.4.tgz",
"integrity": "sha512-2WSLa6OdYd2ng8oqiGIWnJqyFArvhn+5vgx5GTxMbUYjCYKUcuKS62YLFF0R/BDGlB1yzXjQOLtPAfHsgirEpg==",
"dev": true
},
"union-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.0.tgz",
"integrity": "sha1-XHHDTLW61dzr4+oM0IIHulqhrqQ=",
"dev": true,
"optional": true,
"requires": {
"arr-union": "^3.1.0",
"get-value": "^2.0.6",
"is-extendable": "^0.1.1",
"set-value": "^0.4.3"
},
"dependencies": {
"extend-shallow": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
"integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
"dev": true,
"optional": true,
"requires": {
"is-extendable": "^0.1.0"
}
},
"set-value": {
"version": "0.4.3",
"resolved": "https://registry.npmjs.org/set-value/-/set-value-0.4.3.tgz",
"integrity": "sha1-fbCPnT0i3H945Trzw79GZuzfzPE=",
"dev": true,
"optional": true,
"requires": {
"extend-shallow": "^2.0.1",
"is-extendable": "^0.1.1",
"is-plain-object": "^2.0.1",
"to-object-path": "^0.3.0"
}
}
}
},
"unset-value": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
"integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
"dev": true,
"optional": true,
"requires": {
"has-value": "^0.3.1",
"isobject": "^3.0.0"
},
"dependencies": {
"has-value": {
"version": "0.3.1",
"resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
"integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
"dev": true,
"optional": true,
"requires": {
"get-value": "^2.0.3",
"has-values": "^0.1.4",
"isobject": "^2.0.0"
},
"dependencies": {
"isobject": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
"integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
"dev": true,
"optional": true,
"requires": {
"isarray": "1.0.0"
}
}
}
},
"has-values": {
"version": "0.1.4",
"resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
"integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
"dev": true,
"optional": true
},
"isobject": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
"integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
"dev": true,
"optional": true
}
}
},
"upath": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz",
"integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==",
"dev": true,
"optional": true
},
"upper-case": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
"integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
},
"urix": {
"version": "0.1.0",
"resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
"integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
"dev": true,
"optional": true
},
"use": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
"integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
"dev": true,
"optional": true
},
"user-home": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
"integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=",
"dev": true,
"requires": {
"os-homedir": "^1.0.0"
}
},
"util-deprecate": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
"integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"vise": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/vise/-/vise-3.0.0.tgz",
"integrity": "sha512-kBFZLmiL1Vm3rHXphkhvvAcsjgeQXRrOFCbJb0I50YZZP4HGRNH+xGzK3matIMcpbsfr3I02u9odj4oCD0TWgA==",
"requires": {
"hoek": "5.x.x"
},
"dependencies": {
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"warning": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz",
"integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=",
"requires": {
"loose-envify": "^1.0.0"
}
},
"which": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
"integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
"requires": {
"isexe": "^2.0.0"
}
},
"which-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
},
"which-pm-runs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
"integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs="
},
"wide-align": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"requires": {
"string-width": "^1.0.2 || 2"
}
},
"winston": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/winston/-/winston-3.2.1.tgz",
"integrity": "sha512-zU6vgnS9dAWCEKg/QYigd6cgMVVNwyTzKs81XZtTFuRwJOcDdBg7AU0mXVyNbs7O5RH2zdv+BdNZUlx7mXPuOw==",
"requires": {
"async": "^2.6.1",
"diagnostics": "^1.1.1",
"is-stream": "^1.1.0",
"logform": "^2.1.1",
"one-time": "0.0.4",
"readable-stream": "^3.1.1",
"stack-trace": "0.0.x",
"triple-beam": "^1.3.0",
"winston-transport": "^4.3.0"
},
"dependencies": {
"readable-stream": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
"integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
},
"safe-buffer": {
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
"integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg=="
},
"string_decoder": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
"integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
"requires": {
"safe-buffer": "~5.2.0"
}
}
}
},
"winston-transport": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.3.0.tgz",
"integrity": "sha512-B2wPuwUi3vhzn/51Uukcao4dIduEiPOcOt9HJ3QeaXgkJ5Z7UwpBzxS4ZGNHtrxrUvTwemsQiSys0ihOf8Mp1A==",
"requires": {
"readable-stream": "^2.3.6",
"triple-beam": "^1.2.0"
},
"dependencies": {
"readable-stream": {
"version": "2.3.7",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
"requires": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
"isarray": "~1.0.0",
"process-nextick-args": "~2.0.0",
"safe-buffer": "~5.1.1",
"string_decoder": "~1.1.1",
"util-deprecate": "~1.0.1"
}
},
"string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"requires": {
"safe-buffer": "~5.1.0"
}
}
}
},
"wordwrap": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
"integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
"dev": true
},
"wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
},
"wreck": {
"version": "14.0.2",
"resolved": "https://registry.npmjs.org/wreck/-/wreck-14.0.2.tgz",
"integrity": "sha512-QCm3omWNJUseqrSzwX2QZi1rBbmCfbFHJAXputLLyZ37VSiFnSYQB0ms/mPnSvrlIu7GVm89Y/gBNhSY26uVIQ==",
"requires": {
"boom": "7.x.x",
"hoek": "5.x.x"
},
"dependencies": {
"boom": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/boom/-/boom-7.2.0.tgz",
"integrity": "sha1-K/8kpVVldn/ehp7ICDF+sQxI6WY=",
"requires": {
"hoek": "5.x.x"
}
},
"hoek": {
"version": "5.0.3",
"resolved": "https://registry.npmjs.org/hoek/-/hoek-5.0.3.tgz",
"integrity": "sha512-Bmr56pxML1c9kU+NS51SMFkiVQAb+9uFfXwyqR2tn4w2FPvmPt65eZ9aCcEfRXd9G74HkZnILC6p967pED4aiw=="
}
}
},
"write": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
"integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
"dev": true,
"requires": {
"mkdirp": "^0.5.1"
}
},
"xtend": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
"integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
},
"yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
"integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
}
}
}
diff --git a/package.json b/package.json
index 89faf92c..6050e386 100644
--- a/package.json
+++ b/package.json
@@ -1,81 +1,81 @@
{
"name": "sealious",
"homepage": "http://sealious.github.io/",
"version": "0.10.11",
"description": "A declarative framework for fast & easy app development.",
"main": "./lib/main.js",
"scripts": {
"test": "mocha --timeout=10000 setup-test.js \"./common_lib/**/*.test.js\" \"./lib/**/*.test.js\"",
"stress-test": "mocha --timeout=20000 setup-test.js \"./stress_test/**/*.test.js\"",
"build": "tsc"
},
"repository": {
"type": "git",
"url": "https://github.com/sealcode/sealious"
},
"author": "The Sealious team (http://github.com/Sealious)",
"license": "BSD-2-Clause",
"bugs": {
"url": "https://github.com/Sealious/Sealious/issues"
},
"dependencies": {
"@3846masa/axios-cookiejar-support": "^0.1.4",
"@babel/polyfill": "^7.0.0",
"@types/bluebird": "^3.5.30",
"@types/clone": "^0.1.30",
"@types/color": "^3.0.1",
"@types/object-hash": "^1.3.3",
"@types/sharp": "^0.25.0",
"axios": "^0.18.1",
"bluebird": "^3.4.6",
"boom": "^7.3.0",
"clone": "^1.0.2",
"color": "latest",
"deep-equal": "^1.0.1",
"deepmerge": "^4.2.2",
"dot-prop": "^5.2.0",
"escape-html": "^1.0.3",
"events": "^2.0.0",
"expand-hash": "^1.0.1",
"gm": "^1.23.0",
"hapi": "^17.5.2",
"inert": "^5.1.0",
"locreq": "^1.1.0",
"mime": "^2.4.6",
"mjml": "^4.2.0",
"mongodb": "^3.5.5",
"node-uuid": "^1.4.7",
"nodemailer": "^6.4.6",
"object-hash": "^2.0.3",
"pretty-ms": "^7.0.0",
"qs": "^6.5.1",
"resolve": "^1.1.7",
"sanitize-html": "^1.13.0",
"sharp": "^0.23.0",
"shortid": "^2.2.6",
"tough-cookie": "^2.3.4",
"winston": "^3.2.1"
},
"devDependencies": {
"@babel/cli": "^7.0.0",
"@babel/core": "^7.0.0",
"@babel/plugin-proposal-object-rest-spread": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@babel/preset-react": "^7.0.0",
"@types/boom": "^7.3.0",
"@types/escape-html": "^1.0.0",
"@types/mime": "^2.0.2",
"@types/mjml": "^4.0.4",
"@types/mocha": "^7.0.2",
"@types/mongodb": "^3.5.20",
"@types/node": "^13.13.4",
"@types/nodemailer": "^6.4.0",
"@types/shortid": "0.0.29",
"@types/sinon": "^9.0.4",
"eslint": "^3.1.1",
"mocha": "*",
- "prettier": "^1.18.2",
- "typescript": "^3.8.3",
- "sinon": "^9.0.2"
+ "prettier": "^2.0.5",
+ "sinon": "^9.0.2",
+ "typescript": "^3.8.3"
}
}
diff --git a/src/action.ts b/src/action.ts
index 197a243e..f76ef6bb 100644
--- a/src/action.ts
+++ b/src/action.ts
@@ -1,35 +1,35 @@
-import SubjectPath from "./data-structures/subject-path.js";
-import Subject from "./subject/subject.js";
+import SubjectPath from "./data-structures/subject-path";
+import Subject from "./subject/subject";
export type ShowActionName = "show";
export type CreateActionName = "create";
export type EditActionName = "edit";
export type ReplaceActionName = "replace";
export type DeleteActionName = "delete";
export type ActionName =
| ShowActionName
| CreateActionName
| EditActionName
| ReplaceActionName
| DeleteActionName;
export default class Action {
subject_path: SubjectPath;
action_name: ActionName;
RootSubject: Subject;
constructor(
RootSubject: Subject,
subject_path: SubjectPath,
action_name: ActionName
) {
this.RootSubject = RootSubject;
this.subject_path = new SubjectPath(subject_path);
this.action_name = action_name;
}
static curry(RootSubject: Subject) {
return function (subject_path: SubjectPath, action_name: ActionName) {
return new Action(RootSubject, subject_path, action_name);
};
}
}
diff --git a/src/app/app.ts b/src/app/app.ts
index dff9a97a..49099518 100644
--- a/src/app/app.ts
+++ b/src/app/app.ts
@@ -1,144 +1,144 @@
// @ts-ignore
const locreq = require("locreq")(__dirname);
import { EventEmitter } from "events";
import assert from "assert";
import winston from "winston";
import { ActionName } from "../action";
import Mailer from "../email/mailer";
import * as Sealious from "../main";
-import run_action_curry from "./run-action-curry.js";
+import { runActionCurry } from "./run-action-curry";
import Datastore from "../datastore/datastore";
import Metadata from "./metadata";
import { SubjectPathEquiv } from "../data-structures/subject-path";
import { PartialConfig } from "./config";
import { Collection, Hookable } from "../main";
const default_config = locreq("default_config.json");
export type AppEvents = "starting" | "started" | "stopping" | "stopped";
class App extends Hookable {
launch_time: number;
status: "stopped" | "running" | "starting" | "stopping";
Sealious: typeof Sealious;
manifest: Sealious.Manifest;
i18n: any;
ConfigManager: Sealious.ConfigManager;
Logger: winston.Logger;
ChipManager: Sealious.ChipManager;
Email: Mailer;
HTTPServer: Sealious.HttpServer;
RootSubject: Sealious.Subject;
Action: (
subject_path: Sealious.SubjectPath,
action_name: ActionName
) => Sealious.Action;
- run_action: (
+ runAction: (
context: Sealious.Context,
path: SubjectPathEquiv,
action: ActionName,
params?: any
) => Promise<any>;
Datastore: Datastore;
Metadata: Metadata;
private e: EventEmitter;
constructor(custom_config: PartialConfig, manifest: Sealious.Manifest) {
super();
this.e = new EventEmitter();
this.launch_time = Date.now();
this.status = "stopped";
this.Sealious = Sealious;
this.manifest = manifest;
this.checkManifest(manifest);
this.i18n = Sealious.i18nFactory(manifest.default_language);
this.ConfigManager = new Sealious.ConfigManager();
for (let key in default_config) {
this.ConfigManager.setDefault(key, default_config[key]);
}
this.ConfigManager.setRoot(custom_config);
this.Logger = Sealious.Logger(this);
this.ChipManager = new Sealious.ChipManager(this);
this.Email = Sealious.EmailFactory(this);
this.HTTPServer = new Sealious.HttpServer(this);
this.RootSubject = new Sealious.RootSubject(this);
this.Action = Sealious.Action.curry(this.RootSubject);
- this.run_action = run_action_curry(this);
+ this.runAction = runActionCurry(this);
this.Datastore = new Datastore(this);
this.Metadata = new Sealious.MetadataFactory(this);
assert(
this.ConfigManager.get("upload_path"),
"'upload_path' not set in config"
);
}
checkManifest(manifest: Sealious.Manifest) {
assert(manifest, "Please provide the app manifest");
[
"name",
"logo",
"version",
"default_language",
"base_url",
"admin_email",
].forEach((key: keyof Sealious.Manifest) => {
assert(
manifest[key],
`Please specify '${key}' field in the app manifest`
);
});
}
async start() {
this.status = "starting";
assert(
["dev", "production"].includes(
this.ConfigManager.get("core").environment
),
`"core.environment" config should be either "dev" or "production"`
);
this.e.emit("starting");
await this.Datastore.start();
await this.Email.init();
await this.ChipManager.startChips();
this.e.emit("started");
this.status = "running";
return this;
}
async stop() {
this.status = "stopping";
this.e.emit("stopping");
await this.HTTPServer.stop();
this.Datastore.stop();
this.status = "stopped";
this.e.emit("stopped");
}
async removeAllData() {
this.ChipManager.getAllCollections().map((collection_name) =>
this.Datastore.remove(collection_name, {}, "just_one" && false)
);
}
async on(event_name: string, callback: () => void) {
this.e.on(event_name, callback);
}
registerCollection(collection: Collection) {
this.ChipManager.addChip("collection", collection.name, collection);
}
}
export default App;
diff --git a/src/app/base-chips/access-strategy-types/access-strategy-types.ts b/src/app/base-chips/access-strategy-types/access-strategy-types.ts
index 9849c95b..6c754eb0 100644
--- a/src/app/base-chips/access-strategy-types/access-strategy-types.ts
+++ b/src/app/base-chips/access-strategy-types/access-strategy-types.ts
@@ -1,15 +1,15 @@
export * from "./and";
export * from "./if";
-export * from "./logged_in";
+export * from "./logged-in";
export * from "./noone";
export * from "./not";
export * from "./or";
export * from "./owner";
export * from "./public";
export * from "./roles";
export * from "./same-anon";
export * from "./same-as-for-resource-in-field";
export * from "./super";
export * from "./themselves";
export * from "./user-referenced-in-field";
export * from "./users-who-can";
diff --git a/src/app/base-chips/access-strategy-types/and.subtest.ts b/src/app/base-chips/access-strategy-types/and.subtest.ts
index 3bc68b28..5bc4adc0 100644
--- a/src/app/base-chips/access-strategy-types/and.subtest.ts
+++ b/src/app/base-chips/access-strategy-types/and.subtest.ts
@@ -1,131 +1,131 @@
import assert from "assert";
import Bluebird from "bluebird";
import { App, Collection } from "../../../main";
-import { with_running_app } from "../../../test_utils/with-test-app";
-import create_strategies from "../../../test_utils/access-strategy-types/create_strategies_with_complex_pipeline";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import create_strategies from "../../../test_utils/access-strategy-types/create-strategies-with-complex-pipeline";
describe("AndAccessStrategy", () => {
async function setup(app: App) {
Collection.fromDefinition(app, {
name: "numbers",
fields: [
{
name: "number",
type: "int",
},
],
});
- create_strategies.allow_deny(app);
+ create_strategies.allowDeny(app);
const collections = [
{
name:
"collection-and(nested-and(allow, public), nested-or(allow, noone))",
strategies: [
["and", ["complex-allow-pipeline", "public"]],
["or", ["complex-allow-pipeline", "noone"]],
],
},
{
name: "collection-and(complex-allow-pipeline, noone)",
strategies: ["complex-allow-pipeline", "noone"],
},
{
name: "collection-and(complex-allow-pipeline, public)",
strategies: ["complex-allow-pipeline", "public"],
},
{
name: "collection-and(complex-deny-pipeline, public)",
strategies: ["complex-deny-pipeline", "public"],
},
];
for (const { name, strategies } of collections) {
Collection.fromDefinition(app, {
name: name,
fields: [
{
name: "number",
type: "single_reference",
params: { collection: "numbers" },
required: true,
},
],
access_strategy: {
show: ["and", strategies],
create: "public",
},
});
}
let numbers = await Bluebird.map([0, 1, 2], (n) =>
- app.run_action(
+ app.runAction(
new app.Sealious.SuperContext(),
["collections", "numbers"],
"create",
{ number: n }
)
);
for (const number of numbers) {
await Bluebird.map(collections, ({ name }) =>
- app.run_action(
+ app.runAction(
new app.Sealious.SuperContext(),
["collections", name],
"create",
{ number: number.id }
)
);
}
}
it("return everything for collection-and(nested-and(allow, public), nested-or(allow, noone))", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
return rest_api
.get(
"/api/v1/collections/collection-and(nested-and(allow, public), nested-or(allow, noone))"
)
.then(({ items }: { items: any[] }) =>
assert.equal(items.length, 3)
);
}));
it("returns nothing for and(complex-allow-pipeline, noone)", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
return rest_api
.get(
"/api/v1/collections/collection-and(complex-allow-pipeline, noone)"
)
.then(({ items }: { items: any[] }) =>
assert.equal(items.length, 0)
);
}));
it("returns everything for and(complex-allow-pipeline, public)", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
return rest_api
.get(
"/api/v1/collections/collection-and(complex-allow-pipeline, public)"
)
.then(({ items }: { items: any[] }) =>
assert.equal(items.length, 3)
);
}));
it("returns nothing for and(complex-deny-pipeline, public)", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
return rest_api
.get(
"/api/v1/collections/collection-and(complex-deny-pipeline, public)"
)
.then(({ items }: { items: any[] }) =>
assert.equal(items.length, 0)
);
}));
});
diff --git a/src/app/base-chips/access-strategy-types/and.ts b/src/app/base-chips/access-strategy-types/and.ts
index a3349b0c..e0a50676 100644
--- a/src/app/base-chips/access-strategy-types/and.ts
+++ b/src/app/base-chips/access-strategy-types/and.ts
@@ -1,40 +1,40 @@
import Bluebird from "bluebird";
-import { And as AndQuery } from "../../../datastore/query.js";
-import { Context } from "../../../main.js";
-import SealiousResponse from "../../../../common_lib/response/sealious-response.js";
+import { And as AndQuery } from "../../../datastore/query";
+import { Context } from "../../../main";
+import SealiousResponse from "../../../../common_lib/response/sealious-response";
import AccessStrategy, {
ReducingAccessStrategy,
-} from "../../../chip-types/access-strategy.js";
+} from "../../../chip-types/access-strategy";
export default class And extends ReducingAccessStrategy {
async getRestrictingQuery(context: Context) {
const queries = await Bluebird.map(this.access_strategies, (strategy) =>
strategy.getRestrictingQuery(context)
);
return new AndQuery(...queries);
}
isItemSensitive() {
return Bluebird.map(this.access_strategies, (strategy) =>
strategy.isItemSensitive()
).reduce((a, b) => a || b);
}
async checkerFunction(context: Context, response: SealiousResponse) {
const results = await this.checkAllStrategies(context, response);
const negatives = results.filter((result) => result?.allowed === false);
if (negatives.length > 0) {
return AccessStrategy.deny(
`conditions: ${negatives
.map((n) => `"${n?.reason}"`)
.join(", ")} are not met`
);
}
return AccessStrategy.allow(
`conditions: ${results
.filter((r) => r !== null)
.map((r) => `"${r?.reason}"`)
.join(", ")} are all met`
);
}
}
diff --git a/src/app/base-chips/access-strategy-types/if.subtest.ts b/src/app/base-chips/access-strategy-types/if.subtest.ts
index eebab056..baf585de 100644
--- a/src/app/base-chips/access-strategy-types/if.subtest.ts
+++ b/src/app/base-chips/access-strategy-types/if.subtest.ts
@@ -1,73 +1,73 @@
import assert from "assert";
-import { with_stopped_app } from "../../../test_utils/with-test-app";
+import { withStoppedApp } from "../../../test_utils/with-test-app";
import { App, Collection } from "../../../main";
import Matches from "../special_filters/matches";
describe("when", () => {
- async function create_resources(app: App) {
+ async function createResources(app: App) {
Collection.fromDefinition(app, {
name: "numbers",
fields: [{ name: "number", type: "int" }],
named_filters: {
positive: new Matches(app, { number: { ">": 0 } }),
negative: new Matches(app, { number: { "<": 0 } }),
},
access_strategy: {
default: [
"when",
- ["numbers", "negative", "logged_in", "public"],
+ ["numbers", "negative", "logged-in", "public"],
],
},
});
await app.start();
for (let number of [-1, 0, 1]) {
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "numbers"],
"create",
{ number }
);
}
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username: "user",
password: "password",
email: "user@example.com",
}
);
}
it("should only use 'when_true' access strategy when the item passes the filter", async () =>
- with_stopped_app(async ({ app, rest_api }) => {
- await create_resources(app);
+ withStoppedApp(async ({ app, rest_api }) => {
+ await createResources(app);
const session = await rest_api.login({
username: "user",
password: "password",
});
const { items: resources_when_logged_in } = await rest_api.get(
"/api/v1/collections/numbers?sort[number]=asc",
session
);
assert.equal(resources_when_logged_in.length, 3);
assert.equal(resources_when_logged_in[0].number, -1);
}));
it("should only use 'when_false' access strategy when the item doesn't pass the filter", async () =>
- with_stopped_app(async ({ app, rest_api }) => {
- await create_resources(app);
+ withStoppedApp(async ({ app, rest_api }) => {
+ await createResources(app);
const { items: public_resources } = await rest_api.get(
"/api/v1/collections/numbers?sort[number]=asc"
);
assert.equal(public_resources.length, 2);
}));
});
diff --git a/src/app/base-chips/access-strategy-types/logged_in.ts b/src/app/base-chips/access-strategy-types/logged-in.ts
similarity index 70%
rename from src/app/base-chips/access-strategy-types/logged_in.ts
rename to src/app/base-chips/access-strategy-types/logged-in.ts
index 8df1a5ff..6b3aa1eb 100644
--- a/src/app/base-chips/access-strategy-types/logged_in.ts
+++ b/src/app/base-chips/access-strategy-types/logged-in.ts
@@ -1,23 +1,22 @@
-import AccessStrategy from "../../../chip-types/access-strategy.js";
-import { Context, App } from "../../../main.js";
-
-const Query = require("../../../datastore/query.js").default;
+import AccessStrategy from "../../../chip-types/access-strategy";
+import { Context, App } from "../../../main";
+import Query from "../../../datastore/query-types";
export default class LoggedIn extends AccessStrategy {
constructor(app: App) {
super(app, {});
}
async getRestrictingQuery(context: Context) {
if (context.user_id) {
return new Query.AllowAll();
}
return new Query.DenyAll();
}
async checkerFunction(context: Context) {
if (context.user_id) {
return AccessStrategy.allow("you are logged in");
} else {
return AccessStrategy.deny("you are not logged in");
}
}
}
diff --git a/src/app/base-chips/access-strategy-types/noone.ts b/src/app/base-chips/access-strategy-types/noone.ts
index 40e92884..2354f6dc 100644
--- a/src/app/base-chips/access-strategy-types/noone.ts
+++ b/src/app/base-chips/access-strategy-types/noone.ts
@@ -1,13 +1,13 @@
-import AccessStrategy from "../../../chip-types/access-strategy.js";
+import AccessStrategy from "../../../chip-types/access-strategy";
const Query = require("../../../datastore/query.js").default;
export default class Noone extends AccessStrategy {
async getRestrictingQuery() {
return new Query.DenyAll();
}
async checkerFunction() {
return AccessStrategy.deny("noone is allowed");
}
isItemSensitive = async () => false;
}
diff --git a/src/app/base-chips/access-strategy-types/not.subtest.ts b/src/app/base-chips/access-strategy-types/not.subtest.ts
index 3d9531f4..d6e6bb9b 100644
--- a/src/app/base-chips/access-strategy-types/not.subtest.ts
+++ b/src/app/base-chips/access-strategy-types/not.subtest.ts
@@ -1,181 +1,181 @@
import assert from "assert";
import Bluebird from "bluebird";
import * as Sealious from "./../../../main";
-import { with_running_app } from "../../../test_utils/with-test-app";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
import Context from "../../../context";
import SealiousResponse from "../../../../common_lib/response/sealious-response";
import { Collection } from "./../../../main";
describe("NotAccessStrategy", () => {
async function setup(app: Sealious.App) {
Collection.fromDefinition(app, {
name: "numbers",
fields: [
{
name: "number",
type: "int",
},
],
});
create_less_than_strategy(app, 2);
create_less_than_strategy(app, 6);
const collections = [
{
name: "collection-not(less-than(2))",
strategy: ["less-than(2)"],
},
{
name: "collection-not(less-than(6))",
strategy: ["less-than(6)"],
},
{
name: "collection-not(public)",
strategy: ["public"],
},
{
name: "collection-not(noone)",
strategy: ["noone"],
},
];
for (const { name, strategy } of collections) {
Collection.fromDefinition(app, {
name: name,
fields: [
{
name: "number",
type: "single_reference",
params: { collection: "numbers" },
required: true,
},
],
access_strategy: {
show: ["not", strategy],
create: "public",
},
});
}
for (let i of [0, 1, 2, 3, 4]) {
- const { id } = await app.run_action(
+ const { id } = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "numbers"],
"create",
{ number: i }
);
await Bluebird.map(collections, ({ name }) =>
- app.run_action(
+ app.runAction(
new app.Sealious.SuperContext(),
["collections", name],
"create",
{ number: id }
)
);
}
}
function create_less_than_strategy(app: Sealious.App, number: number) {
class LessThanStrategy extends Sealious.AccessStrategy {
async getRestrictingQuery() {
const query = new Sealious.Query();
const id = query.lookup({
from: "numbers",
localField: "number",
foreignField: "sealious_id",
unwind: true,
});
query.match({
[`${id}.number`]: {
$lt: number,
},
});
return query;
}
async checkerFunction(
_: Context,
sealious_response: SealiousResponse
) {
const item_number = ((sealious_response as unknown) as {
number: { number: number };
}).number.number;
if (item_number >= number) {
return Sealious.AccessStrategy.deny(
`Given value is not lower than ${number}`
);
}
return Sealious.AccessStrategy.allow(
`Number is less than ${number}`
);
}
isItemSensitive = async () => true;
}
app.ChipManager.addChip(
"access_strategy_type",
`less-than(${number})`,
LessThanStrategy
);
}
it("returns nothing for collection-not(public)", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
- await assert_throws_async(
+ await assertThrowsAsync(
async () =>
await rest_api.get(
"/api/v1/collections/collection-not(public)"
),
- e => {
+ (e) => {
assert.equal((e as any).response.status, 401);
}
);
}));
it("returns everything for collection-not(noone)", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
const response = await rest_api.getSealiousResponse(
"/api/v1/collections/collection-not(noone)?attachments[number]=true"
);
const numbers = response.items.map(
- item => (item.number as { number: number }).number
+ (item) => (item.number as { number: number }).number
);
assert.deepEqual(numbers, [0, 1, 2, 3, 4]);
}));
it("returns correct numbers for collection-not(less-than(2))", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
const response = await rest_api.getSealiousResponse(
"/api/v1/collections/collection-not(less-than(2))?attachments[number]=true"
);
const numbers = response.items.map(
- item => (item.number as { number: number }).number
+ (item) => (item.number as { number: number }).number
);
assert.deepEqual(numbers, [2, 3, 4]);
}));
it("returns correct numbers for collection-not(less-than(6))", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
const response = await rest_api.getSealiousResponse(
"/api/v1/collections/collection-not(less-than(6))?attachments[number]=true"
);
const numbers = response.items.map(
- item => (item.number as { number: number }).number
+ (item) => (item.number as { number: number }).number
);
assert.deepEqual(numbers, []);
}));
});
diff --git a/src/app/base-chips/access-strategy-types/not.ts b/src/app/base-chips/access-strategy-types/not.ts
index 2d5e59d9..b38fb119 100644
--- a/src/app/base-chips/access-strategy-types/not.ts
+++ b/src/app/base-chips/access-strategy-types/not.ts
@@ -1,41 +1,41 @@
import AccessStrategy, {
AccessStrategyDefinition,
-} from "../../../chip-types/access-strategy.js";
-import * as Query from "./../../../datastore/query.js";
-import { Context, App } from "../../../main.js";
-import SealiousResponse from "../../../../common_lib/response/sealious-response.js";
+} from "../../../chip-types/access-strategy";
+import * as Query from "./../../../datastore/query";
+import { Context, App } from "../../../main";
+import SealiousResponse from "../../../../common_lib/response/sealious-response";
export default class Not extends AccessStrategy {
strategy_to_negate: AccessStrategy;
constructor(app: App, strategy: AccessStrategyDefinition) {
super(app, strategy);
this.strategy_to_negate = AccessStrategy.fromDefinition(app, strategy);
}
async getRestrictingQuery(context: Context) {
//assuming "not" can take only one access strategy as a parameter
const query = await this.strategy_to_negate.getRestrictingQuery(
context
);
return new Query.Not(query);
}
async isItemSensitive() {
return this.strategy_to_negate.isItemSensitive();
}
async checkerFunction(
context: Context,
sealious_response: SealiousResponse
) {
const result = await this.strategy_to_negate.check(
context,
sealious_response
);
if (result === null) {
return null;
}
if (result.allowed) {
return AccessStrategy.deny(result.reason);
}
return AccessStrategy.allow(`it's not true that "${result.reason}"`);
}
}
diff --git a/src/app/base-chips/access-strategy-types/or.subtest.ts b/src/app/base-chips/access-strategy-types/or.subtest.ts
index cedfa138..a766bb43 100644
--- a/src/app/base-chips/access-strategy-types/or.subtest.ts
+++ b/src/app/base-chips/access-strategy-types/or.subtest.ts
@@ -1,124 +1,124 @@
import assert from "assert";
import Bluebird from "bluebird";
-import { with_running_app } from "../../../test_utils/with-test-app";
-import create_strategies from "../../../test_utils/access-strategy-types/create_strategies_with_complex_pipeline";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import create_strategies from "../../../test_utils/access-strategy-types/create-strategies-with-complex-pipeline";
import * as Sealious from "../../../main";
import { Collection } from "../../../main";
describe("OrAccessStrategy", () => {
async function setup(app: Sealious.App) {
Collection.fromDefinition(app, {
name: "numbers",
fields: [
{
name: "number",
type: "int",
},
],
});
- create_strategies.allow_deny(app);
+ create_strategies.allowDeny(app);
const collections = [
{
name:
"collection-or(nested-or(allow, noone), nested-and(allow, public))",
strategies: [
["or", ["complex-allow-pipeline", "noone"]],
["and", ["complex-allow-pipeline", "public"]],
],
},
{
name: "collection-or(complex-allow-pipeline, public)",
strategies: ["complex-allow-pipeline", "public"],
},
{
name: "collection-or(complex-deny-pipeline, noone)",
strategies: ["complex-deny-pipeline", "noone"],
},
{
name: "collection-or(complex-deny-pipeline, public)",
strategies: ["complex-deny-pipeline", "public"],
},
];
for (const { name, strategies } of collections) {
Collection.fromDefinition(app, {
name: name,
fields: [
{
name: "number",
type: "single_reference",
params: { collection: "numbers" },
required: true,
},
],
access_strategy: {
show: ["or", strategies],
create: "public",
},
});
}
let numbers = await Bluebird.map([0, 1, 2], (n) =>
- app.run_action(
+ app.runAction(
new app.Sealious.SuperContext(),
["collections", "numbers"],
"create",
{ number: n }
)
);
for (const number of numbers) {
await Bluebird.map(collections, ({ name }) =>
- app.run_action(
+ app.runAction(
new app.Sealious.SuperContext(),
["collections", name],
"create",
{ number: number.id }
)
);
}
}
it("returns everything for collection-or(nested-or(allow, noone), nested-and(allow, public))", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
return rest_api
.getSealiousResponse(
"/api/v1/collections/collection-or(nested-or(allow, noone), nested-and(allow, public))"
)
.then(({ items }) => assert.equal(items.length, 3));
}));
it("returns everything for or(complex-allow-pipeline, public)", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
return rest_api
.getSealiousResponse(
"/api/v1/collections/collection-or(complex-allow-pipeline, public)"
)
.then(({ items }) => assert.equal(items.length, 3));
}));
it("returns nothing for or(complex-deny-pipeline, noone)", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
return rest_api
.getSealiousResponse(
"/api/v1/collections/collection-or(complex-deny-pipeline, noone)"
)
.then(({ items }) => assert.equal(items.length, 0));
}));
it("returns everything for or(complex-deny-pipeline, public)", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
return rest_api
.getSealiousResponse(
"/api/v1/collections/collection-or(complex-deny-pipeline, public)"
)
.then(({ items }) => assert.equal(items.length, 3));
}));
});
diff --git a/src/app/base-chips/access-strategy-types/or.ts b/src/app/base-chips/access-strategy-types/or.ts
index ec6fedbb..22a8fe58 100644
--- a/src/app/base-chips/access-strategy-types/or.ts
+++ b/src/app/base-chips/access-strategy-types/or.ts
@@ -1,42 +1,42 @@
import AccessStrategy, {
ReducingAccessStrategy,
AccessStrategyDecision,
-} from "../../../chip-types/access-strategy.js";
+} from "../../../chip-types/access-strategy";
-import Context from "../../../context.js";
+import Context from "../../../context";
import Bluebird from "bluebird";
-import SealiousResponse from "../../../../common_lib/response/sealious-response.js";
+import SealiousResponse from "../../../../common_lib/response/sealious-response";
const Query = require("../../../datastore/query.js").default;
export default class Or extends ReducingAccessStrategy {
async getRestrictingQuery(context: Context) {
const queries = await Bluebird.map(this.access_strategies, (strategy) =>
strategy.getRestrictingQuery(context)
);
if (queries.some((query) => query instanceof Query.AllowAll)) {
return new Query.AllowAll();
}
return new Query.Or(...queries);
}
async isItemSensitive() {
return Bluebird.map(this.access_strategies, (strategy) =>
strategy.isItemSensitive()
).reduce((a, b) => a || b, true);
}
async checkerFunction(context: Context, response: SealiousResponse) {
const results = await this.checkAllStrategies(context, response);
const positives: Exclude<
AccessStrategyDecision,
null
>[] = results.filter((result) => result?.allowed === true) as Exclude<
AccessStrategyDecision,
null
>[];
if (positives.length === 0) {
return AccessStrategy.deny(
results.map((r) => `"${r?.reason}"`).join(", ")
);
}
return AccessStrategy.allow(positives[0].reason);
}
}
diff --git a/src/app/base-chips/access-strategy-types/roles.subtest.ts b/src/app/base-chips/access-strategy-types/roles.subtest.ts
index 45db46d9..60f8e624 100644
--- a/src/app/base-chips/access-strategy-types/roles.subtest.ts
+++ b/src/app/base-chips/access-strategy-types/roles.subtest.ts
@@ -1,79 +1,79 @@
import assert from "assert";
-import { with_stopped_app } from "../../../test_utils/with-test-app";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
+import { withStoppedApp } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
import { Collection } from "../../../main";
describe("roles", () => {
it("allows access to users with designated role and denies access to users without it", async () =>
- with_stopped_app(async ({ app, rest_api }) => {
+ withStoppedApp(async ({ app, rest_api }) => {
Collection.fromDefinition(app, {
name: "secrets",
fields: [{ name: "content", type: "text" }],
access_strategy: { default: ["roles", ["admin"]] },
});
await app.start();
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username: "regular-user",
email: "regular@example.com",
password: "password",
}
);
- const admin = await app.run_action(
+ const admin = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username: "admin",
email: "admin@example.com",
password: "admin-password",
}
);
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "user-roles"],
"create",
{ user: admin.id, role: "admin" }
);
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "secrets"],
"create",
{ content: "It's a secret to everybody" }
);
const admin_session = await rest_api.login({
username: "admin",
password: "admin-password",
});
const { items: admin_response } = await rest_api.get(
"/api/v1/collections/secrets",
admin_session
);
assert.equal(admin_response.length, 1);
const user_session = await rest_api.login({
username: "regular-user",
password: "password",
});
- await assert_throws_async(
+ await assertThrowsAsync(
() => rest_api.get("/api/v1/collections/secrets", user_session),
(error) => {
assert.equal(
(error as any).response.data.message,
"Action allowed only for users with role admin."
);
}
);
}));
});
diff --git a/src/app/base-chips/access-strategy-types/roles.ts b/src/app/base-chips/access-strategy-types/roles.ts
index 03acd596..4ca9d7eb 100644
--- a/src/app/base-chips/access-strategy-types/roles.ts
+++ b/src/app/base-chips/access-strategy-types/roles.ts
@@ -1,64 +1,64 @@
import Context from "../../../context";
import AccessStrategy from "../../../chip-types/access-strategy";
import App from "../../app";
import SuperContext from "../../../super-context";
import Item from "../../../../common_lib/response/item";
import { QueryTypes } from "../../../main";
export default class Roles extends AccessStrategy {
allowed_roles: string[];
constructor(app: App, allowed_roles: string[]) {
super(app, allowed_roles);
this.allowed_roles = allowed_roles;
}
async countMatchingRoles(context: Context) {
const user_id = context.user_id;
const user_roles = (
- await this.app.run_action(
+ await this.app.runAction(
new SuperContext(context),
["collections", "user-roles"],
"show",
{ filter: { user: user_id } }
)
).items.map((role_resource: Item) => role_resource.role);
return this.allowed_roles.filter((allowed_role) =>
user_roles.includes(allowed_role)
).length;
}
async getRestrictingQuery(context: Context) {
if (context.is_super) {
return new QueryTypes.AllowAll();
}
if (context.user_id === null) {
return new QueryTypes.DenyAll();
}
const matching_roles_count = await this.countMatchingRoles(context);
return matching_roles_count > 0
? new QueryTypes.AllowAll()
: new QueryTypes.DenyAll();
}
async checkerFunction(context: Context) {
if (context.user_id === null) {
return AccessStrategy.deny("you are not logged in");
}
const matching_roles_count = await this.countMatchingRoles(context);
return matching_roles_count > 0
? AccessStrategy.allow(
`you have one of the roles: ${this.allowed_roles.join(
", "
)}`
)
: AccessStrategy.deny(
`you dont have any of the roles: ${this.allowed_roles.join(
", "
)}.`
);
}
}
diff --git a/src/app/base-chips/access-strategy-types/same-as-for-resource-in-field.subtest.ts b/src/app/base-chips/access-strategy-types/same-as-for-resource-in-field.subtest.ts
index b45f5cd2..32c4d1bc 100644
--- a/src/app/base-chips/access-strategy-types/same-as-for-resource-in-field.subtest.ts
+++ b/src/app/base-chips/access-strategy-types/same-as-for-resource-in-field.subtest.ts
@@ -1,198 +1,195 @@
import assert from "assert";
-import {
- with_running_app,
- MockRestApi,
-} from "../../../test_utils/with-test-app";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
+import { withRunningApp, MockRestApi } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
import { App, Collection, ActionName } from "../../../main";
import { AccessStrategyDefinition } from "../../../chip-types/access-strategy";
import Matches from "../special_filters/matches";
describe("SameAsForResourceInField", () => {
const sessions: { [username: string]: any } = {};
const numbers: number[] = [];
async function setup(
app: App,
rest_api: MockRestApi,
access_strategy: {
[action_name in ActionName]?: AccessStrategyDefinition;
}
) {
Collection.fromDefinition(app, {
name: "numbers",
fields: [
{
name: "number",
type: "int",
},
],
named_filters: {
greater_than_1: new Matches(app, {
number: { ">": 1 },
}),
},
access_strategy,
});
Collection.fromDefinition(app, {
name: "number-notes",
fields: [
{
name: "note",
type: "text",
},
{
name: "number",
type: "single_reference",
params: { collection: "numbers" },
},
],
access_strategy: {
create: [
"same-as-for-resource-in-field",
{
action_name: "create",
field: "number",
collection: "number-notes",
},
],
show: [
"same-as-for-resource-in-field",
{
action_name: "show",
field: "number",
collection: "number-notes",
},
],
},
});
const password = "password";
for (let username of ["alice", "bob"]) {
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username,
password,
email: `${username}@example.com`,
}
);
sessions[username] = await rest_api.login({
username,
password,
});
}
for (let n of [0, 1, 2]) {
numbers.push(
(
await rest_api.post(
"/api/v1/collections/numbers",
{
number: n,
},
sessions.alice
)
).id
);
}
}
async function post_number_notes(rest_api: MockRestApi, user: string) {
const notes = [];
for (let number of numbers) {
notes.push(
await rest_api.post(
"/api/v1/collections/number-notes",
{
note: "Lorem ipsum " + (notes.length + 1),
number: number,
},
sessions[user]
)
);
}
return notes;
}
it("returns everything for number-notes referring to own numbers", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api, {
create: "public",
show: "owner",
});
const posted_notes = await post_number_notes(rest_api, "alice");
const { items: got_notes } = await rest_api.get(
"/api/v1/collections/number-notes",
sessions.alice
);
assert.equal(got_notes.length, posted_notes.length);
}));
it("returns nothing for number-notes referring to other user's numbers", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api, { create: "public", show: "owner" });
await post_number_notes(rest_api, "alice");
const { items: got_notes } = await rest_api.get(
"/api/v1/collections/number-notes",
sessions.bob
);
assert.equal(got_notes.length, 0);
}));
it("returns item for number-notes referring to numbers with complex access strategy", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api, {
- create: "logged_in",
+ create: "logged-in",
show: [
"or",
[
"owner",
["when", ["numbers", "greater_than_1", "public"]],
],
],
});
await post_number_notes(rest_api, "alice");
const { items: got_notes } = await rest_api.get(
"/api/v1/collections/number-notes",
sessions.bob
);
assert.equal(got_notes.length, 1);
}));
it("doesn't allow to edit number-notes referring to other user's numbers", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api, {
- create: "logged_in",
+ create: "logged-in",
edit: "owner",
show: "owner",
});
const posted_notes = await post_number_notes(rest_api, "alice");
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
rest_api.patch(
`/api/v1/collections/number-notes/${posted_notes[0].id}`,
{ note: "Lorem ipsumm" },
sessions.bob
),
(error) => {
assert.equal(
(error as any).response.data.message,
"Only the owner of this resource can perform this operation on this item."
);
}
);
}));
});
diff --git a/src/app/base-chips/access-strategy-types/same-as-for-resource-in-field.ts b/src/app/base-chips/access-strategy-types/same-as-for-resource-in-field.ts
index 1e720711..266c94bd 100644
--- a/src/app/base-chips/access-strategy-types/same-as-for-resource-in-field.ts
+++ b/src/app/base-chips/access-strategy-types/same-as-for-resource-in-field.ts
@@ -1,118 +1,118 @@
import AccessStrategy from "../../../chip-types/access-strategy";
import { App, Context, SuperContext } from "../../../main";
import Collection, {
CollectionDefinition,
} from "../../../chip-types/collection";
import { ActionName } from "../../../action";
import SingleItemResponse from "../../../../common_lib/response/single-item-response";
import QueryStage from "../../../datastore/query-stage";
import SingleReference from "../field-types/single-reference";
const Query = require("../../../datastore/query.js").default;
export default class SameAsForResourceInField extends AccessStrategy {
current_collection: Collection;
referenced_collection: Collection;
referenced_access_strategy: AccessStrategy;
field: string;
constructor(
app: App,
{
action_name,
collection,
field,
}: {
action_name: ActionName;
collection: CollectionDefinition;
field: string;
}
) {
super(app, { action_name, collection, field });
this.current_collection = Collection.fromDefinition(app, collection);
this.referenced_collection = (this.current_collection.fields[
field
] as SingleReference).target_collection;
this.referenced_access_strategy = this.referenced_collection.getAccessStrategy(
"show"
);
this.field = field;
}
async getRestrictingQuery(context: Context) {
const referenced_restricting_query = await this.referenced_access_strategy.getRestrictingQuery(
context
);
if (
referenced_restricting_query instanceof Query.DenyAll ||
referenced_restricting_query instanceof Query.AllowAll
) {
return referenced_restricting_query;
}
const query = new Query();
const parent_prefix = query.lookup({
from: this.referenced_collection,
localField: this.field,
foreignField: "sealious_id",
});
const referenced_restricting_pipeline = referenced_restricting_query.toPipeline();
add_parent_prefix_to_pipeline(
referenced_restricting_pipeline,
parent_prefix
);
const pipeline = query
.toPipeline()
.concat(referenced_restricting_pipeline);
return Query.fromCustomPipeline(pipeline);
}
async checkerFunction(context: Context, response: SingleItemResponse) {
- const sealious_response_in_field = await this.app.run_action(
+ const sealious_response_in_field = await this.app.runAction(
new SuperContext(),
[
"collections",
this.referenced_collection.name,
response[this.field],
],
"show"
);
return this.referenced_access_strategy.check(
context,
sealious_response_in_field
);
}
item_sensitive: true;
}
function add_parent_prefix_to_pipeline(
pipeline: QueryStage[],
parent_property: string
) {
for (let stage of pipeline) {
add_parent_prefix(stage, parent_property);
}
}
const prop_regex = /^[a-z0-9_]/;
function add_parent_prefix(group: QueryStage, parent_property: string) {
const ret: { [name: string]: any } = {};
for (const prop in group) {
if (Array.isArray(group[prop])) {
group[prop] = group[prop].map((subgroup: QueryStage) =>
add_parent_prefix(subgroup, parent_property)
);
} else if (group[prop] instanceof Object) {
group[prop] = add_parent_prefix(group[prop], parent_property);
}
const new_prop = prop_regex.test(prop)
? parent_property + "." + prop
: prop;
ret[new_prop] = group[prop];
}
return ret;
}
diff --git a/src/app/base-chips/access-strategy-types/super.ts b/src/app/base-chips/access-strategy-types/super.ts
index e57699df..db06882b 100644
--- a/src/app/base-chips/access-strategy-types/super.ts
+++ b/src/app/base-chips/access-strategy-types/super.ts
@@ -1,27 +1,27 @@
-import AccessStrategy from "../../../chip-types/access-strategy.js";
-import Context from "../../../context.js";
+import AccessStrategy from "../../../chip-types/access-strategy";
+import Context from "../../../context";
const Query = require("../../../datastore/query.js").default;
export default class Super extends AccessStrategy {
async getRestrictingQuery(context: Context) {
if (context.is_super) {
return new Query.AllowAll();
}
return new Query.DenyAll();
}
async checkerFunction(context: Context) {
if (context.is_super) {
return AccessStrategy.allow(
"this method was ran with a supercontext"
);
} else {
return AccessStrategy.allow(
"this method was not ran with a supercontext"
);
}
}
isItemSensitive = async () => false;
}
module.exports = Super;
diff --git a/src/app/base-chips/access-strategy-types/user-referenced-in-field.subtest.ts b/src/app/base-chips/access-strategy-types/user-referenced-in-field.subtest.ts
index 450bf923..ab175989 100644
--- a/src/app/base-chips/access-strategy-types/user-referenced-in-field.subtest.ts
+++ b/src/app/base-chips/access-strategy-types/user-referenced-in-field.subtest.ts
@@ -1,56 +1,56 @@
import assert from "assert";
-import { with_stopped_app } from "../../../test_utils/with-test-app";
+import { withStoppedApp } from "../../../test_utils/with-test-app";
import { Collection } from "../../../main";
describe("user-referenced-in-field", () => {
it("should deny if the user isn't the one referenced in the field and allow if it is", async () =>
- with_stopped_app(async ({ app, rest_api }) => {
+ withStoppedApp(async ({ app, rest_api }) => {
Collection.fromDefinition(app, {
name: "pets",
fields: [
{ name: "name", type: "text" },
{
name: "owner",
type: "single_reference",
params: { collection: "users" },
},
],
access_strategy: {
create: "public",
default: ["user-referenced-in-field", "owner"],
},
});
await app.start();
for (let username of ["Alice", "Bob"]) {
- const user = await app.run_action(
+ const user = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username: username,
password: "password",
email: `${username.toLowerCase()}@example.com`,
}
);
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "pets"],
"create",
{ name: `${username}'s pet`, owner: user.id }
);
}
const alice_session = await rest_api.login({
username: "Alice",
password: "password",
});
const { items } = await rest_api.get(
"/api/v1/collections/pets",
alice_session
);
assert.equal(items.length, 1);
assert.equal(items[0].name, "Alice&#39;s pet");
}));
});
diff --git a/src/app/base-chips/access-strategy-types/users-who-can.subtest.ts b/src/app/base-chips/access-strategy-types/users-who-can.subtest.ts
index 797e7bc2..992efaad 100644
--- a/src/app/base-chips/access-strategy-types/users-who-can.subtest.ts
+++ b/src/app/base-chips/access-strategy-types/users-who-can.subtest.ts
@@ -1,57 +1,57 @@
import assert from "assert";
-import { with_running_app } from "../../../test_utils/with-test-app";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
import axios from "axios";
import { Collection } from "../../../main";
describe("users-who-can", () => {
it("should deny if the user can't perform the action", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
const bricks = Collection.fromDefinition(app, {
name: "bricks",
fields: [{ name: "number", type: "int" }],
access_strategy: { create: "noone" },
});
Collection.fromDefinition(app, {
name: "houses",
fields: [{ name: "address", type: "text" }],
access_strategy: {
create: ["users-who-can", ["create", bricks]],
},
});
- await assert_throws_async(
+ await assertThrowsAsync(
async () =>
axios
.post(`${base_url}/api/v1/collections/houses`, {
address: "any",
})
.then(),
(e: any) => {
assert.equal(e.response.status, 401);
assert.equal(
e.response.data.message,
"You can't perform this action beacuse you can't create bricks"
);
}
);
}));
it("should allow if the user can't perform the action", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
const bricks = Collection.fromDefinition(app, {
name: "bricks",
fields: [{ name: "number", type: "int" }],
access_strategy: { create: "public" },
});
Collection.fromDefinition(app, {
name: "houses",
fields: [{ name: "address", type: "text" }],
access_strategy: {
create: ["users-who-can", ["create", bricks]],
},
});
await axios.post(`${base_url}/api/v1/collections/houses`, {
address: "any",
});
}));
});
diff --git a/src/app/base-chips/calculated-field-types/map-reduce.ts b/src/app/base-chips/calculated-field-types/map-reduce.ts
index 056d591b..af669af9 100644
--- a/src/app/base-chips/calculated-field-types/map-reduce.ts
+++ b/src/app/base-chips/calculated-field-types/map-reduce.ts
@@ -1,58 +1,58 @@
import {
App,
Collection,
CalculatedField,
Item,
SubjectPathEquiv,
ActionName,
Context,
} from "../../../main";
type ParamGetter<T> = (context: Context, item: Item) => Promise<T> | T;
type ParamOrGetter<T> = T | ParamGetter<T>;
type MapReduceParams<ReturnType, IntermediateValue = any> = {
source: {
subject_path: ParamOrGetter<SubjectPathEquiv>;
action_name: ParamOrGetter<ActionName>;
params: ParamOrGetter<any>;
};
map: (items: Item[]) => IntermediateValue[];
reduce: [(intermediate: IntermediateValue[]) => ReturnType, any];
};
export default class MapReduce<
ReturnType,
IntermediateValue
> extends CalculatedField<ReturnType> {
name = "map-reduce";
params: MapReduceParams<ReturnType, IntermediateValue>;
constructor(
app: App,
collection: Collection,
params: MapReduceParams<ReturnType, IntermediateValue>
) {
super(app, collection);
this.params = params;
}
async calculate(context: Context, item: Item) {
const action_arguments = [
context,
this.params.source.subject_path,
this.params.source.action_name,
this.params.source.params,
].map(function (element) {
if (element instanceof Function) {
return element(context, item);
} else {
return element;
}
});
const fulfilled_params = Promise.all(action_arguments);
- return (await this.app.run_action.apply(App, fulfilled_params))
+ return (await this.app.runAction.apply(App, fulfilled_params))
.map(this.params.map)
.reduce(this.params.reduce[0], this.params.reduce[1]);
}
}
diff --git a/src/app/base-chips/field-types/boolean.subtest.ts b/src/app/base-chips/field-types/boolean.subtest.ts
index e4203eab..ff4d0391 100644
--- a/src/app/base-chips/field-types/boolean.subtest.ts
+++ b/src/app/base-chips/field-types/boolean.subtest.ts
@@ -1,101 +1,101 @@
import assert from "assert";
-import { with_running_app } from "../../../test_utils/with-test-app.js";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
-import { App, Collection } from "../../../main.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
+import { App, Collection } from "../../../main";
const URL = "/api/v1/collections/boolseals";
describe("boolean", () => {
async function setup(app: App) {
Collection.fromDefinition(app, {
name: "boolseals",
fields: [
{
name: "is_old",
type: "boolean",
required: true,
},
],
access_strategy: {
default: "public",
},
});
}
it("Allows to insert values considered correct", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
const cases = [
[true, true],
[false, false],
["true", true],
["false", false],
["1", true],
["0", false],
[1, true],
[0, false],
];
await Promise.all(
cases.map(async ([field_value, saved_value]) => {
const { is_old } = await rest_api.post(URL, {
is_old: field_value,
});
assert.equal(is_old, saved_value);
})
);
}));
it("Doesn't let undefined in", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
- await assert_throws_async(
+ await assertThrowsAsync(
() => rest_api.post(`${URL}`, { is_old: undefined }),
(error) =>
assert.deepEqual(
error.response.data.data.is_old.message,
"Missing value for field 'is_old'"
)
);
}));
it("Doesn't let '' in", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
- await assert_throws_async(
+ await assertThrowsAsync(
() => rest_api.post(`${URL}`, { is_old: "" }),
(error) => {
assert.equal(error.response.status, 403);
assert.deepEqual(
error.response.data.data.is_old.message,
"Missing value for required field: 'is_old'"
);
}
);
}));
it("Doesn't let unwelcomed values in", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
const cases = [
[null, "Value 'null' is not boolean format."],
[{}, "Value '[object Object]' is not boolean format."],
[[], "Value '' is not boolean format."],
[[false], "Value 'false' is not boolean format."],
[{ a: true }, "Value '[object Object]' is not boolean format."],
];
await Promise.all(
cases.map(([value, error_message]) =>
- assert_throws_async(
+ assertThrowsAsync(
() => rest_api.post(`${URL}`, { is_old: value }),
(error) => {
assert.equal(error.response.status, 403);
assert.deepEqual(
error.response.data.data.is_old.message,
error_message
);
}
)
)
);
}));
});
diff --git a/src/app/base-chips/field-types/cached-value.subtest.ts b/src/app/base-chips/field-types/cached-value.subtest.ts
index 5f8f713b..ddaea862 100644
--- a/src/app/base-chips/field-types/cached-value.subtest.ts
+++ b/src/app/base-chips/field-types/cached-value.subtest.ts
@@ -1,360 +1,360 @@
import assert from "assert";
import {
- with_running_app,
- with_stopped_app,
+ withRunningApp,
+ withStoppedApp,
MockRestApi,
-} from "../../../test_utils/with-test-app.js";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
-import { getDateTime } from "../../../utils/get-datetime.js";
+} from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
+import { getDateTime } from "../../../utils/get-datetime";
import {
App,
Context,
SuperContext,
Item,
SingleItemResponse,
Collection,
-} from "../../../main.js";
+} from "../../../main";
import Bluebird from "bluebird";
const action_to_status: { [name: string]: string } = {
create: "created",
open: "open",
suspend: "suspended",
close: "closed",
};
describe("cached-value", () => {
- function create_collections(app: App, is_status_field_desired = true) {
+ function createCollections(app: App, is_status_field_desired = true) {
Collection.fromDefinition(app, {
name: "accounts",
fields: [
{
name: "username",
type: "username",
required: true,
},
{
name: "number",
type: "cached-value",
params: {
base_field_type: {
name: "int",
params: {
min: 0,
},
},
get_value: async (_: Context, resource_id: string) => {
- return app.run_action(
+ return app.runAction(
new app.Sealious.SuperContext(),
["collections", "accounts", resource_id],
"show"
);
},
refresh_on: [],
},
},
{
name: "date_time",
type: "cached-value",
params: {
base_field_type: { name: "datetime" },
get_value: () => new Date("2018-01-01").getTime(),
refresh_on: make_refresh_on(app),
},
},
],
});
Collection.fromDefinition(app, {
name: "actions",
fields: [
{
name: "name",
type: "enum",
params: {
values: ["create", "open", "suspend", "close"],
},
required: true,
},
{
name: "account",
type: "single_reference",
params: { collection: "accounts" },
},
],
});
if (is_status_field_desired) {
create_status_field(app);
}
}
function create_status_field(app: App) {
const collection = app.ChipManager.getChip("collection", "accounts");
collection.add_field({
name: "status",
type: "cached-value",
params: {
base_field_type: {
name: "enum",
params: {
values: Object.values(action_to_status),
},
},
get_value: async (_: Context, resource_id: string) => {
const [latest_action] = await app.Datastore.aggregate(
"actions",
[
{
$match: {
account: resource_id,
},
},
{
$group: {
_id: "$name",
timestamp: {
$max:
"$_metadata.last_modified_context.timestamp",
},
},
},
]
);
return action_to_status[latest_action._id];
},
refresh_on: make_refresh_on(app),
},
});
}
async function add_account(rest_api: MockRestApi, account: {}) {
const { id } = await rest_api.post(
"/api/v1/collections/accounts",
account
);
await rest_api.post("/api/v1/collections/actions", {
name: "create",
account: id,
});
return id;
}
async function add_a_few_accounts(app: App) {
return Bluebird.map([1, 2, 3, 4, 5], async (i) =>
- app.run_action(
+ app.runAction(
new SuperContext(),
["collections", "accounts"],
"create",
{ username: `user_${i}`, number: i }
)
);
}
it("Correctly fills in cached-values if such field is added later", async () => {
const account_ids: string[] = [];
- await with_stopped_app(
- async ({ app, dont_clear_database_on_stop, rest_api }) => {
- create_collections(app, "create_status_field" && false);
+ await withStoppedApp(
+ async ({ app, dontClearDatabaseOnStop, rest_api }) => {
+ createCollections(app, "create_status_field" && false);
await app.start();
for (const username of ["user_1", "user_2"]) {
account_ids.push(await add_account(rest_api, { username }));
}
await rest_api.post("/api/v1/collections/actions", {
name: "suspend",
account: account_ids[1],
});
- dont_clear_database_on_stop();
+ dontClearDatabaseOnStop();
}
);
- await with_stopped_app(async ({ app, rest_api }) => {
- create_collections(app);
+ await withStoppedApp(async ({ app, rest_api }) => {
+ createCollections(app);
await app.start();
await assert_status_equals(rest_api, account_ids[0], "created");
await assert_status_equals(rest_api, account_ids[1], "suspended");
});
});
it("Correctly updates cached-value on create", async () =>
- with_running_app(async ({ app, rest_api }) => {
- create_collections(app);
+ withRunningApp(async ({ app, rest_api }) => {
+ createCollections(app);
const account_ids = [];
for (const username of ["user_1", "user_2"]) {
account_ids.push(await add_account(rest_api, { username }));
}
await assert_status_equals(rest_api, account_ids[0], "created");
const actions = ["open", "suspend", "close"];
for (let action of actions) {
await rest_api.post("/api/v1/collections/actions", {
name: action,
account: account_ids[0],
});
const status = action_to_status[action];
await assert_status_equals(rest_api, account_ids[0], status);
await assert_status_equals(rest_api, account_ids[1], "created");
}
}));
it("Correctly updates cached-value on update", async () =>
- with_running_app(async ({ app, rest_api }) => {
- create_collections(app);
+ withRunningApp(async ({ app, rest_api }) => {
+ createCollections(app);
const account_id = await add_account(rest_api, {
username: "user_1",
});
const {
items: [{ id: action_id }],
} = await rest_api.get("/api/v1/collections/actions", {
account: account_id,
});
await rest_api.patch(`/api/v1/collections/actions/${action_id}`, {
name: "open",
});
await assert_status_equals(rest_api, account_id, "open");
}));
it("Respects is_proper_value of base field type", async () =>
- with_running_app(async ({ app }) => {
- create_collections(app);
- await assert_throws_async(
+ withRunningApp(async ({ app }) => {
+ createCollections(app);
+ await assertThrowsAsync(
() =>
- app.run_action(
+ app.runAction(
new SuperContext(),
["collections", "accounts"],
"create",
{ username: "user_2", number: -1 }
),
(error) => {
assert.equal(
error.data.number.message,
"Value should be larger or equal to '0'."
);
}
);
}));
it("Respects filters of base field type", async () =>
- with_running_app(async ({ app, rest_api }) => {
- create_collections(app);
+ withRunningApp(async ({ app, rest_api }) => {
+ createCollections(app);
await add_a_few_accounts(app);
const { items: accounts } = await rest_api.get(
"/api/v1/collections/accounts?filter[number][>]=3"
);
assert.equal(accounts.length, 2);
}));
it("Respects format of base field type", async () =>
- with_running_app(async ({ app, rest_api }) => {
- create_collections(app);
+ withRunningApp(async ({ app, rest_api }) => {
+ createCollections(app);
const id = await add_account(rest_api, { username: "user_1" });
const expected_datetime = getDateTime(
new Date("2018-01-01"),
"yyyy-mm-dd hh:mm:ss"
);
const actual_datetime = ((await rest_api.getSealiousResponse(
`/api/v1/collections/accounts/${id}?format[date_time]=human_readable`
)) as any).date_time;
assert.equal(actual_datetime, expected_datetime);
}));
it("Properly responds to recursive edits", async () =>
- with_running_app(async ({ app }) => {
- await assert_throws_async(
+ withRunningApp(async ({ app }) => {
+ await assertThrowsAsync(
async () => {
Collection.fromDefinition(app, {
name: "happy-numbers",
fields: [
{
name: "number",
type: "int",
required: true,
},
{
name: "double_number",
type: "cached-value",
params: {
base_field_type: { name: "int" },
get_value: async (
context: Context,
number_id: string
) => {
- const sealious_response = await app.run_action(
+ const sealious_response = await app.runAction(
context,
[
"collections",
"happy-numbers",
number_id,
],
"show"
);
return sealious_response.number * 2;
},
refresh_on: [
{
event_matcher: new app.Sealious.EventMatchers.Collection(
{
when: "after",
collection_name:
"happy-numbers",
action: "create",
}
),
resource_id_getter: (
_: any,
resource: Item
) => resource.id,
},
],
},
},
],
});
},
(error) =>
assert.equal(
error,
`Error: In the happy-numbers collection definition you've tried to create the double_number cached-value field that refers to the collection itself. Consider using 'derived-value' field type to avoid problems with endless recurrence.`
)
);
}));
});
function make_refresh_on(app: App) {
return [
{
event_matcher: new app.Sealious.EventMatchers.Collection({
when: "after",
collection_name: "actions",
action: "create",
}),
resource_id_getter: (_: any, resource: Item) => resource.account,
},
{
event_matcher: new app.Sealious.EventMatchers.Resource({
when: "after",
collection_name: "actions",
action: "edit",
}),
resource_id_getter: (_: any, resource: Item) => resource.account,
},
];
}
async function assert_status_equals(
rest_api: MockRestApi,
account_id: string,
expected_status: string
) {
const response = (await rest_api.getSealiousResponse(
`/api/v1/collections/accounts/${account_id}`
)) as SingleItemResponse;
assert.equal(response.status, expected_status);
}
diff --git a/src/app/base-chips/field-types/cached-value.ts b/src/app/base-chips/field-types/cached-value.ts
index 78c74fcf..143fb07c 100644
--- a/src/app/base-chips/field-types/cached-value.ts
+++ b/src/app/base-chips/field-types/cached-value.ts
@@ -1,182 +1,182 @@
import {
App,
Field,
Context,
EventDescription,
EventMatchers,
SuperContext,
} from "../../../main";
import { EventMatcher } from "../../event-matchers";
import HybridField, {
HybridFieldParams,
} from "../../../chip-types/field-hybrid";
type RefreshCondition = {
event_matcher: EventMatcher;
resource_id_getter: (
emitted_event: EventDescription,
response: any
) => Promise<string>;
};
type GetValue<T extends Field> = (
context: Context,
resource_id: string
) => Promise<Parameters<T["encode"]>[1]>;
export default class CachedValue<T extends Field> extends HybridField<T> {
getTypeName = () => "cached-value";
value_path_after_field_name: ".value";
app: App;
refresh_on: RefreshCondition[];
get_value: GetValue<T>;
setParams(
params: HybridFieldParams<T> & {
refresh_on: RefreshCondition[];
get_value: GetValue<T>;
}
) {
super.setParams(params);
this.refresh_on = params.refresh_on;
this.get_value = params.get_value;
}
async init(app: App) {
this.app = app;
this.checkForPossibleRecursiveEdits();
const create_action = this.refresh_on.find(({ event_matcher }) =>
event_matcher.containsAction("create")
);
if (create_action) {
app.on("start", () =>
this._refresh_outdated_cache_values(create_action)
);
}
for (let { event_matcher, resource_id_getter } of this.refresh_on) {
app.addHook(event_matcher, async (emitted_event, resource) => {
const cache_resource_id = await resource_id_getter(
emitted_event,
resource
);
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(
emitted_event.metadata.context
),
["collections", this.collection.name, cache_resource_id],
"edit",
{
[this.name]: await this.get_value(
emitted_event.metadata.context,
cache_resource_id
),
}
);
});
}
}
checkForPossibleRecursiveEdits() {
const doesAnyMatches = this.refresh_on.some(({ event_matcher }) => {
if (
event_matcher instanceof EventMatchers.Collection ||
event_matcher instanceof EventMatchers.Resource
) {
return event_matcher.collection_name === this.collection.name;
}
return event_matcher.subject_path.test(
`collections.${this.collection.name}`
);
});
if (doesAnyMatches) {
throw new Error(
"In the " +
this.collection.name +
" collection definition you've tried to create the " +
this.name +
" cached-value field that refers to the collection itself. Consider using 'derived-value' field type to avoid problems with endless recurrence."
);
}
}
async _refresh_outdated_cache_values(create_action: RefreshCondition) {
const referenced_collection_name =
create_action.event_matcher.collection_name;
if (!referenced_collection_name) {
this.app.Logger.debug(
"Not refreshing outdated values, unknown collection for: " +
JSON.stringify(create_action)
);
return;
}
- const response = await this.app.run_action(
+ const response = await this.app.runAction(
new SuperContext(),
["collections", referenced_collection_name],
"show",
{
sort: { "_metadata.last_modified_context.timestamp": "desc" },
pagination: { items: 1 },
}
);
if (response.empty) {
return;
}
const last_modified_timestamp =
response.items[0]._metadata.last_modified_context.timestamp;
const outdated_resources = await this.app.Datastore.aggregate(
this.collection.name,
[
{
$match: {
$or: [
{
[`${this.name}.timestamp`]: {
$lt: last_modified_timestamp,
},
},
{ [this.name]: { $exists: false } },
],
},
},
]
);
if (!outdated_resources) {
return;
}
const context = new SuperContext();
for (let resource of outdated_resources) {
const cache_value = await this.encode(
context,
await this.get_value(context, resource.sealious_id)
);
await this.app.Datastore.update(
this.collection.name,
{ sealious_id: resource.sealious_id },
{ $set: { [this.name]: cache_value } }
);
}
}
async isProperValue(
context: Context,
new_value: Parameters<T["isProperValue"]>[1],
old_value: Parameters<T["isProperValue"]>[2]
) {
if (!context.is_super) {
return Promise.reject("This is a read-only field");
}
return this.virtual_field.isProperValue(context, new_value, old_value);
}
}
diff --git a/src/app/base-chips/field-types/control-access.subtest.ts b/src/app/base-chips/field-types/control-access.subtest.ts
index e33cae2b..7101e3b4 100644
--- a/src/app/base-chips/field-types/control-access.subtest.ts
+++ b/src/app/base-chips/field-types/control-access.subtest.ts
@@ -1,208 +1,205 @@
import assert from "assert";
-import {
- with_running_app,
- MockRestApi,
-} from "../../../test_utils/with-test-app.js";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
-import { App, Collection } from "../../../main.js";
+import { withRunningApp, MockRestApi } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
+import { App, Collection } from "../../../main";
const SSH_KEYS_URL = "/api/v1/collections/ssh-keys";
type Key = { [access in "_public" | "_private"]: string };
describe("control-access", () => {
let sessions: { [username: string]: {}[] } = {};
- async function create_ssh_keys_collections(app: App) {
+ async function createSshKeysCollections(app: App) {
Collection.fromDefinition(app, {
name: "ssh-keys",
fields: [
{
name: "public",
type: "text",
required: true,
},
{
name: "private",
type: "control-access",
params: {
target_access_strategies: {
show: ["roles", ["admin"]],
edit: ["roles", ["admin"]],
},
target_field_type_name: "text",
target_params: {
min_length: 3,
},
},
required: true,
},
],
access_strategy: {
default: "public",
create: ["roles", ["admin"]],
},
});
}
- async function setup_users(App: App, rest_api: MockRestApi) {
+ async function setupUsers(App: App, rest_api: MockRestApi) {
const password = "it-really-doesnt-matter";
let admin_id;
for (let username of ["admin", "regular-user"]) {
- const user = await App.run_action(
+ const user = await App.runAction(
new App.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username,
password,
email: `${username}@example.com`,
}
);
sessions[username] = await rest_api.login({
username,
password,
});
if (username === "admin") admin_id = user.id;
}
await rest_api.post(
"/api/v1/collections/user-roles",
{
user: admin_id,
role: "admin",
},
sessions.admin
);
}
- async function fill_keys_collections(App: App) {
+ async function fillKeysCollections(App: App) {
const keys: Key[] = [
{
_public: "a-public-key",
_private: "seeeeecret",
},
{
_public: "go-get-it",
_private: "you-cannot-see",
},
];
for (let { _public, _private } of keys) {
- await App.run_action(
+ await App.runAction(
new App.Sealious.SuperContext(),
["collections", "ssh-keys"],
"create",
{
public: _public,
private: _private,
}
);
}
}
async function setup(app: App, rest_api: MockRestApi) {
- await create_ssh_keys_collections(app);
- await fill_keys_collections(app);
- await setup_users(app, rest_api);
+ await createSshKeysCollections(app);
+ await fillKeysCollections(app);
+ await setupUsers(app, rest_api);
}
it("Hides a protected value from regular-user", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const { items: ssh_keys } = await rest_api.get(
SSH_KEYS_URL,
sessions["regular-user"]
);
ssh_keys.forEach((key: Key) => {
assert.deepEqual(key._private, "");
});
}));
it("Uncovers a protected value for admin", async () =>
- with_running_app(async ({ app, rest_api, base_url }) => {
+ withRunningApp(async ({ app, rest_api, base_url }) => {
await setup(app, rest_api);
const { items: ssh_keys } = await rest_api.get(
SSH_KEYS_URL,
sessions.admin
);
ssh_keys.forEach((key: Key) => {
assert(key._private.length >= 3);
});
}));
it("Respects given field type constraints", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
rest_api.post(
SSH_KEYS_URL,
{
public: "XDDDDDDDDDDDD",
private: "XD",
},
sessions.admin
),
(e) =>
assert.equal(
e.response.data.data.private.message,
"Text 'XD' is too short, minimum length is 3 chars."
)
);
}));
it("Allows admin to update a protected field", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const key = await rest_api.post(
SSH_KEYS_URL,
{
public: "123123",
private: "321321",
},
sessions.admin
);
const updated_key = await rest_api.patch(
`${SSH_KEYS_URL}/${key.id}`,
{
private: "654321",
},
sessions.admin
);
assert.deepEqual(updated_key.private, "654321");
}));
it("Doesn't allow regular-user to update a protected field", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const key = await rest_api.post(
SSH_KEYS_URL,
{
public: "123123",
private: "321321",
},
sessions.admin
);
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
rest_api.patch(
`${SSH_KEYS_URL}/${key.id}`,
{ private: "331c6883dd6010864b7ead130be77cd5" },
sessions["regular-user"]
),
(e) =>
assert.deepEqual(
e.response.data.data.private.message,
"You are not allowed to update this field."
)
);
}));
});
diff --git a/src/app/base-chips/field-types/derived-value.subtest.ts b/src/app/base-chips/field-types/derived-value.subtest.ts
index 3789120e..f9320f85 100644
--- a/src/app/base-chips/field-types/derived-value.subtest.ts
+++ b/src/app/base-chips/field-types/derived-value.subtest.ts
@@ -1,218 +1,218 @@
import assert from "assert";
-import { with_running_app } from "../../../test_utils/with-test-app.js";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
-import { App, Collection } from "../../../main.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
+import { App, Collection } from "../../../main";
const make_test_collection = (
app: App,
derived_value_params: {
deriving_fn: Function | string;
fields: string[] | string;
}
) => async () => {
Collection.fromDefinition(app, {
name: "people",
fields: [
{
name: "username",
type: "text",
required: true,
},
{
name: "surname",
type: "text",
required: true,
},
{
name: "name_and_surname",
type: "derived-value",
params: {
base_field_type: { name: "text" },
...derived_value_params,
},
},
{ name: "age", type: "int" },
],
});
};
describe("derived-value", () => {
it("throws when deriving_fn param is not a function", async () =>
- with_running_app(async ({ app }) => {
- await assert_throws_async(
+ withRunningApp(async ({ app }) => {
+ await assertThrowsAsync(
make_test_collection(app, {
fields: ["username", "surname"],
deriving_fn: "definitely not a function",
}),
(error) => {
assert.equal(
error,
`Error: 'deriving_fn' param in name_and_surname derived-value field is not a function.`
);
}
);
}));
it("throws when field param is not an array", async () =>
- with_running_app(async ({ app }) => {
- await assert_throws_async(
+ withRunningApp(async ({ app }) => {
+ await assertThrowsAsync(
make_test_collection(app, {
fields: "definitely not an array",
deriving_fn: () => {},
}),
(error) => {
assert.equal(
error,
`Error: 'fields' param in name_and_surname derived-value field is not an array.`
);
}
);
}));
it("throws when at least one of the elements of fields param is not declared in the collection", async () =>
- with_running_app(async ({ app }) => {
- await assert_throws_async(
+ withRunningApp(async ({ app }) => {
+ await assertThrowsAsync(
make_test_collection(app, {
fields: ["username", "shoe_size"],
deriving_fn: () => {},
}),
(error) => {
assert.equal(
error,
`Error: Missing declaration for fields from derived-value params: 'shoe_size' in people collection. REMEMBER: 'derived-value' field must be declared *after* the fields it depends on.`
);
}
);
}));
it("throws an error if given value that is not proper for some field", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await make_test_collection(app, {
fields: ["username", "surname"],
deriving_fn: async (username: string, surname: string) =>
`${username} ${surname}`,
})();
- await assert_throws_async(
+ await assertThrowsAsync(
async () => {
const person = await rest_api.post(
"/api/v1/collections/people",
{
username: "Antoine",
surname: 123123,
}
);
},
(error) =>
assert.deepEqual(
error.response.data.data.surname.message,
"Type of 123123 is number, not string."
)
);
}));
it("properly reacts to pre:create handler", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await make_test_collection(app, {
fields: ["username", "surname"],
deriving_fn: async (username: string, surname: string) =>
`${username} ${surname}`,
})();
const person = await rest_api.post("/api/v1/collections/people", {
username: "Jan",
surname: "Kowalski",
});
assert.deepEqual("Jan Kowalski", person.name_and_surname);
}));
it("properly reacts to pre:edit handler", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await make_test_collection(app, {
fields: ["username", "surname"],
deriving_fn: async (username: string, surname: string) =>
`${username} ${surname}`,
})();
const person = await rest_api.post("/api/v1/collections/people", {
username: "Jan",
surname: "Kowalski",
});
assert.deepEqual("Jan Kowalski", person.name_and_surname);
const updated_person = await rest_api.patch(
`/api/v1/collections/people/${person.id}`,
{
username: "Janusz",
}
);
assert.deepEqual(updated_person.username, "Janusz");
assert.deepEqual(
updated_person.name_and_surname,
"Janusz Kowalski"
);
const updated_person2 = await rest_api.patch(
`/api/v1/collections/people/${person.id}`,
{
username: "John",
surname: "Doe",
}
);
assert.deepEqual(updated_person2.username, "John");
assert.deepEqual(updated_person2.surname, "Doe");
assert.deepEqual(updated_person2.name_and_surname, "John Doe");
}));
it("value isn't undefined after edit on fields other than the ones conerning derived_value", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await make_test_collection(app, {
fields: ["username", "surname"],
deriving_fn: async (username: string, surname: string) =>
`${username} ${surname}`,
})();
const person = await rest_api.post("/api/v1/collections/people", {
username: "Jan",
surname: "Kowalski",
age: 60,
});
assert.deepEqual(60, person.age);
const updated_person = await rest_api.patch(
`/api/v1/collections/people/${person.id}`,
{
age: 22,
}
);
assert.deepEqual(updated_person.age, 22);
assert.deepEqual(updated_person.name_and_surname, "Jan Kowalski");
}));
it("throws when the value returned from deriving_fn is unnacceptable by target_field_type of derived-value", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await make_test_collection(app, {
fields: ["username", "surname"],
deriving_fn: async (_: string, __: string) => 555,
})();
- await assert_throws_async(
+ await assertThrowsAsync(
async () => {
await rest_api.post("/api/v1/collections/people", {
username: "Jan",
surname: "Kowalski",
});
},
(error) => {
assert.deepEqual(
error.response.data.data.name_and_surname.message,
"Type of 555 is number, not string."
);
}
);
}));
});
diff --git a/src/app/base-chips/field-types/derived-value.ts b/src/app/base-chips/field-types/derived-value.ts
index 3e400bc6..3a602f47 100644
--- a/src/app/base-chips/field-types/derived-value.ts
+++ b/src/app/base-chips/field-types/derived-value.ts
@@ -1,147 +1,147 @@
import {
HybridField,
Field,
ExtractOutput,
App,
Context,
HybridFieldParams,
} from "../../../main";
import Bluebird from "bluebird";
/*
todo: make the deriving_fn more type-safe by reading the types of the fields?
*/
type DerivingFn<T extends Field> = (
...args: any[]
) => Promise<ExtractOutput<T>>;
export default class DerivedValue<T extends Field> extends HybridField<T> {
getTypeName = () => "derived-value";
fields: Field[];
deriving_fn: DerivingFn<T>;
private async checkAllCollectionFields(
context: Context,
event_params: { [field_name: string]: any }
) {
for (const field_name in event_params) {
try {
await this.collection.fields[field_name].isProperValue(
context,
event_params[field_name],
null
);
} catch (e) {
return;
}
}
}
setParams(
params: HybridFieldParams<T> & {
fields: Field[];
deriving_fn: DerivingFn<T>;
}
) {
super.setParams(params);
this.fields = params.fields;
this.deriving_fn = params.deriving_fn;
if (typeof this.deriving_fn !== "function") {
throw new Error(
`'derived_fn' param in ${this.name} derived-value field is not a function.`
);
}
if (!Array.isArray(this.fields)) {
throw new Error(
`'fields' param in ${this.name} derived-value field is not an array.`
);
}
const not_matching_fields = this.fields.filter(
(field) => !Object.values(this.collection.fields).includes(field)
);
if (not_matching_fields.length) {
throw new Error(
`Missing declaration for fields from derived-value params: ${not_matching_fields
.map((field) => `'${field}'`)
.join(", ")} in ${
this.collection.name
} collection. REMEMBER: 'derived-value' field must be declared *after* the fields it depends on.`
);
}
}
init(app: App) {
app.addHook(
new app.Sealious.EventMatchers.Collection({
when: "before",
collection_name: this.collection.name,
action: "create",
}),
async (event, params) => {
this.checkAllCollectionFields(event.metadata.context, params);
const derived_fn_args = this.fields.map((field) =>
params[field.name] === undefined ||
params[field.name] === null
? ""
: params[field.name]
);
const derived_value = await this.deriving_fn(
...derived_fn_args
);
return {
[this.name]: derived_value,
...params,
};
}
);
app.addHook(
new app.Sealious.EventMatchers.Resource({
when: "before",
collection_name: this.collection.name,
action: "edit",
}),
async ({ metadata, subject_path }, params) => {
this.checkAllCollectionFields(metadata.context, params);
if (
this.fields.some((field) =>
Object.values(params).includes(field)
)
) {
const derived_fn_args = await Bluebird.map(
this.fields,
async ({ name: current_field }) => {
if (Object.keys(params).includes(current_field)) {
return params[current_field];
}
- const sealious_response = await app.run_action(
+ const sealious_response = await app.runAction(
new app.Sealious.SuperContext(),
subject_path.split("."),
"show"
);
return sealious_response[current_field];
}
);
const derived_value = await this.deriving_fn(
...derived_fn_args
);
return {
...params,
[this.name]: derived_value,
};
}
return params;
}
);
}
}
diff --git a/src/app/base-chips/field-types/disallow-update.subtest.ts b/src/app/base-chips/field-types/disallow-update.subtest.ts
index abd5fdc7..ec4397ad 100644
--- a/src/app/base-chips/field-types/disallow-update.subtest.ts
+++ b/src/app/base-chips/field-types/disallow-update.subtest.ts
@@ -1,119 +1,119 @@
import { App, Field, Context, Collection } from "../../../main";
import assert from "assert";
-import { with_running_app } from "../../../test_utils/with-test-app.js";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
const url = "/api/v1/collections/constseals";
describe("disallow-update", () => {
async function setup(app: App) {
class NullOrFive extends Field {
getTypeName = () => "null-or-five";
async isProperValue(_: Context, __: any, new_value: any) {
if (new_value === null || new_value === 5) {
return Field.valid();
}
return Field.invalid("Null or five, you got it?");
}
}
Collection.fromDefinition(app, {
name: "constseals",
fields: [
{
name: "age",
type: "disallow-update",
params: {
target_field: {
type: "int",
params: {
min: 0,
},
},
},
required: true,
},
{
name: "attribute",
type: "disallow-update",
params: {
target_field: {
type: NullOrFive,
},
},
required: true,
},
],
access_strategy: {
default: "public",
},
});
}
it("Respects target field type", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
- await assert_throws_async(
+ await assertThrowsAsync(
() => rest_api.post(url, { age: "abc", attribute: 5 }),
(error) => {
assert.deepEqual(
error.response.data.data.age.message,
"Value 'abc' is not a int number format."
);
}
);
}));
it("Respects target field params", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
- await assert_throws_async(
+ await assertThrowsAsync(
() => rest_api.post(url, { age: -2 }),
(error) =>
assert.deepEqual(
error.response.data.data.age.message,
"Value should be larger or equal to '0'."
)
);
}));
it("Initially allows to insert a value", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
await rest_api.post(url, { age: 2, attribute: 5 });
}));
it("Rejects a new value if there's an old value", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
const { id } = await rest_api.post(url, {
age: 18,
attribute: null,
});
- await assert_throws_async(
+ await assertThrowsAsync(
() => rest_api.patch(`${url}/${id}`, { age: 21 }),
(error) =>
assert.deepEqual(
error.response.data.data.age.message,
"You cannot change previously set value."
)
);
}));
it("Rejects a new value if the old value is `null`", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
const { id } = await rest_api.post(url, {
age: 21,
attribute: null,
});
- await assert_throws_async(
+ await assertThrowsAsync(
() => rest_api.patch(`${url}/${id}`, { attribute: 5 }),
(error) =>
assert.deepEqual(
error.response.data.data.attribute.message,
"You cannot change previously set value."
)
);
}));
});
diff --git a/src/app/base-chips/field-types/field-types.test.js b/src/app/base-chips/field-types/field-types.test.js
deleted file mode 100644
index 2419cee1..00000000
--- a/src/app/base-chips/field-types/field-types.test.js
+++ /dev/null
@@ -1,14 +0,0 @@
-describe("field types", () => {
- require("./cached-value.subtest.js");
- require("./single_reference.subtest.js");
- require("./text.subtest");
- require("./int.subtest.js");
- require("./reverse-single-reference.subtest.js");
- require("./settable-by.subtest.js");
- require("./control-access.subtest");
- require("./json-object.subtest.js");
- require("./password.subtest.js");
- require("./derived-value.subtest.js");
- require("./disallow-update.subtest");
- require("./boolean.subtest");
-});
diff --git a/src/app/base-chips/field-types/field-types.test.ts b/src/app/base-chips/field-types/field-types.test.ts
new file mode 100644
index 00000000..e99f78df
--- /dev/null
+++ b/src/app/base-chips/field-types/field-types.test.ts
@@ -0,0 +1,14 @@
+describe("field types", () => {
+ require("./cached-value.subtest");
+ require("./single-reference.subtest");
+ require("./text.subtest");
+ require("./int.subtest");
+ require("./reverse-single-reference.subtest");
+ require("./settable-by.subtest");
+ require("./control-access.subtest");
+ require("./json-object.subtest");
+ require("./password.subtest");
+ require("./derived-value.subtest");
+ require("./disallow-update.subtest");
+ require("./boolean.subtest");
+});
diff --git a/src/app/base-chips/field-types/int.subtest.ts b/src/app/base-chips/field-types/int.subtest.ts
index a446f5cb..b4cb51f7 100644
--- a/src/app/base-chips/field-types/int.subtest.ts
+++ b/src/app/base-chips/field-types/int.subtest.ts
@@ -1,199 +1,199 @@
import Axios from "axios";
import { equal, deepEqual } from "assert";
-import { with_running_app } from "../../../test_utils/with-test-app.js";
-import { assert_throws_async } from "../../../test_utils";
-import { IntStorageParams } from "./int.js";
-import { App, Collection } from "../../../main.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
+import { IntStorageParams } from "./int";
+import { App, Collection } from "../../../main";
describe("int", () => {
const COLLECTION_NAME = "ages";
function assertFormatIsNotAccepted(provided_value: any) {
- return with_running_app(async ({ app, base_url }) => {
- await create_test_collection({
+ return withRunningApp(async ({ app, base_url }) => {
+ await createTestCollection({
app,
});
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
Axios.post(
`${base_url}/api/v1/collections/${COLLECTION_NAME}`,
{
age: provided_value,
}
),
(e) => {
equal(
e.response.data.data.age.message,
`Value '${provided_value}' is not a int number format.`
);
}
);
});
}
- async function create_test_collection({
+ async function createTestCollection({
app,
params,
}: {
app: App;
params?: IntStorageParams;
}) {
Collection.fromDefinition(app, {
name: COLLECTION_NAME,
fields: [
{
name: "age",
type: "int",
params,
},
],
});
}
it("should allow an integer value", async () =>
- with_running_app(async ({ app, base_url }) => {
- await create_test_collection({
+ withRunningApp(async ({ app, base_url }) => {
+ await createTestCollection({
app,
});
const { data: response } = await Axios.post(
`${base_url}/api/v1/collections/${COLLECTION_NAME}`,
{
age: 10,
}
);
equal(response.age, 10);
}));
it("should allow a string which can be interpreted as an integer value", async () =>
- with_running_app(async ({ app, base_url }) => {
- await create_test_collection({
+ withRunningApp(async ({ app, base_url }) => {
+ await createTestCollection({
app,
});
const { data: response } = await Axios.post(
`${base_url}/api/v1/collections/${COLLECTION_NAME}`,
{
age: "1",
}
);
equal(response.age, 1);
}));
it("should respect given min and max value", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
const [min, max] = [30, 50];
- await create_test_collection({
+ await createTestCollection({
app,
params: { min, max },
});
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
Axios.post(
`${base_url}/api/v1/collections/${COLLECTION_NAME}`,
{
age: 29,
}
),
(e) => {
equal(
e.response.data.data.age.message,
`Value should be larger or equal to '${min}'.`
);
}
);
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
Axios.post(
`${base_url}/api/v1/collections/${COLLECTION_NAME}`,
{
age: 51,
}
),
(e) => {
equal(
e.response.data.data.age.message,
`Value should be smaller or equal to '${max}'.`
);
}
);
}));
it("should let proper a string as an integer value in the defined range", async () =>
- with_running_app(async ({ app, base_url }) => {
- await create_test_collection({
+ withRunningApp(async ({ app, base_url }) => {
+ await createTestCollection({
app,
params: { min: -2, max: 6 },
});
return Axios.post(
`${base_url}/api/v1/collections/${COLLECTION_NAME}`,
{
age: "-1",
}
).then((response) => deepEqual(response.status, 201));
}));
it("should allow a largest integer value", async () =>
- with_running_app(async ({ app, base_url }) => {
- await create_test_collection({
+ withRunningApp(async ({ app, base_url }) => {
+ await createTestCollection({
app,
});
const { data: response } = await Axios.post(
`${base_url}/api/v1/collections/${COLLECTION_NAME}`,
{
age: Number.MAX_SAFE_INTEGER,
}
);
equal(response.age, Number.MAX_SAFE_INTEGER);
}));
it("should allow a smallest integer value provided as a string value", async () =>
- with_running_app(async ({ app, base_url }) => {
- await create_test_collection({
+ withRunningApp(async ({ app, base_url }) => {
+ await createTestCollection({
app,
});
const { data: response } = await Axios.post(
`${base_url}/api/v1/collections/${COLLECTION_NAME}`,
{
age: Number.MIN_SAFE_INTEGER.toString(),
}
);
equal(response.age, Number.MIN_SAFE_INTEGER);
}));
it("should allow a string with whitespace characters which can be interpreted as an integer value", async () =>
- with_running_app(async ({ app, base_url }) => {
- await create_test_collection({
+ withRunningApp(async ({ app, base_url }) => {
+ await createTestCollection({
app,
});
const { data: response } = await Axios.post(
`${base_url}/api/v1/collections/${COLLECTION_NAME}`,
{
age: " -20 ",
}
);
equal(response.age, -20);
}));
it("shouldn't allow a boolean value", async () =>
await assertFormatIsNotAccepted(true));
it("shouldn't allow an object value", async () =>
await assertFormatIsNotAccepted({}));
it("shouldn't allow a string which cannot be interpreted as an integer value", async () =>
await assertFormatIsNotAccepted("2013ffff"));
it("shouldn't allow a float number which cannot be interpreted as an integer value", async () =>
await assertFormatIsNotAccepted(1.2));
it("shouldn't allow a float number inserted as a string which cannot be interpreted as an integer value", async () =>
await assertFormatIsNotAccepted("1.2"));
});
diff --git a/src/app/base-chips/field-types/json-object.subtest.ts b/src/app/base-chips/field-types/json-object.subtest.ts
index 6c439a42..ffe369b2 100644
--- a/src/app/base-chips/field-types/json-object.subtest.ts
+++ b/src/app/base-chips/field-types/json-object.subtest.ts
@@ -1,148 +1,148 @@
import assert from "assert";
-import { with_running_app } from "../../../test_utils/with-test-app.js";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
-import { App, Collection } from "../../../main.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
+import { App, Collection } from "../../../main";
describe("json-object", () => {
function setup(app: App) {
Collection.fromDefinition(app, {
name: "seals",
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "metadata",
type: "json-object",
required: true,
params: {},
},
],
});
}
it("Correctly adds and edits record with json field", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
setup(app);
const item = {
name: "Hoover",
metadata: {
gender: "male",
weight: 300,
},
};
const { id } = await rest_api.post(
"/api/v1/collections/seals",
item
);
let { name, metadata } = (await rest_api.getSealiousResponse(
`/api/v1/collections/seals/${id}`
)) as any;
assert.deepEqual({ name, metadata }, item);
item.metadata.weight = 320;
await rest_api.patch(`/api/v1/collections/seals/${id}`, item);
let {
name: name2,
metadata: metadata2,
} = (await rest_api.getSealiousResponse(
`/api/v1/collections/seals/${id}`
)) as any;
assert.deepEqual({ name2, metadata2 }, item);
}));
it("Doesn't allow to post a primitive", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
setup(app);
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
rest_api.post("/api/v1/collections/seals", {
name: "Hoover",
metadata: "atadatem",
}),
(e) =>
assert.equal(
e.response.data.data.metadata.message,
"A primitive, not an object!"
)
);
}));
it("Respects filter passed to query", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
setup(app);
await rest_api.post("/api/v1/collections/seals", {
name: "Hoover",
metadata: {
gender: "male",
weight: 300,
},
});
await rest_api.post("/api/v1/collections/seals", {
name: "Maksiu",
metadata: {
gender: "male",
weight: 280,
},
});
let seals = (await rest_api.get("/api/v1/collections/seals")).items;
assert.equal(seals.length, 2);
seals = (
await rest_api.get(
"/api/v1/collections/seals?filter[name]=Hoover"
)
).items;
assert.equal(seals[0].name, "Hoover");
seals = (
await rest_api.get(
"/api/v1/collections/seals?filter[metadata][weight]=280"
)
).items;
assert.equal(seals.length, 1);
assert.equal(seals[0].name, "Maksiu");
}));
it("Respects filter passed to query when value can be parsed as number", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
setup(app);
const seals = [
{
name: "Hoover",
metadata: {
gender: "male",
weight: "300.253",
},
},
{
name: "Maksiu",
metadata: {
gender: "male",
weight: "280",
},
},
];
for (let seal of seals) {
await rest_api.post("/api/v1/collections/seals", seal);
}
for (let seal of seals) {
let { items: actual_seals } = await rest_api.get(
`/api/v1/collections/seals?filter[metadata][weight]=${seal.metadata.weight}`
);
assert.equal(actual_seals.length, 1);
assert.equal(actual_seals[0].name, seal.name);
}
}));
});
diff --git a/src/app/base-chips/field-types/json-object.ts b/src/app/base-chips/field-types/json-object.ts
index 2fc7f8ad..a4f2815c 100644
--- a/src/app/base-chips/field-types/json-object.ts
+++ b/src/app/base-chips/field-types/json-object.ts
@@ -1,53 +1,53 @@
import { Field, Context } from "../../../main";
import flattenObjectToDotNotation from "../../../utils/flatten-object-dot-notation";
export default class JsonObject extends Field<{}> {
getTypeName = () => "json-object";
async isProperValue(_: Context, new_value: {}, __: {}) {
let stringified_value;
try {
stringified_value = JSON.stringify(new_value);
} catch (e) {
return Field.invalid(
`Value ${new_value} cannot be represented as JSON object`
);
}
if (!stringified_value.startsWith("{")) {
return Field.invalid("A primitive, not an object!");
}
return Field.valid();
}
async encode(_: Context, value: {}) {
return JSON.parse(JSON.stringify(value));
}
async getAggregationStages(
_: Context,
{ filter }: Parameters<Field["getAggregationStages"]>[1]
) {
if (!filter) {
return [];
}
const flattened_filter = flattenObjectToDotNotation(
await this.getValuePath(),
filter
);
for (let prop_path of Object.keys(flattened_filter)) {
const filter_entry = flattened_filter[prop_path];
- flattened_filter[prop_path] = get_query_with_proper_operator(
+ flattened_filter[prop_path] = getQueryWithProperOperator(
filter_entry
);
}
return [{ $match: flattened_filter }];
}
}
-function get_query_with_proper_operator(filter: any) {
+function getQueryWithProperOperator(filter: any) {
let filter_as_number = parseFloat(filter);
return Number.isFinite(filter_as_number)
? { $in: [filter, filter_as_number] }
: { $eq: filter };
}
diff --git a/src/app/base-chips/field-types/password.subtest.ts b/src/app/base-chips/field-types/password.subtest.ts
index 4b9d600b..31f802e0 100644
--- a/src/app/base-chips/field-types/password.subtest.ts
+++ b/src/app/base-chips/field-types/password.subtest.ts
@@ -1,70 +1,70 @@
import assert from "assert";
-import { with_running_app } from "../../../test_utils/with-test-app.js";
-import SecureHasher from "../../../utils/secure-hasher.js";
-import App from "../../app.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import SecureHasher from "../../../utils/secure-hasher";
+import App from "../../app";
describe("password", () => {
const password = "it-really-doesnt-matter";
const username = "some-user";
let user_id: string;
async function setup(app: App) {
user_id = (
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username,
password,
email: "some-user@example.com",
}
)
).id;
}
it("Hides password", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app);
const session = await rest_api.login({
username,
password,
});
assert.ok(
!(
await rest_api.get(
`/api/v1/collections/users/${user_id}`,
session
)
).password
);
assert.ok(
!(
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users", user_id],
"show"
)
).password
);
}));
it("Stores correct password value", async () =>
- with_running_app(async ({ app }) => {
+ withRunningApp(async ({ app }) => {
await setup(app);
const hashed_password = (
await app.Datastore.find("users", {
sealious_id: user_id,
})
)[0].password;
assert.ok(await SecureHasher.matches(password, hashed_password));
assert.ok(
!(await SecureHasher.matches("wrong-password", hashed_password))
);
assert.ok(!(await SecureHasher.matches("", hashed_password)));
}));
});
diff --git a/src/app/base-chips/field-types/password.ts b/src/app/base-chips/field-types/password.ts
index 1c58273a..906e6fc9 100644
--- a/src/app/base-chips/field-types/password.ts
+++ b/src/app/base-chips/field-types/password.ts
@@ -1,21 +1,21 @@
-import SecureHasher from "../../../utils/secure-hasher.js";
-import { Context, Field } from "../../../main.js";
+import SecureHasher from "../../../utils/secure-hasher";
+import { Context, Field } from "../../../main";
const MIN_LENGTH = 8;
export default class Password extends Field<string> {
getTypeName = () => "password";
async isProperValue(_: Context, input: string) {
return input.length > MIN_LENGTH
? Field.valid()
: Field.invalid(
`Password must have at least ${MIN_LENGTH} characters`
);
}
async encode(_: Context, input: string) {
const hash_params = this.app.ConfigManager.get("password_hash");
const salt = SecureHasher.generateRandomSalt(hash_params.salt_length);
return SecureHasher.hash(input, salt, hash_params);
}
}
diff --git a/src/app/base-chips/field-types/reverse-single-reference.subtest.ts b/src/app/base-chips/field-types/reverse-single-reference.subtest.ts
index 3fcd7585..a2ac038d 100644
--- a/src/app/base-chips/field-types/reverse-single-reference.subtest.ts
+++ b/src/app/base-chips/field-types/reverse-single-reference.subtest.ts
@@ -1,205 +1,202 @@
import assert from "assert";
-import {
- with_stopped_app,
- MockRestApi,
-} from "../../../test_utils/with-test-app.js";
-import { App, Collection } from "../../../main.js";
-import { CollectionResponse } from "../../../../common_lib/response/responses.js";
+import { withStoppedApp, MockRestApi } from "../../../test_utils/with-test-app";
+import { App, Collection } from "../../../main";
+import { CollectionResponse } from "../../../../common_lib/response/responses";
describe("reverse-single-reference", () => {
- async function create_referencing_collections(
+ async function createReferencingCollections(
app: App,
with_reverse: boolean
) {
const A = Collection.fromDefinition(app, {
name: "A",
fields: [
{
name: "reference_to_b",
type: "single_reference",
params: { collection: "B" },
},
{
name: "pairity",
type: "text",
},
],
});
app.registerCollection(A);
const B = Collection.fromDefinition(app, {
name: "B",
fields: [{ name: "number", type: "int" }],
});
if (with_reverse) {
B.addField({
name: "references_in_a",
type: "reverse-single-reference",
params: { collection: "A", field_name: "reference_to_b" },
});
}
}
- async function create_resources(app: App) {
+ async function createResources(app: App) {
const numbers = [1, 2, 3];
const bs = [];
for (let number of numbers) {
bs.push(
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "B"],
"create",
{ number }
)
);
}
for (let b of bs) {
for (let i = 1; i <= b.number; i++) {
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "A"],
"create",
{ reference_to_b: b.id, pairity: i % 2 ? "odd" : "even" }
);
}
}
}
- async function with_reverse(
+ async function withReverse(
fn: (args: { app: App; rest_api: MockRestApi }) => Promise<void>
) {
- return with_stopped_app(async (args) => {
- await create_referencing_collections(
+ return withStoppedApp(async (args) => {
+ await createReferencingCollections(
args.app,
"with_reverse" && true
);
await args.app.start();
- await create_resources(args.app);
+ await createResources(args.app);
await fn(args);
});
}
it("recreates the cached values if the field has just been added", async () => {
- await with_stopped_app(async ({ app, dont_clear_database_on_stop }) => {
- await create_referencing_collections(app, "with_reverse" && false);
+ await withStoppedApp(async ({ app, dontClearDatabaseOnStop }) => {
+ await createReferencingCollections(app, "with_reverse" && false);
await app.start();
- await create_resources(app);
- dont_clear_database_on_stop();
+ await createResources(app);
+ dontClearDatabaseOnStop();
});
- await with_stopped_app(async ({ app, rest_api }) => {
- await create_referencing_collections(app, "with_reverse" && true);
+ await withStoppedApp(async ({ app, rest_api }) => {
+ await createReferencingCollections(app, "with_reverse" && true);
await app.start();
const {
items: [result],
} = await rest_api.get("/api/v1/collections/B?filter[number]=1");
assert(result.references_in_a);
assert.equal(result.references_in_a.length, 1);
const {
items: [result2],
} = await rest_api.get("/api/v1/collections/B?filter[number]=2");
assert(result2.references_in_a);
assert.equal(result2.references_in_a.length, 2);
});
});
it("updates the cached value when a new reference is created", async () => {
- await with_stopped_app(async ({ app, rest_api }) => {
- await create_referencing_collections(app, "with_reverse" && true);
+ await withStoppedApp(async ({ app, rest_api }) => {
+ await createReferencingCollections(app, "with_reverse" && true);
await app.start();
- await create_resources(app);
+ await createResources(app);
const {
items: [result],
} = await rest_api.get("/api/v1/collections/B?filter[number]=2");
assert(result.references_in_a instanceof Array);
assert.equal(result.references_in_a.length, 2);
});
});
it("updates the cached value when an old reference is deleted", async () =>
- with_reverse(async ({ rest_api }) => {
+ withReverse(async ({ rest_api }) => {
const {
items: [result],
} = await rest_api.get("/api/v1/collections/B?filter[number]=2");
const referencing_id = result.references_in_a[0];
await rest_api.delete(`/api/v1/collections/A/${referencing_id}`);
const {
items: [new_result2],
} = await rest_api.get("/api/v1/collections/B?filter[number]=2");
assert.equal(new_result2.references_in_a.length, 1);
}));
it("updates the cached value when an old reference is edited to a new one", async () =>
- with_reverse(async ({ rest_api }) => {
+ withReverse(async ({ rest_api }) => {
const {
items: [result1],
} = await rest_api.get("/api/v1/collections/B?filter[number]=1");
const {
items: [result2],
} = await rest_api.get("/api/v1/collections/B?filter[number]=2");
const referencing_id = result2.references_in_a[0];
await rest_api.patch(`/api/v1/collections/A/${referencing_id}`, {
reference_to_b: result1.id,
});
const {
items: [new_result2],
} = await rest_api.get("/api/v1/collections/B?filter[number]=2");
assert.equal(new_result2.references_in_a.length, 1);
const {
items: [new_result1],
} = await rest_api.get("/api/v1/collections/B?filter[number]=1");
assert.equal(new_result1.references_in_a.length, 2);
}));
it("updates the cached value when an old reference is edited to an empty one", async () =>
- with_reverse(async ({ rest_api }) => {
+ withReverse(async ({ rest_api }) => {
await rest_api.get("/api/v1/collections/B?filter[number]=1");
const {
items: [result2],
} = await rest_api.get("/api/v1/collections/B?filter[number]=2");
const referencing_id = result2.references_in_a[0];
await rest_api.patch(`/api/v1/collections/A/${referencing_id}`, {
reference_to_b: "",
});
const {
items: [new_result2],
} = await rest_api.get("/api/v1/collections/B?filter[number]=2");
assert.equal(new_result2.references_in_a.length, 1);
}));
it("allows to filter by a value of the referencing resource", async () =>
- with_reverse(async ({ rest_api }) => {
+ withReverse(async ({ rest_api }) => {
let results = (
await rest_api.get(
"/api/v1/collections/B?filter[references_in_a][pairity]=non-existant"
)
).items;
assert.equal(results.length, 0);
results = (
await rest_api.get(
"/api/v1/collections/B?filter[references_in_a][pairity]=odd"
)
).items;
assert.equal(results.length, 3);
results = (
await rest_api.get(
"/api/v1/collections/B?filter[references_in_a][pairity]=even&filter[number]=3"
)
).items;
assert.equal(results.length, 1);
}));
it("allows to display the full body of the referencing resources", async () =>
- with_reverse(async ({ rest_api }) => {
+ withReverse(async ({ rest_api }) => {
const response = (await rest_api.getSealiousResponse(
"/api/v1/collections/B?attachments[references_in_a]=true"
)) as CollectionResponse;
const { pairity } = (response.items[0].references_in_a as {
pairity: string;
}[])[0];
assert.equal(pairity, "odd");
}));
});
diff --git a/src/app/base-chips/field-types/reverse-single-reference.ts b/src/app/base-chips/field-types/reverse-single-reference.ts
index c574142c..65252d4f 100644
--- a/src/app/base-chips/field-types/reverse-single-reference.ts
+++ b/src/app/base-chips/field-types/reverse-single-reference.ts
@@ -1,197 +1,197 @@
import * as assert from "assert";
import { Field, Context, Collection, App } from "../../../main";
import { QueryStage } from "../../../datastore/query";
import ReferenceToCollection from "../../../subject/attachments/reference-to-collection";
import { CollectionResponse } from "../../../../common_lib/response/responses";
export default class ReverseSingleReference extends Field<never, string[]> {
getTypeName = () => "reverse-single-refernce";
referencing_field: Field;
private referencing_collection: Collection;
async isProperValue(context: Context, _: any) {
return context.is_super
? Field.valid()
: Field.invalid("This is a read-only field");
}
setParams(params: { referencing_field: Field }) {
this.referencing_field = params.referencing_field;
this.referencing_collection = params.referencing_field.collection;
}
getCacheKey() {
return `${this.collection.name}___${this.name}-reverse-single-reference(${this.referencing_field.collection.name},${this.referencing_field.name}).last_update`;
}
async init(app: App) {
app.on("started", async () => {
- const response = await app.run_action(
+ const response = await app.runAction(
new app.Sealious.SuperContext(),
["collections", this.collection.name],
"show",
{
sort: {
"_metadata.last_modified_context.timestamp": "desc",
},
pagination: { items: 1 },
}
);
if (response.empty) {
return;
}
const last_modified_resource_in_reference_collection =
response.items[0];
if (last_modified_resource_in_reference_collection) {
const last_modified_resource_timestamp =
last_modified_resource_in_reference_collection._metadata
.last_modified_context.timestamp;
const last_field_cache_update =
(await app.Metadata.get(this.getCacheKey())) || 0;
if (
last_modified_resource_timestamp > last_field_cache_update
) {
await this.updateCache();
await app.Metadata.set(this.getCacheKey(), Date.now());
}
}
});
app.addHook(
new app.Sealious.EventMatchers.Collection({
when: "after",
collection_name: this.referencing_field.collection.name,
action: "create",
}),
async (_, resource) => {
const referenced_id = resource[this.referencing_field.name];
await this.updateCache([referenced_id]);
}
);
app.addHook(
new app.Sealious.EventMatchers.Resource({
when: "after",
collection_name: this.referencing_field.collection.name,
action: "delete",
}),
async (emitted_event) => {
const deleted_id = emitted_event.subject_path.split(".")[2];
const affected = await app.Datastore.find(
this.collection.name,
{
[this.name]: deleted_id,
}
);
const affected_ids = affected.map(
(document: { sealious_id: string }) => document.sealious_id
);
await this.updateCache(affected_ids);
}
);
app.addHook(
new app.Sealious.EventMatchers.Resource({
when: "after",
collection_name: this.referencing_collection.name,
action: "edit",
}),
async ({ metadata, subject_path }) => {
if (
!metadata.params.hasOwnProperty(this.referencing_field.name)
)
return;
const edited_id = subject_path.split(".")[2];
const no_longer_referenced = await app.Datastore.find(
this.collection.name,
{
[this.name]: edited_id,
}
);
const affected_ids = no_longer_referenced.map(
(document: { sealious_id: string }) => document.sealious_id
);
if (metadata.params[this.referencing_field.name]) {
affected_ids.push(
metadata.params[this.referencing_field.name]
);
}
await this.updateCache(affected_ids);
}
);
}
async updateCache(resource_ids: string[] = []) {
let pipeline: QueryStage[];
if (resource_ids) {
assert.ok(Array.isArray(resource_ids));
pipeline = [
{
$match: {
[this.referencing_field.name]: { $in: resource_ids },
},
},
];
} else {
pipeline = [];
}
pipeline.push({
$group: {
_id: `$${this.referencing_field.name}`,
referenced_by: { $push: "$sealious_id" },
},
});
const to_update = await this.app.Datastore.aggregate(
this.referencing_field.collection.name,
pipeline
);
if (resource_ids) {
for (let resource_id of resource_ids) {
if (
to_update.filter(
(e: { _id: string }) => e._id === resource_id
).length === 0
) {
to_update.push({ _id: resource_id, referenced_by: [] });
}
}
}
for (let entry of to_update) {
await this.app.Datastore.update(
this.collection.name,
{ sealious_id: entry._id },
{ $set: { [this.name]: entry.referenced_by } }
);
}
}
getAttachmentLoader(
context: Context,
_: boolean,
attachment_params: ConstructorParameters<
typeof ReferenceToCollection
>[2]
) {
return new ReferenceToCollection(context, this.name, attachment_params);
}
async filterToQuery(context: Context, field_filter: any) {
if (typeof field_filter !== "object") {
return {
$eq: field_filter,
};
}
- const { items } = (await this.app.run_action(
+ const { items } = (await this.app.runAction(
context,
["collections", this.referencing_collection.name],
"show",
{ filter: field_filter }
)) as CollectionResponse;
return {
$in: items.map((resource) => resource.id),
};
}
}
diff --git a/src/app/base-chips/field-types/settable-by.subtest.ts b/src/app/base-chips/field-types/settable-by.subtest.ts
index 3fd42bb7..cfa6aae6 100644
--- a/src/app/base-chips/field-types/settable-by.subtest.ts
+++ b/src/app/base-chips/field-types/settable-by.subtest.ts
@@ -1,96 +1,96 @@
import assert from "assert";
import axios from "axios";
-import { assert_throws_async } from "../../../test_utils";
-import { with_running_app } from "../../../test_utils/with-test-app.js";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
+import { withRunningApp } from "../../../test_utils/with-test-app";
import App from "../../app";
import { SingleItemResponse } from "../../../../common_lib/response/responses";
import { Collection } from "../../../main";
describe("settable-by", async () => {
function create_collections(app: App) {
const int = app.ChipManager.getChip("field_type", "int");
Collection.fromDefinition(app, {
name: "forbidden-collection",
fields: [
{
name: "any",
type: "settable-by",
params: {
access_strategy_description: "noone",
target_field_type: int,
},
},
],
});
Collection.fromDefinition(app, {
name: "allowed-collection",
fields: [
{
name: "any",
type: "settable-by",
params: {
access_strategy_description: "public",
target_field_type: int,
},
},
],
});
}
it("should not allow any value when rejected by access strategy", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
create_collections(app);
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
axios.post(
`${base_url}/api/v1/collections/forbidden-collection`,
{
any: "thing",
}
),
(e) => assert.equal(e.response.data.message, "Noone gets in!")
);
}));
it("should allow proper value when accepted by access strategy", async () =>
- with_running_app(async ({ app, base_url, rest_api }) => {
+ withRunningApp(async ({ app, base_url, rest_api }) => {
create_collections(app);
const response = (
await axios.post(
`${base_url}/api/v1/collections/allowed-collection`,
{
any: 1,
}
)
).data;
assert.equal(response.any, 1);
const response2 = (await rest_api.getSealiousResponse(
`/api/v1/collections/allowed-collection/${response.id}`
)) as SingleItemResponse;
assert.equal(response2.any, 1);
}));
it("should not allow invalid value when access strategy allows", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
create_collections(app);
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
axios.post(
`${base_url}/api/v1/collections/allowed-collection`,
{
any: "thing",
}
),
(e) => {
assert.equal(
e.response.data.data.any.message,
"Value 'thing' is not a int number format."
);
}
);
}));
});
diff --git a/src/app/base-chips/field-types/single_reference.subtest.ts b/src/app/base-chips/field-types/single-reference.subtest.ts
similarity index 92%
rename from src/app/base-chips/field-types/single_reference.subtest.ts
rename to src/app/base-chips/field-types/single-reference.subtest.ts
index a44ee26e..8b3f9e3f 100644
--- a/src/app/base-chips/field-types/single_reference.subtest.ts
+++ b/src/app/base-chips/field-types/single-reference.subtest.ts
@@ -1,481 +1,478 @@
import assert from "assert";
-import {
- with_running_app,
- MockRestApi,
-} from "../../../test_utils/with-test-app.js";
-import assert_throws_async from "../../../test_utils/assert_throws_async.js";
-import { App, Item, Collection } from "../../../main.js";
-import { CollectionResponse } from "../../../../common_lib/response/responses.js";
+import { withRunningApp, MockRestApi } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
+import { App, Item, Collection } from "../../../main";
+import { CollectionResponse } from "../../../../common_lib/response/responses";
const A = "/api/v1/collections/A";
const B = "/api/v1/collections/B";
const C = "/api/v1/collections/C";
const Seals = "/api/v1/collections/seals";
const Water_Areas = "/api/v1/collections/water_areas";
const Water_Area_Types = "/api/v1/collections/water_area_types";
const Food = "/api/v1/collections/food";
describe("single_reference", () => {
describe("from A to B", () => {
async function create_referencing_collections(app: App) {
Collection.fromDefinition(app, {
name: "A",
fields: [
{
name: "reference_to_b",
type: "single_reference",
params: { collection: "B" },
},
{
name: "filtered_reference_to_b",
type: "single_reference",
params: { collection: "B", filter: { number: 1 } },
},
],
});
Collection.fromDefinition(app, {
name: "B",
fields: [{ name: "number", type: "int" }],
});
}
it("should not allow a value that is not an existing id", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await create_referencing_collections(app);
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
rest_api.post(A, {
reference_to_b: "non-existing-id",
}),
(e) =>
assert.equal(
e.response.data.data.reference_to_b.message,
"Nie masz dostępu do danego zasobu z kolekcji B lub on nie istnieje."
)
);
}));
it("should allow a value that exists in B", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await create_referencing_collections(app);
const { id } = await rest_api.post(B, { number: 1 });
await rest_api.post(A, {
reference_to_b: id,
});
}));
it("should not allow a value that exists in B but does not meet the filter criteria", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await create_referencing_collections(app);
const { id } = await rest_api.post(B, { number: 0 });
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
rest_api.post(A, {
filtered_reference_to_b: id,
}),
(e) =>
assert.equal(
e.response.data.data.filtered_reference_to_b
.message,
"Nie masz dostępu do danego zasobu z kolekcji B lub on nie istnieje."
)
);
}));
it("should allow a value that exists in B and meets the filter criteria", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await create_referencing_collections(app);
const { id } = await rest_api.post(B, { number: 1 });
await rest_api.post(A, { filtered_reference_to_b: id });
}));
it("should be filterable by referenced collection fields", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await create_referencing_collections(app);
for (let number of [1, 2, 3]) {
const { id } = await rest_api.post(B, { number });
await rest_api.post(A, { reference_to_b: id });
}
const response = (await rest_api.getSealiousResponse(
`${A}?filter[reference_to_b][number]=3&attachments[reference_to_b]=true`
)) as CollectionResponse;
assert.equal(response.items.length, 1);
assert.equal(response.items[0].reference_to_b.number, 3);
}));
it("should be filterable by referenced collection field of referenced collection field", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
// A => B => C
Collection.fromDefinition(app, {
name: "A",
fields: [
{
name: "reference_to_b",
type: "single_reference",
params: { collection: "B" },
},
],
});
Collection.fromDefinition(app, {
name: "B",
fields: [
{
name: "reference_to_c",
type: "single_reference",
params: { collection: "C" },
},
],
});
Collection.fromDefinition(app, {
name: "C",
fields: [
{
name: "number",
type: "int",
},
],
});
let c_ids = [];
let b_ids = [];
for (let number of [1, 2, 3]) {
const { id } = await rest_api.post(C, { number });
c_ids.push(id);
}
for (let c_id of c_ids) {
const { id } = await rest_api.post(B, {
reference_to_c: c_id,
});
b_ids.push(id);
}
for (let b_id of b_ids) {
await rest_api.post(A, { reference_to_b: b_id });
}
const response = (await rest_api.getSealiousResponse(
`${A}?filter[reference_to_b][reference_to_c][number]=3&attachments[reference_to_b][reference_to_c]=true`
)) as CollectionResponse;
assert.equal(response.items.length, 1);
assert.equal(
response.items[0].reference_to_b.reference_to_c.number,
3
);
}));
});
describe("from A to A", () => {
const items: { [name: string]: Item } = {};
async function setup(app: App, rest_api: MockRestApi) {
Collection.fromDefinition(app, {
name: "seals",
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "best_friend",
type: "single_reference",
params: { collection: "seals" },
},
],
});
items.hoover = await rest_api.post(Seals, {
name: "Hoover",
});
items.nelly = await rest_api.post(Seals, {
name: "Nelly",
best_friend: items.hoover.id,
});
items.maksiu = await rest_api.post(Seals, {
name: "Maksiu",
best_friend: items.nelly.id,
});
items.cycle = await rest_api.post(Seals, {
name: "Cycle",
});
await rest_api.patch(`${Seals}/${items.hoover.id}`, {
best_friend: items.maksiu.id,
});
await rest_api.patch(`${Seals}/${items.cycle.id}`, {
best_friend: items.cycle.id,
});
}
it("returns single attachment from directly referenced collection", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const {
items: [hoover, nelly, maksiu, cycle],
} = await rest_api.getSealiousResponse(
`${Seals}?attachments[best_friend]=true`
);
assert.equal(hoover.name, "Hoover");
assert.equal(hoover.best_friend.name, "Maksiu");
assert.equal(nelly.name, "Nelly");
assert.equal(nelly.best_friend.name, "Hoover");
assert.equal(maksiu.name, "Maksiu");
assert.equal(maksiu.best_friend.name, "Nelly");
assert.equal(cycle.name, "Cycle");
assert.equal(cycle.best_friend.name, "Cycle");
}));
});
describe("attachments behaviour", () => {
const items: { [name: string]: Item } = {};
async function setup(app: App, rest_api: MockRestApi) {
Collection.fromDefinition(app, {
name: "seals",
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "water_area",
type: "single_reference",
params: { collection: "water_areas" },
},
{
name: "favourite_meal",
type: "single_reference",
params: { collection: "food" },
},
],
});
Collection.fromDefinition(app, {
name: "water_areas",
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "type",
type: "single_reference",
params: { collection: "water_area_types" },
},
],
});
Collection.fromDefinition(app, {
name: "water_area_types",
fields: [
{
name: "type_name",
type: "text",
required: true,
},
{
name: "how_good_for_seals",
type: "text",
required: true,
},
],
});
Collection.fromDefinition(app, {
name: "food",
fields: [
{
name: "food_name",
type: "text",
required: true,
},
],
});
items.cool_sea = await rest_api.post(Water_Area_Types, {
type_name: "Cool Sea",
how_good_for_seals: "perfect",
});
items.warm_sea = await rest_api.post(Water_Area_Types, {
type_name: "Warm Sea",
how_good_for_seals: "okay",
});
items.warm_sea = await rest_api.post(Water_Area_Types, {
type_name: "Fantasy Sea",
how_good_for_seals: "hard_to_tell",
});
items.tuna = await rest_api.post(Food, {
food_name: "Tuna",
});
items.baltic_cod = await rest_api.post(Food, {
food_name: "Baltic Cod",
});
items.baltic_sea = await rest_api.post(Water_Areas, {
name: "Baltic Sea",
type: items.cool_sea.id,
});
items.arabic_sea = await rest_api.post(Water_Areas, {
name: "Arabic Sea",
type: items.warm_sea.id,
});
items.unused_sea = await rest_api.post(Water_Areas, {
name: "Unused Sea",
type: items.warm_sea.id,
});
items.hoover = await rest_api.post(Seals, {
name: "Hoover",
water_area: items.arabic_sea.id,
favourite_meal: items.tuna.id,
});
items.nelly = await rest_api.post(Seals, {
name: "Nelly",
water_area: items.baltic_sea.id,
favourite_meal: items.tuna.id,
});
items.maksiu = await rest_api.post(Seals, {
name: "Maksiu",
water_area: items.baltic_sea.id,
favourite_meal: items.baltic_cod.id,
});
}
it("returns single attachment from directly referenced collection", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const {
items: seals,
attachments,
fieldsWithAttachments,
} = await rest_api.get(`${Seals}?attachments[water_area]=true`);
assert.equal(seals.length, 3);
assert.deepEqual(fieldsWithAttachments, {
water_area: {},
});
assert.deepEqual(attachments, {
[items.baltic_sea.id]: items.baltic_sea,
[items.arabic_sea.id]: items.arabic_sea,
});
}));
it("returns attachments when single resource is queried", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const {
item: seal,
attachments,
fieldsWithAttachments,
} = await rest_api.get(
`${Seals}/${items.maksiu.id}?attachments[water_area]=true`
);
assert.equal(seal.name, items.maksiu.name);
assert.deepEqual(fieldsWithAttachments, {
water_area: {},
});
assert.deepEqual(attachments, {
[items.baltic_sea.id]: items.baltic_sea,
});
}));
it("throws error when not existing field is given to request", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const scenarios = {
"[fake_field_1]": "fake_field_1",
"[fake_field_1][fake_field_2]": "fake_field_1",
"[water_area][fake_field_2]": "fake_field_2",
};
for (let field_prop of Object.keys(scenarios)) {
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
rest_api.get(
`${Seals}?attachments${field_prop}=true`
),
(e) => {
assert.equal(e.response.status, 404);
assert.equal(
e.response.data.message,
`Given field ${
scenarios[
field_prop as keyof typeof scenarios
]
} is not declared in collection!`
);
}
);
}
}));
it("throws error when inappropriate field is given to request", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
- await assert_throws_async(
+ await assertThrowsAsync(
() => rest_api.get(`${Seals}?attachments[name]=true`),
(e) => {
assert.equal(e.response.status, 405);
assert.equal(
e.response.data.message,
"Given field name does not support attachments!"
);
}
);
}));
it("returns multiple attachments", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const {
items: seals,
attachments,
fieldsWithAttachments,
} = await rest_api.get(
`${Seals}?attachments[water_area][type]=true&attachments[favourite_meal]=true`
);
assert.equal(seals.length, 3);
assert.deepEqual(fieldsWithAttachments, {
water_area: {
type: {},
},
favourite_meal: {},
});
assert.deepEqual(attachments, {
[items.cool_sea.id]: items.cool_sea,
[items.warm_sea.id]: items.warm_sea,
[items.baltic_sea.id]: items.baltic_sea,
[items.arabic_sea.id]: items.arabic_sea,
[items.tuna.id]: items.tuna,
[items.baltic_cod.id]: items.baltic_cod,
});
}));
});
});
diff --git a/src/app/base-chips/field-types/single-reference.ts b/src/app/base-chips/field-types/single-reference.ts
index 48df65cd..6347e89d 100644
--- a/src/app/base-chips/field-types/single-reference.ts
+++ b/src/app/base-chips/field-types/single-reference.ts
@@ -1,118 +1,118 @@
import Bluebird from "bluebird";
import Collection from "../../../chip-types/collection";
import { Field, Context } from "../../../main";
import { CollectionResponse } from "../../../../common_lib/response/responses";
import ReferenceToCollection from "../../../subject/attachments/reference-to-collection";
export default class SingleReference extends Field<string> {
getTypeName = () => "single-reference";
hasIndex = () => true;
target_collection: Collection;
filter: any;
setParams(params: { target_collection: Collection; filter: any }) {
this.target_collection = params.target_collection;
this.filter = params.filter;
}
async isProperValue(context: Context, input: string) {
const filter = this.filter || {};
if (input === "") {
return Field.valid();
}
let stages = await this.target_collection.getAggregationStages(
context,
"show",
{ filter }
);
stages = [{ $match: { sealious_id: input } }, ...stages];
const results = await this.app.Datastore.aggregate(
this.target_collection.name,
stages
);
return results.length > 0
? Field.valid()
: Field.invalid(
`Nie masz dostępu do danego zasobu z kolekcji ${this.target_collection.name} lub on nie istnieje.`
);
}
async filterToQuery(context: Context, filter: any) {
// treating filter as a query here
if (typeof filter !== "object") {
return {
$eq: filter,
};
}
- const { items } = (await this.app.run_action(
+ const { items } = (await this.app.runAction(
context,
["collections", this.target_collection.name],
"show",
{
filter,
}
)) as CollectionResponse;
return { $in: items.map((resource) => resource.id) };
}
async getAggregationStages(
context: Context,
query: Parameters<Field["getAggregationStages"]>[1]
) {
let filter: { [field_name: string]: any } = {};
const temp_field_name = `${
this.target_collection.name
}-lookup${Math.floor(Math.random() * Math.pow(10, 7))}`;
const request_filter = query.filter && query.filter[this.name];
if (!request_filter || Object.keys(request_filter).length === 0)
return [];
if (typeof request_filter === "string") {
return [
{ $match: { [await this.getValuePath()]: request_filter } },
];
}
if (request_filter instanceof Array) {
let _in = request_filter;
if (request_filter[0] instanceof Array) _in = request_filter[0];
return [
{
$match: {
[await this.getValuePath()]: { $in: _in },
},
},
];
}
for (let field_name in request_filter) {
let field = this.target_collection.fields[field_name];
if (!field)
return Promise.reject(
"Unknown field in filter for '" +
this.target_collection.name +
"': " +
field_name
);
filter[`${temp_field_name}.0.${field_name}`] = field.filterToQuery(
context,
request_filter[field_name]
);
}
filter = Bluebird.props(filter);
return [
{
$lookup: {
from: this.target_collection.name,
localField: this.getValuePath(),
foreignField: "sealious_id",
as: temp_field_name,
},
},
{ $match: filter },
];
}
getAttachmentLoader(context: any, _: any, params: any) {
return new ReferenceToCollection(context, this.name, params);
}
}
diff --git a/src/app/base-chips/field-types/text.subtest.ts b/src/app/base-chips/field-types/text.subtest.ts
index 70568b66..cb78af67 100644
--- a/src/app/base-chips/field-types/text.subtest.ts
+++ b/src/app/base-chips/field-types/text.subtest.ts
@@ -1,105 +1,105 @@
import assert from "assert";
import axios from "axios";
-import { with_running_app } from "../../../test_utils/with-test-app.js";
-import { App, Collection } from "../../../main.js";
-import { TextParams } from "./text.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { App, Collection } from "../../../main";
+import { TextParams } from "./text";
describe("text", () => {
const COLLECTION_NAME = "surnames";
async function create_test_collection({
app,
params,
}: {
app: App;
params: TextParams;
}) {
Collection.fromDefinition(app, {
name: COLLECTION_NAME,
fields: [
{
name: "surname",
type: "text",
params,
},
],
});
}
function assert_creation_error_factory({
base_url,
collection,
}: {
base_url: string;
collection: string;
}) {
return async ({
resource,
message,
}: {
resource: { [field_name: string]: any };
message: string;
}) => {
try {
await axios.post(
`${base_url}/api/v1/collections/${collection}`,
resource
);
throw "This should not pass";
} catch (e) {
assert.deepEqual(e.response.data.data.surname.message, message);
}
};
}
it("shouldn't allow a value that isn't a string", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
await create_test_collection({ app, params: {} });
const assert_creation_error = assert_creation_error_factory({
base_url,
collection: COLLECTION_NAME,
});
await assert_creation_error({
resource: { surname: false },
message: "Type of false is boolean, not string.",
});
await assert_creation_error({
resource: { surname: {} },
message: "Type of [object Object] is object, not string.",
});
}));
it("should respect given min and max length", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
await create_test_collection({
app,
params: { min_length: 3, max_length: 5 },
});
const assert_creation_error = assert_creation_error_factory({
base_url,
collection: COLLECTION_NAME,
});
await assert_creation_error({
resource: { surname: "lo" },
message: "Text 'lo' is too short, minimum length is 3 chars.",
});
await assert_creation_error({
resource: { surname: "abcdefghijk" },
message:
"Text 'abcdefghijk' has exceeded max length of 5 chars.",
});
}));
it("should let proper string in", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
await create_test_collection({
app,
params: { min_length: 3, max_length: 5 },
});
return axios
.post(`${base_url}/api/v1/collections/surnames`, {
surname: "1234",
})
.then((resp) => assert.deepEqual(resp.status, 201));
}));
});
diff --git a/src/app/base-chips/field-types/username.ts b/src/app/base-chips/field-types/username.ts
index 2fee043d..9c5de7da 100644
--- a/src/app/base-chips/field-types/username.ts
+++ b/src/app/base-chips/field-types/username.ts
@@ -1,35 +1,35 @@
import Context from "../../../context";
import { Field } from "../../../main";
import me_synonyms from "../../../misc/me-synonyms";
-import SuperContext from "../../../super-context.js";
+import SuperContext from "../../../super-context";
import TextStorage from "./text-storage";
export default class Username extends TextStorage {
getTypeName = () => "username";
async isProperValue(
context: Context,
new_value: string,
old_value: string
) {
if (old_value === new_value) {
return Field.valid();
}
if (me_synonyms.indexOf(new_value) !== -1) {
return Field.invalid(
`'${new_value}' is a reserved keyword. Please pick another username.`
);
}
- const response = await this.app.run_action(
+ const response = await this.app.runAction(
new SuperContext(context),
["collections", "users"],
"show",
{ filter: { username: new_value } }
);
if (!response.empty) {
return Field.invalid("Username already taken");
}
return Field.valid();
}
}
diff --git a/src/app/base-chips/field-types/value-existing-in-collection.ts b/src/app/base-chips/field-types/value-existing-in-collection.ts
index bc7ce827..6b743c45 100644
--- a/src/app/base-chips/field-types/value-existing-in-collection.ts
+++ b/src/app/base-chips/field-types/value-existing-in-collection.ts
@@ -1,42 +1,42 @@
import Field from "../../../chip-types/field";
import { Context } from "../../../main";
export default class ValueExistingInCollection extends Field {
getTypeName = () => "value-existing-in-collection";
field: Field;
include_forbidden: boolean;
async isProperValue(
context: Context,
new_value: Parameters<this["field"]["isProperValue"]>[1],
old_value: Parameters<this["field"]["isProperValue"]>[2]
) {
const collection = this.field.collection;
await this.field.isProperValue(context, new_value, old_value);
if (this.include_forbidden) {
context = new this.app.Sealious.SuperContext();
}
- const sealious_response = await this.app.run_action(
+ const sealious_response = await this.app.runAction(
context,
["collections", collection.name],
"show",
{
filter: { [this.field.name]: new_value },
}
);
if (sealious_response.empty) {
return Field.invalid(
`No ${collection.name} with ${this.field.name} set to ${new_value}`
);
}
return Field.valid();
}
setParams(params: { field: Field; include_forbidden: boolean }) {
this.field = params.field;
this.include_forbidden = params.include_forbidden;
this.encode = this.field.encode;
this.format = this.field.format;
this.filterToQuery = this.field.filterToQuery;
this.getAggregationStages = this.field.getAggregationStages;
}
}
diff --git a/src/app/base-chips/field-types/value-not-existing-in-collection.ts b/src/app/base-chips/field-types/value-not-existing-in-collection.ts
index 17514aa9..cbb61291 100644
--- a/src/app/base-chips/field-types/value-not-existing-in-collection.ts
+++ b/src/app/base-chips/field-types/value-not-existing-in-collection.ts
@@ -1,28 +1,28 @@
import ValueExistingInCollection from "./value-existing-in-collection";
import { Context, Field } from "../../../main";
export default class ValueNotExistingInCollection extends ValueExistingInCollection {
getTypeName = () => "value-not-existing-in-collection";
async isProperValue(
context: Context,
new_value: Parameters<this["field"]["isProperValue"]>[1],
old_value: Parameters<this["field"]["isProperValue"]>[2]
) {
await this.field.isProperValue(context, new_value, old_value);
if (this.include_forbidden) {
context = new this.app.Sealious.SuperContext();
}
- const sealious_response = await this.app.run_action(
+ const sealious_response = await this.app.runAction(
context,
["collections", this.field.collection.name],
"show",
{ filter: { [this.field.name]: new_value } }
);
if (!sealious_response.empty) {
return Field.invalid(
`Collection ${this.field.collection.name} already has a record with '${this.field.name}' set to '${new_value}'`
);
}
return Field.valid();
}
}
diff --git a/src/app/base-chips/special_filters/IsReferencedByResourcesMatching.subtest.ts b/src/app/base-chips/special_filters/IsReferencedByResourcesMatching.subtest.ts
index 3af650d7..aa1f0f65 100644
--- a/src/app/base-chips/special_filters/IsReferencedByResourcesMatching.subtest.ts
+++ b/src/app/base-chips/special_filters/IsReferencedByResourcesMatching.subtest.ts
@@ -1,95 +1,95 @@
import * as assert from "assert";
-import { with_running_app } from "../../../test_utils/with-test-app.js";
-import { App, Collection } from "../../../main.js";
-import IsReferencedByResourcesMatching from "./IsReferencedByResourcesMatching.js";
-import { CollectionResponse } from "../../../../common_lib/response/responses.js";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { App, Collection } from "../../../main";
+import IsReferencedByResourcesMatching from "./IsReferencedByResourcesMatching";
+import { CollectionResponse } from "../../../../common_lib/response/responses";
describe("IsReferencedByResourcesMatching", () => {
async function setup(
app: App,
rest_api: import("../../../test_utils/with-test-app.js").MockRestApi
) {
const Users = app.ChipManager.getChip("collection", "users");
Users.set_access_strategy({
create: "public",
show: "public",
});
const UsersRoles = Collection.fromDefinition(app, {
name: "users-roles",
fields: [
{
name: "user",
type: "single_reference",
params: { collection: "users" },
required: true,
},
{
name: "role",
type: "enum",
params: {
values: ["admin", "moderator", "user"],
},
required: true,
},
],
});
Users.add_special_filters({
staff: new IsReferencedByResourcesMatching(app, {
referencing_field: UsersRoles.fields.user,
field_to_check: UsersRoles.fields.role,
allowed_values: ["admin", "moderator"],
nopass_reason:
"Resource you want to retrieve does not match given filter.!",
}),
});
const users = [
{
username: "admin",
password: "admin_password",
email: "any@example.com",
},
{
username: "moderator",
password: "moderator_password",
email: "any2@example.com",
},
{
username: "user",
password: "user_password",
email: "any3@example.com",
},
];
for (let user of users) {
const { id, username } = await rest_api.post(
"/api/v1/collections/users",
user
);
await rest_api.post("/api/v1/collections/users-roles", {
user: id,
role: username,
});
}
}
it("returns only users with role matching `allowed_values`", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
return rest_api
.get("/api/v1/collections/users/@staff")
.then(({ items }: CollectionResponse) => {
assert.ok(items.length > 0);
items.forEach((user) =>
assert.ok(
user.username === "admin" ||
user.username === "moderator"
)
);
});
}));
});
diff --git a/src/app/base-chips/special_filters/matches.subtest.ts b/src/app/base-chips/special_filters/matches.subtest.ts
index 4aceeafb..37ad24e7 100644
--- a/src/app/base-chips/special_filters/matches.subtest.ts
+++ b/src/app/base-chips/special_filters/matches.subtest.ts
@@ -1,72 +1,69 @@
import * as assert from "assert";
-import {
- with_running_app,
- MockRestApi,
-} from "../../../test_utils/with-test-app.js";
-import { App, Collection, Item } from "../../../main.js";
-import Matches from "./matches.js";
+import { withRunningApp, MockRestApi } from "../../../test_utils/with-test-app";
+import { App, Collection, Item } from "../../../main";
+import Matches from "./matches";
describe("Matches", () => {
async function setup(app: App, rest_api: MockRestApi) {
Collection.fromDefinition(app, {
name: "numbers",
fields: [
{
name: "number",
type: "int",
},
],
named_filters: {
positive: new Matches(app, { number: { ">": 0 } }),
negative: new Matches(app, { number: { "<": 0 } }),
},
});
const numbers = [-2, -1, 0, 1, 2];
for (let number of numbers) {
await rest_api.post("/api/v1/collections/numbers", { number });
}
}
it("returns only positive numbers when using filter", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
- const sealious_response = await app.run_action(
+ const sealious_response = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "numbers", "@positive"],
"show"
);
assert.deepEqual(
sealious_response.items.map(
(resource: Item) => resource.number
),
[1, 2]
);
}));
it("returns only positive numbers when using @positive filter", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const { items } = await rest_api.get(
"/api/v1/collections/numbers/@positive?sort[number]=asc"
);
assert.deepEqual(
items.map((resource: Item) => resource.number),
[1, 2]
);
}));
it("returns empty array when using both @positive and @negative filters", () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await setup(app, rest_api);
const { items } = await rest_api.get(
"/api/v1/collections/numbers/@positive/@negative"
);
assert.deepEqual(
items.map((resource: Item) => resource.number),
[]
);
}));
});
diff --git a/src/app/base-chips/special_filters/special-filters.ts b/src/app/base-chips/special_filters/special-filters.ts
index 5db82311..30bc3c71 100644
--- a/src/app/base-chips/special_filters/special-filters.ts
+++ b/src/app/base-chips/special_filters/special-filters.ts
@@ -1,2 +1,2 @@
export { default as IsReferencedByResourcesMatching } from "./IsReferencedByResourcesMatching";
-export { default as Matches } from "./matches.js";
+export { default as Matches } from "./matches";
diff --git a/src/app/collections/password-reset-intents.subtest.ts b/src/app/collections/password-reset-intents.subtest.ts
index 4de68b54..ab44a2c2 100644
--- a/src/app/collections/password-reset-intents.subtest.ts
+++ b/src/app/collections/password-reset-intents.subtest.ts
@@ -1,98 +1,98 @@
import axios from "axios";
import assert from "assert";
import {
- with_running_app,
- with_running_app_prod,
-} from "../../test_utils/with-test-app.js";
-import { App } from "../../main.js";
+ withRunningApp,
+ withRunningAppProd,
+} from "../../test_utils/with-test-app";
+import { App } from "../../main";
describe("password-reset-intents", () => {
- async function create_a_user(app: App) {
- await app.run_action(
+ async function createAUser(app: App) {
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username: "user",
email: "user@example.com",
password: "password",
}
);
}
it("tells you if the email address doesn't exist", async () =>
- with_running_app(async ({ base_url }) => {
+ withRunningApp(async ({ base_url }) => {
try {
await axios.post(
`${base_url}/api/v1/collections/password-reset-intents`,
{
email: "fake@example.com",
}
);
} catch (e) {
assert.equal(
e.response.data.data.email.message,
"No users with email set to fake@example.com"
);
return;
}
throw new Error("it didn't throw");
}));
it("allows anyone to create an intent, if the email exists", async () =>
- with_running_app(async ({ app, base_url }) => {
- await create_a_user(app);
+ withRunningApp(async ({ app, base_url }) => {
+ await createAUser(app);
const { email, token } = (
await axios.post(
`${base_url}/api/v1/collections/password-reset-intents`,
{
email: "user@example.com",
}
)
).data;
assert.deepEqual(
{ email, token },
{
email: "user@example.com",
token: "it's a secret to everybody",
}
);
}));
it("tells you if the email address is malformed", async () =>
- with_running_app(async ({ base_url }) => {
+ withRunningApp(async ({ base_url }) => {
try {
await axios.post(
`${base_url}/api/v1/collections/password-reset-intents`,
{
email: "incorrect-address",
}
);
} catch (e) {
assert.equal(
e.response.data.data.email.message,
"incorrect-address is a not valid e-mail address."
);
return;
}
throw new Error("it didn't throw");
}));
it("sends an email with the reset password link", async () =>
- with_running_app_prod(async ({ app, base_url, mail_api }) => {
- await create_a_user(app);
+ withRunningAppProd(async ({ app, base_url, mail_api }) => {
+ await createAUser(app);
await axios.post(
`${base_url}/api/v1/collections/password-reset-intents`,
{
email: "user@example.com",
}
);
- const messages = (await mail_api.get_messages()).filter(
+ const messages = (await mail_api.getMessages()).filter(
(message) => message.recipients[0] == "<user@example.com>"
);
assert.equal(messages.length, 1);
assert.equal(messages[0].recipients.length, 1);
assert.equal(messages[0].recipients[0], "<user@example.com>");
}));
});
diff --git a/src/app/collections/password-reset-intents.ts b/src/app/collections/password-reset-intents.ts
index 9e5a8b91..55791d5c 100644
--- a/src/app/collections/password-reset-intents.ts
+++ b/src/app/collections/password-reset-intents.ts
@@ -1,46 +1,46 @@
import { App, EventMatchers, Collection } from "../../main";
import PasswordResetTemplate from "../../email/templates/password-reset";
module.exports = (app: App) => {
app.addHook(
new EventMatchers.Collection({
when: "after",
collection_name: "password-reset-intents",
action: "create",
}),
async ({ metadata }, intent) => {
- const { token } = await app.run_action(
+ const { token } = await app.runAction(
new app.Sealious.SuperContext(metadata.context),
["collections", "password-reset-intents", intent.id],
"show"
);
const message = await PasswordResetTemplate(app, {
email_address: intent.email,
token,
});
await message.send(app);
}
);
return Collection.fromDefinition(app, {
name: "password-reset-intents",
fields: [
{
name: "email",
type: "value-existing-in-collection",
params: {
collection: app.ChipManager.getCollection("users"),
field: "email",
include_forbidden: true,
},
},
{ name: "token", type: "secret-token" },
],
access_strategy: {
default: "super",
create: "public",
edit: "noone",
},
});
};
diff --git a/src/app/collections/registration-intents.subtest.ts b/src/app/collections/registration-intents.subtest.ts
index 140b4426..4e587318 100644
--- a/src/app/collections/registration-intents.subtest.ts
+++ b/src/app/collections/registration-intents.subtest.ts
@@ -1,81 +1,78 @@
import axios from "axios";
import assert from "assert";
-import { assert_throws_async } from "../../test_utils";
-import {
- with_running_app,
- with_stopped_app,
-} from "../../test_utils/with-test-app.js";
+import { assertThrowsAsync } from "../../test_utils/assert-throws-async";
+import { withRunningApp, withStoppedApp } from "../../test_utils/with-test-app";
import { App } from "../../main";
describe("registration-intents", () => {
async function create_a_user(app: App) {
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username: "user",
email: "user@example.com",
password: "password",
}
);
}
it("doesn't allow setting a role for registration intention when the user in context can't create user-roles", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
app.ChipManager.getChip(
"collection",
"user-roles"
).set_access_strategy({
create: "noone",
});
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
axios
.post(
`${base_url}/api/v1/collections/registration-intents`,
{
email: "cunning@fox.com",
role: "admin",
}
)
.then(),
(e: any) => {
assert.equal(
e.response.data.message,
"You can't perform this action beacuse you can't create user-roles"
);
}
);
}));
it("allows setting a role for registration intention when the user in context can create user-roles", async () =>
- with_stopped_app(async ({ app, base_url }) => {
+ withStoppedApp(async ({ app, base_url }) => {
app.ConfigManager.set("roles", ["admin"]);
await app.start();
app.ChipManager.getChip(
"collection",
"user-roles"
).set_access_strategy({
create: "public",
});
const intent = (
await axios.post(
`${base_url}/api/v1/collections/registration-intents`,
{
email: "genuine@fox.com",
role: "admin",
}
)
).data;
assert.equal(intent.role, "admin");
- const { role } = await app.run_action(
+ const { role } = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "registration-intents", intent.id],
"show"
);
assert.equal(role, "admin");
}));
});
diff --git a/src/app/collections/registration-intents.ts b/src/app/collections/registration-intents.ts
index f5314fd1..6dabb8ab 100644
--- a/src/app/collections/registration-intents.ts
+++ b/src/app/collections/registration-intents.ts
@@ -1,69 +1,69 @@
import { App, Collection } from "../../main";
import RegistrationIntentTemplate from "../../email/templates/registration-intent";
module.exports = (app: App) => {
const user_roles = app.ChipManager.getChip("collection", "user-roles");
app.addHook(
new app.Sealious.EventMatchers.Collection({
when: "after",
collection_name: "registration-intents",
action: "create",
}),
async (emitted_event, intent) => {
const token = (
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(
emitted_event.metadata.context
),
["collections", "registration-intents", intent.id],
"show"
)
).token;
const message = await RegistrationIntentTemplate(app, {
email_address: intent.email,
token,
});
await message.send(app);
}
);
return Collection.fromDefinition(app, {
name: "registration-intents",
fields: [
{
name: "email",
required: true,
type: "value-not-existing-in-collection",
params: {
collection: app.ChipManager.getChip("collection", "users"),
field: "email",
include_forbidden: true,
},
},
{ name: "token", type: "secret-token" },
{
name: "role",
type: "settable-by",
params: {
access_strategy_description: [
"users-who-can",
["create", user_roles],
],
target_field_type: app.ChipManager.getChip(
"field_type",
"enum"
),
target_params: {
values: () => app.ConfigManager.get("roles"),
},
},
},
],
access_strategy: {
default: "super",
create: "public",
edit: "noone",
},
});
};
diff --git a/src/app/collections/user-roles.subtest.ts b/src/app/collections/user-roles.subtest.ts
index 3db5247f..b51c15a0 100644
--- a/src/app/collections/user-roles.subtest.ts
+++ b/src/app/collections/user-roles.subtest.ts
@@ -1,54 +1,54 @@
import axios from "axios";
import assert from "assert";
-import { with_running_app } from "../../test_utils/with-test-app.js";
-import { assert_throws_async } from "../../test_utils";
-import { App } from "../../main.js";
+import { withRunningApp } from "../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../test_utils/assert-throws-async";
+import { App } from "../../main";
describe("user-roles", () => {
function create_a_user(app: App, username: string) {
- return app.run_action(
+ return app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username,
email: `${username}@example.com`,
password: "password",
}
);
}
it("rejects when given an empty role", async () =>
- with_running_app(async ({ app, base_url }) => {
+ withRunningApp(async ({ app, base_url }) => {
const user = await create_a_user(app, "super_user");
- await assert_throws_async(
+ await assertThrowsAsync(
() =>
axios.post(`${base_url}/api/v1/collections/user-roles`, {
user: user.id,
}),
(e: any) => {
assert(
e.response.data.data.role.message ===
"Missing value for field 'role'"
);
}
);
}));
it("accepts correct dataset", async () =>
- with_running_app(async ({ app, base_url, rest_api }) => {
+ withRunningApp(async ({ app, base_url, rest_api }) => {
const user = await create_a_user(app, "special_user");
const session = await rest_api.login({
username: "special_user",
password: "password",
});
const response = await axios.post(
`${base_url}/api/v1/collections/user-roles`,
{
user: user.id,
role: "admin",
},
session
);
assert.equal(response.status, 201);
}));
});
diff --git a/src/app/collections/users.subtest.ts b/src/app/collections/users.subtest.ts
index e3a475db..1bccc238 100644
--- a/src/app/collections/users.subtest.ts
+++ b/src/app/collections/users.subtest.ts
@@ -1,153 +1,153 @@
import assert from "assert";
-import { with_running_app } from "../../test_utils/with-test-app.js";
-import assert_throws_async from "../../test_utils/assert_throws_async.js";
-import { Item, App } from "../../main.js";
+import { withRunningApp } from "../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../test_utils/assert-throws-async";
+import { Item, App } from "../../main";
describe("users", () => {
describe("auto create admin", () => {
it("should automatically create a registration intent for the admin user", async () =>
- with_running_app(async ({ app }) => {
- const sealious_response = await app.run_action(
+ withRunningApp(async ({ app }) => {
+ const sealious_response = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "registration-intents"],
"show",
{ filter: { email: app.manifest.admin_email } }
);
assert.equal(sealious_response.items.length, 1);
assert.equal(sealious_response.items[0].role, "admin");
}));
it("should properly handle route to account cration", async () =>
- with_running_app(async ({ app, rest_api }) => {
- const sealious_response = await app.run_action(
+ withRunningApp(async ({ app, rest_api }) => {
+ const sealious_response = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "registration-intents"],
"show",
{ filter: { email: app.manifest.admin_email } }
);
const { email, token } = sealious_response.items[0];
const response = await rest_api.get(
`/account-creation-details?token=${token}&email=${email}`
);
assert(response.includes("Uzupełnij dane o Twoim koncie"));
}));
});
describe("users routes", () => {
it("should correctly handle me when not logged in", async () =>
- with_running_app(async ({ rest_api }) => {
- await assert_throws_async(
+ withRunningApp(async ({ rest_api }) => {
+ await assertThrowsAsync(
async () =>
await rest_api.get(
"/api/v1/users/me?attachments[roles]=true"
),
(e) => {
assert.equal(e.response.status, 401);
assert.equal(
e.response.data.message,
"You're not logged in!"
);
}
);
}));
it("should correctly handle me when logged in", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await add_user(app);
const session = await rest_api.login({
username: "seal",
password: "seal",
});
const { roles } = ((await rest_api.getSealiousResponse(
"/api/v1/users/me?attachments[roles]=true",
session
)) as unknown) as Item;
assert.equal((roles as string[]).length, 1);
assert.equal(
(roles as { user: string; role: string }[])[0].role,
"admin"
);
}));
});
async function add_user(app: App) {
- const user = await app.run_action(
+ const user = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username: "seal",
password: "seal",
email: "seal@sealious.com",
}
);
- return app.run_action(
+ return app.runAction(
new app.Sealious.SuperContext(),
["collections", "user-roles"],
"create",
{ user: user.id, role: "admin" }
);
}
describe("login", () => {
it("correctly rejects when provided incorrect password", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await add_user(app);
const incorrect_password_variants = [
{ password: "", message: "Missing password!" },
{
password: "incorrect_password",
message: "Incorrect password!",
},
];
for (let variant of incorrect_password_variants) {
- await assert_throws_async(
+ await assertThrowsAsync(
async () =>
await rest_api.login({
username: "seal",
password: variant.password,
}),
(e) => {
assert.equal(e.response.status, 401);
assert.equal(
e.response.data.message,
variant.message
);
}
);
}
}));
it("correctly rejects when provided incorrect username", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await add_user(app);
const incorrect_username_variants = [
{ username: "", message: "Missing username!" },
{
username: "incorrect_username",
message: "Incorrect username!",
},
];
for (let variant of incorrect_username_variants) {
- await assert_throws_async(
+ await assertThrowsAsync(
async () =>
await rest_api.login({
username: variant.username,
password: "seal",
}),
(e) => {
assert.equal(e.response.status, 401);
assert.equal(
e.response.data.message,
variant.message
);
}
);
}
}));
});
});
diff --git a/src/app/collections/users.ts b/src/app/collections/users.ts
index e0fba5e3..f18c424a 100644
--- a/src/app/collections/users.ts
+++ b/src/app/collections/users.ts
@@ -1,67 +1,67 @@
import { Collection, App } from "../../main";
module.exports = (app: App) => {
app.on("started", async () => {
- const sealious_response = await app.run_action(
+ const sealious_response = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"show",
{ filter: { email: app.manifest.admin_email } }
);
if (sealious_response.empty) {
app.Logger.warning(
`Creating an admin account for ${app.manifest.admin_email}`
);
- return app.run_action(
+ return app.runAction(
new app.Sealious.SuperContext(),
["collections", "registration-intents"],
"create",
{ email: app.manifest.admin_email, role: "admin" }
);
}
});
return Collection.fromDefinition(app, {
name: "users",
fields: [
{
name: "username",
type: "username",
required: true,
},
{
name: "email",
type: "email",
required: true,
},
{
name: "password",
type: "password",
params: {
min_length: 6,
},
required: true,
},
{
name: "status",
type: "text",
},
{
name: "last_login_context",
type: "context",
},
{
name: "roles",
type: "reverse-single-reference",
params: {
collection: "user-roles",
field_name: "user",
},
},
],
access_strategy: {
default: "public",
show: "themselves",
},
});
};
diff --git a/src/app/hookable.subtest.ts b/src/app/hookable.subtest.ts
index 2312b6c5..49f32968 100644
--- a/src/app/hookable.subtest.ts
+++ b/src/app/hookable.subtest.ts
@@ -1,332 +1,332 @@
import assert from "assert";
-import { assert_throws_async } from "../test_utils";
+import { assertThrowsAsync } from "../test_utils/assert-throws-async";
import { EventMatcher, Collection, Resource } from "./event-matchers";
import { EventDescription, Hookable } from "./hookable";
import Context from "../context";
type Handler = (event: EventDescription, data: any) => any;
const metadata = {
context: new Context(),
params: {},
};
describe("hookable", () => {
function createHook(App: Hookable, handler: Handler) {
App.addHook(
new EventMatcher({
when: "before",
subject_path: /collections.movies/,
action: "create",
}),
handler
);
}
function createAnotherHook(App: Hookable, handler: Handler) {
App.addHook(
new EventMatcher({
when: "after",
subject_path: /collections.movies/,
action: "create",
}),
handler
);
}
function getResult(App: Hookable, data: any) {
return App.emitHook(
{
when: "before",
subject_path: "collections.movies",
action: "create",
metadata,
},
data
);
}
async function assertErrorThrownOnAppAddHook(
event_matcher: EventMatcher,
callback: any
) {
- await assert_throws_async(
+ await assertThrowsAsync(
async () => {
const App = new Hookable();
App.addHook(event_matcher, callback);
},
(error) => assert.deepEqual(error.code, "ERR_ASSERTION")
);
}
async function assertErrorThrownOnAppEmit(
event_description: EventDescription
) {
- await assert_throws_async(
+ await assertThrowsAsync(
async () => {
const App = new Hookable();
await App.emitHook(event_description, 0);
},
(error) => assert.deepEqual(error.code, "ERR_ASSERTION")
);
}
it("properly passess value from handler to handler (happy path)", async () => {
const App = new Hookable();
createHook(App, async (_, number) => number + 2);
createHook(App, async (_, number) => number * 2);
const result = await getResult(App, 1);
assert.equal(result, 6);
});
it("returns proper value if one of the handlers in the middle doesn't return anything", async () => {
const App = new Hookable();
createHook(App, (_, number) => number + 2);
createHook(App, async () => {
return undefined;
});
createHook(App, async (_, number) => number * 10);
const result = await getResult(App, 1);
assert.equal(result, 30);
});
it("returns back given data if handler doesn't return anything", async () => {
const App = new Hookable();
createHook(App, async () => {});
const result = await getResult(App, 1);
assert.equal(result, 1);
});
it("doesn't trigger hooks that refer to another event", async () => {
const App = new Hookable();
createHook(App, async (_, number) => number * 2);
createAnotherHook(App, async (_, number) => number * 100);
const result = await getResult(App, 1);
assert.equal(result, 2);
});
it("properly reacts to async handlers", async () => {
const App = new Hookable();
const sleep = (ms: number) =>
new Promise((resolve) => {
setTimeout(() => {
resolve();
}, ms);
});
createHook(App, async (_, number) => {
await sleep(10);
return number * 128;
});
const result = await getResult(App, 2);
assert.equal(result, 256);
});
it("should fire the handler if emitted action is included in action array", async () => {
const App = new Hookable();
App.addHook(
new EventMatcher({
when: "before",
subject_path: /collections.movies/,
action: ["create", "edit"],
}),
(_, number) => number + 50
);
const result = await App.emitHook(
{
when: "before",
subject_path: "collections.movies",
action: "create",
metadata,
},
50
);
assert.equal(result, 100);
});
it("should work properly when given an instance of EventMatcher ", async () => {
const App = new Hookable();
App.addHook(
new EventMatcher({
when: "before",
subject_path: /collections.movies/,
action: ["create", "edit"],
}),
(_, number) => number + 50
);
const result = await App.emitHook(
{
when: "before",
subject_path: "collections.movies",
action: "create",
metadata,
},
50
);
assert.equal(result, 100);
});
it("should work properly when given an instance of CollectionEventMatcher", async () => {
const App = new Hookable();
const _collection_event_matcher = new Collection({
when: "before",
collection_name: "shows",
action: ["create"],
});
assert.deepEqual(_collection_event_matcher.collection_name, "shows");
App.addHook(_collection_event_matcher, (_, number) => number + 51);
const result = await App.emitHook(
{
when: "before",
subject_path: "collections.shows",
action: "create",
metadata,
},
50
);
assert.equal(result, 101);
});
it("should work properly when given an instance of ResourceEventMatcher", async () => {
const App = new Hookable();
const _resource_event_matcher = new Resource({
when: "before",
collection_name: "series",
action: ["create"],
});
assert.deepEqual(_resource_event_matcher.collection_name, "series");
App.addHook(_resource_event_matcher, (_, number) => number + 52);
const result = await App.emitHook(
{
when: "before",
subject_path: "collections.series.id",
action: "create",
metadata,
},
50
);
assert.equal(result, 102);
});
it("should take care of `App.addHook` params validation", async () => {
// `callback` is not a function
await assertErrorThrownOnAppAddHook(
new EventMatcher({
when: "before",
subject_path: /collections.movies/,
action: ["create", "edit"],
}),
2
);
// `when` is not a string
await assertErrorThrownOnAppAddHook(
{
//@ts-ignore
when: 222,
subject_path: /collections.movies/,
action: ["create", "edit"],
},
() => {}
);
// `action` is not a string/array
await assertErrorThrownOnAppAddHook(
{
when: "before",
subject_path: /collections.movies/,
//@ts-ignore
action: {},
},
() => {}
);
// `subject_path` is not a regexp
await assertErrorThrownOnAppAddHook(
{
when: "before",
//@ts-ignore
subject_path: [""],
action: "create",
},
() => {}
);
});
it("should take care of `App.emit` params validation", async () => {
// `when` is not a string
await assertErrorThrownOnAppEmit({
//@ts-ignore
when: [],
subject_path: "collections.events",
action: "create",
});
// `subject_path` is not a string
await assertErrorThrownOnAppEmit({
when: "before",
//@ts-ignore
subject_path: 222,
action: "create",
});
// `action` is not a string
await assertErrorThrownOnAppEmit({
when: "before",
subject_path: "collections.events",
//@ts-ignore
action: {},
});
// `metadata` is not an object
await assertErrorThrownOnAppEmit({
when: "before",
subject_path: "collections.events",
action: "create",
//@ts-ignore
metadata: 2,
});
});
it("should take care of `*EventMatcher` collection_name validation", async () => {
// collection_name must be a string
- await assert_throws_async(
+ await assertThrowsAsync(
async () => {
new Collection({
when: "before",
//@ts-ignore
collection_name: 222,
action: "create",
});
},
(error: { code: any }) =>
assert.deepEqual(error.code, "ERR_ASSERTION")
);
// collection_name must be a string
- await assert_throws_async(
+ await assertThrowsAsync(
async () => {
new Resource({
when: "before",
//@ts-ignore
collection_name: [],
action: "create",
});
},
(error: { code: any }) =>
assert.deepEqual(error.code, "ERR_ASSERTION")
);
});
it("allows to check if EventMatcher responds to given action", async () => {
const matcher = new EventMatcher({
when: "before",
subject_path: /.*/,
action: ["create", "edit"],
});
assert(matcher.containsAction("create"));
assert(!matcher.containsAction("show"));
const anotherMatcher = new EventMatcher({
when: "before",
subject_path: /.*/,
action: "create",
});
assert(anotherMatcher.containsAction("create"));
assert(!anotherMatcher.containsAction("show"));
});
});
diff --git a/src/app/run-action-curry.ts b/src/app/run-action-curry.ts
index bdaa3541..f25a259a 100644
--- a/src/app/run-action-curry.ts
+++ b/src/app/run-action-curry.ts
@@ -1,58 +1,58 @@
import { Context, ActionName, App } from "../main";
import { NotFound } from "../response/errors";
const ActionResultCache = new WeakMap();
-export default function run_action_curry(app: App) {
- return async function run_action(
+export function runActionCurry(app: App) {
+ return async function runAction(
context: Context,
subject_path: string[],
action_name: ActionName,
params: any
) {
if (!action_name) {
throw new Error("Action name not provided");
}
const original_context = context.original_context || context;
if (!ActionResultCache.has(original_context)) {
ActionResultCache.set(original_context, new Map());
}
app.Logger.debug(subject_path.toString(), action_name, params);
const subject = await app.RootSubject.getSubject(subject_path);
if (!subject) {
throw new NotFound("Subject not found: " + subject_path.toString());
}
params = await app.emitHook(
{
when: "before",
subject_path: subject_path.join("."),
action: action_name,
metadata: {
context,
params,
},
},
params
);
const response = await subject.performAction(
context,
action_name,
params
);
return app.emitHook(
{
when: "after",
subject_path: subject_path.join("."),
action: action_name,
metadata: {
context,
params,
},
},
response
);
};
}
diff --git a/src/app/sort.subtest.ts b/src/app/sort.subtest.ts
index 609a8484..69de58c7 100644
--- a/src/app/sort.subtest.ts
+++ b/src/app/sort.subtest.ts
@@ -1,124 +1,121 @@
import assert from "assert";
-import {
- with_running_app,
- MockRestApi,
-} from "../test_utils/with-test-app.js";
-import { assert_throws_async } from "../test_utils";
-import { App, Item, Collection } from "../main.js";
-import { CollectionResponse } from "../../common_lib/response/responses.js";
+import { withRunningApp, MockRestApi } from "../test_utils/with-test-app";
+import { assertThrowsAsync } from "../test_utils/assert-throws-async";
+import { App, Item, Collection } from "../main";
+import { CollectionResponse } from "../../common_lib/response/responses";
describe("sorting", () => {
const items: { [name: string]: Item } = {};
async function create_resources(app: App, rest_api: MockRestApi) {
Collection.fromDefinition(app, {
name: "water_areas",
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "temperature",
type: "int",
required: true,
},
],
});
Collection.fromDefinition(app, {
name: "seals",
fields: [
{
name: "name",
type: "text",
required: true,
},
{
name: "favorite_number",
type: "int",
required: true,
},
{
name: "water_area",
type: "single_reference",
params: { collection: "water_areas" },
},
],
});
items.baltic_sea = await rest_api.post(
"/api/v1/collections/water_areas",
{
name: "Baltic Sea",
temperature: 10,
}
);
items.arabic_sea = await rest_api.post(
"/api/v1/collections/water_areas",
{
name: "Arabic Sea",
temperature: 20,
}
);
const seals = [
{
name: "Hoover",
favorite_number: 3,
water_area: items.arabic_sea.id,
},
{
name: "Maksiu",
favorite_number: 3,
water_area: items.baltic_sea.id,
},
{
name: "Nelly",
favorite_number: 8,
water_area: items.baltic_sea.id,
},
];
for (let seal of seals) {
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "seals"],
"create",
seal
);
}
}
it("properly sorts for correct sort key", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await create_resources(app, rest_api);
const { items } = (await rest_api.get(
"/api/v1/collections/seals?sort[favorite_number]=desc"
)) as CollectionResponse;
assert.deepEqual(
items.map((item) => item.favorite_number),
[8, 3, 3]
);
}));
it("throws application error for incorrect sort key", async () =>
- with_running_app(async ({ app, rest_api }) => {
+ withRunningApp(async ({ app, rest_api }) => {
await create_resources(app, rest_api);
- await assert_throws_async(
+ await assertThrowsAsync(
async () =>
await rest_api.get(
"/api/v1/collections/seals?sort[favorite_number]=dsc"
),
(e) => {
assert.equal(e.response.status, 405);
assert.equal(
e.response.data.message,
"Unknown sort key: dsc. Available sort keys are: desc, descending, asc, ascending."
);
}
);
}));
});
diff --git a/src/chip-types/access-strategy.ts b/src/chip-types/access-strategy.ts
index 84830475..dc0023f3 100644
--- a/src/chip-types/access-strategy.ts
+++ b/src/chip-types/access-strategy.ts
@@ -1,111 +1,111 @@
-import App from "../app/app.js";
-import SealiousResponse from "../../common_lib/response/sealious-response.js";
-import Context from "../context.js";
-import Query from "../datastore/query.js";
-import { ChipTypeName } from "../app/chip-manager.js";
-import Chip from "./chip.js";
+import App from "../app/app";
+import SealiousResponse from "../../common_lib/response/sealious-response";
+import Context from "../context";
+import Query from "../datastore/query";
+import { ChipTypeName } from "../app/chip-manager";
+import Chip from "./chip";
export type AccessStrategyDefinition =
| [string | AccessStrategyClass, any]
| string
| {
type: "string" | AccessStrategyClass;
params: any;
}
| AccessStrategy;
export type AccessStrategyDecision = {
allowed: boolean;
reason: string;
} | null;
export type AccessStrategyClass = new (app: App, params: any) => AccessStrategy;
export default abstract class AccessStrategy extends Chip {
app: App;
type_name: ChipTypeName = "access_strategy_type";
params: any;
constructor(app: App, params: any) {
super();
this.app = app;
this.params = params;
}
abstract checkerFunction(
context: Context,
sealious_response?: SealiousResponse
): Promise<AccessStrategyDecision | null>;
async isItemSensitive() {
return false;
}
abstract getRestrictingQuery(context: Context): Promise<Query>;
async check(
context: Context,
sealious_response?: SealiousResponse
): Promise<AccessStrategyDecision | null> {
if (context.is_super) {
return AccessStrategy.allow("super-context is always allowed");
}
const is_item_sensitive = await this.isItemSensitive();
if (is_item_sensitive && sealious_response === undefined) {
return null;
}
return this.checkerFunction(context, sealious_response);
}
public static fromDefinition(
app: App,
definition: AccessStrategyDefinition
) {
if (definition instanceof AccessStrategy) {
return definition;
}
let [strategy, params] =
typeof definition === "string"
? [definition, null]
: Array.isArray(definition)
? [definition[0], definition[1] || null]
: [definition.type, definition.params || null];
let constructor: AccessStrategyClass;
if (typeof strategy === "string") {
constructor = app.ChipManager.getAccessStrategy(strategy);
} else {
constructor = strategy;
}
return new constructor(app, params);
}
static allow(reason: string) {
return { allowed: true, reason };
}
static deny(reason: string) {
return { allowed: false, reason };
}
}
export abstract class ReducingAccessStrategy extends AccessStrategy {
access_strategies: AccessStrategy[];
constructor(app: App, params: AccessStrategyDefinition[]) {
super(app, params);
this.access_strategies = params.map((definition) =>
AccessStrategy.fromDefinition(app, definition)
);
}
checkAllStrategies(
context: Context,
response?: SealiousResponse
): Promise<AccessStrategyDecision[]> {
return Promise.all(
this.access_strategies.map((strategy) =>
strategy.check(context, response)
)
);
}
}
diff --git a/src/chip-types/collection.ts b/src/chip-types/collection.ts
index a6646363..f84ae2e3 100644
--- a/src/chip-types/collection.ts
+++ b/src/chip-types/collection.ts
@@ -1,531 +1,531 @@
import Bluebird from "bluebird";
-import * as Errors from "../response/errors.js";
-import Chip from "./chip.js";
-import Field from "./field.js";
-import CalculatedField from "./calculated-field.js";
-import AccessStrategy, { AccessStrategyDefinition } from "./access-strategy.js";
+import * as Errors from "../response/errors";
+import Chip from "./chip";
+import Field from "./field";
+import CalculatedField from "./calculated-field";
+import AccessStrategy, { AccessStrategyDefinition } from "./access-strategy";
-import SingleItemResponse from "../../common_lib/response/single-item-response.js";
-import App from "../app/app.js";
-import { ActionName } from "../action.js";
-import Context from "../context.js";
+import SingleItemResponse from "../../common_lib/response/single-item-response";
+import App from "../app/app";
+import { ActionName } from "../action";
+import Context from "../context";
type values<T = any> = { [field_name: string]: T };
import { FieldDefinition } from "./field";
-import Item from "../../common_lib/response/item.js";
-import Query from "../datastore/query.js";
-import { ChipTypeName } from "../app/chip-manager.js";
-import SpecialFilter from "./special-filter.js";
-import Public from "../app/base-chips/access-strategy-types/public.js";
+import Item from "../../common_lib/response/item";
+import Query from "../datastore/query";
+import { ChipTypeName } from "../app/chip-manager";
+import SpecialFilter from "./special-filter";
+import Public from "../app/base-chips/access-strategy-types/public";
export type CollectionDefinition = {
name: string;
fields: FieldDefinition<any>[];
access_strategy?: Partial<
{
[action in ActionName | "default"]: AccessStrategyDefinition;
}
>;
display_hints?: {};
human_readable_name?: string;
summary?: string;
named_filters?: { [name: string]: SpecialFilter };
calculated_fields?: {
[field_name: string]: CalculatedField<any>;
};
};
export default class Collection extends Chip {
type_name: ChipTypeName = "collection";
name: string;
app: App;
fields: {
[field_name: string]: Field;
};
human_readable_name: string | null;
summary: string | null;
display_hints: any;
access_strategy: { [action in ActionName | "default"]?: AccessStrategy };
named_filters: { [name: string]: SpecialFilter };
calculated_fields: {
[field_name: string]: CalculatedField<any>;
} = {};
constructor(app: App, definition: CollectionDefinition) {
super();
this.app = app;
this.name = definition.name;
this.fields = {};
this.human_readable_name = definition.human_readable_name || null;
this.summary = definition.summary || null;
this.display_hints = definition.display_hints || {};
this.access_strategy = {
default: AccessStrategy.fromDefinition(app, "public"),
};
this.named_filters = definition.named_filters || {};
for (let i = 0; i < definition.fields.length; i++) {
if (definition.fields[i].params) {
if (typeof definition.fields[i].params !== "object") {
throw new Errors.ValidationError(
`In field "${definition.fields[i].name}": "params" is of wrong type, it should be an object`
);
}
}
}
this.addFields(definition.fields);
if (definition.calculated_fields) {
for (const calc_field_name in definition.calculated_fields) {
this.addCalculatedField(
calc_field_name,
definition.calculated_fields[calc_field_name]
);
}
}
this.setAccessStrategy(
definition.access_strategy || { default: new Public(app, {}) }
);
}
static fromDefinition(
app: App,
definition: CollectionDefinition
): Collection {
const ret = new Collection(app, definition);
app.registerCollection(ret);
return ret;
}
addField(field_definition: FieldDefinition<any>) {
const field = Field.fromDefinition(this.app, this, field_definition);
const field_name = field.name;
if (!this.fields[field_name]) {
this.fields[field_name] = field;
} else {
throw new Errors.DeveloperError(
`Duplicate field names: "${field_name}" in collection: "${this.name}"`
);
}
}
addFields(field_definitions: FieldDefinition<any>[]) {
for (const definition of field_definitions) {
this.addField(definition);
}
}
addCalculatedField(
calc_field_name: string,
calc_field: CalculatedField<any>
) {
this.calculated_fields[calc_field_name] = calc_field;
}
addSpecialFilters(named_filters: { [name: string]: SpecialFilter }) {
this.named_filters = named_filters;
}
getUnknownFieldErrors(values: values) {
const validation_errors: values = {};
for (const field_name in values) {
if (this.fields[field_name] === undefined) {
validation_errors[field_name] = new Errors.ValidationError(
`Unknown field '${field_name}'`
);
}
}
return validation_errors;
}
getMissingValuesChecker(
values: values,
assume_delete_value_on_missing_key: boolean,
old_values: values
) {
if (assume_delete_value_on_missing_key) {
return (field_name: string) =>
this.fields[field_name].required &&
values[field_name] === undefined;
} else {
return (field_name: string) =>
this.fields[field_name].required &&
values[field_name] === undefined &&
old_values[field_name] === undefined;
}
}
async getMissingFieldValuesErrors(
values: values,
assume_delete_value_on_missing_key: boolean,
old_values: values
) {
const errors: values = {};
const checker_fn = this.getMissingValuesChecker(
values,
assume_delete_value_on_missing_key,
old_values
);
await Bluebird.filter(Object.keys(this.fields), checker_fn).each(
function (field_name) {
errors[field_name] = new Errors.ValidationError(
`Missing value for field '${field_name}'`
);
}
);
return errors;
}
async getInvalidFieldValuesErrors(
context: Context,
values: values,
old_values?: values
) {
const errors: { [field_name: string]: Error } = {};
const promises = [];
for (const field_name in values) {
if (this.fields[field_name]) {
const value = values[field_name];
if (value === "") continue;
const old_value = old_values
? old_values[field_name]
: undefined;
const promise = this.fields[field_name]
.isProperValue(context, value, old_value)
.catch(function (error) {
if (
typeof error === "string" ||
error.type === "validation"
) {
errors[field_name] = new Errors.ValidationError(
error
);
} else {
throw error;
}
});
promises.push(promise);
}
}
await Promise.all(promises);
return errors;
}
getMissingRequiredFieldValues(new_values: values) {
const errors: { [field_name: string]: Error } = {};
for (const field_name in new_values) {
if (
this.fields[field_name] &&
this.fields[field_name].required &&
new_values[field_name] === ""
) {
errors[field_name] = new Errors.ValidationError(
`Missing value for required field: '${field_name}'`
);
}
}
return errors;
}
async validateFieldValues(
context: Context,
assume_delete_value_on_missing_key: boolean,
new_values: values,
old_values?: values
) {
const errors_array = [
this.getMissingRequiredFieldValues(new_values),
this.getUnknownFieldErrors(new_values),
old_values
? this.getMissingFieldValuesErrors(
new_values,
assume_delete_value_on_missing_key,
old_values
)
: {},
this.getInvalidFieldValuesErrors(context, new_values, old_values),
];
const errors = (await Promise.all(errors_array)).reduce((a, b) => {
return { ...a, ...b };
}, {});
const user_errors: values = {};
const non_user_errors: values = {};
for (const field_name in errors) {
const error = errors[field_name];
if (error.is_user_fault) {
user_errors[field_name] = error;
} else {
non_user_errors[field_name] = error;
}
}
const non_user_errors_amount = Object.keys(non_user_errors).length;
if (non_user_errors_amount > 0) {
throw non_user_errors[Object.keys(non_user_errors)[0]];
}
const user_errors_amount = Object.keys(user_errors).length;
if (user_errors_amount > 0) {
throw new Errors.ValidationError(
"There are problems with some of the provided values.",
user_errors
);
}
}
async encodeFieldValues(context: Context, body: values, old_body?: values) {
const promises: values = {};
for (let field_name in this.fields) {
const field = this.fields[field_name];
if (
!body[field_name] &&
field.hasDefaultValue() &&
(!old_body || old_body[field_name] === undefined)
) {
body[field_name] = await field.getDefaultValue();
}
}
for (const field_name in body) {
const current_value = body[field_name];
if (current_value === undefined || current_value === "") {
promises[field_name] = "";
} else {
const old_value = old_body && old_body[field_name];
promises[field_name] = this.fields[field_name].encode(
context,
current_value,
old_value
);
}
}
return Bluebird.props(promises);
}
getSpecification(summary: any) {
// with_validators:boolean - whether to include validator functions in field descriptions. Warning! If set to true, the output is not serializable in JSON.
const fields_spec: {
[field: string]: {
name: string;
type: string;
display_hints: any;
required?: boolean;
};
} = {};
for (const field_name in this.fields) {
const field_specification = this.fields[
field_name
].getSpecification();
fields_spec[field_name] = {
...field_specification,
name: field_name,
};
fields_spec[field_name].required = this.fields[field_name].required;
}
const specification = {
name: this.name,
human_readable_name: this.human_readable_name,
summary: summary,
fields: fields_spec,
display_hints: this.display_hints,
};
return specification;
}
setAccessStrategy(
strategy_definition: Partial<
{
[action in ActionName | "default"]: AccessStrategyDefinition;
}
>
) {
if (
typeof strategy_definition === "string" ||
strategy_definition instanceof AccessStrategy ||
strategy_definition instanceof Array
) {
this.access_strategy = {
default: AccessStrategy.fromDefinition(
this.app,
strategy_definition as AccessStrategyDefinition
),
};
} else if (typeof strategy_definition === "object") {
for (const action_name in strategy_definition) {
const access_strategy = (strategy_definition as {
[action in ActionName]: AccessStrategyDefinition;
})[action_name as ActionName];
this.access_strategy[
action_name as ActionName
] = AccessStrategy.fromDefinition(this.app, access_strategy);
}
}
}
getAccessStrategy(action_name: ActionName): AccessStrategy {
const ret =
this.access_strategy[action_name] ||
this.access_strategy["default"];
return ret as AccessStrategy;
}
hasLargeDataFields() {
for (const i in this.fields) {
const field = this.fields[i];
if (field.handles_large_data) {
return true;
}
}
return false;
}
isOldValueSensitive(action_name: ActionName) {
for (const field_name in this.fields) {
if (this.fields[field_name].isOldValueSensitive(action_name)) {
return true;
}
}
return false;
}
decodeValues(context: Context, values: values, format: any) {
const decoded_values: values = {};
for (const field_name in this.fields) {
const value = values[field_name];
const field = this.fields[field_name];
if (field === undefined) {
continue;
}
const field_format = format[field_name] || null;
// todo: probably need to fetch the old value here
decoded_values[field_name] = field.decode(
context,
value,
null,
field_format
);
}
return Bluebird.props(decoded_values);
}
async _getBody(context: Context, db_document: {}, format: any) {
return this.decodeValues(context, db_document, format || {});
}
_getCalculatedFields(
context: Context,
item: Item,
raw_db_entry: values,
calculate: boolean | values<boolean>
) {
const ret: values<any> = {};
for (const field_name in this.calculated_fields) {
if (
calculate === true ||
(calculate as values<boolean>)[field_name]
) {
ret[field_name] = this.calculated_fields[field_name].calculate(
context,
item,
raw_db_entry
);
}
}
return Bluebird.props(ret);
}
async getResourceRepresentation(
context: Context,
db_document: any,
format: any,
calculate?: boolean | values<boolean>
): Promise<Item> {
if (calculate === undefined) calculate = true;
const representation = await this._getBody(
context,
db_document,
format
);
representation.id = db_document.sealious_id;
representation._metadata = db_document._metadata;
representation._metadata.collection_name = this.name;
if (calculate) {
representation.calculated_fields = await this._getCalculatedFields(
context,
representation as Item,
db_document,
calculate
);
}
return representation as Item;
}
checkIfActionIsAllowed(
context: Context,
action_name: ActionName,
item?: Item
) {
const access_strategy = this.getAccessStrategy(action_name);
const sealious_response = item
? new SingleItemResponse({
item,
attachments: {},
fieldsWithAttachments: {},
})
: undefined;
return access_strategy.check(context, sealious_response);
}
async getAggregationStages(
context: Context,
action_name: ActionName,
query_params: { search?: {}; filter?: {} },
ids: string[] = []
) {
const fields = this.fields;
const access_strategy = this.getAccessStrategy(action_name);
return Bluebird.all([
query_params.search
? [
{
$match: {
$text: {
$search: query_params.search.toString(),
$caseSensitive: false,
$diacriticSensitive: false,
},
},
},
]
: [],
access_strategy
.getRestrictingQuery(context)
.then((query) => query.toPipeline()),
Promise.all(
Object.keys(fields).map((field_name) =>
fields[field_name].getAggregationStages(
context,
query_params
)
)
).then((array) =>
array.sort((a, _) => {
return Object.keys(a[0] || {})[0] === "$match" ? -1 : 1;
})
),
Promise.resolve(
ids.length === 0
? []
: Query.fromSingleMatch({
sealious_id: { $in: ids },
}).toPipeline()
),
])
.map(Promise.all)
.reduce((a, b) => a.concat(b), [] as any[])
.reduce((a, b) => a.concat(b), [] as any[]);
}
getNamedFilter(filter_name: string) {
return this.named_filters[filter_name];
}
}
diff --git a/src/chip-types/field.ts b/src/chip-types/field.ts
index e63fd786..0ffaed72 100644
--- a/src/chip-types/field.ts
+++ b/src/chip-types/field.ts
@@ -1,212 +1,212 @@
-import Collection from "./collection.js";
-import Context from "../context.js";
-import { ActionName } from "../action.js";
-import { ChipTypeName } from "../app/chip-manager.js";
-import { App } from "../main.js";
-import QueryStage from "../datastore/query-stage.js";
-import AttachmentLoader from "../subject/attachments/attachment-loader.js";
-import ReferenceToCollection from "../subject/attachments/reference-to-collection.js";
+import Collection from "./collection";
+import Context from "../context";
+import { ActionName } from "../action";
+import { ChipTypeName } from "../app/chip-manager";
+import { App } from "../main";
+import QueryStage from "../datastore/query-stage";
+import AttachmentLoader from "../subject/attachments/attachment-loader";
+import ReferenceToCollection from "../subject/attachments/reference-to-collection";
export type Depromisify<T> = T extends Promise<infer V> ? V : T;
export type ExtractParams<F extends Field> = Parameters<F["setParams"]>[0];
export type ExtractInput<F extends Field> = Parameters<F["encode"]>[1];
export type ExtractOutput<F extends Field> = Depromisify<
ReturnType<F["decode"]>
>;
export type ExtractStorage<F extends Field<any>> = Depromisify<
ReturnType<F["encode"]>
>;
export type ExtractFormatParams<F> = F extends Field<any, infer T> ? T : never;
export type FieldDefinition<ParamsType> = {
name: string;
required?: boolean;
type: string | FieldClass;
params?: ParamsType;
display_hints?: any;
};
export type FieldClass<ParamsType = any> = new (
app: App,
collection: Collection,
name: string,
required: boolean,
display_hints: any
) => Field<ParamsType>;
type ValidationResult = {
valid: boolean;
reason?: string;
};
export default abstract class Field<
InputType = any,
OutputType = InputType,
FormatParams = any
> {
name: string;
app: App;
display_hints: any;
handles_large_data: boolean = false;
type_name: ChipTypeName = "field_type";
collection: Collection;
required: boolean;
constructor(
app: App,
collection: Collection,
name: string,
required: boolean,
display_hints: any
) {
this.app = app;
this.name = name;
this.display_hints = display_hints || {};
this.collection = collection;
this.required = required;
}
static fromDefinition<ParamsType>(
app: App,
collection: Collection,
definition: FieldDefinition<ParamsType>
) {
let type: FieldClass;
if (typeof definition.type === "string") {
type = app.ChipManager.getFieldType(definition.type);
} else {
type = definition.type;
}
return new type(
app,
collection,
definition.name,
definition.required || false,
definition.display_hints
);
}
setParams(_: any): void | Promise<void> {}
getSpecification() {
return {
name: this.name,
type: this.getTypeName(),
display_hints: this.display_hints,
};
}
hasIndex(): boolean | { [field_name: string]: "text" } {
return false;
}
async getAggregationStages(
context: Context,
query_params: { filter?: { [field_name: string]: any } }
): Promise<QueryStage[]> {
if (!query_params || !query_params.filter) return [];
let field_filter = query_params.filter[this.name];
if (
field_filter &&
field_filter.length === 1 &&
field_filter[0] instanceof Array
) {
field_filter = field_filter[0]; // to fix an edge case where instead of array of values the array is wrapped within another array
}
if (!(this.name in query_params.filter)) {
return [];
}
if (this.name in query_params.filter && field_filter === undefined)
return [
{
$match: { [await this.getValuePath()]: { $exists: false } },
} as QueryStage,
];
let new_filter = null;
if (field_filter instanceof Array) {
new_filter = await Promise.all(
field_filter.map((element) => this.encode(context, element))
).then((filters) => {
return { $in: filters };
});
} else {
new_filter = await this.filterToQuery(context, field_filter);
}
return [
{ $match: { [await this.getValuePath()]: new_filter } },
] as QueryStage[];
}
async getValuePath(): Promise<string> {
return this.name;
}
abstract getTypeName(): string;
abstract isProperValue(
context: Context,
new_value: InputType,
old_value: InputType
): Promise<ValidationResult>;
format: never;
filter_to_query: never;
async encode(_: Context, value: InputType, __?: InputType): Promise<any> {
return value as any;
}
async decode(
_: Context,
storage_value: Depromisify<ReturnType<this["encode"]>>,
__: OutputType,
___: FormatParams
): Promise<OutputType> {
return (storage_value as unknown) as OutputType;
}
async filterToQuery(context: Context, filter: any): Promise<any> {
return this.encode(context, filter);
}
async fullTextSearchEnabled(): Promise<boolean> {
return false;
}
hasDefaultValue = () => true;
getDefaultValue(): Depromisify<ReturnType<this["decode"]>> | null {
return null;
}
isOldValueSensitive(_: ActionName) {
return false;
}
static valid(): ValidationResult {
return { valid: true };
}
static invalid(reason: string): ValidationResult {
return { valid: false, reason };
}
init(_: App): Promise<void> | void {}
getAttachmentLoader(
context: Context,
omit_it: Boolean,
attachment_params: ConstructorParameters<
typeof ReferenceToCollection
>[2]
): AttachmentLoader | null {
return null;
}
}
export { default as HybridField } from "./field-hybrid";
export * from "./field-hybrid";
diff --git a/src/context.ts b/src/context.ts
index 364368ff..2f271ea5 100644
--- a/src/context.ts
+++ b/src/context.ts
@@ -1,68 +1,68 @@
import App from "./app/app";
-import SuperContext from "./super-context.js";
+import SuperContext from "./super-context";
import Item from "../common_lib/response/item";
export default class Context {
timestamp: number;
ip: string | null;
user_id: string | null;
anonymous_user_id: string | null;
user_data: null | Promise<Item> = null;
loading_user_data: boolean;
session_id: string | null;
anonymous_session_id: string | null;
anon_session_is_new: boolean | null;
is_super = false;
original_context: Context | null;
constructor(
timestamp: number = Date.now(),
ip?: string | null,
user_id?: string | null,
session_id?: string | null,
anonymous_session_id?: string | null,
anon_session_is_new?: boolean | null,
anonymous_user_id?: string | null
) {
this.original_context = this;
this.loading_user_data = false;
Object.defineProperty(this, "session_id", {
value: session_id,
}); // to make it non-enumerable and non-writeable
Object.defineProperty(this, "anonymous_session_id", {
value: anonymous_session_id || null,
}); // to make it non-enumerable and non-writeable
Object.defineProperty(this, "anon_session_is_new", {
value: anon_session_is_new || false,
}); // to make it non-enumerable and non-writeable
this.timestamp = timestamp;
this.ip = ip || null;
this.user_id = user_id || null;
this.anonymous_user_id = anonymous_user_id || null;
this.session_id = session_id || null;
this.anonymous_session_id = anonymous_session_id || null;
this.anon_session_is_new = anon_session_is_new || null;
this.anonymous_user_id = anonymous_user_id || null;
}
async getUserData(app: App): Promise<Item | null> {
if (this.user_data) {
return this.user_data;
}
if (this.user_id === null) {
return null;
}
const c = new SuperContext(this);
- this.user_data = app.run_action(
+ this.user_data = app.runAction(
c,
["collections", "users", this.user_id],
"show"
);
return this.user_data;
}
}
diff --git a/src/datastore/query_and.ts b/src/datastore/query-and.ts
similarity index 98%
rename from src/datastore/query_and.ts
rename to src/datastore/query-and.ts
index 86a7026f..25dc2fb0 100644
--- a/src/datastore/query_and.ts
+++ b/src/datastore/query-and.ts
@@ -1,96 +1,96 @@
import Query from "./query";
import QueryStep, { Match } from "./query-step";
-import Graph from "./graph.js";
+import Graph from "./graph";
import { QueryTypes } from "../main";
export default class And extends Query {
graph: Graph;
aggregation_steps: { [id: string]: QueryStep | QueryStep[] };
received_deny_all: boolean;
constructor(...queries: Query[]) {
super();
this._reset();
for (let query of queries) {
this.addQuery(query);
}
}
_reset() {
this.graph = new Graph();
this.aggregation_steps = {};
this.received_deny_all = false;
}
addQuery(query: Query) {
if (this.received_deny_all) {
return;
}
if (query instanceof QueryTypes.DenyAll) {
this._reset();
this.received_deny_all = true;
}
const steps = query.dump();
for (let step of steps) {
const id = step.hash();
if (this._isInGraph(id)) {
continue;
}
this._addToAggregationSteps(id, step);
this._addDependenciesInGraph(id, step);
}
}
_isInGraph(key: string) {
return key.length === 32 && this.graph.node_ids.includes(key);
}
_addToAggregationSteps(id: string, step: QueryStep) {
this.graph.addNode(id, step.getCost());
this.aggregation_steps[id] = step;
}
_addDependenciesInGraph(id: string, step: QueryStep) {
let dependencies = step
.getUsedFields()
.filter((field) => this._isInGraph(field));
if (step instanceof Match) {
dependencies = dependencies.filter((d1) =>
this._isNotDependencyForAnyInGroup(d1, dependencies)
);
}
for (let dependency of dependencies) {
this.graph.addEdge(dependency, id);
}
}
_isNotDependencyForAnyInGroup(id: string, nodeGroup: string[]) {
return !nodeGroup.some(
(node) => id !== node && this.graph.pathExists(id, node)
);
}
dump() {
const sortedStepIds = this.graph.bestFirstSearch();
return sortedStepIds.reduce((steps, id) => {
if (Array.isArray(this.aggregation_steps[id])) {
steps.push(...(this.aggregation_steps[id] as QueryStep[]));
} else {
steps.push(this.aggregation_steps[id] as QueryStep);
}
return steps;
}, [] as QueryStep[]);
}
toPipeline() {
const sortedStepIds = this.graph.bestFirstSearch();
return sortedStepIds.reduce((pipeline, id) => {
if (Array.isArray(this.aggregation_steps[id])) {
for (let step of this.aggregation_steps[id] as QueryStep[]) {
step.pushStage(pipeline);
}
return pipeline;
}
return (this.aggregation_steps[id] as QueryStep).pushStage(
pipeline
);
}, []);
}
}
diff --git a/src/datastore/query_not.ts b/src/datastore/query-not.ts
similarity index 92%
rename from src/datastore/query_not.ts
rename to src/datastore/query-not.ts
index c651fef4..de01b8fe 100644
--- a/src/datastore/query_not.ts
+++ b/src/datastore/query-not.ts
@@ -1,21 +1,21 @@
-import Query from "./query.js";
+import Query from "./query";
export default class Not extends Query {
constructor(query: Query) {
super();
this.addQuery(query);
}
addQuery(query: Query) {
const steps = query.dump();
this.steps.push(...steps);
}
dump() {
return this.steps.map((step) => step.negate());
}
toPipeline() {
return this.steps.reduce(
(acc, step) => step.negate().pushStage(acc),
[]
);
}
}
diff --git a/src/datastore/query_or.ts b/src/datastore/query-or.ts
similarity index 92%
rename from src/datastore/query_or.ts
rename to src/datastore/query-or.ts
index a62daa57..0d1d7d38 100644
--- a/src/datastore/query_or.ts
+++ b/src/datastore/query-or.ts
@@ -1,48 +1,48 @@
-import Query from "./query.js";
-import QueryStep, { Lookup, Match } from "./query-step.js";
+import Query from "./query";
+import QueryStep, { Lookup, Match } from "./query-step";
export default class Or extends Query {
lookup_steps: QueryStep[];
constructor(...queries: Query[]) {
super();
this.lookup_steps = [];
for (let query of queries) {
this.addQuery(query);
}
}
addQuery(query: Query) {
const steps = query.dump();
this.lookup_steps.push(
...(steps.filter((step) => step instanceof Lookup) as Lookup[])
);
const match_stage_bodies: Query[] = [];
steps
.filter((step) => step instanceof Match)
.forEach((step) => step.pushDump(match_stage_bodies));
const match_stage =
match_stage_bodies.length > 1
? { $and: match_stage_bodies }
: match_stage_bodies[0];
this.steps.push(new Match(match_stage));
}
dump() {
return this.lookup_steps.concat(
new Match({ $or: this._getMatchExpressions() })
);
}
toPipeline() {
const lookups = this.lookup_steps.reduce(
(acc, step) => step.pushStage(acc),
[]
);
return lookups.concat({ $match: { $or: this._getMatchExpressions() } });
}
_getMatchExpressions() {
return this.steps.reduce((acc, step) => step.pushDump(acc), []);
}
}
diff --git a/src/datastore/query-types.ts b/src/datastore/query-types.ts
index f66be0f9..a53f9296 100644
--- a/src/datastore/query-types.ts
+++ b/src/datastore/query-types.ts
@@ -1,13 +1,13 @@
-import And from "./query_and";
-import Or from "./query_or";
+import And from "./query-and";
+import Or from "./query-or";
import { AllowAll } from "./allow-all";
import DenyAll from "./deny-all";
-import Not from "./query_not";
+import Not from "./query-not";
export default {
And,
Or,
Not,
DenyAll,
AllowAll,
};
diff --git a/src/datastore/query.test.ts b/src/datastore/query.test.ts
index bd580e92..8f500998 100644
--- a/src/datastore/query.test.ts
+++ b/src/datastore/query.test.ts
@@ -1,518 +1,518 @@
import Query, { Or } from "./query";
import * as assert from "assert";
-import QueryStep, { LookupBody, Lookup } from "./query-step.js";
+import QueryStep, { LookupBody, Lookup } from "./query-step";
import { QueryTypes } from "../main";
describe("Query", () => {
describe("Query general", () => {
it("Creates correct query from custom pipeline", () => {
const pipeline = [
{ $match: { title: { $ne: "The Joy of PHP" }, edition: 1 } },
{
$lookup: {
from: "authors",
localField: "author",
foreignField: "_id",
as: "author_item",
},
},
{
$unwind: "$author_item",
},
{ $match: { "author_item.name": { $regex: "some_regex" } } },
{
$lookup: {
from: "states",
localField: "author.state",
foreignField: "_id",
as: "state_item",
},
},
{ $unwind: "$state_item" },
{
$match: {
$or: [
{ "author_item.age": { $le: 30 } },
{ edition: { $gt: 3 } },
],
"state_item.abbrevation": { $eq: "PL" },
},
},
];
const query = Query.fromCustomPipeline(pipeline);
const authors_hash = hashLookup(
pipeline[1] as { $lookup: LookupBody }
);
const states_hash = hashLookup(
pipeline[4] as { $lookup: LookupBody }
);
const expected_pipeline = [
{ $match: { title: { $ne: "The Joy of PHP" } } },
{ $match: { edition: 1 } },
{
$lookup: {
from: "authors",
localField: "author",
foreignField: "_id",
as: authors_hash,
},
},
{
$unwind: "$" + authors_hash,
},
{
$match: {
[`${authors_hash}.name`]: {
$regex: "some_regex",
},
},
},
{
$lookup: {
from: "states",
localField: "author.state",
foreignField: "_id",
as: states_hash,
},
},
{ $unwind: "$" + states_hash },
{
$match: {
$or: [
{ [`${authors_hash}.age`]: { $le: 30 } },
{ edition: { $gt: 3 } },
],
},
},
{ $match: { [`${states_hash}.abbrevation`]: { $eq: "PL" } } },
];
assert.deepEqual(query.toPipeline(), expected_pipeline);
});
});
describe("Query.Or", () => {
it("Returns correct pipeline stages for simple case", () => {
const queries = [];
const M1 = {
title: { $ne: "The Joy of PHP" },
};
queries.push(Query.fromSingleMatch(M1));
let query = new Query();
const L2: LookupBody = {
from: "authors",
localField: "author",
foreignField: "_id",
unwind: true,
as: "author", //included for type safety during typescript migration
};
const L2_id = query.lookup(L2);
const M3 = {
[`${L2_id}.last_name`]: { $in: ["Scott", "Dostoyevsky"] },
};
query.match(M3);
queries.push(query);
const or = new Or(...queries);
const expected_pipeline = [
{
$lookup: {
from: L2.from,
localField: L2.localField,
foreignField: L2.foreignField,
as: L2_id,
},
},
{ $unwind: `$${L2_id}` },
{ $match: { $or: [M1, M3] } },
];
assert.deepEqual(or.toPipeline(), expected_pipeline);
});
it("Returns correct pipeline stages when And query is provided", () => {
let queries = [];
let subquery = new Query();
const L1: LookupBody = {
from: "authors",
localField: "author",
foreignField: "_id",
unwind: true,
as: "author", //added during typescript migration for type safety
};
const L1_id = subquery.lookup(L1);
const M2 = {
[`${L1_id}.last_name`]: { $in: ["Christie", "Rowling"] },
};
subquery.match(M2);
queries.push(subquery);
const M3 = {
title: { $ne: "The Joy of PHP" },
};
queries.push(Query.fromSingleMatch(M3));
const and_1 = new QueryTypes.And(...queries);
queries = [];
subquery = new Query();
const L4: LookupBody = {
from: "authors",
localField: "author",
foreignField: "_id",
unwind: true,
as: "author", //added during typescript migration for type safety
};
const L4_id = subquery.lookup(L4);
const M4 = {
[`${L4_id}.middle_name`]: { $in: ["Brown", "Black"] },
};
subquery.match(M4);
queries.push(subquery);
subquery = new Query();
subquery.lookup(L4);
const L5: LookupBody = {
from: "publisher",
localField: `${L4_id}.publisher`,
foreignField: "publisher_id",
unwind: true,
as: "author", //added during typescript migration for type safety
};
const L5_id = subquery.lookup(L5);
const M6 = {
$or: [
{ [`${L4_id}.first_name`]: "Ann" },
{ [`${L5_id}.income`]: { $gt: 1000 } },
],
};
subquery.match(M6);
const M7 = {
price: { $lte: 100 },
};
subquery.match(M7);
queries.push(subquery);
const and_2 = new QueryTypes.And(...queries);
const query = new QueryTypes.Or(and_1, and_2);
const expected_pipeline = makeQueryFromStageBodies([
L1,
L4,
L5,
{
$or: [{ $and: [M3, M2] }, { $and: [M7, M4, M6] }],
},
]).toPipeline();
assert.deepEqual(expected_pipeline, query.toPipeline());
});
});
describe("QueryTypes.Not", () => {
it("Correctly converts or to nor and vice versa", () => {
const query = new QueryTypes.Or(
Query.fromSingleMatch({ pages: { $gt: 200 } }),
Query.fromSingleMatch({ title: { $eq: "The Joy of PHP" } })
);
let negated_query = new QueryTypes.Not(query);
const expected_pipeline = query.toPipeline();
expected_pipeline[0].$match.$nor = expected_pipeline[0].$match.$or;
delete expected_pipeline[0].$match.$or;
assert.deepEqual(negated_query.toPipeline(), expected_pipeline);
assertQueryEqualsDoubleNegatedQuery(query, negated_query);
});
it("Correctly converts query with lookup", () => {
const query = new Query();
const L1: LookupBody = {
from: "authors",
localField: "author",
foreignField: "_id",
as: "author", //added during typescript migration for type safety
};
const L1_id = query.lookup(L1);
query.match({
[`${L1_id}.last_name`]: { $in: ["Christie", "Rowling"] },
});
let negated_query = new QueryTypes.Not(query);
const expected_pipeline = query.toPipeline();
expected_pipeline[1].$match = {
[`${L1_id}.last_name`]: {
$not: expected_pipeline[1].$match[`${L1_id}.last_name`],
},
};
assert.deepEqual(negated_query.toPipeline(), expected_pipeline);
assertQueryEqualsDoubleNegatedQuery(query, negated_query);
});
it("Correctly converts query with complex stages", () => {
const query = new Query();
const stage = {
$and: [
{ pages: { $gt: 200 } },
{ title: { $in: ["Clean Code", "The Joy of JS"] } },
{ printed: { $not: { $gte: 10000 } } },
],
};
query.match(stage);
let negated_query = new QueryTypes.Not(query);
const expected_pipeline: any[] = [
{
$match: {
$or: [
{ pages: { $not: stage.$and[0].pages } },
{ title: { $not: stage.$and[1].title } },
{ printed: stage.$and[2].printed?.$not },
],
},
},
];
assert.deepEqual(negated_query.toPipeline(), expected_pipeline);
expected_pipeline[0].$match = {
$nor: expected_pipeline[0].$match.$or,
};
const double_negated_query = new QueryTypes.Not(negated_query);
assert.deepEqual(
double_negated_query.toPipeline(),
expected_pipeline
);
});
function assertQueryEqualsDoubleNegatedQuery(
query: Query,
negated_query: Query
) {
const double_negated_query = new QueryTypes.Not(negated_query);
assert.deepEqual(
double_negated_query.toPipeline(),
query.toPipeline()
);
}
});
describe("QueryTypes.And", () => {
it("Returns pipeline stages in correct order for simple case", () => {
const queries = [];
let query = new Query();
const L1 = {
from: "authors",
localField: "author",
foreignField: "_id",
unwind: true,
as: "author", //added during typescript migration for type safety
};
const L1_id = query.lookup(L1);
const M2 = {
[`${L1_id}.last_name`]: { $in: ["Christie", "Rowling"] },
};
query.match(M2);
queries.push(query);
const M3 = {
title: { $ne: "The Joy of PHP" },
};
queries.push(Query.fromSingleMatch(M3));
const and = new QueryTypes.And(...queries);
const stageBodies = [M3, L1, M2];
assertStagesAreCorrectlyOrdered(stageBodies, and.toPipeline());
assert.deepEqual(makeSteps(stageBodies), and.dump());
});
function assertStagesAreCorrectlyOrdered(
expectedRawPipeline: any[],
actualPipeline: any[]
) {
const query = makeQueryFromStageBodies(expectedRawPipeline);
assert.deepEqual(actualPipeline, query.toPipeline());
}
function makeSteps(stageBodies: any[]) {
return stageBodies.reduce((acc, stageBody) => {
if (stageBody instanceof QueryTypes.Or) {
return acc.concat(stageBody.dump());
}
if ((stageBody as LookupBody).from) {
return acc.concat(new Lookup(stageBody as LookupBody));
}
return acc.concat(Query.fromSingleMatch(stageBody).dump());
}, []);
}
it("Returns pipeline stages in correct order for complex case", () => {
const queries = [];
let query = new Query();
const L1 = {
from: "authors",
localField: "author",
foreignField: "_id",
unwind: true,
as: "author", //added during typescript migration for type safety
};
const L1_id = query.lookup(L1);
const L2 = {
from: "publisher",
localField: `${L1_id}.publisher`,
foreignField: "publisher_id",
unwind: true,
as: "author", //added during typescript migration for type safety
};
const L2_id = query.lookup(L2);
const M3_4 = {
[`${L2_id}.city`]: { $in: ["A", "B"] },
$or: [
{ [`${L1_id}.first_name`]: "Ann" },
{ [`${L2_id}.income`]: { $gt: 1000 } },
],
};
query.match(M3_4);
queries.push(query);
query = new Query();
const M5 = {
title: { $ne: "The Joy of PHP" },
};
query.match(M5);
queries.push(query);
let subquery1 = new Query();
const O6_L1 = {
from: "libraries",
localField: "first_library",
foreignField: "library_id",
as: "author", //added during typescript migration for type safety
};
const O6_L1_id = subquery1.lookup(O6_L1);
const O6_M1 = {
[`${O6_L1_id}.street`]: { $in: ["A street", "B street"] },
[`${O6_L1_id}.open_at_night`]: { $eq: true },
};
subquery1.match(O6_M1);
const O6_M2 = {
books_count: { $lte: 30 },
};
let subquery2 = Query.fromSingleMatch(O6_M2);
const O6 = new QueryTypes.Or(subquery1, subquery2);
queries.push(O6);
const O7_M1 = {
title: {
$in: ["PHP - Python Has Power", "The Good Parts of JS"],
},
};
const O7_M2 = O6_M2;
const O7 = new QueryTypes.Or(
Query.fromSingleMatch(O7_M1),
Query.fromSingleMatch(O7_M2)
);
queries.push(O7);
query = new Query();
const L8 = {
from: "cover_types",
localField: "cover",
foreignField: "cover_type_id",
unwind: true,
as: "author", //added during typescript migration for type safety
};
const L8_id = query.lookup(L8);
const M9 = {
[`${L8_id}.name`]: { $ne: "hard" },
};
query.match(M9);
queries.push(query);
query = new Query();
// check if hashing is order insensitive
const L10 = {
localField: "cover",
from: "cover_types",
foreignField: "cover_type_id",
unwind: true,
as: "author", //added during typescript migration for type safety
};
const L10_id = query.lookup(L10);
const M11 = {
[`${L10_id}.name`]: { $ne: "no_cover" },
};
query.match(M11);
queries.push(query);
const stageBodies = [M5, O7, L8, M9, M11, O6, L1, L2, M3_4];
let and = new QueryTypes.And(...queries);
assertStagesAreCorrectlyOrdered(stageBodies, and.toPipeline());
assert.deepEqual(makeSteps(stageBodies), and.dump());
});
it("Returns deny all pipeline when provided QueryTypes.DenyAll", () => {
const queries: Query[] = [];
let query = new Query();
const L1 = {
from: "authors",
localField: "author",
foreignField: "_id",
unwind: true,
as: "author", //added during typescript migration for type safety
};
const L1_id = query.lookup(L1);
const M2 = {
[`${L1_id}.last_name`]: { $in: ["Christie", "Rowling"] },
};
query.match(M2);
queries.push(query);
const deny_all_query = new QueryTypes.DenyAll();
queries.push(deny_all_query);
const M3 = {
title: { $ne: "The Joy of PHP" },
};
queries.push(Query.fromSingleMatch(M3));
const and = new QueryTypes.And(...queries);
assert.deepEqual(and.toPipeline(), deny_all_query.toPipeline());
assert.deepEqual(and.dump(), deny_all_query.dump());
});
});
});
function makeQueryFromStageBodies(stageBodies: any[]) {
const query = new Query();
for (let i = 0; i < stageBodies.length; ++i) {
const stage = stageBodies[i];
if (stage instanceof Query) {
query.steps.push(...stage.dump());
} else if (stage.from) {
query.lookup(stage);
} else {
for (let step of Object.keys(stage)) {
query.match({ [step]: stage[step] });
}
}
}
return query;
}
function hashLookup({ $lookup }: { $lookup: LookupBody }) {
const { as, ...lookup_without_as } = $lookup;
return QueryStep.hashBody(lookup_without_as);
}
diff --git a/src/datastore/query.ts b/src/datastore/query.ts
index 8a19f70e..23fd5b19 100644
--- a/src/datastore/query.ts
+++ b/src/datastore/query.ts
@@ -1,93 +1,93 @@
import { Lookup, Match, default as QueryStep, LookupBody } from "./query-step";
import transformObject from "../utils/transform-object";
import QueryStage from "./query-stage";
export default class Query {
steps: QueryStep[];
body: any;
constructor() {
this.steps = [];
}
lookup(body: LookupBody) {
const lookup_step = new Lookup(body);
this.steps.push(lookup_step);
return lookup_step.hash();
}
match(body: { [key: string]: any }) {
for (let key of Object.keys(body)) {
this.steps.push(new Match({ [key]: body[key] }));
}
}
dump() {
return this.steps;
}
toPipeline() {
return this.steps.reduce(
(pipeline, query_step) => query_step.pushStage(pipeline),
[]
);
}
static fromSingleMatch(body: any) {
const query = new Query();
query.match(body);
return query;
}
static fromCustomPipeline(stages: QueryStage[]) {
const query = new Query();
let steps;
const field_as_to_hash: { [field_as: string]: string } = {};
for (let i = 0; i < stages.length; ++i) {
if (stages[i].$unwind) {
continue;
}
const stage = transformObject(
stages[i],
(prop) => {
if (prop.startsWith("$")) {
return prop;
}
const fields = prop.split(".");
return fields
.map((field) => field_as_to_hash[field] || field)
.join(".");
},
(prop, value) => {
let fields;
if (typeof value !== "string") {
return value;
}
if (prop === "localField") {
fields = value.split(".");
} else if (value.startsWith("$")) {
fields = value.substring(1).split(".");
} else {
return value;
}
return fields
.map((field) => field_as_to_hash[field] || field)
.join(".");
}
);
steps = QueryStep.fromStage(stage, query._isUnwindStage(stages, i));
if (stage.$lookup) {
const field_as = stage.$lookup.as;
field_as_to_hash[field_as] = steps[0].hash();
}
query.steps.push(...steps);
}
return query;
}
_isUnwindStage(stages: QueryStage[], i: number) {
if (!stages[i].$lookup) {
return false;
}
return stages[i + 1] && stages[i + 1].$unwind;
}
}
-export { default as Or } from "./query_or";
+export { default as Or } from "./query-or";
-export { default as And } from "./query_and";
-export { default as Not } from "./query_not";
+export { default as And } from "./query-and";
+export { default as Not } from "./query-not";
export { default as QueryStage } from "./query-stage";
diff --git a/src/email/templates/password-reset.ts b/src/email/templates/password-reset.ts
index ff66304b..2dbe74e0 100644
--- a/src/email/templates/password-reset.ts
+++ b/src/email/templates/password-reset.ts
@@ -1,32 +1,32 @@
import SimpleTemplate from "./simple";
import { App } from "../../main";
export default async function PasswordResetTemplate(
app: App,
{ email_address, token }: { email_address: string; token: string }
) {
const {
items: [{ username }],
- } = await app.run_action(
+ } = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"show",
{ filter: { email: email_address } }
);
return SimpleTemplate(app, {
subject: app.i18n("password_reset_email_subject", app.manifest.name),
to: `${username}<${email_address}>`,
text: `
${app.i18n("password_reset_email_text", [
app.manifest.name,
username,
])}`,
buttons: [
{
text: app.i18n("password_reset_cta"),
href: `${app.manifest.base_url}/confirm-password-reset?token=${token}&email=${email_address}`,
},
],
});
}
diff --git a/src/email/templates/simple.test.ts b/src/email/templates/simple.test.ts
index f7cf961f..d4042206 100644
--- a/src/email/templates/simple.test.ts
+++ b/src/email/templates/simple.test.ts
@@ -1,21 +1,21 @@
import assert from "assert";
-import { with_running_app_prod } from "../../test_utils/with-test-app.js";
-import SimpleTemplate from "./simple.js";
+import { withRunningAppProd } from "../../test_utils/with-test-app";
+import SimpleTemplate from "./simple";
describe("simpleTemplate", () => {
it("sends an email", async () =>
- with_running_app_prod(async ({ app, mail_api }) => {
+ withRunningAppProd(async ({ app, mail_api }) => {
const message = await SimpleTemplate(app, {
to: "test@example.com",
subject: "Congratulations!",
text: "Enlarge your 'seal' with herbal supplements",
});
await message.send(app);
- const messages = await mail_api.get_messages();
+ const messages = await mail_api.getMessages();
assert.equal(messages.length, 1);
assert.equal(
messages[0].sender,
`<${app.ConfigManager.get("email").from_address}>`
);
}));
});
diff --git a/src/email/templates/simple.ts b/src/email/templates/simple.ts
index e6c92569..d02c91f9 100644
--- a/src/email/templates/simple.ts
+++ b/src/email/templates/simple.ts
@@ -1,88 +1,88 @@
-import Message from "./../message.js";
+import Message from "./../message";
import path from "path";
import mjml2html from "mjml";
import assert from "assert";
-import { App } from "../../main.js";
+import { App } from "../../main";
export type Button = { text: string; href: string };
export type SimpleTemplateData = {
text: string;
subject: string;
to: string;
buttons?: Button[];
};
export default async function SimpleTemplate(
app: App,
data: SimpleTemplateData
) {
assert(data.text);
assert(data.subject);
assert(data.to);
assert(data.buttons === undefined || Array.isArray(data.buttons));
if (data.buttons === undefined) {
data.buttons = [];
}
const logo_cid = Math.floor(Math.random() * 10e6).toString();
let html;
if ((app.ConfigManager.get("core") as any).environment === "production") {
html = get_html(app, data, logo_cid);
} else {
html = "dummy";
}
const text = data.text + "\n\n" + buttons_to_text(data.buttons);
return new Message({
to: data.to,
subject: data.subject,
attachments: [
{
filename: path.basename(app.manifest.logo),
path: app.manifest.logo,
cid: logo_cid,
},
],
text,
html,
});
}
function buttons_to_text(buttons: Button[]) {
return buttons
.map((button) => `\t* ${button.text}: ${button.href}`)
.join("\n");
}
function get_html(app: App, data: SimpleTemplateData, logo_cid: string) {
const result = mjml2html(`
<mjml>
<mj-body>
<mj-section>
<mj-column>
<mj-image width="100" src="cid:${logo_cid}"></mj-image>
<mj-divider border-color="${
(app.manifest.colors && app.manifest.colors.primary) ||
"black"
}"></mj-divider>
<mj-text>
<h1>
${data.subject}
</h1>
${data.text}
</mj-text>
${
(data.buttons &&
data.buttons.map(
(button) =>
`<mj-button href="${button.href}" font-size="20px" background-color="#0074D9">${button.text}</mj-button>`
)) ||
""
}
</mj-column>
</mj-section>
</mj-body>
</mjml>
`);
return result.html;
}
diff --git a/src/http/extract-context.ts b/src/http/extract-context.ts
index 03d6599a..f40fa8c4 100644
--- a/src/http/extract-context.ts
+++ b/src/http/extract-context.ts
@@ -1,84 +1,84 @@
import App from "../app/app";
import SuperContext from "../super-context";
import Context from "../context";
function create_anonymous_session(app: App) {
- return app.run_action(
+ return app.runAction(
new SuperContext(),
["collections", "anonymous-sessions"],
"create",
{ "anonymous-session-id": null, "anonymous-user-id": null } //need to provide null here so the ids are genreated. Skipping the field would leave them "undefined"
);
}
function get_anonymous_session(app: App, anon_session_id: string) {
return app
- .run_action(
+ .runAction(
new SuperContext(),
["collections", "anonymous-sessions"],
"show",
{
filter: { "anonymous-session-id": anon_session_id },
}
)
.then(function (sealious_response) {
if (sealious_response.empty) {
return create_anonymous_session(app);
} else {
return sealious_response.items[0];
}
});
}
export default async function extract_context(app: App, request: any) {
const config = app.ConfigManager.get("www-server");
const cookie_name = config["session-cookie-name"];
const anon_cookie_name = config["anonymous-cookie-name"];
let session_id = request.state[cookie_name];
let anon_session_is_new = request.state[anon_cookie_name] === undefined;
let anonymous_session_id = null;
let get_anonymous_data = null;
if (anon_session_is_new) {
get_anonymous_data = create_anonymous_session(app);
} else {
anonymous_session_id = request.state[anon_cookie_name];
get_anonymous_data = get_anonymous_session(app, anonymous_session_id);
}
let anonymous_user_id = null;
await get_anonymous_data.then(function (anon_session) {
anonymous_session_id = anon_session["anonymous-session-id"];
anonymous_user_id = anon_session["anonymous-user-id"];
});
- const sealious_response = await app.run_action(
+ const sealious_response = await app.runAction(
new SuperContext(),
["collections", "sessions"],
"show",
{ filter: { "session-id": session_id } }
);
const timestamp = Date.now();
const ip = request.info.remoteAddress;
let user;
if (sealious_response.empty) {
session_id = undefined;
} else {
user = sealious_response.items[0].user;
}
return new Context(
timestamp,
ip,
user,
session_id,
anonymous_session_id,
anon_session_is_new,
anonymous_user_id
);
}
module.exports = extract_context;
diff --git a/src/http/get-request-body.subtest.ts b/src/http/get-request-body.subtest.ts
index 97fec315..cae1b9bf 100644
--- a/src/http/get-request-body.subtest.ts
+++ b/src/http/get-request-body.subtest.ts
@@ -1,124 +1,124 @@
import assert from "assert";
-import { with_running_app } from "../test_utils/with-test-app.js";
-import { assert_throws_async } from "../test_utils";
+import { withRunningApp } from "../test_utils/with-test-app";
+import { assertThrowsAsync } from "../test_utils/assert-throws-async";
import { request, RequestOptions } from "http";
-import Field from "../chip-types/field.js";
-import { App, Collection } from "../main.js";
+import Field from "../chip-types/field";
+import { App, Collection } from "../main";
describe("get-request-body", () => {
- async function async_request(
+ async function asyncRequest(
options: RequestOptions,
form_data: string
): Promise<{ body: any; source: any }> {
return new Promise((resolve) => {
const req = request(options, (res) => {
res.setEncoding("utf-8");
res.on("data", (chunk) => {
const { body, source } = JSON.parse(chunk);
resolve({ body, source });
});
});
req.write(form_data);
req.end();
});
}
- async function create_resources(app: App) {
+ async function createResources(app: App) {
class ArrayOfObjects extends Field {
getTypeName = () => "array-of-objects";
async isProperValue(_: any, new_value: any) {
if (!Array.isArray(new_value)) {
return Field.invalid("It should be array of objects.");
}
for (const value of new_value) {
if (typeof value !== "object") {
return Field.invalid("One of array item isn't object.");
}
}
return Field.valid();
}
}
Collection.fromDefinition(app, {
name: "complex-data",
fields: [
{
name: "body",
type: ArrayOfObjects,
required: true,
},
{
name: "source",
type: "image",
required: true,
},
],
});
Collection.fromDefinition(app, {
name: "strings",
fields: [
{
name: "title",
type: "text",
},
],
});
}
it("throws application error when `null` is provided as root field value and content-type is set to `application/json`", async () =>
- with_running_app(async ({ app, rest_api }) => {
- await create_resources(app);
+ withRunningApp(async ({ app, rest_api }) => {
+ await createResources(app);
- await assert_throws_async(
+ await assertThrowsAsync(
async () =>
await rest_api.post(
"/api/v1/collections/strings",
{ title: null },
{
headers: { "content-type": "application/json" },
}
),
(e) => {
assert.equal(e.response.status, 403);
assert.equal(
e.response.data.message,
"There are problems with some of the provided values."
);
assert.notEqual(e.response.status, 500);
assert.notEqual(
e.response.data.message,
"An internal server error occurred"
);
}
);
}));
it("handles complex data sent as multipart/form-data", async () => {
- await with_running_app(async ({ app }) => {
- await create_resources(app);
+ await withRunningApp(async ({ app }) => {
+ await createResources(app);
// PNG file is empty but it doesnt matter for the test
const form_data =
'------------------------------4ebf00fbcf09\r\nContent-Disposition: form-data; name="source"; filename="test.png"\r\nContent-Type: image/png\r\n\r\nPNG\r\n\r\n\r\n------------------------------4ebf00fbcf09\r\nContent-Disposition: form-data; name="body"; filename="blob"\r\nContent-Type: application/json\r\n\r\n[["Foo", {"Bar": "baz"}]]\r\n------------------------------4ebf00fbcf09--\r\n';
const options = {
hostname: "localhost",
port: 8888,
path: "/api/v1/collections/complex-data",
method: "POST",
headers: {
"Content-Type":
"multipart/form-data; boundary=----------------------------4ebf00fbcf09",
},
};
const Test = new RegExp(/\/api\/v1\/uploaded-files\/\S*\/test.png/);
- const { body, source } = await async_request(options, form_data);
+ const { body, source } = await asyncRequest(options, form_data);
assert.strict.deepEqual(body, [["Foo", { Bar: "baz" }]]);
assert.ok(Test.test(source));
});
});
});
diff --git a/src/http/get-request-body.ts b/src/http/get-request-body.ts
index 531b14a1..081bec9c 100644
--- a/src/http/get-request-body.ts
+++ b/src/http/get-request-body.ts
@@ -1,61 +1,61 @@
import Context from "../context";
import File from "../data-structures/file";
import { App } from "../main";
const squares = {
set: function (obj: any, key: string, value: any) {
const keys = key.split(/[\]\[]{1,2}/g);
if (keys.length > 1) {
keys.splice(-1); //to remove the trailing empty string;
}
const last_key = keys[keys.length - 1];
let current = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
const next_key = keys[i + 1];
if (current[key] === undefined) {
if (next_key === "") {
current[key] = [];
} else {
current[key] = {};
}
}
current = current[key];
}
if (last_key === "") {
current.push(value);
} else {
current[last_key] = value;
}
},
};
-export default async function get_request_body(
+export default async function getRequestBody(
app: App,
_: Context,
request: any
) {
const parsed_query: { [field: string]: any } = {};
for (const i in request.query) {
squares.set(parsed_query, i, request.query[i]);
}
for (const i in request.payload) {
squares.set(parsed_query, i, request.payload[i]);
}
for (var i in request.payload) {
if (
// In case `request.payload[i]` is either null or undefined,
// we can't access a `payload` property of it,
// a TypeError will be thrown.
request.payload[i] &&
request.payload[i].payload
) {
let filename = request.payload[i].filename;
var data = request.payload[i].payload;
const file = await File.fromData(app, data);
file.filename = filename;
parsed_query[i] = data instanceof Buffer ? file : data;
}
}
return parsed_query;
}
diff --git a/src/http/handle-request.ts b/src/http/handle-request.ts
index 240b0f9f..26578522 100644
--- a/src/http/handle-request.ts
+++ b/src/http/handle-request.ts
@@ -1,42 +1,42 @@
-import get_request_body from "./get-request-body";
-import http_to_subject_method from "./http-to-method-name.js";
-import extract_context from "./extract-context";
-import handle_response from "./handle-response.js";
-import handle_error from "./handle-error.js";
-import SealiousResponse from "../../common_lib/response/sealious-response.js";
-import App from "../app/app.js";
+import getRequestBody from "./get-request-body";
+import http_to_subject_method from "./http-to-method-name";
+import extractContext from "./extract-context";
+import handleResponse from "./handle-response";
+import handleError from "./handle-error";
+import SealiousResponse from "../../common_lib/response/sealious-response";
+import App from "../app/app";
const ID_INDEX = 2;
export default async function handle_request(app: App, request: any, h: any) {
try {
const path_elements = parsePathElements(request);
const action_name =
http_to_subject_method[
request.method.toUpperCase() as keyof typeof http_to_subject_method
];
- const context = await extract_context(app, request);
- const body = get_request_body(app, context, request);
+ const context = await extractContext(app, request);
+ const body = getRequestBody(app, context, request);
return app
- .run_action(context, path_elements, action_name, body)
+ .runAction(context, path_elements, action_name, body)
.then((response) =>
response instanceof SealiousResponse
? response.toObject()
: response
)
- .then((result) => handle_response(app, context, h)(result))
- .catch((result) => handle_error(app)(result));
+ .then((result) => handleResponse(app, context, h)(result))
+ .catch((result) => handleError(app)(result));
} catch (error) {
app.Logger.error(error);
return error;
}
}
function parsePathElements(request: any) {
const path_elements = request.params.elements.split("/");
if (path_elements[ID_INDEX] && path_elements[ID_INDEX].includes("+")) {
path_elements[ID_INDEX] = path_elements[ID_INDEX].split("+");
}
return path_elements;
}
diff --git a/src/http/routes/account-creation-details.subtest.ts b/src/http/routes/account-creation-details.subtest.ts
index 540b85b2..851252f7 100644
--- a/src/http/routes/account-creation-details.subtest.ts
+++ b/src/http/routes/account-creation-details.subtest.ts
@@ -1,24 +1,24 @@
import axios from "axios";
import assert from "assert";
-import { with_running_app } from "../../test_utils/with-test-app.js";
-import { assert_throws_async } from "../../test_utils";
+import { withRunningApp } from "../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../test_utils/assert-throws-async";
describe("account-creation-details", () => {
it("throws when no token/email is present", () =>
- with_running_app(({ base_url }) =>
- assert_throws_async(
+ withRunningApp(({ base_url }) =>
+ assertThrowsAsync(
async () => {
await axios.get(`${base_url}/account-creation-details`);
},
(_) => {}
)
));
it("displays an html form after the positive flow", () =>
- with_running_app(async ({ base_url }) => {
+ withRunningApp(async ({ base_url }) => {
const resp = await axios.get(
`${base_url}/account-creation-details?token=oieajgoiea&email=ababab@ok.pl`
);
assert.deepEqual(resp.status, 200);
assert(resp.data.length);
}));
});
diff --git a/src/http/routes/confirm-password-reset.subtest.ts b/src/http/routes/confirm-password-reset.subtest.ts
index 48102425..29cbe176 100644
--- a/src/http/routes/confirm-password-reset.subtest.ts
+++ b/src/http/routes/confirm-password-reset.subtest.ts
@@ -1,11 +1,11 @@
import axios from "axios";
-import { with_running_app } from "../../test_utils/with-test-app.js";
+import { withRunningApp } from "../../test_utils/with-test-app";
describe("confirm-password-reset", () => {
it("displays an html form", async () =>
- with_running_app(async ({ base_url }) => {
+ withRunningApp(async ({ base_url }) => {
await axios.get(
`${base_url}/confirm-password-reset?token=kupcia&email=dupcia`
);
}));
});
diff --git a/src/http/routes/finalize-password-reset.subtest.ts b/src/http/routes/finalize-password-reset.subtest.ts
index 977682c2..cec23d95 100644
--- a/src/http/routes/finalize-password-reset.subtest.ts
+++ b/src/http/routes/finalize-password-reset.subtest.ts
@@ -1,75 +1,73 @@
import assert from "assert";
import tough from "tough-cookie";
-import { assert_throws_async } from "../../test_utils";
-import { with_running_app_prod } from "../../test_utils/with-test-app.js";
+import { assertThrowsAsync } from "../../test_utils/assert-throws-async";
+import { withRunningAppProd } from "../../test_utils/with-test-app";
import { App } from "../../main";
describe("finalize password reset", () => {
async function create_a_user(app: App) {
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
username: "user",
email: "user@example.com",
password: "password",
}
);
}
it("allows to change a password (entire flow)", async () =>
- with_running_app_prod(async ({ app, mail_api, rest_api }) => {
+ withRunningAppProd(async ({ app, mail_api, rest_api }) => {
await create_a_user(app);
const cookieJar = new tough.CookieJar();
const options = {
jar: cookieJar,
withCredentials: true,
};
await rest_api.post(
"/api/v1/sessions",
{ username: "user", password: "password" },
options
);
await rest_api.delete("/api/v1/sessions/current", options);
await rest_api.post("/api/v1/collections/password-reset-intents", {
email: "user@example.com",
});
- const message_metadata = (await mail_api.get_messages()).filter(
+ const message_metadata = (await mail_api.getMessages()).filter(
(message) => message.recipients[0] == "<user@example.com>"
)[0];
assert(message_metadata.subject);
- const message = await mail_api.get_message_by_id(
- message_metadata.id
- );
+ const message = await mail_api.getMessageById(message_metadata.id);
const matches = message.match(/token=([^?&]+)/);
if (!matches) {
throw new Error("token not found in the message");
}
const token = matches[1];
await rest_api.post("/finalize-password-reset", {
email: "user@example.com",
token,
password: "new-password",
});
await rest_api.post(
"/api/v1/sessions",
{ username: "user", password: "new-password" },
options
);
- await assert_throws_async(
+ await assertThrowsAsync(
async () =>
rest_api.post("/finalize-password-reset", {
email: "user@example.com",
token,
password: "using the same token twice hehehehhee",
}),
() => {}
);
}));
});
diff --git a/src/http/routes/finalize-password-reset.ts b/src/http/routes/finalize-password-reset.ts
index 98fc17bf..04f056ac 100644
--- a/src/http/routes/finalize-password-reset.ts
+++ b/src/http/routes/finalize-password-reset.ts
@@ -1,46 +1,46 @@
import assert from "assert";
import { App } from "../../main";
export default (app: App) => {
app.HTTPServer.custom_route(
"POST",
"/finalize-password-reset",
async (app, _, params) => {
assert(params.token, "Token missing");
assert(params.password, "Password missing");
- const intent_response = await app.run_action(
+ const intent_response = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "password-reset-intents"],
"show",
{ filter: { token: params.token } }
);
if (intent_response.empty) {
throw new Error("Incorrect token");
}
const { email, id } = intent_response.items[0];
- const user_response = await app.run_action(
+ const user_response = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"show",
{ filter: { email } }
);
if (user_response.empty) {
throw new Error("No user with this email address.");
}
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users", user_response.items[0].id],
"edit",
{ password: params.password }
);
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "password-reset-intents", id],
"delete"
);
return "Password reset successful";
}
);
};
diff --git a/src/http/routes/finalize-registration-intent.subtest.ts b/src/http/routes/finalize-registration-intent.subtest.ts
index 15a9b964..f1e3506d 100644
--- a/src/http/routes/finalize-registration-intent.subtest.ts
+++ b/src/http/routes/finalize-registration-intent.subtest.ts
@@ -1,56 +1,54 @@
import * as assert from "assert";
import tough from "tough-cookie";
-import { with_stopped_app_prod } from "../../test_utils/with-test-app.js";
-import { SingleItemResponse } from "../../../common_lib/response/responses.js";
+import { withStoppedAppProd } from "../../test_utils/with-test-app";
+import { SingleItemResponse } from "../../../common_lib/response/responses";
describe("finalize registration", () => {
it("allows to register an account (entire flow)", async () =>
- with_stopped_app_prod(async ({ app, mail_api, rest_api }) => {
+ withStoppedAppProd(async ({ app, mail_api, rest_api }) => {
app.ConfigManager.set("roles", ["admin"]);
await app.start();
const cookieJar = new tough.CookieJar();
const options = {
jar: cookieJar,
withCredentials: true,
};
await rest_api.post(
"/api/v1/collections/registration-intents",
{ email: "user@example.com", role: "admin" },
options
);
- const message_metadata = (await mail_api.get_messages()).filter(
+ const message_metadata = (await mail_api.getMessages()).filter(
(message) => message.recipients[0] == "<user@example.com>"
)[0];
assert.ok(message_metadata?.subject);
- const message = await mail_api.get_message_by_id(
- message_metadata.id
- );
+ const message = await mail_api.getMessageById(message_metadata.id);
const match_result = message.match(/token=([^?&]+)/);
if (!match_result) {
throw new Error("Didn't find a token");
}
const token = match_result[1];
await rest_api.post("/finalize-registration-intent", {
email: "user@example.com",
token,
password: "password",
username: "user",
});
await rest_api.post(
"/api/v1/sessions",
{ username: "user", password: "password" },
options
);
const { roles } = (await rest_api.getSealiousResponse(
"/api/v1/users/me?attachments[roles]=true",
options
)) as SingleItemResponse;
assert.equal(roles.length, 1);
assert.equal(roles[0].role, "admin");
}));
});
diff --git a/src/http/routes/finalize-registration-intent.ts b/src/http/routes/finalize-registration-intent.ts
index c2135a4e..1dd8aea0 100644
--- a/src/http/routes/finalize-registration-intent.ts
+++ b/src/http/routes/finalize-registration-intent.ts
@@ -1,61 +1,61 @@
import assert from "assert";
import { App } from "../../main";
module.exports = (app: App) => {
app.HTTPServer.custom_route(
"POST",
"/finalize-registration-intent",
async (app, _, params) => {
assert(params.token, "Token missing");
assert(params.username, "Username missing");
assert(params.password, "Password missing");
- const response = await app.run_action(
+ const response = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "registration-intents"],
"show",
{ filter: { token: params.token } }
);
if (response.empty) {
throw new Error("Incorrect token");
}
const { email, role, id } = response.items[0];
- const user = await app.run_action(
+ const user = await app.runAction(
new app.Sealious.SuperContext(),
["collections", "users"],
"create",
{
password: params.password,
username: params.username,
email,
}
);
if (role) {
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "user-roles"],
"create",
{ user: user.id, role }
);
}
- await app.run_action(
+ await app.runAction(
new app.Sealious.SuperContext(),
["collections", "registration-intents", id],
"delete"
);
const target_path = app.ConfigManager.get(
"accout_creation_success_path"
);
if (target_path) {
assert.equal(
target_path[0],
"/",
"'accout_creation_success_path' set, but doesn't start with a '/'"
);
return `<meta http-equiv="refresh" content="0; url=${target_path}" />`;
}
return "Account creation successful";
}
);
};
diff --git a/src/main.ts b/src/main.ts
index dccc9ab4..675aede4 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,45 +1,45 @@
export { default as Query } from "./datastore/query";
export { default as QueryTypes } from "./datastore/query-types";
export { default as SpecialFilter } from "./chip-types/special-filter";
export * as SpecialFilters from "./app/base-chips/special_filters/special-filters";
export { Hookable } from "./app/hookable";
export { default as Response } from "../common_lib/response/sealious-response";
export { default as SingleItemResponse } from "../common_lib/response/single-item-response";
export { ActionName } from "./action";
-export { default as Action } from "./action.js";
-export { default as App } from "./app/app.js";
-export { default as ChipManager } from "./app/chip-manager.js";
+export { default as Action } from "./action";
+export { default as App } from "./app/app";
+export { default as ChipManager } from "./app/chip-manager";
export { default as Config } from "./app/config";
-export { default as ConfigManager } from "./app/config-manager.js";
+export { default as ConfigManager } from "./app/config-manager";
export { default as Logger } from "./app/logger";
export { default as Manifest } from "./app/manifest";
-export { default as MetadataFactory } from "./app/metadata.js";
+export { default as MetadataFactory } from "./app/metadata";
export { default as AccessStrategy } from "./chip-types/access-strategy";
export * as AccessStrategies from "./chip-types/access-strategy";
export { default as Channel } from "./chip-types/channel";
export {
CollectionDefinition,
default as Collection,
} from "./chip-types/collection";
export { default as Context } from "./context";
export {
default as SubjectPath,
SubjectPathEquiv,
} from "./data-structures/subject-path";
export * as Queries from "./datastore/query";
export { default as EmailFactory } from "./email/email";
export { default as HttpServer } from "./http/http";
export { default as i18nFactory } from "./i18n/i18n";
-export { default as RootSubject } from "./subject/predefined-subjects/root-subject.js";
+export { default as RootSubject } from "./subject/predefined-subjects/root-subject";
export { default as Subject } from "./subject/subject";
export { default as SuperContext } from "./super-context";
export { default as CalculatedField } from "./chip-types/calculated-field";
export { default as Item } from "../common_lib/response/item";
export * as EventMatchers from "./app/event-matchers";
export * as EmailTemplates from "./email/templates/templates";
export { default as Field } from "./chip-types/field";
export * from "./chip-types/field";
export { EventDescription } from "./app/hookable";
export * as Errors from "./response/errors";
export { default as File } from "./data-structures/file";
diff --git a/src/subject/attachments/reference-to-collection.ts b/src/subject/attachments/reference-to-collection.ts
index 69b7e8dd..d3f2510a 100644
--- a/src/subject/attachments/reference-to-collection.ts
+++ b/src/subject/attachments/reference-to-collection.ts
@@ -1,86 +1,86 @@
import AttachmentLoader from "./attachment-loader";
import Context from "../../context";
import App from "../../app/app";
import { Document } from "../../data-structures/document";
import { LooseObject } from "../types";
export type ReferenceToCollectionConstructorParams = {
collection: string;
attachments_query: object;
documents: Array<Document>;
};
export default class ReferenceToCollection extends AttachmentLoader {
collection: string;
attachments_query: object;
documents: Array<Document>;
constructor(
context: Context,
field_name: string,
{
collection,
attachments_query,
documents,
}: ReferenceToCollectionConstructorParams
) {
super(context, field_name);
this.context = context;
this.field_name = field_name;
this.documents = documents;
this.collection = collection;
this.attachments_query = attachments_query;
}
async loadTo(
app: App,
attachments: LooseObject,
fieldsWithAttachments: LooseObject
): Promise<any> {
const ids = Array.from(this._extractIds());
const responses = await Promise.all(
ids.map((id: string) =>
- app.run_action(
+ app.runAction(
this.context,
["collections", this.collection, id],
"show",
this._getActionParams(this.attachments_query)
)
)
);
for (let response of responses) {
Object.assign(attachments, response.getAttachments());
response.items.forEach((document: Document) => {
attachments[document.id] = document;
});
const submetadata = response.getMetadata();
fieldsWithAttachments[this.field_name] = {};
if (submetadata) {
Object.assign(
fieldsWithAttachments[this.field_name],
submetadata
);
}
}
}
_extractIds() {
const ids = new Set();
for (let document of this.documents) {
if (Array.isArray(document[this.field_name])) {
for (let id of document[this.field_name]) {
ids.add(id);
}
} else {
ids.add(document[this.field_name]);
}
}
return ids;
}
_getActionParams(attachments_query: object) {
return typeof attachments_query === "object"
? { attachments: attachments_query }
: {};
}
}
diff --git a/src/subject/predefined-subjects/me-subject.ts b/src/subject/predefined-subjects/me-subject.ts
index 3c7a660a..474d4e9b 100644
--- a/src/subject/predefined-subjects/me-subject.ts
+++ b/src/subject/predefined-subjects/me-subject.ts
@@ -1,32 +1,32 @@
import { LeafSubject } from "../subject";
import * as Errors from "../../response/errors";
import { ActionName } from "../../action";
import Context from "../../context";
export default class MeSubject extends LeafSubject {
async performAction(
context: Context,
action_name: ActionName,
params: any
) {
if (!context.user_id) {
throw new Errors.InvalidCredentials("You're not logged in!");
}
try {
- return await this.app.run_action(
+ return await this.app.runAction(
context,
["collections", "users", context.user_id],
action_name,
params
);
} catch (error) {
if (error.type === "not_found") {
throw new Errors.InvalidCredentials("You're not logged in!");
}
throw error;
}
}
getName() {
return "me";
}
}
diff --git a/src/subject/predefined-subjects/sessions-subject.ts b/src/subject/predefined-subjects/sessions-subject.ts
index e5f50eab..5d4b117c 100644
--- a/src/subject/predefined-subjects/sessions-subject.ts
+++ b/src/subject/predefined-subjects/sessions-subject.ts
@@ -1,92 +1,89 @@
import Subject from "../subject";
import App from "../../app/app";
import Context from "../../context";
import { NewSession } from "../../../common_lib/response/responses";
import { CreateActionName } from "../../action";
-const CurrentSessionSubject = require("../subject-types/current-session-subject.js");
-const SuperContext = require("../../super-context.js");
+
+import CurrentSessionSubject from "../subject-types/current-session-subject.js";
+import SuperContext from "../../super-context";
import * as Errors from "../../response/errors";
-const SecureHasher = require("../../utils/secure-hasher.js");
+import SecureHasher from "../../utils/secure-hasher.js";
-async function validate_auth_data(
- app: App,
- username: string,
- password: string
-) {
+async function validateAuthData(app: App, username: string, password: string) {
const [user] = await app.Datastore.find("users", {
"username.safe": username,
});
if (!user) {
throw new Errors.InvalidCredentials("Incorrect username!");
}
const is_valid = await SecureHasher.matches(password, user.password);
if (!is_valid) {
throw new Errors.InvalidCredentials("Incorrect password!");
}
return user;
}
type TryToLoginParams = {
username: string;
password: string;
};
-async function try_to_login(
+async function tryToLogin(
app: App,
context: Context,
{ username, password }: TryToLoginParams
) {
if (!username) {
throw new Errors.InvalidCredentials("Missing username!");
}
if (!password) {
throw new Errors.InvalidCredentials("Missing password!");
}
- const user = await validate_auth_data(app, username, password);
- const session = await app.run_action(
+ const user = await validateAuthData(app, username, password);
+ const session = await app.runAction(
new SuperContext(),
["collections", "sessions"],
"create",
{ user: user.sealious_id, "session-id": null }
);
- await app.run_action(
+ await app.runAction(
new SuperContext(),
["collections", "users", user.sealious_id],
"edit",
{ last_login_context: context }
);
return new NewSession(session["session-id"]);
}
export default class SessionsSubject extends Subject {
async performAction(
context: Context,
action_name: CreateActionName,
params: any
) {
if (action_name === "create") {
- return try_to_login(this.app, context, params || {});
+ return tryToLogin(this.app, context, params || {});
}
throw new Errors.BadSubjectAction(
`Unknown/unsupported action '${action_name}' for SessionsSubject`
);
}
async getChildSubject(path_element: string) {
if (path_element === "current") {
return new CurrentSessionSubject(this.app);
}
throw new Errors.BadSubjectPath(
`No child subject with key '${path_element}' in SessionSubject`
);
}
getName() {
return "sessions";
}
}
diff --git a/src/subject/predefined-subjects/specifications.test.ts b/src/subject/predefined-subjects/specifications.test.ts
index 86c2786d..2592171b 100644
--- a/src/subject/predefined-subjects/specifications.test.ts
+++ b/src/subject/predefined-subjects/specifications.test.ts
@@ -1,61 +1,61 @@
import axios from "axios";
import assert from "assert";
-import { with_running_app } from "../../test_utils/with-test-app.js";
-import { Collection } from "../../main.js";
+import { withRunningApp } from "../../test_utils/with-test-app";
+import { Collection } from "../../main";
describe("specifications endpoint", () => {
it("returns a list of collections", async () => {
- await with_running_app(async ({ base_url }) => {
+ await withRunningApp(async ({ base_url }) => {
const { data: result } = await axios.get(
`${base_url}/api/v1/specifications`
);
assert.deepEqual(
[
"user-roles",
"users",
"sessions",
"anonymous-sessions",
"formatted-images",
"password-reset-intents",
"registration-intents",
],
result.map((collection_spec: any) => collection_spec.name)
);
});
});
it("contains information on whether or not a field is required", async () => {
- await with_running_app(async ({ base_url }) => {
+ await withRunningApp(async ({ base_url }) => {
const { data: result } = await axios.get(
`${base_url}/api/v1/specifications`
);
assert.notEqual(
result.filter(
(collection: any) => collection.name === "users"
)[0].fields.username.required,
undefined
);
});
});
it("contains display_hints when provided", async function () {
- await with_running_app(async ({ app, rest_api }) => {
+ await withRunningApp(async ({ app, rest_api }) => {
Collection.fromDefinition(app, {
name: "foo",
fields: [{ name: "bar", type: "text" }],
display_hints: "A hint",
});
const specifications = await rest_api.get("/api/v1/specifications");
const does_every_element_have_dh = specifications.every(
(e: any) => e.display_hints
);
assert.ok(does_every_element_have_dh);
const created_collection = specifications.find(
(e: any) => e.name === "foo"
);
assert.equal(created_collection.display_hints, "A hint");
});
});
});
diff --git a/src/subject/predefined-subjects/users-subject.ts b/src/subject/predefined-subjects/users-subject.ts
index 5f6ae45d..43116d08 100644
--- a/src/subject/predefined-subjects/users-subject.ts
+++ b/src/subject/predefined-subjects/users-subject.ts
@@ -1,65 +1,65 @@
-import Subject from "../subject.js";
+import Subject from "../subject";
import * as Errors from "../../response/errors";
import me_synonyms from "../../misc/me-synonyms";
import MeSubject from "./me-subject";
-import SuperContext from "../../super-context.js";
-import App from "../../app/app.js";
-import Context from "../../context.js";
-import { CreateActionName, ShowActionName } from "../../action.js";
+import SuperContext from "../../super-context";
+import App from "../../app/app";
+import Context from "../../context";
+import { CreateActionName, ShowActionName } from "../../action";
export default class UsersSubject extends Subject {
getName = () => "users";
async performAction(
context: Context,
action_name: CreateActionName | ShowActionName,
params: any
) {
params = params || {};
switch (action_name) {
case "create":
- return this.app.run_action(
+ return this.app.runAction(
context,
["collections", "users"],
"create",
params
);
case "show":
- return this.app.run_action(
+ return this.app.runAction(
context,
["collections", "users"],
"show",
params
);
default:
throw new Errors.BadSubjectAction(
`Unknown/unsupported action for UsersSubject: '${action_name}'`
);
}
}
async getChildSubject(path_element: string) {
if (me_synonyms.indexOf(path_element) !== -1) {
return new MeSubject(this.app);
}
const username = path_element;
- const response = await this.app.run_action(
+ const response = await this.app.runAction(
new SuperContext(),
["collections", "users"],
"show",
{
filter: { username: username },
}
);
if (response.empty) {
throw new Errors.BadSubjectPath(`Unknown username: '${username}'`);
}
return this.app.RootSubject.getSubject([
"collections",
"users",
response.id,
]);
}
}
diff --git a/src/subject/subject-types/collection-subject.test.ts b/src/subject/subject-types/collection-subject.test.ts
index 68d90f5d..afd9a430 100644
--- a/src/subject/subject-types/collection-subject.test.ts
+++ b/src/subject/subject-types/collection-subject.test.ts
@@ -1,57 +1,57 @@
import assert from "assert";
import sinon from "sinon";
-import { with_stopped_app } from "../../test_utils/with-test-app.js";
-import { Collection } from "../../main.js";
+import { withStoppedApp } from "../../test_utils/with-test-app";
+import { Collection } from "../../main";
describe("collection-subject", () => {
describe("multiple post", () => {
it("should fire handlers for every resource", async () =>
- with_stopped_app(async ({ app, rest_api }) => {
+ withStoppedApp(async ({ app, rest_api }) => {
Collection.fromDefinition(app, {
name: "target",
fields: [{ name: "value", type: "int" }],
});
Collection.fromDefinition(app, {
name: "source",
fields: [{ name: "value", type: "int" }],
});
const handler = sinon.spy();
app.addHook(
new app.Sealious.EventMatchers.Collection({
when: "after",
collection_name: "target",
action: "create",
}),
handler
);
await app.start();
for (let i = 1; i <= 3; i++) {
await rest_api.post("/api/v1/collections/source", {
value: i,
});
}
await rest_api.post("/api/v1/collections/target", {
__multiple: true,
mode: "cartesian",
sources: [
[
"collection_fields",
{
collection: "source",
filter: {},
fields: ["value"],
map_to: ["value"],
},
],
],
});
assert.equal(handler.callCount, 4);
}));
});
});
diff --git a/src/subject/subject-types/current-session-subject.ts b/src/subject/subject-types/current-session-subject.ts
index f7d8cd54..0acc0f06 100644
--- a/src/subject/subject-types/current-session-subject.ts
+++ b/src/subject/subject-types/current-session-subject.ts
@@ -1,68 +1,68 @@
-import { LeafSubject } from "../subject.js";
+import { LeafSubject } from "../subject";
import * as Errors from "../../response/errors";
import Context from "../../context";
import { DeleteActionName } from "../../action";
import SuperContext from "../../super-context";
import Item from "../../../common_lib/response/item";
export default class CurrentSession extends LeafSubject {
async performAction(
context: Context,
action_name: DeleteActionName,
_: any
) {
if (action_name !== "delete") {
throw new Errors.DeveloperError(
`Unknown action ${action_name} for CurrentSession subject.`
);
}
try {
- const session_sealious_response = await this.app.run_action(
+ const session_sealious_response = await this.app.runAction(
new SuperContext(),
["collections", "sessions"],
"show",
{
filter: { "session-id": context.session_id },
}
);
await Promise.all(
session_sealious_response.items.map((session: Item) =>
- this.app.run_action(
+ this.app.runAction(
new SuperContext(),
["collections", "sessions", session.id],
"delete"
)
)
);
- const anonymous_session_sealious_response = await this.app.run_action(
+ const anonymous_session_sealious_response = await this.app.runAction(
new SuperContext(),
["collections", "anonymous-sessions"],
"show",
{
filter: {
"anonymous-session-id": context.anonymous_session_id,
},
}
);
await Promise.all(
anonymous_session_sealious_response.items.map((session: Item) =>
- this.app.run_action(
+ this.app.runAction(
new SuperContext(),
["collections", "anonymous-sessions", session.id],
"delete"
)
)
);
return "You've been logged out";
} catch (e) {
return Promise.reject(new Errors.BadContext("Invalid session id!"));
}
}
getName() {
return "CurrentSession";
}
}
diff --git a/src/subject/subject-types/image-format/image-format.test.ts b/src/subject/subject-types/image-format/image-format.test.ts
index ce97837e..c0946f35 100644
--- a/src/subject/subject-types/image-format/image-format.test.ts
+++ b/src/subject/subject-types/image-format/image-format.test.ts
@@ -1,77 +1,77 @@
import { App, Collection } from "../../../main";
-import { with_running_app } from "../../../test_utils/with-test-app";
-import { assert_throws_async } from "../../../test_utils";
+import { withRunningApp } from "../../../test_utils/with-test-app";
+import { assertThrowsAsync } from "../../../test_utils/assert-throws-async";
import { resolve } from "path";
import assert from "assert";
import axios from "axios";
import File from "../../../data-structures/file";
describe("image-format", function () {
async function create_resource(app: App) {
Collection.fromDefinition(app, {
name: "images",
fields: [
{ name: "source", type: "image", required: true },
{ name: "name", type: "text", required: true },
],
});
- await app.run_action(
+ await app.runAction(
new app.Sealious.Context(),
["collections", "images"],
"create",
{
name: "logo",
source: File.fromPath(
app,
resolve(__dirname, "../../../assets/logo.png")
),
}
);
}
it("should return a valid image with a given format when provided", async () => {
- await with_running_app(async ({ app, base_url }) => {
+ await withRunningApp(async ({ app, base_url }) => {
app.ConfigManager.set("image_formats", {
thumbnail: {
size: [200, 200],
},
});
await create_resource(app);
const { data } = await axios.get(
`${base_url}/api/v1/collections/images?format[source]=thumbnail`
);
assert.ok(data.items[0].source);
const resp = await axios.get(base_url + data.items[0].source);
assert.equal(resp.status, 200);
assert.ok(resp.data);
});
});
it("should throw a neat error message when format is not defined", async () => {
- await with_running_app(async ({ app, rest_api }) => {
+ await withRunningApp(async ({ app, rest_api }) => {
await create_resource(app);
const { items } = await rest_api.get(
"/api/v1/collections/images?format[source]=seal"
);
const sample_uri = items[0].source;
- await assert_throws_async(
+ await assertThrowsAsync(
async () => await rest_api.get(sample_uri),
(error) => {
assert.equal(error.response.status, 404);
assert.equal(
error.response.data.message,
"Unknown image format: seal"
);
assert.equal(error.response.data.type, "bad_subject");
}
);
});
});
});
diff --git a/src/subject/subject-types/image-format/image-format.ts b/src/subject/subject-types/image-format/image-format.ts
index e7bf1efb..5cb03b9f 100644
--- a/src/subject/subject-types/image-format/image-format.ts
+++ b/src/subject/subject-types/image-format/image-format.ts
@@ -1,171 +1,171 @@
import sharp from "sharp";
import path from "path";
import { promises as fs } from "fs";
import { NoActionSubject, LeafSubject } from "../../subject";
import * as Errors from "../../../response/errors";
import App from "../../../app/app";
import Context from "../../../context";
import { ShowActionName } from "../../../action";
import File from "../../../data-structures/file";
const QUALITY = 80;
type FormatObject = {
size: number[];
};
function formatHash(format_obj: FormatObject) {
return format_obj.size[0] + ":" + format_obj.size[1] + "(" + QUALITY + ")";
}
function formatFilename(
original_filename: string,
format_name: string
): string {
return (
path.basename(original_filename, path.extname(original_filename)) +
"-" +
format_name +
".jpg"
);
}
class ImageFormatFile extends LeafSubject {
file_id: string;
file_name: string;
format_name: string;
constructor(
app: App,
file_id: string,
file_name: string,
format_name: string
) {
super(app);
this.file_id = file_id;
this.file_name = file_name;
this.format_name = format_name;
}
getFormat() {
const image_formats = this.app.ConfigManager.get("image_formats");
return (
image_formats[this.format_name as keyof typeof image_formats] ||
null
);
}
async performAction(context: Context, action_name: ShowActionName, _: any) {
if (action_name !== "show") {
throw new Errors.DeveloperError(
`Unknown action for '${this.getName()}' subject: '${action_name}'`
);
}
const format_obj = this.getFormat();
if (!format_obj) {
throw new Errors.BadSubjectPath(
"Unknown image format: " + this.format_name
);
}
let formattedVersion = await this.getFormattedVersion(format_obj);
if (!formattedVersion) {
formattedVersion = await this.createFormattedVersion(
this.file_id,
this.format_name
);
}
return formattedVersion;
}
async getFormattedVersion(format_obj: FormatObject): Promise<File> {
const hash = formatHash(format_obj);
const results = await this.app.Datastore.aggregate("formatted-images", [
{
$match: {
original_photo_file: { $eq: this.file_id },
},
},
{
$match: {
$or: [{ "format.original": hash }, { "format.safe": hash }],
},
},
]);
return File.fromID(this.app, results[0].formatted_photo_file);
}
getFormatData(format_name: string) {
const formats = this.app.ConfigManager.get("image_formats");
return formats[format_name as keyof typeof formats];
}
async createFormattedVersion(
file_id: string,
format_name: string
): Promise<File> {
const format_obj: FormatObject = this.getFormatData(format_name);
const original_file = await File.fromID(this.app, file_id);
const file_path = original_file.getDataPath();
const [width, height] = format_obj.size;
const temp_file_name = formatFilename(
original_file.filename,
format_name
);
const temp_file_path = `/tmp/${temp_file_name}`;
await sharp(file_path).resize(width, height).toFile(temp_file_path);
const formatted_file = await File.fromPath(this.app, temp_file_path);
await formatted_file.save();
- await this.app.run_action(
+ await this.app.runAction(
new this.app.Sealious.SuperContext(),
["collections", "formatted-images"],
"create",
{
original_photo_file: original_file.id,
formatted_photo_file: formatted_file.id,
format: formatHash(format_obj),
}
);
await fs.unlink(temp_file_path);
return formatted_file;
}
getName() {
return "SingleFile";
}
}
export class ImageFormat extends NoActionSubject {
file_id: string;
format_name: string;
constructor(app: App, file_id: string, format_name: string) {
super(app);
this.file_id = file_id;
this.format_name = format_name;
}
async getChildSubject(path_element: string) {
const file_name = path_element;
return new ImageFormatFile(
this.app,
this.file_id,
file_name,
this.format_name
);
}
getName() {
return "ImageFormats";
}
}
diff --git a/src/subject/subject-types/image-formats.ts b/src/subject/subject-types/image-formats.ts
index e257f404..95e9d5fb 100644
--- a/src/subject/subject-types/image-formats.ts
+++ b/src/subject/subject-types/image-formats.ts
@@ -1,19 +1,19 @@
import Subject, { NoActionSubject } from "../subject";
-import App from "../../app/app.js";
-import { ImageFormat } from "./image-format/image-format.js";
+import App from "../../app/app";
+import { ImageFormat } from "./image-format/image-format";
export default class ImageFormats extends NoActionSubject {
file_id: string;
constructor(app: App, file_id: string) {
super(app);
this.file_id = file_id;
}
getName() {
return "ImageFormats";
}
async getChildSubject(path_element: string) {
return new ImageFormat(this.app, this.file_id, path_element);
}
}
diff --git a/src/subject/subject-types/single-file-subject.ts b/src/subject/subject-types/single-file-subject.ts
index 488b8070..5cb7eb8d 100644
--- a/src/subject/subject-types/single-file-subject.ts
+++ b/src/subject/subject-types/single-file-subject.ts
@@ -1,44 +1,44 @@
-import App from "../../app/app.js";
+import App from "../../app/app";
import * as Errors from "../../response/errors";
import { NoActionSubject, LeafSubject } from "../subject";
import Context from "../../context";
import { ShowActionName } from "../../action";
-import { File } from "../../main.js";
+import { File } from "../../main";
export default class FileHash extends NoActionSubject {
file_id: string;
constructor(app: App, file_id: string) {
super(app);
this.file_id = file_id;
}
getName() {
return "FileHash";
}
async getChildSubject(path_element: string) {
return new SingleFileSubject(this.app, this.file_id, path_element);
}
}
class SingleFileSubject extends LeafSubject {
file_id: string;
file_name: string;
constructor(app: App, file_id: string, file_name: string) {
super(app);
this.file_id = file_id;
this.file_name = file_name;
}
getName() {
return "SingleFile";
}
async performAction(_: Context, action_name: ShowActionName, __?: any) {
if (action_name !== "show") {
throw new Errors.DeveloperError(
`Unknown action for '${this.name}' subject: '${action_name}'`
);
}
return await File.fromID(this.app, this.file_id);
}
}
diff --git a/src/subject/subject.ts b/src/subject/subject.ts
index 8725af0b..655a68d0 100644
--- a/src/subject/subject.ts
+++ b/src/subject/subject.ts
@@ -1,59 +1,57 @@
-import SubjectPath, {
- SubjectPathEquiv,
-} from "../data-structures/subject-path.js";
-import { ActionName } from "../action.js";
-import Context from "../context.js";
-import App from "../app/app.js";
+import SubjectPath, { SubjectPathEquiv } from "../data-structures/subject-path";
+import { ActionName } from "../action";
+import Context from "../context";
+import App from "../app/app";
import * as Errors from "./../response/errors";
export default abstract class Subject {
name: string;
app: App;
constructor(app: App) {
this.app = app;
}
abstract getName(): string;
abstract async getChildSubject(
path_element: string
): Promise<Subject | null>;
abstract async performAction(
context: Context,
action_name: ActionName,
params: any
): Promise<any>;
async getSubject(
subject_path_equiv: SubjectPathEquiv
): Promise<Subject | null> {
// This is a recursive function. It traverses the subject tree and returns
// the subject referenced by subject_path
const subject_path = new SubjectPath(subject_path_equiv);
const child_subject = await this.getChildSubject(subject_path.head());
if (subject_path.elements.length === 1) {
return child_subject;
} else {
if (child_subject === null) {
return null;
}
return child_subject.getSubject(subject_path.tail());
}
}
}
export abstract class LeafSubject extends Subject {
async getChildSubject() {
return null;
}
}
export abstract class NoActionSubject extends Subject {
async performAction() {
throw new Errors.BadSubjectAction(
"This subject pdoes not provide any actions."
);
}
}
diff --git a/src/test_utils/access-strategy-types/create_strategies_with_complex_pipeline.ts b/src/test_utils/access-strategy-types/create-strategies-with-complex-pipeline.ts
similarity index 96%
rename from src/test_utils/access-strategy-types/create_strategies_with_complex_pipeline.ts
rename to src/test_utils/access-strategy-types/create-strategies-with-complex-pipeline.ts
index 4a55b60b..fc2e6cc8 100644
--- a/src/test_utils/access-strategy-types/create_strategies_with_complex_pipeline.ts
+++ b/src/test_utils/access-strategy-types/create-strategies-with-complex-pipeline.ts
@@ -1,40 +1,40 @@
import { App, AccessStrategy, Query } from "../../main";
export default {
- allow_deny: function(app: App) {
+ allowDeny: function (app: App) {
const access_strategies = [
"complex-deny-pipeline",
"complex-allow-pipeline",
];
for (const strategy_name of access_strategies) {
app.ChipManager.addChip(
"access_strategy_type",
strategy_name,
class extends AccessStrategy {
async getRestrictingQuery() {
const query = new Query();
const id = query.lookup({
from: "numbers",
localField: "number",
foreignField: "sealious_id",
});
query.match({
[`${id}._id`]: {
$exists:
strategy_name === "complex-allow-pipeline",
},
});
return query;
}
async checkerFunction() {
return AccessStrategy.allow(
"I don't care about individual items, my goal is to test the filtering pipelines"
);
}
item_sensitive: true;
}
);
}
},
};
diff --git a/src/test_utils/assert_throws_async.ts b/src/test_utils/assert-throws-async.ts
similarity index 85%
rename from src/test_utils/assert_throws_async.ts
rename to src/test_utils/assert-throws-async.ts
index c0efa80e..f5539245 100644
--- a/src/test_utils/assert_throws_async.ts
+++ b/src/test_utils/assert-throws-async.ts
@@ -1,16 +1,16 @@
import assert from "assert";
-export default async function assertThrowsAsync(
+export async function assertThrowsAsync(
fn: () => Promise<any>,
error_handler: (e: any) => Promise<any> | any
) {
let error = null;
try {
await fn();
} catch (e) {
error = e;
} finally {
assert.notStrictEqual(error, null, "It didn't throw");
await error_handler(error as any);
}
}
diff --git a/src/test_utils/index.js b/src/test_utils/index.js
deleted file mode 100644
index bca79957..00000000
--- a/src/test_utils/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default as assert_throws_async } from "./assert_throws_async.js";
diff --git a/src/test_utils/with-test-app.ts b/src/test_utils/with-test-app.ts
index 0f017190..afc9f82b 100644
--- a/src/test_utils/with-test-app.ts
+++ b/src/test_utils/with-test-app.ts
@@ -1,225 +1,225 @@
import { App, ActionName } from "../main";
// @ts-ignore
const locreq = require("locreq")(__dirname);
import axios from "axios";
import tough from "tough-cookie";
import { Environment } from "../app/config";
import SealiousResponse from "../../common_lib/response/sealious-response";
import { EventMatcher } from "../app/event-matchers";
import {
CollectionResponse,
SingleItemResponse,
} from "../../common_lib/response/responses";
type TestCallback = (params: CallbackParams) => Promise<any>;
-export async function with_stopped_app(cb: TestCallback): Promise<any> {
- with_test_app("auto_start" && false, "dev", cb);
+export async function withStoppedApp(cb: TestCallback): Promise<any> {
+ withTestApp("auto_start" && false, "dev", cb);
}
-export async function with_running_app(cb: TestCallback): Promise<any> {
- with_test_app("auto_start" && true, "dev", cb);
+export async function withRunningApp(cb: TestCallback): Promise<any> {
+ withTestApp("auto_start" && true, "dev", cb);
}
-export async function with_running_app_prod(cb: TestCallback): Promise<any> {
- with_test_app("auto_start" && true, "production", cb);
+export async function withRunningAppProd(cb: TestCallback): Promise<any> {
+ withTestApp("auto_start" && true, "production", cb);
}
-export async function with_stopped_app_prod(cb: TestCallback) {
- with_test_app.bind("auto_start" && false, "production", cb);
+export async function withStoppedAppProd(cb: TestCallback) {
+ withTestApp.bind("auto_start" && false, "production", cb);
}
export type MockRestApi = {
get: Function;
getSealiousResponse: (
url: string,
body?: { [field: string]: any }
) => Promise<SealiousResponse>;
delete: Function;
patch: Function;
post: Function;
login: Function;
};
type CallbackParams = {
app: App;
base_url: string;
smtp_api_url: string;
rest_api: MockRestApi;
mail_api: {
- get_messages: () => Promise<
+ getMessages: () => Promise<
{
recipients: string[];
subject: string;
id: number;
sender: string;
}[]
>;
- get_message_by_id: (id: number) => Promise<string>;
+ getMessageById: (id: number) => Promise<string>;
};
- dont_clear_database_on_stop: () => void;
+ dontClearDatabaseOnStop: () => void;
};
-async function with_test_app(
+async function withTestApp(
auto_start: boolean,
env: Environment,
fn: (params: CallbackParams) => Promise<any>
) {
const port = 8888;
const base_url = `http://localhost:${port}`;
const smtp_api_url = "http://mailcatcher:1080";
const app = new App(
{
upload_path: "/tmp",
datastore_mongo: { host: "db", password: "sealious-test" },
smtp: {
host: "mailcatcher",
port: 1025,
user: "any",
password: "any",
},
email: {
from_name: "Sealious test app",
from_address: "sealious@example.com",
},
core: { environment: env },
app: { version: "0.0.0-test" },
logger: { level: "emerg" },
"www-server": {
port,
},
password_hash: {
iterations: 1,
},
},
{
name: "testing app",
logo: locreq.resolve("lib/assets/logo.png"),
default_language: "pl",
version: "0.0.0-test",
base_url,
colors: {
primary: "#4d394b",
},
admin_email: "admin@example.com",
}
);
const possible_actions: ActionName[] = ["create", "show", "edit", "delete"];
const debug_matcher = (when: "before" | "after") =>
new EventMatcher({
when: when,
action: possible_actions,
subject_path: /.*/,
});
app.addHook(debug_matcher("after"), async () =>
app.Logger.debug(arguments)
);
app.addHook(debug_matcher("before"), async () =>
app.Logger.debug(arguments)
);
let clear_database_on_stop = true;
app.on("stopping", async () => {
if (clear_database_on_stop) {
for (const collection_name of app.ChipManager.getAllCollections()) {
await app.Datastore.remove(
collection_name,
{},
"just_one" && false
);
}
await app.Datastore.remove(
app.Metadata.db_collection_name,
{},
"just_one" && false
);
}
});
if (auto_start) {
await app.start();
}
try {
await axios.delete(`${smtp_api_url}/messages`);
await fn({
app,
base_url,
smtp_api_url,
mail_api: {
- get_messages: async () =>
+ getMessages: async () =>
(await axios.get(`${smtp_api_url}/messages`)).data,
- get_message_by_id: async (id: number) =>
+ getMessageById: async (id: number) =>
(await axios.get(`${smtp_api_url}/messages/${id}.html`))
.data as string,
},
- dont_clear_database_on_stop: () => (clear_database_on_stop = false),
+ dontClearDatabaseOnStop: () => (clear_database_on_stop = false),
rest_api: {
get: async (
url: string,
options: Parameters<typeof axios.get>[1]
) => (await axios.get(`${base_url}${url}`, options)).data,
getSealiousResponse: async (url, options) => {
const resp = (await axios.get(`${base_url}${url}`, options))
.data;
return resp.items
? new CollectionResponse(resp)
: new SingleItemResponse(resp);
},
delete: async (
url: string,
options: Parameters<typeof axios.delete>[1]
) => (await axios.delete(`${base_url}${url}`, options)).data,
patch: async (
url: string,
data: any,
options: Parameters<typeof axios.patch>[1]
) =>
(await axios.patch(`${base_url}${url}`, data, options))
.data,
post: async (
url: string,
data: any,
options: Parameters<typeof axios.post>[2]
) =>
(await axios.post(`${base_url}${url}`, data, options)).data,
login: async ({
username,
password,
}: {
username: string;
password: string;
}) => {
const cookie_jar = new tough.CookieJar();
const options = {
jar: cookie_jar,
withCredentials: true,
};
await axios.post(
`${base_url}/api/v1/sessions`,
{
username,
password,
},
options
);
return options;
},
},
});
} catch (e) {
throw e;
} finally {
if (app.status !== "stopped") {
await app.stop();
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Dec 24, 14:02 (17 h, 50 m)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
e0/0d/aca83e3768f5acacc3d3a8602052
Default Alt Text
(599 KB)

Event Timeline