From 19df37e6a201f175ebaa6394047c70afc1731310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Bajto=C5=A1?= Date: Mon, 9 Sep 2019 11:45:49 +0200 Subject: [PATCH] feat(cli): add new command `import-lb3-model` (EXPERIMENTAL) --- docs/site/Importing-LB3-models.md | 113 ++ docs/site/sidebars/lb4_sidebar.yml | 4 + docs/site/tables/lb4-artifact-commands.html | 7 +- .../cli/generators/import-lb3-models/index.js | 162 ++ .../import-lb3-models/lb3app-loader.js | 31 + .../import-lb3-models/migrate-model.js | 206 +++ .../import-lb3-models/model-names.js | 32 + packages/cli/lib/cli.js | 4 + packages/cli/lib/utils.js | 1 + packages/cli/package-lock.json | 1327 +++++++++++++++-- packages/cli/package.json | 2 + .../cli/cli.integration.snapshots.js | 2 + ...import-lb3-models.integration.snapshots.js | 64 + .../import-lb3-models.integration.js | 94 ++ .../import-lb3-model/migrate-model.test.js | 377 +++++ .../unit/import-lb3-model/model-names.test.js | 53 + 16 files changed, 2355 insertions(+), 124 deletions(-) create mode 100644 docs/site/Importing-LB3-models.md create mode 100644 packages/cli/generators/import-lb3-models/index.js create mode 100644 packages/cli/generators/import-lb3-models/lb3app-loader.js create mode 100644 packages/cli/generators/import-lb3-models/migrate-model.js create mode 100644 packages/cli/generators/import-lb3-models/model-names.js create mode 100644 packages/cli/snapshots/integration/generators/import-lb3-models.integration.snapshots.js create mode 100644 packages/cli/test/integration/generators/import-lb3-models.integration.js create mode 100644 packages/cli/test/unit/import-lb3-model/migrate-model.test.js create mode 100644 packages/cli/test/unit/import-lb3-model/model-names.test.js diff --git a/docs/site/Importing-LB3-models.md b/docs/site/Importing-LB3-models.md new file mode 100644 index 000000000000..4f1756ddc756 --- /dev/null +++ b/docs/site/Importing-LB3-models.md @@ -0,0 +1,113 @@ +--- +lang: en +title: 'Importing models from LoopBack 3 projects' +keywords: LoopBack 4.0, Migration +sidebar: lb4_sidebar +permalink: /doc/en/lb4/Importing-LB3-models.html +--- + +## Synopsis + +To simplify migration from LoopBack 3, LoopBack 4 provides a CLI tool to import +LoopBack 3 models into your LoopBack 4 project. + +{% include warning.html content=" +This command is experimental and not feature-complete yet. +See the list of known limitations below. +" %} + +## Overview + +Import one or more models from your LB 3.x application by running +`lb4 import-lb3-models` command. + +### Arguments + +`lb3app`: Path to the directory containing your LoopBack 3.x application. + +{% include important.html content=" +The generator loads the application via `require()`, it does not +support applications that are unable to boot (throw errors at startup). +" %} + +### Options + +`outDir`: Directory where to write the generated source file. Default: +`src/models` + +## Known limitations + +{% include note.html content=" +Please up-vote the tracking GitHub issue for scenarios that are important to +your project. It will help us to better prioritize which limitations to remove +first. +" %} + +### Connector-specific metadata in property definitions is not imported + +_The tracking GitHub issue: +[loopback-next#3810](https://github.com/strongloop/loopback-next/issues/3810)_ + +Workaround: Add this metadata manually to the generated file. + +### Nested properties are not upgraded + +_The tracking GitHub issue: +[loopback-next#3811](https://github.com/strongloop/loopback-next/issues/3811)_ + +When a property is defined with a complex object type, the nested property +definitions are not converted from LB3 to LB4 format. + +Workaround: Fix the generated definition manually. + +### Model relations are not imported + +_The tracking GitHub issue: +[loopback-next#3812](https://github.com/strongloop/loopback-next/issues/3812)_ + +Workaround: define relational metadata & navigational properties manually. + +### Models inheriting from custom base class + +_The tracking GitHub issue: +[loopback-next#3813](https://github.com/strongloop/loopback-next/issues/3813)_ + +Models inheriting from application-specific models (including LB3 built-in +models like `User`) cannot be imported yet. + +Workaround: + +1. Modify your LB3 model to inherit from `Model`, `PersistedModel` or + `KeyValueModel`. + +2. Import the model to LB4 + +3. Update the imported model to inherit for the desired application-specific + model. + +### MongoDB's `ObjectID` type + +The tracking GitHub issue: +[loopback-next#3814](https://github.com/strongloop/loopback-next/issues/3814). + +For models attached to MongoDB datasource, the imported LB4 model contains +incorrect definition of the primary key property of `ObjectID` type. + +As a workaround, you can change the property definition from: + +```ts +@property({ + type: ObjectID; +}) +id: ObjectID; +``` + +to: + +```ts +@property({ + type: 'string', + mongodb: {dataType: 'ObjectID'} +}) +id: string; +``` diff --git a/docs/site/sidebars/lb4_sidebar.yml b/docs/site/sidebars/lb4_sidebar.yml index 171ecbdc85e7..f9d672fda331 100644 --- a/docs/site/sidebars/lb4_sidebar.yml +++ b/docs/site/sidebars/lb4_sidebar.yml @@ -384,6 +384,10 @@ children: url: DataSource-generator.html output: 'web, pdf' + - title: 'Import models from LoopBack 3' + url: Importing-LB3-models.html + output: 'web, pdf' + - title: 'Model generator' url: Model-generator.html output: 'web, pdf' diff --git a/docs/site/tables/lb4-artifact-commands.html b/docs/site/tables/lb4-artifact-commands.html index 983021640f4f..1f77827137fa 100644 --- a/docs/site/tables/lb4-artifact-commands.html +++ b/docs/site/tables/lb4-artifact-commands.html @@ -23,6 +23,11 @@ DataSource generator + + lb4 import-lb3-models + Import one or more LoopBack 3 models to a LoopBack 4 application + Importer for LoopBack 3 models + lb4 model Add a new model to a LoopBack 4 application @@ -70,7 +75,5 @@ Generate interceptors Global interceptor generator - - diff --git a/packages/cli/generators/import-lb3-models/index.js b/packages/cli/generators/import-lb3-models/index.js new file mode 100644 index 000000000000..d05e8cb355f9 --- /dev/null +++ b/packages/cli/generators/import-lb3-models/index.js @@ -0,0 +1,162 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const chalk = require('chalk'); +const path = require('path'); +const BaseGenerator = require('../../lib/base-generator'); +const modelUtils = require('../../lib/model-discoverer'); +const debug = require('../../lib/debug')('import-lb3-models'); +const utils = require('../../lib/utils'); +const {loadLb3App} = require('./lb3app-loader'); +const {importLb3ModelDefinition} = require('./migrate-model'); +const {canImportModelName} = require('./model-names'); + +module.exports = class Lb3ModelImporter extends BaseGenerator { + constructor(args, opts) { + super(args, opts); + + this.argument('lb3app', { + type: String, + required: true, + description: + 'Path to your LoopBack 3.x application. ' + + 'This can be a project directory (e.g. "my-lb3-app") or ' + + 'the server file (e.g. "my-lb3-app/server/server.js").', + }); + + this.option('outDir', { + type: String, + description: 'Directory where to write the generated source file', + default: 'src/models', + }); + } + + async processOptions() { + this.sourceAppDir = this.args[0]; + this.artifactInfo.outDir = this.options.outDir; + this.artifactInfo.relPath = path.relative( + this.destinationPath(), + this.artifactInfo.outDir, + ); + return super.setOptions(); + } + + async logExperimentalStatus() { + this.log( + chalk.red(` +WARNING: This command is experimental and not feature-complete yet. +Learn more at https://loopback.io/doc/en/lb4/Importing-LB3-models.html +`), + ); + } + + /** + * Ensure CLI is being run in a LoopBack 4 project. + */ + checkLoopBackProject() { + if (this.shouldExit()) return; + return super.checkLoopBackProject(); + } + + async loadTheApp() { + this.lb3app = await loadLb3App(this.sourceAppDir); + this.modelRegistry = this.lb3app.registry.modelBuilder.models; + } + + async promptModels() { + const modelNames = Object.keys(this.modelRegistry).filter( + canImportModelName, + ); + + debug('Available LB3 models', modelNames); + + const prompts = [ + { + name: 'modelNames', + message: 'Select models to import:', + type: 'checkbox', + choices: modelNames, + validate: result => !!result.length, + // TODO: add a CLI flag to supply these names programmatically + }, + ]; + + const answers = await this.prompt(prompts); + debug('Models chosen:', answers.modelNames); + this.modelNames = answers.modelNames; + } + + async migrateSelectedModels() { + if (this.shouldExit()) return; + this.modelFiles = []; + + try { + for (const name of this.modelNames) { + await this._migrateSingleModel(name); + } + } catch (err) { + if (err.exit) { + this.exit(err.message); + } else { + throw err; + } + } + } + + async _migrateSingleModel(name) { + utils.logClassCreation('model', 'models', name, this.log.bind(this)); + const modelCtor = this.modelRegistry[name]; + if (typeof modelCtor !== 'function') { + const availableModels = Object.keys(this.modelRegistry) + .filter(canImportModelName) + .join(', '); + + this.exit( + `Unknown model name ${name}. Available models: ${availableModels}.`, + ); + return; + } + + const templateData = importLb3ModelDefinition( + modelCtor, + this.log.bind(this), + ); + debug('LB4 model data', templateData); + + const fileName = utils.getModelFileName(name); + const fullTargetPath = path.resolve(this.artifactInfo.relPath, fileName); + debug('Model %s output file', name, fullTargetPath); + + this.copyTemplatedFiles( + modelUtils.MODEL_TEMPLATE_PATH, + fullTargetPath, + templateData, + ); + + this.modelFiles.push(fileName); + } + + /** + * Iterate through all the models we have discovered and scaffold + */ + async scaffold() { + if (this.shouldExit()) return; + } + + async end() { + if (this.shouldExit() || !this._isGenerationSuccessful()) { + await super.end(); + return; + } + + for (const f of this.modelFiles) { + await this._updateIndexFile(this.artifactInfo.outDir, f); + } + + await super.end(); + } +}; diff --git a/packages/cli/generators/import-lb3-models/lb3app-loader.js b/packages/cli/generators/import-lb3-models/lb3app-loader.js new file mode 100644 index 000000000000..49e829770523 --- /dev/null +++ b/packages/cli/generators/import-lb3-models/lb3app-loader.js @@ -0,0 +1,31 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const debug = require('../../lib/debug')('import-lb3-models'); +const path = require('path'); +const pEvent = require('p-event'); + +module.exports = { + loadLb3App, +}; + +// TODO: do we want to share this code with `Lb3AppBooter.loadAndBootTheApp`? +async function loadLb3App(dir) { + debug('Loading LB3 app from', dir); + const lb3App = require(path.resolve(dir)); + + debug( + 'If your LB3 app does not boot correctly then make sure it is using loopback-boot version 3.2.1 or higher.', + ); + + if (lb3App.booting) { + debug(' waiting for boot process to finish'); + // Wait until the legacy LB3 app boots + await pEvent(lb3App, 'booted'); + } + return lb3App; +} diff --git a/packages/cli/generators/import-lb3-models/migrate-model.js b/packages/cli/generators/import-lb3-models/migrate-model.js new file mode 100644 index 000000000000..a3c9070a006c --- /dev/null +++ b/packages/cli/generators/import-lb3-models/migrate-model.js @@ -0,0 +1,206 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const { + validateClassName, + logNamingIssues, + pascalCase, + stringifyModelSettings, +} = require('../../lib/utils'); +const {sanitizeProperty} = require('../../lib/model-discoverer'); +const { + createPropertyTemplateData, + BUILTIN_TYPES, +} = require('../model/property-definition'); +const chalk = require('chalk'); + +module.exports = { + importLb3ModelDefinition, +}; + +/** + * Convert definition of a LB3 model into template data used by + * LB4 model generator. + * + * @param {Function} modelCtor LB3 model class + * @param {(msg: string, ...args: any) => void} log Logging function + * @returns {object} Template data for model source file template + */ +function importLb3ModelDefinition(modelCtor, log) { + const modelName = modelCtor.modelName; + const result = validateClassName(modelName); + if (!result) { + const err = new Error( + `Cannot import model: the name ${modelName} is not valid. ${result}`, + ); + err.exit = true; + throw err; + } + + logNamingIssues(modelName, log); + + const templateData = { + name: modelName, + className: pascalCase(modelName), + ...migrateBaseClass(modelCtor.settings.base), + properties: migrateModelProperties(modelCtor.definition.properties), + settings: migrateModelSettings(modelCtor.definition.settings, log), + }; + + const settings = templateData.settings; + delete settings.base; // already handled by migrateBaseClass + templateData.allowAdditionalProperties = !settings.strict; + templateData.modelSettings = stringifyModelSettings(settings); + + return templateData; +} + +function migrateModelProperties(properties) { + const templateData = {}; + + // In LB 3.x, primary keys are typically contributed by connectors later in + // the startup process, therefore they end up at the end of the property list. + // Here we create placeholder entries for PKs to get them generated first. + Object.keys(properties) + .filter(p => !!properties[p].id) + .forEach(pk => { + templateData[pk] = null; + }); + + for (const prop in properties) { + const def = migratePropertyDefinition(properties[prop]); + templateData[prop] = createPropertyTemplateData(def); + } + + return templateData; +} + +function migratePropertyDefinition(lb3PropDef) { + const def = {...lb3PropDef}; + + if (!Array.isArray(def.type)) { + // scalar type + def.type = migratePropertyType(def.type); + } else { + // array type - conversion is slightly more complex + def.itemType = migratePropertyType(def.type[0]); + def.type = 'array'; + + // workaround for a weird behavior of LB3 + if (0 in def && def[0] === def.itemType) { + delete def[0]; + } + } + + if (def.updateOnly === false) { + // updateOnly is disabled by default, no need to specify "false" value + delete def.updateOnly; + } + sanitizeProperty(def); + return def; +} + +function migratePropertyType(typeDef) { + if (typeof typeDef === 'function') { + typeDef = typeDef.name.toString(); + } + + const builtin = BUILTIN_TYPES.find(t => t === typeDef.toLowerCase()); + if (builtin) typeDef = builtin; + + // TODO: handle anonymous object types (nested properties) + + return typeDef; +} + +const BUILTIN_BASE_MODELS = { + Model: 'Model', + PersistedModel: 'Entity', + KeyValueModel: 'KeyValueModel', +}; + +function migrateBaseClass(base) { + const baseModelName = base.modelName || base.name || base; + if (baseModelName in BUILTIN_BASE_MODELS) { + return { + modelBaseClass: BUILTIN_BASE_MODELS[baseModelName], + isModelBaseBuiltin: true, + }; + } + + // TODO: handle inheritance from application models + throw new Error( + 'Models inheriting from app-specific models cannot be migrated yet. ' + + `Base model configured: ${baseModelName}`, + ); +} + +function migrateModelSettings(settings = {}, log) { + // Shallow-clone the object to prevent modification of external data + settings = {...settings}; + + // "strict" mode is enabled only when explicitly requested + // LB3 models allow additional properties by default + settings.strict = settings.strict === true; + + if (settings.forceId === 'auto') { + // The value 'auto' is used when a parent model wants to let the child + // model make the decision automatically, depending on whether the child + // model has a database-generated PK. + // See https://github.com/strongloop/loopback-datasource-juggler/blob/15251880a1d07ccc2ca6d2dccdd065d00a7375eb/lib/model-builder.js#L347-L355 + // + // Let's delete the flag from the generated model settings and + // leave it up to the runtime to decide. + delete settings.forceId; + } + + // Notable settings that are not supported yet: + // relations, acls, methods, mixins, validations + + const relationNames = Object.keys(settings.relations || {}); + if (relationNames.length) { + log( + chalk.yellow( + 'Import of model relations is not supported yet. ' + + 'Skipping the following relations: ' + + relationNames.join(', '), + ), + ); + } + delete settings.relations; + + const unsupportedSettings = []; + if ((settings.acls || []).length) { + unsupportedSettings.push('acls'); + } + delete settings.acls; + + for (const k of ['methods', 'mixins', 'validations']) { + if (k in settings && Object.keys(settings[k]).length) { + unsupportedSettings.push(k); + } + delete settings[k]; + } + + if (unsupportedSettings.length) { + log( + chalk.yellow( + 'Ignoring the following unsupported settings: ' + + unsupportedSettings.join(', '), + ), + ); + } + + if ( + typeof settings.hiddenProperties === 'object' && + Object.keys(settings.hiddenProperties).length === 0 + ) { + delete settings.hiddenProperties; + } + + return settings; +} diff --git a/packages/cli/generators/import-lb3-models/model-names.js b/packages/cli/generators/import-lb3-models/model-names.js new file mode 100644 index 000000000000..e7f2a6fea971 --- /dev/null +++ b/packages/cli/generators/import-lb3-models/model-names.js @@ -0,0 +1,32 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +module.exports = { + canImportModelName, +}; + +// List of built-in LB models to exclude from the prompt +const EXCLUDED_MODEL_NAMES = [ + // base models + 'Model', + 'PersistedModel', + 'KeyValueModel', + // change tracking & replication + 'Change', + 'Checkpoint', + // Email - a dummy model used to attach email-connector methods only + 'Email', +]; + +function canImportModelName(name) { + if (EXCLUDED_MODEL_NAMES.includes(name)) return false; + // TODO: find out where are anonymous models coming from + // (perhaps from object types defined inside property definitions?) + // and add test cases to verify that we are handling those scenarios correctly + if (name.startsWith('AnonymousModel_')) return false; + return true; +} diff --git a/packages/cli/lib/cli.js b/packages/cli/lib/cli.js index 829b59707b61..d6fb1063add8 100644 --- a/packages/cli/lib/cli.js +++ b/packages/cli/lib/cli.js @@ -62,6 +62,10 @@ function setupGenerators() { path.join(__dirname, '../generators/datasource'), PREFIX + 'datasource', ); + env.register( + path.join(__dirname, '../generators/import-lb3-models'), + PREFIX + 'import-lb3-models', + ); env.register(path.join(__dirname, '../generators/model'), PREFIX + 'model'); env.register( path.join(__dirname, '../generators/repository'), diff --git a/packages/cli/lib/utils.js b/packages/cli/lib/utils.js index 9cdf1403228f..998f3de6dc28 100644 --- a/packages/cli/lib/utils.js +++ b/packages/cli/lib/utils.js @@ -564,6 +564,7 @@ exports.dataSourceToJSONFileName = function(dataSourceClass) { }; exports.stringifyModelSettings = function(modelSettings) { + if (!modelSettings || !Object.keys(modelSettings).length) return ''; return stringifyObject( {settings: modelSettings}, { diff --git a/packages/cli/package-lock.json b/packages/cli/package-lock.json index f7e2a03cf262..2d073e0f418e 100644 --- a/packages/cli/package-lock.json +++ b/packages/cli/package-lock.json @@ -128,6 +128,23 @@ "defer-to-connect": "^1.0.1" } }, + "@types/body-parser": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.17.1.tgz", + "integrity": "sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.32", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.32.tgz", + "integrity": "sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg==", + "requires": { + "@types/node": "*" + } + }, "@types/ejs": { "version": "2.6.3", "resolved": "https://registry.npmjs.org/@types/ejs/-/ejs-2.6.3.tgz", @@ -139,6 +156,25 @@ "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==" }, + "@types/express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.1.tgz", + "integrity": "sha512-VfH/XCP0QbQk5B5puLqTLEeFgR8lfCJHZJKkInZ9mkYd+u8byX0kztXEQxEk4wZXJs8HI+7km2ALXjn4YKcX9w==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.16.9", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.16.9.tgz", + "integrity": "sha512-GqpaVWR0DM8FnRUJYKlWgyARoBUAVfRIeVDZQKOttLFp5SmhhF9YFIYeTPwMd/AXfxlP7xVO2dj1fGu0Q+krKQ==", + "requires": { + "@types/node": "*", + "@types/range-parser": "*" + } + }, "@types/glob": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", @@ -156,6 +192,11 @@ } } }, + "@types/mime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.1.tgz", + "integrity": "sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw==" + }, "@types/minimatch": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", @@ -172,6 +213,20 @@ "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz", "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==" }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" + }, + "@types/serve-static": { + "version": "1.13.3", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.3.tgz", + "integrity": "sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/mime": "*" + } + }, "JSONStream": { "version": "1.3.5", "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", @@ -185,12 +240,20 @@ "version": "3.0.18", "resolved": "https://registry.npmjs.org/accept-language/-/accept-language-3.0.18.tgz", "integrity": "sha1-9QJfF79lpGaoRYOMz5jNuHfYM4Q=", - "dev": true, "requires": { "bcp47": "^1.1.2", "stable": "^0.1.6" } }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, "agent-base": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", @@ -302,6 +365,11 @@ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==" }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, "array-from": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", @@ -332,7 +400,6 @@ "version": "0.2.4", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, "requires": { "safer-buffer": "~2.1.0" } @@ -340,8 +407,7 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" }, "assign-symbols": { "version": "1.0.0", @@ -359,8 +425,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "atob": { "version": "2.1.2", @@ -370,14 +435,12 @@ "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=", - "dev": true + "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==", - "dev": true + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" }, "balanced-match": { "version": "1.0.0", @@ -434,21 +497,29 @@ } } }, + "base64-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.0.2.tgz", + "integrity": "sha1-R0IRyV5s8qVH20YeT2d4tR0I+mU=" + }, "bcp47": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/bcp47/-/bcp47-1.1.2.tgz", - "integrity": "sha1-NUvjMH/9CEM6ePXh4glYRfifx/4=", - "dev": true + "integrity": "sha1-NUvjMH/9CEM6ePXh4glYRfifx/4=" }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, "requires": { "tweetnacl": "^0.14.3" } }, + "bcryptjs": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", + "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms=" + }, "better-ajv-errors": { "version": "0.6.7", "resolved": "https://registry.npmjs.org/better-ajv-errors/-/better-ajv-errors-0.6.7.tgz", @@ -472,7 +543,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.0.tgz", "integrity": "sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA==", - "dev": true, "requires": { "readable-stream": "^2.3.5", "safe-buffer": "^5.1.1" @@ -483,6 +553,57 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz", "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==" }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + } + } + }, + "bops": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bops/-/bops-1.0.0.tgz", + "integrity": "sha1-YxqJKPEXhBfrb3Bs9prNteWk6q0=", + "requires": { + "base64-js": "1.0.2", + "to-utf8": "0.0.1" + } + }, "boxen": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/boxen/-/boxen-3.2.0.tgz", @@ -574,6 +695,11 @@ "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", "integrity": "sha1-y5T662HIaWRR2zZTThQi+U8K7og=" }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, "cacache": { "version": "12.0.3", "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", @@ -685,6 +811,11 @@ "quick-lru": "^4.0.1" } }, + "canonical-json": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/canonical-json/-/canonical-json-0.0.4.tgz", + "integrity": "sha1-ZXnAcsPbXEd+xB3JePvyuPQQdKM=" + }, "capture-stack-trace": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", @@ -693,8 +824,7 @@ "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" }, "chalk": { "version": "2.4.2", @@ -739,8 +869,7 @@ "charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", - "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=", - "dev": true + "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" }, "chownr": { "version": "1.1.2", @@ -776,8 +905,7 @@ "cldrjs": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/cldrjs/-/cldrjs-0.5.1.tgz", - "integrity": "sha512-xyiP8uAm8K1IhmpDndZLraloW1yqu0L+HYdQ7O1aGPxx9Cr+BMnPANlNhSt++UKfxytL2hd2NPXgTjiy7k43Ew==", - "dev": true + "integrity": "sha512-xyiP8uAm8K1IhmpDndZLraloW1yqu0L+HYdQ7O1aGPxx9Cr+BMnPANlNhSt++UKfxytL2hd2NPXgTjiy7k43Ew==" }, "cli-boxes": { "version": "2.2.0", @@ -928,7 +1056,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -936,8 +1063,7 @@ "commander": { "version": "2.20.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "optional": true + "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==" }, "commondir": { "version": "1.0.1", @@ -999,6 +1125,36 @@ "upper-case": "^1.1.1" } }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.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==" + } + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, "copy-concurrently": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", @@ -1067,8 +1223,7 @@ "crypt": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz", - "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=", - "dev": true + "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=" }, "crypto-random-string": { "version": "1.0.0", @@ -1089,7 +1244,6 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -1135,6 +1289,14 @@ "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.0.2.tgz", "integrity": "sha512-k09hcQcTDY+cwgiwa6PYKLm3jlagNzQ+RSvhjzESOGOx+MNOuXkxTfEvPrO1IOQ81tArCFYQgi631clB70RpQw==" }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "requires": { + "object-keys": "^1.0.12" + } + }, "define-property": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", @@ -1175,8 +1337,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "depd": { "version": "2.0.0", @@ -1184,6 +1345,11 @@ "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, "detect-conflict": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.1.tgz", @@ -1218,6 +1384,16 @@ "is-obj": "^1.0.0" } }, + "duplex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/duplex/-/duplex-1.0.0.tgz", + "integrity": "sha1-arxcFuwX5MV4V4cnEmcAWQ06Ldo=" + }, + "duplexer": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.0.4.tgz", + "integrity": "sha1-r8t/H4uNdPggcmFx1dZKyeSo/yA=" + }, "duplexer3": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", @@ -1238,7 +1414,6 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -1253,6 +1428,11 @@ "semver": "^6.3.0" } }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, "ejs": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.1.tgz", @@ -1263,6 +1443,11 @@ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, "encoding": { "version": "0.1.12", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", @@ -1308,6 +1493,33 @@ "is-arrayish": "^0.2.1" } }, + "es-abstract": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", + "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.0.0", + "string.prototype.trimright": "^2.0.0" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "es6-promise": { "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", @@ -1321,6 +1533,11 @@ "es6-promise": "^4.0.3" } }, + "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", @@ -1349,6 +1566,16 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "eventemitter2": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-5.0.1.tgz", + "integrity": "sha1-YZegldX7a1folC9v1+qtY6CclFI=" + }, "execa": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", @@ -1408,11 +1635,82 @@ } } }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "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==" + } + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" }, "extend-shallow": { "version": "3.0.2", @@ -1505,8 +1803,12 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A=" }, "fast-deep-equal": { "version": "1.1.0", @@ -1560,6 +1862,35 @@ "to-regex-range": "^5.0.1" } }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "find-up": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", @@ -1593,20 +1924,23 @@ "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true + "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==", - "dev": true, "requires": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", "mime-types": "^2.1.12" } }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, "fragment-cache": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", @@ -1615,6 +1949,11 @@ "map-cache": "^0.2.2" } }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, "from2": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", @@ -1658,6 +1997,11 @@ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, "genfun": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/genfun/-/genfun-5.0.0.tgz", @@ -1690,7 +2034,6 @@ "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, "requires": { "assert-plus": "^1.0.0" } @@ -1788,7 +2131,6 @@ "version": "1.4.2", "resolved": "https://registry.npmjs.org/globalize/-/globalize-1.4.2.tgz", "integrity": "sha512-IfKeYI5mAITBmT5EnH8kSQB5uGson4Fkj2XtTpyEbIS7IHNfLHoeTyLJ6tfjiKC6cJXng3IhVurDk5C7ORqFhQ==", - "dev": true, "requires": { "cldrjs": "^0.5.0" } @@ -1847,14 +2189,12 @@ "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" }, "har-validator": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, "requires": { "ajv": "^6.5.5", "har-schema": "^2.0.0" @@ -1864,7 +2204,6 @@ "version": "6.10.2", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "dev": true, "requires": { "fast-deep-equal": "^2.0.1", "fast-json-stable-stringify": "^2.0.0", @@ -1875,17 +2214,23 @@ "fast-deep-equal": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" }, "json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" } } }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", @@ -1897,6 +2242,11 @@ "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", "dev": true }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=" + }, "has-to-string-tag-x": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", @@ -1977,6 +2327,30 @@ "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==" }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "dependencies": { + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + } + } + }, "http-proxy-agent": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", @@ -2005,18 +2379,36 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", "sshpk": "^1.7.0" } }, + "http-status": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/http-status/-/http-status-1.3.2.tgz", + "integrity": "sha512-vR1YTaDyi2BukI0UiH01xy92oiZi4in7r0dmSPnrZg72Vu1SzyOLalwWP5NUk1rNiB2L+XVK2lcSVOqaertX8A==" + }, "http2-client": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.3.tgz", "integrity": "sha512-nUxLymWQ9pzkzTmir24p2RtsgruLmhje7lH3hLX1IpwvyTg77fW+1brenPPP3USAR+rQ36p5sTA/x7sjCJVkAA==" }, + "httpntlm": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz", + "integrity": "sha1-rQFScUOi6Hc8+uapb1hla7UqNLI=", + "requires": { + "httpreq": ">=0.4.22", + "underscore": "~1.7.0" + } + }, + "httpreq": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.24.tgz", + "integrity": "sha1-QzX/2CzZaWaKOUZckprGHWOTYn8=" + }, "https-proxy-agent": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.2.tgz", @@ -2088,8 +2480,7 @@ "inflection": { "version": "1.12.0", "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", - "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", - "dev": true + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" }, "inflight": { "version": "1.0.6", @@ -2145,6 +2536,11 @@ "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=" }, + "ipaddr.js": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz", + "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==" + }, "is-absolute": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", @@ -2182,6 +2578,11 @@ "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==" + }, "is-ci": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", @@ -2208,6 +2609,11 @@ } } }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=" + }, "is-descriptor": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", @@ -2322,6 +2728,14 @@ "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=" }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "requires": { + "has": "^1.0.1" + } + }, "is-regexp": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz", @@ -2353,6 +2767,14 @@ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "requires": { + "has-symbols": "^1.0.0" + } + }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -2399,6 +2821,11 @@ "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.2.tgz", "integrity": "sha512-C3FSxJdNrEr2F4z6uFtNzECDM5hXk+46fxaa+cwBe5/XrWSmzdG8DDgyjfX6/NRdBB21q2JXuRAzPCUs+fclnQ==" }, + "isemail": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isemail/-/isemail-2.2.1.tgz", + "integrity": "sha1-A1PT2aYpUQgMJiwqoKQrjqjp4qY=" + }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2412,8 +2839,7 @@ "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" }, "istextorbinary": { "version": "2.5.1", @@ -2435,6 +2861,21 @@ "is-object": "^1.0.1" } }, + "jayson": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-2.1.2.tgz", + "integrity": "sha512-2GejcQnEV35KYTXoBvzALIDdO/1oyEIoJHBnaJFhJhcurv0x2JqUXQW6xlDUhcNOpN9t+d2w+JGA6vOphb+5mg==", + "requires": { + "@types/node": "^10.3.5", + "JSONStream": "^1.3.1", + "commander": "^2.12.2", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "json-stringify-safe": "^5.0.1", + "lodash": "^4.17.11", + "uuid": "^3.2.1" + } + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -2449,11 +2890,18 @@ "esprima": "^4.0.0" } }, + "js2xmlparser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/js2xmlparser/-/js2xmlparser-3.0.0.tgz", + "integrity": "sha1-P7YOqgicVED5MZ9RdgzNB+JJlzM=", + "requires": { + "xmlcreate": "^1.0.1" + } + }, "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" }, "json-buffer": { "version": "3.0.0", @@ -2468,8 +2916,7 @@ "json-schema": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" }, "json-schema-ref-parser": { "version": "7.1.1", @@ -2489,8 +2936,7 @@ "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=", - "dev": true + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, "json-to-ast": { "version": "2.1.0", @@ -2531,7 +2977,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -2652,11 +3097,96 @@ "integrity": "sha512-gKO5uExCXvSm6zbF562EvM+rd1kQDnB9AZBbiQVzf1ZmdDpxUSvpnAaVOP83N/31mRK8Ml8/VE8DMvsAZQ+7wg==", "dev": true }, + "loopback": { + "version": "3.26.0", + "resolved": "https://registry.npmjs.org/loopback/-/loopback-3.26.0.tgz", + "integrity": "sha512-QDREGpTTjLwMgteSIajFXMklW4slbVO5PvY2bPXBn3EUfPzmWXfaDiSlzwbbRbw+cyMUAr2EorL1r0+IsIslWg==", + "requires": { + "async": "^2.0.1", + "bcryptjs": "^2.1.0", + "bluebird": "^3.1.1", + "body-parser": "^1.12.0", + "canonical-json": "0.0.4", + "debug": "^2.1.2", + "depd": "^1.0.0", + "ejs": "^2.3.1", + "express": "^4.14.0", + "inflection": "^1.6.0", + "isemail": "^2.2.1", + "loopback-connector-remote": "^3.0.0", + "loopback-datasource-juggler": "^3.28.0", + "loopback-filters": "^1.0.0", + "loopback-phase": "^3.0.0", + "nodemailer": "^4.0.1", + "nodemailer-direct-transport": "^3.3.2", + "nodemailer-stub-transport": "^1.1.0", + "serve-favicon": "^2.2.0", + "stable": "^0.1.5", + "strong-globalize": "^4.1.1", + "strong-remoting": "^3.11.0", + "uid2": "0.0.3", + "underscore.string": "^3.3.5" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "loopback-datasource-juggler": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/loopback-datasource-juggler/-/loopback-datasource-juggler-3.33.1.tgz", + "integrity": "sha512-VltMiPJxVWQjjWRM1TeSvGL/NF6Ey9575gsEva54+wgtuTO7gRAJTX0DDhpHvwTCflW+s0vWXPFPoTgQaThXEw==", + "requires": { + "async": "^2.6.0", + "bluebird": "^3.1.1", + "debug": "^3.1.0", + "depd": "^1.0.0", + "inflection": "^1.6.0", + "lodash": "^4.17.4", + "loopback-connector": "^4.4.0", + "minimatch": "^3.0.3", + "qs": "^6.5.0", + "shortid": "^2.2.6", + "strong-globalize": "^4.1.1", + "traverse": "^0.6.6", + "uuid": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, "loopback-connector": { "version": "4.9.0", "resolved": "https://registry.npmjs.org/loopback-connector/-/loopback-connector-4.9.0.tgz", "integrity": "sha512-WtHPxItqNLOxuonsOthuOIZrkd9kW+t0HtMweU0pjtEquCvKJAV8s9xqaNs8q8kmbv6rgmYEtmzxkRUsRcV+xQ==", - "dev": true, "requires": { "async": "^3.1.0", "bluebird": "^3.4.6", @@ -2669,20 +3199,17 @@ "async": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/async/-/async-3.1.0.tgz", - "integrity": "sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ==", - "dev": true + "integrity": "sha512-4vx/aaY6j/j3Lw3fbCHNWP0pPaTCew3F6F3hYyl/tHs/ndmV1q7NW9T5yuJ2XAGwdQrP+6Wu20x06U4APo/iQQ==" }, "invert-kv": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-3.0.0.tgz", - "integrity": "sha512-JzF8q2BeZA1ZkE3XROwRpoMQ9ObMgTtp0JH8EXewlbkikuOj2GPLIpUipdO+VL8QsTr2teAJD02EFGGL5cO7uw==", - "dev": true + "integrity": "sha512-JzF8q2BeZA1ZkE3XROwRpoMQ9ObMgTtp0JH8EXewlbkikuOj2GPLIpUipdO+VL8QsTr2teAJD02EFGGL5cO7uw==" }, "lcid": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/lcid/-/lcid-3.1.0.tgz", "integrity": "sha512-HC0Rr2YRxWISzAJ9K0ZiCVRUdjDT6fE6kUKZkXZOZgy968cKWOYy++xwUHO497RRQPPNiABY7SwdoQMMNcZmDQ==", - "dev": true, "requires": { "invert-kv": "^3.0.0" } @@ -2691,7 +3218,6 @@ "version": "5.1.1", "resolved": "https://registry.npmjs.org/mem/-/mem-5.1.1.tgz", "integrity": "sha512-qvwipnozMohxLXG1pOqoLiZKNkC4r4qqRucSoDwXowsNGDSULiqFTRUF05vcZWnwJSG22qTsynQhxbaMtnX9gw==", - "dev": true, "requires": { "map-age-cleaner": "^0.1.3", "mimic-fn": "^2.1.0", @@ -2702,7 +3228,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-4.0.0.tgz", "integrity": "sha512-HsSR1+2l6as4Wp2SGZxqLnuFHxVvh1Ir9pvZxyujsC13egZVe7P0YeBLN0ijQzM/twrO5To3ia3jzBXAvpMTEA==", - "dev": true, "requires": { "execa": "^1.0.0", "lcid": "^3.0.0", @@ -2713,7 +3238,6 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/strong-globalize/-/strong-globalize-5.0.2.tgz", "integrity": "sha512-Y5iuJLEcjI5iUusOvPlen0Q6ej11jUFMzJF4er9gMGy1+yVv/i7v2TuFvD/8lhMAPrE++RRawNQZMpJYsdju/Q==", - "dev": true, "requires": { "accept-language": "^3.0.18", "debug": "^4.1.1", @@ -2727,24 +3251,111 @@ } } }, - "loopback-datasource-juggler": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/loopback-datasource-juggler/-/loopback-datasource-juggler-4.13.0.tgz", - "integrity": "sha512-y0dWSD6BAgY3twhYsa4SmLzOgmp6REAzRJ6gNcc0dhSJ+qur2Ne54BQLqg/bs3KKl9l6AJcLVqB/DRrbjXFn6Q==", - "dev": true, + "loopback-connector-remote": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/loopback-connector-remote/-/loopback-connector-remote-3.4.1.tgz", + "integrity": "sha512-O22X2Gcq8YzZF9DvRjOCyktQlASw1/22i/zzqxJHNKSQA5aQYeTB0w5FttOiKxcw6Q/jzL476hUvUE/NaZVZ1Q==", + "requires": { + "loopback-datasource-juggler": "^3.0.0", + "strong-remoting": "^3.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "loopback-datasource-juggler": { + "version": "3.33.1", + "resolved": "https://registry.npmjs.org/loopback-datasource-juggler/-/loopback-datasource-juggler-3.33.1.tgz", + "integrity": "sha512-VltMiPJxVWQjjWRM1TeSvGL/NF6Ey9575gsEva54+wgtuTO7gRAJTX0DDhpHvwTCflW+s0vWXPFPoTgQaThXEw==", + "requires": { + "async": "^2.6.0", + "bluebird": "^3.1.1", + "debug": "^3.1.0", + "depd": "^1.0.0", + "inflection": "^1.6.0", + "lodash": "^4.17.4", + "loopback-connector": "^4.4.0", + "minimatch": "^3.0.3", + "qs": "^6.5.0", + "shortid": "^2.2.6", + "strong-globalize": "^4.1.1", + "traverse": "^0.6.6", + "uuid": "^3.0.1" + } + } + } + }, + "loopback-datasource-juggler": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/loopback-datasource-juggler/-/loopback-datasource-juggler-4.13.0.tgz", + "integrity": "sha512-y0dWSD6BAgY3twhYsa4SmLzOgmp6REAzRJ6gNcc0dhSJ+qur2Ne54BQLqg/bs3KKl9l6AJcLVqB/DRrbjXFn6Q==", + "dev": true, + "requires": { + "async": "^2.6.0", + "debug": "^4.1.0", + "depd": "^2.0.0", + "inflection": "^1.6.0", + "lodash": "^4.17.11", + "loopback-connector": "^4.4.0", + "minimatch": "^3.0.3", + "qs": "^6.5.0", + "shortid": "^2.2.6", + "strong-globalize": "^4.1.1", + "traverse": "^0.6.6", + "uuid": "^3.0.1" + } + }, + "loopback-datatype-geopoint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loopback-datatype-geopoint/-/loopback-datatype-geopoint-1.0.0.tgz", + "integrity": "sha1-/apcerjXMKmrflRVS+Fl8xzfYQA=" + }, + "loopback-filters": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/loopback-filters/-/loopback-filters-1.0.0.tgz", + "integrity": "sha512-uFQQLfj4T27CM6dzlWMH6aF1lf/Qj97VmXMlVnNWcG+Pd8R8ZbU4i/shArYXArXfis+ICD80YadrPbf9DYRbOA==", + "requires": { + "debug": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "loopback-phase": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/loopback-phase/-/loopback-phase-3.3.0.tgz", + "integrity": "sha512-0NAMtZ2P7VHtW2vgADmDFzFCeniCJwL4I3AdAxX5Ds8IFDQNbnRFnBQSvg+F50HcB7ZkKmR5gtOxtr7bXbqaAQ==", "requires": { - "async": "^2.6.0", - "debug": "^4.1.0", - "depd": "^2.0.0", - "inflection": "^1.6.0", - "lodash": "^4.17.11", - "loopback-connector": "^4.4.0", - "minimatch": "^3.0.3", - "qs": "^6.5.0", - "shortid": "^2.2.6", - "strong-globalize": "^4.1.1", - "traverse": "^0.6.6", - "uuid": "^3.0.1" + "async": "^2.6.1", + "debug": "^3.1.0", + "strong-globalize": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } } }, "lower-case": { @@ -2829,13 +3440,17 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz", "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=", - "dev": true, "requires": { "charenc": "~0.0.1", "crypt": "~0.0.1", "is-buffer": "~1.1.1" } }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, "mem": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz", @@ -3112,11 +3727,21 @@ } } }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, "merge2": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==" }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, "micromatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", @@ -3126,17 +3751,20 @@ "picomatch": "^2.0.5" } }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, "mime-db": { "version": "1.40.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", - "dev": true + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" }, "mime-types": { "version": "2.1.24", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "dev": true, "requires": { "mime-db": "1.40.0" } @@ -3266,11 +3894,51 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, + "msgpack-js": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/msgpack-js/-/msgpack-js-0.3.0.tgz", + "integrity": "sha1-Aw7AjFlW+cp9F9QKVy1Tlv7BCSM=", + "requires": { + "bops": "~0.0.6" + }, + "dependencies": { + "base64-js": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.2.tgz", + "integrity": "sha1-Ak8Pcq+iW3X5wO5zzU9V7Bvtl4Q=" + }, + "bops": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/bops/-/bops-0.0.7.tgz", + "integrity": "sha1-tKClqDmkBkVK8P4FqLkaenZqVOI=", + "requires": { + "base64-js": "0.0.2", + "to-utf8": "0.0.1" + } + } + } + }, + "msgpack-stream": { + "version": "0.0.13", + "resolved": "https://registry.npmjs.org/msgpack-stream/-/msgpack-stream-0.0.13.tgz", + "integrity": "sha1-UKZzrE6uyl43cBkk0JPUM1DB5Sw=", + "requires": { + "bops": "1.0.0", + "msgpack-js": "0.3.0", + "through": "2.3.4" + }, + "dependencies": { + "through": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.4.tgz", + "integrity": "sha1-SV5A6Nio6uvHwnXqiMK4/BTFZFU=" + } + } + }, "msgpack5": { "version": "4.2.1", "resolved": "https://registry.npmjs.org/msgpack5/-/msgpack5-4.2.1.tgz", "integrity": "sha512-Xo7nE9ZfBVonQi1rSopNAqPdts/QHyuSEUwIEzAkB+V2FtmkkLUbP6MyVqVVQxsZYI65FpvW3Bb8Z9ZWEjbgHQ==", - "dev": true, "requires": { "bl": "^2.0.1", "inherits": "^2.0.3", @@ -3295,11 +3963,36 @@ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" }, + "mux-demux": { + "version": "3.7.9", + "resolved": "https://registry.npmjs.org/mux-demux/-/mux-demux-3.7.9.tgz", + "integrity": "sha1-NTZ3GP02AcgLzi63YlMVdtekrO8=", + "requires": { + "duplex": "~1.0.0", + "json-buffer": "~2.0.4", + "msgpack-stream": "~0.0.10", + "stream-combiner": "0.0.2", + "stream-serializer": "~1.1.1", + "through": "~2.3.1", + "xtend": "~1.0.3" + }, + "dependencies": { + "json-buffer": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-2.0.11.tgz", + "integrity": "sha1-PkQf2jCYvo0eMXGtWRvGKjPi1V8=" + }, + "xtend": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-1.0.3.tgz", + "integrity": "sha1-P12Tc1PM7Y4IU5mlY/2yJUHClgo=" + } + } + }, "nanoid": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-2.1.1.tgz", - "integrity": "sha512-0YbJdaL4JFoejIOoawgLcYValFGJ2iyUuVDIWL3g8Es87SSOWFbWdRUMV3VMSiyPs3SQ3QxCIxFX00q5DLkMCw==", - "dev": true + "integrity": "sha512-0YbJdaL4JFoejIOoawgLcYValFGJ2iyUuVDIWL3g8Es87SSOWFbWdRUMV3VMSiyPs3SQ3QxCIxFX00q5DLkMCw==" }, "nanomatch": { "version": "1.2.13", @@ -3324,6 +4017,11 @@ "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=" }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, "nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -3383,6 +4081,38 @@ } } }, + "nodemailer": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-4.7.0.tgz", + "integrity": "sha512-IludxDypFpYw4xpzKdMAozBSkzKHmNBvGanUREjJItgJ2NYcK/s8+PggVhj7c2yGFQykKsnnmv1+Aqo0ZfjHmw==" + }, + "nodemailer-direct-transport": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz", + "integrity": "sha1-6W+vuQNYVglH5WkBfZfmBzilCoY=", + "requires": { + "nodemailer-shared": "1.1.0", + "smtp-connection": "2.12.0" + } + }, + "nodemailer-fetch": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz", + "integrity": "sha1-ecSQihwPXzdbc/6IjamCj23JY6Q=" + }, + "nodemailer-shared": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz", + "integrity": "sha1-z1mU4v0mjQD1zw+nZ6CBae2wfsA=", + "requires": { + "nodemailer-fetch": "1.6.0" + } + }, + "nodemailer-stub-transport": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/nodemailer-stub-transport/-/nodemailer-stub-transport-1.1.0.tgz", + "integrity": "sha1-EUIdLWa07m9AU1T5FMH0ZB6ySw0=" + }, "normalize-package-data": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", @@ -3562,8 +4292,7 @@ "oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" }, "object-copy": { "version": "0.1.0", @@ -3593,6 +4322,16 @@ } } }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, "object-visit": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", @@ -3601,6 +4340,15 @@ "isobject": "^3.0.0" } }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, "object.pick": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", @@ -3609,6 +4357,14 @@ "isobject": "^3.0.1" } }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3640,6 +4396,11 @@ "resolved": "https://registry.npmjs.org/openapi-types/-/openapi-types-1.3.5.tgz", "integrity": "sha512-11oi4zYorsgvg5yBarZplAqbpev5HkuVNPlZaPTknPDzAynq+lnJdXAmruGWP0s+dNYZS7bjM+xrTpJw7184Fg==" }, + "options": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz", + "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8=" + }, "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", @@ -3679,6 +4440,24 @@ "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" }, + "p-event": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-4.1.0.tgz", + "integrity": "sha512-4vAd06GCsgflX4wHN1JqrMzBh/8QZ4j+rzp0cd2scXRwuBEv+QR3wrVA5aLhWDLw4y2WgDKvzWF3CCLmVM1UgA==", + "requires": { + "p-timeout": "^2.0.1" + }, + "dependencies": { + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "requires": { + "p-finally": "^1.0.0" + } + } + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -3810,6 +4589,11 @@ "lines-and-columns": "^1.1.6" } }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, "pascal-case": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz", @@ -3887,8 +4671,7 @@ "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "picomatch": { "version": "2.0.7", @@ -3960,6 +4743,15 @@ "genfun": "^5.0.0" } }, + "proxy-addr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz", + "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.0" + } + }, "pseudomap": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", @@ -3968,8 +4760,7 @@ "psl": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", - "dev": true + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==" }, "pump": { "version": "3.0.0", @@ -4004,20 +4795,34 @@ "punycode": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" }, "qs": { "version": "6.9.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.0.tgz", - "integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA==", - "dev": true + "integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA==" }, "quick-lru": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==" }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -4166,7 +4971,6 @@ "version": "2.88.0", "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, "requires": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -4193,8 +4997,7 @@ "qs": { "version": "6.5.2", "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" } } }, @@ -4334,6 +5137,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "scoped-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz", @@ -4359,6 +5167,53 @@ } } }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + } + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, "sentence-case": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz", @@ -4368,6 +5223,41 @@ "upper-case-first": "^1.1.2" } }, + "serve-favicon": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz", + "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=", + "requires": { + "etag": "~1.8.1", + "fresh": "0.5.2", + "ms": "2.1.1", + "parseurl": "~1.3.2", + "safe-buffer": "5.1.1" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", @@ -4394,6 +5284,11 @@ } } }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, "shebang-command": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", @@ -4421,7 +5316,6 @@ "version": "2.2.15", "resolved": "https://registry.npmjs.org/shortid/-/shortid-2.2.15.tgz", "integrity": "sha512-5EaCy2mx2Jgc/Fdn9uuDuNIIfWBpzY4XIlhoqtXF6qsf+/+SGZ+FxDdX/ZsMZiWupIWNqAEmiNY4RC+LSmCeOw==", - "dev": true, "requires": { "nanoid": "^2.1.0" } @@ -4504,6 +5398,15 @@ "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==" }, + "smtp-connection": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz", + "integrity": "sha1-1275EnyyPCJZ7bHoNJwujV4tdME=", + "requires": { + "httpntlm": "1.6.1", + "nodemailer-shared": "1.1.0" + } + }, "snake-case": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz", @@ -4713,11 +5616,18 @@ "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" }, + "sse": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/sse/-/sse-0.0.8.tgz", + "integrity": "sha512-cviG7JH31TUhZeaEVhac3zTzA+2FwA7qvHziAHpb7mC7RNVJ/RbHN+6LIGsS2ugP4o2H15DWmrSMK+91CboIcg==", + "requires": { + "options": "0.0.6" + } + }, "sshpk": { "version": "1.16.1", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, "requires": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -4741,8 +5651,7 @@ "stable": { "version": "0.1.8", "resolved": "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz", - "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==", - "dev": true + "integrity": "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==" }, "static-extend": { "version": "0.1.2", @@ -4763,12 +5672,25 @@ } } }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, "stealthy-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", "dev": true }, + "stream-combiner": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.2.tgz", + "integrity": "sha1-3+DnRnV0JWXnbGBWeI6lwjvZfbQ=", + "requires": { + "duplexer": "~0.0.3" + } + }, "stream-each": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", @@ -4778,6 +5700,11 @@ "stream-shift": "^1.0.0" } }, + "stream-serializer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/stream-serializer/-/stream-serializer-1.1.2.tgz", + "integrity": "sha1-wfl9FdolH1lK4n1B7IraCahG408=" + }, "stream-shift": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", @@ -4798,6 +5725,24 @@ "strip-ansi": "^5.2.0" } }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, "string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -4858,11 +5803,34 @@ "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=" }, + "strong-error-handler": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/strong-error-handler/-/strong-error-handler-3.2.0.tgz", + "integrity": "sha512-WBU5itMkVPoEPf1W3ptb0AjtPvRWabDzVO4Lcy8MbJQUbo8vdWngLAcNQptQovdFoMGLgQAgJzZkelm6FRADuQ==", + "requires": { + "@types/express": "^4.16.0", + "accepts": "^1.3.3", + "debug": "^3.1.0", + "ejs": "^2.6.1", + "http-status": "^1.1.2", + "js2xmlparser": "^3.0.0", + "strong-globalize": "^4.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, "strong-globalize": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/strong-globalize/-/strong-globalize-4.1.3.tgz", "integrity": "sha512-SJegV7w5D4AodEspZJtJ7rls3fmi+Zc0PdyJCqBsg4RN9B8TC80/uAI2fikC+s1Jp9FLvr2vDX8f0Fqc62M4OA==", - "dev": true, "requires": { "accept-language": "^3.0.18", "debug": "^4.1.1", @@ -4874,6 +5842,48 @@ "yamljs": "^0.3.0" } }, + "strong-remoting": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/strong-remoting/-/strong-remoting-3.14.0.tgz", + "integrity": "sha512-kBOVMBIGW8fCv37G8uyvxBLO+ed0mF9z+gulAgOZfdIXWa0AgXhndpjTqAWvde+2iXt/n6odiyYvCUbXCrfBsQ==", + "requires": { + "async": "^2.0.1", + "body-parser": "^1.12.4", + "debug": "^3.1.0", + "depd": "^1.1.0", + "escape-string-regexp": "^1.0.5", + "eventemitter2": "^5.0.1", + "express": "4.x", + "inflection": "^1.7.1", + "jayson": "^2.0.5", + "js2xmlparser": "^3.0.0", + "loopback-datatype-geopoint": "^1.0.0", + "loopback-phase": "^3.1.0", + "mux-demux": "^3.7.9", + "qs": "^6.2.1", + "request": "^2.83.0", + "sse": "0.0.8", + "strong-error-handler": "^3.0.0", + "strong-globalize": "^4.1.0", + "traverse": "^0.6.6", + "xml2js": "^0.4.8" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + } + } + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -5088,11 +6098,20 @@ "is-number": "^7.0.0" } }, + "to-utf8": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/to-utf8/-/to-utf8-0.0.1.tgz", + "integrity": "sha1-0Xrqcv8vujm55DYBvns/9y4ImFI=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, "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==", - "dev": true, "requires": { "psl": "^1.1.24", "punycode": "^1.4.1" @@ -5101,16 +6120,14 @@ "punycode": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" } } }, "traverse": { "version": "0.6.6", "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.6.6.tgz", - "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=", - "dev": true + "integrity": "sha1-y99WD9e5r2MlAv7UD5GMFX6pcTc=" }, "ts-morph": { "version": "4.0.1", @@ -5136,7 +6153,6 @@ "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, "requires": { "safe-buffer": "^5.0.1" } @@ -5144,8 +6160,7 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" }, "type-detect": { "version": "4.0.8", @@ -5158,6 +6173,15 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.5.2.tgz", "integrity": "sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==" }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, "typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -5176,11 +6200,30 @@ "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.6.3.tgz", "integrity": "sha512-N7bceJL1CtRQ2RiG0AQME13ksR7DiuQh/QehubYcghzv20tnh+MQnQIuJddTmsbqYj+dztchykemz0zFzlvdQw==" }, + "uid2": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.3.tgz", + "integrity": "sha1-SDEm4Rd03y9xuLY53NeZw3YWK4I=" + }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=" }, + "underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=" + }, + "underscore.string": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", + "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", + "requires": { + "sprintf-js": "^1.0.3", + "util-deprecate": "^1.0.2" + } + }, "unicode-10.0.0": { "version": "0.7.5", "resolved": "https://registry.npmjs.org/unicode-10.0.0/-/unicode-10.0.0-0.7.5.tgz", @@ -5231,6 +6274,11 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -5313,7 +6361,6 @@ "version": "4.2.2", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, "requires": { "punycode": "^2.1.0" } @@ -5355,11 +6402,24 @@ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, "uuid": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", - "dev": true + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==" }, "validate-npm-package-license": { "version": "3.0.4", @@ -5383,11 +6443,15 @@ "resolved": "https://registry.npmjs.org/validator/-/validator-11.1.0.tgz", "integrity": "sha512-qiQ5ktdO7CD6C/5/mYV4jku/7qnqzjrxb3C/Q5wR3vGGinHTgJZN/TdFT3ZX4vXhX2R1PXx42fB1cn5W+uJ4lg==" }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -5582,6 +6646,26 @@ "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=" }, + "xml2js": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz", + "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==", + "requires": { + "sax": ">=0.6.0", + "util.promisify": "~1.0.0", + "xmlbuilder": "~11.0.0" + } + }, + "xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==" + }, + "xmlcreate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/xmlcreate/-/xmlcreate-1.0.2.tgz", + "integrity": "sha1-+mv3YqYKQT+z3Y9LA8WyaSONMI8=" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -5609,7 +6693,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/yamljs/-/yamljs-0.3.0.tgz", "integrity": "sha512-C/FsVVhht4iPQYXOInoxUM/1ELSf9EsgKH34FofQOp6hwCPrW4vG4w5++TED3xRUo8gD7l0P1J1dLlDYzODsTQ==", - "dev": true, "requires": { "argparse": "^1.0.7", "glob": "^7.0.5" diff --git a/packages/cli/package.json b/packages/cli/package.json index 5196ce34ac9f..100c566e340e 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -50,9 +50,11 @@ "inquirer": "~7.0.0", "json5": "^2.1.0", "lodash": "^4.17.15", + "loopback": "^3.26.0", "minimist": "^1.2.0", "mkdirp": "^0.5.1", "natural-compare": "^1.4.0", + "p-event": "^4.1.0", "pacote": "^9.5.8", "pluralize": "^8.0.0", "regenerate": "^1.4.0", diff --git a/packages/cli/snapshots/integration/cli/cli.integration.snapshots.js b/packages/cli/snapshots/integration/cli/cli.integration.snapshots.js index 1e1289db5be7..c02ee82dc3de 100644 --- a/packages/cli/snapshots/integration/cli/cli.integration.snapshots.js +++ b/packages/cli/snapshots/integration/cli/cli.integration.snapshots.js @@ -13,6 +13,7 @@ Available commands: lb4 extension lb4 controller lb4 datasource + lb4 import-lb3-models lb4 model lb4 repository lb4 service @@ -31,6 +32,7 @@ Available commands: lb4 extension lb4 controller lb4 datasource + lb4 import-lb3-models lb4 model lb4 repository lb4 service diff --git a/packages/cli/snapshots/integration/generators/import-lb3-models.integration.snapshots.js b/packages/cli/snapshots/integration/generators/import-lb3-models.integration.snapshots.js new file mode 100644 index 000000000000..7b852937c5f2 --- /dev/null +++ b/packages/cli/snapshots/integration/generators/import-lb3-models.integration.snapshots.js @@ -0,0 +1,64 @@ +// IMPORTANT +// This snapshot file is auto-generated, but designed for humans. +// It should be checked into source control and tracked carefully. +// Re-generate by setting UPDATE_SNAPSHOTS=1 and running tests. +// Make sure to inspect the changes in the snapshots below. +// Do not ignore changes! + +'use strict'; + +exports[`lb4 import-lb3-models imports CoffeeShop model from lb3-example app 1`] = ` +import {Entity, model, property} from '@loopback/repository'; + +@model({ + settings: { + strict: false, + forceId: false, + replaceOnPUT: true, + validateUpsert: true, + idInjection: true + } +}) +export class CoffeeShop extends Entity { + @property({ + type: 'number', + id: 1, + generated: true, + }) + id?: number; + + @property({ + type: 'string', + required: true, + }) + name: string; + + @property({ + type: 'string', + }) + city?: string; + + // Define well-known properties here + + // Indexer property to allow additional data + // eslint-disable-next-line @typescript-eslint/no-explicit-any + [prop: string]: any; + + constructor(data?: Partial) { + super(data); + } +} + +export interface CoffeeShopRelations { + // describe navigational properties here +} + +export type CoffeeShopWithRelations = CoffeeShop & CoffeeShopRelations; + +`; + + +exports[`lb4 import-lb3-models imports CoffeeShop model from lb3-example app 2`] = ` +export * from './coffee-shop.model'; + +`; diff --git a/packages/cli/test/integration/generators/import-lb3-models.integration.js b/packages/cli/test/integration/generators/import-lb3-models.integration.js new file mode 100644 index 000000000000..a468c5b689c7 --- /dev/null +++ b/packages/cli/test/integration/generators/import-lb3-models.integration.js @@ -0,0 +1,94 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const assert = require('yeoman-assert'); +const {expect, TestSandbox} = require('@loopback/testlab'); +const path = require('path'); +const generator = path.join(__dirname, '../../../generators/import-lb3-models'); +const {expectFileToMatchSnapshot} = require('../../snapshots'); +const testUtils = require('../../test-utils'); + +const SANDBOX_PATH = path.resolve(__dirname, '../.sandbox'); +const sandbox = new TestSandbox(SANDBOX_PATH); + +// In this test suite we invoke the full generator with mocked prompts +// and inspect the generated model file(s). +// Such tests are slow to run, we strive to keep only few of them. +// Use unit tests to verify the conversion from LB3 to LB4 model definition, +// see tests/unit/import-lb3-models/migrate-model.test.ts + +const { + loadLb3App, +} = require('../../../generators/import-lb3-models/lb3app-loader'); + +const COFFEE_SHOP_EXAMPLE = require.resolve( + '../../../../../examples/lb3-application/lb3app/server/server', +); + +describe('lb4 import-lb3-models', function() { + require('../lib/base-generator')(generator, {args: ['path-to-lb3-app']})(); + + before(function preloadCoffeeShopExampleApp() { + // The CoffeeShop example app takes some time to load :( + // eslint-disable-next-line no-invalid-this + this.timeout(10000); + return loadLb3App(COFFEE_SHOP_EXAMPLE); + }); + + beforeEach('reset sandbox', () => sandbox.reset()); + + it('imports CoffeeShop model from lb3-example app', async () => { + await testUtils + .executeGenerator(generator) + .inDir(SANDBOX_PATH, () => testUtils.givenLBProject(SANDBOX_PATH)) + .withArguments(COFFEE_SHOP_EXAMPLE) + .withPrompts({ + modelNames: ['CoffeeShop'], + }); + + // The default outDir is "src/models" + const outDir = path.join(SANDBOX_PATH, 'src/models'); + + // Verify the source code generated for the model + expectFileToMatchSnapshot(`${outDir}/coffee-shop.model.ts`); + + // Verify that the index file was updated + expectFileToMatchSnapshot(`${outDir}/index.ts`); + }); + + it('honours `outDir` option', async () => { + const outDir = path.join(SANDBOX_PATH, 'my-models'); + + await testUtils + .executeGenerator(generator) + .inDir(SANDBOX_PATH, () => testUtils.givenLBProject(SANDBOX_PATH)) + .withArguments(COFFEE_SHOP_EXAMPLE) + .withPrompts({ + modelNames: ['CoffeeShop'], + }) + .withOptions({ + outDir, + }); + + assert.file([`${outDir}/coffee-shop.model.ts`, `${outDir}/index.ts`]); + }); + + it('reports a helpful error when the selected model does not exist', () => { + return expect( + testUtils + .executeGenerator(generator) + .inDir(SANDBOX_PATH, () => testUtils.givenLBProject(SANDBOX_PATH)) + .withArguments(COFFEE_SHOP_EXAMPLE) + .withPrompts({ + modelNames: ['ModelDoesNotExist'], + }), + ).to.be.rejectedWith( + 'Unknown model name ModelDoesNotExist. Available models: Application, ' + + 'AccessToken, User, RoleMapping, Role, ACL, Scope, CoffeeShop.', + ); + }); +}); diff --git a/packages/cli/test/unit/import-lb3-model/migrate-model.test.js b/packages/cli/test/unit/import-lb3-model/migrate-model.test.js new file mode 100644 index 000000000000..16710f007318 --- /dev/null +++ b/packages/cli/test/unit/import-lb3-model/migrate-model.test.js @@ -0,0 +1,377 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const loopback = require('loopback'); +const {expect, sinon, toJSON} = require('@loopback/testlab'); +const { + importLb3ModelDefinition, +} = require('../../../generators/import-lb3-models/migrate-model'); + +describe('importLb3ModelDefinition', () => { + let log; + beforeEach(function setupLogSpy() { + log = sinon.spy(); + }); + + afterEach(function verifyNoExtraLogs() { + sinon.assert.notCalled(log); + }); + + context('bare-bone model attached to memory', () => { + let modelData; + + before(function setupLb3AppWithMemoryAndModel() { + const MyModel = givenLb3Model('MyModel', {name: 'string'}); + modelData = importLb3ModelDefinition(MyModel, log); + }); + + it('normalizes model settings', () => { + expect(toJSON(modelData.settings)).to.deepEqual({ + // By default, LB3 models are not strict + strict: false, + replaceOnPUT: true, + }); + }); + + it('imports all properties', () => { + expect(Object.keys(modelData.properties)).to.deepEqual(['id', 'name']); + }); + + it('normalizes custom property', () => { + expect(modelData.properties) + .to.have.property('name') + .deepEqual({ + type: `'string'`, + tsType: 'string', + }); + }); + + it('handles id property injected by the connector', () => { + expect(modelData.properties) + .to.have.property('id') + .deepEqual({ + type: `'number'`, + tsType: 'number', + id: 1, + generated: true, + updateOnly: true, + }); + }); + + it('adds other data for the model template', () => { + const options = getModelTemplateOptions(modelData); + + expect(options).to.deepEqual({ + name: 'MyModel', + className: 'MyModel', + + modelBaseClass: 'Entity', + isModelBaseBuiltin: true, + + allowAdditionalProperties: true, + }); + }); + }); + + context('array properties', () => { + it('correctly converts short-hand definition', () => { + const MyModel = givenLb3Model('MyModel', { + tags: ['string'], + }); + const modelData = importLb3ModelDefinition(MyModel, log); + + expect(modelData.properties) + .to.have.property('tags') + .deepEqual({ + type: "'array'", + itemType: "'string'", + tsType: 'string[]', + }); + }); + + it('correctly converts long-style definition', () => { + const MyModel = givenLb3Model('MyModel', { + counts: { + type: ['number'], + required: true, + }, + }); + const modelData = importLb3ModelDefinition(MyModel, log); + + expect(modelData.properties) + .to.have.property('counts') + .deepEqual({ + type: "'array'", + itemType: "'number'", + tsType: 'number[]', + required: true, + }); + }); + }); + + context('base classes', () => { + it('recognizes "Model" base', () => { + const MyModel = givenLb3Model('MyModel', {}, {base: 'Model'}); + const modelData = importLb3ModelDefinition(MyModel, log); + + const options = getModelTemplateOptions(modelData); + expect(options).to.containDeep({ + modelBaseClass: 'Model', + isModelBaseBuiltin: true, + }); + }); + + it('recognizes "PersistedModel" base', () => { + const MyModel = givenLb3Model('MyModel', {}, {base: 'PersistedModel'}); + const modelData = importLb3ModelDefinition(MyModel, log); + + const options = getModelTemplateOptions(modelData); + expect(options).to.containDeep({ + modelBaseClass: 'Entity', + isModelBaseBuiltin: true, + }); + }); + + it('recognizes "KeyValueModel" base', () => { + const MyModel = givenLb3Model( + 'MyModel', + {}, + {base: 'KeyValueModel'}, + {connector: 'kv-memory'}, + ); + const modelData = importLb3ModelDefinition(MyModel, log); + + const options = getModelTemplateOptions(modelData); + expect(options).to.containDeep({ + modelBaseClass: 'KeyValueModel', + isModelBaseBuiltin: true, + }); + }); + + it('refuses to import model extending a non-LB4-built-in (for now)', () => { + // Note: User is a built-in model in LB3 + const MyModel = givenLb3Model('MyModel', {}, {base: 'User'}); + expect(() => importLb3ModelDefinition(MyModel, log)).to.throw( + 'Models inheriting from app-specific models cannot be migrated yet. ' + + 'Base model configured: User', + ); + }); + }); + + context('strict mode', () => { + it('correctly handles "strict: true"', () => { + const MyModel = givenLb3Model('MyModel', {}, {strict: true}); + + const modelData = importLb3ModelDefinition(MyModel, log); + + const options = getModelTemplateOptions(modelData); + expect(options).to.have.property('allowAdditionalProperties', false); + expect(modelData.settings).to.have.property('strict', true); + }); + + it('correctly handles "strict: false"', () => { + const MyModel = givenLb3Model('MyModel', {}, {strict: false}); + + const modelData = importLb3ModelDefinition(MyModel, log); + + const options = getModelTemplateOptions(modelData); + expect(options).to.have.property('allowAdditionalProperties', true); + expect(modelData.settings).to.have.property('strict', false); + }); + + it('interprets "strict: undefined" as "strict: false"', () => { + const MyModel = givenLb3Model('MyModel', {}, {strict: undefined}); + + const modelData = importLb3ModelDefinition(MyModel, log); + + const options = getModelTemplateOptions(modelData); + expect(options).to.have.property('allowAdditionalProperties', true); + expect(modelData.settings).to.have.property('strict', false); + }); + }); + + context('forceId', () => { + it('honors "forceId: true"', () => { + const MyModel = givenLb3Model('MyModel', {}, {forceId: true}); + + const modelData = importLb3ModelDefinition(MyModel, log); + + // "forceId: true" is converted by juggler to "auto" and then removed + // during import, we want the runtime to decide based on PK definition + expect(modelData.settings).to.not.have.property('forceId'); + + expect(modelData.properties.id).to.containDeep({ + updateOnly: true, + }); + }); + + it('honors "forceId: false"', () => { + const MyModel = givenLb3Model('MyModel', {}, {forceId: false}); + + const modelData = importLb3ModelDefinition(MyModel, log); + + expect(modelData.settings).to.have.property('forceId', false); + expect(modelData.properties.id).to.not.have.property('updateOnly'); + }); + }); + + context('connector settings at model level', () => { + it('is migrated as-is', () => { + const MyModel = givenLb3Model( + 'MyModel', + {}, + { + strictObjectIDCoercion: true, + mongodb: { + collection: 'CustomCollectionName', + }, + }, + ); + const modelData = importLb3ModelDefinition(MyModel, log); + expect(modelData.settings).to.containDeep({ + strictObjectIDCoercion: true, + mongodb: { + collection: 'CustomCollectionName', + }, + }); + }); + }); + + context('relations', () => { + it('reports a warning', () => { + const app = givenLb3App(); + app.dataSource('ds', {connector: 'memory'}); + + const Product = app.registry.createModel('Product'); + app.model(Product, {dataSource: 'ds'}); + + const Category = Product.app.registry.createModel( + 'Category', + {}, + { + relations: { + products: { + type: 'hasMany', + model: 'Product', + }, + }, + }, + ); + app.model(Category, {dataSource: 'ds'}); + + importLb3ModelDefinition(Category, log); + + sinon.assert.calledOnce(log); + sinon.assert.calledWithMatch( + log, + /Import of model relations is not supported yet. Skipping the following relations: products/, + ); + log.resetHistory(); // disable assertion in afterEach hook + }); + }); + + context('acls', () => { + it('reports a warning', () => { + const DUMMY_ACL = { + principalType: 'ROLE', + principalId: '$everyone', + permission: 'DENY', + }; + const MyModel = givenLb3Model('MyModel', {}, {acls: [DUMMY_ACL]}); + + importLb3ModelDefinition(MyModel, log); + + sinon.assert.calledOnce(log); + sinon.assert.calledWithMatch( + log, + /Ignoring the following unsupported settings: acls/, + ); + log.resetHistory(); // disable assertion in afterEach hook + }); + }); + + context('methods', () => { + it('reports a warning', () => { + const DUMMY_METHODS = { + find: { + accepts: [], + returns: [], + }, + }; + + const MyModel = givenLb3Model('MyModel', {}, {methods: DUMMY_METHODS}); + + importLb3ModelDefinition(MyModel, log); + + sinon.assert.calledOnce(log); + sinon.assert.calledWithMatch( + log, + /Ignoring the following unsupported settings: methods/, + ); + log.resetHistory(); // disable assertion in afterEach hook + }); + }); + + context('mixins', () => { + it('reports a warning', () => { + const app = givenLb3App(); + app.dataSource('ds', {connector: 'memory'}); + + // Register a dummy mixin + app.registry.modelBuilder.mixins.define('timestamp', function(ctor) {}); + + // Create a model using that mixin + const DUMMY_MIXINS = { + timestamp: true, + }; + const MyModel = app.registry.createModel( + 'MyModel', + {}, + {mixins: DUMMY_MIXINS}, + ); + app.model(MyModel, {dataSource: 'ds'}); + + importLb3ModelDefinition(MyModel, log); + + sinon.assert.calledOnce(log); + sinon.assert.calledWithMatch( + log, + /Ignoring the following unsupported settings: mixins/, + ); + log.resetHistory(); // disable assertion in afterEach hook + }); + }); +}); + +function givenLb3App() { + return loopback({localRegistry: true, loadBuiltinModels: true}); +} + +function givenLb3Model( + name, + properties = {}, + settings = {}, + dataSourceConfig = {connector: 'memory'}, +) { + const app = givenLb3App(); + app.dataSource('ds', dataSourceConfig); + const ModelCtor = app.registry.createModel(name, properties, settings); + app.model(ModelCtor, {dataSource: 'ds'}); + return ModelCtor; +} + +function getModelTemplateOptions(templateData) { + const options = {...templateData}; + + // Settings & properties have been already tested (see above) + delete options.settings; + delete options.properties; + // We don't care about stringified settings as they are auto-generated + delete options.modelSettings; + + return options; +} diff --git a/packages/cli/test/unit/import-lb3-model/model-names.test.js b/packages/cli/test/unit/import-lb3-model/model-names.test.js new file mode 100644 index 000000000000..f695d58cba3d --- /dev/null +++ b/packages/cli/test/unit/import-lb3-model/model-names.test.js @@ -0,0 +1,53 @@ +// Copyright IBM Corp. 2019. All Rights Reserved. +// Node module: @loopback/cli +// This file is licensed under the MIT License. +// License text available at https://opensource.org/licenses/MIT + +'use strict'; + +const { + canImportModelName, +} = require('../../../generators/import-lb3-models/model-names'); +const {expect} = require('@loopback/testlab'); + +describe('canImportModelName', () => { + ['Model', 'PersistedModel', 'KeyValueModel'].forEach(name => { + it(`rejects base model ${name}`, () => { + expect(canImportModelName(name)).to.equal(false); + }); + }); + + ['Change', 'Checkpoint'].forEach(name => { + it(`rejects change-tracking model ${name}`, () => { + expect(canImportModelName(name)).to.equal(false); + }); + }); + + it('rejects model Email', () => { + expect(canImportModelName('Email')).to.equal(false); + }); + + it('rejects anonymous models', () => { + expect(canImportModelName('AnonymousModel_0')).to.equal(false); + }); + + [ + 'ACL', + 'AccessToken', + 'Application', + 'Role', + 'RoleMapping', + 'Scope', + 'User', + ].forEach(name => { + it(`allows built-in model ${name}`, () => { + expect(canImportModelName(name)).to.equal(true); + }); + }); + + ['Product', 'Category', 'CoffeeShop', 'Customer'].forEach(name => { + it(`allows application-specific model name ${name}`, () => { + expect(canImportModelName('Product')).to.equal(true); + }); + }); +});