From 86e20282a0acc98cbb97e1483de96cf2d46a0d2f Mon Sep 17 00:00:00 2001 From: Rich Gwozdz Date: Wed, 22 Nov 2023 14:54:49 -0800 Subject: [PATCH 1/3] feat: add options and change routes --- .changeset/beige-rocks-cheat.md | 5 + .changeset/fair-mirrors-rescue.md | 7 + .changeset/perfect-feet-remember.md | 7 + .nycrc | 2 +- demo/index.js | 10 +- demo/user-store.json | 4 + package-lock.json | 11 +- package.json | 2 +- packages/core/README.md | 10 + packages/core/coverage.svg | 14 +- .../core/src/data-provider/extend-model.js | 71 +- .../src/data-provider/extend-model.spec.js | 182 ++- packages/core/src/index.js | 57 +- packages/core/src/index.spec.js | 160 ++- packages/featureserver/README.md | 77 +- .../helpers/normalize-spatial-reference.js | 1 + .../src/rest-info-route-handler.js | 5 +- .../src/rest-info-route-handler.spec.js | 45 +- packages/output-geoservices/README.md | 105 +- packages/output-geoservices/package-lock.json | 1181 +++++++++++++++++ packages/output-geoservices/package.json | 1 + packages/output-geoservices/src/index.js | 93 +- packages/output-geoservices/src/index.spec.js | 280 ++-- 23 files changed, 1908 insertions(+), 422 deletions(-) create mode 100644 .changeset/beige-rocks-cheat.md create mode 100644 .changeset/fair-mirrors-rescue.md create mode 100644 .changeset/perfect-feet-remember.md create mode 100644 demo/user-store.json create mode 100644 packages/output-geoservices/package-lock.json diff --git a/.changeset/beige-rocks-cheat.md b/.changeset/beige-rocks-cheat.md new file mode 100644 index 000000000..60433c2ca --- /dev/null +++ b/.changeset/beige-rocks-cheat.md @@ -0,0 +1,5 @@ +--- +'@koopjs/featureserver': minor +--- + +- add owningSystemUrl to restInfo response diff --git a/.changeset/fair-mirrors-rescue.md b/.changeset/fair-mirrors-rescue.md new file mode 100644 index 000000000..be2b42df1 --- /dev/null +++ b/.changeset/fair-mirrors-rescue.md @@ -0,0 +1,7 @@ +--- +'@koopjs/koop-core': major +--- + +- route change in geoservices +- generic plugins and file-system plugins no longer supported +- add option to skip default geoservices plugin diff --git a/.changeset/perfect-feet-remember.md b/.changeset/perfect-feet-remember.md new file mode 100644 index 000000000..309f297aa --- /dev/null +++ b/.changeset/perfect-feet-remember.md @@ -0,0 +1,7 @@ +--- +'@koopjs/output-geoservices': major +--- + +- change generateToken route so it matches latest pattern in ArcGIS +- add option "useHttpForTokenUrl" to use http protocol on the authInfo.tokenServicesUrl returned by rest/info route + diff --git a/.nycrc b/.nycrc index 8ce00725e..d66ed279b 100644 --- a/.nycrc +++ b/.nycrc @@ -6,7 +6,7 @@ "packages/cache-memory/src/**/*.js", "packages/logger/src/**/*.js", "packages/output-geoservices/src/**/*.js", - "packages/koop-core/src/**/*.js" + "packages/core/src/**/*.js" ], "exclude": ["**/*.spec.js"], "includeAllSources": true diff --git a/demo/index.js b/demo/index.js index a27caa5ac..5f8c17ca7 100644 --- a/demo/index.js +++ b/demo/index.js @@ -1,6 +1,12 @@ const Koop = require('@koopjs/koop-core'); const provider = require('@koopjs/provider-file-geojson'); - const koop = new Koop({ logLevel: 'debug' }); + +// const auth = require('@koopjs/auth-direct-file')( +// 'pass-in-your-secret', +// `${__dirname}/user-store.json` +// ); + +// koop.register(auth); koop.register(provider, { dataDir: './demo/provider-data'}); -koop.server.listen(8080); \ No newline at end of file +koop.server.listen(process.env.PORT || 8080); \ No newline at end of file diff --git a/demo/user-store.json b/demo/user-store.json new file mode 100644 index 000000000..39bd2082b --- /dev/null +++ b/demo/user-store.json @@ -0,0 +1,4 @@ +[{ + "username": "helloworld", + "password": "foobar" +}] \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a4789f8e6..8635cb7dd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,7 @@ "@changesets/changelog-git": "^0.1.14", "@changesets/cli": "^2.26.2", "@commitlint/config-conventional": "^18.4.2", - "@koopjs/auth-direct-file": "^2.0.2", + "@koopjs/auth-direct-file": "^3.0.0-alpha.0", "@koopjs/provider-file-geojson": "^2.2.0", "await-spawn": "^4.0.2", "byline": "^5.0.0", @@ -2917,9 +2917,10 @@ } }, "node_modules/@koopjs/auth-direct-file": { - "version": "2.0.2", + "version": "3.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/@koopjs/auth-direct-file/-/auth-direct-file-3.0.0-alpha.0.tgz", + "integrity": "sha512-CM0gXbrlqL2Qc1FhnB5WtCyJSnGnCl5TsMK9kw2AbR8hmD3rZN9UxtmumqggciolgtbOB9SGc14ycvmB8qLEug==", "dev": true, - "license": "Apache-2.0", "dependencies": { "fs-extra": "^11.1.1", "joi": "^17.9.2", @@ -23210,7 +23211,9 @@ } }, "@koopjs/auth-direct-file": { - "version": "2.0.2", + "version": "3.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/@koopjs/auth-direct-file/-/auth-direct-file-3.0.0-alpha.0.tgz", + "integrity": "sha512-CM0gXbrlqL2Qc1FhnB5WtCyJSnGnCl5TsMK9kw2AbR8hmD3rZN9UxtmumqggciolgtbOB9SGc14ycvmB8qLEug==", "dev": true, "requires": { "fs-extra": "^11.1.1", diff --git a/package.json b/package.json index 3e2e340df..a03992c26 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@changesets/changelog-git": "^0.1.14", "@changesets/cli": "^2.26.2", "@commitlint/config-conventional": "^18.4.2", - "@koopjs/auth-direct-file": "^2.0.2", + "@koopjs/auth-direct-file": "^3.0.0-alpha.0", "@koopjs/provider-file-geojson": "^2.2.0", "await-spawn": "^4.0.2", "byline": "^5.0.0", diff --git a/packages/core/README.md b/packages/core/README.md index 690e19df6..00e97fb7a 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -94,6 +94,16 @@ const options = { } ``` +#### skipGeoservicesRegistration +By default, Koop will register the GeoServices output-plugin (a.k.a. FeatureServer). If you do not want this plugin registered or want to register a specific version, you can skip the default registration by setting the option to `true`: + +```js +const options = { + skipGeoservicesRegistration: true +} +``` + + #### geoservicesDefaults Koop registers the Geoservices output plugin (FeatureServer) by default. This plugin takes its own options including those to set server and layer metadata (e.g., FeatureServer version, copyrightText, maxRecordCount, etc). These are useful for overriding defaults set in the FeatureServer codebase. You can have Koop set these options at start-up by passing the `geoservicesDefaults` option. It should be a JSON object with the specification described in the [FeatureServer documentation](packages/featureserver#featureserver.setdefaults). diff --git a/packages/core/coverage.svg b/packages/core/coverage.svg index df5fb6bbe..4354a36ca 100644 --- a/packages/core/coverage.svg +++ b/packages/core/coverage.svg @@ -1,20 +1,20 @@ - - coverage: 95.2% + + coverage: 100% - + - - + + \ No newline at end of file diff --git a/packages/core/src/data-provider/extend-model.js b/packages/core/src/data-provider/extend-model.js index 6016c4d07..4905f77dd 100644 --- a/packages/core/src/data-provider/extend-model.js +++ b/packages/core/src/data-provider/extend-model.js @@ -35,6 +35,11 @@ module.exports = function extendModel ({ ProviderModel, namespace, logger, cache } async pull (req, callback) { + const { error } = await this.#authorizeRequest(req); + if (error) { + return callback(error); + } + const key = this.#createCacheKey(req); try { @@ -63,6 +68,11 @@ module.exports = function extendModel ({ ProviderModel, namespace, logger, cache // TODO: the pullLayer() and the pullCatalog() are very similar to the pull() // function. We may consider to merging them in the future. async pullLayer (req, callback) { + const { error } = await this.#authorizeRequest(req); + if (error) { + return callback(error); + } + if (!this.#getLayer) { callback(new Error(`getLayer() method is not implemented in the ${this.namespace} provider.`)); } @@ -91,6 +101,11 @@ module.exports = function extendModel ({ ProviderModel, namespace, logger, cache } async pullCatalog (req, callback) { + const { error } = await this.#authorizeRequest(req); + if (error) { + return callback(error); + } + if (!this.#getCatalog) { callback(new Error(`getCatalog() method is not implemented in the ${this.namespace} provider.`)); } @@ -119,6 +134,12 @@ module.exports = function extendModel ({ ProviderModel, namespace, logger, cache } async pullStream (req) { + const { error } = await this.#authorizeRequest(req); + + if (error) { + throw error; + } + if (this.getStream) { await this.#before(req); const providerStream = await this.getStream(req); @@ -135,20 +156,48 @@ module.exports = function extendModel ({ ProviderModel, namespace, logger, cache } return hasher(req.url).toString(); } + + async #authorizeRequest (req) { + try { + await this.authorize(req); + } catch (error) { + error.code = 401; + return { error }; + } + + return { error: null }; + } } - // Add auth methods if auth plugin registered with Koop - if (authModule) { - const { - authenticationSpecification, - authenticate, - authorize - } = authModule; - - Model.prototype.authenticationSpecification = Object.assign({}, authenticationSpecification(namespace), { provider: namespace }); - Model.prototype.authenticate = authenticate; - Model.prototype.authorize = authorize; + // If provider does not have auth-methods, + // check for global auth-module. if exists, use it, + // otherwise use dummy methods + + if (typeof ProviderModel.prototype.authorize !== 'function') { + Model.prototype.authorize = typeof authModule?.authorize === 'function' ? authModule.authorize : async () => {}; } + + if (typeof ProviderModel.prototype.authenticate !== 'function') { + Model.prototype.authenticate = typeof authModule?.authenticate === 'function' ? authModule?.authenticate : async () => { return {}; }; + } + + if(typeof authModule?.authenticationSpecification === 'function') { + logger.warn('Use of "authenticationSpecification" is deprecated. It will be removed in a future release.'); + Model.prototype.authenticationSpecification = authModule?.authenticationSpecification; + } + // Add auth methods if auth plugin registered with Koop + // if (authModule) { + // const { + // authenticationSpecification, + // authenticate, + // authorize + // } = authModule; + + // Model.prototype.authenticationSpecification = Object.assign({}, authenticationSpecification(namespace), { provider: namespace }); + // Model.prototype.authenticate = authenticate; + // Model.prototype.authorize = authorize; + // } + return new Model({ logger, cache }, options); }; diff --git a/packages/core/src/data-provider/extend-model.spec.js b/packages/core/src/data-provider/extend-model.spec.js index 9816ec029..20a80fd6f 100644 --- a/packages/core/src/data-provider/extend-model.spec.js +++ b/packages/core/src/data-provider/extend-model.spec.js @@ -16,6 +16,7 @@ const mockCache = { const mockLogger = { debug: sinon.spy(), + warn: sinon.spy(), info: () => {}, }; @@ -325,6 +326,34 @@ describe('Tests for extend-model', function () { mockCache.insert.notCalled.should.equal(true); }); + it('should pass authorization error in callback', async () => { + const mockCache = { + retrieve: sinon.spy((key, query, callback) => { + callback(null); + }), + insert: sinon.spy(() => {}), + }; + + class Model extends MockModel {} + Model.prototype.authorize = async () => { + throw new Error('unauthorized'); + }; + + const model = extendModel({ + ProviderModel: Model, + logger: mockLogger, + cache: mockCache, + }); + const pullData = promisify(model.pull).bind(model); + + try { + await pullData({ url: 'domain/test-provider', params: {}, query: {} }); + should.fail(); + } catch (err) { + err.message.should.equal('unauthorized'); + } + }); + it('should send error in callback', async () => { const mockCache = { retrieve: sinon.spy((key, query, callback) => { @@ -390,24 +419,76 @@ describe('Tests for extend-model', function () { }); describe('auth methods', () => { - it('should attach auth methods when auth plugin is registered with Koop', () => { + it('should attach auth methods from authModule if provider does not already define them', async () => { const model = extendModel({ ProviderModel: MockModel, namespace: 'test-provider', logger: mockLogger, cache: mockCache, authModule: { - authenticate: () => {}, - authorize: () => {}, - authenticationSpecification: sinon.spy(), + authenticate: () => { + return 'from auth-module'; + }, + authorize: () => { + return 'from auth-module'; + }, + authenticationSpecification: () => { + return 'from auth-module'; + } + + }, + }); + const authenticateResult = await model.authenticate(); + authenticateResult.should.equal('from auth-module'); + const authorizeResult = await model.authorize(); + authorizeResult.should.equal('from auth-module'); + const specResult = await model.authenticationSpecification(); + specResult.should.equal('from auth-module'); + }); + + it('should use provider auth methods if defined', async () => { + class Model extends MockModel {} + Model.prototype.authenticate = async() => { + return 'from provider'; + }; + + Model.prototype.authorize = async() => { + return 'from provider'; + }; + + const model = extendModel({ + ProviderModel: Model, + namespace: 'test-provider', + logger: mockLogger, + cache: mockCache, + authModule: { + authenticate: () => { + return 'from auth-module'; + }, + authorize: () => { + return 'from auth-module'; + } }, }); - model.should.have.property('authorize').and.be.a.Function(); - model.should.have.property('authenticate').and.be.a.Function(); - model.should.have - .property('authenticationSpecification') - .and.deepEqual({ provider: 'test-provider' }); + const authenticateResult = await model.authenticate(); + authenticateResult.should.equal('from provider'); + const authorizeResult = await model.authorize(); + authorizeResult.should.equal('from provider'); + }); + + it('should use dummy auth methods', async () => { + const model = extendModel({ + ProviderModel: MockModel, + namespace: 'test-provider', + logger: mockLogger, + cache: mockCache, + }); + const authenticateResult = await model.authenticate(); + authenticateResult.should.deepEqual({}); + const authorizeResult = await model.authorize(); + should(authorizeResult).deepEqual(undefined); }); + }); describe('transformation functions', function () { @@ -520,6 +601,34 @@ describe('Tests for extend-model', function () { extendModel.prototype.createKey = undefined; }); + it('should pass authorization error in callback', async () => { + const mockCache = { + retrieve: sinon.spy((key, query, callback) => { + callback(null); + }), + insert: sinon.spy(() => {}), + }; + + class Model extends MockModel {} + Model.prototype.authorize = async () => { + throw new Error('unauthorized'); + }; + + const model = extendModel({ + ProviderModel: Model, + logger: mockLogger, + cache: mockCache, + }); + const pullLayer = promisify(model.pullLayer).bind(model); + + try { + await pullLayer({ url: 'domain/test-provider', params: {}, query: {} }); + should.fail(); + } catch (err) { + err.message.should.equal('unauthorized'); + } + }); + it('should throw an error if the getLayer() function is not implemented', async () => { class Model extends MockModel {} Model.prototype.getLayer = undefined; @@ -907,6 +1016,34 @@ describe('Tests for extend-model', function () { err.message.should.equal('err in getCatalog'); } }); + + it('should pass authorization error in callback', async () => { + const mockCache = { + retrieve: sinon.spy((key, query, callback) => { + callback(null); + }), + insert: sinon.spy(() => {}), + }; + + class Model extends MockModel {} + Model.prototype.authorize = async () => { + throw new Error('unauthorized'); + }; + + const model = extendModel({ + ProviderModel: Model, + logger: mockLogger, + cache: mockCache, + }); + const pullCatalog = promisify(model.pullCatalog).bind(model); + + try { + await pullCatalog({ url: 'domain/test-provider', params: {}, query: {} }); + should.fail(); + } catch (err) { + err.message.should.equal('unauthorized'); + } + }); }); describe('model pullStream method', function () { @@ -972,5 +1109,32 @@ describe('Tests for extend-model', function () { err.should.be.an.Error(); } }); + + it('should throw authorization error', async () => { + const mockCache = { + retrieve: sinon.spy((key, query, callback) => { + callback(null); + }), + insert: sinon.spy(() => {}), + }; + + class Model extends MockModel {} + Model.prototype.authorize = async () => { + throw new Error('unauthorized'); + }; + + const model = extendModel({ + ProviderModel: Model, + logger: mockLogger, + cache: mockCache, + }); + + try { + await model.pullStream({ some: 'options' }); + should.fail(); + } catch (err) { + err.message.should.equal('unauthorized'); + } + }); }); }); diff --git a/packages/core/src/index.js b/packages/core/src/index.js index ff7dea472..7015f4c0c 100644 --- a/packages/core/src/index.js +++ b/packages/core/src/index.js @@ -12,11 +12,12 @@ const DataProvider = require('./data-provider'); const geoservices = require('@koopjs/output-geoservices'); class Koop extends Events { + #authModule; + constructor(options) { super(); this.version = pkg.version; - // TODO: remove usage of "config" module this.config = { ...options, ...config }; this.server = initServer(this.config); this.log = this.config.logger || new Logger(this.config); @@ -29,11 +30,13 @@ class Koop extends Events { const { geoservicesDefaults } = this.config; - this.register(geoservices, { - logger: this.log, - authInfo: this.config.authInfo, - defaults: geoservicesDefaults - }); + if (this.config.skipGeoservicesRegistration !== true) { + this.register(geoservices, { + logger: this.log, + authInfo: this.config.authInfo, + defaults: geoservicesDefaults + }); + } this.server .on('mount', () => { @@ -46,7 +49,7 @@ class Koop extends Events { })); } - register(plugin = {}, options) { + register(plugin, options) { if (!plugin) { throw new Error('Plugin registration failed: plugin undefined'); } @@ -63,18 +66,10 @@ class Koop extends Events { return this.#registerOutput(plugin, options); } - if (plugin.type === 'filesystem') { - return this.#registerFilesystem(plugin, options); - } - if (plugin.type === 'auth') { return this.#registerAuth(plugin, options); } - if (plugin.type === 'plugin') { - return this.#registerPlugin(plugin, options); - } - this.log.warn( 'Unrecognized plugin type: "' + plugin.type + @@ -87,7 +82,7 @@ class Koop extends Events { const dataProvider = new DataProvider({ logger: this.log, cache: this.cache, - authModule: this._authModule, + authModule: this.#authModule, pluginDefinition, outputPlugins: this.outputs, options, @@ -112,33 +107,9 @@ class Koop extends Events { } #registerAuth (auth) { - this._authModule = auth; + this.#authModule = auth; this.log.info(`registered auth module: ${auth.name} v${auth.version}`); } - - #registerFilesystem (Filesystem) { - this.fs = new Filesystem(); - this.log.info( - `registered filesystem: ${Filesystem.pluginName || Filesystem.plugin_name || Filesystem.name} v${Filesystem.version}` - ); - } - - #registerPlugin (Plugin) { - const name = Plugin.pluginName || Plugin.plugin_name || Plugin.name; - if (!name) { - throw new Error('Plugin is missing name'); - } - - let dependencies; - if (Array.isArray(Plugin.dependencies) && Plugin.dependencies.length) { - dependencies = Plugin.dependencies.reduce((deps, dep) => { - deps[dep] = this[dep]; - return deps; - }, {}); - } - this[name] = new Plugin(dependencies); - this.log.info('registered plugin:', name, Plugin.version); - } } /** @@ -156,12 +127,12 @@ function initServer(options) { .use(express.static(path.join(__dirname, '/public'))); // Use CORS unless explicitly disabled in the config - if (!options.disableCors) { + if (options.disableCors !== true) { app.use(cors()); } // Use compression unless explicitly disable in the config - if (!options.disableCompression) { + if (options.disableCompression !== true) { app.use(compression()); } diff --git a/packages/core/src/index.spec.js b/packages/core/src/index.spec.js index 9179d9777..ff2cb9719 100644 --- a/packages/core/src/index.spec.js +++ b/packages/core/src/index.spec.js @@ -4,6 +4,28 @@ const _ = require('lodash'); const DataProvider = require('./data-provider'); const providerConstructorSpy = sinon.spy(); + +const mockApp = { + use: sinon.spy(() => mockApp), + disable: sinon.spy(() => mockApp), + set: sinon.spy(() => mockApp), + on: sinon.spy((event, callback) => { + callback(); + return mockApp; + }), + get: sinon.spy((route, handler) => { + if( route === '/status') { + handler({}, { json: () => {} }); + } + return mockApp; + }), + post: sinon.spy(() => mockApp), +}; + +const mockExpress = () => { + return mockApp; +}; + class mockDataProviderModule extends DataProvider { constructor(params) { providerConstructorSpy(params); @@ -11,8 +33,17 @@ class mockDataProviderModule extends DataProvider { } } +class MockLogger { + warn () {} + log () {} + error () {} + info () {} + silly () {} +} const Koop = proxyquire('./', { - './data-provider': mockDataProviderModule + './data-provider': mockDataProviderModule, + '@koopjs/logger': MockLogger, + 'express': mockExpress }); class MockProviderPluginController { @@ -49,84 +80,95 @@ const mockProviderDefinition = { Model: MockModel }; -const Geoservices = require('@koopjs/output-geoservices'); - const should = require('should') // eslint-disable-line -const geoservicesFixtureRoutes = Geoservices.routes.reduce((acc, route) => { - return acc + route.methods.length; -}, 0); -const providerFixtureRoutes = mockProviderDefinition.routes.reduce((acc, route) => { - return acc + route.methods.length; -}, 0); - describe('Index tests', function () { + beforeEach(() => { + sinon.reset(); + }); describe('Koop instantiation', function () { + it('should instantiate Koop without options', function () { + const koop = new Koop(); + koop.config.should.be.empty(); + mockApp.use.callCount.should.equal(5); + }); + it('should instantiate Koop with options', function () { const koop = new Koop({ foo: 'bar', logLevel: 'error' }); koop.config.should.have.property('foo', 'bar'); }); - it('should instantiate Koop without options', function () { - const koop = new Koop(); - koop.config.should.be.empty(); + it('should skip geoservices registration', function () { + const koop = new Koop({ skipGeoservicesRegistration: true}); + koop.register(mockProviderDefinition, { routePrefix: 'watermelon' }); + koop.outputs.length.should.equal(0); + }); + + it('should disable CORS and compression', function () { + new Koop({ disableCors: true, disableCompression: true }); + + mockApp.use.callCount.should.equal(3); }); }); - describe('Provider registration', function () { + describe('Plugin registration', function () { + it('should fail if no plugin', () => { + try { + const koop = new Koop({ logLevel: 'error' }); + koop.register(); + throw new Error('should have thrown'); + } catch (error) { + error.should.have.property('message', 'Plugin registration failed: plugin undefined'); + } + }); + it('should register provider and add output and provider routes to router stack', function () { const koop = new Koop({ logLevel: 'error' }); koop.register(mockProviderDefinition, { routePrefix: 'watermelon' }); koop.providers.length.should.equal(1); - koop.providers[0].should.have.property('namespace', 'test-provider'); - // Check that the stack includes routes with the provider name in the path - const providerRoutes = koop.server._router.stack - .filter((layer) => { - return layer?.route?.path.includes('watermelon'); - }) - .map(layer => { - return _.get(layer, 'route.path'); - }); - providerRoutes.length.should.equal(geoservicesFixtureRoutes + providerFixtureRoutes); }); - }); -}); -describe('Auth plugin registration', function () { - const mockAuthPlugin = { - type: 'auth', - authenticationSpecification: function () { - return function () { }; - }, - authenticate: function () {}, - authorize: function () {} - }; - - it('should register successfully', function () { - const koop = new Koop({ logLevel: 'error' }); - koop.register(mockAuthPlugin); - koop._authModule.should.be.instanceOf(Object); - koop._authModule.authenticate.should.be.instanceOf(Function); - koop._authModule.authorize.should.be.instanceOf(Function); - koop._authModule.authenticationSpecification.should.be.instanceOf(Function); - }); -}); + it('should register unknown plugin type as provider and add output and provider routes to router stack', function () { + const koop = new Koop({ logLevel: 'error' }); + const unknownPlugin = _.cloneDeep(mockProviderDefinition); + delete unknownPlugin.type; -describe('Generic plugin registration', function () { - class fakePlugin { - static type = 'plugin'; - static version = '0.0.0'; + koop.register(unknownPlugin, { routePrefix: 'watermelon' }); + koop.providers.length.should.equal(1); + koop.providers[0].should.have.property('namespace', 'test-provider'); + }); - testFunc () { - return true; - } - } - it('should register successfully', function () { - const koop = new Koop({ logLevel: 'error' }); - koop.register(fakePlugin); - koop.fakePlugin.should.be.instanceOf(Object); - koop.fakePlugin.testFunc.should.be.instanceOf(Function); - koop.fakePlugin.testFunc().should.equal(true); + it('should register auth-plugin successfully', function () { + const mockAuthPlugin = { + type: 'auth', + authenticate: function () {}, + authorize: function () {} + }; + + const koop = new Koop({ logLevel: 'error' }); + try { + koop.register(mockAuthPlugin); + } catch (error) { + (error).should.equal(undefined); + } + + }); + + it('should register cache-plugin successfully', function () { + const mockCachePlugin = class MockCache { + static type = 'cache'; + }; + + const koop = new Koop({ logLevel: 'error' }); + try { + koop.register(mockCachePlugin); + } catch (error) { + (error).should.equal(undefined); + } + + }); }); + }); + diff --git a/packages/featureserver/README.md b/packages/featureserver/README.md index 99bb62f2c..8ed08b81a 100644 --- a/packages/featureserver/README.md +++ b/packages/featureserver/README.md @@ -35,13 +35,11 @@ routes.forEach(route => { ## API * [FeatureServer.route](#featureserver.route) * [FeatureServer.query](#featureserver.query) +* [FeatureServer.restInfo](#featureserver.serverInfo) * [FeatureServer.serverInfo](#featureserver.serverInfo) * [FeatureServer.layerInfo](#featureserver.layerInfo) * [FeatureServer.layers](#featureserver.layers) * [FeatureServer.generateRenderer](#featureserver.generateRenderer) -* [FeatureServer.authenticate](#featureserver.authenticate) -* [FeatureServer.error.authorize](#featureserver.error.authorize) -* [FeatureServer.authenticate](#featureserver.error.authenticate) * [FeatureServer.queryRelatedRecords](#featureserver.queryRelatedRecords) * [FeatureServer.setDefaults](#featureserver.setDefaults) @@ -157,8 +155,22 @@ const options = { FeatureServer.query(geojson, options) ``` +### FeatureServer.restInfo +Pass in a `data` object and the request object and return a response object that adheres to the specification of the `rest/info` response. The `data` object may contain the `owningSystemUrl` and the `authInfo` object: +```js +{ + owningSystemUrl: 'https://domain.com/some/path' + authInfo: { + isTokenBasedSecurity: true, + tokenServicesUrl: 'https://url/that/will/generate/a/token' + } +} +``` + +The response will include the above information as well as the FeatureServer version numbers. + ### FeatureServer.serverInfo -Generate version `10.51` Geoservices server info +Generate Geoservices server info ```js const server = { @@ -214,7 +226,7 @@ FeatureServer.serverInfo(server) ``` ### FeatureServer.layerInfo -Generate version `10.51` Geoservices information about a single layer +Generate Geoservices information about a single layer ```js FeatureServer.layerInfo(geojson, options) ``` @@ -264,7 +276,7 @@ const metadata = { ``` ### FeatureServer.layers -Generate version `10.51` Geoservices information about one or many layers +Generate Geoservices information about one or many layers Can pass a single geojson object or an array of geojson objects ```js @@ -419,59 +431,6 @@ Output: ] ``` -### FeatureServer.authenticate -Pass in an outgoing response object and an authentication success object and this function will route and return a formatted authentication success response. - - FeatureServer.authenticate(res, auth, ssl = false) - -* `auth` is the result of a successful authentication attempt that returns a token and expiration time -* `ssl` is a boolean flag indicating if token should always be passed back via HTTPS. Defaults to `false` - -e.g., - - const auth = { - "token":"elS39KU4bMmZQgMXDuswgA14vavIp4mfpiqcWSr0qM6q4dFguTnnHddWqbpK5Mc3HsCN8XghlwawUUYApOOcxKNyg_9WqTofChJXxxD058_rL1HZkM5PDhUOh9YYQn1K", - "expires":1524508236322 - } - - FeatureServer.authenticate(res, auth) - - { - "token":"elS39KU4bMmZQgMXDuswgA14vavIp4mfpiqcWSr0qM6q4dFguTnnHddWqbpK5Mc3HsCN8XghlwawUUYApOOcxKNyg_9WqTofChJXxxD058_rL1HZkM5PDhUOh9YYQn1K", - "expires":1524508236322, - ssl: false - } - -### FeatureServer.error.authorize -Pass in an outgoing response object and this function will route and return a formattted authorization error. - - FeatureServer.error.authorize(res) - - { - "error": { - "code": 499, - "message": "Token Required", - "details": [] - } - } - -### FeatureServer.error.authenticate -Pass in an outgoing response object and this function will route and return a formatted authentication error. - - FeatureServer.error.authenticate(res) - - { - "error": { - "code": 400, - "message": "Unable to generate token.", - "details": ["Invalid username or password."] - } - } - - -[npm-image]: https://img.shields.io/npm/v/@koopjs/featureserver.svg?style=flat-square -[npm-url]: https://www.npmjs.com/package/@koopjs/featureserver - ### FeatureServer.queryRelatedRecords Pass in `geojson` and `options`, and the function will return a valid queryRelatedRecords object. Required attributes within `options` are `objectIds` and `relationshipId`. diff --git a/packages/featureserver/src/helpers/normalize-spatial-reference.js b/packages/featureserver/src/helpers/normalize-spatial-reference.js index 568cd7953..b2fc62cd1 100644 --- a/packages/featureserver/src/helpers/normalize-spatial-reference.js +++ b/packages/featureserver/src/helpers/normalize-spatial-reference.js @@ -88,6 +88,7 @@ function esriWktLookup (lookupValue) { const { wkid, latestWkid } = result; // Add the WKT to the local lookup so we don't need to scan the Esri lookups next time + // TODO: move to LRU cache wktLookup.set(wkid, { wkid, latestWkid }); return { latestWkid, wkid }; } diff --git a/packages/featureserver/src/rest-info-route-handler.js b/packages/featureserver/src/rest-info-route-handler.js index 7a5c61e3e..5c1905baa 100644 --- a/packages/featureserver/src/rest-info-route-handler.js +++ b/packages/featureserver/src/rest-info-route-handler.js @@ -9,7 +9,10 @@ function restInfo (data = {}, req) { return { currentVersion, fullVersion, - ...data + owningSystemUrl: data.owningSystemUrl, + authInfo: { + ...data.authInfo + } }; } diff --git a/packages/featureserver/src/rest-info-route-handler.spec.js b/packages/featureserver/src/rest-info-route-handler.spec.js index 447bfd693..ddddfc93f 100644 --- a/packages/featureserver/src/rest-info-route-handler.spec.js +++ b/packages/featureserver/src/rest-info-route-handler.spec.js @@ -1,4 +1,4 @@ -const should = require('should') // eslint-disable-line +const should = require('should'); // eslint-disable-line const restInfo = require('./rest-info-route-handler'); const CURRENT_VERSION = 11.1; const FULL_VERSION = '11.1.0'; @@ -7,34 +7,34 @@ describe('rest/info handler', () => { it('should return default info', () => { const req = { app: { - locals: {} - } + locals: {}, + }, }; const result = restInfo(undefined, req); result.should.deepEqual({ currentVersion: CURRENT_VERSION, - fullVersion: FULL_VERSION + fullVersion: FULL_VERSION, + authInfo: {}, + owningSystemUrl: undefined, }); }); it('should return default plus supplied info', () => { const data = { - hello: { - world: true - } + authInfo: { foo: 'bar' }, + owningSystemUrl: 'helloworld', }; const req = { app: { - locals: {} - } + locals: {}, + }, }; const result = restInfo(data, req); result.should.deepEqual({ currentVersion: CURRENT_VERSION, fullVersion: FULL_VERSION, - hello: { - world: true - } + authInfo: { foo: 'bar' }, + owningSystemUrl: 'helloworld', }); }); @@ -45,16 +45,23 @@ describe('rest/info handler', () => { config: { featureServer: { currentVersion: 10.81, - fullVersion: '10.8.1' - } - } - } - } + fullVersion: '10.8.1', + }, + }, + }, + }, }; - const result = restInfo({}, req); + const result = restInfo( + { authInfo: { foo: 'bar' }, owningSystemUrl: 'helloworld' }, + req, + ); result.should.deepEqual({ currentVersion: 10.81, - fullVersion: '10.8.1' + fullVersion: '10.8.1', + authInfo: { + foo: 'bar', + }, + owningSystemUrl: 'helloworld', }); }); }); diff --git a/packages/output-geoservices/README.md b/packages/output-geoservices/README.md index e55c94d3c..8beb7edbd 100644 --- a/packages/output-geoservices/README.md +++ b/packages/output-geoservices/README.md @@ -20,56 +20,67 @@ koop.register(provider) koop.server.listen(80) ``` -## Routes +## Options + +### `defaults (Object)` +The `defaults` options allows the setting of some FeatureServer metadata properties. The `defaults` option should be an object with some of the following properties: ```js -Geoservices.routes = [ - { - path: '$namespace/rest/info', - methods: ['get', 'post'], - handler: 'featureServerRestInfo' - }, - { - path: '$namespace/tokens/:method', - methods: ['get', 'post'], - handler: 'generateToken' - }, - { - path: '$namespace/tokens/', - methods: ['get', 'post'], - handler: 'generateToken' - }, - { - path: '$namespace/rest/services/$providerParams/FeatureServer/:layer/:method', - methods: ['get', 'post'], - handler: 'featureServer' - }, - { - path: '$namespace/rest/services/$providerParams/FeatureServer/layers', - methods: ['get', 'post'], - handler: 'featureServer' - }, - { - path: '$namespace/rest/services/$providerParams/FeatureServer/:layer', - methods: ['get', 'post'], - handler: 'featureServer' - }, - { - path: '$namespace/rest/services/$providerParams/FeatureServer', - methods: ['get', 'post'], - handler: 'featureServer' - }, - { - path: '$namespace/rest/services/$providerParams/FeatureServer*', - methods: ['get', 'post'], - handler: 'featureServer' - }, - { - path: '$namespace/rest/services/$providerParams/MapServer*', - methods: ['get', 'post'], - handler: 'featureServer' +{ + defaults: { + currentVersion, // number (11.2) + fullVersion, // string ('11.2.0') + maxRecordCount, // number (500) + server: { + serviceDescription, // string ('Default text for serviceDescription') + description, // string ('Default text for description') + copyrightText, // string ('Default text for copyright') + hasStaticData, // boolean (true) + spatialReference, // object (Esri spatial reference) + initialExtent, // object (Esri spatial envelope) + fullExtent, // object (Esri spatial envelope) + }, + layer: { + description, // string ('Default text for layer description') + copyrightText, // string ('Default text for layer copyright') + extent, // object (Esri spatial envelope) + }, } -] +} + +``` +Note that the `defaults` option only overrides FeatureServer's defaults. Providers that set metadata may override values set by the above `defaults` properties. + + +### `useHttpForTokenUrl (boolean)` +The `rest/info` route generates a property `tokenServicesUrl` with value for the URL to use when requesting a token. By default the protocol for this URL is `https`, but if you require it to be `http` set the value of this option to `true`. + +```js +{ + useHttpForTokenUrl: true +} +``` + +### `logger (Logger)` +You can leverage your own custom logger instance, but it must adhere to the Winston logger specification. + +```js +{ + logger // some custom Logger instance +} +``` + +## Routes + +```js +/rest/info +/rest/generateToken +/rest/services//FeatureServer/:layer/:method +/rest/services//FeatureServer/layers +/rest/services//FeatureServer/:layer +/rest/services//FeatureServer +/rest/services//FeatureServer* +/rest/services//MapServer* ``` [npm-img]: https://img.shields.io/npm/v/@koopjs/output-geoservices.svg?style=flat-square diff --git a/packages/output-geoservices/package-lock.json b/packages/output-geoservices/package-lock.json new file mode 100644 index 000000000..c689c0ed1 --- /dev/null +++ b/packages/output-geoservices/package-lock.json @@ -0,0 +1,1181 @@ +{ + "name": "@koopjs/output-geoservices", + "version": "7.1.9", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@koopjs/output-geoservices", + "version": "7.1.9", + "license": "Apache-2.0", + "dependencies": { + "@koopjs/featureserver": "8.1.9", + "@koopjs/logger": "5.0.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@esri/proj-codes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@esri/proj-codes/-/proj-codes-3.2.0.tgz", + "integrity": "sha512-HgmOdGTEpLvqCG7kl6jgqVlhsxqtlCvNUgFQxTs6cMiMrLD7sYlu526lcu4hOxHsly02QsI3EkRU6U+QPsANag==" + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@koopjs/featureserver": { + "version": "8.1.9", + "resolved": "https://registry.npmjs.org/@koopjs/featureserver/-/featureserver-8.1.9.tgz", + "integrity": "sha512-rCGYnrW1bPr2ilopnWmzyQJnjeajhcq5Fe8vCTSlhGq8C8vvmuUd0K3/skJGvIrCzDcFYYYb8qynUHG+zhWeVw==", + "dependencies": { + "@esri/proj-codes": "^3.1.0", + "@koopjs/logger": "5.0.0", + "@koopjs/winnow": "4.2.1", + "@terraformer/spatial": "^2.1.2", + "chroma-js": "^2.4.2", + "esri-extent": "^1.1.3", + "geojson-validation": "^1.0.2", + "iso-datestring-validator": "^2.2.2", + "joi": "^17.10.2", + "lodash": "^4.17.21", + "postgres-date": "^2.1.0", + "wkt-parser": "^1.3.3" + } + }, + "node_modules/@koopjs/logger": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@koopjs/logger/-/logger-5.0.0.tgz", + "integrity": "sha512-iBcLe3Z8F8aeqW2QSSbJlBlqMn6qOIM/781yKQCY/hXw9fLfdFpOCe6SUlv1mnhoYvhdVfF+k0cVxx4mZ9qPEg==", + "dependencies": { + "winston": "^3.2.1" + } + }, + "node_modules/@koopjs/winnow": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@koopjs/winnow/-/winnow-4.2.1.tgz", + "integrity": "sha512-Z/7M0pLWtU2udIemgKGlk36ausyh53YOxWiPWAMPYWTfHIgmwOoxbsfMALvTtjBH1BAR+CTCg0Rg03ZZmvTXJw==", + "dependencies": { + "@esri/proj-codes": "^3.1.0", + "@koopjs/logger": "5.0.0", + "@terraformer/arcgis": "^2.1.2", + "@terraformer/spatial": "^2.1.2", + "@turf/bbox-polygon": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@types/geojson": "^7946.0.10", + "alasql": "^4.1.9", + "classybrew": "0.0.3", + "joi": "^17.10.2", + "js-sql-parser": "^1.4.1", + "lodash": "^4.17.21", + "moment": "^2.29.4", + "ngeohash": "^0.6.3", + "proj4": "^2.9.0", + "simple-statistics": "^7.8.3", + "string-hash": "^1.1.3", + "wkt-parser": "^1.3.3" + }, + "optionalDependencies": { + "farmhash": "^3.3.0" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" + }, + "node_modules/@terraformer/arcgis": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@terraformer/arcgis/-/arcgis-2.1.2.tgz", + "integrity": "sha512-IvdfqehcNAUtKU1OFMKwPT8EvdKlVFZ7q7ZKzkIF8XzYZIVsZLuXuOS1UBdRh5u/o+X5Gax7jiZhD8U/4TV+Jw==", + "dependencies": { + "@terraformer/common": "^2.1.2" + } + }, + "node_modules/@terraformer/common": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@terraformer/common/-/common-2.1.2.tgz", + "integrity": "sha512-cwPdTFzIpekZhZRrgDEkqLKNPoqbyCBQHiemaovnGIeUx0Pl336MY/eCxzJ5zXkrQLVo9zPalq/vYW5HnyKevQ==" + }, + "node_modules/@terraformer/spatial": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@terraformer/spatial/-/spatial-2.1.2.tgz", + "integrity": "sha512-pb1PZNwFlBDjBWUs17/r7jvRoXZraAefqkbfG07DxuKqu3IAniqrXugkxYx343muCZmVLJ8pOxcyDZJGLNwjqg==", + "dependencies": { + "@terraformer/common": "^2.1.2" + } + }, + "node_modules/@turf/bbox-polygon": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-6.5.0.tgz", + "integrity": "sha512-+/r0NyL1lOG3zKZmmf6L8ommU07HliP4dgYToMoTxqzsWzyLjaj/OzgQ8rBmv703WJX+aS6yCmLuIhYqyufyuw==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/centroid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-6.5.0.tgz", + "integrity": "sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/helpers": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", + "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==", + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/meta": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz", + "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@types/geojson": { + "version": "7946.0.13", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz", + "integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==" + }, + "node_modules/@types/triple-beam": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", + "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" + }, + "node_modules/alasql": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/alasql/-/alasql-4.2.2.tgz", + "integrity": "sha512-GjKrHVmNVsDHIMtCZfENSXPAeD2R/iZdcLc2fjeKsb3cynOVm8O2LlgwsIAHP7otLSHd3BErcg0zrVVO162iAg==", + "dependencies": { + "cross-fetch": "4", + "yargs": "16" + }, + "bin": { + "alasql": "bin/alasql-cli.js" + }, + "engines": { + "node": ">=15" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ansi-styles/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ansi-styles/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/bbox2extent": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/bbox2extent/-/bbox2extent-1.1.1.tgz", + "integrity": "sha512-w6Lk0O6axv5JFjP+aXGcoajni1f7lfSuz2x3Br+WFVV/BbZshp4q1RmBk5q+tnWAyZvfBgQ8Ozy+eMK0WjnhbA==" + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "optional": true + }, + "node_modules/chroma-js": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz", + "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==" + }, + "node_modules/classybrew": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/classybrew/-/classybrew-0.0.3.tgz", + "integrity": "sha512-Z1ky+DGpSFKaUpmIcWEM31c8U9gj1e1/gAUb/PWT5gUJBz+8gtFeXnn7HVUgEuWxsRFhxgKB9fs3gf7sTWt0GQ==" + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", + "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", + "dependencies": { + "color-convert": "^1.9.3", + "color-string": "^1.6.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/color-string": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", + "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", + "dependencies": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" + } + }, + "node_modules/colorspace": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", + "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", + "dependencies": { + "color": "^3.1.3", + "text-hex": "1.0.x" + } + }, + "node_modules/cross-fetch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", + "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/detect-libc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/enabled": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", + "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/esri-extent": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/esri-extent/-/esri-extent-1.1.3.tgz", + "integrity": "sha512-NimS0bZmeLwXOVwZ56JPx5gnVZ3pDW7FzqkbgXkBXA4Vy9jKiM8vIOd6uCjzZbg/hbN4qJvsKIelSfOp2EhSXg==", + "dependencies": { + "@types/geojson": "^7946.0.0", + "bbox2extent": "^1.0.1" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/farmhash": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/farmhash/-/farmhash-3.3.0.tgz", + "integrity": "sha512-IZJWJXvX+TZJ4qZrcRZkDqI66s4VxrRD+NsduTSe0PZ9BGEDB53S0cd+e4rTXIWbL5k213W8cN6pMZuPVA+z0Q==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "node-addon-api": "^5.1.0", + "prebuild-install": "^7.1.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/fecha": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", + "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" + }, + "node_modules/fn.name": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", + "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "optional": true + }, + "node_modules/geojson-validation": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/geojson-validation/-/geojson-validation-1.0.2.tgz", + "integrity": "sha512-K5jrJ4wFvORn2pRKeg181LL0QPYuEKn2KHPvfH1m2QtFlAXFLKdseqt0XwBM3ELOY7kNM1fglRQ6ZwUQZ5S00A==", + "bin": { + "gjv": "bin/gjv" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "optional": true + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "optional": true + }, + "node_modules/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/iso-datestring-validator": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", + "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==" + }, + "node_modules/joi": { + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-sql-parser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/js-sql-parser/-/js-sql-parser-1.5.0.tgz", + "integrity": "sha512-scBV/03oaNVPtni/moDdBsHslS/woxiKDliJlwyiXN0KsoD9NpXKLMjxPw36pGfUb7Xw2IdZYvnr+QP2Rl6Vzg==" + }, + "node_modules/kuler": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", + "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/logform": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", + "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", + "dependencies": { + "@colors/colors": "1.6.0", + "@types/triple-beam": "^1.3.2", + "fecha": "^4.2.0", + "ms": "^2.1.1", + "safe-stable-stringify": "^2.3.1", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/mgrs": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", + "integrity": "sha512-awNbTOqCxK1DBGjalK3xqWIstBZgN6fxsMSiXLs9/spqWkF2pAhb2rrYCFSsr1/tT7PhcDGjZndG8SWYn0byYA==" + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "optional": true + }, + "node_modules/moment": { + "version": "2.29.4", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", + "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/napi-build-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", + "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", + "optional": true + }, + "node_modules/ngeohash": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/ngeohash/-/ngeohash-0.6.3.tgz", + "integrity": "sha512-kltF0cOxgx1AbmVzKxYZaoB0aj7mOxZeHaerEtQV0YaqnkXNq26WWqMmJ6lTqShYxVRWZ/mwvvTrNeOwdslWiw==", + "engines": { + "node": ">=v0.2.0" + } + }, + "node_modules/node-abi": { + "version": "3.51.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", + "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "optional": true + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/one-time": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", + "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", + "dependencies": { + "fn.name": "1.x.x" + } + }, + "node_modules/postgres-date": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", + "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", + "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^1.0.1", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prebuild-install/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/proj4": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.9.2.tgz", + "integrity": "sha512-bdyfNmtlWjQN/rHEHEiqFvpTUHhuzDaeQ6Uu1G4sPGqk+Xkxae6ahh865fClJokSGPBmlDOQWWaO6465TCfv5Q==", + "dependencies": { + "mgrs": "1.0.0", + "wkt-parser": "^1.3.3" + } + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/simple-statistics": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-7.8.3.tgz", + "integrity": "sha512-JFvMY00t6SBGtwMuJ+nqgsx9ylkMiJ5JlK9bkj8AdvniIe5615wWQYkKHXe84XtSuc40G/tlrPu0A5/NlJvv8A==", + "engines": { + "node": "*" + } + }, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", + "dependencies": { + "is-arrayish": "^0.3.1" + } + }, + "node_modules/stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", + "engines": { + "node": "*" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tar-fs": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", + "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/text-hex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", + "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, + "node_modules/triple-beam": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", + "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", + "engines": { + "node": ">= 14.0.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/winston": { + "version": "3.11.0", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", + "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", + "dependencies": { + "@colors/colors": "^1.6.0", + "@dabh/diagnostics": "^2.0.2", + "async": "^3.2.3", + "is-stream": "^2.0.0", + "logform": "^2.4.0", + "one-time": "^1.0.0", + "readable-stream": "^3.4.0", + "safe-stable-stringify": "^2.3.1", + "stack-trace": "0.0.x", + "triple-beam": "^1.3.0", + "winston-transport": "^4.5.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/winston-transport": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", + "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", + "dependencies": { + "logform": "^2.3.2", + "readable-stream": "^3.6.0", + "triple-beam": "^1.3.0" + }, + "engines": { + "node": ">= 12.0.0" + } + }, + "node_modules/wkt-parser": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.3.tgz", + "integrity": "sha512-ZnV3yH8/k58ZPACOXeiHaMuXIiaTk1t0hSUVisbO0t4RjA5wPpUytcxeyiN2h+LZRrmuHIh/1UlrR9e7DHDvTw==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "optional": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "optional": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "engines": { + "node": ">=10" + } + } + } +} diff --git a/packages/output-geoservices/package.json b/packages/output-geoservices/package.json index 350bf9f21..341ba5950 100644 --- a/packages/output-geoservices/package.json +++ b/packages/output-geoservices/package.json @@ -37,6 +37,7 @@ }, "jest": { "coverageReporters": [ + "json-summary", "json", "text", "lcov" diff --git a/packages/output-geoservices/src/index.js b/packages/output-geoservices/src/index.js index d89008259..5675423fc 100644 --- a/packages/output-geoservices/src/index.js +++ b/packages/output-geoservices/src/index.js @@ -17,7 +17,8 @@ const tokenRequiredError = { error: { code: 499, message: 'Token Required', - details: [], + messageCode: 'GWM_0003', + details: ['Token Required'], }, }; @@ -39,8 +40,10 @@ const authorizationError = { }; class GeoServices { - #useHttp = false; + #useHttpForTokenUrl = false; + #authInfo; #pullData; + #logger; static type = 'output'; static version = require('../package.json').version; @@ -51,12 +54,7 @@ class GeoServices { handler: 'restInfoHandler', }, { - path: '$namespace/tokens/:method', - methods: ['get', 'post'], - handler: 'generateToken', - }, - { - path: '$namespace/tokens/', + path: '$namespace/rest/generateToken', methods: ['get', 'post'], handler: 'generateToken', }, @@ -95,30 +93,48 @@ class GeoServices { constructor(model, options = {}) { this.model = model; this.#pullData = promisify(this.model.pull).bind(this.model); - this.options = options; - this.logger = options.logger || logger; - this.authInfo = options.authInfo || {}; - this.#useHttp = - this.model.authenticationSpecification?.useHttp === true || - process.env.KOOP_AUTH_HTTP === 'true'; - FeatureServer.setLogger({ logger: this.logger }); + this.#logger = options.logger || logger; + this.#authInfo = options.authInfo || { + isTokenBasedSecurity: true, + }; + + this.#useHttpForTokenUrl = this.#getHttpSetting(options, model); + + FeatureServer.setLogger({ logger: this.#logger }); // Set overrides FeatureServer.setDefaults(options.defaults); } + #getHttpSetting(options, model) { + if (options.useHttpForTokenUrl || process.env.GEOSERVICES_HTTP === 'true') { + return ( + options.useHttpForTokenUrl || process.env.GEOSERVICES_HTTP === 'true' + ); + } + + if (typeof model.authenticationSpecification === 'function') { + return model.authenticationSpecification()?.useHttp === true; + } + + if (typeof process.env.KOOP_AUTH_HTTP !== 'undefined') { + this.#logger.warn( + 'Use of "KOOP_AUTH_HTTP" environment variable is deprecated. It will be removed in a future release. Use the "useHttpForTokenUrl" option or "GEOSERVICES_HTTP" environment variable.', + ); + return process.env.KOOP_AUTH_HTTP === 'true'; + } + + return false; + } + async generalHandler(req, res) { try { - if (this.#shouldAuthorize()) { - await this.model.authorize(req); - } - const data = await this.#pullData(req); return FeatureServer.route(req, res, data); } catch (error) { - this.logger.error(error); + this.#logger.error(error); - const token = this.#getToken(req); + const token = this.#extractTokenFromRequest(req); const { code, message, details = [] } = normalizeError(error); res.status(200); // ArcGIS standard is to wrap errors in 200 success @@ -145,11 +161,7 @@ class GeoServices { } } - #shouldAuthorize() { - return typeof this.model.authorize === 'function'; - } - - #getToken(req) { + #extractTokenFromRequest(req) { const { headers: { authorization }, query, @@ -164,37 +176,34 @@ class GeoServices { } restInfoHandler(req, res) { - const authInfo = { ...this.authInfo }; - - if (this.model.authenticationSpecification) { - authInfo.isTokenBasedSecurity = true; + const authInfo = { ...this.#authInfo }; + if (this.#authInfo.isTokenBasedSecurity) { authInfo.tokenServicesUrl = this.#buildTokensUrl( req.headers.host, req.baseUrl, ); } - FeatureServer.route(req, res, { authInfo }); + FeatureServer.route(req, res, { owningSystemUrl: this.#buildOwningSystemUrl(req.headers.host, + req.baseUrl), authInfo }); } #buildTokensUrl(host, baseUrl) { - const protocol = this.#useHttp ? 'http' : 'https'; - return `${protocol}://${host}${baseUrl}/${this.model.namespace}/tokens/`; + const protocol = this.#useHttpForTokenUrl ? 'http' : 'https'; + return `${protocol}://${host}${baseUrl}/${this.model.namespace}/rest/generateToken`; } - async generateToken(req, res) { - if (typeof this.model.authenticate !== 'function') { - return res - .status(500) - .json({ error: '"authenticate" not implemented for this provider' }); - } + #buildOwningSystemUrl(host, baseUrl) { + const protocol = this.#useHttpForTokenUrl ? 'http' : 'https'; + return `${protocol}://${host}${baseUrl}/${this.model.namespace}`; + } + async generateToken(req, res) { try { + //const decodedToken = await this.model.authorize(req); const tokenResponse = await this.model.authenticate(req); - res - .status(200) - .json({ ...tokenResponse, ssl: tokenResponse.ssl || false }); + res.status(200).json(tokenResponse); } catch (error) { const { code, message, details = [] } = normalizeError(error); diff --git a/packages/output-geoservices/src/index.spec.js b/packages/output-geoservices/src/index.spec.js index f8158f413..d069ad2b5 100644 --- a/packages/output-geoservices/src/index.spec.js +++ b/packages/output-geoservices/src/index.spec.js @@ -1,19 +1,19 @@ const OutputGeoServices = require('./index'); const FeatureServer = require('@koopjs/featureserver'); -// test.js jest.mock('@koopjs/featureserver', () => ({ setLogger: jest.fn(), route: jest.fn(), - setDefaults: jest.fn() + setDefaults: jest.fn(), })); const loggerMock = { silly: () => {}, - error: () => {} + error: () => {}, }; const modelMock = { + namespace: 'provider-name', pull: jest.fn((req, callback) => callback(null, 'someData')), }; @@ -51,12 +51,7 @@ describe('Output Geoservices', () => { handler: 'restInfoHandler', }, { - path: '$namespace/tokens/:method', - methods: ['get', 'post'], - handler: 'generateToken', - }, - { - path: '$namespace/tokens/', + path: '$namespace/rest/generateToken', methods: ['get', 'post'], handler: 'generateToken', }, @@ -92,24 +87,6 @@ describe('Output Geoservices', () => { }, ]); }); - - test('should include expected default properties', () => { - const output = new OutputGeoServices(modelMock); - expect(output.options).toEqual({}); - expect(output.logger).toBeDefined(); - expect(output.authInfo).toEqual({}); - expect(FeatureServer.setLogger.mock.calls.length).toBe(1); - }); - - test('should include properties with optional set values', () => { - const output = new OutputGeoServices(modelMock, { - logger: loggerMock, - authInfo: { food: 'baz' }, - }); - expect(Object.keys(output.logger)).toEqual(['silly', 'error']); - expect(output.authInfo).toEqual({ food: 'baz' }); - expect(FeatureServer.setLogger.mock.calls.length).toBe(1); - }); }); describe('generalHandler', () => { @@ -129,7 +106,6 @@ describe('Output Geoservices', () => { test('should authorize, then pull data and route', async () => { const modelMock = { pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(), }; const output = new OutputGeoServices(modelMock, { logger: loggerMock }); await output.generalHandler({ foo: 'bar' }, resMock); @@ -187,11 +163,10 @@ describe('Output Geoservices', () => { test('should handle required token error', async () => { const modelMock = { - pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(() => { + pull: jest.fn((req, callback) => { const err = new Error('no token'); err.code = 401; - throw err; + callback(err); }), }; const output = new OutputGeoServices(modelMock, { logger: loggerMock }); @@ -203,8 +178,9 @@ describe('Output Geoservices', () => { { error: { code: 499, - details: [], + details: ['Token Required'], message: 'Token Required', + messageCode: 'GWM_0003', }, }, ]); @@ -212,11 +188,10 @@ describe('Output Geoservices', () => { test('should handle invalid token error', async () => { const modelMock = { - pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(() => { + pull: jest.fn((req, callback) => { const err = new Error('invalid token'); err.code = 401; - throw err; + callback(err); }), }; const output = new OutputGeoServices(modelMock, { logger: loggerMock }); @@ -240,11 +215,10 @@ describe('Output Geoservices', () => { test('should handle invalid token error', async () => { const modelMock = { - pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(() => { + pull: jest.fn((req, callback) => { const err = new Error('Forbidden'); err.code = 403; - throw err; + callback(err); }), }; const output = new OutputGeoServices(modelMock, { logger: loggerMock }); @@ -291,51 +265,51 @@ describe('Output Geoservices', () => { }); describe('restInfoHandler', () => { - test('should return rest info', async () => { + test('should return rest info authInfo override', async () => { const output = new OutputGeoServices(modelMock, { authInfo: { food: 'baz' }, }); - await output.restInfoHandler({ foo: 'bar' }, resMock); + await output.restInfoHandler(reqMock, resMock); expect(FeatureServer.route.mock.calls.length).toBe(1); expect(FeatureServer.route.mock.calls[0]).toEqual([ - { foo: 'bar' }, + reqMock, resMock, - { authInfo: { food: 'baz' } }, + { + owningSystemUrl: 'https://some-host.com/api/v1/provider-name', + authInfo: { food: 'baz' }, + }, ]); }); - test('should return rest info with auth specification', async () => { + test('should return rest info with default authInfo, default https token url', async () => { const modelMock = { + namespace: 'provider-name', pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(), - authenticationSpecification: {}, }; - const output = new OutputGeoServices(modelMock, { - authInfo: { food: 'baz' }, - }); + const output = new OutputGeoServices(modelMock); await output.restInfoHandler(reqMock, resMock); expect(FeatureServer.route.mock.calls.length).toBe(1); expect(FeatureServer.route.mock.calls[0]).toEqual([ reqMock, resMock, { + owningSystemUrl: 'https://some-host.com/api/v1/provider-name', authInfo: { - food: 'baz', isTokenBasedSecurity: true, - tokenServicesUrl: 'https://some-host.com/api/v1/undefined/tokens/', + tokenServicesUrl: + 'https://some-host.com/api/v1/provider-name/rest/generateToken', }, }, ]); }); - test('should return rest info with auth specification, http', async () => { + test('should return rest info with default authInfo, http token url, set by option', async () => { const modelMock = { + namespace: 'provider-name', pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(), - authenticationSpecification: { useHttp: true }, }; const output = new OutputGeoServices(modelMock, { - authInfo: { food: 'baz' }, + useHttpForTokenUrl: true, }); await output.restInfoHandler(reqMock, resMock); expect(FeatureServer.route.mock.calls.length).toBe(1); @@ -343,10 +317,95 @@ describe('Output Geoservices', () => { reqMock, resMock, { + owningSystemUrl: 'http://some-host.com/api/v1/provider-name', authInfo: { - food: 'baz', isTokenBasedSecurity: true, - tokenServicesUrl: 'http://some-host.com/api/v1/undefined/tokens/', + tokenServicesUrl: + 'http://some-host.com/api/v1/provider-name/rest/generateToken', + }, + }, + ]); + }); + + test('should return rest info with default authInfo, http token url, set by GEOSERVICES_HTTP', async () => { + const modelMock = { + namespace: 'provider-name', + pull: jest.fn((req, callback) => callback(null, 'someData')), + }; + try { + process.env.GEOSERVICES_HTTP = 'true'; + const output = new OutputGeoServices(modelMock); + await output.restInfoHandler(reqMock, resMock); + expect(FeatureServer.route.mock.calls.length).toBe(1); + expect(FeatureServer.route.mock.calls[0]).toEqual([ + reqMock, + resMock, + { + owningSystemUrl: 'http://some-host.com/api/v1/provider-name', + authInfo: { + isTokenBasedSecurity: true, + tokenServicesUrl: + 'http://some-host.com/api/v1/provider-name/rest/generateToken', + }, + }, + ]); + } catch (error) { + expect(error).toBeUndefined(); + } finally { + delete process.env.GEOSERVICES_HTTP; + } + }); + + test('should return rest info with default authInfo, http token url, set by KOOP_AUTH_HTTP', async () => { + const modelMock = { + namespace: 'provider-name', + pull: jest.fn((req, callback) => callback(null, 'someData')), + }; + try { + process.env.KOOP_AUTH_HTTP = 'true'; + const output = new OutputGeoServices(modelMock); + await output.restInfoHandler(reqMock, resMock); + expect(FeatureServer.route.mock.calls.length).toBe(1); + expect(FeatureServer.route.mock.calls[0]).toEqual([ + reqMock, + resMock, + { + owningSystemUrl: 'http://some-host.com/api/v1/provider-name', + authInfo: { + isTokenBasedSecurity: true, + tokenServicesUrl: + 'http://some-host.com/api/v1/provider-name/rest/generateToken', + }, + }, + ]); + } catch (error) { + expect(error).toBeUndefined(); + } finally { + delete process.env.KOOP_AUTH_HTTP; + } + }); + + test('should return rest info with default authInfo, http token url, set by authenticationSpecification', async () => { + const modelMock = { + namespace: 'provider-name', + pull: jest.fn((req, callback) => callback(null, 'someData')), + authenticationSpecification: () => { + return { useHttp: true }; + }, + }; + + const output = new OutputGeoServices(modelMock); + await output.restInfoHandler(reqMock, resMock); + expect(FeatureServer.route.mock.calls.length).toBe(1); + expect(FeatureServer.route.mock.calls[0]).toEqual([ + reqMock, + resMock, + { + owningSystemUrl: 'http://some-host.com/api/v1/provider-name', + authInfo: { + isTokenBasedSecurity: true, + tokenServicesUrl: + 'http://some-host.com/api/v1/provider-name/rest/generateToken', }, }, ]); @@ -357,10 +416,9 @@ describe('Output Geoservices', () => { test('should generate token', async () => { const modelMock = { pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(), authenticate: jest.fn(() => { return { token: 'abc' }; - }) + }), }; const output = new OutputGeoServices(modelMock, { authInfo: { food: 'baz' }, @@ -369,38 +427,21 @@ describe('Output Geoservices', () => { expect(resMock.status.mock.calls.length).toBe(1); expect(resMock.status.mock.calls[0]).toEqual([200]); expect(resMock.json.mock.calls.length).toBe(1); - expect(resMock.json.mock.calls[0]).toEqual([{ - ssl: false, - token: 'abc' - }]); - }); - - test('should message that there is no authenticate method', async () => { - const modelMock = { - pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(), - }; - const output = new OutputGeoServices(modelMock, { - authInfo: { food: 'baz' }, - }); - await output.generateToken(reqMock, resMock); - expect(resMock.status.mock.calls.length).toBe(1); - expect(resMock.status.mock.calls[0]).toEqual([500]); - expect(resMock.json.mock.calls.length).toBe(1); - expect(resMock.json.mock.calls[0]).toEqual([{ - error: '"authenticate" not implemented for this provider' - }]); + expect(resMock.json.mock.calls[0]).toEqual([ + { + token: 'abc', + }, + ]); }); test('should fail to generate token due to 401', async () => { const modelMock = { pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(), authenticate: jest.fn(() => { const err = new Error('bad creds'); err.code = 401; throw err; - }) + }), }; const output = new OutputGeoServices(modelMock, { authInfo: { food: 'baz' }, @@ -409,28 +450,29 @@ describe('Output Geoservices', () => { expect(resMock.status.mock.calls.length).toBe(1); expect(resMock.status.mock.calls[0]).toEqual([200]); expect(resMock.json.mock.calls.length).toBe(1); - expect(resMock.json.mock.calls[0]).toEqual([{ - error: { - code: 400, - details: ['Invalid username or password.'], - message: 'Unable to generate token.' - } - }]); + expect(resMock.json.mock.calls[0]).toEqual([ + { + error: { + code: 400, + details: ['Invalid username or password.'], + message: 'Unable to generate token.', + }, + }, + ]); }); test('should fail to generate token due to credentials', async () => { const modelMock = { pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(), authenticate: jest.fn(() => { const err = { error: { code: 400, - message: 'Unable to generate token.' - } + message: 'Unable to generate token.', + }, }; throw err; - }) + }), }; const output = new OutputGeoServices(modelMock, { authInfo: { food: 'baz' }, @@ -439,24 +481,25 @@ describe('Output Geoservices', () => { expect(resMock.status.mock.calls.length).toBe(1); expect(resMock.status.mock.calls[0]).toEqual([200]); expect(resMock.json.mock.calls.length).toBe(1); - expect(resMock.json.mock.calls[0]).toEqual([{ - error: { - code: 400, - details: ['Invalid username or password.'], - message: 'Unable to generate token.' - } - }]); + expect(resMock.json.mock.calls[0]).toEqual([ + { + error: { + code: 400, + details: ['Invalid username or password.'], + message: 'Unable to generate token.', + }, + }, + ]); }); test('should fail to generate token due to 5xx', async () => { const modelMock = { pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(), authenticate: jest.fn(() => { const err = new Error('upstream'); err.code = 503; throw err; - }) + }), }; const output = new OutputGeoServices(modelMock, { authInfo: { food: 'baz' }, @@ -465,23 +508,24 @@ describe('Output Geoservices', () => { expect(resMock.status.mock.calls.length).toBe(1); expect(resMock.status.mock.calls[0]).toEqual([200]); expect(resMock.json.mock.calls.length).toBe(1); - expect(resMock.json.mock.calls[0]).toEqual([{ - error: { - code: 503, - details: [], - message: 'upstream' - } - }]); + expect(resMock.json.mock.calls[0]).toEqual([ + { + error: { + code: 503, + details: [], + message: 'upstream', + }, + }, + ]); }); test('should fail to generate token due to 500', async () => { const modelMock = { pull: jest.fn((req, callback) => callback(null, 'someData')), - authorize: jest.fn(), authenticate: jest.fn(() => { const err = new Error('upstream'); throw err; - }) + }), }; const output = new OutputGeoServices(modelMock, { authInfo: { food: 'baz' }, @@ -490,13 +534,15 @@ describe('Output Geoservices', () => { expect(resMock.status.mock.calls.length).toBe(1); expect(resMock.status.mock.calls[0]).toEqual([200]); expect(resMock.json.mock.calls.length).toBe(1); - expect(resMock.json.mock.calls[0]).toEqual([{ - error: { - code: 500, - details: [], - message: 'upstream' - } - }]); + expect(resMock.json.mock.calls[0]).toEqual([ + { + error: { + code: 500, + details: [], + message: 'upstream', + }, + }, + ]); }); }); }); From 1f9de6d354aef7a9bdc7822164bb62fef9bd4732 Mon Sep 17 00:00:00 2001 From: Rich Gwozdz Date: Wed, 22 Nov 2023 14:56:34 -0800 Subject: [PATCH 2/3] chore: remove package lock file --- packages/output-geoservices/package-lock.json | 1181 ----------------- 1 file changed, 1181 deletions(-) delete mode 100644 packages/output-geoservices/package-lock.json diff --git a/packages/output-geoservices/package-lock.json b/packages/output-geoservices/package-lock.json deleted file mode 100644 index c689c0ed1..000000000 --- a/packages/output-geoservices/package-lock.json +++ /dev/null @@ -1,1181 +0,0 @@ -{ - "name": "@koopjs/output-geoservices", - "version": "7.1.9", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "@koopjs/output-geoservices", - "version": "7.1.9", - "license": "Apache-2.0", - "dependencies": { - "@koopjs/featureserver": "8.1.9", - "@koopjs/logger": "5.0.0" - } - }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@esri/proj-codes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@esri/proj-codes/-/proj-codes-3.2.0.tgz", - "integrity": "sha512-HgmOdGTEpLvqCG7kl6jgqVlhsxqtlCvNUgFQxTs6cMiMrLD7sYlu526lcu4hOxHsly02QsI3EkRU6U+QPsANag==" - }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==" - }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@koopjs/featureserver": { - "version": "8.1.9", - "resolved": "https://registry.npmjs.org/@koopjs/featureserver/-/featureserver-8.1.9.tgz", - "integrity": "sha512-rCGYnrW1bPr2ilopnWmzyQJnjeajhcq5Fe8vCTSlhGq8C8vvmuUd0K3/skJGvIrCzDcFYYYb8qynUHG+zhWeVw==", - "dependencies": { - "@esri/proj-codes": "^3.1.0", - "@koopjs/logger": "5.0.0", - "@koopjs/winnow": "4.2.1", - "@terraformer/spatial": "^2.1.2", - "chroma-js": "^2.4.2", - "esri-extent": "^1.1.3", - "geojson-validation": "^1.0.2", - "iso-datestring-validator": "^2.2.2", - "joi": "^17.10.2", - "lodash": "^4.17.21", - "postgres-date": "^2.1.0", - "wkt-parser": "^1.3.3" - } - }, - "node_modules/@koopjs/logger": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@koopjs/logger/-/logger-5.0.0.tgz", - "integrity": "sha512-iBcLe3Z8F8aeqW2QSSbJlBlqMn6qOIM/781yKQCY/hXw9fLfdFpOCe6SUlv1mnhoYvhdVfF+k0cVxx4mZ9qPEg==", - "dependencies": { - "winston": "^3.2.1" - } - }, - "node_modules/@koopjs/winnow": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@koopjs/winnow/-/winnow-4.2.1.tgz", - "integrity": "sha512-Z/7M0pLWtU2udIemgKGlk36ausyh53YOxWiPWAMPYWTfHIgmwOoxbsfMALvTtjBH1BAR+CTCg0Rg03ZZmvTXJw==", - "dependencies": { - "@esri/proj-codes": "^3.1.0", - "@koopjs/logger": "5.0.0", - "@terraformer/arcgis": "^2.1.2", - "@terraformer/spatial": "^2.1.2", - "@turf/bbox-polygon": "^6.5.0", - "@turf/centroid": "^6.5.0", - "@types/geojson": "^7946.0.10", - "alasql": "^4.1.9", - "classybrew": "0.0.3", - "joi": "^17.10.2", - "js-sql-parser": "^1.4.1", - "lodash": "^4.17.21", - "moment": "^2.29.4", - "ngeohash": "^0.6.3", - "proj4": "^2.9.0", - "simple-statistics": "^7.8.3", - "string-hash": "^1.1.3", - "wkt-parser": "^1.3.3" - }, - "optionalDependencies": { - "farmhash": "^3.3.0" - } - }, - "node_modules/@sideway/address": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", - "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", - "dependencies": { - "@hapi/hoek": "^9.0.0" - } - }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==" - }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==" - }, - "node_modules/@terraformer/arcgis": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@terraformer/arcgis/-/arcgis-2.1.2.tgz", - "integrity": "sha512-IvdfqehcNAUtKU1OFMKwPT8EvdKlVFZ7q7ZKzkIF8XzYZIVsZLuXuOS1UBdRh5u/o+X5Gax7jiZhD8U/4TV+Jw==", - "dependencies": { - "@terraformer/common": "^2.1.2" - } - }, - "node_modules/@terraformer/common": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@terraformer/common/-/common-2.1.2.tgz", - "integrity": "sha512-cwPdTFzIpekZhZRrgDEkqLKNPoqbyCBQHiemaovnGIeUx0Pl336MY/eCxzJ5zXkrQLVo9zPalq/vYW5HnyKevQ==" - }, - "node_modules/@terraformer/spatial": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@terraformer/spatial/-/spatial-2.1.2.tgz", - "integrity": "sha512-pb1PZNwFlBDjBWUs17/r7jvRoXZraAefqkbfG07DxuKqu3IAniqrXugkxYx343muCZmVLJ8pOxcyDZJGLNwjqg==", - "dependencies": { - "@terraformer/common": "^2.1.2" - } - }, - "node_modules/@turf/bbox-polygon": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-6.5.0.tgz", - "integrity": "sha512-+/r0NyL1lOG3zKZmmf6L8ommU07HliP4dgYToMoTxqzsWzyLjaj/OzgQ8rBmv703WJX+aS6yCmLuIhYqyufyuw==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/centroid": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-6.5.0.tgz", - "integrity": "sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/helpers": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", - "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==", - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/meta": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz", - "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@types/geojson": { - "version": "7946.0.13", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.13.tgz", - "integrity": "sha512-bmrNrgKMOhM3WsafmbGmC+6dsF2Z308vLFsQ3a/bT8X8Sv5clVYpPars/UPq+sAaJP+5OoLAYgwbkS5QEJdLUQ==" - }, - "node_modules/@types/triple-beam": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", - "integrity": "sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==" - }, - "node_modules/alasql": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/alasql/-/alasql-4.2.2.tgz", - "integrity": "sha512-GjKrHVmNVsDHIMtCZfENSXPAeD2R/iZdcLc2fjeKsb3cynOVm8O2LlgwsIAHP7otLSHd3BErcg0zrVVO162iAg==", - "dependencies": { - "cross-fetch": "4", - "yargs": "16" - }, - "bin": { - "alasql": "bin/alasql-cli.js" - }, - "engines": { - "node": ">=15" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/ansi-styles/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/ansi-styles/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/bbox2extent": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/bbox2extent/-/bbox2extent-1.1.1.tgz", - "integrity": "sha512-w6Lk0O6axv5JFjP+aXGcoajni1f7lfSuz2x3Br+WFVV/BbZshp4q1RmBk5q+tnWAyZvfBgQ8Ozy+eMK0WjnhbA==" - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "optional": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "optional": true - }, - "node_modules/chroma-js": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chroma-js/-/chroma-js-2.4.2.tgz", - "integrity": "sha512-U9eDw6+wt7V8z5NncY2jJfZa+hUH8XEj8FQHgFJTrUFnJfXYf4Ml4adI2vXZOjqRDpFWtYVWypDfZwnJ+HIR4A==" - }, - "node_modules/classybrew": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/classybrew/-/classybrew-0.0.3.tgz", - "integrity": "sha512-Z1ky+DGpSFKaUpmIcWEM31c8U9gj1e1/gAUb/PWT5gUJBz+8gtFeXnn7HVUgEuWxsRFhxgKB9fs3gf7sTWt0GQ==" - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz", - "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==", - "dependencies": { - "color-convert": "^1.9.3", - "color-string": "^1.6.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/colorspace": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/colorspace/-/colorspace-1.1.4.tgz", - "integrity": "sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==", - "dependencies": { - "color": "^3.1.3", - "text-hex": "1.0.x" - } - }, - "node_modules/cross-fetch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz", - "integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==", - "dependencies": { - "node-fetch": "^2.6.12" - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "optional": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "optional": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/enabled": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/enabled/-/enabled-2.0.0.tgz", - "integrity": "sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "optional": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/esri-extent": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/esri-extent/-/esri-extent-1.1.3.tgz", - "integrity": "sha512-NimS0bZmeLwXOVwZ56JPx5gnVZ3pDW7FzqkbgXkBXA4Vy9jKiM8vIOd6uCjzZbg/hbN4qJvsKIelSfOp2EhSXg==", - "dependencies": { - "@types/geojson": "^7946.0.0", - "bbox2extent": "^1.0.1" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/farmhash": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/farmhash/-/farmhash-3.3.0.tgz", - "integrity": "sha512-IZJWJXvX+TZJ4qZrcRZkDqI66s4VxrRD+NsduTSe0PZ9BGEDB53S0cd+e4rTXIWbL5k213W8cN6pMZuPVA+z0Q==", - "hasInstallScript": true, - "optional": true, - "dependencies": { - "node-addon-api": "^5.1.0", - "prebuild-install": "^7.1.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/fecha": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz", - "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==" - }, - "node_modules/fn.name": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz", - "integrity": "sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==" - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "optional": true - }, - "node_modules/geojson-validation": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/geojson-validation/-/geojson-validation-1.0.2.tgz", - "integrity": "sha512-K5jrJ4wFvORn2pRKeg181LL0QPYuEKn2KHPvfH1m2QtFlAXFLKdseqt0XwBM3ELOY7kNM1fglRQ6ZwUQZ5S00A==", - "bin": { - "gjv": "bin/gjv" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "optional": true - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "optional": true - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/iso-datestring-validator": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/iso-datestring-validator/-/iso-datestring-validator-2.2.2.tgz", - "integrity": "sha512-yLEMkBbLZTlVQqOnQ4FiMujR6T4DEcCb1xizmvXS+OxuhwcbtynoosRzdMA69zZCShCNAbi+gJ71FxZBBXx1SA==" - }, - "node_modules/joi": { - "version": "17.11.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", - "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", - "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0", - "@sideway/address": "^4.1.3", - "@sideway/formula": "^3.0.1", - "@sideway/pinpoint": "^2.0.0" - } - }, - "node_modules/js-sql-parser": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/js-sql-parser/-/js-sql-parser-1.5.0.tgz", - "integrity": "sha512-scBV/03oaNVPtni/moDdBsHslS/woxiKDliJlwyiXN0KsoD9NpXKLMjxPw36pGfUb7Xw2IdZYvnr+QP2Rl6Vzg==" - }, - "node_modules/kuler": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/kuler/-/kuler-2.0.0.tgz", - "integrity": "sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==" - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/logform": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.6.0.tgz", - "integrity": "sha512-1ulHeNPp6k/LD8H91o7VYFBng5i1BDE7HoKxVbZiGFidS1Rj65qcywLxX+pVfAPoQJEjRdvKcusKwOupHCVOVQ==", - "dependencies": { - "@colors/colors": "1.6.0", - "@types/triple-beam": "^1.3.2", - "fecha": "^4.2.0", - "ms": "^2.1.1", - "safe-stable-stringify": "^2.3.1", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mgrs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mgrs/-/mgrs-1.0.0.tgz", - "integrity": "sha512-awNbTOqCxK1DBGjalK3xqWIstBZgN6fxsMSiXLs9/spqWkF2pAhb2rrYCFSsr1/tT7PhcDGjZndG8SWYn0byYA==" - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "optional": true - }, - "node_modules/moment": { - "version": "2.29.4", - "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz", - "integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==", - "engines": { - "node": "*" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "optional": true - }, - "node_modules/ngeohash": { - "version": "0.6.3", - "resolved": "https://registry.npmjs.org/ngeohash/-/ngeohash-0.6.3.tgz", - "integrity": "sha512-kltF0cOxgx1AbmVzKxYZaoB0aj7mOxZeHaerEtQV0YaqnkXNq26WWqMmJ6lTqShYxVRWZ/mwvvTrNeOwdslWiw==", - "engines": { - "node": ">=v0.2.0" - } - }, - "node_modules/node-abi": { - "version": "3.51.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.51.0.tgz", - "integrity": "sha512-SQkEP4hmNWjlniS5zdnfIXTk1x7Ome85RDzHlTbBtzE97Gfwz/Ipw4v/Ryk20DWIy3yCNVLVlGKApCnmvYoJbA==", - "optional": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", - "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", - "optional": true - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "optional": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/one-time": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/one-time/-/one-time-1.0.0.tgz", - "integrity": "sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==", - "dependencies": { - "fn.name": "1.x.x" - } - }, - "node_modules/postgres-date": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.1.0.tgz", - "integrity": "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA==", - "engines": { - "node": ">=12" - } - }, - "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prebuild-install/node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/proj4": { - "version": "2.9.2", - "resolved": "https://registry.npmjs.org/proj4/-/proj4-2.9.2.tgz", - "integrity": "sha512-bdyfNmtlWjQN/rHEHEiqFvpTUHhuzDaeQ6Uu1G4sPGqk+Xkxae6ahh865fClJokSGPBmlDOQWWaO6465TCfv5Q==", - "dependencies": { - "mgrs": "1.0.0", - "wkt-parser": "^1.3.3" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "optional": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/rc/node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", - "engines": { - "node": ">=10" - } - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/simple-statistics": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/simple-statistics/-/simple-statistics-7.8.3.tgz", - "integrity": "sha512-JFvMY00t6SBGtwMuJ+nqgsx9ylkMiJ5JlK9bkj8AdvniIe5615wWQYkKHXe84XtSuc40G/tlrPu0A5/NlJvv8A==", - "engines": { - "node": "*" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==", - "engines": { - "node": "*" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-hash": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", - "integrity": "sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==" - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tar-fs": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", - "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", - "optional": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "optional": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/text-hex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", - "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==" - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/triple-beam": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz", - "integrity": "sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==", - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "optional": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/winston": { - "version": "3.11.0", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.11.0.tgz", - "integrity": "sha512-L3yR6/MzZAOl0DsysUXHVjOwv8mKZ71TrA/41EIduGpOOV5LQVodqN+QdQ6BS6PJ/RdIshZhq84P/fStEZkk7g==", - "dependencies": { - "@colors/colors": "^1.6.0", - "@dabh/diagnostics": "^2.0.2", - "async": "^3.2.3", - "is-stream": "^2.0.0", - "logform": "^2.4.0", - "one-time": "^1.0.0", - "readable-stream": "^3.4.0", - "safe-stable-stringify": "^2.3.1", - "stack-trace": "0.0.x", - "triple-beam": "^1.3.0", - "winston-transport": "^4.5.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/winston-transport": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.6.0.tgz", - "integrity": "sha512-wbBA9PbPAHxKiygo7ub7BYRiKxms0tpfU2ljtWzb3SjRjv5yl6Ozuy/TkXf00HTAt+Uylo3gSkNwzc4ME0wiIg==", - "dependencies": { - "logform": "^2.3.2", - "readable-stream": "^3.6.0", - "triple-beam": "^1.3.0" - }, - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/wkt-parser": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/wkt-parser/-/wkt-parser-1.3.3.tgz", - "integrity": "sha512-ZnV3yH8/k58ZPACOXeiHaMuXIiaTk1t0hSUVisbO0t4RjA5wPpUytcxeyiN2h+LZRrmuHIh/1UlrR9e7DHDvTw==" - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "optional": true - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "optional": true - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "engines": { - "node": ">=10" - } - } - } -} From 1d72b58815fe619fdd30333b1e9003726be61aba Mon Sep 17 00:00:00 2001 From: Rich Gwozdz Date: Wed, 22 Nov 2023 16:20:54 -0800 Subject: [PATCH 3/3] chore: e2e tests --- test/geoservice-error-handling.spec.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/test/geoservice-error-handling.spec.js b/test/geoservice-error-handling.spec.js index ce1dd9944..612083036 100644 --- a/test/geoservice-error-handling.spec.js +++ b/test/geoservice-error-handling.spec.js @@ -6,7 +6,7 @@ const mockLogger = { info: () => {}, silly: () => {}, warn: () => {}, - error: () => {} + error: () => {}, }; describe('geoservices error handling', () => { @@ -15,7 +15,8 @@ describe('geoservices error handling', () => { const koop = new Koop({ logLevel: 'error', logger: mockLogger }); koop.register(provider, { dataDir: './test/provider-data', - before: (req, callback) => { // eslint-disable-line + // eslint-disable-next-line + before: (req, callback) => { throw new Error('error in the provider'); }, }); @@ -42,7 +43,6 @@ describe('geoservices error handling', () => { let auth = require('@koopjs/auth-direct-file')( 'pass-in-your-secret', `${__dirname}/helpers/user-store.json`, - { useHttp: true }, ); koop.register(auth); koop.register(provider, { @@ -56,8 +56,9 @@ describe('geoservices error handling', () => { expect(response.body).toEqual({ error: { code: 499, - details: [], + details: ['Token Required'], message: 'Token Required', + messageCode: 'GWM_0003' }, }); } catch (error) { @@ -71,7 +72,6 @@ describe('geoservices error handling', () => { let auth = require('@koopjs/auth-direct-file')( 'pass-in-your-secret', `${__dirname}/helpers/user-store.json`, - { useHttp: true }, ); koop.register(auth); koop.register(provider, { @@ -102,14 +102,13 @@ describe('geoservices error handling', () => { let auth = require('@koopjs/auth-direct-file')( 'pass-in-your-secret', `${__dirname}/helpers/user-store.json`, - { useHttp: true }, ); koop.register(auth); koop.register(provider, { dataDir: './test/provider-data', }); try { - const response = await request(koop.server).get('/file-geojson/tokens'); + const response = await request(koop.server).get('/file-geojson/rest/generateToken'); expect(response.status).toBe(200); expect(response.body).toEqual({ error: {