diff --git a/.dockerignore b/.dockerignore index 17a8f5409f6076009cd717b8a76672feab1c9519..0727a20a84abbcc1eaa66a9feb70bd2b55944389 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,4 +5,5 @@ node_modules/ .circleci/ helm/ google-storage.json -*.tgz \ No newline at end of file +*.tgz +.dck \ No newline at end of file diff --git a/.prettierrc.js b/.prettierrc.js new file mode 100644 index 0000000000000000000000000000000000000000..e3e0097101444f0b61b000068e4c5e5b7f037399 --- /dev/null +++ b/.prettierrc.js @@ -0,0 +1,9 @@ +module.exports = { + bracketSpacing: true, + jsxBracketSameLine: true, + singleQuote: true, + trailingComma: 'all', + arrowParens: 'avoid', + useTabs: true, + semi: false, +} diff --git a/Dockerfile b/Dockerfile index c6648bf6393163b4551b6688753f95d7930b8bc9..f6db5a421d2d41d84d9ac02c5cbb8300534c2de0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,12 +1,15 @@ -FROM mhart/alpine-node:15 as base +FROM mhart/alpine-node:14 as base WORKDIR /app COPY package*.json ./ RUN npm install --only=production --unsafe-perm -FROM mhart/alpine-node:slim-15 as api +FROM mhart/alpine-node:slim-14 as api +ARG APP_VERSION + LABEL maintainer="Louis Capitanchik <louis@jetsam.tech>" LABEL description="The Jetsam API server" +LABEL version=$APP_VERSION RUN apk add --no-cache bash @@ -15,6 +18,7 @@ WORKDIR /app COPY --from=base /app/node_modules ./node_modules COPY server.js . +COPY worker.js . COPY run.js . COPY .sequelizerc . @@ -22,6 +26,7 @@ COPY src ./src COPY scripts ./scripts COPY database ./database COPY views ./views +COPY public ./public COPY package.json ./package.json # Add more COPY lines here as resources are added @@ -45,6 +50,7 @@ ENV MAIL_FROM_ADDRESS="" ENV MAIL_FROM_NAME="" ENV SENDGRID_KEY="" +ENV POSTMARK_KEY="" ENV GCS_BUCKET="" ENV GCS_CREDENTIALS_FILE="" diff --git a/Makefile b/Makefile index a6d22faa68cb882cb4517025a346e1ae824cde78..bd5121cd40586a6a581a9315732810e852ef7a53 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,10 @@ ORG=jetsam APPNAME=api TAG=latest REMOTE_TAG=$(TAG) -REMOTE=lcr.gr +REMOTE=registry.digitalocean.com + +CHART_REPO=https://museum.lcr.gr/api/charts +CHART_TAG=0.0.0 export @@ -19,6 +22,14 @@ push: tag docker: build tag push +chart: + helm package helm/api + +museum: + curl --data-binary "@api-$(CHART_TAG).tgz" "$(CHART_REPO)" + +helm: chart museum + hasura-claims: @echo @envsubst < hasura/claims_config.json | jq -c . diff --git a/README.md b/README.md new file mode 100644 index 0000000000000000000000000000000000000000..362af52a522d8b71fd943a3d1ea75403103083ff --- /dev/null +++ b/README.md @@ -0,0 +1,8 @@ +# api-server + +## Running api-server + +1. start the docker environment: `npm run exec:env` +2. start the server: `npm run watch` +3. start the queue worker: `npm run watch:queue` +4. start NGrok: `ngrok http 7123 --hostname <myhostname>` \ No newline at end of file diff --git a/database/migrations/20000101000000-enable-extensions.js b/database/migrations/20000101000000-enable-extensions.js index 9ddb56a4008ab7735a764711f2cc08b7beb9186c..c152cf230c7896725adaa7c98f10a6bf91f03321 100644 --- a/database/migrations/20000101000000-enable-extensions.js +++ b/database/migrations/20000101000000-enable-extensions.js @@ -1,17 +1,32 @@ module.exports = { up: (migration, Types) => { return migration.sequelize.transaction(async t => { - await migration.sequelize.query('CREATE EXTENSION IF NOT EXISTS postgis;', { transaction: t }) - await migration.sequelize.query('CREATE EXTENSION IF NOT EXISTS pg_trgm;', { transaction: t }) - await migration.sequelize.query('CREATE EXTENSION IF NOT EXISTS timescaledb;', { transaction: t }) + await migration.sequelize.query( + 'CREATE EXTENSION IF NOT EXISTS postgis;', + { transaction: t }, + ) + await migration.sequelize.query( + 'CREATE EXTENSION IF NOT EXISTS pg_trgm;', + { transaction: t }, + ) + await migration.sequelize.query( + 'CREATE EXTENSION IF NOT EXISTS timescaledb;', + { transaction: t }, + ) }) }, down: (migration, Types) => { return migration.sequelize.transaction(async t => { - await migration.sequelize.query('DROP EXTENSION IF EXISTS postgis;', { transaction: t }) - await migration.sequelize.query('DROP EXTENSION IF EXISTS pg_trgm;', { transaction: t }) - await migration.sequelize.query('DROP EXTENSION IF EXISTS timescaledb;', { transaction: t }) + await migration.sequelize.query('DROP EXTENSION IF EXISTS postgis;', { + transaction: t, + }) + await migration.sequelize.query('DROP EXTENSION IF EXISTS pg_trgm;', { + transaction: t, + }) + await migration.sequelize.query('DROP EXTENSION IF EXISTS timescaledb;', { + transaction: t, + }) }) }, -} \ No newline at end of file +} diff --git a/database/migrations/20191117234148-create-users-table.js b/database/migrations/20191117234148-create-users-table.js index 04ca0110c08c96f92f3798ea3328c4325a69959c..a99e6b39233d953fb474f0af654a8262a9d20fb2 100644 --- a/database/migrations/20191117234148-create-users-table.js +++ b/database/migrations/20191117234148-create-users-table.js @@ -49,4 +49,4 @@ module.exports = { down: (migration, Types) => { return migration.dropTable('users') }, -} \ No newline at end of file +} diff --git a/database/migrations/20191118001739-create-metrics-table.js b/database/migrations/20191118001739-create-metrics-table.js index acfb2aabd95b229dfadbc5c80a4d3f7951b7e17c..7cb5e4258657316d520663e7dab427e25cae6a4f 100644 --- a/database/migrations/20191118001739-create-metrics-table.js +++ b/database/migrations/20191118001739-create-metrics-table.js @@ -1,59 +1,70 @@ module.exports = { up: (migration, Types) => { return migration.sequelize.transaction(async t => { - await migration.createTable('metrics', { - id: { - type: Types.UUID, - defaultValue: Types.UUIDV4, - allowNull: false, - }, - value: { - type: Types.TEXT, - allowNull: false, - }, - type: { - type: Types.TEXT, - allowNull: false, - }, - location: { - type: Types.GEOGRAPHY('POINT', 4326), - allowNull: false, - }, - author_id: { - type: Types.UUID, - allowNull: true, - references: { - model: 'users', - key: 'id', - }, - onDelete: 'SET NULL', - onUpdate: 'CASCADE', - }, - meta: { - type: Types.JSONB, - defaultValue: {}, - allowNull: false, - }, - recorded_at: { - type: Types.DATE, - defaultValue: Types.fn('now'), - allowNull: false, - }, - deleted_at: { - type: Types.DATE, - defaultValue: null, - allowNull: true, + await migration.createTable( + 'metrics', + { + id: { + type: Types.UUID, + defaultValue: Types.UUIDV4, + allowNull: false, + }, + value: { + type: Types.TEXT, + allowNull: false, + }, + type: { + type: Types.TEXT, + allowNull: false, + }, + location: { + type: Types.GEOGRAPHY('POINT', 4326), + allowNull: false, + }, + author_id: { + type: Types.UUID, + allowNull: true, + references: { + model: 'users', + key: 'id', + }, + onDelete: 'SET NULL', + onUpdate: 'CASCADE', + }, + meta: { + type: Types.JSONB, + defaultValue: {}, + allowNull: false, + }, + recorded_at: { + type: Types.DATE, + defaultValue: Types.fn('now'), + allowNull: false, + }, + deleted_at: { + type: Types.DATE, + defaultValue: null, + allowNull: true, + }, }, - }, { transaction: t }) - await migration.sequelize.query('CREATE INDEX metrics_id_idx ON metrics(id)', { transaction: t }) - await migration.sequelize.query('SELECT create_hypertable(\'metrics\', \'recorded_at\')', { transaction: t }) + { transaction: t }, + ) + await migration.sequelize.query( + 'CREATE INDEX metrics_id_idx ON metrics(id)', + { transaction: t }, + ) + await migration.sequelize.query( + "SELECT create_hypertable('metrics', 'recorded_at')", + { transaction: t }, + ) }) - }, down: (migration, Types) => { return migration.sequelize.transaction(async t => { - await migration.removeIndex('metrics', 'metrics_id_idx', { transaction: t }) + await migration.removeIndex('metrics', 'metrics_id_idx', { + transaction: t, + }) await migration.dropTable('metrics', { transaction: t }) }) }, diff --git a/database/migrations/20191118004631-create-oauth-access-tokens-table.js b/database/migrations/20191118004631-create-oauth-access-tokens-table.js index 619aa0e053dbcaf45c8174d2bb99425fec4aa37b..94bb96357db76ab0ec9b26952e256bbca51c0c2f 100644 --- a/database/migrations/20191118004631-create-oauth-access-tokens-table.js +++ b/database/migrations/20191118004631-create-oauth-access-tokens-table.js @@ -66,4 +66,4 @@ module.exports = { down: (migration, Types) => { return migration.dropTable('oauth_access_tokens') }, -} \ No newline at end of file +} diff --git a/database/migrations/20191118005011-create-oauth-refresh-tokens-table.js b/database/migrations/20191118005011-create-oauth-refresh-tokens-table.js index 16265efa39b55f4653b19d77827e7a79ae24ad59..364331a082b462cd8dd64b9a90734793c4cabc1e 100644 --- a/database/migrations/20191118005011-create-oauth-refresh-tokens-table.js +++ b/database/migrations/20191118005011-create-oauth-refresh-tokens-table.js @@ -66,4 +66,4 @@ module.exports = { down: (migration, Types) => { return migration.dropTable('oauth_refresh_tokens') }, -} \ No newline at end of file +} diff --git a/database/migrations/20191118011656-create-files-search-index-table.js b/database/migrations/20191118011656-create-files-search-index-table.js index 6f0feb3d104512a3ed6d5874d7541e4cdc2382d4..020eb638a5ebb075044fbfe5872a4d5c5099aa07 100644 --- a/database/migrations/20191118011656-create-files-search-index-table.js +++ b/database/migrations/20191118011656-create-files-search-index-table.js @@ -1,15 +1,22 @@ module.exports = { up: (migration, Types) => { return migration.sequelize.transaction(async t => { - await migration.sequelize.query(` + await migration.sequelize.query( + ` CREATE TABLE IF NOT EXISTS files_search_index ( file_id UUID UNIQUE PRIMARY KEY NOT NULL REFERENCES files(id) ON DELETE CASCADE ON UPDATE CASCADE, search_index TSVECTOR NOT NULL -);`, { transaction: t }) +);`, + { transaction: t }, + ) - await migration.sequelize.query(`CREATE INDEX IF NOT EXISTS files_search_index_idx ON files_search_index USING GIN(search_index);`, { transaction: t }) + await migration.sequelize.query( + `CREATE INDEX IF NOT EXISTS files_search_index_idx ON files_search_index USING GIN(search_index);`, + { transaction: t }, + ) - await migration.sequelize.query(` + await migration.sequelize.query( + ` CREATE OR REPLACE FUNCTION update_files_search_index() RETURNS TRIGGER AS $FUNC$ DECLARE indexed_text TSVECTOR := to_tsvector(concat(NEW.comment, array_to_string(NEW.tags, ' ', ''), array_to_string(NEW.labels, ' ', ''))); @@ -20,20 +27,37 @@ CREATE OR REPLACE FUNCTION update_files_search_index() RETURNS TRIGGER AS $FUNC$ RETURN NEW; END; -$FUNC$ LANGUAGE plpgsql;`, { transaction: t }) +$FUNC$ LANGUAGE plpgsql;`, + { transaction: t }, + ) - await migration.sequelize.query(` + await migration.sequelize.query( + ` CREATE TRIGGER update_files_search_index_trigger AFTER INSERT OR UPDATE ON files - FOR EACH ROW EXECUTE FUNCTION update_files_search_index();`, { transaction: t }) + FOR EACH ROW EXECUTE FUNCTION update_files_search_index();`, + { transaction: t }, + ) }) }, down: (migration, Types) => { return migration.sequelize.transaction(async t => { - await migration.sequelize.query(`DROP TRIGGER IF EXISTS update_files_search_index_trigger ON files`, { transaction: t }) - await migration.sequelize.query(`DROP FUNCTION IF EXISTS update_files_search_index()`, { transaction: t }) - await migration.sequelize.query(`DROP INDEX IF EXISTS files_search_index_idx`, { transaction: t }) - await migration.sequelize.query(`DROP TABLE IF EXISTS files_search_index`, { transaction: t }) + await migration.sequelize.query( + `DROP TRIGGER IF EXISTS update_files_search_index_trigger ON files`, + { transaction: t }, + ) + await migration.sequelize.query( + `DROP FUNCTION IF EXISTS update_files_search_index()`, + { transaction: t }, + ) + await migration.sequelize.query( + `DROP INDEX IF EXISTS files_search_index_idx`, + { transaction: t }, + ) + await migration.sequelize.query( + `DROP TABLE IF EXISTS files_search_index`, + { transaction: t }, + ) }) - } -} \ No newline at end of file + }, +} diff --git a/database/migrations/20200112223826-create-files-likes-table.js b/database/migrations/20200112223826-create-files-likes-table.js index f8122036754e45913b4540a3af8b7d4ddec11cd4..196a7aefc50ef5d3613a88a97cf3e2c156bf1b90 100644 --- a/database/migrations/20200112223826-create-files-likes-table.js +++ b/database/migrations/20200112223826-create-files-likes-table.js @@ -36,4 +36,4 @@ module.exports = { down: (migration, Types) => { return migration.dropTable('user_file_likes') }, -} \ No newline at end of file +} diff --git a/database/migrations/20200210015221-add-files-featured-timestamp.js b/database/migrations/20200210015221-add-files-featured-timestamp.js index 15d4fe0546854bb93d1cf8430a76d97d6475d4e3..bc81b39c3635520240224030a88336c9e58aaf5f 100644 --- a/database/migrations/20200210015221-add-files-featured-timestamp.js +++ b/database/migrations/20200210015221-add-files-featured-timestamp.js @@ -9,4 +9,4 @@ module.exports = { down: (migration, Types) => { return migration.removeColumn('files', 'featured_at') }, -} \ No newline at end of file +} diff --git a/database/migrations/20200323000437-create-bundle-codes-table.js b/database/migrations/20200323000437-create-bundle-codes-table.js index 056e525a787e45646a0c697e636d942da65f3038..d5037b37a2466510c2a9c73861737f42b50f96ec 100644 --- a/database/migrations/20200323000437-create-bundle-codes-table.js +++ b/database/migrations/20200323000437-create-bundle-codes-table.js @@ -46,4 +46,4 @@ module.exports = { down: (migration, Types) => { return migration.dropTable('') }, -} \ No newline at end of file +} diff --git a/database/migrations/20200323000553-create-user-bundle-codes-table.js b/database/migrations/20200323000553-create-user-bundle-codes-table.js index 84b0443be83e4e9c405463d84e5a32162028c6d3..0609c16d0e368be55bcdd7a61fb79ea940504544 100644 --- a/database/migrations/20200323000553-create-user-bundle-codes-table.js +++ b/database/migrations/20200323000553-create-user-bundle-codes-table.js @@ -27,4 +27,4 @@ module.exports = { down: (migration, Types) => { return migration.dropTable('user_bundle_codes') }, -} \ No newline at end of file +} diff --git a/database/migrations/20210000000000-create-analytics-table.js b/database/migrations/20210000000000-create-analytics-table.js new file mode 100644 index 0000000000000000000000000000000000000000..05336c70e79f296c50ebb47811615df37761e12f --- /dev/null +++ b/database/migrations/20210000000000-create-analytics-table.js @@ -0,0 +1,80 @@ +module.exports = { + up: (migration, Types) => { + return migration.sequelize.transaction(async t => { + await migration.createTable( + 'analytics', + { + id: { + type: Types.UUID, + primaryKey: true, + defaultValue: Types.UUIDV4, + allowNull: false, + }, + session_id: { + type: Types.UUID, + allowNull: true, + }, + action: { + type: Types.TEXT, + allowNull: false, + }, + event: { + type: Types.TEXT, + allowNull: false, + }, + start_time: { + type: Types.DATE, + defaultValue: Types.fn('now'), + allowNull: false, + }, + end_time: { + type: Types.DATE, + allowNull: true, + }, + parent_id: { + type: Types.UUID, + allowNull: true, + references: { + model: 'analytics', + key: 'id', + }, + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }, + properties: { + type: Types.JSONB, + defaultValue: '{}', + allowNull: false, + }, + location: { + type: Types.GEOGRAPHY('POINT', 4326), + allowNull: true, + }, + device: { + type: Types.JSONB, + allowNull: true, + }, + meta: { + type: Types.JSONB, + defaultValue: {}, + allowNull: false, + }, + }, + { transaction: t }, + ) + await migration.sequelize.query( + 'CREATE INDEX analytics_session_id_idx ON analytics(session_id)', + { transaction: t }, + ) + }) + }, + + down: (migration, Types) => { + return migration.sequelize.transaction(async t => { + await migration.removeIndex('analytics', 'analytics_session_id_idx', { + transaction: t, + }) + await migration.dropTable('analytics', { transaction: t }) + }) + }, +} diff --git a/database/migrations/20210000000001-create-uploads-table.js b/database/migrations/20210000000001-create-uploads-table.js new file mode 100644 index 0000000000000000000000000000000000000000..6f3faab2c2cc1b88b08edd57de1a9c89441ebf35 --- /dev/null +++ b/database/migrations/20210000000001-create-uploads-table.js @@ -0,0 +1,69 @@ +module.exports = { + up: (migration, Types) => { + return migration.createTable('uploads', { + id: { + type: Types.UUID, + primaryKey: true, + defaultValue: Types.UUIDV4, + allowNull: false, + }, + user_id: { + type: Types.UUID, + allowNull: true, + references: { + model: 'users', + key: 'id', + }, + }, + provider: { + type: Types.TEXT, + allowNull: false, + }, + upload_url: { + type: Types.TEXT, + allowNull: false, + }, + request_params: { + type: Types.JSONB, + allowNull: false, + }, + expires_at: { + type: Types.DATE, + allowNull: false, + }, + status: { + type: Types.TEXT, + allowNull: 'false', + default: 'pending', + }, + status_reason: { + type: Types.TEXT, + allowNull: true, + }, + meta: { + type: Types.JSONB, + defaultValue: {}, + allowNull: false, + }, + created_at: { + type: Types.DATE, + defaultValue: Types.fn('now'), + allowNull: false, + }, + updated_at: { + type: Types.DATE, + defaultValue: Types.fn('now'), + allowNull: false, + }, + deleted_at: { + type: Types.DATE, + defaultValue: null, + allowNull: true, + }, + }) + }, + + down: (migration, Types) => { + return migration.dropTable('uploads') + }, +} diff --git a/database/migrations/20210000000002-create-surveys-table.js b/database/migrations/20210000000002-create-surveys-table.js new file mode 100644 index 0000000000000000000000000000000000000000..cb63aa4995d4f071381fa10d8da5d99de5879cc7 --- /dev/null +++ b/database/migrations/20210000000002-create-surveys-table.js @@ -0,0 +1,86 @@ +module.exports = { + up: (migration, Types) => { + return migration.createTable('surveys', { + id: { + type: Types.UUID, + primaryKey: true, + defaultValue: Types.UUIDV4, + allowNull: false, + }, + slug: { + type: Types.TEXT, + allowNull: true, + index: true, + }, + name: { + type: Types.TEXT, + allowNull: false, + }, + header_image_url: { + type: Types.TEXT, + allowNull: false, + }, + partner_names: { + type: Types.ARRAY(Types.TEXT), + allowNull: false, + }, + description: { + type: Types.JSONB, + allowNull: false, + default: [] + }, + requirements: { + type: Types.JSONB, + allowNull: false, + default: [] + }, + settings: { + type: Types.JSONB, + allowNull: false, + default: [] + }, + properties: { + type: Types.JSONB, + allowNull: false, + default: {} + }, + public: { + type: Types.BOOLEAN, + allowNull: false, + }, + published_at: { + type: Types.DATE, + allowNull: true, + default: null, + }, + expires_at: { + type: Types.DATE, + allowNull: false, + }, + meta: { + type: Types.JSONB, + defaultValue: {}, + allowNull: false, + }, + created_at: { + type: Types.DATE, + defaultValue: Types.fn('now'), + allowNull: false, + }, + updated_at: { + type: Types.DATE, + defaultValue: Types.fn('now'), + allowNull: false, + }, + deleted_at: { + type: Types.DATE, + defaultValue: null, + allowNull: true, + }, + }) + }, + + down: (migration, Types) => { + return migration.dropTable('surveys') + }, +} diff --git a/database/migrations/20210000000003-create-survey-users-table.js b/database/migrations/20210000000003-create-survey-users-table.js new file mode 100644 index 0000000000000000000000000000000000000000..306999a7aa9d7c9c7e8f70eaf4ffe268225624d0 --- /dev/null +++ b/database/migrations/20210000000003-create-survey-users-table.js @@ -0,0 +1,36 @@ +module.exports = { + up: (migration, Types) => { + return migration.createTable('survey_users', { + survey_id: { + type: Types.UUID, + allowNull: false, + references: { + model: 'surveys', + key: 'id', + }, + }, + user_id: { + type: Types.UUID, + allowNull: true, + references: { + model: 'users', + key: 'id', + }, + }, + properties: { + type: Types.JSONB, + allowNull: false, + default: {} + }, + created_at: { + type: Types.DATE, + defaultValue: Types.fn('now'), + allowNull: false, + }, + }) + }, + + down: (migration, Types) => { + return migration.dropTable('survey_users') + }, +} diff --git a/database/migrations/20210000000004-add-oauth-client-name-description.js b/database/migrations/20210000000004-add-oauth-client-name-description.js new file mode 100644 index 0000000000000000000000000000000000000000..202dc71cdd8fc7e82d295bd607605c1569a46543 --- /dev/null +++ b/database/migrations/20210000000004-add-oauth-client-name-description.js @@ -0,0 +1,30 @@ +module.exports = { + up: (migration, Types) => { + return migration.sequelize.transaction(async t => { + await migration.addColumn('oauth_clients', 'name', { + type: Types.TEXT, + defaultValue: '', + allowNull: false, + }, { + transaction: t + }) + await migration.addColumn('oauth_clients', 'description', { + type: Types.TEXT, + defaultValue: '', + allowNull: false, + }, { + transaction: t + }) + }) + }, + down: (migration, Types) => { + return migration.sequelize.transaction(async t => { + await migration.removeColumn('oauth_clients', 'description', { + transaction: t + }) + await migration.removeColumn('oauth_clients', 'name', { + transaction: t + }) + }) + }, +} diff --git a/docker-compose.yml b/docker-compose.yml index f324da52b96cf6386f0f58c521654857bab8321c..2ae61a811f85d119bc24d4b2a30768d11a7782ce 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,6 +2,7 @@ version: '3.3' services: redis: image: 'redis:6' + restart: on-failure ports: - '25000:6379' volumes: @@ -10,6 +11,7 @@ services: tech.jetsam.environment: 'staging' amqp: image: 'rabbitmq:3-management' + restart: on-failure hostname: jetsam_rabbit ports: - '25001:5672' @@ -18,14 +20,36 @@ services: - ./.dck/rabbit:/data labels: tech.jetsam.environment: 'staging' - hsaura: - image: hasura/graphql-engine:v1.3.3 - ports: - - "25003:8080" - network_mode: "host" + postgres: + image: timescale/timescaledb-postgis:latest-pg13 + restart: on-failure + volumes: + - ./.dck/pg:/var/lib/postgresql/data environment: - HASURA_GRAPHQL_DATABASE_URL: postgres://jetsam:jetsam@localhost:5432/jetsam - HASURA_GRAPHQL_ENABLE_CONSOLE: "true" - HASURA_GRAPHQL_DEV_MODE: "true" - HASURA_GRAPHQL_ADMIN_SECRET: "secret_key" - HASURA_GRAPHQL_JWT_SECRET: '{"jwk_url":"http://localhost:7123/.well-known/jwks.json","claims_map":{"x-hasura-user-id":{"path":"$$.session.id"},"x-hasura-allowed-roles":{"path":"$$.session.roles"},"x-hasura-default-role":{"path":"$$.session.roles[0]"}}}' \ No newline at end of file + POSTGRES_USER: jetsam + POSTGRES_PASSWORD: jetsam + POSTGRES_DB: jetsam + ports: + - "5432:5432" + labels: + tech.jetsam.environment: 'staging' + graphql-engine: + image: hasura/graphql-engine:v2.0.10 + restart: on-failure + ports: + - "15432:8080" + depends_on: + - "postgres" + env_file: + - hasura/.env +# hsaura: +# image: hasura/graphql-engine:v1.3.3 +# ports: +# - "25003:8080" +# network_mode: "host" +# environment: +# HASURA_GRAPHQL_DATABASE_URL: postgres://jetsam:jetsam@localhost:5432/jetsam +# HASURA_GRAPHQL_ENABLE_CONSOLE: "true" +# HASURA_GRAPHQL_DEV_MODE: "true" +# HASURA_GRAPHQL_ADMIN_SECRET: "secret_key" +# HASURA_GRAPHQL_JWT_SECRET: '{"jwk_url":"http://localhost:7123/.well-known/jwks.json","claims_map":{"x-hasura-user-id":{"path":"$$.session.id"},"x-hasura-allowed-roles":{"path":"$$.session.roles"},"x-hasura-default-role":{"path":"$$.session.roles[0]"}}}' \ No newline at end of file diff --git a/hasura/config.yaml b/hasura/config.yaml new file mode 100644 index 0000000000000000000000000000000000000000..85d6ce2a3c7285e4fa45de946f53a42991639060 --- /dev/null +++ b/hasura/config.yaml @@ -0,0 +1,6 @@ +version: 3 +endpoint: http://localhost:15432 +metadata_directory: metadata +actions: + kind: synchronous + handler_webhook_baseurl: "http://172.17.0.1:7124/api" diff --git a/hasura/jwk_props_dev.json b/hasura/jwk_props_dev.json new file mode 100644 index 0000000000000000000000000000000000000000..84d71062d53fbef34d6cea5478255c221f954f67 --- /dev/null +++ b/hasura/jwk_props_dev.json @@ -0,0 +1,13 @@ +{ + "jwk_url": "http://172.17.0.1:7124/.well-known/jwks.json", + "header": { + "type": "Authorization" + }, + "issuer": "urn:hackerfest:systems:auth", + "claims_namespace": "urn:hackerfest:resources:claims", + "claims_map": { + "x-hasura-user-id": { "path": "$$['urn:hackerfest:resources:claims']['user-id']" }, + "x-hasura-default-role": { "path": "$$['urn:hackerfest:resources:claims']['default-role']" }, + "x-hasura-allowed-roles": { "path": "$$['urn:hackerfest:resources:claims']['allowed-roles']" } + } +} \ No newline at end of file diff --git a/hasura/metadata/actions.graphql b/hasura/metadata/actions.graphql new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/hasura/metadata/actions.yaml b/hasura/metadata/actions.yaml new file mode 100644 index 0000000000000000000000000000000000000000..1edb4c2ffc54522b4a3fff02fbbee9dd1690b565 --- /dev/null +++ b/hasura/metadata/actions.yaml @@ -0,0 +1,6 @@ +actions: [] +custom_types: + enums: [] + input_objects: [] + objects: [] + scalars: [] diff --git a/hasura/metadata/allow_list.yaml b/hasura/metadata/allow_list.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fe51488c7066f6687ef680d6bfaa4f7768ef205c --- /dev/null +++ b/hasura/metadata/allow_list.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/metadata/cron_triggers.yaml b/hasura/metadata/cron_triggers.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fe51488c7066f6687ef680d6bfaa4f7768ef205c --- /dev/null +++ b/hasura/metadata/cron_triggers.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/metadata/databases/databases.yaml b/hasura/metadata/databases/databases.yaml new file mode 100644 index 0000000000000000000000000000000000000000..65a11b202ed88526ac3cff9018de41a763814fd9 --- /dev/null +++ b/hasura/metadata/databases/databases.yaml @@ -0,0 +1,14 @@ +- name: default + kind: postgres + configuration: + connection_info: + database_url: + from_env: HASURA_GRAPHQL_DATABASE_URL + isolation_level: read-committed + pool_settings: + connection_lifetime: 600 + idle_timeout: 180 + max_connections: 50 + retries: 1 + use_prepared_statements: true + tables: "!include default/tables/tables.yaml" diff --git a/hasura/metadata/databases/default/tables/public_analytics.yaml b/hasura/metadata/databases/default/tables/public_analytics.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ec71a3b68fe56dafe840f395bcbe31b5cc012949 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_analytics.yaml @@ -0,0 +1,32 @@ +table: + name: analytics + schema: public +object_relationships: +- name: parent + using: + foreign_key_constraint_on: parent_id +array_relationships: +- name: children + using: + foreign_key_constraint_on: + column: parent_id + table: + name: analytics + schema: public +select_permissions: +- permission: + allow_aggregations: true + columns: + - id + - session_id + - action + - event + - start_time + - end_time + - parent_id + - properties + - location + - device + - meta + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_bundle_codes.yaml b/hasura/metadata/databases/default/tables/public_bundle_codes.yaml new file mode 100644 index 0000000000000000000000000000000000000000..d49af64c4cebe385f7b86e0ce85e87a5b91f7333 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_bundle_codes.yaml @@ -0,0 +1,25 @@ +table: + name: bundle_codes + schema: public +array_relationships: +- name: user_bundle_codes + using: + foreign_key_constraint_on: + column: bundle_code_id + table: + name: user_bundle_codes + schema: public +select_permissions: +- permission: + allow_aggregations: true + columns: + - id + - name + - description + - platforms + - meta + - created_at + - updated_at + - deleted_at + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_files.yaml b/hasura/metadata/databases/default/tables/public_files.yaml new file mode 100644 index 0000000000000000000000000000000000000000..e82bf5f883b26a5adb457bebaf1efa350aaf61a9 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_files.yaml @@ -0,0 +1,45 @@ +table: + name: files + schema: public +object_relationships: +- name: files_search_index + using: + foreign_key_constraint_on: + column: file_id + table: + name: files_search_index + schema: public +- name: user + using: + foreign_key_constraint_on: user_id +array_relationships: +- name: user_file_likes + using: + foreign_key_constraint_on: + column: file_id + table: + name: user_file_likes + schema: public +select_permissions: +- permission: + allow_aggregations: true + columns: + - id + - user_id + - provider + - file_root + - file_name + - stream + - comment + - tags + - labels + - featured + - requires_approval + - approved + - meta + - created_at + - updated_at + - deleted_at + - featured_at + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_files_search_index.yaml b/hasura/metadata/databases/default/tables/public_files_search_index.yaml new file mode 100644 index 0000000000000000000000000000000000000000..183be4b89af525732c2a9b45240d6ad434c578d7 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_files_search_index.yaml @@ -0,0 +1,15 @@ +table: + name: files_search_index + schema: public +object_relationships: +- name: file + using: + foreign_key_constraint_on: file_id +select_permissions: +- permission: + allow_aggregations: true + columns: + - file_id + - search_index + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_metrics.yaml b/hasura/metadata/databases/default/tables/public_metrics.yaml new file mode 100644 index 0000000000000000000000000000000000000000..72a28305f5ca224b7a06b9fe54f5f1056296e8c8 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_metrics.yaml @@ -0,0 +1,21 @@ +table: + name: metrics + schema: public +object_relationships: +- name: user + using: + foreign_key_constraint_on: author_id +select_permissions: +- permission: + allow_aggregations: true + columns: + - id + - value + - type + - location + - author_id + - meta + - recorded_at + - deleted_at + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_oauth_access_tokens.yaml b/hasura/metadata/databases/default/tables/public_oauth_access_tokens.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fbcc3007bb0429c27192fb9cbb4726f86200fa24 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_oauth_access_tokens.yaml @@ -0,0 +1,10 @@ +table: + name: oauth_access_tokens + schema: public +object_relationships: +- name: oauth_client + using: + foreign_key_constraint_on: client_id +- name: user + using: + foreign_key_constraint_on: user_id diff --git a/hasura/metadata/databases/default/tables/public_oauth_authorization_codes.yaml b/hasura/metadata/databases/default/tables/public_oauth_authorization_codes.yaml new file mode 100644 index 0000000000000000000000000000000000000000..eafee9b233460a27823462a01d7a3d0d592f6c6f --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_oauth_authorization_codes.yaml @@ -0,0 +1,10 @@ +table: + name: oauth_authorization_codes + schema: public +object_relationships: +- name: oauth_client + using: + foreign_key_constraint_on: client_id +- name: user + using: + foreign_key_constraint_on: user_id diff --git a/hasura/metadata/databases/default/tables/public_oauth_clients.yaml b/hasura/metadata/databases/default/tables/public_oauth_clients.yaml new file mode 100644 index 0000000000000000000000000000000000000000..749d7f3013648dd033e6f4fd50731aa2422ec78a --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_oauth_clients.yaml @@ -0,0 +1,47 @@ +table: + name: oauth_clients + schema: public +object_relationships: +- name: user + using: + foreign_key_constraint_on: owner_id +array_relationships: +- name: oauth_access_tokens + using: + foreign_key_constraint_on: + column: client_id + table: + name: oauth_access_tokens + schema: public +- name: oauth_authorization_codes + using: + foreign_key_constraint_on: + column: client_id + table: + name: oauth_authorization_codes + schema: public +- name: oauth_refresh_tokens + using: + foreign_key_constraint_on: + column: client_id + table: + name: oauth_refresh_tokens + schema: public +select_permissions: +- permission: + allow_aggregations: true + columns: + - id + - secret + - owner_id + - redirect_uris + - grant_types + - internal + - meta + - created_at + - updated_at + - deleted_at + - name + - description + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_oauth_refresh_tokens.yaml b/hasura/metadata/databases/default/tables/public_oauth_refresh_tokens.yaml new file mode 100644 index 0000000000000000000000000000000000000000..4aed769d5606c429a451b489ccbfc553f5fe0232 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_oauth_refresh_tokens.yaml @@ -0,0 +1,10 @@ +table: + name: oauth_refresh_tokens + schema: public +object_relationships: +- name: oauth_client + using: + foreign_key_constraint_on: client_id +- name: user + using: + foreign_key_constraint_on: user_id diff --git a/hasura/metadata/databases/default/tables/public_survey_users.yaml b/hasura/metadata/databases/default/tables/public_survey_users.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c598f860cbcd9a6be63586d4df9da0ac84a824ad --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_survey_users.yaml @@ -0,0 +1,20 @@ +table: + name: survey_users + schema: public +object_relationships: +- name: survey + using: + foreign_key_constraint_on: survey_id +- name: user + using: + foreign_key_constraint_on: user_id +select_permissions: +- permission: + allow_aggregations: true + columns: + - survey_id + - user_id + - properties + - created_at + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_surveys.yaml b/hasura/metadata/databases/default/tables/public_surveys.yaml new file mode 100644 index 0000000000000000000000000000000000000000..c39d8d01a7749b8408cf87ca305b9cc88ff97c59 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_surveys.yaml @@ -0,0 +1,33 @@ +table: + name: surveys + schema: public +array_relationships: +- name: survey_users + using: + foreign_key_constraint_on: + column: survey_id + table: + name: survey_users + schema: public +select_permissions: +- permission: + allow_aggregations: true + columns: + - id + - slug + - name + - header_image_url + - partner_names + - description + - requirements + - settings + - properties + - public + - published_at + - expires_at + - meta + - created_at + - updated_at + - deleted_at + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_uploads.yaml b/hasura/metadata/databases/default/tables/public_uploads.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0d2f61c89ee2d31d5a71786a826b903b72d805c7 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_uploads.yaml @@ -0,0 +1,25 @@ +table: + name: uploads + schema: public +object_relationships: +- name: user + using: + foreign_key_constraint_on: user_id +select_permissions: +- permission: + allow_aggregations: true + columns: + - id + - user_id + - provider + - upload_url + - request_params + - expires_at + - status + - status_reason + - meta + - created_at + - updated_at + - deleted_at + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_user_bundle_codes.yaml b/hasura/metadata/databases/default/tables/public_user_bundle_codes.yaml new file mode 100644 index 0000000000000000000000000000000000000000..2044a9c5741092ffa37ba9d502e3faeb82a739cb --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_user_bundle_codes.yaml @@ -0,0 +1,18 @@ +table: + name: user_bundle_codes + schema: public +object_relationships: +- name: bundle_code + using: + foreign_key_constraint_on: bundle_code_id +- name: user + using: + foreign_key_constraint_on: user_id +select_permissions: +- permission: + allow_aggregations: true + columns: + - user_id + - bundle_code_id + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_user_file_likes.yaml b/hasura/metadata/databases/default/tables/public_user_file_likes.yaml new file mode 100644 index 0000000000000000000000000000000000000000..cb1016fd9d75793e6e9d220d713a1dbf016a6434 --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_user_file_likes.yaml @@ -0,0 +1,21 @@ +table: + name: user_file_likes + schema: public +object_relationships: +- name: file + using: + foreign_key_constraint_on: file_id +- name: user + using: + foreign_key_constraint_on: user_id +select_permissions: +- permission: + allow_aggregations: true + columns: + - user_id + - file_id + - created_at + - updated_at + - deleted_at + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/public_users.yaml b/hasura/metadata/databases/default/tables/public_users.yaml new file mode 100644 index 0000000000000000000000000000000000000000..3a2f1badf32a0e7a9c6c4d139ce7b0fa772685bb --- /dev/null +++ b/hasura/metadata/databases/default/tables/public_users.yaml @@ -0,0 +1,89 @@ +table: + name: users + schema: public +array_relationships: +- name: files + using: + foreign_key_constraint_on: + column: user_id + table: + name: files + schema: public +- name: metrics + using: + foreign_key_constraint_on: + column: author_id + table: + name: metrics + schema: public +- name: oauth_access_tokens + using: + foreign_key_constraint_on: + column: user_id + table: + name: oauth_access_tokens + schema: public +- name: oauth_authorization_codes + using: + foreign_key_constraint_on: + column: user_id + table: + name: oauth_authorization_codes + schema: public +- name: oauth_clients + using: + foreign_key_constraint_on: + column: owner_id + table: + name: oauth_clients + schema: public +- name: oauth_refresh_tokens + using: + foreign_key_constraint_on: + column: user_id + table: + name: oauth_refresh_tokens + schema: public +- name: survey_users + using: + foreign_key_constraint_on: + column: user_id + table: + name: survey_users + schema: public +- name: uploads + using: + foreign_key_constraint_on: + column: user_id + table: + name: uploads + schema: public +- name: user_bundle_codes + using: + foreign_key_constraint_on: + column: user_id + table: + name: user_bundle_codes + schema: public +- name: user_file_likes + using: + foreign_key_constraint_on: + column: user_id + table: + name: user_file_likes + schema: public +select_permissions: +- permission: + allow_aggregations: true + columns: + - id + - name + - email + - password + - reset_token + - meta + - created_at + - updated_at + - deleted_at + filter: {} + role: overseer diff --git a/hasura/metadata/databases/default/tables/tables.yaml b/hasura/metadata/databases/default/tables/tables.yaml new file mode 100644 index 0000000000000000000000000000000000000000..ae8e81f9b3d88e5b8a35da5f395bfea4c7ab5979 --- /dev/null +++ b/hasura/metadata/databases/default/tables/tables.yaml @@ -0,0 +1,15 @@ +- "!include public_analytics.yaml" +- "!include public_bundle_codes.yaml" +- "!include public_files.yaml" +- "!include public_files_search_index.yaml" +- "!include public_metrics.yaml" +- "!include public_oauth_access_tokens.yaml" +- "!include public_oauth_authorization_codes.yaml" +- "!include public_oauth_clients.yaml" +- "!include public_oauth_refresh_tokens.yaml" +- "!include public_survey_users.yaml" +- "!include public_surveys.yaml" +- "!include public_uploads.yaml" +- "!include public_user_bundle_codes.yaml" +- "!include public_user_file_likes.yaml" +- "!include public_users.yaml" diff --git a/hasura/metadata/query_collections.yaml b/hasura/metadata/query_collections.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fe51488c7066f6687ef680d6bfaa4f7768ef205c --- /dev/null +++ b/hasura/metadata/query_collections.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/metadata/remote_schemas.yaml b/hasura/metadata/remote_schemas.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fe51488c7066f6687ef680d6bfaa4f7768ef205c --- /dev/null +++ b/hasura/metadata/remote_schemas.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/metadata/rest_endpoints.yaml b/hasura/metadata/rest_endpoints.yaml new file mode 100644 index 0000000000000000000000000000000000000000..fe51488c7066f6687ef680d6bfaa4f7768ef205c --- /dev/null +++ b/hasura/metadata/rest_endpoints.yaml @@ -0,0 +1 @@ +[] diff --git a/hasura/metadata/version.yaml b/hasura/metadata/version.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0a70affa4bdaac5b06bfd9793ffc20f5f60e9ea6 --- /dev/null +++ b/hasura/metadata/version.yaml @@ -0,0 +1 @@ +version: 3 diff --git a/helm/api/.helmignore b/helm/api/.helmignore index 0e8a0eb36f4ca2c939201c0d54b5d82a1ea34778..54be7e08c62ce99461627c4f31ba17f51836999f 100644 --- a/helm/api/.helmignore +++ b/helm/api/.helmignore @@ -21,3 +21,4 @@ .idea/ *.tmproj .vscode/ +.dck/ diff --git a/helm/api/Chart.yaml b/helm/api/Chart.yaml index 8372812027ec2a74d9aab148caa2fa9de0964ca7..8bc50c1b0216a2dcf5a6bd40b542a1eab6e531d2 100644 --- a/helm/api/Chart.yaml +++ b/helm/api/Chart.yaml @@ -15,10 +15,10 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.2.8 +version: 0.3.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "2.0.0.beta-1" +appVersion: "2.2.0" diff --git a/helm/api/templates/deployment-workers.yaml b/helm/api/templates/deployment-workers.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b195986bd9e6785cd59a66eb2a6cc3b599aeb55e --- /dev/null +++ b/helm/api/templates/deployment-workers.yaml @@ -0,0 +1,98 @@ +{{- if .Values.worker.enabled }} +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ include "api.fullname" . }}-worker" + labels: + {{- include "api.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.worker.replicaCount }} + {{- end }} + selector: + matchLabels: + service-type: queue-worker + {{- include "api.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + service-type: queue-worker + {{- include "api.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "api.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + containers: + - name: "{{ .Chart.Name }}-worker" + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + command: + - node + - worker + imagePullPolicy: {{ .Values.image.pullPolicy }} + env: + {{- toYaml .Values.environment | nindent 10 }} + - name: QUEUE_ACTION + value: consumer + - name: GCS_CREDENTIALS_B64 + valueFrom: + secretKeyRef: + name: "{{- .Values.secrets.name }}" + key: "key.gcs" + - name: SENTRY_DSN + valueFrom: + secretKeyRef: + name: "{{- .Values.secrets.name }}" + key: "dsn.sentry" + - name: SENDGRID_KEY + valueFrom: + secretKeyRef: + name: "{{- .Values.secrets.name }}" + key: "key.sendgrid" + - name: APP_KEY + valueFrom: + secretKeyRef: + name: "{{- .Values.secrets.name }}" + key: "key.app" + - name: DATABASE_CA_CERT + valueFrom: + secretKeyRef: + name: "{{- .Values.secrets.name }}" + key: "cert.database" + optional: true + {{- if .Values.server.livenessProbe.enabled }} + livenessProbe: + httpGet: + path: / + port: http + {{- end}} + {{- if .Values.server.readinessProbe.enabled }} + readinessProbe: + httpGet: + path: / + port: http + {{- end}} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- end }} \ No newline at end of file diff --git a/helm/api/values.yaml b/helm/api/values.yaml index 10a5fbd2a92cce56292ee1ad021df3e9ac792e2f..968edbf1a581c2700df7de9ec9019646975e7d1b 100644 --- a/helm/api/values.yaml +++ b/helm/api/values.yaml @@ -29,7 +29,7 @@ secrets: image: - repository: lcr.gr/jetsam/api + repository: registry.digitalocean.com/jetsam/api pullPolicy: IfNotPresent # Overrides the image tag whose default is the chart appVersion. tag: "latest" diff --git a/package-lock.json b/package-lock.json index 2adb6e0d1d7bdb5c3676ca357aad9e595bea52ae..a2d9da7a5c3db490c61358954473d62e9a429355 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,8 +1,12334 @@ { "name": "jetsam-api", - "version": "2.0.0-beta.1", - "lockfileVersion": 1, + "version": "2.2.2", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "name": "jetsam-api", + "version": "2.2.2", + "license": "GPL-3.0+", + "dependencies": { + "@commander-lol/vault-client": "^0.1.1", + "@google-cloud/storage": "^5.5.0", + "@koa/cors": "^3.1.0", + "@koa/multer": "^3.0.0", + "@koa/router": "^9.3.1", + "@sendgrid/mail": "^7.4.2", + "@sentry/node": "^6.1.0", + "@sentry/tracing": "^6.1.0", + "amqplib": "^0.6.0", + "change-case": "^4.1.1", + "dataloader": "^2.0.0", + "debug": "^4.2.0", + "dotenv": "^8.2.0", + "dotenv-expand": "^5.1.0", + "faker": "^5.5.3", + "fs-jetpack": "^2.4.0", + "handlebars": "^4.7.6", + "ioredis": "^4.17.3", + "joi": "^17.3.0", + "jose": "^3.6.1", + "koa": "^2.13.0", + "koa-bodyparser": "^4.3.0", + "koa-compress": "^5.0.1", + "koa-csrf": "^3.0.8", + "koa-etag": "^3.0.0", + "koa-logger": "^3.2.1", + "koa-mount": "^4.0.0", + "koa-session": "^6.0.0", + "koa-static": "^5.0.0", + "lodash": "^4.17.19", + "mime-types": "^2.1.27", + "moment": "^2.27.0", + "moment-range": "^4.0.2", + "multer": "^1.4.2", + "node-fetch": "^2.6.1", + "nodemailer": "^6.4.17", + "oauth2-server": "^3.1.1", + "pg": "^8.3.0", + "pg-hstore": "^2.3.3", + "pluralize": "^8.0.0", + "postmark": "^2.7.1", + "redbird": "^0.10.0", + "remarkable": "^2.0.1", + "scrypt-kdf": "^2.0.1", + "sequelize": "^6.3.3", + "sequelize-cli": "^6.2.0", + "uuid": "^8.3.1", + "yargs": "^13.3.2" + }, + "devDependencies": { + "hasura-cli": "^2.0.9", + "jest": "^26.6.3", + "nodemon": "^2.0.4", + "prettier": "^2.2.1", + "supertest": "^6.1.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://npm.lcr.gr/@babel%2fcode-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/core": { + "version": "7.12.10", + "resolved": "https://npm.lcr.gr/@babel%2fcore/-/core-7.12.10.tgz", + "integrity": "sha512-eTAlQKq65zHfkHZV0sIVODCPGVgoo1HdBlbSLi9CqOzuZanMv2ihzY+4paiKr1mH+XmYESMAmJ/dpZ68eN6d8w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.12.10", + "@babel/helper-module-transforms": "^7.12.1", + "@babel/helpers": "^7.12.5", + "@babel/parser": "^7.12.10", + "@babel/template": "^7.12.7", + "@babel/traverse": "^7.12.10", + "@babel/types": "^7.12.10", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://npm.lcr.gr/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/@babel/core/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://npm.lcr.gr/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.12.11", + "resolved": "https://npm.lcr.gr/@babel%2fgenerator/-/generator-7.12.11.tgz", + "integrity": "sha512-Ggg6WPOJtSi8yYQvLVjG8F/TlpWDlKx0OpS4Kt+xMQPs5OaGYWy+v1A+1TvxI6sAMGZpKWWoAQ1DaeQbImlItA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.11", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/generator/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://npm.lcr.gr/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.12.11", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-function-name/-/helper-function-name-7.12.11.tgz", + "integrity": "sha512-AtQKjtYNolKNi6nNNVLQ27CP6D9oFR6bq/HPYSizlzbp7uC1M59XJe8L+0uXjbIaZaUJF99ruHqVGiKXU/7ybA==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.12.10", + "@babel/template": "^7.12.7", + "@babel/types": "^7.12.11" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.12.10", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-get-function-arity/-/helper-get-function-arity-7.12.10.tgz", + "integrity": "sha512-mm0n5BPjR06wh9mPQaDdXWDoll/j5UpCAPl1x8fS71GHm7HA6Ua2V4ylG1Ju8lvcTOietbPNNPaSilKj+pj+Ag==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.10" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.12.7", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-member-expression-to-functions/-/helper-member-expression-to-functions-7.12.7.tgz", + "integrity": "sha512-DCsuPyeWxeHgh1Dus7APn7iza42i/qXqiFPWyBDdOFtvS581JQePsc1F/nD+fHrcswhLlRc2UpYS1NwERxZhHw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.7" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.12.5", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-module-imports/-/helper-module-imports-7.12.5.tgz", + "integrity": "sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.5" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.12.1", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-module-transforms/-/helper-module-transforms-7.12.1.tgz", + "integrity": "sha512-QQzehgFAZ2bbISiCpmVGfiGux8YVFXQ0abBic2Envhej22DVXV9nCFaS5hIQbkyo1AdGb+gNME2TSh3hYJVV/w==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.12.1", + "@babel/helper-replace-supers": "^7.12.1", + "@babel/helper-simple-access": "^7.12.1", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/helper-validator-identifier": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.1", + "@babel/types": "^7.12.1", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.12.10", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-optimise-call-expression/-/helper-optimise-call-expression-7.12.10.tgz", + "integrity": "sha512-4tpbU0SrSTjjt65UMWSrUOPZTsgvPgGG4S8QSTNHacKzpS51IVWGDj0yCwyeZND/i+LSN2g/O63jEXEWm49sYQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.10" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.12.11", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-replace-supers/-/helper-replace-supers-7.12.11.tgz", + "integrity": "sha512-q+w1cqmhL7R0FNzth/PLLp2N+scXEK/L2AHbXUyydxp828F4FEa5WcVoqui9vFRiHDQErj9Zof8azP32uGVTRA==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.12.7", + "@babel/helper-optimise-call-expression": "^7.12.10", + "@babel/traverse": "^7.12.10", + "@babel/types": "^7.12.11" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.12.1", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-simple-access/-/helper-simple-access-7.12.1.tgz", + "integrity": "sha512-OxBp7pMrjVewSSC8fXDFrHrBcJATOOFssZwv16F3/6Xtc138GHybBfPbm9kfiqQHKhYQrlamWILwlDCeyMFEaA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.1" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.12.11", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-split-export-declaration/-/helper-split-export-declaration-7.12.11.tgz", + "integrity": "sha512-LsIVN8j48gHgwzfocYUSkO/hjYAOJqlpJEc7tGXcIm4cubjVUf8LGW6eWRyxEu7gA25q02p0rQUWoCI33HNS5g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.12.11" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.12.11", + "resolved": "https://npm.lcr.gr/@babel%2fhelper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", + "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", + "dev": true + }, + "node_modules/@babel/helpers": { + "version": "7.12.5", + "resolved": "https://npm.lcr.gr/@babel%2fhelpers/-/helpers-7.12.5.tgz", + "integrity": "sha512-lgKGMQlKqA8meJqKsW6rUnc4MdUk35Ln0ATDqdM1a/UpARODdI4j5Y5lVfUScnSNkJcdCRAaWkspykNoFg9sJA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.12.5", + "@babel/types": "^7.12.5" + } + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://npm.lcr.gr/@babel%2fhighlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.12.11", + "resolved": "https://npm.lcr.gr/@babel%2fparser/-/parser-7.12.11.tgz", + "integrity": "sha512-N3UxG+uuF4CMYoNj8AhnbAcJF0PiuJ9KHuy1lQmkYsxTer/MAH9UBNHsBoAX/4s6NvlDD047No8mYVGGzLL4hg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.1", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.1.tgz", + "integrity": "sha512-U40A76x5gTwmESz+qiqssqmeEsKvcSyvtgktrm0uzcARAmM9I1jR221f6Oq+GmHrcD+LvZDag1UTOTe2fL3TeA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.12.1", + "resolved": "https://npm.lcr.gr/@babel%2fplugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.12.1.tgz", + "integrity": "sha512-i7ooMZFS+a/Om0crxZodrTzNEPJHZrlMVGMTEpFAj6rYY/bKCddB0Dk/YxfPuYXOopuhKk/e1jV6h+WUU9XN3A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.12.7", + "resolved": "https://npm.lcr.gr/@babel%2ftemplate/-/template-7.12.7.tgz", + "integrity": "sha512-GkDzmHS6GV7ZeXfJZ0tLRBhZcMcY0/Lnb+eEbXDBfCAcZCjrZKe6p3J4we/D24O9Y8enxWAg1cWwof59yLh2ow==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.12.7", + "@babel/types": "^7.12.7" + } + }, + "node_modules/@babel/traverse": { + "version": "7.12.12", + "resolved": "https://npm.lcr.gr/@babel%2ftraverse/-/traverse-7.12.12.tgz", + "integrity": "sha512-s88i0X0lPy45RrLM8b9mz8RPH5FqO9G9p7ti59cToE44xFm1Q+Pjh5Gq4SXBbtb88X7Uy7pexeqRIQDDMNkL0w==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.11", + "@babel/generator": "^7.12.11", + "@babel/helper-function-name": "^7.12.11", + "@babel/helper-split-export-declaration": "^7.12.11", + "@babel/parser": "^7.12.11", + "@babel/types": "^7.12.12", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/types": { + "version": "7.12.12", + "resolved": "https://npm.lcr.gr/@babel%2ftypes/-/types-7.12.12.tgz", + "integrity": "sha512-lnIX7piTxOH22xE7fDXDbSHg9MM1/6ORnafpJmov5rs0kX5g4BZxeXNJLXsMRiO0U5Rb8/FvMS6xlTnTHvxonQ==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.12.11", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://npm.lcr.gr/@bcoe%2fv8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cnakazawa/watch": { + "version": "1.0.4", + "resolved": "https://npm.lcr.gr/@cnakazawa%2fwatch/-/watch-1.0.4.tgz", + "integrity": "sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ==", + "dev": true, + "dependencies": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + }, + "bin": { + "watch": "cli.js" + }, + "engines": { + "node": ">=0.1.95" + } + }, + "node_modules/@commander-lol/vault-client": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@commander-lol/vault-client/-/vault-client-0.1.1.tgz", + "integrity": "sha512-fZDlKNIX2vF/JLOqV5zUI7QsOSnmjX8huEIt65yWDk3hMTk6Kyd2lDdcvwdjqOlwmNTRRv9OijDfOayQ0ObDEw==", + "dependencies": { + "date-fns": "^2.17.0", + "node-fetch": "^2.6.1" + } + }, + "node_modules/@google-cloud/common": { + "version": "3.5.0", + "resolved": "https://npm.lcr.gr/@google-cloud%2fcommon/-/common-3.5.0.tgz", + "integrity": "sha512-10d7ZAvKhq47L271AqvHEd8KzJqGU45TY+rwM2Z3JHuB070FeTi7oJJd7elfrnKaEvaktw3hH2wKnRWxk/3oWQ==", + "dependencies": { + "@google-cloud/projectify": "^2.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.1", + "duplexify": "^4.1.1", + "ent": "^2.2.0", + "extend": "^3.0.2", + "google-auth-library": "^6.1.1", + "retry-request": "^4.1.1", + "teeny-request": "^7.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/paginator": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@google-cloud/paginator/-/paginator-3.0.5.tgz", + "integrity": "sha512-N4Uk4BT1YuskfRhKXBs0n9Lg2YTROZc6IMpkO/8DIHODtm5s3xY8K5vVBo23v/2XulY3azwITQlYWgT4GdLsUw==", + "dependencies": { + "arrify": "^2.0.0", + "extend": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/projectify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@google-cloud/projectify/-/projectify-2.0.1.tgz", + "integrity": "sha512-ZDG38U/Yy6Zr21LaR3BTiiLtpJl6RkPS/JwoRT453G+6Q1DhlV0waNf8Lfu+YVYGIIxgKnLayJRfYlFJfiI8iQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/promisify": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@google-cloud/promisify/-/promisify-2.0.3.tgz", + "integrity": "sha512-d4VSA86eL/AFTe5xtyZX+ePUjE8dIFu2T8zmdeNBSa5/kNgXPCx/o/wbFNHAGLJdGnk1vddRuMESD9HbOC8irw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/storage": { + "version": "5.5.0", + "resolved": "https://npm.lcr.gr/@google-cloud%2fstorage/-/storage-5.5.0.tgz", + "integrity": "sha512-Pat83kHNnKJpEHUirtQtCoAJ2K3OlEo2ZcSlPjierJnEKnhbIQPyJ6mAbs/ovm3K3QDQhouKJ9QSONkFPEwQuA==", + "dependencies": { + "@google-cloud/common": "^3.3.0", + "@google-cloud/paginator": "^3.0.0", + "@google-cloud/promisify": "^2.0.0", + "arrify": "^2.0.0", + "compressible": "^2.0.12", + "date-and-time": "^0.14.0", + "duplexify": "^4.0.0", + "extend": "^3.0.2", + "gaxios": "^4.0.0", + "gcs-resumable-upload": "^3.1.0", + "get-stream": "^6.0.0", + "hash-stream-validation": "^0.2.2", + "mime": "^2.2.0", + "mime-types": "^2.0.8", + "onetime": "^5.1.0", + "p-limit": "^3.0.1", + "pumpify": "^2.0.0", + "snakeize": "^0.1.0", + "stream-events": "^1.0.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@google-cloud/storage/node_modules/get-stream": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.0.tgz", + "integrity": "sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@google-cloud/storage/node_modules/mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@google-cloud/storage/node_modules/p-limit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.0.2.tgz", + "integrity": "sha512-iwqZSOoWIW+Ew4kAGUlN16J4M7OB3ysMLSZtnhmqx7njIHFPlxWBX8xo3lVTyFVq6mI/lL9qt2IsN1sHwaxJkg==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.1.0.tgz", + "integrity": "sha512-i9YbZPN3QgfighY/1X1Pu118VUz2Fmmhd6b2n0/O8YVgGGfw0FbUYoA97k7FkpGJ+pLCFEDLUmAPPV4D1kpeFw==" + }, + "node_modules/@hapi/topo": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.0.0.tgz", + "integrity": "sha512-tFJlT47db0kMqVm3H4nQYgn6Pwg10GTZHb1pwmSiv1K4ks6drQOtfEF5ZnPjkvC+y4/bUPHK+bc87QvLcL+WMw==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://npm.lcr.gr/@istanbuljs%2fload-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://npm.lcr.gr/@istanbuljs%2fschema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/@jest%2fconsole/-/console-26.6.2.tgz", + "integrity": "sha512-IY1R2i2aLsLr7Id3S6p2BA82GNWryt4oSvEXLAKc+L2zdi89dSkE8xC1C+0kpATG4JhBJREnQOH7/zmccM2B0g==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^26.6.2", + "jest-util": "^26.6.2", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/@jest%2fcore/-/core-26.6.3.tgz", + "integrity": "sha512-xvV1kKbhfUqFVuZ8Cyo+JPpipAHHAV3kcDBftiduK8EICXmTFddryy3P7NfZt8Pv37rA9nEJBKCCkglCPt/Xjw==", + "dev": true, + "dependencies": { + "@jest/console": "^26.6.2", + "@jest/reporters": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-changed-files": "^26.6.2", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-resolve-dependencies": "^26.6.3", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "jest-watcher": "^26.6.2", + "micromatch": "^4.0.2", + "p-each-series": "^2.1.0", + "rimraf": "^3.0.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/core/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://npm.lcr.gr/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@jest/core/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/@jest%2fenvironment/-/environment-26.6.2.tgz", + "integrity": "sha512-nFy+fHl28zUrRsCeMB61VDThV1pVTtlEokBRgqPrcT1JNq4yRNIyTHfyht6PqtUvY9IsuLGTrbG8kPXjSZIZwA==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/fake-timers": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/@jest%2ffake-timers/-/fake-timers-26.6.2.tgz", + "integrity": "sha512-14Uleatt7jdzefLPYM3KLcnUl1ZNikaKq34enpb5XG9i81JpppDb5muZvonvKyrl7ftEHkKS5L5/eB/kxJ+bvA==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@sinonjs/fake-timers": "^6.0.1", + "@types/node": "*", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/globals": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/@jest%2fglobals/-/globals-26.6.2.tgz", + "integrity": "sha512-85Ltnm7HlB/KesBUuALwQ68YTU72w9H2xW9FjZ1eL1U3lhtefjjl5c2MiUbpXt/i6LaPRvoOFJ22yCBSfQ0JIA==", + "dev": true, + "dependencies": { + "@jest/environment": "^26.6.2", + "@jest/types": "^26.6.2", + "expect": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/reporters": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/@jest%2freporters/-/reporters-26.6.2.tgz", + "integrity": "sha512-h2bW53APG4HvkOnVMo8q3QXa6pcaNt1HkwVsOPMBV6LD/q9oSpxNSYZQYkAnjdMjrJ86UuYeLo+aEZClV6opnw==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.2", + "graceful-fs": "^4.2.4", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^4.0.3", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.0.2", + "jest-haste-map": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "slash": "^3.0.0", + "source-map": "^0.6.0", + "string-length": "^4.0.1", + "terminal-link": "^2.0.0", + "v8-to-istanbul": "^7.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "optionalDependencies": { + "node-notifier": "^8.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/source-map": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/@jest%2fsource-map/-/source-map-26.6.2.tgz", + "integrity": "sha512-YwYcCwAnNmOVsZ8mr3GfnzdXDAl4LaenZP5z+G0c8bzC9/dugL8zRmxZzdoTl4IaS3CryS1uWnROLPFmb6lVvA==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0", + "graceful-fs": "^4.2.4", + "source-map": "^0.6.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/test-result": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/@jest%2ftest-result/-/test-result-26.6.2.tgz", + "integrity": "sha512-5O7H5c/7YlojphYNrK02LlDIV2GNPYisKwHm2QTKjNZeEzezCbwYs9swJySv2UfPMyZ0VdsmMv7jIlD/IKYQpQ==", + "dev": true, + "dependencies": { + "@jest/console": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/@jest%2ftest-sequencer/-/test-sequencer-26.6.3.tgz", + "integrity": "sha512-YHlVIjP5nfEyjlrSr8t/YdNfU/1XEt7c5b4OxcXCjyRhjzLYu/rO69/WHPuYcbCWkz8kAeZVZp2N2+IOLLEPGw==", + "dev": true, + "dependencies": { + "@jest/test-result": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-runner": "^26.6.3", + "jest-runtime": "^26.6.3" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/transform": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/@jest%2ftransform/-/transform-26.6.2.tgz", + "integrity": "sha512-E9JjhUgNzvuQ+vVAL21vlyfy12gP0GhazGgJC4h6qUt1jSdUXGWJ1wfu/X7Sd8etSgxV4ovT1pb9v5D6QW4XgA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/types": "^26.6.2", + "babel-plugin-istanbul": "^6.0.0", + "chalk": "^4.0.0", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-haste-map": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-util": "^26.6.2", + "micromatch": "^4.0.2", + "pirates": "^4.0.1", + "slash": "^3.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/@jest%2ftypes/-/types-26.6.2.tgz", + "integrity": "sha512-fC6QCp7Sc5sX6g8Tvbmj4XUTbyrik0akgRy03yjXbQaBWWNWGE7SGtJk98m0N8nzegD/7SggrUlivxo5ax4KWQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@koa/cors": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@koa/cors/-/cors-3.1.0.tgz", + "integrity": "sha512-7ulRC1da/rBa6kj6P4g2aJfnET3z8Uf3SWu60cjbtxTA5g8lxRdX/Bd2P92EagGwwAhANeNw8T8if99rJliR6Q==", + "dependencies": { + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@koa/multer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@koa/multer/-/multer-3.0.0.tgz", + "integrity": "sha512-y+OQBmex5D1jIl723gAEUYcAWPEicIXppaAKw/zCMfpllQ08ZNweDPwoCLxEoatqd5pCu2XG6V8dl67JRq3RJw==", + "engines": { + "node": ">= 8" + }, + "peerDependencies": { + "multer": "*" + } + }, + "node_modules/@koa/router": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@koa/router/-/router-9.3.1.tgz", + "integrity": "sha512-OOy4pOEO+Zz5vy+zqc8mWRGKYIpDqjgbVTF/U41fCwBwVWHGmkedvcJ9V5MLI7Ivy0iTv8o0XLDtGWtYHquvxg==", + "dependencies": { + "debug": "^4.1.1", + "http-errors": "^1.7.3", + "koa-compose": "^4.1.0", + "methods": "^1.1.2", + "path-to-regexp": "^6.1.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@root/mkdirp": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/@root%2fmkdirp/-/mkdirp-1.0.0.tgz", + "integrity": "sha512-hxGAYUx5029VggfG+U9naAhQkoMSXtOeXtbql97m3Hi6/sQSRL/4khKZPyOF6w11glyCOU38WCNLu9nUcSjOfA==" + }, + "node_modules/@root/request": { + "version": "1.7.0", + "resolved": "https://npm.lcr.gr/@root%2frequest/-/request-1.7.0.tgz", + "integrity": "sha512-lre7XVeEwszgyrayWWb/kRn5fuJfa+n0Nh+rflM9E+EpC28yIYA+FPm/OL1uhzp3TxhQM0HFN4FE2RDIPGlnmg==" + }, + "node_modules/@sendgrid/client": { + "version": "7.4.2", + "resolved": "https://npm.lcr.gr/@sendgrid%2fclient/-/client-7.4.2.tgz", + "integrity": "sha512-bu8lLbRD+OV7YsYNemEy8DRoxs8/8u325EXNlQ3VaqhcpbM0eSvdL5e5Wa7VZpbczcNCJmf/sr/uqFmwcO5S+A==", + "dependencies": { + "@sendgrid/helpers": "^7.4.2", + "axios": "^0.21.1" + }, + "engines": { + "node": "6.* || 8.* || >=10.*" + } + }, + "node_modules/@sendgrid/helpers": { + "version": "7.4.2", + "resolved": "https://npm.lcr.gr/@sendgrid%2fhelpers/-/helpers-7.4.2.tgz", + "integrity": "sha512-b/IyBwT4zrOfXA0ISvWZsnhYz+5uAO20n68J8n/6qe5P1E2p0L7kWNTN5LYu0S7snJPUlbEa6FpfrSKzEcP9JA==", + "dependencies": { + "deepmerge": "^4.2.2" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@sendgrid/mail": { + "version": "7.4.2", + "resolved": "https://npm.lcr.gr/@sendgrid%2fmail/-/mail-7.4.2.tgz", + "integrity": "sha512-hvIOnm8c3zVyDnJcyBuAeujmpKX56N3D/LpiZrFuLHjAz4iEHrmL2sJ3iU9O6hxcb07gd1CES+z9Fg7FBT26uQ==", + "dependencies": { + "@sendgrid/client": "^7.4.2", + "@sendgrid/helpers": "^7.4.2" + }, + "engines": { + "node": "6.* || 8.* || >=10.*" + } + }, + "node_modules/@sentry/core": { + "version": "6.1.0", + "resolved": "https://npm.lcr.gr/@sentry%2fcore/-/core-6.1.0.tgz", + "integrity": "sha512-57mXkp3NoyxRycXrL+Ec6bYS6UYJZp9tYX0lUp5Ry2M0FxDZ3Q4drkjr8MIQOhBaQXP2ukSX4QTVLGMPm60zMw==", + "dependencies": { + "@sentry/hub": "6.1.0", + "@sentry/minimal": "6.1.0", + "@sentry/types": "6.1.0", + "@sentry/utils": "6.1.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/hub": { + "version": "6.1.0", + "resolved": "https://npm.lcr.gr/@sentry%2fhub/-/hub-6.1.0.tgz", + "integrity": "sha512-JnBSCgNg3VHiMojUl5tCHU8iWPVuE+qqENIzG9A722oJms1kKWBvWl+yQzhWBNdgk5qeAY3F5UzKWJZkbJ6xow==", + "dependencies": { + "@sentry/types": "6.1.0", + "@sentry/utils": "6.1.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/minimal": { + "version": "6.1.0", + "resolved": "https://npm.lcr.gr/@sentry%2fminimal/-/minimal-6.1.0.tgz", + "integrity": "sha512-g6sfNKenL7wnsr/tibp8nFiMv/XRH0s0Pt4p151npmNI+SmjuUz3GGYEXk8ChCyaKldYKilkNOFdVXJxUf5gZw==", + "dependencies": { + "@sentry/hub": "6.1.0", + "@sentry/types": "6.1.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/node": { + "version": "6.1.0", + "resolved": "https://npm.lcr.gr/@sentry%2fnode/-/node-6.1.0.tgz", + "integrity": "sha512-yOxYHoPxg8Br19QOsJbonP2uYirv1FFxdNkdeykfO2QBorRUkcirjET5qjRfz73jF1YYtUZBuxwR+f9ZOPqGTg==", + "dependencies": { + "@sentry/core": "6.1.0", + "@sentry/hub": "6.1.0", + "@sentry/tracing": "6.1.0", + "@sentry/types": "6.1.0", + "@sentry/utils": "6.1.0", + "cookie": "^0.4.1", + "https-proxy-agent": "^5.0.0", + "lru_map": "^0.3.3", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/tracing": { + "version": "6.1.0", + "resolved": "https://npm.lcr.gr/@sentry%2ftracing/-/tracing-6.1.0.tgz", + "integrity": "sha512-s6a4Ra3hHn4awiNz4fOEK6TCV2w2iLcxdppijcYEB7S/1rJpmqZgHWDicqufbOmVMOLmyKLEQ7w+pZq3TR3WgQ==", + "dependencies": { + "@sentry/hub": "6.1.0", + "@sentry/minimal": "6.1.0", + "@sentry/types": "6.1.0", + "@sentry/utils": "6.1.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/types": { + "version": "6.1.0", + "resolved": "https://npm.lcr.gr/@sentry%2ftypes/-/types-6.1.0.tgz", + "integrity": "sha512-kIaN52Fw5K+2mKRaHE2YluJ+F/qMGSUzZXIFDNdC6OUMXQ4TM8gZTrITXs8CLDm7cK8iCqFCtzKOjKK6KyOKAg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@sentry/utils": { + "version": "6.1.0", + "resolved": "https://npm.lcr.gr/@sentry%2futils/-/utils-6.1.0.tgz", + "integrity": "sha512-6JAplzUOS6bEwfX0PDRZBbYRvn9EN22kZfcL0qGHtM9L0QQ5ybjbbVwOpbXgRkiZx++dQbzLFtelxnDhsbFG+Q==", + "dependencies": { + "@sentry/types": "6.1.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.0.tgz", + "integrity": "sha512-wAH/JYRXeIFQRsxerIuLjgUu2Xszam+O5xKeatJ4oudShOOirfmsQ1D6LL54XOU2tizpCYku+s1wmU0SYdpoSA==", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz", + "integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==" + }, + "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/@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.2", + "resolved": "https://npm.lcr.gr/@sinonjs%2fcommons/-/commons-1.8.2.tgz", + "integrity": "sha512-sruwd86RJHdsVf/AtBoijDmUqJp3B6hF/DGC23C+JaegnDHaZyewCjoVGTdg3J0uz3Zs7NnIT05OBOmML72lQw==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "6.0.1", + "resolved": "https://npm.lcr.gr/@sinonjs%2ffake-timers/-/fake-timers-6.0.1.tgz", + "integrity": "sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "dependencies": { + "defer-to-connect": "^1.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/babel__core": { + "version": "7.1.12", + "resolved": "https://npm.lcr.gr/@types%2fbabel__core/-/babel__core-7.1.12.tgz", + "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://npm.lcr.gr/@types%2fbabel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.0", + "resolved": "https://npm.lcr.gr/@types%2fbabel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.11.0", + "resolved": "https://npm.lcr.gr/@types%2fbabel__traverse/-/babel__traverse-7.11.0.tgz", + "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.4", + "resolved": "https://npm.lcr.gr/@types%2fgraceful-fs/-/graceful-fs-4.1.4.tgz", + "integrity": "sha512-mWA/4zFQhfvOA8zWkXobwJvBD7vzcxgrOQ0J5CH1votGqdq9m7+FwtGaqyCZqC3NyyBkc9z4m+iry4LlqcMWJg==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.3", + "resolved": "https://npm.lcr.gr/@types%2fistanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz", + "integrity": "sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/@types%2fistanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/@types%2fistanbul-reports/-/istanbul-reports-3.0.0.tgz", + "integrity": "sha512-nwKNbvnwJ2/mndE9ItP/zc2TCzw6uuodnF4EHYWD+gCQDVBuRQL5UzbZD0/ezy1iKsFU2ZQiDqg4M9dN4+wZgA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/node": { + "version": "14.0.22", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.22.tgz", + "integrity": "sha512-emeGcJvdiZ4Z3ohbmw93E/64jRzUHAItSHt8nF7M4TGgQTiWqFVGB8KNpLGFmUHmHLvjvBgFwVlqNcq+VuGv9g==" + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.0", + "resolved": "https://npm.lcr.gr/@types%2fnormalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==", + "dev": true + }, + "node_modules/@types/prettier": { + "version": "2.1.6", + "resolved": "https://npm.lcr.gr/@types%2fprettier/-/prettier-2.1.6.tgz", + "integrity": "sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA==", + "dev": true + }, + "node_modules/@types/stack-utils": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/@types%2fstack-utils/-/stack-utils-2.0.0.tgz", + "integrity": "sha512-RJJrrySY7A8havqpGObOB4W92QXKJo63/jFLLgpvOtsGUqbQZ9Sbgl35KMm1DjC6j7AvmmU2bIno+3IyEaemaw==", + "dev": true + }, + "node_modules/@types/yargs": { + "version": "15.0.13", + "resolved": "https://npm.lcr.gr/@types%2fyargs/-/yargs-15.0.13.tgz", + "integrity": "sha512-kQ5JNTrbDv3Rp5X2n/iUu37IJBDU2gsZ5R/g1/KHOOEc5IKfUFjXT6DENPGduh08I/pamwtEq4oul7gUqKTQDQ==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "20.2.0", + "resolved": "https://npm.lcr.gr/@types%2fyargs-parser/-/yargs-parser-20.2.0.tgz", + "integrity": "sha512-37RSHht+gzzgYeobbG+KWryeAW8J33Nhr69cjTqSYymXVZEN9NbRYWoYlRtDhHKPVT1FyNKwaTPC1NynKZpzRA==", + "dev": true + }, + "node_modules/abab": { + "version": "2.0.5", + "resolved": "https://npm.lcr.gr/abab/-/abab-2.0.5.tgz", + "integrity": "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acme": { + "version": "1.3.5", + "resolved": "https://npm.lcr.gr/acme/-/acme-1.3.5.tgz", + "integrity": "sha512-KIFVyMho7y3RxRSTzkuX031TmfXwzl0ioy8+r2pnfLz6YWFQ5q7a/cYUDTgIbrFMPe/syY26Qv1DOdHQ5ARWcw==", + "dependencies": { + "acme-v2": "^1.8.6" + } + }, + "node_modules/acme-dns-01-cli": { + "version": "3.0.7", + "resolved": "https://npm.lcr.gr/acme-dns-01-cli/-/acme-dns-01-cli-3.0.7.tgz", + "integrity": "sha512-Aa4bUpq6ftX1VODiShOetOY5U0tsXY5EV7+fQwme3Q8Y9rjYBArBXHgFCAVKtK1AF+Ev8pIuF6Z42hzMFa73/w==" + }, + "node_modules/acme-v2": { + "version": "1.8.6", + "resolved": "https://npm.lcr.gr/acme-v2/-/acme-v2-1.8.6.tgz", + "integrity": "sha512-LWdicUYHTGDtYX7LlgsQurmM9txwfAFydg7mQLPKHrFMnNNtfJEtHC2fWfr+pFGNb3XKIbvyFUoyFB6cOmWRpA==", + "hasInstallScript": true, + "dependencies": { + "@root/request": "^1.3.11", + "rsa-compat": "^2.0.8" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://npm.lcr.gr/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-globals": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/acorn-globals/-/acorn-globals-6.0.0.tgz", + "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", + "dev": true, + "dependencies": { + "acorn": "^7.1.1", + "acorn-walk": "^7.1.1" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.3", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.3.tgz", + "integrity": "sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/amqplib": { + "version": "0.6.0", + "resolved": "https://npm.lcr.gr/amqplib/-/amqplib-0.6.0.tgz", + "integrity": "sha512-zXCh4jQ77TBZe1YtvZ1n7sUxnTjnNagpy8MVi2yc1ive239pS3iLwm4e4d5o4XZGx1BdTKQ/U0ZmaDU3c8MxYQ==", + "dependencies": { + "bitsyntax": "~0.1.0", + "bluebird": "^3.5.2", + "buffer-more-ints": "~1.0.0", + "readable-stream": "1.x >=1.1.9", + "safe-buffer": "~5.1.2", + "url-parse": "~1.4.3" + }, + "engines": { + "node": ">=0.8 <=14" + } + }, + "node_modules/amqplib/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://npm.lcr.gr/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/amqplib/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://npm.lcr.gr/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "dependencies": { + "string-width": "^3.0.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.1", + "resolved": "https://npm.lcr.gr/ansi-escapes/-/ansi-escapes-4.3.1.tgz", + "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", + "dev": true, + "dependencies": { + "type-fest": "^0.11.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.11.0", + "resolved": "https://npm.lcr.gr/type-fest/-/type-fest-0.11.0.tgz", + "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY=" + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/arr-diff": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-flatten": { + "version": "1.1.0", + "resolved": "https://npm.lcr.gr/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arr-union": { + "version": "3.1.0", + "resolved": "https://npm.lcr.gr/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-unique": { + "version": "0.3.2", + "resolved": "https://npm.lcr.gr/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assign-symbols": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "node_modules/atob": { + "version": "2.1.2", + "resolved": "https://npm.lcr.gr/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true, + "bin": { + "atob": "bin/atob.js" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/autolinker": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-3.14.1.tgz", + "integrity": "sha512-yvsRHIaY51EYDml6MGlbqyJGfl4n7zezGYf+R7gvM8c5LNpRGc4SISkvgAswSS8SWxk/OrGCylKV9mJyVstz7w==", + "dependencies": { + "tslib": "^1.9.3" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz", + "integrity": "sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA==" + }, + "node_modules/axios": { + "version": "0.21.1", + "resolved": "https://npm.lcr.gr/axios/-/axios-0.21.1.tgz", + "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", + "dependencies": { + "follow-redirects": "^1.10.0" + } + }, + "node_modules/babel-jest": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/babel-jest/-/babel-jest-26.6.3.tgz", + "integrity": "sha512-pl4Q+GAVOHwvjrck6jKjvmGhnO3jHX/xuB9d27f+EJZ/6k+6nMuPjorrYp7s++bKKdANwzElBWnLWaObvTnaZA==", + "dev": true, + "dependencies": { + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/babel__core": "^7.1.7", + "babel-plugin-istanbul": "^6.0.0", + "babel-preset-jest": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz", + "integrity": "sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^4.0.0", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.6.2.tgz", + "integrity": "sha512-PO9t0697lNTmcEHH69mdtYiOIkkOlj9fySqfO3K1eCcdISevLAE0xY59VLLUj0SoiPiTX/JU2CYFpILydUa5Lw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.0.0", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://npm.lcr.gr/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/babel-preset-jest/-/babel-preset-jest-26.6.2.tgz", + "integrity": "sha512-YvdtlVm9t3k777c5NPQIv6cxFFFapys25HiUmuSgHwIZhfifweR5c5Sf5nwE3MAbfu327CYSvps8Yx6ANLyleQ==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^26.6.2", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/base": { + "version": "0.11.2", + "resolved": "https://npm.lcr.gr/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "dependencies": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://npm.lcr.gr/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==" + }, + "node_modules/basic-auth": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/bignumber.js": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.1.tgz", + "integrity": "sha512-IdZR9mh6ahOBv/hYGiXyVuyCetmGJhtYkqLBpTStdhEGjegpPlUawydyaF3pbIOFynJTpllEs+NP+CS9jKFLjA==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://npm.lcr.gr/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bitsyntax": { + "version": "0.1.0", + "resolved": "https://npm.lcr.gr/bitsyntax/-/bitsyntax-0.1.0.tgz", + "integrity": "sha512-ikAdCnrloKmFOugAfxWws89/fPc+nw0OOG1IzIE72uSOg/A3cYptKCjSUhDTuj7fhsJtzkzlv7l3b8PzRHLN0Q==", + "dependencies": { + "buffer-more-ints": "~1.0.0", + "debug": "~2.6.9", + "safe-buffer": "~5.1.2" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/bitsyntax/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://npm.lcr.gr/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/bitsyntax/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" + }, + "node_modules/boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/boxen/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==", + "dev": true + }, + "node_modules/boxen/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==", + "dev": true + }, + "node_modules/boxen/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/boxen/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-process-hrtime": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", + "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", + "dev": true + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://npm.lcr.gr/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.6.0.tgz", + "integrity": "sha512-/gDYp/UtU0eA1ys8bOs9J6a+E/KWIY+DZ+Q2WESNUA0jFRsJOc0SNUO6xJ5SGA1xueg3NL65W6s+NY5l9cunuw==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "node_modules/buffer-more-ints": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/buffer-more-ints/-/buffer-more-ints-1.0.0.tgz", + "integrity": "sha512-EMetuGFz5SLsT0QTnXzINh4Ksr+oo4i+UGTXEshiGCQWnsgSs7ZhJ8fzlwQ+OzEMs0MpDAMr1hxnblp5a4vcHg==" + }, + "node_modules/buffer-writer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", + "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/busboy": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz", + "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=", + "dependencies": { + "dicer": "0.2.5", + "readable-stream": "1.1.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/busboy/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/busboy/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cache-base": { + "version": "1.0.1", + "resolved": "https://npm.lcr.gr/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "dependencies": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cache-content-type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", + "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", + "dependencies": { + "mime-types": "^2.1.18", + "ylru": "^1.2.0" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/get-stream": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.1.0.tgz", + "integrity": "sha512-EXr1FOzrzTfGeL0gQdeFEvOMm2mzMOglyiOXSTpPC+iAjAKftbr3jpCMWynogwYnM+eSj9sHGc6wjIcDvYiygw==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cacheable-request/node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://npm.lcr.gr/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camel-case": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.1.tgz", + "integrity": "sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q==", + "dependencies": { + "pascal-case": "^3.1.1", + "tslib": "^1.10.0" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/capital-case": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/capital-case/-/capital-case-1.0.3.tgz", + "integrity": "sha512-OlUSJpUr7SY0uZFOxcwnDOU7/MpHlKTZx2mqnDYQFrDudXLFm0JJ9wr/l4csB+rh2Ug0OPuoSO53PqiZBqno9A==", + "dependencies": { + "no-case": "^3.0.3", + "tslib": "^1.10.0", + "upper-case-first": "^2.0.1" + } + }, + "node_modules/capture-exit": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "dependencies": { + "rsvp": "^4.8.4" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "node_modules/cert-info": { + "version": "1.5.1", + "resolved": "https://npm.lcr.gr/cert-info/-/cert-info-1.5.1.tgz", + "integrity": "sha512-eoQC/yAgW3gKTKxjzyClvi+UzuY97YCjcl+lSqbsGIy7HeGaWxCPOQFivhUYm27hgsBMhsJJFya3kGvK6PMIcQ==", + "bin": { + "cert-info": "bin/cert-info.js" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/change-case": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-4.1.1.tgz", + "integrity": "sha512-qRlUWn/hXnX1R1LBDF/RelJLiqNjKjUqlmuBVSEIyye8kq49CXqkZWKmi8XeUAdDXWFOcGLUMZ+aHn3Q5lzUXw==", + "dependencies": { + "camel-case": "^4.1.1", + "capital-case": "^1.0.3", + "constant-case": "^3.0.3", + "dot-case": "^3.0.3", + "header-case": "^2.0.3", + "no-case": "^3.0.3", + "param-case": "^3.0.3", + "pascal-case": "^3.1.1", + "path-case": "^3.0.3", + "sentence-case": "^3.0.3", + "snake-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://npm.lcr.gr/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/chokidar": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.0.tgz", + "integrity": "sha512-aXAaho2VJtisB/1fg1+3nlLJqGOuewTzQpd/Tz0yTg2R0e4IGtshYvtjowyEumcBv2z+y4+kc75Mz7j5xJskcQ==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "node_modules/cjs-module-lexer": { + "version": "0.6.0", + "resolved": "https://npm.lcr.gr/cjs-module-lexer/-/cjs-module-lexer-0.6.0.tgz", + "integrity": "sha512-uc2Vix1frTfnuzxxu1Hp4ktSvM3QaI4oXl4ZUqL1wjTu/BGki9TrCWoqLTg/drR1KwAEarXuRFCG2Svr1GxPFw==", + "dev": true + }, + "node_modules/class-utils": { + "version": "0.3.6", + "resolved": "https://npm.lcr.gr/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/class-utils/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://npm.lcr.gr/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cli-boxes": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.0.tgz", + "integrity": "sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-color": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.4.0.tgz", + "integrity": "sha512-xu6RvQqqrWEo6MPR1eixqGPywhYBHRs653F9jfXB2Hx4jdM/3WxiNE1vppRmxtMIfl16SFYTpYlrnqH/HsK/2w==", + "dependencies": { + "ansi-regex": "^2.1.1", + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "memoizee": "^0.4.14", + "timers-ext": "^0.1.5" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz", + "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/co-bluebird": { + "version": "1.1.0", + "resolved": "https://npm.lcr.gr/co-bluebird/-/co-bluebird-1.1.0.tgz", + "integrity": "sha1-yLnzqTIKftMJh9zKGlw8/1llXHw=", + "dependencies": { + "bluebird": "^2.10.0", + "co-use": "^1.1.0" + }, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/co-bluebird/node_modules/bluebird": { + "version": "2.11.0", + "resolved": "https://npm.lcr.gr/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + }, + "node_modules/co-body": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.0.0.tgz", + "integrity": "sha512-9ZIcixguuuKIptnY8yemEOuhb71L/lLf+Rl5JfJEUiDNJk0e02MBt7BPxR2GEh5mw8dPthQYR4jPI/BnS1MQgw==", + "dependencies": { + "inflation": "^2.0.0", + "qs": "^6.5.2", + "raw-body": "^2.3.3", + "type-is": "^1.6.16" + } + }, + "node_modules/co-use": { + "version": "1.1.0", + "resolved": "https://npm.lcr.gr/co-use/-/co-use-1.1.0.tgz", + "integrity": "sha1-xrs83xDLc17Kqdru2kbXJclKTmI=", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://npm.lcr.gr/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/collection-visit": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "dependencies": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.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": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/component-emitter": { + "version": "1.3.0", + "resolved": "https://npm.lcr.gr/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/concat-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/concat-stream/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/concat-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dependencies": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/constant-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-3.0.3.tgz", + "integrity": "sha512-FXtsSnnrFYpzDmvwDGQW+l8XK3GV1coLyBN0eBz16ZUzGaZcT2ANVCJmLeuw2GQgxKHQIe9e0w2dzkSfaRlUmA==", + "dependencies": { + "no-case": "^3.0.3", + "tslib": "^1.10.0", + "upper-case": "^2.0.1" + } + }, + "node_modules/content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "dependencies": { + "safe-buffer": "5.1.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://npm.lcr.gr/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://npm.lcr.gr/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookiejar": { + "version": "2.1.2", + "resolved": "https://npm.lcr.gr/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, + "node_modules/cookies": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", + "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "dependencies": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cookies/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/copy-descriptor": { + "version": "0.1.1", + "resolved": "https://npm.lcr.gr/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/copy-to": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", + "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU=" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/crc": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/crc/-/crc-3.8.0.tgz", + "integrity": "sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==", + "dependencies": { + "buffer": "^5.1.0" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://npm.lcr.gr/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/cross-spawn/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://npm.lcr.gr/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/csrf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", + "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", + "dependencies": { + "rndm": "1.2.0", + "tsscmp": "1.0.6", + "uid-safe": "2.1.5" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cssom": { + "version": "0.4.4", + "resolved": "https://npm.lcr.gr/cssom/-/cssom-0.4.4.tgz", + "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", + "dev": true + }, + "node_modules/cssstyle": { + "version": "2.3.0", + "resolved": "https://npm.lcr.gr/cssstyle/-/cssstyle-2.3.0.tgz", + "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", + "dev": true, + "dependencies": { + "cssom": "~0.3.6" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cssstyle/node_modules/cssom": { + "version": "0.3.8", + "resolved": "https://npm.lcr.gr/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/data-urls": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/data-urls/-/data-urls-2.0.0.tgz", + "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/dataloader": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dataloader/-/dataloader-2.0.0.tgz", + "integrity": "sha512-YzhyDAwA4TaQIhM5go+vCLmU0UikghC/t9DTQYZR2M/UvZ1MdOhPezSDZcjj9uqQJOMqjLcpWtyW2iNINdlatQ==" + }, + "node_modules/date-and-time": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/date-and-time/-/date-and-time-0.14.1.tgz", + "integrity": "sha512-M4RggEH5OF2ZuCOxgOU67R6Z9ohjKbxGvAQz48vj53wLmL0bAgumkBvycR32f30pK+Og9pIR+RFDyChbaE4oLA==" + }, + "node_modules/date-fns": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.17.0.tgz", + "integrity": "sha512-ZEhqxUtEZeGgg9eHNSOAJ8O9xqSgiJdrL0lzSSfMF54x6KXWJiOH/xntSJ9YomJPrYH/p08t6gWjGWq1SDJlSA==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, + "node_modules/deasync": { + "version": "0.1.21", + "resolved": "https://npm.lcr.gr/deasync/-/deasync-0.1.21.tgz", + "integrity": "sha512-kUmM8Y+PZpMpQ+B4AuOW9k2Pfx/mSupJtxOsLzmnHY2WqZUYRFccFn2RhzPAqt3Xb+sorK/badW2D4zNzqZz5w==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.5.0", + "node-addon-api": "^1.7.1" + }, + "engines": { + "node": ">=0.11.0" + } + }, + "node_modules/debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decimal.js": { + "version": "10.2.1", + "resolved": "https://npm.lcr.gr/decimal.js/-/decimal.js-10.2.1.tgz", + "integrity": "sha512-KaL7+6Fw6i5A2XSnsbhm/6B+NuEA7TZ4vqxnd5tXz9sbKtrN9Srj8ab4vKVdK8YAqZO9P1kg45Y6YLoduPf+kw==", + "dev": true + }, + "node_modules/decode-uri-component": { + "version": "0.2.0", + "resolved": "https://npm.lcr.gr/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "dependencies": { + "mimic-response": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "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==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://npm.lcr.gr/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.2.2", + "resolved": "https://npm.lcr.gr/deepmerge/-/deepmerge-4.2.2.tgz", + "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "node_modules/define-property": { + "version": "2.0.2", + "resolved": "https://npm.lcr.gr/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-property/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://npm.lcr.gr/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "node_modules/denque": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://npm.lcr.gr/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/detect-node": { + "version": "2.0.4", + "resolved": "https://npm.lcr.gr/detect-node/-/detect-node-2.0.4.tgz", + "integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==" + }, + "node_modules/dicer": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz", + "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=", + "dependencies": { + "readable-stream": "1.1.x", + "streamsearch": "0.1.2" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/dicer/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/dicer/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=" + }, + "node_modules/diff-sequences": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/diff-sequences/-/diff-sequences-26.6.2.tgz", + "integrity": "sha512-Mv/TDa3nZ9sbc5soK+OoA74BsS3mL37yixCvUAQkiuA4Wz6YtwP/K47n2rv2ovzHZvoiQeA5FTQOschKkEwB0Q==", + "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/dolphin": { + "version": "0.1.14", + "resolved": "https://npm.lcr.gr/dolphin/-/dolphin-0.1.14.tgz", + "integrity": "sha1-pUWuInYsC8mrm4GNm07/i/8ovz4=", + "dependencies": { + "bluebird": "^2.9.24", + "lodash": "^4.15.0", + "request": "^2.65.0" + } + }, + "node_modules/dolphin/node_modules/bluebird": { + "version": "2.11.0", + "resolved": "https://npm.lcr.gr/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + }, + "node_modules/domexception": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/domexception/-/domexception-2.0.1.tgz", + "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", + "dev": true, + "dependencies": { + "webidl-conversions": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/domexception/node_modules/webidl-conversions": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/webidl-conversions/-/webidl-conversions-5.0.0.tgz", + "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dot-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.3.tgz", + "integrity": "sha512-7hwEmg6RiSQfm/GwPL4AAWXKy3YNNZA3oFv2Pdiey0mwkRCPZ9x6SZbkLcn8Ma5PYeVokzoD4Twv2n7LKp5WeA==", + "dependencies": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/dot-prop": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.2.0.tgz", + "integrity": "sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==", + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dotenv-expand": { + "version": "5.1.0", + "resolved": "https://npm.lcr.gr/dotenv-expand/-/dotenv-expand-5.1.0.tgz", + "integrity": "sha512-YXQl1DSa4/PQyRfgrv6aoNjhasp/p4qs9FjJ4q4cQk+8m4r6k4ZSiEyytKG8f8W9gi8WsQtIObNmKd+tMzNTmA==" + }, + "node_modules/dottie": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.2.tgz", + "integrity": "sha512-fmrwR04lsniq/uSr8yikThDTrM7epXHBAAjH9TbeH3rEA8tdCO7mRzB9hdmdGyJCxF8KERo9CITcm3kGuoyMhg==" + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "node_modules/duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/eckles": { + "version": "1.4.1", + "resolved": "https://npm.lcr.gr/eckles/-/eckles-1.4.1.tgz", + "integrity": "sha512-auWyk/k8oSkVHaD4RxkPadKsLUcIwKgr/h8F7UZEueFDBO7BsE4y+H6IMUDbfqKIFPg/9MxV6KcBdJCmVVcxSA==", + "bin": { + "eckles": "bin/eckles.js" + } + }, + "node_modules/editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "dependencies": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + }, + "bin": { + "editorconfig": "bin/editorconfig" + } + }, + "node_modules/editorconfig/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/emittery": { + "version": "0.7.2", + "resolved": "https://npm.lcr.gr/emittery/-/emittery-0.7.2.tgz", + "integrity": "sha512-A8OG5SR/ij3SsJdWDJdkkSYUjQdCUx6APQXem0SaEePBSRg4eymGYwBkKo1Y6DU+af/Jn2dBQqDBvjnr9Vi8nQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "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==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=" + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://npm.lcr.gr/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es5-ext": { + "version": "0.10.53", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", + "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "dependencies": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.3", + "next-tick": "~1.0.0" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "1.14.3", + "resolved": "https://npm.lcr.gr/escodegen/-/escodegen-1.14.3.tgz", + "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://npm.lcr.gr/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://npm.lcr.gr/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://npm.lcr.gr/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/exec-sh": { + "version": "0.3.4", + "resolved": "https://npm.lcr.gr/exec-sh/-/exec-sh-0.3.4.tgz", + "integrity": "sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A==", + "dev": true + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/execa/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://npm.lcr.gr/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://npm.lcr.gr/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-brackets": { + "version": "2.1.4", + "resolved": "https://npm.lcr.gr/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "dependencies": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://npm.lcr.gr/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/expand-brackets/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://npm.lcr.gr/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expand-brackets/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/expect": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/expect/-/expect-26.6.2.tgz", + "integrity": "sha512-9/hlOBkQl2l/PLHJx6JjoDF6xPKcJEsUlWKb23rKE7KzeDqUZKXKNMW27KIue5JMdBV9HgmoJPcc8HtO85t9IA==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-styles": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-regex-util": "^26.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/expect/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/expect/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/expect/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dependencies": { + "type": "^2.0.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.0.0.tgz", + "integrity": "sha512-KBt58xCHry4Cejnc2ISQAF7QY+ORngsWfxezO68+12hKV6lQY8P/psIkcbjeHWn7MqcgciWJyCCevFMJdIXpow==" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extend-shallow": { + "version": "3.0.2", + "resolved": "https://npm.lcr.gr/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend-shallow/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://npm.lcr.gr/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob": { + "version": "2.0.4", + "resolved": "https://npm.lcr.gr/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "dependencies": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extglob/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://npm.lcr.gr/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://npm.lcr.gr/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fast-redact": { + "version": "2.1.0", + "resolved": "https://npm.lcr.gr/fast-redact/-/fast-redact-2.1.0.tgz", + "integrity": "sha512-0LkHpTLyadJavq9sRzzyqIoMZemWli77K2/MGOkafrR64B9ItrvZ9aT+jluvNDsv0YEHjSNhlMBtbokuoqii4A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://npm.lcr.gr/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "node_modules/fast-text-encoding": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.3.tgz", + "integrity": "sha512-dtm4QZH9nZtcDt8qJiOH9fcQd1NAgi+K1O2DbE6GG1PPCK/BWfOH3idCTRQ4ImXRUOyopDEgDEnVEE7Y/2Wrig==" + }, + "node_modules/fb-watchman": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/fb-watchman/-/fb-watchman-2.0.1.tgz", + "integrity": "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/flatstr": { + "version": "1.0.12", + "resolved": "https://npm.lcr.gr/flatstr/-/flatstr-1.0.12.tgz", + "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw==" + }, + "node_modules/follow-redirects": { + "version": "1.13.1", + "resolved": "https://npm.lcr.gr/follow-redirects/-/follow-redirects-1.13.1.tgz", + "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://npm.lcr.gr/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/formidable": { + "version": "1.2.2", + "resolved": "https://npm.lcr.gr/formidable/-/formidable-1.2.2.tgz", + "integrity": "sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q==", + "dev": true, + "funding": { + "url": "https://ko-fi.com/tunnckoCore/commissions" + } + }, + "node_modules/fragment-cache": { + "version": "0.2.1", + "resolved": "https://npm.lcr.gr/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "dependencies": { + "map-cache": "^0.2.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs-jetpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/fs-jetpack/-/fs-jetpack-2.4.0.tgz", + "integrity": "sha512-S/o9Dd7K9A7gicVU32eT8G0kHcmSu0rCVdP79P0MWInKFb8XpTc8Syhoo66k9no+HDshtlh4pUJTws8X+8fdFQ==", + "dependencies": { + "minimatch": "^3.0.2", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "deprecated": "\"Please update to latest v2.3 or v2.2\"", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://npm.lcr.gr/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gaxios": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-4.0.1.tgz", + "integrity": "sha512-jOin8xRZ/UytQeBpSXFqIzqU7Fi5TqgPNLlUsSB8kjJ76+FiGBfImF8KJu++c6J4jOldfJUtt0YmkRj2ZpSHTQ==", + "dependencies": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gcp-metadata": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-4.2.1.tgz", + "integrity": "sha512-tSk+REe5iq/N+K+SK1XjZJUrFPuDqGZVzCy2vocIHIGmPlTGsa8owXMJwGkrXr73NO0AzhPW4MF2DEHz7P2AVw==", + "dependencies": { + "gaxios": "^4.0.0", + "json-bigint": "^1.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gcs-resumable-upload": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/gcs-resumable-upload/-/gcs-resumable-upload-3.1.1.tgz", + "integrity": "sha512-RS1osvAicj9+MjCc6jAcVL1Pt3tg7NK2C2gXM5nqD1Gs0klF2kj5nnAFSBy97JrtslMIQzpb7iSuxaG8rFWd2A==", + "dependencies": { + "abort-controller": "^3.0.0", + "configstore": "^5.0.0", + "extend": "^3.0.2", + "gaxios": "^3.0.0", + "google-auth-library": "^6.0.0", + "pumpify": "^2.0.0", + "stream-events": "^1.0.4" + }, + "bin": { + "gcs-upload": "build/src/cli.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gcs-resumable-upload/node_modules/gaxios": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-3.2.0.tgz", + "integrity": "sha512-+6WPeVzPvOshftpxJwRi2Ozez80tn/hdtOUag7+gajDHRJvAblKxTFSSMPtr2hmnLy7p0mvYz0rMXLBl8pSO7Q==", + "dependencies": { + "abort-controller": "^3.0.0", + "extend": "^3.0.2", + "https-proxy-agent": "^5.0.0", + "is-stream": "^2.0.0", + "node-fetch": "^2.3.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://npm.lcr.gr/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "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/get-package-type": { + "version": "0.1.0", + "resolved": "https://npm.lcr.gr/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-value": { + "version": "2.0.6", + "resolved": "https://npm.lcr.gr/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/global-dirs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", + "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==", + "dev": true, + "dependencies": { + "ini": "^1.3.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://npm.lcr.gr/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/google-auth-library": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-6.1.3.tgz", + "integrity": "sha512-m9mwvY3GWbr7ZYEbl61isWmk+fvTmOt0YNUfPOUY2VH8K5pZlAIWJjxEi0PqR3OjMretyiQLI6GURMrPSwHQ2g==", + "dependencies": { + "arrify": "^2.0.0", + "base64-js": "^1.3.0", + "ecdsa-sig-formatter": "^1.0.11", + "fast-text-encoding": "^1.0.0", + "gaxios": "^4.0.0", + "gcp-metadata": "^4.2.0", + "gtoken": "^5.0.4", + "jws": "^4.0.0", + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-auth-library/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==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/google-auth-library/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/google-p12-pem": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-3.0.3.tgz", + "integrity": "sha512-wS0ek4ZtFx/ACKYF3JhyGe5kzH7pgiQ7J5otlumqR9psmWMYc+U9cErKlCYVYHoUaidXHdZ2xbo34kB+S+24hA==", + "dependencies": { + "node-forge": "^0.10.0" + }, + "bin": { + "gp12-pem": "build/src/bin/gp12-pem.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==" + }, + "node_modules/greenlock": { + "version": "2.8.8", + "resolved": "https://npm.lcr.gr/greenlock/-/greenlock-2.8.8.tgz", + "integrity": "sha512-U2pqxXXf0naeZc2363Xe174C6/T9lXGZYQjXBqa/PMb1CYRQuHwXlAqFEUu75JkxyHAzFGj/uliqSyQwIc91Yg==", + "dependencies": { + "acme": "^1.3.5", + "acme-dns-01-cli": "^3.0.0", + "acme-v2": "^1.8.6", + "cert-info": "^1.5.1", + "greenlock-store-fs": "^3.0.2", + "keypairs": "^1.2.14", + "le-challenge-fs": "^2.0.2", + "le-sni-auto": "^2.1.9", + "le-store-certbot": "^2.2.3", + "rsa-compat": "^2.0.8" + }, + "engines": { + "node": ">=4.5" + } + }, + "node_modules/greenlock-store-fs": { + "version": "3.2.2", + "resolved": "https://npm.lcr.gr/greenlock-store-fs/-/greenlock-store-fs-3.2.2.tgz", + "integrity": "sha512-92ejLB4DyV4qv/2b6VLGF2nKfYQeIfg3o+e/1cIoYLjlIaUFdbBXkzLTRozFlHsQPZt2ALi5qYrpC9IwH7GK8A==", + "dependencies": { + "@root/mkdirp": "^1.0.0", + "safe-replace": "^1.1.0" + } + }, + "node_modules/growly": { + "version": "1.3.0", + "resolved": "https://npm.lcr.gr/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true, + "optional": true + }, + "node_modules/gtoken": { + "version": "5.1.0", + "resolved": "https://npm.lcr.gr/gtoken/-/gtoken-5.1.0.tgz", + "integrity": "sha512-4d8N6Lk8TEAHl9vVoRVMh9BNOKWVgl2DdNtr3428O75r3QFrF/a5MMu851VmK0AA8+iSvbwRv69k5XnMLURGhg==", + "dependencies": { + "gaxios": "^4.0.0", + "google-p12-pem": "^3.0.3", + "jws": "^4.0.0", + "mime": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gtoken/node_modules/mime": { + "version": "2.4.6", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.6.tgz", + "integrity": "sha512-RZKhC3EmpBchfTGBVb8fb+RL2cWyw/32lshnsETttkBAyAUXSGHxbEJWWRXc751DrIxG1q04b8QwMbAwkRPpUA==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/handlebars": { + "version": "4.7.6", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.6.tgz", + "integrity": "sha512-1f2BACcBfiwAfStCKZNrUCgqNZkGsAT7UM3kkYtXuLo0KnaVfjKOyf7PRzB6++aK9STyT1Pd2ZCPe3EGOXleXA==", + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.0", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://npm.lcr.gr/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-value": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "dependencies": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-values/node_modules/kind-of": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/hash-stream-validation": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", + "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==" + }, + "node_modules/hasura-cli": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/hasura-cli/-/hasura-cli-2.0.9.tgz", + "integrity": "sha512-95xAxNFfF1nntncULGKGQ9UEbhEWsgcMHdqOLsreq9E1emh2CVu1xuY/WezGMaCe1D4ZII7HxSQZBIhdnF9vKg==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "axios": "^0.21.1", + "chalk": "^2.4.2" + }, + "bin": { + "hasura": "hasura" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/header-case": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.3.tgz", + "integrity": "sha512-LChe/V32mnUQnTwTxd3aAlNMk8ia9tjCDb/LjYtoMrdAPApxLB+azejUk5ERZIZdIqvinwv6BAUuFXH/tQPdZA==", + "dependencies": { + "capital-case": "^1.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.8", + "resolved": "https://npm.lcr.gr/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://npm.lcr.gr/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/hpack.js/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://npm.lcr.gr/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/hpack.js/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://npm.lcr.gr/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", + "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "dev": true, + "dependencies": { + "whatwg-encoding": "^1.0.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://npm.lcr.gr/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz", + "integrity": "sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==", + "dependencies": { + "deep-equal": "~1.0.1", + "http-errors": "~1.7.2" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-assert/node_modules/http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://npm.lcr.gr/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=" + }, + "node_modules/http-errors": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.0.tgz", + "integrity": "sha512-4I8r0C5JDhT5VkvI47QktDW75rNlGVsUf/8hzjCC/wkWI/jdTRmBb9aI7erSG82r1bjKY3F6k28WnsVxB1C73A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://npm.lcr.gr/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", + "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://npm.lcr.gr/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/humanize-number": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/humanize-number/-/humanize-number-0.0.2.tgz", + "integrity": "sha1-EcCvakcWQ2M1iFiASPF5lUFInBg=" + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==" + }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-local": { + "version": "3.0.2", + "resolved": "https://npm.lcr.gr/import-local/-/import-local-3.0.2.tgz", + "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", + "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=", + "engines": [ + "node >= 0.4.0" + ] + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "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.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "deprecated": "Please update to ini >=1.3.6 to avoid a prototype pollution issue", + "engines": { + "node": "*" + } + }, + "node_modules/ioredis": { + "version": "4.17.3", + "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.17.3.tgz", + "integrity": "sha512-iRvq4BOYzNFkDnSyhx7cmJNOi1x/HWYe+A4VXHBu4qpwJaGT1Mp+D2bVGJntH9K/Z/GeOM/Nprb8gB3bmitz1Q==", + "dependencies": { + "cluster-key-slot": "^1.1.0", + "debug": "^4.1.1", + "denque": "^1.1.0", + "lodash.defaults": "^4.2.0", + "lodash.flatten": "^4.4.0", + "redis-commands": "1.5.0", + "redis-errors": "^1.2.0", + "redis-parser": "^3.0.0", + "standard-as-callback": "^2.0.1" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/ioredis" + } + }, + "node_modules/ip-regex": { + "version": "2.1.0", + "resolved": "https://npm.lcr.gr/ip-regex/-/ip-regex-2.1.0.tgz", + "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://npm.lcr.gr/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-accessor-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://npm.lcr.gr/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://npm.lcr.gr/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "dependencies": { + "ci-info": "^2.0.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-class-hotfix": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/is-class-hotfix/-/is-class-hotfix-0.0.6.tgz", + "integrity": "sha512-0n+pzCC6ICtVr/WXnN2f03TK/3BfXY7me4cjCAqT8TYXEl0+JBRoqBo94JJHXcyDSLUeWbNX8Fvy5g5RJdAstQ==" + }, + "node_modules/is-core-module": { + "version": "2.2.0", + "resolved": "https://npm.lcr.gr/is-core-module/-/is-core-module-2.2.0.tgz", + "integrity": "sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://npm.lcr.gr/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-data-descriptor/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor": { + "version": "0.1.6", + "resolved": "https://npm.lcr.gr/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-descriptor/node_modules/kind-of": { + "version": "5.1.0", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-docker": { + "version": "2.1.1", + "resolved": "https://npm.lcr.gr/is-docker/-/is-docker-2.1.1.tgz", + "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==", + "dev": true, + "optional": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://npm.lcr.gr/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "engines": { + "node": ">=4" + } + }, + "node_modules/is-generator": { + "version": "1.0.3", + "resolved": "https://npm.lcr.gr/is-generator/-/is-generator-1.0.3.tgz", + "integrity": "sha1-wUwhBX7TbjKNuANHlmxpP4hjifM=" + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://npm.lcr.gr/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", + "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "dependencies": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://npm.lcr.gr/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz", + "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c=", + "dev": true + }, + "node_modules/is-promise": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.2.2.tgz", + "integrity": "sha512-+lP4/6lKUBfQjZ2pdxThZvLUAafmZb8OAxFb8XXtiQmS35INgr85hdOGoEs124ez1FCnZJt6jau/T+alh58QFQ==" + }, + "node_modules/is-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", + "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-type-of": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-type-of/-/is-type-of-1.2.1.tgz", + "integrity": "sha512-uK0kyX9LZYhSDS7H2sVJQJop1UnWPWmo5RvR3q2kFH6AUHYs7sOrVg0b4nyBHw29kRRNFofYN/JbHZDlHiItTA==", + "dependencies": { + "core-util-is": "^1.0.2", + "is-class-hotfix": "~0.0.6", + "isstream": "~0.1.2" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://npm.lcr.gr/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://npm.lcr.gr/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dev": true, + "optional": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://npm.lcr.gr/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz", + "integrity": "sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "4.0.3", + "resolved": "https://npm.lcr.gr/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz", + "integrity": "sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ==", + "dev": true, + "dependencies": { + "@babel/core": "^7.7.5", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.0.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://npm.lcr.gr/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz", + "integrity": "sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-reports": { + "version": "3.0.2", + "resolved": "https://npm.lcr.gr/istanbul-reports/-/istanbul-reports-3.0.2.tgz", + "integrity": "sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/jest/-/jest-26.6.3.tgz", + "integrity": "sha512-lGS5PXGAzR4RF7V5+XObhqz2KZIDUA1yD0DG6pBVmy10eh0ZIXQImRuzocsI/N2XZ1GrLFwTS27In2i2jlpq1Q==", + "dev": true, + "dependencies": { + "@jest/core": "^26.6.3", + "import-local": "^3.0.2", + "jest-cli": "^26.6.3" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-changed-files": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-changed-files/-/jest-changed-files-26.6.2.tgz", + "integrity": "sha512-fDS7szLcY9sCtIip8Fjry9oGf3I2ht/QT21bAHm5Dmf0mD4X3ReNUf17y+bO6fR8WgbIZTlbyG1ak/53cbRzKQ==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "execa": "^4.0.0", + "throat": "^5.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-changed-files/node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://npm.lcr.gr/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/jest-changed-files/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/jest-changed-files/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://npm.lcr.gr/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-changed-files/node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://npm.lcr.gr/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://npm.lcr.gr/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-changed-files/node_modules/which": { + "version": "2.0.2", + "resolved": "https://npm.lcr.gr/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/jest-config": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/jest-config/-/jest-config-26.6.3.tgz", + "integrity": "sha512-t5qdIj/bCj2j7NFVHb2nFB4aUdfucDn3JRKgrZnplb8nieAirAzRSHP8uDEd+qV6ygzg9Pz4YG7UTJf94LPSyg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^26.6.3", + "@jest/types": "^26.6.2", + "babel-jest": "^26.6.3", + "chalk": "^4.0.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.1", + "graceful-fs": "^4.2.4", + "jest-environment-jsdom": "^26.6.2", + "jest-environment-node": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-jasmine2": "^26.6.3", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + }, + "peerDependencies": { + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-diff/-/jest-diff-26.6.2.tgz", + "integrity": "sha512-6m+9Z3Gv9wN0WFVasqjCL/06+EFCMTqDEUl/b87HYK2rAPTyfz4ZIuSlPhY51PIQRWx5TaxeF1qmXKe9gfN3sA==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "26.0.0", + "resolved": "https://npm.lcr.gr/jest-docblock/-/jest-docblock-26.0.0.tgz", + "integrity": "sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-each": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-each/-/jest-each-26.6.2.tgz", + "integrity": "sha512-Mer/f0KaATbjl8MCJ+0GEpNdqmnVmDYqCTJYTvoo7rqmRiDllmp2AYN+06F93nXcY3ur9ShIjS+CO/uD+BbH4A==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-jsdom": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-environment-jsdom/-/jest-environment-jsdom-26.6.2.tgz", + "integrity": "sha512-jgPqCruTlt3Kwqg5/WVFyHIOJHsiAvhcp2qiR2QQstuG9yWox5+iHpU3ZrcBxW14T4fe5Z68jAfLRh7joCSP2Q==", + "dev": true, + "dependencies": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2", + "jsdom": "^16.4.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-environment-node": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-environment-node/-/jest-environment-node-26.6.2.tgz", + "integrity": "sha512-zhtMio3Exty18dy8ee8eJ9kjnRyZC1N4C1Nt/VShN1apyXc8rWGtJ9lI7vqiWcyyXS4BVSEn9lxAM2D+07/Tag==", + "dev": true, + "dependencies": { + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "jest-mock": "^26.6.2", + "jest-util": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-get-type": { + "version": "26.3.0", + "resolved": "https://npm.lcr.gr/jest-get-type/-/jest-get-type-26.3.0.tgz", + "integrity": "sha512-TpfaviN1R2pQWkIihlfEanwOXK0zcxrKEE4MlU6Tn7keoXdN6/3gK/xl0yEh8DOunn5pOVGKf8hB4R9gVh04ig==", + "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-haste-map": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-haste-map/-/jest-haste-map-26.6.2.tgz", + "integrity": "sha512-easWIJXIw71B2RdR8kgqpjQrbMRWQBgiBwXYEhtGUTaX+doCjBheluShdDMeR8IMfJiTqH4+zfhtg29apJf/8w==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/graceful-fs": "^4.1.2", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.4", + "jest-regex-util": "^26.0.0", + "jest-serializer": "^26.6.2", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "micromatch": "^4.0.2", + "sane": "^4.0.3", + "walker": "^1.0.7" + }, + "engines": { + "node": ">= 10.14.2" + }, + "optionalDependencies": { + "fsevents": "^2.1.2" + } + }, + "node_modules/jest-jasmine2": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/jest-jasmine2/-/jest-jasmine2-26.6.3.tgz", + "integrity": "sha512-kPKUrQtc8aYwBV7CqBg5pu+tmYXlvFlSFYn18ev4gPFtrRzB15N2gW/Roew3187q2w2eHuu0MU9TJz6w0/nPEg==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "expect": "^26.6.2", + "is-generator-fn": "^2.0.0", + "jest-each": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "pretty-format": "^26.6.2", + "throat": "^5.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-jasmine2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-jasmine2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-jasmine2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-jasmine2/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-jasmine2/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-leak-detector": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-leak-detector/-/jest-leak-detector-26.6.2.tgz", + "integrity": "sha512-i4xlXpsVSMeKvg2cEKdfhh0H39qlJlP5Ex1yQxwF9ubahboQYMgTtz5oML35AVA3B4Eu+YsmwaiKVev9KCvLxg==", + "dev": true, + "dependencies": { + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-matcher-utils": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-matcher-utils/-/jest-matcher-utils-26.6.2.tgz", + "integrity": "sha512-llnc8vQgYcNqDrqRDXWwMr9i7rS5XFiCwvh6DTP7Jqa2mqpcCBBlpCbn+trkG0KNhPu/h8rzyBkriOtBstvWhw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-message-util/-/jest-message-util-26.6.2.tgz", + "integrity": "sha512-rGiLePzQ3AzwUshu2+Rn+UMFk0pHN58sOG+IaJbk5Jxuqo3NYO1U2/MIR4S1sKgsoYSXSzdtSa0TgrmtUwEbmA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "micromatch": "^4.0.2", + "pretty-format": "^26.6.2", + "slash": "^3.0.0", + "stack-utils": "^2.0.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-mock/-/jest-mock-26.6.2.tgz", + "integrity": "sha512-YyFjePHHp1LzpzYcmgqkJ0nm0gg/lJx2aZFzFy1S6eUqNjXsOqTK10zNRff2dNfssgokjkG65OlWNcIlgd3zew==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.2", + "resolved": "https://npm.lcr.gr/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", + "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "26.0.0", + "resolved": "https://npm.lcr.gr/jest-regex-util/-/jest-regex-util-26.0.0.tgz", + "integrity": "sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==", + "dev": true, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-resolve": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-resolve/-/jest-resolve-26.6.2.tgz", + "integrity": "sha512-sOxsZOq25mT1wRsfHcbtkInS+Ek7Q8jCHUB0ZUTP0tc/c41QHriU/NunqMfCUWsL4H3MHpvQD4QR9kSYhS7UvQ==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^26.6.2", + "read-pkg-up": "^7.0.1", + "resolve": "^1.18.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/jest-resolve-dependencies/-/jest-resolve-dependencies-26.6.3.tgz", + "integrity": "sha512-pVwUjJkxbhe4RY8QEWzN3vns2kqyuldKpxlxJlzEYfKSvY6/bMvxoFrYYzUO1Gx28yKWN37qyV7rIoIp2h8fTg==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-snapshot": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/resolve": { + "version": "1.19.0", + "resolved": "https://npm.lcr.gr/resolve/-/resolve-1.19.0.tgz", + "integrity": "sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==", + "dev": true, + "dependencies": { + "is-core-module": "^2.1.0", + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/jest-runner/-/jest-runner-26.6.3.tgz", + "integrity": "sha512-atgKpRHnaA2OvByG/HpGA4g6CSPS/1LK0jK3gATJAoptC1ojltpmVlYC3TYgdmGp+GLuhzpH30Gvs36szSL2JQ==", + "dev": true, + "dependencies": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.7.1", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-docblock": "^26.0.0", + "jest-haste-map": "^26.6.2", + "jest-leak-detector": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "jest-runtime": "^26.6.3", + "jest-util": "^26.6.2", + "jest-worker": "^26.6.2", + "source-map-support": "^0.5.6", + "throat": "^5.0.0" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/jest-runtime/-/jest-runtime-26.6.3.tgz", + "integrity": "sha512-lrzyR3N8sacTAMeonbqpnSka1dHNux2uk0qqDXVkMv2c/A3wYnvQ4EXuI013Y6+gSKSCxdaczvf4HF0mVXHRdw==", + "dev": true, + "dependencies": { + "@jest/console": "^26.6.2", + "@jest/environment": "^26.6.2", + "@jest/fake-timers": "^26.6.2", + "@jest/globals": "^26.6.2", + "@jest/source-map": "^26.6.2", + "@jest/test-result": "^26.6.2", + "@jest/transform": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/yargs": "^15.0.0", + "chalk": "^4.0.0", + "cjs-module-lexer": "^0.6.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.4", + "jest-config": "^26.6.3", + "jest-haste-map": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-mock": "^26.6.2", + "jest-regex-util": "^26.0.0", + "jest-resolve": "^26.6.2", + "jest-snapshot": "^26.6.2", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "slash": "^3.0.0", + "strip-bom": "^4.0.0", + "yargs": "^15.4.1" + }, + "bin": { + "jest-runtime": "bin/jest-runtime.js" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-runtime/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://npm.lcr.gr/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://npm.lcr.gr/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://npm.lcr.gr/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://npm.lcr.gr/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://npm.lcr.gr/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jest-serializer": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-serializer/-/jest-serializer-26.6.2.tgz", + "integrity": "sha512-S5wqyz0DXnNJPd/xfIzZ5Xnp1HrJWBczg8mMfMpN78OJ5eDxXyf+Ygld9wX1DnUWbIbhM1YDY95NjR4CBXkb2g==", + "dev": true, + "dependencies": { + "@types/node": "*", + "graceful-fs": "^4.2.4" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-snapshot": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-snapshot/-/jest-snapshot-26.6.2.tgz", + "integrity": "sha512-OLhxz05EzUtsAmOMzuupt1lHYXCNib0ECyuZ/PZOx9TrZcC8vL0x+DUG3TL+GLX3yHG45e6YGjIm0XwDc3q3og==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0", + "@jest/types": "^26.6.2", + "@types/babel__traverse": "^7.0.4", + "@types/prettier": "^2.0.0", + "chalk": "^4.0.0", + "expect": "^26.6.2", + "graceful-fs": "^4.2.4", + "jest-diff": "^26.6.2", + "jest-get-type": "^26.3.0", + "jest-haste-map": "^26.6.2", + "jest-matcher-utils": "^26.6.2", + "jest-message-util": "^26.6.2", + "jest-resolve": "^26.6.2", + "natural-compare": "^1.4.0", + "pretty-format": "^26.6.2", + "semver": "^7.3.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://npm.lcr.gr/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/jest-util": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-util/-/jest-util-26.6.2.tgz", + "integrity": "sha512-MDW0fKfsn0OI7MS7Euz6h8HNDXVQ0gaM9uW6RjfDmd1DAFcaxX9OqIakHIqhbnmF08Cf2DLDG+ulq8YQQ0Lp0Q==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "@types/node": "*", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.4", + "is-ci": "^2.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-validate/-/jest-validate-26.6.2.tgz", + "integrity": "sha512-NEYZ9Aeyj0i5rQqbq+tpIOom0YS1u2MVu6+euBsvpgIme+FOfRmoC4R5p0JiAUpaFvFy24xgrpMknarR/93XjQ==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "camelcase": "^6.0.0", + "chalk": "^4.0.0", + "jest-get-type": "^26.3.0", + "leven": "^3.1.0", + "pretty-format": "^26.6.2" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://npm.lcr.gr/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-watcher/-/jest-watcher-26.6.2.tgz", + "integrity": "sha512-WKJob0P/Em2csiVthsI68p6aGKTIcsfjH9Gsx1f0A3Italz43e3ho0geSAVsmj09RWOELP1AZ/DXyJgOgDKxXQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "jest-util": "^26.6.2", + "string-length": "^4.0.1" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/jest-worker/-/jest-worker-26.6.2.tgz", + "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://npm.lcr.gr/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/jest/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/jest-cli": { + "version": "26.6.3", + "resolved": "https://npm.lcr.gr/jest-cli/-/jest-cli-26.6.3.tgz", + "integrity": "sha512-GF9noBSa9t08pSyl3CY4frMrqp+aQXFGFkf5hEPbh/pIUFYWMK6ZLTfbmadxJVcJrdRoChlWQsA2VkJcDFK8hg==", + "dev": true, + "dependencies": { + "@jest/core": "^26.6.3", + "@jest/test-result": "^26.6.2", + "@jest/types": "^26.6.2", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.4", + "import-local": "^3.0.2", + "is-ci": "^2.0.0", + "jest-config": "^26.6.3", + "jest-util": "^26.6.2", + "jest-validate": "^26.6.2", + "prompts": "^2.0.1", + "yargs": "^15.4.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": ">= 10.14.2" + } + }, + "node_modules/jest/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://npm.lcr.gr/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://npm.lcr.gr/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://npm.lcr.gr/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://npm.lcr.gr/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/joi": { + "version": "17.3.0", + "resolved": "https://npm.lcr.gr/joi/-/joi-17.3.0.tgz", + "integrity": "sha512-Qh5gdU6niuYbUIUV5ejbsMiiFmBdw8Kcp8Buj2JntszCkCfxJ9Cz76OtHxOZMPXrt5810iDIXs+n1nNVoquHgg==", + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.0", + "@sideway/formula": "^3.0.0", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/jose": { + "version": "3.6.1", + "resolved": "https://npm.lcr.gr/jose/-/jose-3.6.1.tgz", + "integrity": "sha512-AZ+dcXaYbX79uvqedXl7QMDkhpQBVXFezLRP734phyVw8EEcnwRIsOMLw4JAMJ+7Iyhv5Eb7isQUEZvqCCk6vA==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, + "node_modules/js-beautify": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.11.0.tgz", + "integrity": "sha512-a26B+Cx7USQGSWnz9YxgJNMmML/QG2nqIaL7VVYPCXbqiKz8PN0waSNvroMtvAK6tY7g/wPdNWGEP+JTNIBr6A==", + "dependencies": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "mkdirp": "~1.0.3", + "nopt": "^4.0.3" + }, + "bin": { + "css-beautify": "js/bin/css-beautify.js", + "html-beautify": "js/bin/html-beautify.js", + "js-beautify": "js/bin/js-beautify.js" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://npm.lcr.gr/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "node_modules/jsdom": { + "version": "16.4.0", + "resolved": "https://npm.lcr.gr/jsdom/-/jsdom-16.4.0.tgz", + "integrity": "sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==", + "dev": true, + "dependencies": { + "abab": "^2.0.3", + "acorn": "^7.1.1", + "acorn-globals": "^6.0.0", + "cssom": "^0.4.4", + "cssstyle": "^2.2.0", + "data-urls": "^2.0.0", + "decimal.js": "^10.2.0", + "domexception": "^2.0.1", + "escodegen": "^1.14.1", + "html-encoding-sniffer": "^2.0.1", + "is-potential-custom-element-name": "^1.0.0", + "nwsapi": "^2.2.0", + "parse5": "5.1.1", + "request": "^2.88.2", + "request-promise-native": "^1.0.8", + "saxes": "^5.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^3.0.1", + "w3c-hr-time": "^1.0.2", + "w3c-xmlserializer": "^2.0.0", + "webidl-conversions": "^6.1.0", + "whatwg-encoding": "^1.0.5", + "whatwg-mimetype": "^2.3.0", + "whatwg-url": "^8.0.0", + "ws": "^7.2.3", + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "canvas": "^2.5.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/tough-cookie": { + "version": "3.0.1", + "resolved": "https://npm.lcr.gr/tough-cookie/-/tough-cookie-3.0.1.tgz", + "integrity": "sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg==", + "dev": true, + "dependencies": { + "ip-regex": "^2.1.0", + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://npm.lcr.gr/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://npm.lcr.gr/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "node_modules/json5": { + "version": "2.2.0", + "resolved": "https://npm.lcr.gr/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "node_modules/jwa": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", + "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", + "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", + "dependencies": { + "jwa": "^2.0.0", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "dependencies": { + "tsscmp": "1.0.6" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/keypairs": { + "version": "1.2.14", + "resolved": "https://npm.lcr.gr/keypairs/-/keypairs-1.2.14.tgz", + "integrity": "sha512-ZoZfZMygyB0QcjSlz7Rh6wT2CJasYEHBPETtmHZEfxuJd7bnsOG5AdtPZqHZBT+hoHvuWCp/4y8VmvTvH0Y9uA==", + "dependencies": { + "eckles": "^1.4.1", + "rasha": "^1.2.4" + }, + "bin": { + "keypairs-install": "bin/keypairs.js" + } + }, + "node_modules/keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://npm.lcr.gr/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/koa": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.13.0.tgz", + "integrity": "sha512-i/XJVOfPw7npbMv67+bOeXr3gPqOAw6uh5wFyNs3QvJ47tUx3M3V9rIE0//WytY42MKz4l/MXKyGkQ2LQTfLUQ==", + "dependencies": { + "accepts": "^1.3.5", + "cache-content-type": "^1.0.0", + "content-disposition": "~0.5.2", + "content-type": "^1.0.4", + "cookies": "~0.8.0", + "debug": "~3.1.0", + "delegates": "^1.0.0", + "depd": "^1.1.2", + "destroy": "^1.0.4", + "encodeurl": "^1.0.2", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.3.0", + "http-errors": "^1.6.3", + "is-generator-function": "^1.0.7", + "koa-compose": "^4.1.0", + "koa-convert": "^1.2.0", + "on-finished": "^2.3.0", + "only": "~0.0.2", + "parseurl": "^1.3.2", + "statuses": "^1.5.0", + "type-is": "^1.6.16", + "vary": "^1.1.2" + }, + "engines": { + "node": "^4.8.4 || ^6.10.1 || ^7.10.1 || >= 8.1.4" + } + }, + "node_modules/koa-bodyparser": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/koa-bodyparser/-/koa-bodyparser-4.3.0.tgz", + "integrity": "sha512-uyV8G29KAGwZc4q/0WUAjH+Tsmuv9ImfBUF2oZVyZtaeo0husInagyn/JH85xMSxM0hEk/mbCII5ubLDuqW/Rw==", + "dependencies": { + "co-body": "^6.0.0", + "copy-to": "^2.0.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", + "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==" + }, + "node_modules/koa-compress": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/koa-compress/-/koa-compress-5.0.1.tgz", + "integrity": "sha512-uTo7Hcyyt6e9o2X3htRS/SNEKy9vDOUc/r1qs/F0YI2Frv9IEbkjz/9dC6IdJWBQAG34lRuU7jBXeq3DRur9Ng==", + "dependencies": { + "bytes": "^3.0.0", + "compressible": "^2.0.0", + "http-errors": "^1.7.3", + "koa-is-json": "^1.0.0", + "statuses": "^2.0.0" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/koa-compress/node_modules/statuses": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.0.tgz", + "integrity": "sha512-w9jNUUQdpuVoYqXxnyOakhckBbOxRaoYqJscyIBYCS5ixyCnO7nQn7zBZvP9zf5QOPZcz2DLUpE3KsNPbJBOFA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/koa-convert": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", + "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", + "dependencies": { + "co": "^4.6.0", + "koa-compose": "^3.0.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/koa-convert/node_modules/koa-compose": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", + "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", + "dependencies": { + "any-promise": "^1.1.0" + } + }, + "node_modules/koa-csrf": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/koa-csrf/-/koa-csrf-3.0.8.tgz", + "integrity": "sha512-qCuFFGKEoc/6o229CwOT3638hp/2WNTUwLnKDezdXYYO/N6caS4l6isYJsjgqpZNjzjM53ZPISbLMMnlfHHv1g==", + "dependencies": { + "csrf": "^3.1.0" + }, + "engines": { + "node": ">= 6.4" + } + }, + "node_modules/koa-etag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/koa-etag/-/koa-etag-3.0.0.tgz", + "integrity": "sha1-nvc4Ld1agqsN6xU0FckVg293HT8=", + "dependencies": { + "etag": "^1.3.0", + "mz": "^2.1.0" + } + }, + "node_modules/koa-is-json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/koa-is-json/-/koa-is-json-1.0.0.tgz", + "integrity": "sha1-JzwH7c3Ljfaiwat9We52SRRR7BQ=" + }, + "node_modules/koa-logger": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koa-logger/-/koa-logger-3.2.1.tgz", + "integrity": "sha512-MjlznhLLKy9+kG8nAXKJLM0/ClsQp/Or2vI3a5rbSQmgl8IJBQO0KI5FA70BvW+hqjtxjp49SpH2E7okS6NmHg==", + "dependencies": { + "bytes": "^3.1.0", + "chalk": "^2.4.2", + "humanize-number": "0.0.2", + "passthrough-counter": "^1.0.0" + }, + "engines": { + "node": ">= 7.6.0" + } + }, + "node_modules/koa-mount": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/koa-mount/-/koa-mount-4.0.0.tgz", + "integrity": "sha512-rm71jaA/P+6HeCpoRhmCv8KVBIi0tfGuO/dMKicbQnQW/YJntJ6MnnspkodoA4QstMVEZArsCphmd0bJEtoMjQ==", + "dependencies": { + "debug": "^4.0.1", + "koa-compose": "^4.1.0" + }, + "engines": { + "node": ">= 7.6.0" + } + }, + "node_modules/koa-send": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.1.tgz", + "integrity": "sha512-tmcyQ/wXXuxpDxyNXv5yNNkdAMdFRqwtegBXUaowiQzUKqJehttS0x2j0eOZDQAyloAth5w6wwBImnFzkUz3pQ==", + "dependencies": { + "debug": "^4.1.1", + "http-errors": "^1.7.3", + "resolve-path": "^1.4.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/koa-session": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/koa-session/-/koa-session-6.0.0.tgz", + "integrity": "sha512-mEj2ximzLqoypk0Q+/JLu0j7fuMk/fL+yiBM0RKmxBqdImKxq3hfnpHLwpMhwya05z/W8i7vawpFl+lsYTZbAg==", + "dependencies": { + "crc": "^3.4.4", + "debug": "^3.1.0", + "is-type-of": "^1.0.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">=7.6" + } + }, + "node_modules/koa-session/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/koa-session/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/koa-static": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/koa-static/-/koa-static-5.0.0.tgz", + "integrity": "sha512-UqyYyH5YEXaJrf9S8E23GoJFQZXkBVJ9zYYMPGz919MSX1KuvAcycIuS0ci150HCoPf4XQVhQ84Qf8xRPWxFaQ==", + "dependencies": { + "debug": "^3.1.0", + "koa-send": "^5.0.0" + }, + "engines": { + "node": ">= 7.6.0" + } + }, + "node_modules/koa-static/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/koa/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/koa/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "dependencies": { + "package-json": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/le-challenge-fs": { + "version": "2.0.9", + "resolved": "https://npm.lcr.gr/le-challenge-fs/-/le-challenge-fs-2.0.9.tgz", + "integrity": "sha512-stzI6rxd+aXGxBl87QJKKY/i/wl3uz6EoWzX2xSazJvCPSYBQys1RVNgOcf0SfUQPh6TBCFJFSJkiR4mznb4sg==", + "dependencies": { + "@root/mkdirp": "^1.0.0" + } + }, + "node_modules/le-sni-auto": { + "version": "2.1.9", + "resolved": "https://npm.lcr.gr/le-sni-auto/-/le-sni-auto-2.1.9.tgz", + "integrity": "sha512-QmQHNwQDi/56GY8+qczFZ06FZbxaeJQjbjEhwwQHhkJ9IHhIQFkPfCT/OyDfLj4gqLIrg5ZX8CemxxVZnLEYfg==" + }, + "node_modules/le-store-certbot": { + "version": "2.2.3", + "resolved": "https://npm.lcr.gr/le-store-certbot/-/le-store-certbot-2.2.3.tgz", + "integrity": "sha512-c4ACR+v+JKMiAOOshLh6gdCKA7wIWR16+mROMLpQjq3rXJ3Vm8FaBHe2H+crT+flP+g7FmciAwUlfOJEJpIuCQ==", + "dependencies": { + "@root/mkdirp": "^1.0.0", + "pyconf": "^1.1.7", + "safe-replace": "^1.1.0" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://npm.lcr.gr/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://npm.lcr.gr/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.1.6", + "resolved": "https://npm.lcr.gr/lines-and-columns/-/lines-and-columns-1.1.6.tgz", + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", + "dev": true + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.19", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz", + "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==" + }, + "node_modules/lodash.defaults": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz", + "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw=" + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=" + }, + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://npm.lcr.gr/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "node_modules/lower-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.1.tgz", + "integrity": "sha512-LiWgfDLLb1dwbFQZsSglpRj+1ctGnayXz3Uv0/WO8n558JycT5fg6zkNcnW0G68Nn0aEldTFeEfmjCfmqry/rQ==", + "dependencies": { + "tslib": "^1.10.0" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru_map": { + "version": "0.3.3", + "resolved": "https://npm.lcr.gr/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "dependencies": { + "es5-ext": "~0.10.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-dir/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/makeerror": { + "version": "1.0.11", + "resolved": "https://npm.lcr.gr/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "dependencies": { + "tmpl": "1.0.x" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://npm.lcr.gr/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-visit": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "dependencies": { + "object-visit": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memoizee": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.14.tgz", + "integrity": "sha512-/SWFvWegAIYAO4NQMpcX+gcra0yEZu4OntmUdrBaWrJncxOqAziGFlHxc7yjKVK2uu3lpPW27P27wkR82wA8mg==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.45", + "es6-weak-map": "^2.0.2", + "event-emitter": "^0.3.5", + "is-promise": "^2.1", + "lru-queue": "0.1", + "next-tick": "1", + "timers-ext": "^0.1.5" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.2", + "resolved": "https://npm.lcr.gr/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dev": true, + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "dependencies": { + "mime-db": "1.44.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://npm.lcr.gr/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "node_modules/mixin-deep": { + "version": "1.3.2", + "resolved": "https://npm.lcr.gr/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "dependencies": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-deep/node_modules/is-extendable": { + "version": "1.0.1", + "resolved": "https://npm.lcr.gr/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/moment": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-range": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/moment-range/-/moment-range-4.0.2.tgz", + "integrity": "sha512-n8sceWwSTjmz++nFHzeNEUsYtDqjgXgcOBzsHi+BoXQU2FW+eU92LUaK8gqOiSu5PG57Q9sYj1Fz4LRDj4FtKA==", + "dependencies": { + "es6-symbol": "^3.1.0" + }, + "engines": { + "node": "*" + }, + "peerDependencies": { + "moment": ">= 2" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.31", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", + "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", + "dependencies": { + "moment": ">= 2.9.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multer": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-1.4.2.tgz", + "integrity": "sha512-xY8pX7V+ybyUpbYMxtjM9KAiD9ixtg5/JkeKUTD6xilfDv0vzzOFcCp4Ljb1UU3tSOM3VTZtKo63OmzOrGi3Cg==", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^0.2.11", + "concat-stream": "^1.5.2", + "mkdirp": "^0.5.1", + "object-assign": "^4.1.1", + "on-finished": "^2.3.0", + "type-is": "^1.6.4", + "xtend": "^4.0.0" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/multer/node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanomatch": { + "version": "1.2.13", + "resolved": "https://npm.lcr.gr/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://npm.lcr.gr/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://npm.lcr.gr/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/no-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.3.tgz", + "integrity": "sha512-ehY/mVQCf9BL0gKfsJBvFJen+1V//U+0HQMPrWct40ixE4jnv0bfvxDbWtAHL9EcaPEOJHVVYKoQn1TlZUB8Tw==", + "dependencies": { + "lower-case": "^2.0.1", + "tslib": "^1.10.0" + } + }, + "node_modules/node-addon-api": { + "version": "1.7.2", + "resolved": "https://npm.lcr.gr/node-addon-api/-/node-addon-api-1.7.2.tgz", + "integrity": "sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==" + }, + "node_modules/node-etcd": { + "version": "7.0.0", + "resolved": "https://npm.lcr.gr/node-etcd/-/node-etcd-7.0.0.tgz", + "integrity": "sha512-kGnYVoxdDuUU2ojCt0GnZhR2wMRZWyJvq0OsWX+adExUbiX0z7D+8//nlv9Gnve1dIvNEQ/mvM+72aSKnWVp5Q==", + "dependencies": { + "deasync": "^0.1.13", + "lodash": "^4.17.10", + "request": "^2.87.0", + "url-parse": "^1.4.3" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-fetch": { + "version": "2.6.1", + "resolved": "https://npm.lcr.gr/node-fetch/-/node-fetch-2.6.1.tgz", + "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", + "engines": { + "node": "4.x || >=6.0.0" + } + }, + "node_modules/node-forge": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz", + "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://npm.lcr.gr/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node_modules/node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/node-notifier": { + "version": "8.0.1", + "resolved": "https://npm.lcr.gr/node-notifier/-/node-notifier-8.0.1.tgz", + "integrity": "sha512-BvEXF+UmsnAfYfoapKM9nGxnP+Wn7P91YfXmrKnfcYCx6VBeoN5Ez5Ogck6I8Bi5k4RlpqRYaw75pAwzX9OphA==", + "dev": true, + "optional": true, + "dependencies": { + "growly": "^1.3.0", + "is-wsl": "^2.2.0", + "semver": "^7.3.2", + "shellwords": "^0.1.1", + "uuid": "^8.3.0", + "which": "^2.0.2" + } + }, + "node_modules/node-notifier/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-notifier/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://npm.lcr.gr/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "optional": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-notifier/node_modules/which": { + "version": "2.0.2", + "resolved": "https://npm.lcr.gr/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "optional": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/node-notifier/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "optional": true + }, + "node_modules/nodemailer": { + "version": "6.4.17", + "resolved": "https://npm.lcr.gr/nodemailer/-/nodemailer-6.4.17.tgz", + "integrity": "sha512-89ps+SBGpo0D4Bi5ZrxcrCiRFaMmkCt+gItMXQGzEtZVR3uAD3QAQIDoxTWnx3ky0Dwwy/dhFrQ+6NNGXpw/qQ==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/nodemon": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", + "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^4.0.0" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=8.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/nodemon/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/nodemon/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://npm.lcr.gr/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://npm.lcr.gr/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/nwsapi": { + "version": "2.2.0", + "resolved": "https://npm.lcr.gr/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/oauth2-server": { + "version": "3.1.1", + "resolved": "https://npm.lcr.gr/oauth2-server/-/oauth2-server-3.1.1.tgz", + "integrity": "sha512-4dv+fE9hrK+xTaCygOLh/kQeFzbFr7UqSyHvBDbrQq8Hg52sAkV2vTsyH3Z42hoeaKpbhM7udhL8Y4GYbl6TGQ==", + "dependencies": { + "basic-auth": "2.0.1", + "bluebird": "3.7.2", + "lodash": "4.17.19", + "promisify-any": "2.0.1", + "statuses": "1.5.0", + "type-is": "1.6.18" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy": { + "version": "0.1.0", + "resolved": "https://npm.lcr.gr/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "dependencies": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://npm.lcr.gr/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "1.3.1", + "resolved": "https://npm.lcr.gr/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/object-visit": { + "version": "1.0.1", + "resolved": "https://npm.lcr.gr/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "dependencies": { + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://npm.lcr.gr/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://npm.lcr.gr/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/only": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", + "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=" + }, + "node_modules/optionator": { + "version": "0.8.3", + "resolved": "https://npm.lcr.gr/optionator/-/optionator-0.8.3.tgz", + "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.6", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "word-wrap": "~1.2.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-each-series": { + "version": "2.2.0", + "resolved": "https://npm.lcr.gr/p-each-series/-/p-each-series-2.2.0.tgz", + "integrity": "sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "dependencies": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/package-json/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/packet-reader": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", + "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" + }, + "node_modules/param-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.3.tgz", + "integrity": "sha512-VWBVyimc1+QrzappRs7waeN2YmoZFCGXWASRYX1/rGHtXqEcrGEIDm+jqIwFa2fRXNgQEwrxaYuIrX0WcAguTA==", + "dependencies": { + "dot-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://npm.lcr.gr/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "5.1.1", + "resolved": "https://npm.lcr.gr/parse5/-/parse5-5.1.1.tgz", + "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==", + "dev": true + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/pascal-case": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.1.tgz", + "integrity": "sha512-XIeHKqIrsquVTQL2crjq3NfJUxmdLasn3TYOU0VBM+UX2a6ztAWBlJQBePLGY7VHW8+2dRadeIPK5+KImwTxQA==", + "dependencies": { + "no-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/pascalcase": { + "version": "0.1.1", + "resolved": "https://npm.lcr.gr/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/passthrough-counter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passthrough-counter/-/passthrough-counter-1.0.0.tgz", + "integrity": "sha1-GWfZ5m2lcrXAI8eH2xEqOHqxZvo=" + }, + "node_modules/path-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/path-case/-/path-case-3.0.3.tgz", + "integrity": "sha512-UMFU6UETFpCNWbIWNczshPrnK/7JAXBP2NYw80ojElbQ2+JYxdqWDBkvvqM93u4u6oLmuJ/tPOf2tM8KtXv4eg==", + "dependencies": { + "dot-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==" + }, + "node_modules/path-to-regexp": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.1.0.tgz", + "integrity": "sha512-h9DqehX3zZZDCEm+xbfU0ZmwCGFCAAraPJWMXJ4+v32NjZJilVg3k1TcKsRgIb8IQ/izZSaydDc1OhJCZvs2Dw==" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "node_modules/pg": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.3.0.tgz", + "integrity": "sha512-jQPKWHWxbI09s/Z9aUvoTbvGgoj98AU7FDCcQ7kdejupn/TcNpx56v2gaOTzXkzOajmOEJEdi9eTh9cA2RVAjQ==", + "dependencies": { + "buffer-writer": "2.0.0", + "packet-reader": "1.0.0", + "pg-connection-string": "^2.3.0", + "pg-pool": "^3.2.1", + "pg-protocol": "^1.2.5", + "pg-types": "^2.1.0", + "pgpass": "1.x", + "semver": "4.3.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/pg-connection-string": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.3.0.tgz", + "integrity": "sha512-ukMTJXLI7/hZIwTW7hGMZJ0Lj0S2XQBCJ4Shv4y1zgQ/vqVea+FLhzywvPj0ujSuofu+yA4MYHGZPTsgjBgJ+w==" + }, + "node_modules/pg-hstore": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.3.tgz", + "integrity": "sha512-qpeTpdkguFgfdoidtfeTho1Q1zPVPbtMHgs8eQ+Aan05iLmIs3Z3oo5DOZRclPGoQ4i68I1kCtQSJSa7i0ZVYg==", + "dependencies": { + "underscore": "^1.7.0" + }, + "engines": { + "node": ">= 0.8.x" + } + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.1.tgz", + "integrity": "sha512-BQDPWUeKenVrMMDN9opfns/kZo4lxmSWhIqo+cSAF7+lfi9ZclQbr9vfnlNaPr8wYF3UYjm5X0yPAhbcgqNOdA==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.2.5.tgz", + "integrity": "sha512-1uYCckkuTfzz/FCefvavRywkowa6M5FohNMF5OjKrqo9PSR8gYc8poVmwwYQaBxhmQdBjhtP514eXy9/Us2xKg==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz", + "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=", + "dependencies": { + "split": "^1.0.0" + } + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pino": { + "version": "5.17.0", + "resolved": "https://npm.lcr.gr/pino/-/pino-5.17.0.tgz", + "integrity": "sha512-LqrqmRcJz8etUjyV0ddqB6OTUutCgQULPFg2b4dtijRHUsucaAdBgSUW58vY6RFSX+NT8963F+q0tM6lNwGShA==", + "dependencies": { + "fast-redact": "^2.0.0", + "fast-safe-stringify": "^2.0.7", + "flatstr": "^1.0.12", + "pino-std-serializers": "^2.4.2", + "quick-format-unescaped": "^3.0.3", + "sonic-boom": "^0.7.5" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-std-serializers": { + "version": "2.5.0", + "resolved": "https://npm.lcr.gr/pino-std-serializers/-/pino-std-serializers-2.5.0.tgz", + "integrity": "sha512-wXqbqSrIhE58TdrxxlfLwU9eDhrzppQDvGhBEr1gYbzzM4KKo3Y63gSjiDXRKLVS2UOXdPNR2v+KnQgNrs+xUg==" + }, + "node_modules/pirates": { + "version": "4.0.1", + "resolved": "https://npm.lcr.gr/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "dependencies": { + "node-modules-regexp": "^1.0.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://npm.lcr.gr/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/posix-character-classes": { + "version": "0.1.1", + "resolved": "https://npm.lcr.gr/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.5.tgz", + "integrity": "sha512-pdau6GRPERdAYUQwkBnGKxEfPyhVZXG/JiS44iZWiNdSOWE09N2lUgN6yshuq6fVSon4Pm0VMXd1srUUkLe9iA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postmark": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/postmark/-/postmark-2.7.1.tgz", + "integrity": "sha512-mevTZY8mZ2+DqBQweoUVsjlcsY2wu/WotDKplsFMiOy4mG7euOzmD4pqkWFymMVjeKbU52NZWEkO2Et1X0tdFw==", + "dependencies": { + "axios": "^0.21.1" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://npm.lcr.gr/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true, + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/pretty-format": { + "version": "26.6.2", + "resolved": "https://npm.lcr.gr/pretty-format/-/pretty-format-26.6.2.tgz", + "integrity": "sha512-7AeGuCYNGmycyQbCqd/3PWH4eOoX/OiCa0uphp57NVTeAGdJGaAliecxwBDHYQCIvrW7aDBZCYeNTP/WX69mkg==", + "dev": true, + "dependencies": { + "@jest/types": "^26.6.2", + "ansi-regex": "^5.0.0", + "ansi-styles": "^4.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/pretty-format/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://npm.lcr.gr/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/pretty-format/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://npm.lcr.gr/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promisify-any": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/promisify-any/-/promisify-any-2.0.1.tgz", + "integrity": "sha1-QD4AqIE/F1JCq1D+M6afjuzkcwU=", + "dependencies": { + "bluebird": "^2.10.0", + "co-bluebird": "^1.1.0", + "is-generator": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/promisify-any/node_modules/bluebird": { + "version": "2.11.0", + "resolved": "https://npm.lcr.gr/bluebird/-/bluebird-2.11.0.tgz", + "integrity": "sha1-U0uQM8AiyVecVro7Plpcqvu2UOE=" + }, + "node_modules/prompts": { + "version": "2.4.0", + "resolved": "https://npm.lcr.gr/prompts/-/prompts-2.4.0.tgz", + "integrity": "sha512-awZAKrk3vN6CroQukBL+R9051a4R3zCZBlJm/HBfrSZ8iTpYix3VX1vU4mveiLpiwmOJT4wokTF9m6HUk4KqWQ==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "node_modules/psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "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==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/pumpify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-2.0.1.tgz", + "integrity": "sha512-m7KOje7jZxrmutanlkS1daj1dS6z6BgslzOXmcSEpIlCxM3VJH7lG5QLeck/6hgF6F4crFf01UtQmNsJfweTAw==", + "dependencies": { + "duplexify": "^4.1.1", + "inherits": "^2.0.3", + "pump": "^3.0.0" + } + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", + "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", + "dev": true, + "dependencies": { + "escape-goat": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pyconf": { + "version": "1.1.7", + "resolved": "https://npm.lcr.gr/pyconf/-/pyconf-1.1.7.tgz", + "integrity": "sha512-v4clh33m68sjtMsh8XMpjhGWb/MQODAYZ1y7ORG5Qv58UK25OddoB+oXyexgDkK8ttFui/lZm2sQDgA2Ftjfkw==", + "dependencies": { + "safe-replace": "^1.0.2" + } + }, + "node_modules/qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://npm.lcr.gr/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==" + }, + "node_modules/quick-format-unescaped": { + "version": "3.0.3", + "resolved": "https://npm.lcr.gr/quick-format-unescaped/-/quick-format-unescaped-3.0.3.tgz", + "integrity": "sha512-dy1yjycmn9blucmJLXOfZDx1ikZJUi6E8bBZLnhPG5gBrVhHXx2xVyqqgKBubVNEXmx51dBACMHpoMQK/N/AXQ==" + }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rasha": { + "version": "1.2.5", + "resolved": "https://npm.lcr.gr/rasha/-/rasha-1.2.5.tgz", + "integrity": "sha512-KxtX+/fBk+wM7O3CNgwjSh5elwFilLvqWajhr6wFr2Hd63JnKTTi43Tw+Jb1hxJQWOwoya+NZWR2xztn3hCrTw==", + "bin": { + "rasha": "bin/rasha.js" + } + }, + "node_modules/raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", + "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/raw-body/node_modules/http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": 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/react-is": { + "version": "17.0.1", + "resolved": "https://npm.lcr.gr/react-is/-/react-is-17.0.1.tgz", + "integrity": "sha512-NAnt2iGDXohE5LI7uBnLnqvLQMtzhkiAOLXTmv+qnF9Ky7xAPcX8Up/xWIhxvLVGJvuLiNc4xQLtuqDRzb4fSA==", + "dev": true + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://npm.lcr.gr/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://npm.lcr.gr/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://npm.lcr.gr/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/redbird": { + "version": "0.10.0", + "resolved": "https://npm.lcr.gr/redbird/-/redbird-0.10.0.tgz", + "integrity": "sha512-81bZYnzDWmImuW/JlPaxpj956I9HsovR16EStTbD27HMU4pp1auugr5Ygk6W6v4QINTl89K4bZT+MOhzGub6yA==", + "dependencies": { + "bluebird": "^3.7.2", + "dolphin": "*", + "greenlock": "^2.8.8", + "http-proxy": "^1.18.0", + "le-challenge-fs": "^2.0.9", + "le-store-certbot": "^2.2.3", + "lodash": "^4.17.15", + "lru-cache": "^5.1.1", + "node-etcd": "^7.0.0", + "object-hash": "^1.3.1", + "pino": "^5.15.0", + "safetimeout": "^0.1.2", + "spdy": "^4.0.1", + "valid-url": "^1.0.9" + } + }, + "node_modules/redbird/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://npm.lcr.gr/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/redbird/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://npm.lcr.gr/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/redis-commands": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.5.0.tgz", + "integrity": "sha512-6KxamqpZ468MeQC3bkWmCB1fp56XL64D4Kf0zJSwDZbVLLm7KFkoIcHrgRvQ+sk8dnhySs7+yBg94yIkAK7aJg==" + }, + "node_modules/redis-errors": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz", + "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60=", + "engines": { + "node": ">=4" + } + }, + "node_modules/redis-parser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz", + "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=", + "dependencies": { + "redis-errors": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regex-not": { + "version": "1.0.2", + "resolved": "https://npm.lcr.gr/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/registry-auth-token": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.1.1.tgz", + "integrity": "sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "dependencies": { + "rc": "^1.2.8" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/remarkable": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/remarkable/-/remarkable-2.0.1.tgz", + "integrity": "sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==", + "dependencies": { + "argparse": "^1.0.10", + "autolinker": "^3.11.0" + }, + "bin": { + "remarkable": "bin/remarkable.js" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://npm.lcr.gr/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "node_modules/repeat-element": { + "version": "1.1.3", + "resolved": "https://npm.lcr.gr/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://npm.lcr.gr/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15" + }, + "engines": { + "node": ">=0.10.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "deprecated": "request-promise-native has been deprecated because it extends the now deprecated request package, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + }, + "engines": { + "node": ">=0.12.0" + }, + "peerDependencies": { + "request": "^2.34" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dependencies": { + "path-parse": "^1.0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-path": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz", + "integrity": "sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc=", + "dependencies": { + "http-errors": "~1.6.2", + "path-is-absolute": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/resolve-path/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/resolve-path/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "node_modules/resolve-path/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/resolve-url": { + "version": "0.2.1", + "resolved": "https://npm.lcr.gr/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "deprecated": "https://github.com/lydell/resolve-url#deprecated", + "dev": true + }, + "node_modules/responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "dependencies": { + "lowercase-keys": "^1.0.0" + } + }, + "node_modules/ret": { + "version": "0.1.15", + "resolved": "https://npm.lcr.gr/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/retry-as-promised": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-3.2.0.tgz", + "integrity": "sha512-CybGs60B7oYU/qSQ6kuaFmRd9sTZ6oXSc0toqePvV74Ac6/IFZSI1ReFQmtCN+uvW1Mtqdwpvt/LGOiCBAY2Mg==", + "dependencies": { + "any-promise": "^1.3.0" + } + }, + "node_modules/retry-request": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/retry-request/-/retry-request-4.1.3.tgz", + "integrity": "sha512-QnRZUpuPNgX0+D1xVxul6DbJ9slvo4Rm6iV/dn63e048MvGbUZiKySVt6Tenp04JqmchxjiLltGerOJys7kJYQ==", + "dependencies": { + "debug": "^4.1.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/rndm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", + "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=" + }, + "node_modules/rsa-compat": { + "version": "2.0.8", + "resolved": "https://npm.lcr.gr/rsa-compat/-/rsa-compat-2.0.8.tgz", + "integrity": "sha512-BFiiSEbuxzsVdaxpejbxfX07qs+rtous49Y6mL/zw6YHh9cranDvm2BvBmqT3rso84IsxNlP5BXnuNvm1Wn3Tw==", + "dependencies": { + "keypairs": "^1.2.14" + }, + "bin": { + "rsa-keygen-js": "bin/rsa-keygen.js" + }, + "engines": { + "node": ">=10.12" + } + }, + "node_modules/rsvp": { + "version": "4.8.5", + "resolved": "https://npm.lcr.gr/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true, + "engines": { + "node": "6.* || >= 7.*" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safe-regex": { + "version": "1.1.0", + "resolved": "https://npm.lcr.gr/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "dependencies": { + "ret": "~0.1.10" + } + }, + "node_modules/safe-replace": { + "version": "1.1.0", + "resolved": "https://npm.lcr.gr/safe-replace/-/safe-replace-1.1.0.tgz", + "integrity": "sha512-9/V2E0CDsKs9DWOOwJH7jYpSl9S3N05uyevNjvsnDauBqRowBPOyot1fIvV5N2IuZAbYyvrTXrYFVG0RZInfFw==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/safetimeout": { + "version": "0.1.2", + "resolved": "https://npm.lcr.gr/safetimeout/-/safetimeout-0.1.2.tgz", + "integrity": "sha512-aSHXtzSwpO82gYr7zbDqBv8MFxT+X7d3FJEGXrZJwgZeyu8u7EHrTJcGmPeCEvvCPZDTdPwpvPtaq6qG0DzCoA==", + "deprecated": "Please use the 'safe-timers' module instead" + }, + "node_modules/sane": { + "version": "4.1.0", + "resolved": "https://npm.lcr.gr/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "deprecated": "some dependency vulnerabilities fixed, support for node < 10 dropped, and newer ECMAScript syntax/features added", + "dev": true, + "dependencies": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "bin": { + "sane": "src/cli.js" + }, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/sane/node_modules/anymatch": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "dependencies": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "node_modules/sane/node_modules/braces": { + "version": "2.3.2", + "resolved": "https://npm.lcr.gr/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "dependencies": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/braces/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/fill-range": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/fill-range/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/is-number": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/is-number/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/micromatch": { + "version": "3.1.10", + "resolved": "https://npm.lcr.gr/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "dependencies": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/normalize-path": { + "version": "2.1.1", + "resolved": "https://npm.lcr.gr/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "dependencies": { + "remove-trailing-separator": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sane/node_modules/to-regex-range": { + "version": "2.1.1", + "resolved": "https://npm.lcr.gr/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "dependencies": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/saxes": { + "version": "5.0.1", + "resolved": "https://npm.lcr.gr/saxes/-/saxes-5.0.1.tgz", + "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", + "dev": true, + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/scrypt-kdf": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/scrypt-kdf/-/scrypt-kdf-2.0.1.tgz", + "integrity": "sha512-dMhpgBVJPDWZP5erOCwTjI6oAO9hKhFAjZsdSQ0spaWJYHuA/wFNF2weQQfsyCIk8eNKoLfEDxr3zAtM+gZo0Q==", + "engines": { + "node": ">=8.5.0" + } + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=" + }, + "node_modules/semver": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", + "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "dependencies": { + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/semver-diff/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/sentence-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-3.0.3.tgz", + "integrity": "sha512-ZPr4dgTcNkEfcGOMFQyDdJrTU9uQO1nb1cjf+nuzb6FxgMDgKddZOM29qEsB7jvsZSMruLRcL2KfM4ypKpa0LA==", + "dependencies": { + "no-case": "^3.0.3", + "tslib": "^1.10.0", + "upper-case-first": "^2.0.1" + } + }, + "node_modules/sequelize": { + "version": "6.3.3", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-6.3.3.tgz", + "integrity": "sha512-WO/b1ehjSFKlBCHzwZoaPhoW3WyXXy9x74yPrOP8NpE67wzbv0dIucDO4a+THLVyl3lnv3nFMZdJRdkUgb/ZAw==", + "dependencies": { + "debug": "^4.1.1", + "dottie": "^2.0.0", + "inflection": "1.12.0", + "lodash": "^4.17.15", + "moment": "^2.26.0", + "moment-timezone": "^0.5.31", + "retry-as-promised": "^3.2.0", + "semver": "^7.3.2", + "sequelize-pool": "^6.0.0", + "toposort-class": "^1.0.1", + "uuid": "^8.1.0", + "validator": "^10.11.0", + "wkx": "^0.5.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependenciesMeta": { + "mariadb": { + "optional": true + }, + "mysql2": { + "optional": true + }, + "pg": { + "optional": true + }, + "pg-hstore": { + "optional": true + }, + "sqlite3": { + "optional": true + }, + "tedious": { + "optional": true + } + } + }, + "node_modules/sequelize-cli": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-6.2.0.tgz", + "integrity": "sha512-6WQ2x91hg30dUn66mXHnzvHATZ4pyI1GHSNbS/TNN/vRR4BLRSLijadeMgC8zqmKDsL0VqzVVopJWfJakuP++Q==", + "dependencies": { + "cli-color": "^1.4.0", + "fs-extra": "^7.0.1", + "js-beautify": "^1.8.8", + "lodash": "^4.17.5", + "resolve": "^1.5.0", + "umzug": "^2.3.0", + "yargs": "^13.1.0" + }, + "bin": { + "sequelize": "lib/sequelize", + "sequelize-cli": "lib/sequelize" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sequelize-pool": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/sequelize-pool/-/sequelize-pool-6.1.0.tgz", + "integrity": "sha512-4YwEw3ZgK/tY/so+GfnSgXkdwIJJ1I32uZJztIEgZeAO6HMgj64OzySbWLgxj+tXhZCJnzRfkY9gINw8Ft8ZMg==", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/sequelize/node_modules/semver": { + "version": "7.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.2.tgz", + "integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/set-value": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "dependencies": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-value/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://npm.lcr.gr/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shellwords": { + "version": "0.1.1", + "resolved": "https://npm.lcr.gr/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true, + "optional": true + }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "node_modules/signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==" + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://npm.lcr.gr/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.3.tgz", + "integrity": "sha512-WM1sIXEO+rsAHBKjGf/6R1HBBcgbncKS08d2Aqec/mrDSpU80SiOU41hO7ny6DToHSyrlwTYzQBIK1FPSx4Y3Q==", + "dependencies": { + "dot-case": "^3.0.3", + "tslib": "^1.10.0" + } + }, + "node_modules/snakeize": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/snakeize/-/snakeize-0.1.0.tgz", + "integrity": "sha1-EMCI2LWOsHazIpu1oE4jLOEmQi0=" + }, + "node_modules/snapdragon": { + "version": "0.8.2", + "resolved": "https://npm.lcr.gr/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "dependencies": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node": { + "version": "2.1.1", + "resolved": "https://npm.lcr.gr/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "dependencies": { + "is-descriptor": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", + "resolved": "https://npm.lcr.gr/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util": { + "version": "3.0.1", + "resolved": "https://npm.lcr.gr/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "dependencies": { + "kind-of": "^3.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://npm.lcr.gr/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://npm.lcr.gr/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/extend-shallow": { + "version": "2.0.1", + "resolved": "https://npm.lcr.gr/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://npm.lcr.gr/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sonic-boom": { + "version": "0.7.7", + "resolved": "https://npm.lcr.gr/sonic-boom/-/sonic-boom-0.7.7.tgz", + "integrity": "sha512-Ei5YOo5J64GKClHIL/5evJPgASXFVpfVYbJV9PILZQytTK6/LCwHvsZJW2Ig4p9FMC2OrBrMnXKgRN/OEoAWfg==", + "dependencies": { + "atomic-sleep": "^1.0.0", + "flatstr": "^1.0.12" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "resolved": "https://npm.lcr.gr/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "dependencies": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://npm.lcr.gr/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "resolved": "https://npm.lcr.gr/source-map-url/-/source-map-url-0.4.1.tgz", + "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://npm.lcr.gr/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://npm.lcr.gr/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://npm.lcr.gr/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.7", + "resolved": "https://npm.lcr.gr/spdx-license-ids/-/spdx-license-ids-3.0.7.tgz", + "integrity": "sha512-U+MTEOO0AiDzxwFvoa4JVnMV6mZlJKk2sBLt90s7G0Gd0Mlknc7kxEn3nuDPNZRta7O2uy8oLcZLVT+4sqNZHQ==", + "dev": true + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://npm.lcr.gr/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "resolved": "https://npm.lcr.gr/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "node_modules/sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stack-utils": { + "version": "2.0.3", + "resolved": "https://npm.lcr.gr/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-gL//fkxfWUsIlFL2Tl42Cl6+HFALEaB1FU76I/Fy+oZjRreP7OPMXFlGbxM7NQsI0ZpUfw76sHnv0WNYuTb7Iw==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/standard-as-callback": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.0.1.tgz", + "integrity": "sha512-NQOxSeB8gOI5WjSaxjBgog2QFw55FV8TkS6Y07BiB3VJ8xNTvUYm0wl0s8ObgQ5NhdpnNfigMIKjgPESzgr4tg==" + }, + "node_modules/static-extend": { + "version": "0.1.2", + "resolved": "https://npm.lcr.gr/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/static-extend/node_modules/define-property": { + "version": "0.2.5", + "resolved": "https://npm.lcr.gr/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "dependencies": { + "is-descriptor": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stream-events": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz", + "integrity": "sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg==", + "dependencies": { + "stubs": "^3.0.0" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "node_modules/streamsearch": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", + "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=", + "engines": { + "node": ">=0.8.0" + } + }, + "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_decoder/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/string-length": { + "version": "4.0.1", + "resolved": "https://npm.lcr.gr/string-length/-/string-length-4.0.1.tgz", + "integrity": "sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stubs": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz", + "integrity": "sha1-6NK6H6nJBXAwPAMLaQD31fiavls=" + }, + "node_modules/superagent": { + "version": "6.1.0", + "resolved": "https://npm.lcr.gr/superagent/-/superagent-6.1.0.tgz", + "integrity": "sha512-OUDHEssirmplo3F+1HWKUrUjvnQuA+nZI6i/JJBdXb5eq9IyEQwPyPpqND+SSsxf6TygpBEkUjISVRN4/VOpeg==", + "dev": true, + "dependencies": { + "component-emitter": "^1.3.0", + "cookiejar": "^2.1.2", + "debug": "^4.1.1", + "fast-safe-stringify": "^2.0.7", + "form-data": "^3.0.0", + "formidable": "^1.2.2", + "methods": "^1.1.2", + "mime": "^2.4.6", + "qs": "^6.9.4", + "readable-stream": "^3.6.0", + "semver": "^7.3.2" + }, + "engines": { + "node": ">= 7.0.0" + } + }, + "node_modules/superagent/node_modules/form-data": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/form-data/-/form-data-3.0.0.tgz", + "integrity": "sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/superagent/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/superagent/node_modules/mime": { + "version": "2.5.0", + "resolved": "https://npm.lcr.gr/mime/-/mime-2.5.0.tgz", + "integrity": "sha512-ft3WayFSFUVBuJj7BMLKAQcSlItKtfjsKDDsii3rqFDAZ7t11zRe8ASw/GlmivGwVUYtwkQrxiGGpL6gFvB0ag==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/superagent/node_modules/semver": { + "version": "7.3.4", + "resolved": "https://npm.lcr.gr/semver/-/semver-7.3.4.tgz", + "integrity": "sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/superagent/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/supertest": { + "version": "6.1.3", + "resolved": "https://npm.lcr.gr/supertest/-/supertest-6.1.3.tgz", + "integrity": "sha512-v2NVRyP73XDewKb65adz+yug1XMtmvij63qIWHZzSX8tp6wiq6xBLUy4SUAd2NII6wIipOmHT/FD9eicpJwdgQ==", + "dev": true, + "dependencies": { + "methods": "^1.1.2", + "superagent": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.1.0", + "resolved": "https://npm.lcr.gr/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz", + "integrity": "sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://npm.lcr.gr/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://npm.lcr.gr/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://npm.lcr.gr/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "node_modules/teeny-request": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/teeny-request/-/teeny-request-7.0.1.tgz", + "integrity": "sha512-sasJmQ37klOlplL4Ia/786M5YlOcoLGQyq2TE4WHSRupbAuDaQW0PfVxV4MtdBtRJ4ngzS+1qim8zP6Zp35qCw==", + "dependencies": { + "http-proxy-agent": "^4.0.0", + "https-proxy-agent": "^5.0.0", + "node-fetch": "^2.6.1", + "stream-events": "^1.0.5", + "uuid": "^8.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/term-size": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", + "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://npm.lcr.gr/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://npm.lcr.gr/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://npm.lcr.gr/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "node_modules/timers-ext": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.7.tgz", + "integrity": "sha512-b85NUNzTSdodShTIbky6ZF02e8STtVVfD+fu4aXXShEELpozH+bCpJLYMPZbsABN2wDH7fJpqIoXxJpzbf0NqQ==", + "dependencies": { + "es5-ext": "~0.10.46", + "next-tick": "1" + } + }, + "node_modules/tmpl": { + "version": "1.0.4", + "resolved": "https://npm.lcr.gr/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "resolved": "https://npm.lcr.gr/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://npm.lcr.gr/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "resolved": "https://npm.lcr.gr/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, + "node_modules/touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "dependencies": { + "nopt": "~1.0.10" + }, + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, + "node_modules/touch/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tr46": { + "version": "2.0.2", + "resolved": "https://npm.lcr.gr/tr46/-/tr46-2.0.2.tgz", + "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==" + }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "engines": { + "node": ">=0.6.x" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://npm.lcr.gr/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://npm.lcr.gr/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/uglify-js": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.10.0.tgz", + "integrity": "sha512-Esj5HG5WAyrLIdYU74Z3JdG2PxdIusvj6IWHMtlyESxc7kcDz7zYlYjpnSokn1UbpV0d/QX9fan7gkCNd/9BQA==", + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/umzug": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.3.0.tgz", + "integrity": "sha512-Z274K+e8goZK8QJxmbRPhl89HPO1K+ORFtm6rySPhFKfKc5GHhqdzD0SGhSWHkzoXasqJuItdhorSvY7/Cgflw==", + "dependencies": { + "bluebird": "^3.7.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "dependencies": { + "debug": "^2.2.0" + } + }, + "node_modules/undefsafe/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/undefsafe/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/underscore": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.10.2.tgz", + "integrity": "sha512-N4P+Q/BuyuEKFJ43B9gYuOj4TQUHXX+j2FqguVOpjkssLUUrnJofCcBccJSCoeturDoZU6GorDTHSvUDlSQbTg==" + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://npm.lcr.gr/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dependencies": { + "crypto-random-string": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "resolved": "https://npm.lcr.gr/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "resolved": "https://npm.lcr.gr/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "resolved": "https://npm.lcr.gr/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://npm.lcr.gr/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/update-notifier": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.0.tgz", + "integrity": "sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==", + "dev": true, + "dependencies": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/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==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/update-notifier/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==", + "dev": true + }, + "node_modules/update-notifier/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/upper-case": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-2.0.1.tgz", + "integrity": "sha512-laAsbea9SY5osxrv7S99vH9xAaJKrw5Qpdh4ENRLcaxipjKsiaBwiAsxfa8X5mObKNTQPsupSq0J/VIxsSJe3A==", + "dependencies": { + "tslib": "^1.10.0" + } + }, + "node_modules/upper-case-first": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-2.0.1.tgz", + "integrity": "sha512-105J8XqQ+9RxW3l9gHZtgve5oaiR9TIwvmZAMAIZWRHe00T21cdvewKORTlOJf/zXW6VukuTshM+HXZNWz7N5w==", + "dependencies": { + "tslib": "^1.10.0" + } + }, + "node_modules/uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "resolved": "https://npm.lcr.gr/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "deprecated": "Please see https://github.com/lydell/urix#deprecated", + "dev": true + }, + "node_modules/url-parse": { + "version": "1.4.7", + "resolved": "https://npm.lcr.gr/url-parse/-/url-parse-1.4.7.tgz", + "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==", + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "dependencies": { + "prepend-http": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/use": { + "version": "3.1.1", + "resolved": "https://npm.lcr.gr/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/uuid": { + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.1.tgz", + "integrity": "sha512-FOmRr+FmWEIG8uhZv6C2bTgEVXsHk08kE7mPlrBbEe+c3r9pjceVPgupIfNIhc4yx55H69OXANrUaSuu9eInKg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-to-istanbul": { + "version": "7.1.0", + "resolved": "https://npm.lcr.gr/v8-to-istanbul/-/v8-to-istanbul-7.1.0.tgz", + "integrity": "sha512-uXUVqNUCLa0AH1vuVxzi+MI4RfxEOKt9pBgKwHbgH7st8Kv2P1m+jvWNnektzBh5QShF3ODgKmUFCf38LnVz1g==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0", + "source-map": "^0.7.3" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/v8-to-istanbul/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://npm.lcr.gr/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/valid-url": { + "version": "1.0.9", + "resolved": "https://npm.lcr.gr/valid-url/-/valid-url-1.0.9.tgz", + "integrity": "sha1-HBRHm0DxOXp1eC8RXkCGRHQzogA=" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://npm.lcr.gr/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validator": { + "version": "10.11.0", + "resolved": "https://registry.npmjs.org/validator/-/validator-10.11.0.tgz", + "integrity": "sha512-X/p3UZerAIsbBfN/IwahhYaBbY68EN/UQBWHtsbXGT5bfrH/p4NQzUCG1kF/rtKaNpnJ7jAu6NGTdSNtyNIXMw==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/w3c-hr-time": { + "version": "1.0.2", + "resolved": "https://npm.lcr.gr/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", + "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", + "dev": true, + "dependencies": { + "browser-process-hrtime": "^1.0.0" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "2.0.0", + "resolved": "https://npm.lcr.gr/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", + "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", + "dev": true, + "dependencies": { + "xml-name-validator": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/walker": { + "version": "1.0.7", + "resolved": "https://npm.lcr.gr/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "dependencies": { + "makeerror": "1.0.x" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://npm.lcr.gr/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/webidl-conversions": { + "version": "6.1.0", + "resolved": "https://npm.lcr.gr/webidl-conversions/-/webidl-conversions-6.1.0.tgz", + "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", + "dev": true, + "engines": { + "node": ">=10.4" + } + }, + "node_modules/whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://npm.lcr.gr/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "dependencies": { + "iconv-lite": "0.4.24" + } + }, + "node_modules/whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://npm.lcr.gr/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "node_modules/whatwg-url": { + "version": "8.4.0", + "resolved": "https://npm.lcr.gr/whatwg-url/-/whatwg-url-8.4.0.tgz", + "integrity": "sha512-vwTUFf6V4zhcPkWp/4CQPr1TW9Ml6SF4lVyaIMBdJw5i6qUUJ1QWM4Z6YYVkfka0OUIzVo/0aNtGVGk256IKWw==", + "dev": true, + "dependencies": { + "lodash.sortby": "^4.7.0", + "tr46": "^2.0.2", + "webidl-conversions": "^6.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://npm.lcr.gr/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "node_modules/widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "dependencies": { + "string-width": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/widest-line/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/widest-line/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==", + "dev": true + }, + "node_modules/widest-line/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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/widest-line/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wkx": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.5.0.tgz", + "integrity": "sha512-Xng/d4Ichh8uN4l0FToV/258EjMGU9MGcA0HV2d9B/ZpZB3lqQm7nkOdZdm5GhKtLLhAE7PiVQwN4eN+2YJJUg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://npm.lcr.gr/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/ws": { + "version": "7.4.2", + "resolved": "https://npm.lcr.gr/ws/-/ws-7.4.2.tgz", + "integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==", + "dev": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/xml-name-validator": { + "version": "3.0.0", + "resolved": "https://npm.lcr.gr/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://npm.lcr.gr/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/ylru": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz", + "integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ==", + "engines": { + "node": ">= 4.0.0" + } + } + }, "dependencies": { "@babel/code-frame": { "version": "7.12.11", @@ -1007,7 +13333,8 @@ "@koa/multer": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@koa/multer/-/multer-3.0.0.tgz", - "integrity": "sha512-y+OQBmex5D1jIl723gAEUYcAWPEicIXppaAKw/zCMfpllQ08ZNweDPwoCLxEoatqd5pCu2XG6V8dl67JRq3RJw==" + "integrity": "sha512-y+OQBmex5D1jIl723gAEUYcAWPEicIXppaAKw/zCMfpllQ08ZNweDPwoCLxEoatqd5pCu2XG6V8dl67JRq3RJw==", + "requires": {} }, "@koa/router": { "version": "9.3.1", @@ -3311,6 +15638,11 @@ "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" }, + "faker": { + "version": "5.5.3", + "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", + "integrity": "sha512-wLTv2a28wjUyWkbnX7u/ABZBkUkIF2fCd73V6P2oFqEGEktDfzWx4UxrSqtPRw0xPRAcjeAOIiJWqZm3pP4u3g==" + }, "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -3809,6 +16141,16 @@ "resolved": "https://registry.npmjs.org/hash-stream-validation/-/hash-stream-validation-0.2.4.tgz", "integrity": "sha512-Gjzu0Xn7IagXVkSu9cSFuK1fqzwtLwFhNhVL8IFJijRNMgUttFbBSIAzKuSIrsFMO1+g1RlsoN49zPIbwPDMGQ==" }, + "hasura-cli": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/hasura-cli/-/hasura-cli-2.0.9.tgz", + "integrity": "sha512-95xAxNFfF1nntncULGKGQ9UEbhEWsgcMHdqOLsreq9E1emh2CVu1xuY/WezGMaCe1D4ZII7HxSQZBIhdnF9vKg==", + "dev": true, + "requires": { + "axios": "^0.21.1", + "chalk": "^2.4.2" + } + }, "header-case": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/header-case/-/header-case-2.0.3.tgz", @@ -5214,7 +17556,8 @@ "version": "1.2.2", "resolved": "https://npm.lcr.gr/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz", "integrity": "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w==", - "dev": true + "dev": true, + "requires": {} }, "jest-regex-util": { "version": "26.0.0", @@ -6345,9 +18688,9 @@ }, "dependencies": { "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "requires": { "ms": "^2.1.1" } @@ -6452,6 +18795,11 @@ "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", "dev": true }, + "lru_map": { + "version": "0.3.3", + "resolved": "https://npm.lcr.gr/lru_map/-/lru_map-0.3.3.tgz", + "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" + }, "lru-cache": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", @@ -6469,11 +18817,6 @@ "es5-ext": "~0.10.2" } }, - "lru_map": { - "version": "0.3.3", - "resolved": "https://npm.lcr.gr/lru_map/-/lru_map-0.3.3.tgz", - "integrity": "sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=" - }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -7254,7 +19597,8 @@ "pg-pool": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.2.1.tgz", - "integrity": "sha512-BQDPWUeKenVrMMDN9opfns/kZo4lxmSWhIqo+cSAF7+lfi9ZclQbr9vfnlNaPr8wYF3UYjm5X0yPAhbcgqNOdA==" + "integrity": "sha512-BQDPWUeKenVrMMDN9opfns/kZo4lxmSWhIqo+cSAF7+lfi9ZclQbr9vfnlNaPr8wYF3UYjm5X0yPAhbcgqNOdA==", + "requires": {} }, "pg-protocol": { "version": "1.2.5", @@ -7393,6 +19737,14 @@ "xtend": "^4.0.0" } }, + "postmark": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/postmark/-/postmark-2.7.1.tgz", + "integrity": "sha512-mevTZY8mZ2+DqBQweoUVsjlcsY2wu/WotDKplsFMiOy4mG7euOzmD4pqkWFymMVjeKbU52NZWEkO2Et1X0tdFw==", + "requires": { + "axios": "^0.21.1" + } + }, "prelude-ls": { "version": "1.1.2", "resolved": "https://npm.lcr.gr/prelude-ls/-/prelude-ls-1.1.2.tgz", @@ -7405,6 +19757,12 @@ "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", "dev": true }, + "prettier": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", + "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", + "dev": true + }, "pretty-format": { "version": "26.6.2", "resolved": "https://npm.lcr.gr/pretty-format/-/pretty-format-26.6.2.tgz", @@ -8695,6 +21053,21 @@ "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz", "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo=" }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "requires": { + "safe-buffer": "~5.2.0" + }, + "dependencies": { + "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==" + } + } + }, "string-length": { "version": "4.0.1", "resolved": "https://npm.lcr.gr/string-length/-/string-length-4.0.1.tgz", @@ -8732,21 +21105,6 @@ "strip-ansi": "^5.1.0" } }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - }, - "dependencies": { - "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==" - } - } - }, "strip-ansi": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", @@ -9656,7 +22014,8 @@ "version": "7.4.2", "resolved": "https://npm.lcr.gr/ws/-/ws-7.4.2.tgz", "integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA==", - "dev": true + "dev": true, + "requires": {} }, "xdg-basedir": { "version": "4.0.0", diff --git a/package.json b/package.json index 13d1e659bf5e0630f870966c5bc88af921f894e6..126ac92971e250bee18721b0ca37c6ebaed234f9 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,19 @@ { "name": "jetsam-api", - "version": "2.0.0-beta.1", + "version": "2.2.2", "description": "The Jetsam App API Server", "main": "server.js", "scripts": { "watch": "NODE_PATH=src DEBUG=server:* nodemon server --ignore './client/src' --ignore './certs' --ignore 'google-storage.json'", "watch:queue": "NODE_PATH=src QUEUE_ACTION=consumer DEBUG=server:* nodemon worker --ignore './client/src' --ignore './certs' --ignore 'google-storage.json'", "exec:env": "docker-compose -p jetenv up", - "exec:ngrok": "ngrok http 7123 --hostname trash.4l2.uk", + "exec:ngrok": "ngrok http 7124 --hostname trash.4l2.uk", "test": "NODE_ENV=testing NODE_PATH=src node scripts/jest.js", "start": "NODE_PATH=src node server", "cmd": "NODE_PATH=src node run", "sql": "NODE_PATH=src node scripts/npx-boot.js sequelize", - "repl": "NODE_PATH=src node -e 'Object.entries(require(\"bootstrap\")).forEach(([key, value]) => Object.defineProperty(global, key, { value })); boot().then(() => console.log(\"Booted\"))' -i" + "repl": "NODE_PATH=src node -e 'Object.entries(require(\"bootstrap\")).forEach(([key, value]) => Object.defineProperty(global, key, { value })); boot().then(() => console.log(\"Booted\"))' -i", + "prettier": "prettier server.js worker.js run.js src database --write" }, "author": "Louis Capitanchik <louis@microhacks.co.uk>", "license": "GPL-3.0+", @@ -31,6 +32,7 @@ "debug": "^4.2.0", "dotenv": "^8.2.0", "dotenv-expand": "^5.1.0", + "faker": "^5.5.3", "fs-jetpack": "^2.4.0", "handlebars": "^4.7.6", "ioredis": "^4.17.3", @@ -56,6 +58,7 @@ "pg": "^8.3.0", "pg-hstore": "^2.3.3", "pluralize": "^8.0.0", + "postmark": "^2.7.1", "redbird": "^0.10.0", "remarkable": "^2.0.1", "scrypt-kdf": "^2.0.1", @@ -65,8 +68,10 @@ "yargs": "^13.3.2" }, "devDependencies": { + "hasura-cli": "^2.0.9", "jest": "^26.6.3", "nodemon": "^2.0.4", + "prettier": "^2.2.1", "supertest": "^6.1.3" } } diff --git a/public/camera.png b/public/camera.png new file mode 100644 index 0000000000000000000000000000000000000000..5b26b4064f4a3e6f10d7b79cfb4608628fc2f234 --- /dev/null +++ b/public/camera.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c0e7823340c620d32e041c7e707fe2f69bca2077906dfc7cd4ad520d51c20df2 +size 798959 diff --git a/public/css/jetsam.css b/public/css/jetsam.css new file mode 100644 index 0000000000000000000000000000000000000000..0dce446709ed754e0bd4319a690da62e151b8bf8 --- /dev/null +++ b/public/css/jetsam.css @@ -0,0 +1,247 @@ +@import url('https://fonts.googleapis.com/css2?family=Bungee&family=Rubik:ital,wght@0,400;0,500;0,700;1,400&display=swap'); + +:root { + --font-headings: Bungee, cursive; + --font-body: Rubik, sans-serif; + + --colour-jetsam: #FF5E82; + --colour-jetsam-light: #FF7BAC; + --colour-jetsam-dark: #FF1D3C; + --colour-black: #292425; + --colour-white: #FAF9F9; + --colour-dark-grey: #697077; + --colour-light-grey: #DDE1E6; + + --colour-success: #48BB78; + --colour-success-dark: #25855A; + --colour-danger: #F56565; + --colour-danger-dark: #C53030; + + --padding-block: 4rem; + + --gradient-jetsam: linear-gradient(135deg, var(--colour-jetsam-light) 0%, var(--colour-jetsam-dark) 100%); + + --breakpoint-small: 720px; +} + +html { + height: 100%; +} + +body { + min-height: 100%; + background: var(--colour-white); + color: var(--colour-black); + + font-style: normal; + font-weight: normal; + font-size: 16px; + line-height: 19px; +} + +h1, h2, h3, h4, h5, p { + margin: 0; +} + +a { + color: var(--colour-jetsam); +} +a:hover { + color: var(--colour-jetsam-dark); +} + +.bg-jetsam { + background: var(--colour-jetsam); +} +.bg-jetsam-gradient { + background: var(--gradient-jetsam); +} + +.font-brand { + font-family: var(--font-headings); +} + +body, .font-body { + font-family: var(--font-body); +} +.text { + font-size: 16px; + line-height: 19px; +} +.text.lg { + font-size: 24px; + line-height: 28px; +} +.text.sm { + font-size: 12px; + line-height: 14px; +} +.text.head { + font-size: 32px; + line-height: 38px; +} +.text.bold { + font-weight: 500; +} + +.text.italic { + font-style: italic; +} +.text.caption { + font-weight: 700; + text-transform: uppercase; +} +.text.subtle { + color: var(--colour-dark-grey); +} +.text.light { + color: var(--colour-white); +} +.text.center { + text-align: center; +} +.split-container { + display: flex; + height: 100%; + align-items: stretch; +} +.split-container > .split-child { + flex: 1; + padding: var(--padding-block); + display: flex; + flex-direction: column; + align-items: flex-start; +} +.center-content { + justify-content: center; + align-items: center; +} +.row { + width: 100%; + display: flex; + align-items: center; +} +.row.space-1 > :not(:last-child) { + margin-right: 1rem; +} +.row.space-2 > :not(:last-child) { + margin-right: 2rem; +} +.row.space-4 > :not(:last-child) { + margin-right: 4rem; +} +.column { + display: flex; + flex-direction: column; + align-items: flex-start; +} +.column.space-1 > :not(:last-child) { + margin-bottom: 1rem; +} +.column.space-2 > :not(:last-child) { + margin-bottom: 2rem; +} +.column.space-4 > :not(:last-child) { + margin-bottom: 4rem; +} + +.form { + width: 100%; +} + +.form .control { + width: 100%; +} + +.form .control label, .form .control input { + padding: 0.5rem 0; +} +.form .control input { + box-sizing: border-box; + padding: 0.75rem; + width: 100%; + border-radius: 6px; + outline: none; + border: transparent 2px solid; + display: block; + background-color: var(--colour-light-grey); + transition: background-color 0.1s linear; +} + +.vertical-block { + padding-top: 10px; + padding-bottom: 10px; +} + +.form .control input:focus { + border-color: var(--colour-jetsam); + background-color: var(--colour-white); +} + +.button { + font-style: normal; + font-weight: 700; + font-size: 16px; + line-height: 19px; + text-transform: uppercase; + + width: 100%; + outline: none; + border: none; + margin: 0; + border-radius: 6px; + padding: 0.75rem; + + transition: background-color 0.1s linear; + cursor: pointer; +} + +.button.primary { + color: var(--colour-white); + background-color: var(--colour-jetsam); +} +.button.primary:hover { + background-color: var(--colour-jetsam-dark); +} + +.button.success { + color: var(--colour-white); + background-color: var(--colour-success); +} +.button.success:hover { + background-color: var(--colour-success-dark); +} + +.button.danger { + color: var(--colour-white); + background-color: var(--colour-danger); +} +.button.danger:hover { + background-color: var(--colour-danger-dark); +} + +.content { + width: 100%; + max-width: var(--breakpoint-small); + border-radius: 12px; + align-self: center; + padding: 20px; +} + +.content.focus { + background-color: var(--colour-white); +} + +@media (max-width: 720px) { + :root { + --padding-block: 2rem; + } + + .split-container { + flex-direction: column; + } + + .focus-content { + border-radius: 0; + } +} \ No newline at end of file diff --git a/public/css/reset.css b/public/css/reset.css new file mode 100644 index 0000000000000000000000000000000000000000..3895e8c460b199072e43693eb26eaeb8f5fb3984 --- /dev/null +++ b/public/css/reset.css @@ -0,0 +1,37 @@ +/*** The new CSS Reset - version 1.2.0 (last updated 23.7.2021) ***/ + +/* Remove all the styles of the "User-Agent-Stylesheet", except for the 'display' property */ +*:where(:not(iframe, canvas, img, svg, video):not(svg *)) { + all: unset; + display: revert; +} + +/* Preferred box-sizing value */ +*, +*::before, +*::after { + box-sizing: border-box; +} + +/* + Remove list styles (bullets/numbers) + in case you use it with normalize.css +*/ +ol, ul { + list-style: none; +} + +/* For images to not be able to exceed their container */ +img { + max-width: 100%; +} + +/* Removes spacing between cells in tables */ +table { + border-collapse: collapse; +} + +/* Revert the 'white-space' property for textarea elements on Safari */ +textarea { + white-space: revert; +} \ No newline at end of file diff --git a/public/ios-app-store-badge-2928664fe1fc6aca88583a6f606d60ba.svg b/public/ios-app-store-badge-2928664fe1fc6aca88583a6f606d60ba.svg new file mode 100644 index 0000000000000000000000000000000000000000..072b425a1ab785ee7143f0f0fba305f55bfb9678 --- /dev/null +++ b/public/ios-app-store-badge-2928664fe1fc6aca88583a6f606d60ba.svg @@ -0,0 +1,46 @@ +<svg id="livetype" xmlns="http://www.w3.org/2000/svg" width="119.66407" height="40" viewBox="0 0 119.66407 40"> + <title>Download_on_the_App_Store_Badge_US-UK_RGB_blk_4SVG_092917</title> + <g> + <g> + <g> + <path d="M110.13477,0H9.53468c-.3667,0-.729,0-1.09473.002-.30615.002-.60986.00781-.91895.0127A13.21476,13.21476,0,0,0,5.5171.19141a6.66509,6.66509,0,0,0-1.90088.627A6.43779,6.43779,0,0,0,1.99757,1.99707,6.25844,6.25844,0,0,0,.81935,3.61816a6.60119,6.60119,0,0,0-.625,1.90332,12.993,12.993,0,0,0-.1792,2.002C.00587,7.83008.00489,8.1377,0,8.44434V31.5586c.00489.3105.00587.6113.01515.9219a12.99232,12.99232,0,0,0,.1792,2.0019,6.58756,6.58756,0,0,0,.625,1.9043A6.20778,6.20778,0,0,0,1.99757,38.001a6.27445,6.27445,0,0,0,1.61865,1.1787,6.70082,6.70082,0,0,0,1.90088.6308,13.45514,13.45514,0,0,0,2.0039.1768c.30909.0068.6128.0107.91895.0107C8.80567,40,9.168,40,9.53468,40H110.13477c.3594,0,.7246,0,1.084-.002.3047,0,.6172-.0039.9219-.0107a13.279,13.279,0,0,0,2-.1768,6.80432,6.80432,0,0,0,1.9082-.6308,6.27742,6.27742,0,0,0,1.6172-1.1787,6.39482,6.39482,0,0,0,1.1816-1.6143,6.60413,6.60413,0,0,0,.6191-1.9043,13.50643,13.50643,0,0,0,.1856-2.0019c.0039-.3106.0039-.6114.0039-.9219.0078-.3633.0078-.7246.0078-1.0938V9.53613c0-.36621,0-.72949-.0078-1.09179,0-.30664,0-.61426-.0039-.9209a13.5071,13.5071,0,0,0-.1856-2.002,6.6177,6.6177,0,0,0-.6191-1.90332,6.46619,6.46619,0,0,0-2.7988-2.7998,6.76754,6.76754,0,0,0-1.9082-.627,13.04394,13.04394,0,0,0-2-.17676c-.3047-.00488-.6172-.01074-.9219-.01269-.3594-.002-.7246-.002-1.084-.002Z" style="fill: #a6a6a6"/> + <path d="M8.44483,39.125c-.30468,0-.602-.0039-.90429-.0107a12.68714,12.68714,0,0,1-1.86914-.1631,5.88381,5.88381,0,0,1-1.65674-.5479,5.40573,5.40573,0,0,1-1.397-1.0166,5.32082,5.32082,0,0,1-1.02051-1.3965,5.72186,5.72186,0,0,1-.543-1.6572,12.41351,12.41351,0,0,1-.1665-1.875c-.00634-.2109-.01464-.9131-.01464-.9131V8.44434S.88185,7.75293.8877,7.5498a12.37039,12.37039,0,0,1,.16553-1.87207,5.7555,5.7555,0,0,1,.54346-1.6621A5.37349,5.37349,0,0,1,2.61183,2.61768,5.56543,5.56543,0,0,1,4.01417,1.59521a5.82309,5.82309,0,0,1,1.65332-.54394A12.58589,12.58589,0,0,1,7.543.88721L8.44532.875H111.21387l.9131.0127a12.38493,12.38493,0,0,1,1.8584.16259,5.93833,5.93833,0,0,1,1.6709.54785,5.59374,5.59374,0,0,1,2.415,2.41993,5.76267,5.76267,0,0,1,.5352,1.64892,12.995,12.995,0,0,1,.1738,1.88721c.0029.2832.0029.5874.0029.89014.0079.375.0079.73193.0079,1.09179V30.4648c0,.3633,0,.7178-.0079,1.0752,0,.3252,0,.6231-.0039.9297a12.73126,12.73126,0,0,1-.1709,1.8535,5.739,5.739,0,0,1-.54,1.67,5.48029,5.48029,0,0,1-1.0156,1.3857,5.4129,5.4129,0,0,1-1.3994,1.0225,5.86168,5.86168,0,0,1-1.668.5498,12.54218,12.54218,0,0,1-1.8692.1631c-.2929.0068-.5996.0107-.8974.0107l-1.084.002Z"/> + </g> + <g id="_Group_" data-name="<Group>"> + <g id="_Group_2" data-name="<Group>"> + <g id="_Group_3" data-name="<Group>"> + <path id="_Path_" data-name="<Path>" d="M24.76888,20.30068a4.94881,4.94881,0,0,1,2.35656-4.15206,5.06566,5.06566,0,0,0-3.99116-2.15768c-1.67924-.17626-3.30719,1.00483-4.1629,1.00483-.87227,0-2.18977-.98733-3.6085-.95814a5.31529,5.31529,0,0,0-4.47292,2.72787c-1.934,3.34842-.49141,8.26947,1.3612,10.97608.9269,1.32535,2.01018,2.8058,3.42763,2.7533,1.38706-.05753,1.9051-.88448,3.5794-.88448,1.65876,0,2.14479.88448,3.591.8511,1.48838-.02416,2.42613-1.33124,3.32051-2.66914a10.962,10.962,0,0,0,1.51842-3.09251A4.78205,4.78205,0,0,1,24.76888,20.30068Z" style="fill: #fff"/> + <path id="_Path_2" data-name="<Path>" d="M22.03725,12.21089a4.87248,4.87248,0,0,0,1.11452-3.49062,4.95746,4.95746,0,0,0-3.20758,1.65961,4.63634,4.63634,0,0,0-1.14371,3.36139A4.09905,4.09905,0,0,0,22.03725,12.21089Z" style="fill: #fff"/> + </g> + </g> + <g> + <path d="M42.30227,27.13965h-4.7334l-1.13672,3.35645H34.42727l4.4834-12.418h2.083l4.4834,12.418H43.438ZM38.0591,25.59082h3.752l-1.84961-5.44727h-.05176Z" style="fill: #fff"/> + <path d="M55.15969,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H48.4302v1.50586h.03418a3.21162,3.21162,0,0,1,2.88281-1.60059C53.645,21.34766,55.15969,23.16406,55.15969,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C52.30227,29.01563,53.24953,27.81934,53.24953,25.96973Z" style="fill: #fff"/> + <path d="M65.12453,25.96973c0,2.81348-1.50586,4.62109-3.77832,4.62109a3.0693,3.0693,0,0,1-2.84863-1.584h-.043v4.48438h-1.8584V21.44238H58.395v1.50586h.03418A3.21162,3.21162,0,0,1,61.312,21.34766C63.60988,21.34766,65.12453,23.16406,65.12453,25.96973Zm-1.91016,0c0-1.833-.94727-3.03809-2.39258-3.03809-1.41992,0-2.375,1.23047-2.375,3.03809,0,1.82422.95508,3.0459,2.375,3.0459C62.26711,29.01563,63.21438,27.81934,63.21438,25.96973Z" style="fill: #fff"/> + <path d="M71.71047,27.03613c.1377,1.23145,1.334,2.04,2.96875,2.04,1.56641,0,2.69336-.80859,2.69336-1.91895,0-.96387-.67969-1.541-2.28906-1.93652l-1.60937-.3877c-2.28027-.55078-3.33887-1.61719-3.33887-3.34766,0-2.14258,1.86719-3.61426,4.51855-3.61426,2.624,0,4.42285,1.47168,4.4834,3.61426h-1.876c-.1123-1.23926-1.13672-1.9873-2.63379-1.9873s-2.52148.75684-2.52148,1.8584c0,.87793.6543,1.39453,2.25488,1.79l1.36816.33594c2.54785.60254,3.60645,1.626,3.60645,3.44238,0,2.32324-1.85059,3.77832-4.79395,3.77832-2.75391,0-4.61328-1.4209-4.7334-3.667Z" style="fill: #fff"/> + <path d="M83.34621,19.2998v2.14258h1.72168v1.47168H83.34621v4.99121c0,.77539.34473,1.13672,1.10156,1.13672a5.80752,5.80752,0,0,0,.61133-.043v1.46289a5.10351,5.10351,0,0,1-1.03223.08594c-1.833,0-2.54785-.68848-2.54785-2.44434V22.91406H80.16262V21.44238H81.479V19.2998Z" style="fill: #fff"/> + <path d="M86.065,25.96973c0-2.84863,1.67773-4.63867,4.29395-4.63867,2.625,0,4.29492,1.79,4.29492,4.63867,0,2.85645-1.66113,4.63867-4.29492,4.63867C87.72609,30.6084,86.065,28.82617,86.065,25.96973Zm6.69531,0c0-1.9541-.89551-3.10742-2.40137-3.10742s-2.40039,1.16211-2.40039,3.10742c0,1.96191.89453,3.10645,2.40039,3.10645S92.76027,27.93164,92.76027,25.96973Z" style="fill: #fff"/> + <path d="M96.18606,21.44238h1.77246v1.541h.043a2.1594,2.1594,0,0,1,2.17773-1.63574,2.86616,2.86616,0,0,1,.63672.06934v1.73828a2.59794,2.59794,0,0,0-.835-.1123,1.87264,1.87264,0,0,0-1.93652,2.083v5.37012h-1.8584Z" style="fill: #fff"/> + <path d="M109.3843,27.83691c-.25,1.64355-1.85059,2.77148-3.89844,2.77148-2.63379,0-4.26855-1.76465-4.26855-4.5957,0-2.83984,1.64355-4.68164,4.19043-4.68164,2.50488,0,4.08008,1.7207,4.08008,4.46582v.63672h-6.39453v.1123a2.358,2.358,0,0,0,2.43555,2.56445,2.04834,2.04834,0,0,0,2.09082-1.27344Zm-6.28223-2.70215h4.52637a2.1773,2.1773,0,0,0-2.2207-2.29785A2.292,2.292,0,0,0,103.10207,25.13477Z" style="fill: #fff"/> + </g> + </g> + </g> + <g id="_Group_4" data-name="<Group>"> + <g> + <path d="M37.82619,8.731a2.63964,2.63964,0,0,1,2.80762,2.96484c0,1.90625-1.03027,3.002-2.80762,3.002H35.67092V8.731Zm-1.22852,5.123h1.125a1.87588,1.87588,0,0,0,1.96777-2.146,1.881,1.881,0,0,0-1.96777-2.13379h-1.125Z" style="fill: #fff"/> + <path d="M41.68068,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C44.57522,13.99463,45.01369,13.42432,45.01369,12.44434Z" style="fill: #fff"/> + <path d="M51.57326,14.69775h-.92187l-.93066-3.31641h-.07031l-.92676,3.31641h-.91309l-1.24121-4.50293h.90137l.80664,3.436h.06641l.92578-3.436h.85254l.92578,3.436h.07031l.80273-3.436h.88867Z" style="fill: #fff"/> + <path d="M53.85354,10.19482H54.709v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915h-.88867V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/> + <path d="M59.09377,8.437h.88867v6.26074h-.88867Z" style="fill: #fff"/> + <path d="M61.21779,12.44434a2.13346,2.13346,0,1,1,4.24756,0,2.1338,2.1338,0,1,1-4.24756,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C64.11232,13.99463,64.5508,13.42432,64.5508,12.44434Z" style="fill: #fff"/> + <path d="M66.4009,13.42432c0-.81055.60352-1.27783,1.6748-1.34424l1.21973-.07031v-.38867c0-.47559-.31445-.74414-.92187-.74414-.49609,0-.83984.18213-.93848.50049h-.86035c.09082-.77344.81836-1.26953,1.83984-1.26953,1.12891,0,1.76563.562,1.76563,1.51318v3.07666h-.85547v-.63281h-.07031a1.515,1.515,0,0,1-1.35254.707A1.36026,1.36026,0,0,1,66.4009,13.42432Zm2.89453-.38477v-.37646l-1.09961.07031c-.62012.0415-.90137.25244-.90137.64941,0,.40527.35156.64111.835.64111A1.0615,1.0615,0,0,0,69.29543,13.03955Z" style="fill: #fff"/> + <path d="M71.34816,12.44434c0-1.42285.73145-2.32422,1.86914-2.32422a1.484,1.484,0,0,1,1.38086.79h.06641V8.437h.88867v6.26074h-.85156v-.71143h-.07031a1.56284,1.56284,0,0,1-1.41406.78564C72.0718,14.772,71.34816,13.87061,71.34816,12.44434Zm.918,0c0,.95508.4502,1.52979,1.20313,1.52979.749,0,1.21191-.583,1.21191-1.52588,0-.93848-.46777-1.52979-1.21191-1.52979C72.72121,10.91846,72.26613,11.49707,72.26613,12.44434Z" style="fill: #fff"/> + <path d="M79.23,12.44434a2.13323,2.13323,0,1,1,4.24707,0,2.13358,2.13358,0,1,1-4.24707,0Zm3.333,0c0-.97607-.43848-1.54687-1.208-1.54687-.77246,0-1.207.5708-1.207,1.54688,0,.98389.43457,1.55029,1.207,1.55029C82.12453,13.99463,82.563,13.42432,82.563,12.44434Z" style="fill: #fff"/> + <path d="M84.66945,10.19482h.85547v.71533h.06641a1.348,1.348,0,0,1,1.34375-.80225,1.46456,1.46456,0,0,1,1.55859,1.6748v2.915H87.605V12.00586c0-.72363-.31445-1.0835-.97168-1.0835a1.03294,1.03294,0,0,0-1.0752,1.14111v2.63428h-.88867Z" style="fill: #fff"/> + <path d="M93.51516,9.07373v1.1416h.97559v.74854h-.97559V13.2793c0,.47168.19434.67822.63672.67822a2.96657,2.96657,0,0,0,.33887-.02051v.74023a2.9155,2.9155,0,0,1-.4834.04541c-.98828,0-1.38184-.34766-1.38184-1.21582v-2.543h-.71484v-.74854h.71484V9.07373Z" style="fill: #fff"/> + <path d="M95.70461,8.437h.88086v2.48145h.07031a1.3856,1.3856,0,0,1,1.373-.80664,1.48339,1.48339,0,0,1,1.55078,1.67871v2.90723H98.69v-2.688c0-.71924-.335-1.0835-.96289-1.0835a1.05194,1.05194,0,0,0-1.13379,1.1416v2.62988h-.88867Z" style="fill: #fff"/> + <path d="M104.76125,13.48193a1.828,1.828,0,0,1-1.95117,1.30273A2.04531,2.04531,0,0,1,100.73,12.46045a2.07685,2.07685,0,0,1,2.07617-2.35254c1.25293,0,2.00879.856,2.00879,2.27V12.688h-3.17969v.0498a1.1902,1.1902,0,0,0,1.19922,1.29,1.07934,1.07934,0,0,0,1.07129-.5459Zm-3.126-1.45117h2.27441a1.08647,1.08647,0,0,0-1.1084-1.1665A1.15162,1.15162,0,0,0,101.63527,12.03076Z" style="fill: #fff"/> + </g> + </g> + </g> +</svg> diff --git a/public/logo.png b/public/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..4ba916fb3e6dea1378b96fc2f73dfae48b9c5fb8 --- /dev/null +++ b/public/logo.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6521c82a8519e2ae987ad3d4a6143681a4618b4fa3a5585f82aa65a778403928 +size 97893 diff --git a/public/main.css b/public/main.css new file mode 100644 index 0000000000000000000000000000000000000000..921ada56d0947bd5f698ac28978af3e0f556b2d0 --- /dev/null +++ b/public/main.css @@ -0,0 +1,50 @@ +* { + margin: 0; + padding: 0; +} + +html { + font-size: 16px; + font-family: Arial, sans-serif; +} + +.container { + display: flex; + flex-direction: column; + padding: 2rem; + align-items: center; +} + +.inner { + width: 100%; + max-width: 600px; +} + +.row { + display: flex; +} + +.header { + padding: 1rem 0; +} + +.text-container { + padding: 2rem; +} + +.centered { + padding: 1rem 0; +} + +.controls { + display: flex; + flex-direction: column; + flex: 1; + max-width: 300px; +} + +.controls input { + width: 100%; + padding: 5px; + margin: 5px 0; +} \ No newline at end of file diff --git a/run.js b/run.js index c2033eae1fb8df6bbb9a6a4bd8ed61de8af03f60..13f1ee6e294cbfc4fd646cc72aeb8317c22eb291 100644 --- a/run.js +++ b/run.js @@ -11,8 +11,7 @@ async function runWorker() { .commandDir(bootstrap.fs.path('src', 'console')) .demandCommand() .recommendCommands() - .help() - .argv + .help().argv } async function runMaster() { @@ -44,9 +43,7 @@ async function run() { } } - -run() - .catch(e => { - console.error(e) - process.exit(1) - }) \ No newline at end of file +run().catch(e => { + console.error(e) + process.exit(1) +}) diff --git a/server.js b/server.js index 339c0902d001a326478040cba144cf7f5e15b7ec..62e95633b796562d6bfd36d925954447eb6ec96e 100644 --- a/server.js +++ b/server.js @@ -9,7 +9,7 @@ const debug = require('debug')('server:boot') const pkg = require('./package.json') const Sentry = require('@sentry/node') -const Tracing = require("@sentry/tracing"); +const Tracing = require('@sentry/tracing') let server = null let worker = null @@ -20,18 +20,21 @@ function bindSentry(app) { debug('Binding sentry to app level errors') - app.on("error", (err, ctx) => { + app.on('error', (err, ctx) => { console.error(err) - Sentry.withScope(function(scope) { - scope.addEventProcessor(function(event) { - return Sentry.Handlers.parseRequest(event, ctx.request); - }); - Sentry.captureException(err); - }); - }); + Sentry.withScope(function (scope) { + scope.addEventProcessor(function (event) { + return Sentry.Handlers.parseRequest(event, ctx.request) + }) + Sentry.captureException(err) + }) + }) } -async function launch(port = 0, host = config('app.host.web', `http://localhost:${ port }`)) { +async function launch( + port = 0, + host = config('app.host.web', `http://localhost:${port}`), +) { const koa = new Koa() const appserver = await app(koa) @@ -41,7 +44,7 @@ async function launch(port = 0, host = config('app.host.web', `http://localhost: const httpServer = http.createServer(appserver.callback()) httpServer.listen(port) - debug(`Listening on ${ host }`) + debug(`Listening on ${host}`) server = httpServer @@ -62,9 +65,9 @@ async function runProxy() { throw new Error('Failed to start') } - debug(`Binding hosts [${ hosts.join(', ') }] to server port ${ address.port}`) + debug(`Binding hosts [${hosts.join(', ')}] to server port ${address.port}`) for (const host of hosts) { - proxy.register(host, `http://127.0.0.1:${ address.port }`) + proxy.register(host, `http://127.0.0.1:${address.port}`) } } @@ -89,18 +92,12 @@ async function main() { } } -main() - .catch(e => { - console.error(e) - process.exit(1) - }) - +main().catch(e => { + console.error(e) + process.exit(1) +}) -const cleanupsigs = [ - 'SIGINT', - 'SIGTERM', - 'SIGUSR2', -] +const cleanupsigs = ['SIGINT', 'SIGTERM', 'SIGUSR2'] cleanupsigs.forEach(signal => { process.on(signal, () => { diff --git a/src/app.js b/src/app.js index 293f58336bbf62df4324883e4ae5d416e32f03db..72b1476d456a34b0433ff1dfd60239dbea2b691d 100644 --- a/src/app.js +++ b/src/app.js @@ -4,10 +4,13 @@ const logger = require('koa-logger') const bodyparser = require('koa-bodyparser') const etag = require('koa-etag') const session = require('koa-session') +const static = require('koa-static') const hbs = require('vendor/koa-handlebars') const { config } = require('bootstrap') +const pathutil = require('path') + const debughbs = require('debug')('server:templates') const debug = require('debug')('server:boot') const requestLog = require('debug')('server:request') @@ -20,20 +23,28 @@ module.exports = async function createApp(app = new Koa()) { app.keys = [config('app.key')] - app.use(hbs(fs.path('views'), { - debug: debughbs, - })) + app.use( + hbs(fs.path('views'), { + debug: debughbs, + }), + ) app.use(etag({ weak: true })) app.use(bodyparser()) app.use(logger(s => requestLog(s))) + app.use(static(pathutil.resolve(__dirname + '/../public'))) - app.use(session({ - key: config('app.session_key'), - renew: true, - secure: config('app.secure_sessions'), - signed: true, - httpOnly: true, - }, app)) + app.use( + session( + { + key: config('app.session_key'), + renew: true, + secure: config('app.secure_sessions'), + signed: true, + httpOnly: true, + }, + app, + ), + ) if (!config('app.secure_sessions')) { debug('Sessions are not restricted to HTTPS') @@ -44,7 +55,11 @@ module.exports = async function createApp(app = new Koa()) { app.use(serviceProvider.attach) Object.values(routers).forEach(router => { - debug('[Prefix "%s"] Mounting %d layers', router.opts?.prefix ?? '/', router.stack?.length ?? 0) + debug( + '[Prefix "%s"] Mounting %d layers', + router.opts?.prefix ?? '/', + router.stack?.length ?? 0, + ) app.use(router.routes()) app.use(router.allowedMethods()) }) diff --git a/src/bootstrap.js b/src/bootstrap.js index 09bf9daab08924efc1544fe436562933ac11ba93..3d82b02b66c6a0019a4a925019e01280ae888a9c 100644 --- a/src/bootstrap.js +++ b/src/bootstrap.js @@ -13,7 +13,7 @@ require('core/events/register') exports.unset = Symbol('unset') -exports.boot = async function() { +exports.boot = async function () { const dotenv = require('dotenv') const expand = require('dotenv-expand') const { loadKeys } = require('core/utils/jwt') @@ -23,7 +23,9 @@ exports.boot = async function() { expand(conf) } - const envEnv = dotenv.config({ path: `.env.${ process.env.NODE_ENV ?? 'development' }`}) + const envEnv = dotenv.config({ + path: `.env.${process.env.NODE_ENV ?? 'development'}`, + }) expand(envEnv) const conf = dotenv.config() @@ -32,8 +34,7 @@ exports.boot = async function() { if (exports.env('GCS_CREDENTIALS_B64', '').trim() !== '') { await exports.fs.writeAsync( 'google-storage.json', - Buffer.from(exports.env('GCS_CREDENTIALS_B64'), 'base64') - .toString() + Buffer.from(exports.env('GCS_CREDENTIALS_B64'), 'base64').toString(), ) } @@ -105,14 +106,13 @@ exports.config = function getConfigValue(path, fallback = null) { const [file, ...innerPath] = path.split('.') let conf = null try { - conf = require(`./config/${ file }`) + conf = require(`./config/${file}`) } catch (e) { console.error(e) // require('services').log.error(e) return fallback } - if (conf.hasOwnProperty('driver')) { if (innerPath.length === 1 && innerPath[0] === 'driver') { return conf.driver @@ -131,8 +131,8 @@ exports.patchConfig = function setConfigValue(path, value) { const [file, ...innerPath] = path.split('.') let conf = null try { - conf = require(`./config/${ file }`) - } catch(e) { + conf = require(`./config/${file}`) + } catch (e) { console.error(e) return null } @@ -155,21 +155,21 @@ exports.fs = jetpack.cwd(pathUtil.join(__dirname, '..')) exports.url = { web(name, params) { const routes = require('./http/routes') - return (new URL( - routes.web.url(name, params), - exports.config('app.host.web')) + return new URL( + routes.web.url(name, params), + exports.config('app.host.web'), ).toString() }, api(name, params) { const routes = require('./http/routes') - return (new URL( - pathUtil.join('api', routes.api.url(name, params)), - exports.config('app.host.api')) + return new URL( + pathUtil.join('api', routes.api.url(name, params)), + exports.config('app.host.api'), ).toString() }, } -exports.route = function(type, name, params) { +exports.route = function (type, name, params) { const routers = require('http/routes') if (!routers.hasOwnProperty(type)) { return null @@ -180,7 +180,9 @@ exports.route = function(type, name, params) { } exports.routes = { - api(name, params) { return exports.route('api', name, params) }, + api(name, params) { + return exports.route('api', name, params) + }, } exports.invoke = async function invokeCommand(command, args = [], sync = true) { @@ -193,6 +195,6 @@ exports.invoke = async function invokeCommand(command, args = [], sync = true) { ...process.env, NODE_PATH: __dirname, }, - stdio: 'inherit' + stdio: 'inherit', }) -} \ No newline at end of file +} diff --git a/src/config/app.js b/src/config/app.js index 333b95cdc679860f160a76ba64c20687f123fc95..6cdbb052505bb40da2517c53f3d3513f682dac51 100644 --- a/src/config/app.js +++ b/src/config/app.js @@ -3,7 +3,7 @@ const { env } = require('bootstrap') module.exports = { env: env('NODE_ENV', 'development'), key: env('APP_KEY', new Error('No App Key Set')), - session_key: env('SESSION_IDENTIFIER', 'hf.sid'), + session_key: env('SESSION_IDENTIFIER', 'jetsam.sid'), port: Number(env('PORT', 4000)), name: env('APP_NAME', 'application'), host: { @@ -17,7 +17,15 @@ module.exports = { public_key_b64: env('RSA_PUBLIC_KEY_B64', null), private_key: null, private_key_b64: env('RSA_PRIVATE_KEY_B64', null), - } + key_id: env('JWK_KEY_ID', null), + super_auth_clients: env('ADMIN_AUTH_CLIENTS', '') + .split(',') + .map(s => s.trim()) + .filter(Boolean) + }, } -module.exports.secure_session = env('SECURE_SESSIONS') != null ? env('SECURE_SESSIONS') !== 'FALSE' : !module.exports.dev +module.exports.secure_session = + env('SECURE_SESSIONS') != null + ? env('SECURE_SESSIONS') !== 'FALSE' + : !module.exports.dev diff --git a/src/config/client.js b/src/config/client.js index 88205e6742295c2359669d75d3a39e3e5108c0bd..4bcd6e0813bb3816caf8cf0f0aa32d7d86bcae7c 100644 --- a/src/config/client.js +++ b/src/config/client.js @@ -8,5 +8,5 @@ module.exports = { red: '#ff8080', yellow: '#ffdd67', orange: '#ffba92', - } + }, } diff --git a/src/config/database.js b/src/config/database.js index a200bb95863d4d7f5caa2fc7a5dad83401813c08..c681d35091401844ce5e918c920f875e2933ea09 100644 --- a/src/config/database.js +++ b/src/config/database.js @@ -1,7 +1,11 @@ const { env } = require('bootstrap') - const pg = require('pg') -pg.defaults.ssl = true + +const useSSL = env('DATABASE_SSL_REQUIRE', 'false') === 'true' + +if (useSSL) { + pg.defaults.ssl = true +} const url = env('DATABASE_URL') if (url) { @@ -18,20 +22,23 @@ if (url) { } else { module.exports = { host: env('DATABASE_HOST', '127.0.0.1'), - database: env('DATABASE_NAME', 'hackerfest'), + database: env('DATABASE_NAME', 'jetsam'), username: env('DATABASE_USER', null), password: env('DATABASE_PASS', null), port: env('DATABASE_PORT', '5432'), - ssl: env('DATABASE_SSL_REQUIRE', 'false') === 'true', - dialectOptions: { + ssl: useSSL, + dialectOptions: useSSL ? { ssl: { rejectUnauthorized: false, - ca: Buffer.from(env('DATABASE_CA_CERT', null) ?? '', 'base64').toString(), - } - }, + ca: Buffer.from( + env('DATABASE_CA_CERT', null) ?? '', + 'base64', + ).toString(), + }, + } : {}, log_queries: env('LOG_SQL_QUERIES', 'true') === 'true', } } // module.exports.logging = require('debug')('server:database') -module.exports.logging = false \ No newline at end of file +module.exports.logging = false diff --git a/src/config/mail.js b/src/config/mail.js index d9735e85b56662572fb9753d6f2e2734d26607c7..221b3722d89eb1ef47fa4d9d4788f1d23172de6a 100644 --- a/src/config/mail.js +++ b/src/config/mail.js @@ -1,7 +1,9 @@ const { env, config } = require('bootstrap') const fromTo = { - from: env('MAIL_FROM', () => { throw new Error('Missing mail from address')}), + from: env('MAIL_FROM', () => { + throw new Error('Missing mail from address') + }), name: env('MAIL_FROM_NAME', 'Autobot'), replyto: env('MAIL_REPLY_TO', () => config('mail.from', null)), } @@ -9,7 +11,9 @@ const fromTo = { module.exports = { driver: env('MAIL_DRIVER', 'log'), sendgrid: { - key: env('SENDGRID_KEY', () => { throw new Error('Missing Sendgrid Key') }), + key: env('SENDGRID_KEY', () => { + throw new Error('Missing Sendgrid Key') + }), ...fromTo, opts: { from: { @@ -25,6 +29,25 @@ module.exports = { 'reset-password': 'd-dd89d66ad75f40f5b3b0ed6849753cf7', }, }, + postmark: { + key: env('POSTMARK_KEY', () => { + throw new Error('Missing Postmark Key') + }), + ...fromTo, + opts: { + from: { + email: env('MAIL_FROM'), + name: env('MAIL_FROM_NAME'), + }, + replyTo: { + email: env('MAIL_REPLY_TO'), + name: env('MAIL_FROM_NAME'), + }, + }, + templates: { + 'reset-password': '22427615', + }, + }, log: { ...fromTo, }, @@ -34,5 +57,5 @@ module.exports = { port: env('SMTP_PORT'), user: env('SMTP_USERNAME'), password: env('SMTP_PASSWORD'), - } + }, } diff --git a/src/config/pusher.js b/src/config/pusher.js index 99a172b2fea42e9857e28c6edd46b44d7abb6ad3..fc61e5028c46b681d9fabb9df1782efecbd8c758 100644 --- a/src/config/pusher.js +++ b/src/config/pusher.js @@ -4,5 +4,5 @@ module.exports = { id: env('PUSHER_APP_ID'), key: env('PUSHER_APP_KEY'), secret: env('PUSHER_APP_SECRET'), - region: env('PUSHER_APP_REGION') + region: env('PUSHER_APP_REGION'), } diff --git a/src/config/queue.js b/src/config/queue.js index c7437c81cff3a52a96ce123e3303edc325e9def5..3e6a3f4f334ee53e3c87b633df3490686ed80966 100644 --- a/src/config/queue.js +++ b/src/config/queue.js @@ -3,10 +3,13 @@ const { env } = require('bootstrap') module.exports = { driver: env('QUEUE_DRIVER', 'async'), amqp: { + url: env('AMQP_DSN', undefined), host: env('AMQP_HOST'), port: env('AMQP_PORT'), user: env('AMQP_USER', 'guest'), pass: env('AMQP_PASSWORD', 'guest'), + vhost: env('AMQP_VHOST', undefined), secure: env('AMQP_SECURE', 'false') === 'true', - } -} \ No newline at end of file + retries: parseInt(env('QUEUE_RETRIES', '5'), 10), + }, +} diff --git a/src/config/sequelize.js b/src/config/sequelize.js index 585e1b1d90c7e6c391c785e566772251893486fb..99516bffaf2779a73e6cc243a1adb2f597e55599 100644 --- a/src/config/sequelize.js +++ b/src/config/sequelize.js @@ -7,13 +7,13 @@ module.exports = { password: 'hackerfest', database: 'hackerfest', host: '127.0.0.1', - ...(config('database', {})), + ...config('database', {}), dialect: 'postgres', pool: { max: 5, min: 1, acquire: 30000, - idle: 10000 + idle: 10000, }, define: { timestamps: true, @@ -26,13 +26,13 @@ module.exports = { password: 'hackerfest', database: 'hackerfest', host: '127.0.0.1', - ...(config('database', {})), + ...config('database', {}), dialect: 'postgres', pool: { max: 10, min: 1, acquire: 30000, - idle: 10000 + idle: 10000, }, define: { timestamps: true, @@ -45,13 +45,13 @@ module.exports = { password: 'hackerfest', database: 'hackerfest', host: '127.0.0.1', - ...(config('database', {})), + ...config('database', {}), dialect: 'postgres', pool: { max: 10, min: 1, acquire: 30000, - idle: 10000 + idle: 10000, }, define: { timestamps: true, diff --git a/src/config/totp.js b/src/config/totp.js index e0d77cdc0e010fd9373f178af3001d690cb1fc0a..5c518ff40abf9e49d4f0feacead3475c3d125c3f 100644 --- a/src/config/totp.js +++ b/src/config/totp.js @@ -2,7 +2,5 @@ const { env } = require('bootstrap') module.exports = { driver: env('TOTP_DRIVER', 'vault'), - vault: { - - } -} \ No newline at end of file + vault: {}, +} diff --git a/src/console/CleanTestDatabases.js b/src/console/CleanTestDatabases.js index 3be7e6e64414441c919867e34f626eba11c79d6d..4477a8a843a59970016fe4300974b797d1cb7a0d 100644 --- a/src/console/CleanTestDatabases.js +++ b/src/console/CleanTestDatabases.js @@ -4,9 +4,11 @@ module.exports = { async handler(args) { const { config } = require('bootstrap') const { sequelize } = require('database/models') - const [databases] = await sequelize.query(`SELECT datname as name FROM pg_database WHERE datistemplate = false;`) + const [databases] = await sequelize.query( + `SELECT datname as name FROM pg_database WHERE datistemplate = false;`, + ) - const prefix = `${ config('database.database') }_` + const prefix = `${config('database.database')}_` const toDelete = [] for (const entry of databases) { @@ -16,16 +18,16 @@ module.exports = { } if (toDelete.length === 0) { - console.log("No databases with the prefix %s", prefix) + console.log('No databases with the prefix %s', prefix) } else { - console.log("Deleting Databases:") + console.log('Deleting Databases:') for (const name of toDelete) { - console.log(` ${ name }`) - await sequelize.query(`DROP DATABASE ${ name };`) + console.log(` ${name}`) + await sequelize.query(`DROP DATABASE ${name};`) } } process.exit(0) - } -} \ No newline at end of file + }, +} diff --git a/src/console/CreateNewDatabase.js b/src/console/CreateNewDatabase.js index d9ee348fc3fd6a98f166dd063a77c1f478bf2028..7f6a913b1e697f2c953f721dd3f3d2e4f96b2bae 100644 --- a/src/console/CreateNewDatabase.js +++ b/src/console/CreateNewDatabase.js @@ -2,47 +2,55 @@ module.exports = { command: 'db:fresh [id]', description: 'Create a fresh database instance with a random name', builder(yargs) { - yargs.positional('id', { - describe: 'A preset ID to use for the database name', - type: 'string', - }).option('and-migrate', { - demandOption: false, - alias: 'migrate', - describe: 'Run migrations against the newly created database', - }) + yargs + .positional('id', { + describe: 'A preset ID to use for the database name', + type: 'string', + }) + .option('and-migrate', { + demandOption: false, + alias: 'migrate', + describe: 'Run migrations against the newly created database', + }) }, async handler(args) { const { v4: uuid } = require('uuid') const { config } = require('bootstrap') const dbid = args.id ?? uuid().replace(/-/g, '') - const newDatabaseName = `${ config('database.database') }_${ dbid }` + const newDatabaseName = `${config('database.database')}_${dbid}` const { sequelize } = require('database/models') - const [databases] = await sequelize.query(`SELECT datname as name FROM pg_database WHERE datistemplate = false;`) + const [databases] = await sequelize.query( + `SELECT datname as name FROM pg_database WHERE datistemplate = false;`, + ) for (const entry of databases) { if (entry.name === newDatabaseName) { - throw new Error(`Database with name ${ newDatabaseName } already exists`) + throw new Error(`Database with name ${newDatabaseName} already exists`) } } console.log('Creating new database with name', newDatabaseName) - await sequelize.query(`CREATE DATABASE ${ newDatabaseName };`) + await sequelize.query(`CREATE DATABASE ${newDatabaseName};`) if (args.migrate) { console.log('Running migrations on database', newDatabaseName) const { exec } = require('core/utils/process') - await exec('npm run sql db:migrate', { - env: { - ...process.env, - DATABASE_NAME: newDatabaseName, + await exec( + 'npm run sql db:migrate', + { + env: { + ...process.env, + DATABASE_NAME: newDatabaseName, + }, + stdio: 'inherit', }, - stdio: 'inherit', - }, true) + true, + ) } process.exit(0) - } -} \ No newline at end of file + }, +} diff --git a/src/console/CreateSystemUser.js b/src/console/CreateSystemUser.js index c1b4982b528bec114fbbefeee470dd8385952572..ac5f406000a59936d263d4fb0e8bc83b75379d4d 100644 --- a/src/console/CreateSystemUser.js +++ b/src/console/CreateSystemUser.js @@ -13,5 +13,5 @@ module.exports = { } process.exit(0) - } -} \ No newline at end of file + }, +} diff --git a/src/core/errors/HttpError.js b/src/core/errors/HttpError.js index b30a5669f8d18bf057ef13c344bef2cd6e14cbe3..bf54766e1a3dea9da5fb4c100379a07a12f2cb16 100644 --- a/src/core/errors/HttpError.js +++ b/src/core/errors/HttpError.js @@ -32,4 +32,4 @@ module.exports = class HttpError extends Error { ctx.body = { errors: { general: [this._message] } } } } -} \ No newline at end of file +} diff --git a/src/core/errors/InputValidationError.js b/src/core/errors/InputValidationError.js index a6234dae6025429a2df5e3e563cb3846b0f648ef..1a97aef27efdefed093e24b1bb7b66e11450238b 100644 --- a/src/core/errors/InputValidationError.js +++ b/src/core/errors/InputValidationError.js @@ -4,4 +4,4 @@ module.exports = class InputValidationError extends HttpError { constructor(fields) { super(422, 'The supplied input was not valid', { fields }) } -} \ No newline at end of file +} diff --git a/src/core/errors/NotFoundError.js b/src/core/errors/NotFoundError.js new file mode 100644 index 0000000000000000000000000000000000000000..ebaf067fa5c5abffc3eaec18eef9b19ae3055c8e --- /dev/null +++ b/src/core/errors/NotFoundError.js @@ -0,0 +1,7 @@ +const HttpError = require('./HttpError') + +module.exports = class NotFoundError extends HttpError { + constructor(resource = 'resource') { + super(404, `Could not find the requested ${ resource }`) + } +} diff --git a/src/core/errors/UnauthorizedError.js b/src/core/errors/UnauthorizedError.js index 34a684efc7f9799b56dcd0eb9cefe3fac12265a7..81323dd2dab9d6d1759ffd581fc94dc2c54d2f4b 100644 --- a/src/core/errors/UnauthorizedError.js +++ b/src/core/errors/UnauthorizedError.js @@ -1,7 +1,7 @@ const HttpError = require('./HttpError') -module.exports = class UnauthorizedError extends HttpError { +module.exports = class UnauthorizedError extends HttpError { constructor() { super(401, 'You must be logged in to access this resource') } -} \ No newline at end of file +} diff --git a/src/core/events/bus.js b/src/core/events/bus.js index cf3958e983301db9dffe5ac339032ecc6bd3e8d5..d41d55dab8f58da01940ce9f9ece17f02609f1ef 100644 --- a/src/core/events/bus.js +++ b/src/core/events/bus.js @@ -1,7 +1,7 @@ const EventEmitter = require('events') const bus = new EventEmitter() -bus.on('error', function(error) { +bus.on('error', function (error) { console.log(error) }) bus.setMaxListeners(250) diff --git a/src/core/injection/ContextualModule.js b/src/core/injection/ContextualModule.js index 8af8b5304d8f71d15983c453d11cc791d66a6efd..0fb0279e24b79f36542d5f43bed0049fcebff43b 100644 --- a/src/core/injection/ContextualModule.js +++ b/src/core/injection/ContextualModule.js @@ -1,8 +1,14 @@ module.exports = class ContextualModule { - static withContext(ctx) { return new this(ctx) } - static withoutContext() { return new this({}) } + static withContext(ctx) { + return new this(ctx) + } + static withoutContext() { + return new this({}) + } - static getServiceName() { throw new Error(`getServiceName Not Implemented for ${ this.name }`) } + static getServiceName() { + throw new Error(`getServiceName Not Implemented for ${this.name}`) + } constructor(context = null) { if (context == null) { diff --git a/src/core/injection/ServiceProvider.js b/src/core/injection/ServiceProvider.js index 5bbee4177b2521452f51566003393b5a95f518ed..f0d72e7f749132847c50c76c638ec72ea24f9fec 100644 --- a/src/core/injection/ServiceProvider.js +++ b/src/core/injection/ServiceProvider.js @@ -32,8 +32,8 @@ function createFakeContext() { res.statusCode = 200 const context = Object.create(baseCtx) - const request = context.request = Object.create(baseReq) - const response = context.response = Object.create(baseRes) + const request = (context.request = Object.create(baseReq)) + const response = (context.response = Object.create(baseRes)) context.app = request.app = response.app = this context.req = request.req = response.req = req @@ -63,7 +63,9 @@ module.exports = class ServiceProvider { services.forEach(service => { const name = service.getServiceName() if (ctx.services.hasOwnProperty(name)) { - console.warn(`Multiple services found for name: ${name}. Using implementation provided by ${service.name}`) + console.warn( + `Multiple services found for name: ${name}. Using implementation provided by ${service.name}`, + ) } ctx.services[name] = createServiceWithProfiling(service, ctx) }) @@ -88,4 +90,4 @@ module.exports = class ServiceProvider { return ServiceProvider.attach(newContext, () => newContext) } -} \ No newline at end of file +} diff --git a/src/core/injection/ThreadContext.js b/src/core/injection/ThreadContext.js index be53ee5c23c268f02bb8caab59a475f5827d5b07..86b3402550f29f97f20d394ce9d1ed6f0d9b898b 100644 --- a/src/core/injection/ThreadContext.js +++ b/src/core/injection/ThreadContext.js @@ -53,7 +53,7 @@ class ThreadContext extends AsyncLocalStorage { if (existing) { return existing } - const Sentry = require("@sentry/node") + const Sentry = require('@sentry/node') const t = Sentry.startTransaction(ctx) this.set('profiling', t) return t diff --git a/src/core/services/dataloaders.js b/src/core/services/dataloaders.js index db2f6971bd8e945056cd78f6c9793e9139616f1c..373e012f22e952b01b0c97911649b35ff593a3f1 100644 --- a/src/core/services/dataloaders.js +++ b/src/core/services/dataloaders.js @@ -1,40 +1,58 @@ const Dataloader = require('dataloader') -const createLoaderForModel = exports.createForModel = function (model, singleProperties = ['id'], multipleProperties = []) { - const loaders = singleProperties.reduce((set, property) => ({ - ...set, - [property]: new Dataloader(keys => Promise.all(keys.map(async key => { - const data = await model.findOne({where: {[property]: key}}) - if (data) { - singleProperties.forEach(prop => { - if (prop !== property && data[prop] != null) { - loaders[prop].prime(data[prop], data) - } - }) - } - return data - }))), - }), {}) +const createLoaderForModel = (exports.createForModel = function ( + model, + singleProperties = ['id'], + multipleProperties = [], +) { + const loaders = singleProperties.reduce( + (set, property) => ({ + ...set, + [property]: new Dataloader(keys => + Promise.all( + keys.map(async key => { + const data = await model.findOne({ where: { [property]: key } }) + if (data) { + singleProperties.forEach(prop => { + if (prop !== property && data[prop] != null) { + loaders[prop].prime(data[prop], data) + } + }) + } + return data + }), + ), + ), + }), + {}, + ) - multipleProperties.reduce((set, property) => ({ - ...set, - [property]: new Dataloader(keys => Promise.all(keys.map(async key => { - const data = await model.find({where: {[property]: key}}) - if (data && data.length) { - singleProperties.forEach(prop => { - data.forEach(datum => { - if (prop !== property && datum[prop] != null) { - loaders[prop].prime(datum[prop], datum) + multipleProperties.reduce( + (set, property) => ({ + ...set, + [property]: new Dataloader(keys => + Promise.all( + keys.map(async key => { + const data = await model.find({ where: { [property]: key } }) + if (data && data.length) { + singleProperties.forEach(prop => { + data.forEach(datum => { + if (prop !== property && datum[prop] != null) { + loaders[prop].prime(datum[prop], datum) + } + }) + }) } - }) - }) - } - return data - }))) - }), loaders) + return data + }), + ), + ), + }), + loaders, + ) return loaders -} +}) exports.generateDataloaders = function () { const { User } = require('database/models') // , Ticket, TicketType, Event, Episode, Venue, Address } = require('database/models') @@ -49,11 +67,15 @@ exports.generateDataloaders = function () { } } -exports.DataloaderService = class extends require('core/injection/ContextualModule') { - static getServiceName() { return 'dataloaderService' } +exports.DataloaderService = class extends ( + require('core/injection/ContextualModule') +) { + static getServiceName() { + return 'dataloaderService' + } constructor(...args) { - super(...args); + super(...args) const dataloader = exports.generateDataloaders() Object.entries(dataloader).forEach(([name, loadermap]) => { @@ -65,5 +87,4 @@ exports.DataloaderService = class extends require('core/injection/ContextualModu }) }) } - } diff --git a/src/core/services/pusher.js b/src/core/services/pusher.js index 5bf6794c885d9266c00c06724aba78e8956ec0c6..c639ec498c0b066047e80890f8856a02916ca6ac 100644 --- a/src/core/services/pusher.js +++ b/src/core/services/pusher.js @@ -1,4 +1,4 @@ -const Pusher = require('pusher'); +const Pusher = require('pusher') const { config } = require('bootstrap') const pusher = new Pusher({ @@ -6,7 +6,7 @@ const pusher = new Pusher({ key: config('pusher.key'), secret: config('pusher.secret'), cluster: config('pusher.region'), - encrypted: true -}); + encrypted: true, +}) module.exports = pusher diff --git a/src/core/services/serialise.js b/src/core/services/serialise.js new file mode 100644 index 0000000000000000000000000000000000000000..3e80e4d68ecf00ab3741db874cb99ba6fbeafb60 --- /dev/null +++ b/src/core/services/serialise.js @@ -0,0 +1,22 @@ +exports.serialise = async function serialise(pattern, data) { + const output = {} + + for (const [key, mapper] of Object.entries(pattern)) { + switch (typeof mapper) { + case 'string': + case 'number': + case 'symbol': + console.log(data[mapper]) + output[key] = data[mapper] + break + case 'function': + output[key] = await mapper(data, output) + break + case 'object': + output[key] = await serialise(mapper, data) + break + } + } + + return output +} diff --git a/src/core/utils/crypto.js b/src/core/utils/crypto.js index a89139038250ebc5276b9a61469f5c46205d7b01..942c26393cc2ca98d47320a8a7c735402420023c 100644 --- a/src/core/utils/crypto.js +++ b/src/core/utils/crypto.js @@ -36,7 +36,24 @@ exports.secureHexString = function generateSecureHexString(bytes) { return exports.secureBuffer(bytes).then(b => b.toString('hex')) } -const hex = ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0', 'a', 'b', 'c', 'd', 'e', 'f'] +const hex = [ + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', +] /** * Generate a hexadecimal string of the given length in a synchronous and insecure manner. @@ -68,9 +85,63 @@ exports.insecureHexString = function generateInsecureHexStringSync(length) { * @type {string[]} */ const friendlyAlphabet = [ - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + 'a', + 'b', + 'c', + 'd', + 'e', + 'f', + 'g', + 'h', + 'j', + 'k', + 'm', + 'n', + 'p', + 'q', + 'r', + 's', + 't', + 'u', + 'v', + 'w', + 'x', + 'y', + 'z', + 'A', + 'B', + 'C', + 'D', + 'E', + 'F', + 'G', + 'H', + 'J', + 'K', + 'L', + 'M', + 'N', + 'P', + 'Q', + 'R', + 'S', + 'T', + 'U', + 'V', + 'W', + 'X', + 'Y', + 'Z', + '1', + '2', + '3', + '4', + '5', + '6', + '7', + '8', + '9', + '0', ] exports.friendlyRefString = function generateFriendlyRefString(length) { const buffer = [] @@ -140,8 +211,7 @@ exports.hash = function hashPayload(payload) { const source = stringifyPayload(payload) const inputBuffer = Buffer.from(source, 'utf-8') const params = getScryptParams() - return scrypt.kdf(inputBuffer, params) - .then(hash => hash.toString('base64')) + return scrypt.kdf(inputBuffer, params).then(hash => hash.toString('base64')) } /** @@ -256,13 +326,21 @@ exports.decryptWith = function decryptWithKey(key, encrypted) { return buffer } -exports.hmac = async function createHmacSignature(payload, secret, algorithm = 'sha256') { +exports.hmac = async function createHmacSignature( + payload, + secret, + algorithm = 'sha256', +) { const hmac = crypto.createHmac(algorithm, secret) hmac.update(payload) return hmac.digest('base64') } -exports.hashFile = function createFileHash(path, algorithm = 'sha384', output = 'base64') { +exports.hashFile = function createFileHash( + path, + algorithm = 'sha384', + output = 'base64', +) { const hash = crypto.createHash(algorithm) const stream = fs.createReadStream(path) @@ -281,4 +359,4 @@ exports.hashFile = function createFileHash(path, algorithm = 'sha384', output = } exports.toBase64 = string => Buffer.from(string).toString('base64') -exports.fromBase64 = string => Buffer.from(string, 'base64').toString() \ No newline at end of file +exports.fromBase64 = string => Buffer.from(string, 'base64').toString() diff --git a/src/core/utils/jwt.js b/src/core/utils/jwt.js index c3038df10968420c48e73579332c3cd5b651afff..13832755faa97c5a3afd81e3284765090f4f6199 100644 --- a/src/core/utils/jwt.js +++ b/src/core/utils/jwt.js @@ -2,25 +2,29 @@ const { generateKeyPair, createPublicKey, createPrivateKey } = require('crypto') async function generateRsaKeys() { const { config } = require('bootstrap') return new Promise((resolve, reject) => { - generateKeyPair('rsa', { - modulusLength: 4096, - publicKeyEncoding: { - type: 'spki', - format: 'pem', + generateKeyPair( + 'rsa', + { + modulusLength: 4096, + publicKeyEncoding: { + type: 'spki', + format: 'pem', + }, + privateKeyEncoding: { + type: 'pkcs8', + format: 'pem', + cipher: 'aes-256-cbc', + passphrase: config('app.key'), + }, }, - privateKeyEncoding: { - type: 'pkcs8', - format: 'pem', - cipher: 'aes-256-cbc', - passphrase: config('app.key'), - } - }, (err, pub, priv) => { - if (err) { - reject(err) - } else { - resolve({ pub: pub.toString(), priv: priv.toString() }) - } - }) + (err, pub, priv) => { + if (err) { + reject(err) + } else { + resolve({ pub: pub.toString(), priv: priv.toString() }) + } + }, + ) }) } @@ -42,7 +46,7 @@ exports.loadKeys = async () => { if (pub != null && priv != null) { return { pub, - priv + priv, } } @@ -56,26 +60,35 @@ exports.loadKeys = async () => { } pub = createPublicKey({ key: pub }) - priv = createPrivateKey({ key: priv, passphrase: config('app.security.private_key_passphrase', env('RSA_PRIVATE_PASSPHRASE', config('app.key'))) }) + priv = createPrivateKey({ + key: priv, + passphrase: config( + 'app.security.private_key_passphrase', + env('RSA_PRIVATE_PASSPHRASE', config('app.key')), + ), + }) patchConfig('app.security.public_key', pub) patchConfig('app.security.private_key', priv) return { pub, priv } } -exports.sign = async (payload) => { +exports.sign = async payload => { const threadContext = require('core/injection/ThreadContext') + const { config } = require('bootstrap') const { default: SignJWT } = require('jose/jwt/sign') const { priv } = exports.getKeys() - return await threadContext.profile('jwt.sign', JSON.stringify(payload), () => new SignJWT(payload) - .setIssuer(exports.jwtOptions.issuer) - .setIssuedAt() - .setProtectedHeader({ alg: 'RS256' }) - .sign(priv)) + return await threadContext.profile('jwt.sign', JSON.stringify(payload), () => + new SignJWT(payload) + .setIssuer(exports.jwtOptions.issuer) + .setIssuedAt() + .setProtectedHeader({ alg: 'RS256', kid: exports.jwtOptions.keyid_prefix + config('app.security.key_id') }) + .sign(priv), + ) } -exports.verify = async(token) => { +exports.verify = async token => { const threadContext = require('core/injection/ThreadContext') const { default: jwtVerify } = require('jose/jwt/verify') const { getKeys, jwtOptions } = exports @@ -87,6 +100,12 @@ exports.verify = async(token) => { }) } +exports.getClaims = tokenPayload => { + return tokenPayload[exports.jwtOptions.claims] +} + exports.jwtOptions = { issuer: 'urn:jetsam:systems:auth', -} \ No newline at end of file + claims: 'urn:jetsam:resources:claims', + keyid_prefix: 'urn:jetsam:jwk:' +} diff --git a/src/core/utils/process.js b/src/core/utils/process.js index d92c4cd43113eb4d16149c93ab8b6d11b6c140ff..6927d1b106ff49588809ce1a28cb0539608e1d1c 100644 --- a/src/core/utils/process.js +++ b/src/core/utils/process.js @@ -1,4 +1,4 @@ -exports.exec = async function(cmd, opts, linkStdio) { +exports.exec = async function (cmd, opts, linkStdio) { const proc = require('child_process') let resolve, reject @@ -18,4 +18,4 @@ exports.exec = async function(cmd, opts, linkStdio) { child.once('exit', resolve) return await defer -} \ No newline at end of file +} diff --git a/src/core/utils/queue.js b/src/core/utils/queue.js index 31b162342f2487ad347ce5144eeee32e9f415d8a..c96201aaf208f97175decc160526c05021db73e5 100644 --- a/src/core/utils/queue.js +++ b/src/core/utils/queue.js @@ -1,8 +1,11 @@ const HANDLERS = [ - ['send-user-password-reset', require('domain/auth/handlers/SendUserPasswordReset')] + [ + 'send-user-password-reset', + require('domain/auth/handlers/SendUserPasswordReset'), + ], ] module.exports = function bindJobHandlers() { const { queue } = require('services') HANDLERS.forEach(([job, handler]) => queue.bind(job, handler)) -} \ No newline at end of file +} diff --git a/src/core/utils/sym.js b/src/core/utils/sym.js new file mode 100644 index 0000000000000000000000000000000000000000..11b42a17df63fdc3cb0bc777b3128625f8206c84 --- /dev/null +++ b/src/core/utils/sym.js @@ -0,0 +1,10 @@ +const SYM = new Proxy( + {}, + { + get(target, p, receiver) { + return p + }, + }, +) + +module.exports = SYM diff --git a/src/core/utils/urls.js b/src/core/utils/urls.js index 8fe489a36de97fc5c8e4a9a009d8a7fd32b6fdc4..2f04912890771a49b43ce85b2bf5d97f0eb04604 100644 --- a/src/core/utils/urls.js +++ b/src/core/utils/urls.js @@ -1,6 +1,8 @@ const { URL } = require('url') const qs = require('querystring') const { unset, config } = require('bootstrap') +const crypto = require('core/utils/crypto') +const {report} = require("../../http/middleware/SentryReporter"); exports.createUrl = (host, path, query = unset) => { const url = new URL(path, host) @@ -10,6 +12,67 @@ exports.createUrl = (host, path, query = unset) => { return url.toString() } -exports.appUrl = (path, query = unset) => exports.createUrl(config('app.host.web'), path, query) +exports.appUrl = (path, query = unset) => + exports.createUrl(config('app.host.web'), path, query) -exports.queryValueToArray = (value = '') => (value || '').split(',').map(s => s.trim()).filter(Boolean) +exports.queryValueToArray = (value = '') => + (value || '') + .split(',') + .map(s => s.trim()) + .filter(Boolean) + +const redirectPairs = [ + ['authorize', '/auth/authorize'] +] + +const nameToUrl = redirectPairs.reduce((cur, [k, v]) => ({ ...cur, [k]: v }), {}) +const urlToName = redirectPairs.reduce((cur, [k, v]) => ({ ...cur, [v]: k }), {}) + +exports.createRedirectState = async ctx => { + const path = ctx.path + const redirect = urlToName[path] ?? '/' + const query = ctx.request.query ?? {} + return crypto.encrypt(JSON.stringify({ redirect, query })) +} + +exports.parseRedirectState = async ctx => { + const state = ctx.request?.query?.login_state + if (!state) { + return { + path: '/', + redirect: 'missing', + query: {} + } + } + + try { + const raw = await crypto.decrypt(state) + const value = JSON.parse(raw) + return { + ...value, + path: nameToUrl[value.redirect] ?? '/', + } + } catch(e) { + console.error(e) + await report(e, ctx) + } + + return { + path: '/', + redirect: 'missing', + query: {} + } +} + +exports.createRedirectedUrl = async (ctx) => { + const values = await exports.parseRedirectState(ctx) + const params = new URLSearchParams() + + console.log(values, params) + + Object.entries(values.query).forEach(([key, value]) => { + params.set(key, value) + }) + + return `${ values.path }?${ params.toString() }` +} \ No newline at end of file diff --git a/src/core/utils/validation.js b/src/core/utils/validation.js index a4bd295a75e9379c44530714dc6e76182a504807..3ba8c211a5770422d947d3ac3c9beebb853ef6e2 100644 --- a/src/core/utils/validation.js +++ b/src/core/utils/validation.js @@ -1,66 +1,57 @@ const Joi = require('joi') exports['survey'] = Joi.object({ - questions: Joi.array().items(Joi.object({ - question: Joi.string().min(1).required(), - type: Joi.any().valid( - 'text', - 'number', - 'checkbox', - 'choice', - 'range', - ).id('survey-type'), - required: Joi.boolean().required(), - constraints: Joi.alternatives().conditional(Joi.ref('#survey-type'), { - switch: [ - { - is: 'text', - then: Joi.object({ - email: Joi.boolean(), - }), - }, - { - is: 'number', - then: Joi.object({ - min: Joi.number(), - max: Joi.number(), - }), - }, - { - is: 'checkbox', - then: Joi.object({ - checkRequired: Joi.boolean(), - }), - }, - { - is: 'choice', - then: Joi.object({ - options: Joi.array().items(Joi.string()) - }), - }, - { - is: 'range', - then: Joi.object({ - - }), - }, - { - is: Joi.invalid('text', 'number', 'checkbox', 'choice', 'range'), - then: Joi.forbidden(), - }, - ], + questions: Joi.array().items( + Joi.object({ + question: Joi.string().min(1).required(), + type: Joi.any() + .valid('text', 'number', 'checkbox', 'choice', 'range') + .id('survey-type'), + required: Joi.boolean().required(), + constraints: Joi.alternatives().conditional(Joi.ref('#survey-type'), { + switch: [ + { + is: 'text', + then: Joi.object({ + email: Joi.boolean(), + }), + }, + { + is: 'number', + then: Joi.object({ + min: Joi.number(), + max: Joi.number(), + }), + }, + { + is: 'checkbox', + then: Joi.object({ + checkRequired: Joi.boolean(), + }), + }, + { + is: 'choice', + then: Joi.object({ + options: Joi.array().items(Joi.string()), + }), + }, + { + is: 'range', + then: Joi.object({}), + }, + { + is: Joi.invalid('text', 'number', 'checkbox', 'choice', 'range'), + then: Joi.forbidden(), + }, + ], + }), }), - })), + ), }) exports['events.ticket_types.new'] = Joi.object({ - name: Joi.string() - .min(1) - .required(), + name: Joi.string().min(1).required(), description: Joi.string(), - quantity: Joi.number() - .integer() - .required() - .min(1), + quantity: Joi.number().integer().required().min(1), survey: exports['survey'], }) diff --git a/src/database/models/AccessToken.js b/src/database/models/AccessToken.js index 16d060d2e89dc972683d1ff3cca6c20a551a7ed6..dcf414f9a92713669d2d67b2c1e0ececcecc8312 100644 --- a/src/database/models/AccessToken.js +++ b/src/database/models/AccessToken.js @@ -3,8 +3,8 @@ const BaseModel = require('./BaseModel') class AccessToken extends BaseModel { static associate(models) { - this.belongsTo(models.User, {foreignKey: 'user_id'}) - this.belongsTo(models.OAuthClient, {foreignKey: 'client_id'}) + this.belongsTo(models.User, { foreignKey: 'user_id' }) + this.belongsTo(models.OAuthClient, { foreignKey: 'client_id' }) } get scopes() { @@ -27,13 +27,13 @@ class AccessToken extends BaseModel { accessToken: this.token, accessTokenExpiresAt: this.expires_at, scope: this.scope, - client: client.toOAuthInterface(), + client: client.toOAuthInterface(), user, } } toJSON() { - const user = this.user ? {user: this.user} : {} + const user = this.user ? { user: this.user } : {} return { id: this.id, token: this.token, @@ -48,34 +48,38 @@ class AccessToken extends BaseModel { } module.exports = (sequelize, DataTypes) => { - AccessToken.init(Object.assign({ - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - validate: { - isUUID: 4, + AccessToken.init( + Object.assign( + { + id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, + validate: { + isUUID: 4, + }, + }, + token: { + type: DataTypes.TEXT, + }, + scope: { + type: DataTypes.TEXT, + }, + expires_at: { + type: DataTypes.DATE, + }, + meta: { + type: DataTypes.JSONB, }, }, - token: { - type: DataTypes.TEXT, - }, - scope: { - type: DataTypes.TEXT, - }, - expires_at: { - type: DataTypes.DATE, - }, - meta: { - type: DataTypes.JSONB, - }, + timestamps(DataTypes), + ), + { + sequelize, + paranoid: true, + tableName: 'oauth_access_tokens', }, - timestamps(DataTypes), - ), { - sequelize, - paranoid: true, - tableName: 'oauth_access_tokens', - }) + ) return AccessToken } diff --git a/src/database/models/AuthorizationCode.js b/src/database/models/AuthorizationCode.js index e6b03a4d2e64aa9decba4cb567c1e6ee39057d0a..abccacd695499a28270d6b6521df00cb587d2e11 100644 --- a/src/database/models/AuthorizationCode.js +++ b/src/database/models/AuthorizationCode.js @@ -13,12 +13,16 @@ class AuthorizationCode extends BaseModel { expiresAt: this.expires_at, redirectUri: this.redirect_uri, scope: this.scope, - client: this.client ? this.client : { - id: this.client_id, - }, - user: this.user ? this.user : { - id: this.user_id, - } + client: this.client + ? this.client + : { + id: this.client_id, + }, + user: this.user + ? this.user + : { + id: this.user_id, + }, } } @@ -35,8 +39,8 @@ class AuthorizationCode extends BaseModel { } toJSON() { - const user = this.user ? { user: this.user } : { } - const client = this.user ? { user: this.user } : { } + const user = this.user ? { user: this.user } : {} + const client = this.user ? { user: this.user } : {} return { id: this.id, scopes: this.scopes, @@ -50,31 +54,34 @@ class AuthorizationCode extends BaseModel { } module.exports = (sequelize, DataTypes) => { - AuthorizationCode.init(Object.assign( - { - auth_code: { - type: DataTypes.TEXT, - primaryKey: true, - }, - scope: { - type: DataTypes.TEXT, + AuthorizationCode.init( + Object.assign( + { + auth_code: { + type: DataTypes.TEXT, + primaryKey: true, + }, + scope: { + type: DataTypes.TEXT, + }, + redirect_uri: { + type: DataTypes.TEXT, + }, + expires_at: { + type: DataTypes.DATE, + }, + meta: { + type: DataTypes.JSONB, + }, }, - redirect_uri: { - type: DataTypes.TEXT, - }, - expires_at: { - type: DataTypes.DATE, - }, - meta: { - type: DataTypes.JSONB, - } + timestamps(DataTypes), + ), + { + sequelize, + paranoid: true, + tableName: 'oauth_authorization_codes', }, - timestamps(DataTypes), - ), { - sequelize, - paranoid: true, - tableName: 'oauth_authorization_codes', - }) + ) return AuthorizationCode } diff --git a/src/database/models/BaseModel.js b/src/database/models/BaseModel.js index a1109b4d27224d525e86349affc4f92400bfcc17..6d3840ab90a84988fdb0d3f26a6c1d1759681aa8 100644 --- a/src/database/models/BaseModel.js +++ b/src/database/models/BaseModel.js @@ -14,13 +14,9 @@ module.exports = class BaseModel extends Model { return this.name } - static associate(models) { + static associate(models) {} - } - - async handleIncludes(includes, loaders) { - - } + async handleIncludes(includes, loaders) {} toJSON() { return { @@ -30,4 +26,4 @@ module.exports = class BaseModel extends Model { updated_at: this.updated_at, } } -} \ No newline at end of file +} diff --git a/src/database/models/BundleCode.js b/src/database/models/BundleCode.js index ef315d24363c1c667e2dbacf5dd47be665b9b427..ed9ad0716cf4c1052e7d48a0bfd1525b7c970f46 100644 --- a/src/database/models/BundleCode.js +++ b/src/database/models/BundleCode.js @@ -7,7 +7,7 @@ class BundleCode extends BaseModel { through: 'user_bundle_codes', foreignKey: 'bundle_code_id', otherKey: 'user_id', - timestamps: false + timestamps: false, }) } toJSON() { @@ -24,35 +24,38 @@ class BundleCode extends BaseModel { } module.exports = (sequelize, DataTypes) => { - BundleCode.init(Object.assign( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - validate: { - isUUID: 4, + BundleCode.init( + Object.assign( + { + id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, + validate: { + isUUID: 4, + }, + }, + name: { + type: DataTypes.TEXT, + }, + description: { + type: DataTypes.TEXT, + }, + platforms: { + type: DataTypes.JSONB, + }, + meta: { + type: DataTypes.JSONB, }, }, - name: { - type: DataTypes.TEXT, - }, - description: { - type: DataTypes.TEXT, - }, - platforms: { - type: DataTypes.JSONB, - }, - meta: { - type: DataTypes.JSONB, - }, + timestamps(DataTypes), + ), + { + sequelize, + paranoid: true, + tableName: 'bundle_codes', }, - timestamps(DataTypes), - ), { - sequelize, - paranoid: true, - tableName: 'bundle_codes', - }) + ) return BundleCode -} \ No newline at end of file +} diff --git a/src/database/models/File.js b/src/database/models/File.js index 8ef0be128fe8e1181b1a11a06ef985aafe9201bf..02fc4babf4c2891611ae3394289d50f370a78a79 100644 --- a/src/database/models/File.js +++ b/src/database/models/File.js @@ -25,64 +25,72 @@ class File extends BaseModel { } function generatePublicUri(provider, file) { - return ['https://storage.googleapis.com', file.meta.bucket, file.file_root, file.file_name].join('/') + return [ + 'https://storage.googleapis.com', + file.meta.bucket, + file.file_root, + file.file_name, + ].join('/') } module.exports = (sequelize, DataTypes) => { - File.init(Object.assign( - { - id: { - type: DataTypes.UUID, - defaultValue: DataTypes.UUIDV4, - primaryKey: true, - }, - provider: { - type: DataTypes.TEXT, - }, - file_root: { - type: DataTypes.TEXT, - }, - file_name: { - type: DataTypes.TEXT, - }, - comment: { - type: DataTypes.TEXT, - }, - tags: { - type: DataTypes.ARRAY(DataTypes.TEXT), - }, - labels: { - type: DataTypes.ARRAY(DataTypes.TEXT), - }, - public_uri: { - type: DataTypes.VIRTUAL, - get() { - const provider = this.provider - return generatePublicUri(provider, this) - } - }, - stream: { - type: DataTypes.TEXT, - }, - requires_approval: { - type: DataTypes.BOOLEAN, - }, - approved: { - type: DataTypes.BOOLEAN, - }, - featured: { - type: DataTypes.BOOLEAN, - }, - meta: { - type: DataTypes.JSONB, + File.init( + Object.assign( + { + id: { + type: DataTypes.UUID, + defaultValue: DataTypes.UUIDV4, + primaryKey: true, + }, + provider: { + type: DataTypes.TEXT, + }, + file_root: { + type: DataTypes.TEXT, + }, + file_name: { + type: DataTypes.TEXT, + }, + comment: { + type: DataTypes.TEXT, + }, + tags: { + type: DataTypes.ARRAY(DataTypes.TEXT), + }, + labels: { + type: DataTypes.ARRAY(DataTypes.TEXT), + }, + public_uri: { + type: DataTypes.VIRTUAL, + get() { + const provider = this.provider + return generatePublicUri(provider, this) + }, + }, + stream: { + type: DataTypes.TEXT, + }, + requires_approval: { + type: DataTypes.BOOLEAN, + }, + approved: { + type: DataTypes.BOOLEAN, + }, + featured: { + type: DataTypes.BOOLEAN, + }, + meta: { + type: DataTypes.JSONB, + }, }, + timestamps(DataTypes), + ), + { + sequelize, + paranoid: true, + tableName: 'files', }, - timestamps(DataTypes), - ), { - sequelize, - paranoid: true, - tableName: 'files', - }) + ) return File } diff --git a/src/database/models/Metric.js b/src/database/models/Metric.js index e975ef2d3ebcd7617edda2f896280318576d924c..a47f28aa6601a9306d12911bff2c0b131d5a1754 100644 --- a/src/database/models/Metric.js +++ b/src/database/models/Metric.js @@ -16,11 +16,14 @@ class Metric extends BaseModel { } static async findUnassociatedForDevice(deviceId) { - return this.findAll({ where: { author_id: null, meta: { device: { id: deviceId } } } }) + return this.findAll({ + where: { author_id: null, meta: { device: { id: deviceId } } }, + }) } static async claimNewUnassociatedForDEvice(authorId, deviceId) { - return this.sequelize.query(` + return this.sequelize.query( + ` update metrics set author_id = :authorId where meta -> 'device' ->> 'id' = :deviceId::text @@ -28,10 +31,12 @@ class Metric extends BaseModel { and not exists ( select * from metrics where meta -> 'device' ->> 'id' = :deviceId::text and author_id is not null limit 1 ); - `, { - replacements: { authorId, deviceId }, - type: sequelize.QueryTypes.UPDATE, - }) + `, + { + replacements: { authorId, deviceId }, + type: sequelize.QueryTypes.UPDATE, + }, + ) } getNativeValue() { @@ -57,8 +62,8 @@ class Metric extends BaseModel { } module.exports = (sequelize, DataTypes) => { - Metric.init(Object.assign( - { + Metric.init( + Object.assign({ fake_pk: { type: DataTypes.VIRTUAL, primaryKey: true, @@ -86,9 +91,15 @@ module.exports = (sequelize, DataTypes) => { }, set(location) { if (Array.isArray(location)) { - this.setDataValue('location', { type: 'Point', coordinates: location }) + this.setDataValue('location', { + type: 'Point', + coordinates: location, + }) } else if (location.latitude && location.longitude) { - this.setDataValue('location', { type: 'Point', coordinated: [location.longitude, location.latitude] }) + this.setDataValue('location', { + type: 'Point', + coordinated: [location.longitude, location.latitude], + }) } else { this.setDataValue('location', location) } @@ -103,13 +114,14 @@ module.exports = (sequelize, DataTypes) => { deleted_at: { type: DataTypes.DATE, }, + }), + { + sequelize, + paranoid: true, + timestamps: false, + tableName: 'metrics', }, - ), { - sequelize, - paranoid: true, - timestamps: false, - tableName: 'metrics', - }) + ) return Metric } diff --git a/src/database/models/OAuthClient.js b/src/database/models/OAuthClient.js index 9f35ae27cedf99c15342c33a56ae2a1a7086d742..5eaa4d320f7645e1ea3bad60fdb51bf134613ce0 100644 --- a/src/database/models/OAuthClient.js +++ b/src/database/models/OAuthClient.js @@ -4,16 +4,23 @@ const BaseModel = require('./BaseModel') class OAuthClient extends BaseModel { static associate(models) { this.belongsTo(models.User, { as: 'owner', foreignKey: 'owner_id' }) - this.belongsToMany(models.User, { as: 'users', through: models.AccessToken, otherKey: 'user_id', foreignKey: 'client_id' }) + this.belongsToMany(models.User, { + as: 'users', + through: models.AccessToken, + otherKey: 'user_id', + foreignKey: 'client_id', + }) this.hasMany(models.AccessToken, { foreignKey: 'client_id' }) this.hasMany(models.RefreshToken, { foreignKey: 'client_id' }) } - static async generateClient(userId, internal = false) { + static async generateClient(userId, params = {}, internal = false) { const crypto = require('core/utils/crypto') const secret = await crypto.secureHexString(32) return this.create({ owner_id: userId, + name: params.name ?? '', + description: params.description ?? '', secret, grant_types: ['authorization_code', 'refresh_token'], internal, @@ -32,6 +39,8 @@ class OAuthClient extends BaseModel { toJSON() { return { id: this.id, + name: this.name, + description: this.description, secret: this.secret, redirect_uris: this.redirect_uris, grant_types: this.grant_types, @@ -43,35 +52,44 @@ class OAuthClient extends BaseModel { } module.exports = (sequelize, DataTypes) => { - OAuthClient.init(Object.assign( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - validate: { - isUUID: 4, + OAuthClient.init( + Object.assign( + { + id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, + validate: { + isUUID: 4, + }, + }, + name: { + type: DataTypes.TEXT, + }, + description: { + type: DataTypes.TEXT, + }, + secret: { + type: DataTypes.TEXT, + }, + redirect_uris: { + type: DataTypes.ARRAY(DataTypes.TEXT), + }, + grant_types: { + type: DataTypes.ARRAY(DataTypes.TEXT), + }, + meta: { + type: DataTypes.JSONB, }, }, - secret: { - type: DataTypes.TEXT, - }, - redirect_uris: { - type: DataTypes.ARRAY(DataTypes.TEXT), - }, - grant_types: { - type: DataTypes.ARRAY(DataTypes.TEXT), - }, - meta: { - type: DataTypes.JSONB, - } + timestamps(DataTypes), + ), + { + sequelize, + paranoid: true, + tableName: 'oauth_clients', }, - timestamps(DataTypes), - ), { - sequelize, - paranoid: true, - tableName: 'oauth_clients', - }) + ) return OAuthClient } diff --git a/src/database/models/RefreshToken.js b/src/database/models/RefreshToken.js index 214edc4471682109bfbc73f4d93531b9fc1429fa..ba315d69f3cf4218c9ab7f72c4aead97baf9c052 100644 --- a/src/database/models/RefreshToken.js +++ b/src/database/models/RefreshToken.js @@ -27,13 +27,13 @@ class RefreshToken extends BaseModel { refreshToken: this.token, refreshTokenExpiresAt: this.expires_at, scope: this.scope, - client: client.toOAuthInterface(), + client: client.toOAuthInterface(), user, } } toJSON() { - const user = this.user ? { user: this.user } : { } + const user = this.user ? { user: this.user } : {} return { id: this.id, token: this.token, @@ -48,35 +48,38 @@ class RefreshToken extends BaseModel { } module.exports = (sequelize, DataTypes) => { - RefreshToken.init(Object.assign( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - validate: { - isUUID: 4, + RefreshToken.init( + Object.assign( + { + id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, + validate: { + isUUID: 4, + }, + }, + token: { + type: DataTypes.TEXT, + }, + scope: { + type: DataTypes.TEXT, + }, + expires_at: { + type: DataTypes.DATE, + }, + meta: { + type: DataTypes.JSONB, }, }, - token: { - type: DataTypes.TEXT, - }, - scope: { - type: DataTypes.TEXT, - }, - expires_at: { - type: DataTypes.DATE, - }, - meta: { - type: DataTypes.JSONB, - } + timestamps(DataTypes), + ), + { + sequelize, + paranoid: true, + tableName: 'oauth_refresh_tokens', }, - timestamps(DataTypes), - ), { - sequelize, - paranoid: true, - tableName: 'oauth_refresh_tokens', - }) + ) return RefreshToken } diff --git a/src/database/models/Survey.js b/src/database/models/Survey.js new file mode 100644 index 0000000000000000000000000000000000000000..dbe253de1053f673195a60087c8d68261d072254 --- /dev/null +++ b/src/database/models/Survey.js @@ -0,0 +1,116 @@ +const timestamps = require('./properties/timestamps') +const BaseModel = require('./BaseModel') + +class Survey extends BaseModel { + static associate(models) { + this.hasMany(models.SurveyUser, { foreignKey: 'survey_id' }) + this.belongsToMany(models.User, { through: models.SurveyUser, timestamps: false }) + } + + toJSON() { + return { + id: this.id, + slug: this.slug, + name: this.name, + header_image_url: this.header_image_url, + partner_names: this.partner_names, + description: this.description, + requirements: this.requirements, + settings: this.settings, + properties: this.properties, + public: this.public, + published_at: this.published_at, + expires_at: this.expires_at, + meta: this.meta, + } + } + + asOwnSurvey() { + const value = this.toJSON() + if (this.SurveyUser) { + value.answers = this.SurveyUser.toJSON().properties + } else if (this.SurveyUsers?.length === 1) { + value.answers = this.SurveyUsers[0].toJSON().properties + } + return value + } +} + +module.exports = (sequelize, DataTypes) => { + Survey.init( + Object.assign( + { + id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, + validate: { + isUUID: 4, + }, + }, + slug: { + type: DataTypes.TEXT, + allowNull: true, + }, + name: { + type: DataTypes.TEXT, + allowNull: false, + }, + header_image_url: { + type: DataTypes.TEXT, + allowNull: false, + }, + partner_names: { + type: DataTypes.ARRAY(DataTypes.TEXT), + allowNull: false, + }, + description: { + type: DataTypes.JSONB, + allowNull: false, + default: [] + }, + requirements: { + type: DataTypes.JSONB, + allowNull: false, + default: [] + }, + settings: { + type: DataTypes.JSONB, + allowNull: false, + default: [] + }, + properties: { + type: DataTypes.JSONB, + allowNull: false, + default: {} + }, + public: { + type: DataTypes.BOOLEAN, + allowNull: false, + }, + published_at: { + type: DataTypes.DATE, + allowNull: true, + default: null, + }, + expires_at: { + type: DataTypes.DATE, + allowNull: false, + }, + meta: { + type: DataTypes.JSONB, + defaultValue: {}, + allowNull: false, + }, + }, + timestamps(DataTypes), + ), + { + sequelize, + paranoid: true, + tableName: 'surveys', + }, + ) + + return Survey +} diff --git a/src/database/models/SurveyUser.js b/src/database/models/SurveyUser.js new file mode 100644 index 0000000000000000000000000000000000000000..cccb463dc8819a797b39174d71f452fad31e3d1e --- /dev/null +++ b/src/database/models/SurveyUser.js @@ -0,0 +1,50 @@ +const timestamps = require('./properties/timestamps') +const BaseModel = require('./BaseModel') + +class SurveyUser extends BaseModel { + static associate(models) { + this.belongsTo(models.User, {foreignKey: 'user_id'}) + this.belongsTo(models.Survey, {foreignKey: 'survey_id'}) + } + + toJSON() { + return { + properties: this.properties, + created_at: this.created_at, + } + } +} + +module.exports = (sequelize, DataTypes) => { + SurveyUser.init( + Object.assign( + { + user_id: { + type: DataTypes.UUID, + }, + survey_id: { + type: DataTypes.UUID, + }, + properties: { + type: DataTypes.JSONB, + defaultValue: {}, + allowNull: false, + }, + created_at: { + type: DataTypes.DATE, + validate: { + isDate: true, + }, + }, + }, + ), + { + sequelize, + paranoid: false, + timestamps: false, + tableName: 'survey_users', + }, + ) + + return SurveyUser +} diff --git a/src/database/models/Upload.js b/src/database/models/Upload.js new file mode 100644 index 0000000000000000000000000000000000000000..99aa08e7e3ecb14c20da935ed480e150201e5316 --- /dev/null +++ b/src/database/models/Upload.js @@ -0,0 +1,78 @@ +const timestamps = require('./properties/timestamps') +const BaseModel = require('./BaseModel') + +class Upload extends BaseModel { + static associate(models) { + this.belongsTo(models.User, { foreignKey: 'user_id' }) + } + + toJSON() { + return { + id: this.id, + provider: this.provider, + upload_url: this.upload_url, + request_params: this.request_params, + expires_at: this.expires_at, + status: this.status, + status_reason: this.status_reason, + meta: this.meta, + created_at: this.created_at, + updated_at: this.updated_at, + } + } +} + +function generatePublicUri(provider, file) { + return [ + 'https://storage.googleapis.com', + file.meta.bucket, + file.file_root, + file.file_name, + ].join('/') +} + +module.exports = (sequelize, DataTypes) => { + Upload.init( + Object.assign( + { + id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, + validate: { + isUUID: 4, + }, + }, + provider: { + type: DataTypes.TEXT, + }, + upload_url: { + type: DataTypes.TEXT, + }, + request_params: { + type: DataTypes.JSONB, + }, + expires_at: { + type: DataTypes.DATE, + }, + status: { + type: DataTypes.TEXT, + }, + status_reason: { + type: DataTypes.TEXT, + }, + meta: { + type: DataTypes.JSONB, + }, + }, + timestamps(DataTypes), + ), + { + sequelize, + paranoid: true, + tableName: 'uploads', + }, + ) + + return Upload +} diff --git a/src/database/models/User.js b/src/database/models/User.js index ea4037e5a23b380a32d6e93d23371bcc6481ce05..25566ecf94b4e36a9dd14f99eb1a25503c5e2feb 100644 --- a/src/database/models/User.js +++ b/src/database/models/User.js @@ -1,5 +1,6 @@ const timestamps = require('./properties/timestamps') const BaseModel = require('./BaseModel') +const {jwtOptions, getClaims} = require("../../core/utils/jwt"); class User extends BaseModel { static associate(models) { @@ -8,18 +9,21 @@ class User extends BaseModel { this.hasMany(models.AccessToken, { foreignKey: 'user_id' }) this.hasMany(models.RefreshToken, { foreignKey: 'user_id' }) this.hasMany(models.File, { foreignKey: 'user_id' }) + this.hasMany(models.Upload, { foreignKey: 'user_id' }) + this.hasMany(models.SurveyUser, { as: 'SurveyMembership', foreignKey: 'user_id' }) this.belongsToMany(models.File, { as: 'likes', through: 'user_file_likes', foreignKey: 'user_id', - otherKey: 'file_id' + otherKey: 'file_id', }) this.belongsToMany(models.BundleCode, { through: 'user_bundle_codes', foreignKey: 'user_id', otherKey: 'bundle_code_id', - timestamps: false + timestamps: false, }) + this.belongsToMany(models.Survey, { through: models.SurveyUser, timestamps: false }) } static async fromToken(token, type) { @@ -38,11 +42,11 @@ class User extends BaseModel { } else { try { id = await this.idFromOpaque(token) - } catch(e) {} + } catch (e) {} if (id == null) { try { id = await this.idFromJwt(token) - } catch(e) {} + } catch (e) {} } } @@ -56,7 +60,12 @@ class User extends BaseModel { static async idFromJwt(token) { const { verify } = require('core/utils/jwt') const payload = await verify(token) - return payload.session.id + + if (payload.session) { + return payload.session.id + } else { + return getClaims(payload)?.['user-id'] + } } static async idFromOpaque(token) { @@ -113,9 +122,10 @@ class User extends BaseModel { const { sign } = require('core/utils/jwt') const roles = await this.getAuthRoles() return await sign({ - session: { - id: this.id, - roles, + [jwtOptions.claims]: { + 'user-id': this.id, + 'default-role': roles[0], + 'allowed-roles': roles, }, ...extras, }) @@ -139,15 +149,12 @@ class User extends BaseModel { return b } - async generateResetToken() { const crypto = require('core/utils/crypto') const moment = require('moment') const id = this.id - const expires = moment.utc() - .add(1, 'hour') - .toISOString() + const expires = moment.utc().add(1, 'hour').toISOString() const token = await crypto.encrypt(JSON.stringify({ id, expires })) this.reset_token = token @@ -156,7 +163,6 @@ class User extends BaseModel { return token } - toJSON() { const meta = { ...this.meta } delete meta.dob @@ -170,38 +176,63 @@ class User extends BaseModel { updated_at: this.updated_at, } } + + serialise() { + const { serialise } = require('core/services/serialise') + const SYM = require('core/utils/sym') + + const { id, name, email, created_at, updated_at } = SYM + + return serialise( + { + id, + name, + email, + meta: user => ({ + ...user.meta, + dob: undefined, + }), + created_at, + updated_at, + }, + this, + ) + } } module.exports = (sequelize, DataTypes) => { - User.init(Object.assign( - { - id: { - type: DataTypes.UUID, - primaryKey: true, - defaultValue: DataTypes.UUIDV4, - }, - name: { - type: DataTypes.TEXT, - }, - email: { - type: DataTypes.TEXT, - }, - password: { - type: DataTypes.TEXT, + User.init( + Object.assign( + { + id: { + type: DataTypes.UUID, + primaryKey: true, + defaultValue: DataTypes.UUIDV4, + }, + name: { + type: DataTypes.TEXT, + }, + email: { + type: DataTypes.TEXT, + }, + password: { + type: DataTypes.TEXT, + }, + reset_token: { + type: DataTypes.TEXT, + }, + meta: { + type: DataTypes.JSONB, + }, }, - reset_token: { - type: DataTypes.TEXT, - }, - meta: { - type: DataTypes.JSONB, - } + timestamps(DataTypes), + ), + { + sequelize, + paranoid: true, + tableName: 'users', }, - timestamps(DataTypes), - ), { - sequelize, - paranoid: true, - tableName: 'users', - }) + ) return User } diff --git a/src/database/models/index.js b/src/database/models/index.js index 3e66754f6c3f2c3da18d47c7b6d253b8fe6cdf29..470e9db10a5454f48acd146d99d47557d7e596f2 100644 --- a/src/database/models/index.js +++ b/src/database/models/index.js @@ -18,11 +18,17 @@ const sequelize = new Sequelize( config('database.database'), config('database.username'), config('database.password'), - conf + conf, ) fs.list(__dirname) - .filter(file => (file[0] !== '.') && file !== 'BaseModel.js' && (file !== basename) && (file.slice(-3) === '.js')) + .filter( + file => + file[0] !== '.' && + file !== 'BaseModel.js' && + file !== basename && + file.slice(-3) === '.js', + ) .forEach(file => { const initialiser = require(path.join(__dirname, file)) const model = initialiser(sequelize, DataTypes) @@ -49,14 +55,14 @@ if (config('database.log_queries')) { const span = trace.startChild({ op: 'sql.query', }) - threadContext.set(`span_${ traceId }`, span) + threadContext.set(`span_${traceId}`, span) query.options.trace = traceId } }) sequelize.addHook('afterQuery', (model, query) => { if (query.options.trace) { - const trace = threadContext.get(`span_${ query.options.trace }`) + const trace = threadContext.get(`span_${query.options.trace}`) if (trace) { trace.description = query.sql trace.setData('sql.params', query.options.bind) diff --git a/src/domain/auth/AuthServer.js b/src/domain/auth/AuthServer.js index 39573c83a0de51d69775d2c2c82222e3e1df4086..fed5552c8c8dc0c999c15dc921c5e43b3807fbd5 100644 --- a/src/domain/auth/AuthServer.js +++ b/src/domain/auth/AuthServer.js @@ -1,5 +1,12 @@ const OAuthServer = require('oauth2-server') -const { Sequelize: { Op }, User, OAuthClient, AccessToken, RefreshToken, AuthorizationCode } = require('database/models') +const { + Sequelize: { Op }, + User, + OAuthClient, + AccessToken, + RefreshToken, + AuthorizationCode, +} = require('database/models') const crypto = require('core/utils/crypto') const HttpError = require('core/errors/HttpError') @@ -17,7 +24,7 @@ function createTokenPair(user, client, access, refresh = {}) { async function createClientEncryptedToken(client, userModel, scope) { const user = await User.findByPk(userModel.id) - const payload = user.asJWTToken({ cid: client.id, scope }) + const payload = user.asJWTToken({ sub: user.id, aud: [client.id], azp: client.id, scope }) return payload } @@ -35,22 +42,31 @@ const model = { } const client = await OAuthClient.findOne({ where }) - const asInterface = client.toOAuthInterface() + const asInterface = client.toOAuthInterface() return asInterface }, getAccessToken(token) { - return AccessToken.findOne({ include: [ { model: User }, { model: OAuthClient } ], where: { token: { [Op.eq]: token } } }) + return AccessToken.findOne({ + include: [{ model: User }, { model: OAuthClient }], + where: { token: { [Op.eq]: token } }, + }) }, async getRefreshToken(token) { - const t = await RefreshToken.findOne({ include: [ { model: User }, { model: OAuthClient } ], where: { token: { [Op.eq]: token } } }) + const t = await RefreshToken.findOne({ + include: [{ model: User }, { model: OAuthClient }], + where: { token: { [Op.eq]: token } }, + }) return await t?.toOAuthInterface() }, getUser: async function getAuthUser(email, password) { - const user = await User.findOne({ - where: { email: { [Op.eq]: email } }, - }, { }) + const user = await User.findOne( + { + where: { email: { [Op.eq]: email } }, + }, + {}, + ) if (user != null) { const valid = await user.checkPassword(password) @@ -93,7 +109,11 @@ const model = { return createTokenPair(user, client, accessTokenModel, refreshTokenModel) }, - saveAuthorizationCode: async function ({ authorizationCode, expiresAt, redirectUri, scope }, client, user) { + saveAuthorizationCode: async function ( + { authorizationCode, expiresAt, redirectUri, scope }, + client, + user, + ) { const authCode = { auth_code: authorizationCode, client_id: client.id, @@ -108,7 +128,11 @@ const model = { return code.toOAuthInterface() }, - revokeToken: async function revokeRefreshToken({ refreshToken, client, user }) { + revokeToken: async function revokeRefreshToken({ + refreshToken, + client, + user, + }) { const deletions = await RefreshToken.destroy({ where: { token: { [Op.eq]: refreshToken }, @@ -120,7 +144,11 @@ const model = { return deletions > 0 }, - revokeAuthorizationCode: async function({ authorizationCode: code, client, user }) { + revokeAuthorizationCode: async function ({ + authorizationCode: code, + client, + user, + }) { const deletions = await AuthorizationCode.destroy({ where: { auth_code: code, @@ -132,7 +160,7 @@ const model = { return deletions > 0 }, - getAuthorizationCode: async function(auth_code) { + getAuthorizationCode: async function (auth_code) { const code = await AuthorizationCode.findOne({ where: { auth_code } }) if (code) { return code.toOAuthInterface() @@ -172,17 +200,12 @@ class KoaOAuthServer { this.authorize = async ctx => { const OAuthFlow = require('./OAuthFlow') const flow = await OAuthFlow.initialiseFlow(ctx) - const { - user, - redirect, - } = flow - - if (!user) { - return ctx.redirect(`/login?auth_state=${ redirect }`) - } else if (ctx.method === 'GET') { + const { user, redirect, action } = flow + + if (ctx.method === 'GET') { return await OAuthFlow.showOAuthConsent(ctx, flow) } else { - if (ctx.request.query.action === 'deny') { + if (action === 'deny') { return await OAuthFlow.handleConsentRejection(ctx, flow) } return await OAuthFlow.handleConsentAcceptance(ctx, flow, this) @@ -199,7 +222,14 @@ class KoaOAuthServer { this.token = async ctx => { const { req, res } = this.transformContext(ctx) - await authServer.token(req, res, { allowExtendedTokenAttributes: true, accessTokenLifetime: 3600 * 24 * 7 }) + + console.log(ctx.request.query) + console.log(ctx.request.body) + + await authServer.token(req, res, { + allowExtendedTokenAttributes: true, + accessTokenLifetime: 3600 * 24 * 7, + }) for (const [name, value] of Object.entries(res.headers)) { ctx.response.set(name, value) } diff --git a/src/domain/auth/AuthenticationService.js b/src/domain/auth/AuthenticationService.js index 07ae33497f7c74b5f6e35760b17e7a5dff76707d..78a5b5c579134e293f06b349c5715958fcf1d48f 100644 --- a/src/domain/auth/AuthenticationService.js +++ b/src/domain/auth/AuthenticationService.js @@ -2,6 +2,7 @@ const ContextualModule = require('core/injection/ContextualModule') const crypto = require('core/utils/crypto') const { User, AccessToken } = require('database/models') const HttpError = require('core/errors/HttpError') +const { reportContextError } = require('../../vendor/sentry') const HEADER_PREFIX = 'Bearer ' @@ -11,9 +12,7 @@ module.exports = class AuthenticationService extends ContextualModule { } static get profileMethods() { - return [ - 'getUser', 'attemptLogin', 'saveToSession' - ] + return ['getUser', 'attemptLogin', 'saveToSession'] } init() { @@ -22,7 +21,10 @@ module.exports = class AuthenticationService extends ContextualModule { async attemptLogin(email, password) { if (this._user != null) { - if (this._user.email === email && await this._user.checkPassword(password)) { + if ( + this._user.email === email && + (await this._user.checkPassword(password)) + ) { return this._user } else { throw new HttpError(401, 'Forbidden') @@ -55,9 +57,10 @@ module.exports = class AuthenticationService extends ContextualModule { } } else if (this.ctx.get('Authorization')) { const token = this.ctx.get('Authorization').substr(HEADER_PREFIX.length) + const accessToken = await AccessToken.findOne({ where: { token }, - include: [{ model: User }] + include: [{ model: User }], }) if (accessToken.User) { @@ -72,7 +75,8 @@ module.exports = class AuthenticationService extends ContextualModule { this.authenticateAs(user) return this._user } - } catch(e) { + } catch (e) { + reportContextError(e, this.ctx) console.error(e) } } @@ -87,13 +91,16 @@ module.exports = class AuthenticationService extends ContextualModule { async saveToSession(logoutIfEmpty = true) { const user = await this.getUser() if (user) { - this.ctx.session.user = await crypto.encrypt(JSON.stringify({ id: user.id })) + this.ctx.session.user = await crypto.encrypt( + JSON.stringify({ id: user.id }), + ) } else if (logoutIfEmpty) { this.ctx.session.user = null } } async clearSessionAuth() { - this.ctx.session.token = null + delete this.ctx.session.token + delete this.ctx.session.user } } diff --git a/src/domain/auth/OAuthFlow.js b/src/domain/auth/OAuthFlow.js index b2d369efa8dbc145a2dc1660994699e0a4130e75..665c76227e31dd78896139727191346421c30051 100644 --- a/src/domain/auth/OAuthFlow.js +++ b/src/domain/auth/OAuthFlow.js @@ -1,6 +1,8 @@ const { OAuthClient } = require('database/models') const HttpError = require('core/errors/HttpError') const crypto = require('core/utils/crypto') +const {config} = require("bootstrap"); +const debug = require('debug')('server:oauth:flow') /** * Retrieve the correct query value and format auth state for an oauth request @@ -11,20 +13,22 @@ exports.initialiseFlow = async ctx => { const user = await ctx.services['core.auth'].getUser() let baseQuery = ctx.request.query - let queryState = null - - console.log(baseQuery) + let queryState = baseQuery if (baseQuery.auth_state) { queryState = JSON.parse(await crypto.decrypt(baseQuery.auth_state)) if (queryState.query) { queryState = queryState.query + } else { + queryState = null } } const action = baseQuery.action - const redirectState = await crypto.encrypt(JSON.stringify({ redirect: 'authorize', query: baseQuery })) + const redirectState = await crypto.encrypt( + JSON.stringify({ redirect: 'authorize', query: baseQuery }), + ) return { user, @@ -36,52 +40,86 @@ exports.initialiseFlow = async ctx => { } exports.showOAuthConsent = async (ctx, queryState) => { - const { - user, - query, - redirect, - } = queryState + let { user, query, redirect } = queryState + + if (query.auth_state) { + try { + const realState = JSON.parse(await crypto.decrypt(query.auth_state)) + query = realState.query + } catch(e) { + console.error(e) + throw new HttpError(500, 'Bad auth state') + } + } + + const [scopes, isPrivileged] = describeScopeRequest(query.scope) + + if (isPrivileged) { + const allowed = new Set(config('app.security.super_auth_clients')) + if (!allowed.has(query.client_id)) { + throw new HttpError(401, 'This app is not allowed to request certain permissions') + } + } - const client = await OAuthClient.findOne({ where: { id: query.client_id }}) + const client = await OAuthClient.findOne({ where: { id: query.client_id } }) if (client == null) { throw new HttpError(400, 'Invalid client id specified') } - const scopes = describeScopeRequest(query.scope) return ctx.render('auth/accept-oauth', { user, - client, + client: client.toJSON(), scopes, redirect, }) } +async function getOauthQueryFromFlow(flow) { + let { state: queryState } = flow + + if (queryState.auth_state) { + const rawQueryState = await crypto.decrypt(queryState.auth_state) + queryState = JSON.parse(rawQueryState).query + } + + return queryState +} + exports.handleConsentRejection = async (ctx, flow) => { - const { redirect_uri } = flow.query + const queryState = await getOauthQueryFromFlow(flow) + const { redirect_uri } = queryState const redirect = new URL(redirect_uri, 'http://localhost') const search = new URLSearchParams(redirect.searchParams) search.set('error', 'access_denied') - search.set('error_description', 'The user has denied the requested permissions') + search.set( + 'error_description', + 'The user has denied the requested permissions', + ) + if (queryState.state) { + search.set('state', queryState.state) + } redirect.search = search.toString() - ctx.set('Location', redirect.toString()) - ctx.status = 302 - ctx.body = null + return await ctx.redirect(redirect.toString(), 302) } exports.handleConsentAcceptance = async (ctx, flow, server) => { - const { state: queryState } = flow - if (!queryState.state) { - queryState.state = crypto.insecureHexString(32) - } - + const queryState = await getOauthQueryFromFlow(flow) const { req, res } = server.transformContext(ctx, { query: queryState }) - await server.getAuthServer().authorize(req, res, { authenticateHandler: { handle() { return flow.user } }}) + + await server.getAuthServer().authorize(req, res, { + authenticateHandler: { + handle() { + return flow.user + }, + }, + }) for (const [name, value] of Object.entries(res.headers)) { ctx.response.set(name, value) } + ctx.response.status = res.status } @@ -89,11 +127,25 @@ const scopeDescriptionMap = { '*': { icon: 'admin', name: 'Full Access', - description: 'Full access to your account, including the ability to create, update and delete any user information, metrics and files.' + description: + 'Full access to your account, including the ability to create, update and delete any user information, metrics and files.', + }, + 'admin': { + icon: 'admin', + name: 'Admin System Access', + description: + 'Access to Jetsam backend data. Access requests for this permission are logged, and will only be granted to privileged users', + }, + 'openid': { + icon: 'openid', + name: 'Open ID Connect', + description: + 'Use your Jetsam account to log in to a third party services. This will provide the third party with your name (if provided), your email address and your Jetsam account ID.' }, 'metrics:create': { name: 'Create Metrics', - description: 'The ability to add data metrics linked to your account. Remember that connected apps that create metrics will know your location!', + description: + 'The ability to add data metrics linked to your account. Remember that connected apps that create metrics will know your location!', }, 'files:upload': { name: 'Upload Files', @@ -101,24 +153,51 @@ const scopeDescriptionMap = { }, 'files:read': { name: 'Read Files', - description: 'The ability to see and download images that you\'ve uploaded to your account', + description: + "The ability to see and download images that you've uploaded to your account", }, 'profile:read': { name: 'Read Profile', - description: 'The ability to see any information associated with your user profile. This includes your name and email address', + description: + 'The ability to see any information associated with your user profile. This includes your name and email address', }, 'profile:write': { name: 'Modify Profile', - description: 'The ability to edit any information associated with your user profile. This includes your name', + description: + 'The ability to edit any information associated with your user profile. This includes your name', }, 'profile:stats': { name: 'Profile Stats', - description: 'The ability to see information about your account stats, including your points and citizen scientist level', + description: + 'The ability to see information about your account stats, including your points and citizen scientist level', }, - } + +/** + * @typedef {object} ScopeDescription + * @property {string} name + * @property {string} description + */ + +/** + * @param scope + * @return {[ScopeDescription[], boolean]} + */ function describeScopeRequest(scope = '*') { - const scopes = scope.split(' ') - return scopes.map(s => scopeDescriptionMap[s]) - .filter(Boolean) + let hasAdminRequest = false + + console.log(scope) + let scopes = [] + if (scope.includes(',')) { + scopes = scope.split(',') + } else { + scopes = scope.split(' ') + } + + return [scopes.map(s => { + if (s.startsWith('admin') || s === '*') { + hasAdminRequest = true + } + return scopeDescriptionMap[s]; + }).filter(Boolean), hasAdminRequest] } diff --git a/src/domain/auth/handlers/SendUserPasswordReset.js b/src/domain/auth/handlers/SendUserPasswordReset.js index fd93380d9fbd33600525dc8b8d7795b0ffb0b6fa..5f7fd64b1430f71cc3c02a519b5692476cb65e49 100644 --- a/src/domain/auth/handlers/SendUserPasswordReset.js +++ b/src/domain/auth/handlers/SendUserPasswordReset.js @@ -2,38 +2,67 @@ const { config } = require('bootstrap') const HttpError = require('core/errors/HttpError') module.exports = async (body, ctx) => { - const { email } = body + const { email, device } = body const user = await ctx.services['core.users'].findByEmail(email) - const token = await ctx.profile('user.generateResetToken', 'Create reset token', () => user.generateResetToken()) + const token = await ctx.profile( + 'user.generateResetToken', + 'Create reset token', + () => user.generateResetToken(), + ) - const name = user.name || 'Jetsam User (You haven\'t told us your name!)' - const reset_link = new URL(`/reset-password?token=${ token }`, config('app.host.web')) + const name = user.name || "Jetsam User (You haven't told us your name!)" + const reset_link = new URL( + `/reset-password?token=${token}`, + config('app.host.web'), + ) const { mail } = require('services') + const data = { name, reset_link, action_url: reset_link, path: reset_link } + + if (device) { + data.security = { + operating_system: device.platform ?? '', + browser_name: device.info?.app_version + ? `Jetsam ${device.info.app_version}` + : device.browser ?? 'Jetsam', + } + } + try { await ctx.profile( 'services.mail.sendTemplate', - `template ${ config('mail.templates.reset-password')}`, - () => mail.sendTemplate(email, 'Reset Your Jetsam password', config('mail.templates.reset-password'), { - name, - reset_link, - }) + `template ${config('mail.templates.reset-password')}`, + () => + mail.sendTemplate( + email, + 'Reset Your Jetsam password', + config('mail.templates.reset-password'), + data, + ), ) } catch (e) { // reporter.report(e) - console.log(e.response.body.errors) + console.error(e) + console.log(e?.response?.body?.errors) throw new HttpError( 500, 'Failed To Send Reset Email', - { status: 500, title: 'Failed to send reset email', description: 'Could not send the password reset email' }, { - sendgrid: (e.response?.body?.errors ?? []).reduce((acc, e, i) => ({ - ...acc, - [`err-${ i }`]: JSON.stringify(e, null, 2), - }), {}), - } + status: 500, + title: 'Failed to send reset email', + description: 'Could not send the password reset email', + }, + { + sendgrid: (e?.response?.body?.errors ?? []).reduce( + (acc, e, i) => ({ + ...acc, + [`err-${i}`]: JSON.stringify(e, null, 2), + }), + {}, + ), + }, ) } -} \ No newline at end of file +} diff --git a/src/domain/data/MetricsService.js b/src/domain/data/MetricsService.js index b9a737fd9c4ffd9fbcbde29df46e30f9226afbfb..6775c843d5c443488867d21435e9ff1476f1ec32 100644 --- a/src/domain/data/MetricsService.js +++ b/src/domain/data/MetricsService.js @@ -3,6 +3,7 @@ const crypto = require('core/utils/crypto') const { User, AccessToken, Metric, Sequelize } = require('database/models') const { unset } = require('bootstrap') const HttpError = require('core/errors/HttpError') +const moment = require("moment"); const { Op } = Sequelize @@ -12,21 +13,45 @@ module.exports = class MetricsService extends ContextualModule { } static get profileMethods() { - return [ - 'queryAggregate', - 'queryAll', - 'recordMetric', - ] + return ['queryAggregate', 'queryAll', 'recordMetric'] } - async recordMetric(value, type, location) { + async recordMetric(value, type, location, meta = {}, transaction) { const user = await this.ctx.services['core.auth'].getUser() - const point = { type: 'Point', coordinates: [location.longitude, location.latitude] } - const payload = { value, type, location: point, author_id: user ? user.id : null } + const surveys = user ? await user.getSurveys({ + where: { + expires_at: { + [Sequelize.Op.gt]: moment.utc().toISOString() + }, + published_at: { + [Sequelize.Op.lt]: moment.utc().toISOString() + }, + public: true, + }, + }) : [] + + if (surveys.length > 0) { + meta.surveys = surveys.map(s => s.id) + } + + const point = { + type: 'Point', + coordinates: [location.longitude, location.latitude], + } + const payload = { + value, + type, + location: point, + author_id: user ? user.id : null, + meta, + } if (this.ctx.request.device) { - payload.meta = { device: this.ctx.request.device } + payload.meta = { + ...(payload.meta ?? {}), + device: this.ctx.request.device, + } } - return await Metric.create(payload) + return await Metric.create(payload, { transaction }) } async queryAggregate(pointBuffer, types, from, to) { @@ -35,24 +60,23 @@ module.exports = class MetricsService extends ContextualModule { return await Metric.findAll({ where: { [Op.and]: [ - Sequelize.literal(`ST_COVEREDBY(${ snapClause }, ST_POLYGONFROMTEXT('POLYGON((${ pointBuffer }))')::geography::geometry)`), + Sequelize.literal( + `ST_COVEREDBY(${snapClause}, ST_POLYGONFROMTEXT('POLYGON((${pointBuffer}))')::geography::geometry)`, + ), ], recorded_at: { - [Op.between]: [from, to] + [Op.between]: [from, to], }, type: { [Op.in]: types, - } + }, }, attributes: [ 'type', [Sequelize.fn('COUNT', Sequelize.col('value')), 'value'], - [Sequelize.literal(snapClause), 'location'] + [Sequelize.literal(snapClause), 'location'], ], - group: [ - Sequelize.literal(snapClause), - 'type', - ] + group: [Sequelize.literal(snapClause), 'type'], }) } @@ -60,14 +84,16 @@ module.exports = class MetricsService extends ContextualModule { return await Metric.findAll({ where: { [Op.and]: [ - Sequelize.literal(`ST_COVEREDBY("Metric"."location", ST_POLYGONFROMTEXT('POLYGON((${ pointBuffer }))'))`), + Sequelize.literal( + `ST_COVEREDBY("Metric"."location", ST_POLYGONFROMTEXT('POLYGON((${pointBuffer}))'))`, + ), ], recorded_at: { - [Op.between]: [from, to] + [Op.between]: [from, to], }, type: { [Op.in]: types, - } + }, }, }) } diff --git a/src/domain/users/UserService.js b/src/domain/users/UserService.js index 2b3ce9e8519819e41cdda1ac4ae601dcc2da321b..167c18712a6dcf5edee7e5f8a208279be1f2f612 100644 --- a/src/domain/users/UserService.js +++ b/src/domain/users/UserService.js @@ -10,12 +10,7 @@ module.exports = class UserService extends ContextualModule { } static get profileMethods() { - return [ - 'register', - 'findUser', - 'findByEmail', - 'findByAccessToken', - ] + return ['register', 'findUser', 'findByEmail', 'findByAccessToken'] } findUser(id) { @@ -30,7 +25,10 @@ module.exports = class UserService extends ContextualModule { } async findByAccessToken(token) { - const accessToken = await AccessToken.findOne({ where: { token }, include: [{ model: User }] }) + const accessToken = await AccessToken.findOne({ + where: { token }, + include: [{ model: User }], + }) if (accessToken) { return accessToken.User } diff --git a/src/http/controllers/api/analytics.js b/src/http/controllers/api/analytics.js new file mode 100644 index 0000000000000000000000000000000000000000..e1b500d2a09b4c9d08afcc3a0d7bbcf419ebdd18 --- /dev/null +++ b/src/http/controllers/api/analytics.js @@ -0,0 +1,58 @@ +const { sequelize } = require('database/models') +const { QueryTypes } = require('sequelize') +const moment = require('moment') +const { v4: uuid } = require('uuid') + +exports.track = async ctx => { + const { events } = ctx.request.body + const device = ctx.request.device + + const results = await ctx.profile('user.event', 'Track app event', () => + sequelize.transaction(async t => { + let succ = 0 + for (const event of events) { + const { + session, + action, + event: eventType, + timestamp, + start_time, + end_time, + data, + properties, + } = event + + const replacements = { + id: uuid(), + session, + action, + event: eventType, + start_time: timestamp + ? moment(timestamp).toISOString() + : start_time ?? null, + end_time: end_time ?? null, + properties: JSON.stringify(properties ?? data ?? {}), + location: null, + device: device ? JSON.stringify(device) : null, + } + + const [_, idx] = await sequelize.query( + `INSERT INTO + analytics (id, session_id, action, event, start_time, end_time, parent_id, properties, location, device) + VALUES + (:id, :session, :action, :event, :start_time, :end_time, null, :properties, :location, :device)`, + { + replacements, + type: QueryTypes.INSERT, + transaction: t, + }, + ) + + succ += idx + } + return succ + }), + ) + + ctx.status = results === events.length ? 201 : 500 +} diff --git a/src/http/controllers/api/app.js b/src/http/controllers/api/app.js index b4fcd9b9b8256691dcca1b93e48631ded22e99b9..cbfe3512f2fe7e5d893d5c95c2d852ed574b5a8e 100644 --- a/src/http/controllers/api/app.js +++ b/src/http/controllers/api/app.js @@ -8,10 +8,10 @@ exports.getBundles = async ctx => { const bundles = await ctx.profile( 'user.getBundleCodes', 'Get codepush bundles for authed user', - () => user.getBundleCodes() + () => user.getBundleCodes(), ) ctx.body = { bundles, } } -} \ No newline at end of file +} diff --git a/src/http/controllers/api/auth.js b/src/http/controllers/api/auth.js index 10290b3fd663c72e242de26f84a2899a6478b67c..d713c68819bfc57d90c371425476cd04fb387583 100644 --- a/src/http/controllers/api/auth.js +++ b/src/http/controllers/api/auth.js @@ -14,11 +14,19 @@ exports.register = async ctx => { const user = await User.findOne({ where: { email } }) if (user != null) { - throw new HttpError(409, 'Email Already Exists', { status: 409, title: 'Email Already Exists', description: 'That email address already exists. Please try another email address.' }) + throw new HttpError(409, 'Email Already Exists', { + status: 409, + title: 'Email Already Exists', + description: + 'That email address already exists. Please try another email address.', + }) } - const newUser = await ctx.services['core.users'] - .register(name ?? null, email, password) + const newUser = await ctx.services['core.users'].register( + name ?? null, + email, + password, + ) await newUser.handleIncludes(ctx.includes) const token = await newUser.asToken(ctx.get('x-token-type')) @@ -27,8 +35,7 @@ exports.register = async ctx => { exports.login = async ctx => { const { email, password } = ctx.request.body - const user = await ctx.services['core.auth'] - .attemptLogin(email, password) + const user = await ctx.services['core.auth'].attemptLogin(email, password) const token = await user.asToken(ctx.get('x-token-type')) @@ -40,10 +47,20 @@ exports.triggerPasswordReset = async ctx => { const { email } = ctx.request.body const user = await ctx.services['core.users'].findByEmail(email) if (!user) { - throw new HttpError(404, 'No Such Email', { status: 404, title: 'No Such Email', description: 'The provided email address is not associated with an account' }) + throw new HttpError(404, 'No Such Email', { + status: 404, + title: 'No Such Email', + description: + 'The provided email address is not associated with an account', + }) } - await queue.dispatch('send-user-password-reset', { email }) + console.log('Sending password reset for [%s]', email) + + await queue.dispatch('send-user-password-reset', { + email, + device: ctx.request.device, + }) ctx.body = { reset_token: null, @@ -116,7 +133,7 @@ exports.handlePasswordReset = async ctx => { if (expires.isSameOrBefore(moment.utc())) { ctx.body = { error: { - message: 'The reset token was invalid or expired' + message: 'The reset token was invalid or expired', }, params: { new_password, @@ -131,7 +148,7 @@ exports.handlePasswordReset = async ctx => { if (!user) { ctx.body = { error: { - message: 'The reset token was invalid or expired' + message: 'The reset token was invalid or expired', }, params: { new_password, @@ -148,4 +165,4 @@ exports.handlePasswordReset = async ctx => { ctx.status = 200 ctx.body = { user } -} \ No newline at end of file +} diff --git a/src/http/controllers/api/content.js b/src/http/controllers/api/content.js index 7b28757d47467eb33984317721fbe108e222d6b5..1f126df9f4a691a6499f3268974f72223aad764c 100644 --- a/src/http/controllers/api/content.js +++ b/src/http/controllers/api/content.js @@ -5,9 +5,57 @@ const moment = require('moment') exports.postMetric = async ctx => { const allowedTypes = new Set(Metric.getSupportedMetricTypes()) - const { value, type, location } = ctx.request.body + const { value, type, location, meta, batch } = ctx.request.body - if (location == null || location.longitude == null || location.latitude == null) { + let metric + let metrics + + if (batch) { + metrics = [] + try { + await sequelize.transaction(async t => { + for (const m of batch) { + const result = await save(m.value, m.type, m.location, m.meta, { + allowedTypes, + transaction: t, + ctx, + }) + + metrics.push(result) + } + }) + } catch (e) { + console.log(e) + + throw new HttpError({ + status: 400, + code: 'MTR-001', + title: 'Failed to save metric', + description: 'Something went wrong trying to save the metric', + }) + } + + ctx.body = { + metrics: metrics.map(metric => metric.toJSON()), + } + } else { + metric = await save(value, type, location, meta, { allowedTypes, ctx }) + ctx.body = { metric: metric.toJSON() } + } +} + +const save = async ( + value, + type, + location, + meta, + { allowedTypes, transaction, ctx }, +) => { + if ( + location == null || + location.longitude == null || + location.latitude == null + ) { throw new HttpError({ status: 400, code: 'MTR-001', @@ -17,22 +65,32 @@ exports.postMetric = async ctx => { } if (allowedTypes.has(type)) { - const metric = await ctx.services['data.metrics'].recordMetric(value, type, location) - ctx.body = { metric: metric.toJSON() } + return await ctx.services['data.metrics'].recordMetric( + value, + type, + location, + meta, + transaction, + ) } else { - throw new HttpError({ status: 400, code: 'MTR-002', title: 'Invalid Metric', description: `${ type } is not a supported type`}) + throw new HttpError({ + status: 400, + code: 'MTR-002', + title: 'Invalid Metric', + description: `${type} is not a supported type`, + }) } } function splitString(str) { - return str.split(',') + return str + .split(',') .map(s => s.trim()) .filter(Boolean) } function pointFromString(str) { - const parts = splitString(str) - .map(Number) + const parts = splitString(str).map(Number) return { latitude: parts[0], @@ -47,7 +105,7 @@ exports.getWithin = async ctx => { date_from, date_to = moment.utc(), types = '', - format = 'full' + format = 'full', } = ctx.request.query const fromPoint = pointFromString(point_from) @@ -69,18 +127,21 @@ exports.getWithin = async ctx => { [maxFromLong, maxFromLat], [maxFromLong, minFromLat], [minFromLong, minFromLat], - ].map(pb => pb.map(Number).join(' ')).join(',') + ] + .map(pb => pb.map(Number).join(' ')) + .join(',') - const query = format === 'marker' ? - ctx.services['data.metrics'].queryAggregate - : ctx.services['data.metrics'].queryAll + const query = + format === 'marker' + ? ctx.services['data.metrics'].queryAggregate + : ctx.services['data.metrics'].queryAll const metrics = await query( pointBuffer, metricTypes, // fromDate.toISOString(), moment().subtract(12, 'months').toISOString(), - toDate.toISOString() + toDate.toISOString(), ) ctx.body = { metrics } diff --git a/src/http/controllers/api/feedback.js b/src/http/controllers/api/feedback.js index 4a12d6998d075b6a6e789add8392b97f01466b50..a70e05ab2cbdf17b4e0569e6a34c4fec42e980b8 100644 --- a/src/http/controllers/api/feedback.js +++ b/src/http/controllers/api/feedback.js @@ -4,46 +4,46 @@ const SLACK_WEBHOOK = process.env.SLACK_WEBHOOK function createSlackPayload({ name, email, message = '' }) { return { - "blocks": [ + blocks: [ { - "type": "divider" + type: 'divider', }, { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "Incoming message from an app user!" - } + type: 'section', + text: { + type: 'mrkdwn', + text: 'Incoming message from an app user!', + }, }, { - "type": "section", - "text": { - "type": "plain_text", + type: 'section', + text: { + type: 'plain_text', text: message, emoji: true, - } + }, }, { - "type": "divider" + type: 'divider', }, { - "type": "context", - "elements": [ + type: 'context', + elements: [ { - "type": "mrkdwn", - "text": (new Date()).toDateString(), + type: 'mrkdwn', + text: new Date().toDateString(), }, name && { - "type": "plain_text", - "text": `From: ${ name }` + type: 'plain_text', + text: `From: ${name}`, }, email && { - "type": "plain_text", - "text": `Email: ${ email }` - } - ].filter(Boolean) - } - ] + type: 'plain_text', + text: `Email: ${email}`, + }, + ].filter(Boolean), + }, + ], } } @@ -77,10 +77,10 @@ exports.send = async ctx => { console.error(response) ctx.status = 500 ctx.body = { - message: 'Something went wrong' + message: 'Something went wrong', } } else { ctx.status = response.status - ctx.body = { message: 'Something Happened'} + ctx.body = { message: 'Something Happened' } } } diff --git a/src/http/controllers/api/oauth.js b/src/http/controllers/api/oauth.js index a82997e69c096dae35aea9a1de61fe1524156c1f..d8c99c11d8723f39c24d90f44d1f94c29acf5019 100644 --- a/src/http/controllers/api/oauth.js +++ b/src/http/controllers/api/oauth.js @@ -7,10 +7,11 @@ exports.createClient = async ctx => { throw new HttpError(403, 'You must be logged in to create an OAuth client') } - const client = await OAuthClient.generateClient(user.id) + const { name, description } = ctx.request.body + const client = await OAuthClient.generateClient(user.id, { name, description }) ctx.body = { - client: client.toOAuthInterface(), + client: client.toJSON(), } } exports.listClients = async ctx => { @@ -22,7 +23,7 @@ exports.listClients = async ctx => { const clients = await user.getOAuthClients() ctx.body = { - clients: clients.map(c => c.toOAuthInterface()) + clients: clients.map(c => c.toJSON()), } } @@ -31,7 +32,10 @@ exports.addClientRedirect = async ctx => { const user = await ctx.services['core.auth'].getUser() if (client?.owner_id !== user.id) { - throw new HttpError(403, 'You do not have permission to modify this oauth client') + throw new HttpError( + 403, + 'You do not have permission to modify this oauth client', + ) } const uri = ctx.request.body?.uri @@ -42,15 +46,12 @@ exports.addClientRedirect = async ctx => { const uris = new Set(client.redirect_uris) if (!uris.has(uri)) { - client.redirect_uris = [ - ...client.redirect_uris, - uri, - ] + client.redirect_uris = [...client.redirect_uris, uri] await client.save() } - ctx.body = { client: client.toOAuthInterface() } + ctx.body = { client: client.toJSON() } } exports.removeClientRedirect = async ctx => { @@ -58,7 +59,10 @@ exports.removeClientRedirect = async ctx => { const user = await ctx.services['core.auth'].getUser() if (client.owner_id !== user.id) { - throw new HttpError(403, 'You do not have permission to modify this oauth client') + throw new HttpError( + 403, + 'You do not have permission to modify this oauth client', + ) } const uri = ctx.request.body?.uri @@ -74,5 +78,5 @@ exports.removeClientRedirect = async ctx => { await client.save() } - ctx.body = { client: client.toOAuthInterface() } -} \ No newline at end of file + ctx.body = { client: client.toJSON() } +} diff --git a/src/http/controllers/api/storage.js b/src/http/controllers/api/storage.js index e8886232ab4536d33751b2258442aad2d0a7b730..544e81ad653cb7e5bcedc695054e5c2434eabb75 100644 --- a/src/http/controllers/api/storage.js +++ b/src/http/controllers/api/storage.js @@ -5,7 +5,7 @@ const mimeType = require('mime-types') const { v4: uuid } = require('uuid') const { fs, env } = require('bootstrap') const moment = require('moment') -const {unset} = require('../../../bootstrap') +const { unset } = require('../../../bootstrap') // const reporter = require('services/Reporter') const { Op } = Sequelize @@ -20,11 +20,15 @@ exports.saveFile = async ctx => { const user = await ctx.profile( 'core.auth.getUser', 'Get logged in user', - async () => ctx.services['core.auth'].getUser() + async () => ctx.services['core.auth'].getUser(), ) if (!user) { - throw new HttpError({ status: 403, title: 'Must be signed in to feature an image', description: 'You must be signed in to submit images to the content feed' }) + throw new HttpError({ + status: 403, + title: 'Must be signed in to feature an image', + description: 'You must be signed in to submit images to the content feed', + }) } const { file } = ctx @@ -37,13 +41,13 @@ exports.saveFile = async ctx => { bucket: env('GCS_BUCKET'), device: ctx.request.device, }, - file_name: `${ uuid() }.${ mimeType.extension(file.mimetype) }`, - file_root: `${ user.id }`, + file_name: `${uuid()}.${mimeType.extension(file.mimetype)}`, + file_root: `${user.id}`, user_id: user.id, stream: 'plastics-public', provider: 'google', comment: '', - tags : [], + tags: [], approved: true, featured: false, } @@ -56,9 +60,11 @@ exports.saveFile = async ctx => { fileInfo.meta.location = location } - const persistedFile = await File.create(fileInfo).catch(e => console.error(e) || null) + const persistedFile = await File.create(fileInfo).catch( + e => console.error(e) || null, + ) - const storagePath = `${ fileInfo.file_root }/${ fileInfo.file_name }` + const storagePath = `${fileInfo.file_root}/${fileInfo.file_name}` const bucket = storage.bucket(env('GCS_BUCKET')) const uploadOpts = { @@ -69,8 +75,8 @@ exports.saveFile = async ctx => { metadata: { mimetype: file.mimetype, uploader: user.id, - } - } + }, + }, } await bucket.upload(file.path, uploadOpts) @@ -88,11 +94,15 @@ exports.saveFile2 = async ctx => { const user = await ctx.profile( 'core.auth.getUser', 'Get logged in user', - async () => ctx.services['core.auth'].getUser() + async () => ctx.services['core.auth'].getUser(), ) if (!user) { - throw new HttpError({ status: 403, title: 'Must be signed in to feature an image', description: 'You must be signed in to submit images to the content feed' }) + throw new HttpError({ + status: 403, + title: 'Must be signed in to feature an image', + description: 'You must be signed in to submit images to the content feed', + }) } const { file } = ctx @@ -104,13 +114,13 @@ exports.saveFile2 = async ctx => { size: file.size, bucket: env('GCS_BUCKET'), }, - file_name: `${ uuid() }.${ mimeType.extension(file.mimetype) }`, - file_root: `${ user.id }`, + file_name: `${uuid()}.${mimeType.extension(file.mimetype)}`, + file_root: `${user.id}`, user_id: user.id, stream: 'plastics-public', provider: 'google', comment: title, - tags : Array.isArray(tags) ? tags : [tags], + tags: Array.isArray(tags) ? tags : [tags], approved: true, featured: false, } @@ -119,9 +129,11 @@ exports.saveFile2 = async ctx => { fileinfo.meta.remote_id = remote_id } - const persistedFile = await File.create(fileinfo).catch(e => console.error(e) || null) + const persistedFile = await File.create(fileinfo).catch( + e => console.error(e) || null, + ) - const storagePath = `${ fileinfo.file_root }/${ fileinfo.file_name }` + const storagePath = `${fileinfo.file_root}/${fileinfo.file_name}` const bucket = storage.bucket(env('GCS_BUCKET')) const uploadOpts = { @@ -133,8 +145,8 @@ exports.saveFile2 = async ctx => { tags, mimetype: file.mimetype, uploader: user.id, - } - } + }, + }, } await bucket.upload(file.path, uploadOpts) @@ -148,14 +160,18 @@ exports.getFiles = async ctx => { const user = await ctx.profile( 'core.auth.getUser', 'Get logged in user', - async () => ctx.services['core.auth'].getUser() + async () => ctx.services['core.auth'].getUser(), ) if (!user) { - throw new HttpError({ status: 403, title: 'Must be signed in to feature an image', description: 'You must be signed in to submit images to the content feed' }) + throw new HttpError({ + status: 403, + title: 'Must be signed in to feature an image', + description: 'You must be signed in to submit images to the content feed', + }) } - const where = { } + const where = {} const { since } = ctx.query if (since && moment.utc(since).isValid()) { @@ -171,13 +187,21 @@ exports.featureImage = async ctx => { const user = await ctx.services['core.auth'].getUser() if (!user) { - throw new HttpError({ status: 403, title: 'Must be signed in to feature an image', description: 'You must be signed in to submit images to the content feed' }) + throw new HttpError({ + status: 403, + title: 'Must be signed in to feature an image', + description: 'You must be signed in to submit images to the content feed', + }) } const { imageId } = ctx.params const file = await File.findOne({ where: { id: imageId } }) if (file.user_id !== user.id) { - throw new HttpError({ status: 403, title: 'Cannot feature non-owned image', description: 'You can\'t feature an image that doesn\'t belong to you' }) + throw new HttpError({ + status: 403, + title: 'Cannot feature non-owned image', + description: "You can't feature an image that doesn't belong to you", + }) } if (file.featured && file.featured_at) { @@ -205,43 +229,42 @@ exports.feed = async ctx => { if (user != null) { includes.push([ - Sequelize.literal(`exists (select * from user_file_likes where user_file_likes.user_id='${ user.id }' and user_file_likes.file_id="File".id)`), + Sequelize.literal( + `exists (select * from user_file_likes where user_file_likes.user_id='${user.id}' and user_file_likes.file_id="File".id)`, + ), 'liked', ]) } else { - includes.push([ - Sequelize.literal('false'), - 'liked', - ]) + includes.push([Sequelize.literal('false'), 'liked']) } await ctx.profile('feed.list', 'Fetch Jetsam community feed', async () => { ctx.body = { - feed: (await File.findAll({ - where: { - approved: true, - featured: true, - created_at: { - [Sequelize.Op.gt]: moment.utc().subtract(1, 'month').toISOString(), + feed: ( + await File.findAll({ + where: { + approved: true, + featured: true, + created_at: { + [Sequelize.Op.gt]: moment + .utc() + .subtract(1, 'month') + .toISOString(), + }, }, - }, - order: [ - ['featured_at', 'desc'], - ['created_at', 'desc'], - ], - attributes: { - include: includes, - exclude: [ - 'labels', - 'updated_at', - 'requires_approval', - 'labels', - ] - } - })).map(inst => ({ + order: [ + ['featured_at', 'desc'], + ['created_at', 'desc'], + ], + attributes: { + include: includes, + exclude: ['labels', 'updated_at', 'requires_approval', 'labels'], + }, + }) + ).map(inst => ({ ...inst.toJSON(), liked: inst.get('liked'), - })) + })), } }) } @@ -251,28 +274,44 @@ exports.like = async ctx => { const user = await ctx.services['core.auth'].getUser() if (!user) { - throw new HttpError({ status: 403, title: 'Must be signed in to like an image', description: 'You must be signed in to like images' }) + throw new HttpError({ + status: 403, + title: 'Must be signed in to like an image', + description: 'You must be signed in to like images', + }) } - const file = await File.findOne({ where: { id: fileId }}) + const file = await File.findOne({ where: { id: fileId } }) if (!file) { - throw new HttpError({ status: 404, title: 'Could not find image', description: 'Could not find image to like' }) + throw new HttpError({ + status: 404, + title: 'Could not find image', + description: 'Could not find image to like', + }) } await user.addLike(file) - ctx.body = { file: {...file.toJSON(), liked: true }} + ctx.body = { file: { ...file.toJSON(), liked: true } } } exports.unlike = async ctx => { const { fileId } = ctx.params const user = await ctx.services['core.auth'].getUser() if (!user) { - throw new HttpError({ status: 403, title: 'Must be signed in to like an image', description: 'You must be signed in to unlike images' }) + throw new HttpError({ + status: 403, + title: 'Must be signed in to like an image', + description: 'You must be signed in to unlike images', + }) } - const file = await File.findOne({ where: { id: fileId }}) + const file = await File.findOne({ where: { id: fileId } }) if (!file) { - throw new HttpError({ status: 404, title: 'Could not find image', description: 'Could not find image to unlike' }) + throw new HttpError({ + status: 404, + title: 'Could not find image', + description: 'Could not find image to unlike', + }) } await user.removeLike(file) - ctx.body = { file: {...file.toJSON(), liked: false }} -} \ No newline at end of file + ctx.body = { file: { ...file.toJSON(), liked: false } } +} diff --git a/src/http/controllers/api/user.js b/src/http/controllers/api/user.js index 8e540b8a2780264d2f8f4869a121279e7386ec61..7c100458b8f026af5fddecdeb2a4409b351fbf6f 100644 --- a/src/http/controllers/api/user.js +++ b/src/http/controllers/api/user.js @@ -3,10 +3,16 @@ const HttpError = require('core/errors/HttpError') exports.self = async ctx => { const user = await ctx.services['core.auth'].getUser() if (user) { - await user.handleIncludes(ctx.includes) + ctx.body = { + user: await user.serialise(), + } + } else { + throw new HttpError({ + status: 404, + title: 'No such user', + description: 'No user is currently logged in', + }) } - - ctx.body = { user } } exports.updateSelf = async ctx => { @@ -28,8 +34,12 @@ exports.updateOne = async ctx => { await user.save() await user.handleIncludes(ctx.includes) } else { - throw new HttpError({ status: 404, title: 'No such user', description: 'No user is currently logged in' }) + throw new HttpError({ + status: 404, + title: 'No such user', + description: 'No user is currently logged in', + }) } ctx.body = { user } -} \ No newline at end of file +} diff --git a/src/http/controllers/api/v2/factories.js b/src/http/controllers/api/v2/factories.js new file mode 100644 index 0000000000000000000000000000000000000000..9438dcf840e6987156eca6f40bd58ae7af5df508 --- /dev/null +++ b/src/http/controllers/api/v2/factories.js @@ -0,0 +1,59 @@ +exports.survey = async ctx => { + const faker = require('faker') + const {v4: uuid} = require('uuid') + const moment = require('moment') + const { Survey } = require('database/models') + + const company = faker.company.companyName() + const name = faker.helpers.randomize([company, faker.hacker.noun(), faker.vehicle.vehicle()]) + + const properties = Math.random() > 0.5 ? {} : { + [faker.database.column()]: 'boolean', + } + + const payload = { + id: uuid(), + name: `${name} Survey`, + partner_names: [company], + header_image_url: faker.image.imageUrl(), + description: [ + { + heading: 'About', + status: null, + content: [{ + type: 'text', + text: faker.lorem.paragraph() + }, { + type: 'text', + text: faker.lorem.paragraph() + }], + } + ], + requirements: Object.values(properties).length === 0 ? [] : [ + { + heading: `${ faker.hacker.adjective() } ${ faker.hacker.noun() } ${ faker.hacker.ingverb() }`, + status: null, + content: [{ + type: 'text', + text: faker.hacker.phrase(), + },{ + type: 'confirmation', + id: Object.keys(properties)[0], + label: faker.lorem.paragraph(), + default: false, + }] + } + ], + properties, + public: true, + published_at: moment(faker.date.past()).toISOString(), + expires_at: moment(faker.date.future()).toISOString(), + } + + payload.settings = payload.requirements + + const survey = await Survey.create(payload) + ctx.body = { + survey, + } +} \ No newline at end of file diff --git a/src/http/controllers/api/v2/surveys.js b/src/http/controllers/api/v2/surveys.js new file mode 100644 index 0000000000000000000000000000000000000000..07127a5e9b9db3bed7fb359bd2f9ac3ed251092f --- /dev/null +++ b/src/http/controllers/api/v2/surveys.js @@ -0,0 +1,158 @@ +const moment = require('moment') +const UnauthorizedError = require("../../../../core/errors/UnauthorizedError"); +const NotFoundError = require("../../../../core/errors/NotFoundError"); +const HttpError = require("../../../../core/errors/HttpError"); +const {Survey, SurveyUser, User, sequelize} = require('database/models') +const {QueryTypes} = require('sequelize') + +exports.get = async ctx => { + const {survey} = ctx.models + if (survey) { + ctx.body = { + survey: survey.asOwnSurvey() + } + } else { + throw new NotFoundError('Survey') + } +} + +exports.list = async ctx => { + const {Sequelize, Survey} = require('database/models') + const user = await ctx.services['core.auth'].getUser() + + let includes = user ? [{ + model: SurveyUser, + required: false, + where: { + user_id: user.id, + } + }] : [] + + const surveys = await Survey.findAll({ + where: { + expires_at: { + [Sequelize.Op.gt]: moment.utc().toISOString() + }, + published_at: { + [Sequelize.Op.lt]: moment.utc().toISOString() + }, + public: true, + }, + include: includes + }) + + ctx.body = { + surveys: surveys.map(s => { + if (Array.isArray(s.SurveyUsers) && s.SurveyUsers[0] != null) { + s.SurveyUser = s.SurveyUsers[0] + } + return s.asOwnSurvey(); + }), + } +} + +exports.joined = async ctx => { + const user = await ctx.services['core.auth'].getUser() + if (user == null) { + ctx.body = { + surveys: [] + } + return + } + + const surveys = await user.getSurveys({include: [SurveyUser]}) + + ctx.body = { + surveys: surveys.map(s => s.asOwnSurvey()) + } +} + +exports.join = async ctx => { + if (ctx.models.survey == null) { + throw new NotFoundError('survey') + } + + const user = await ctx.services['core.auth'].getUser() + if (user == null) { + throw new UnauthorizedError() + } + + const {survey} = ctx.models + const {properties = {}} = ctx.request.body + + if (Object.values(survey.properties).length !== Object.values(properties).length) { + throw new HttpError(400, `Must provide values for all properties. Expecting: [${Object.keys(survey.properties).join(', ')}]; Found [${Object.keys(properties).join(', ')}] `) + } + + const surveyUserProperties = {} + Object.entries(survey.properties).forEach(([key, type]) => { + if (properties[key] == null) { + throw new HttpError(400, `Must provide value for property ${key}`) + } + surveyUserProperties[key] = properties[key] + }) + + + const existing = await SurveyUser.findOne({ + where: { + survey_id: survey.id, + user_id: user.id, + } + }) + + if (existing) { + existing.properties = surveyUserProperties + await existing.save() + + ctx.body = { + survey, + answers: existing, + } + return + } + + const [rows, count] = await sequelize.query(` + INSERT INTO "survey_users" ("user_id", "properties", "survey_id") + VALUES (:user_id, :properties, :survey_id) RETURNING "user_id","survey_id","properties","created_at"; + `, { + replacements: {survey_id: survey.id, user_id: user.id, properties: JSON.stringify(properties)}, + type: QueryTypes.INSERT, + }) + + if (count === 0) { + throw new HttpError(500, 'Unable to join survey') + } + + const surveyUser = SurveyUser.build(rows[0]) + + ctx.body = { + survey, + answers: surveyUser, + } +} + +exports.leave = async ctx => { + if (ctx.models.survey == null) { + throw new NotFoundError('survey') + } + + const user = await ctx.services['core.auth'].getUser() + if (user == null) { + throw new UnauthorizedError() + } + + const result = await sequelize.query(`DELETE + FROM "survey_users" + WHERE user_id = :user_id + AND survey_id = :survey_id`, { + replacements: { + survey_id: ctx.models.survey.id, + user_id: user.id, + }, + type: QueryTypes.DELETE + }) + + ctx.body = { + success: true + } +} \ No newline at end of file diff --git a/src/http/controllers/api/v2/uploads.js b/src/http/controllers/api/v2/uploads.js new file mode 100644 index 0000000000000000000000000000000000000000..62f03586532c700bf6cd8bb2ebcc8689f5f44a75 --- /dev/null +++ b/src/http/controllers/api/v2/uploads.js @@ -0,0 +1,30 @@ +exports.createUpload = async ctx => { + const { fs } = require('services') + const { v4: uuid } = require('uuid') + const { config } = require('bootstrap') + const HttpError = require('core/errors/HttpError') + + const { content_type, id } = ctx.request.body + const user = await ctx.services['core.auth'].getUser() + if (!user) { + throw new HttpError(403, 'You must be logged in to upload an image') + } + + const payload = await fs.createUploadUrl( + `${user.id}/${id ?? uuid()}.jpg`, + 60 * 60 * 2, + { + contentType: content_type, + }, + ) + + const upload = await user.createUpload({ + provider: config('fs.driver'), + upload_url: payload.url, + request_params: payload, + expires_at: payload.expires_at_ms, + status: 'pending', + }) + + ctx.body = { upload: payload } +} diff --git a/src/http/controllers/auth.js b/src/http/controllers/auth.js index 640453fd5d3cc267bd6056c555365c0e0f8ce7cc..1284e3b269e41f6d0745c92c0a958b705642467f 100644 --- a/src/http/controllers/auth.js +++ b/src/http/controllers/auth.js @@ -1,5 +1,6 @@ const crypto = require('core/utils/crypto') const moment = require('moment') +const {createRedirectedUrl} = require("../../core/utils/urls"); exports.login = async ctx => { const { email, password } = ctx.request.body @@ -7,26 +8,54 @@ exports.login = async ctx => { await ctx.services['core.auth'].saveToSession() return exports.handleLoginRedirect(ctx) } +exports.logout = async ctx => { + await ctx.services['core.auth'].clearSessionAuth() + return ctx.redirect('/') +} -exports.handleLoginRedirect = async ctx => { - if (ctx.request.query.login_state) { - const { login_state } = ctx.request.query - const values = JSON.parse(await crypto.decrypt(login_state)) - - console.log(values) - if (values.redirect === 'authorize') { - return ctx.redirect(`/auth/authorize?auth_state=${ values.query.auth_state }`) - } else { - return ctx.redirect('/') - } - } else { - return ctx.redirect('/') +exports.showLogin = async ctx => { + const data = {} + const state = new URLSearchParams() + if (ctx.query.login_state) { + state.set('login_state', ctx.query.login_state) } + if (ctx.query.auth_state) { + state.set('auth_state', ctx.query.auth_state) + } + + data.state_string = `?${ state.toString() }` + return ctx.render('auth/login', data) +} + +exports.handleLoginRedirect = async ctx => { + const redirectTo = await createRedirectedUrl(ctx) + return ctx.redirect(redirectTo) + + // const query = ctx.request.query + // + // if (query.login_state || query.auth_state) { + // const { login_state, auth_state } = ctx.request.query + // const state = login_state ?? auth_state + // + // const values = JSON.parse(await crypto.decrypt(state)) + // + // if (values.redirect === 'authorize') { + // return ctx.redirect( + // `/auth/authorize?auth_state=${state}`, + // ) + // } else { + // return ctx.redirect('/') + // } + // } else { + // return ctx.redirect('/') + // } } const resetErrorMessages = { - missing: 'No token was found in the URL. If you clicked a link to get here, please make sure that it contains a password reset token. You may need to request a new password reset in the Jetsam app.', - invalid: 'The link you clicked was invalid or has expired. Password reset links are valid for 1 hour from the time we send them to you; you may need to request a new password reset in the Jetsam app.', + missing: + 'No token was found in the URL. If you clicked a link to get here, please make sure that it contains a password reset token. You may need to request a new password reset in the Jetsam app.', + invalid: + 'The link you clicked was invalid or has expired. Password reset links are valid for 1 hour from the time we send them to you; you may need to request a new password reset in the Jetsam app.', } exports.resetPassword = async ctx => { @@ -44,7 +73,12 @@ exports.resetPassword = async ctx => { } const { sequelize } = require('database/models') - const [ [ { exists } ] ] = await sequelize.query('SELECT exists(select reset_token from users where reset_token = :token AND deleted_at is null limit 1)', { replacements: { token } }) + const [ + [{ exists }], + ] = await sequelize.query( + 'SELECT exists(select reset_token from users where reset_token = :token AND deleted_at is null limit 1)', + { replacements: { token } }, + ) if (!exists) { errorData.message = resetErrorMessages.invalid @@ -65,7 +99,11 @@ exports.resetPassword = async ctx => { const time = moment.utc(data.expires) - if (data.id == null || data.expires == null || time.isSameOrBefore(moment.utc())) { + if ( + data.id == null || + data.expires == null || + time.isSameOrBefore(moment.utc()) + ) { errorData.message = resetErrorMessages.invalid await ctx.render('auth/reset-password-error', errorData) ctx.status = 400 @@ -84,11 +122,11 @@ exports.handleResetPassword = async ctx => { if (ctx.status >= 400) { const { error } = ctx.body await ctx.render('auth/reset-password-error', { - back_link: `/reset-password?token=${ ctx.request.body.reset_token }`, + back_link: `/reset-password?token=${ctx.request.body.reset_token}`, message: error.message, }) return } await ctx.render('auth/reset-password-success') -} \ No newline at end of file +} diff --git a/src/http/controllers/fs_local.js b/src/http/controllers/fs_local.js index ae77418b2ba42a2df0dd4f27d5456270665bdee5..19a55f1cce1255dbaecdee5fc6971b05e30e956a 100644 --- a/src/http/controllers/fs_local.js +++ b/src/http/controllers/fs_local.js @@ -29,7 +29,7 @@ exports.uploadFile = async ctx => { } const extension = mime.extension(ctx.request.file.mimetype) - const fpath = p.normalize(`${ n(uid) }/${ n(fid) }.${ extension }`) + const fpath = p.normalize(`${n(uid)}/${n(fid)}.${extension}`) await fs.write(fpath, ctx.request.file.buffer) file.meta = { ...file.meta, path: fpath } @@ -52,10 +52,9 @@ exports.serveFile = async ctx => { throw new HttpError(404, 'File not found') } - const { fs } = require('bootstrap') const { fs: fileservice } = require('services') ctx.set('Content-Type', file.meta.contentType) ctx.body = fs.createReadStream(fs.path(fileservice.base, file.meta.path)) -} \ No newline at end of file +} diff --git a/src/http/middleware/DeviceProperties.js b/src/http/middleware/DeviceProperties.js index ec13422448a28ea1e881744052d596242b9e4133..ae8f9578b6bf2aa6dd2c3c7d250323538daf2dc5 100644 --- a/src/http/middleware/DeviceProperties.js +++ b/src/http/middleware/DeviceProperties.js @@ -1,11 +1,9 @@ exports.extractDevice = async (ctx, next) => { - const deviceId = ctx.get('X-Request-Device') - const platform = ctx.get('X-Request-Platform') - const rawSlug = ctx.get('X-Request-Slug') + const deviceId = ctx.get('x-request-device') + const platform = ctx.get('x-request-platform') + const rawSlug = ctx.get('x-request-slug') - const slug = rawSlug ? - Buffer.from(rawSlug, 'base64').toString('utf-8') - : null + const slug = rawSlug ? Buffer.from(rawSlug, 'base64').toString('utf-8') : null ctx.request.device = { id: deviceId, @@ -14,4 +12,4 @@ exports.extractDevice = async (ctx, next) => { } return await next() -} \ No newline at end of file +} diff --git a/src/http/middleware/ParseIncludes.js b/src/http/middleware/ParseIncludes.js index 8869d3772452d76a5328336df91aad36aee91162..a928e3705d321f94d3f4d9fa81e4739fbaf8423c 100644 --- a/src/http/middleware/ParseIncludes.js +++ b/src/http/middleware/ParseIncludes.js @@ -1,7 +1,10 @@ module.exports = async function (ctx, next) { const { expand } = ctx.query if (expand != null) { - const expanded = expand.split(',').map(s => s.trim()).filter(Boolean) + const expanded = expand + .split(',') + .map(s => s.trim()) + .filter(Boolean) ctx.includes = expanded } else { ctx.includes = [] diff --git a/src/http/middleware/Profiler.js b/src/http/middleware/Profiler.js index d9b1e37c028b5b68789666d492ecbc86425ba6fd..9e3b5b086f66a0db44f0fbc309bb53cbf9df6909 100644 --- a/src/http/middleware/Profiler.js +++ b/src/http/middleware/Profiler.js @@ -1,16 +1,16 @@ -const Sentry = require("@sentry/node") -const { extractTraceparentData }= require("@sentry/tracing") +const Sentry = require('@sentry/node') +const { extractTraceparentData } = require('@sentry/tracing') const threadContext = require('core/injection/ThreadContext') module.exports = async (ctx, next) => { let traceparentData - if (ctx.request.get("sentry-trace")) { - traceparentData = extractTraceparentData(ctx.request.get("sentry-trace")); + if (ctx.request.get('sentry-trace')) { + traceparentData = extractTraceparentData(ctx.request.get('sentry-trace')) } const t = threadContext.getTransaction({ op: 'http.request', - name: `[${ ctx.method }] ${ ctx.path }`, + name: `[${ctx.method}] ${ctx.path}`, traceparentData, tags: { 'http.method': ctx.method, @@ -41,7 +41,11 @@ module.exports = async (ctx, next) => { try { return await next() } finally { - t.setName(`[${ ctx.method }] ${ ctx._matchedRouteName ?? ctx._matchedRoute ?? ctx.path }`) + t.setName( + `[${ctx.method}] ${ + ctx._matchedRouteName ?? ctx._matchedRoute ?? ctx.path + }`, + ) t.setHttpStatus(ctx.status) const user = ctx.services['core.auth']._user Sentry.configureScope(scope => { @@ -57,4 +61,4 @@ module.exports = async (ctx, next) => { threadContext.stopTransaction() }) } -} \ No newline at end of file +} diff --git a/src/http/middleware/RedirectToLogin.js b/src/http/middleware/RedirectToLogin.js new file mode 100644 index 0000000000000000000000000000000000000000..52925552876724d82cceb4ec395d6885ef022c83 --- /dev/null +++ b/src/http/middleware/RedirectToLogin.js @@ -0,0 +1,12 @@ +const {createRedirectState} = require("../../core/utils/urls"); + +module.exports = async (ctx, next) => { + const user = await ctx.services['core.auth'].getUser() + + if (user) { + return await next() + } + + const redirectState = await createRedirectState(ctx) + return ctx.redirect(`/login?login_state=${ redirectState }`) +} diff --git a/src/http/middleware/RequiresAuth.js b/src/http/middleware/RequiresAuth.js index 5f6cda3320b8a3077593bdb761d8c640a3363192..35c924ff221d080ba5e343ad168741fa9d8bbcd6 100644 --- a/src/http/middleware/RequiresAuth.js +++ b/src/http/middleware/RequiresAuth.js @@ -6,4 +6,4 @@ module.exports = async (ctx, next) => { throw new UnauthorizedError() } return await next() -} \ No newline at end of file +} diff --git a/src/http/middleware/SentryReporter.js b/src/http/middleware/SentryReporter.js index 694260b142d0f8fa4473b2fad32b202fff9a6ba4..dfa1ed1ab0acef621c37ba494cce5afb987a0d76 100644 --- a/src/http/middleware/SentryReporter.js +++ b/src/http/middleware/SentryReporter.js @@ -17,7 +17,7 @@ exports.report = async function reportErrorToSentry(error, ctx) { } let user = await getUserObject(ctx) - Sentry.withScope(function(scope) { + Sentry.withScope(function (scope) { if (user) { scope.setUser(user) } @@ -30,19 +30,23 @@ exports.report = async function reportErrorToSentry(error, ctx) { scope.setContext('debugging', error._debugging) } - scope.addEventProcessor(function(event) { - return Sentry.Handlers.parseRequest(event, ctx.request); - }); - Sentry.captureException(error); - }); + scope.addEventProcessor(function (event) { + return Sentry.Handlers.parseRequest(event, ctx.request) + }) + Sentry.captureException(error) + }) } exports.reportHttp = async function reportHttpToSentry(ctx) { let user = await getUserObject(ctx) - const error = new HttpError(ctx.status, `[${ ctx.status }] A HTTP Error Occurred`, { body: ctx.body }) + const error = new HttpError( + ctx.status, + `[${ctx.status}] A HTTP Error Occurred`, + { body: ctx.body }, + ) - Sentry.withScope(function(scope) { + Sentry.withScope(function (scope) { if (user) { scope.setUser(user) } @@ -53,9 +57,9 @@ exports.reportHttp = async function reportHttpToSentry(ctx) { scope.setContext('device', ctx.request.device) } - scope.addEventProcessor(function(event) { - return Sentry.Handlers.parseRequest(event, ctx.request); - }); - Sentry.captureException(error); - }); -} \ No newline at end of file + scope.addEventProcessor(function (event) { + return Sentry.Handlers.parseRequest(event, ctx.request) + }) + Sentry.captureException(error) + }) +} diff --git a/src/http/middleware/groups.js b/src/http/middleware/groups.js new file mode 100644 index 0000000000000000000000000000000000000000..8fd1ec9040e2b5b0918c5c69a29f1595bdda37c9 --- /dev/null +++ b/src/http/middleware/groups.js @@ -0,0 +1,15 @@ +const context = require('http/middleware/ThreadContextWrapper') +const errors = require('http/middleware/ErrorHandler') +const includes = require('http/middleware/ParseIncludes') +const profiling = require('http/middleware/Profiler') +const loaders = require('http/middleware/MountLoaders') +const device = require('http/middleware/DeviceProperties').extractDevice + +exports.apiMiddlewareGroup = [ + context, + profiling, + errors, + includes, + loaders, + device, +] diff --git a/src/http/params/event.js b/src/http/params/event.js index 30d1f82abdb5bc74ec952f2cedda6cfbb10c6a67..41db4e4625a14e8ee805da891db25b1e2768590c 100644 --- a/src/http/params/event.js +++ b/src/http/params/event.js @@ -4,4 +4,4 @@ module.exports = async (id, ctx, next) => { ctx.models = ctx.models ?? {} ctx.models.event = await Event.findByPk(id) return await next() -} \ No newline at end of file +} diff --git a/src/http/params/file.js b/src/http/params/file.js index 23c7510705570b9427bb5cd3856416da9ca4bf44..17fcfd8ed0cc576beaeb3013a9aac1ec00e0660b 100644 --- a/src/http/params/file.js +++ b/src/http/params/file.js @@ -4,4 +4,4 @@ module.exports = async (id, ctx, next) => { ctx.models = ctx.models ?? {} ctx.models.file = await File.findByPk(id) return await next() -} \ No newline at end of file +} diff --git a/src/http/params/oauth_client.js b/src/http/params/oauth_client.js index ed386d809639ac9ce6a3df5d3db0e32029615ab3..91ee3d812c8a051727d959c57593720b425d3d9e 100644 --- a/src/http/params/oauth_client.js +++ b/src/http/params/oauth_client.js @@ -4,4 +4,4 @@ module.exports = async (id, ctx, next) => { ctx.models = ctx.models ?? {} ctx.models.oauthClient = await OAuthClient.findByPk(id) return await next() -} \ No newline at end of file +} diff --git a/src/http/params/survey.js b/src/http/params/survey.js new file mode 100644 index 0000000000000000000000000000000000000000..92ded5d8e02be21c1f5280ff39c08f028dc2ec2e --- /dev/null +++ b/src/http/params/survey.js @@ -0,0 +1,37 @@ +const { Survey, SurveyUser, Sequelize} = require('database/models') +const moment = require("moment"); + +module.exports = async (id, ctx, next) => { + ctx.models = ctx.models ?? {} + + const user = await ctx.services['core.auth'].getUser() + + let includes = user ? [{ + model: SurveyUser, + required: false, + where: { + user_id: user.id, + } + }] : [] + + console.log("INCLUDES", includes) + + + ctx.models.survey = await Survey.findOne({ + where: { + id, + expires_at: { + [Sequelize.Op.gt]: moment.utc().toISOString() + }, + published_at: { + [Sequelize.Op.lt]: moment.utc().toISOString() + }, + public: true, + }, + include: includes + }) + + console.log(ctx.models.survey) + + return await next() +} diff --git a/src/http/routers/routes_v2.js b/src/http/routers/routes_v2.js new file mode 100644 index 0000000000000000000000000000000000000000..fc6db7be393b145036e43450caeab180fad6e7b6 --- /dev/null +++ b/src/http/routers/routes_v2.js @@ -0,0 +1,115 @@ +const Router = require('@koa/router') +const { apiMiddlewareGroup } = require('../middleware/groups') +const router = new Router({ prefix: '/v2' }) + +const controller = (path, handler) => require(`../controllers/${path}`)[handler] +const param = name => require(`../params/${name}`) +const { env, config } = require('bootstrap') + +apiMiddlewareGroup.forEach(middleware => router.use(middleware)) + +const noop = ctx => + (ctx.body = { + body: ctx.request.body, + headers: ctx.request.headers, + path: ctx.path, + query: ctx.query, + }) + +router.get( + '/', + ctx => + (ctx.body = { + name: 'Jetsam Data API', + prefix: ctx.path, + }), +) + +router.post('/auth/login', controller('api/auth', 'login')) +router.post('/auth/register', controller('api/auth', 'register')) +router.post( + '/auth/password-reset', + controller('api/auth', 'triggerPasswordReset'), +) + +router.get('/self', controller('api/user', 'self')) +router.get('/self/surveys', controller('api/v2/surveys', 'joined')) +router.get('/self/bundles', controller('api/app', 'getBundles')) +router.put('/self/:property', controller('api/user', 'updateOne')) + +router.get('/metrics', controller('api/content', 'getWithin')) +router.post('/metrics', controller('api/content', 'postMetric')) + +router.get('/images', noop) +router.post('/images', noop) +router.post('/images/:imageId/share', noop) + +router.get('/uploads', noop) +router.post('/uploads', controller('api/v2/uploads', 'createUpload')) +router.get('/uploads/:upload_id', noop) +router.delete('/uploads/:upload_id', noop) +router.put('/uploads/:upload_id/:property', noop) + +router.param('survey', param('survey')) + +router.get('/surveys', controller('api/v2/surveys', 'list')) +router.get('/surveys/:survey', controller('api/v2/surveys', 'get')) +router.post('/surveys/:survey/membership', controller('api/v2/surveys', 'join')) +router.delete('/surveys/:survey/membership', controller('api/v2/surveys', 'leave')) +if (config('app.dev')) { + router.post('/surveys/factory', controller('api/v2/factories', 'survey')) +} + +router.post('/an/ev', controller('api/analytics', 'track')) + +// api.post('/metrics', controller('api/content', 'postMetric')) +// api.get('/metrics', controller('api/content', 'getWithin')) +// +// api.get('/images', controller('api/storage', 'getFiles')) +// api.post( +// '/images', +// upload.single('featured_image'), +// controller('api/storage', 'saveFile'), +// ) +// api.post('/images/:imageId/feature', controller('api/storage', 'featureImage')) +// +// /** @deprecated */ +// api.post( +// '/feature', +// upload.single('featured_image'), +// controller('api/storage', 'saveFile'), +// ) +// +// api.get('/feed', controller('api/storage', 'feed')) +// api.post('/feed/:fileId/like', controller('api/storage', 'like')) +// api.post('/feed/:fileId/unlike', controller('api/storage', 'unlike')) +// +// api.post('/register', controller('api/auth', 'register')) +// api.post('/login', controller('api/auth', 'login')) +// +// api.post('/auth/reset-token', controller('api/auth', 'triggerPasswordReset')) +// api.post('/auth/reset-password', controller('api/auth', 'handlePasswordReset')) +// +// api.param('oauthClientId', param('oauth_client')) +// +// api.get('/oauth/clients', controller('api/oauth', 'listClients')) +// api.post('/oauth/clients', controller('api/oauth', 'createClient')) +// api.post( +// '/oauth/clients/:oauthClientId/redirects', +// controller('api/oauth', 'addClientRedirect'), +// ) +// api.delete( +// '/oauth/clients/:oauthClientId/redirects', +// controller('api/oauth', 'removeClientRedirect'), +// ) +// +// api.get('/self', controller('api/user', 'self')) +// api.get('/self/bundles', controller('api/app', 'getBundles')) +// api.put('/self/:property', controller('api/user', 'updateOne')) +// +// api.post('/an/id', async ctx => {}) +// api.post('/an/ev', controller('api/analytics', 'track')) +// +// api.post('/feedback', controller('api/feedback', 'send')) + +module.exports = router diff --git a/src/http/routes.js b/src/http/routes.js index db1b7ceef2f3edf3cfeea732e6f57f87fb50b424..f268250e40587a65367a59ed96462775360e14dd 100644 --- a/src/http/routes.js +++ b/src/http/routes.js @@ -1,5 +1,5 @@ -const controller = (name, method) => require(`./controllers/${ name }`)[method] -const param = (name) => require(`./params/${ name }`) +const controller = (name, method) => require(`./controllers/${name}`)[method] +const param = name => require(`./params/${name}`) const AuthServer = require('domain/auth/AuthServer') const { env, config } = require('bootstrap') @@ -7,6 +7,7 @@ const { env, config } = require('bootstrap') const Router = require('@koa/router') const multer = require('@koa/multer') const upload = multer({ dest: '/tmp/' }) +const attach = require('koa-mount') const context = require('http/middleware/ThreadContextWrapper') const errors = require('http/middleware/ErrorHandler') @@ -14,6 +15,10 @@ const includes = require('http/middleware/ParseIncludes') const profiling = require('http/middleware/Profiler') const loaders = require('http/middleware/MountLoaders') const userGate = require('http/middleware/RequiresAuth') +const authRedirect = require('http/middleware/RedirectToLogin') +const device = require('http/middleware/DeviceProperties').extractDevice + +const v2 = require('./routers/routes_v2') const well_known = new Router({ prefix: '/.well-known' }) well_known.get('wk.jwks', '/jwks.json', async ctx => { @@ -26,48 +31,53 @@ well_known.get('wk.jwks', '/jwks.json', async ctx => { ctx.set('Cache-Control', `public, max-age=30`) ctx.body = { - keys: [{ - use: 'sig', - ...jwk, - alg: 'RS256', - }], + keys: [ + { + use: 'sig', + ...jwk, + alg: 'RS256', + }, + ], } }) const web = new Router() web.use(profiling) +web.use(device) web.use(well_known.allowedMethods()) web.use(well_known.routes()) -web.get('/login', ctx => { - const data = {} - if (ctx.query.login_state) { - data.login_state = ctx.query.login_state - } - return ctx.render('auth/login', data) -}) +web.get('/login', controller('auth', 'showLogin')) web.post('/login', controller('auth', 'login')) +web.get('/logout', controller('auth', 'logout')) web.get('/reset-password', controller('auth', 'resetPassword')) web.post('/reset-password', controller('auth', 'handleResetPassword')) -web.get('/auth/authorize', AuthServer.authorize) +web.get('/auth/authorize', authRedirect, AuthServer.authorize) web.post('/auth/authorize', AuthServer.authorize) web.post('/auth/token', AuthServer.token) - -;(env('FS_DRIVER', 'local') === 'local') && (function() { - const debug = require('debug')('server:routes') - debug('Mounting local file upload routes for signed URLs') - const p = `${ config('fs.url') }/:uid/:fid` - - web.put(p, errors, includes, loaders, userGate, upload.single('file'), controller('fs_local', 'uploadFile')) - web.get(p, errors, includes, loaders, controller('fs_local', 'serveFile')) - - debug(`Mounted GET ${ p } to serve local files`) - debug(`Mounted PUT ${ p } to upload local files`) -}()) - +env('FS_DRIVER', 'local') === 'local' && + (function () { + const debug = require('debug')('server:routes') + debug('Mounting local file upload routes for signed URLs') + const p = `${config('fs.url')}/:uid/:fid` + + web.put( + p, + errors, + includes, + loaders, + userGate, + upload.single('file'), + controller('fs_local', 'uploadFile'), + ) + web.get(p, errors, includes, loaders, controller('fs_local', 'serveFile')) + + debug(`Mounted GET ${p} to serve local files`) + debug(`Mounted PUT ${p} to upload local files`) + })() const apiRouter = new Router({ prefix: '/api' }) const apiLegacy = new Router({ prefix: '/api/api' }) @@ -78,50 +88,76 @@ function mount(api) { api.use(errors) api.use(includes) api.use(loaders) + api.use(device) api.get('/', ctx => { const pkg = require('../../package.json') ctx.body = { name: 'Jetsam Data API', version: pkg.version, + prefix: ctx.path, } }) - api.post('/metrics', controller('api/content', 'postMetric')) api.get('/metrics', controller('api/content', 'getWithin')) api.get('/images', controller('api/storage', 'getFiles')) - api.post('/images', upload.single('featured_image'), controller('api/storage', 'saveFile')) - api.post('/images/:imageId/feature', controller('api/storage', 'featureImage')) + api.post( + '/images', + upload.single('featured_image'), + controller('api/storage', 'saveFile'), + ) + api.post( + '/images/:imageId/feature', + controller('api/storage', 'featureImage'), + ) /** @deprecated */ - api.post('/feature', upload.single('featured_image'), controller('api/storage', 'saveFile')) + api.post( + '/feature', + upload.single('featured_image'), + controller('api/storage', 'saveFile'), + ) api.get('/feed', controller('api/storage', 'feed')) - api.post('/feed/:fileId/like',controller('api/storage', 'like')) + api.post('/feed/:fileId/like', controller('api/storage', 'like')) api.post('/feed/:fileId/unlike', controller('api/storage', 'unlike')) api.post('/register', controller('api/auth', 'register')) api.post('/login', controller('api/auth', 'login')) api.post('/auth/reset-token', controller('api/auth', 'triggerPasswordReset')) - api.post('/auth/reset-password', controller('api/auth', 'handlePasswordReset')) + api.post( + '/auth/reset-password', + controller('api/auth', 'handlePasswordReset'), + ) api.param('oauthClientId', param('oauth_client')) api.get('/oauth/clients', controller('api/oauth', 'listClients')) api.post('/oauth/clients', controller('api/oauth', 'createClient')) - api.post('/oauth/clients/:oauthClientId/redirects', controller('api/oauth', 'addClientRedirect')) - api.delete('/oauth/clients/:oauthClientId/redirects', controller('api/oauth', 'removeClientRedirect')) + api.post( + '/oauth/clients/:oauthClientId/redirects', + controller('api/oauth', 'addClientRedirect'), + ) + api.delete( + '/oauth/clients/:oauthClientId/redirects', + controller('api/oauth', 'removeClientRedirect'), + ) api.get('/self', controller('api/user', 'self')) api.get('/self/bundles', controller('api/app', 'getBundles')) api.put('/self/:property', controller('api/user', 'updateOne')) + api.post('/an/id', async ctx => {}) + api.post('/an/ev', controller('api/analytics', 'track')) + api.post('/feedback', controller('api/feedback', 'send')) -} + api.use(v2.allowedMethods()) + api.use(v2.routes()) +} mount(apiRouter) mount(apiLegacy) diff --git a/src/http/validators.js b/src/http/validators.js index ea857a51e2069d7f400362810499332204a4d496..82ac43ba5efa41a0d307f1fe520808a166e97aaf 100644 --- a/src/http/validators.js +++ b/src/http/validators.js @@ -7,24 +7,20 @@ exports.validator = name => async (ctx, next) => { const { value, error } = await schema.validate(ctx.request.body) if (error instanceof ValidationError) { - throw new InputValidationError(error.details.map(detail => ({ - field: detail.path.join('.'), - type: detail.type, - path: detail.path, - }))) + throw new InputValidationError( + error.details.map(detail => ({ + field: detail.path.join('.'), + type: detail.type, + path: detail.path, + })), + ) } return await next() } exports.newEvent = Joi.object({ - name: Joi.string() - .required(), - tags: Joi.array() - .items(Joi.string()) - .unique() - .required(), - location: Joi.string() - .valid('online', 'physical') - .required(), -}) \ No newline at end of file + name: Joi.string().required(), + tags: Joi.array().items(Joi.string()).unique().required(), + location: Joi.string().valid('online', 'physical').required(), +}) diff --git a/src/services/cache/interface.js b/src/services/cache/interface.js index 3ea3f6b8862c1863bf3657e7740b5d7768cceb75..b06ce3ff6d8d8099930dc731076aa550f8d57ecd 100644 --- a/src/services/cache/interface.js +++ b/src/services/cache/interface.js @@ -2,10 +2,18 @@ const { notImplemented } = require('services/utils') const { Model } = require('sequelize') module.exports = class Cache { - get() { notImplemented('cache', 'get') } - set() { notImplemented('cache', 'set') } - remember() { notImplemented('cache', 'remember') } - clear() { notImplemented('cache', 'clear') } + get() { + notImplemented('cache', 'get') + } + set() { + notImplemented('cache', 'set') + } + remember() { + notImplemented('cache', 'remember') + } + clear() { + notImplemented('cache', 'clear') + } serialize(data) { if (Array.isArray(data)) { @@ -46,7 +54,11 @@ module.exports = class Cache { } // Enable for Sequelize model support // - if (hydrated != null && typeof hydrated === 'object' && '$$_modelName' in hydrated) { + if ( + hydrated != null && + typeof hydrated === 'object' && + '$$_modelName' in hydrated + ) { return this.deserializeModel(hydrated) } return this.deserializeObject(hydrated) @@ -69,9 +81,10 @@ module.exports = class Cache { deserializeObject(object) { if (object != null && object.hasOwnProperty('expiresAt')) { - object = Object.assign({}, object, { data: this.deserialize(object.data) }) + object = Object.assign({}, object, { + data: this.deserialize(object.data), + }) } return object } - } diff --git a/src/services/cache/memory.js b/src/services/cache/memory.js index b76f5e151e3b8c051ebf88a319bbd37d484953b5..1d177b833f6b23ba965c033dc20476f916e6f26f 100644 --- a/src/services/cache/memory.js +++ b/src/services/cache/memory.js @@ -9,11 +9,15 @@ class MemoryCache extends Cache { } _generateKey(key) { - return `${ config('cache.prefix') }:${ key }` + return `${config('cache.prefix')}:${key}` } - get(key) { return this.deserialize(this._cache.get(key)) } - set(key, value) { this._cache.set(key, this.serialize(value)) } + get(key) { + return this.deserialize(this._cache.get(key)) + } + set(key, value) { + this._cache.set(key, this.serialize(value)) + } async remember(key, forS, fn) { let value = null if (this._cache.has(key)) { @@ -28,14 +32,18 @@ class MemoryCache extends Cache { if (value == null) { value = await fn() - const payload = { expiresAt: moment.utc().add(forS, 'seconds').toISOString(), data: value } + const payload = { + expiresAt: moment.utc().add(forS, 'seconds').toISOString(), + data: value, + } await this.set(key, payload) } return value } - clear(key) { this._cache.delete(key) } - + clear(key) { + this._cache.delete(key) + } } module.exports = new MemoryCache() diff --git a/src/services/cache/null.js b/src/services/cache/null.js index 1d0bac2ce385cb5e730495069191856f1cebbcaa..e79e7f96b3ee57d6806b85f2a1d522f6e5667e37 100644 --- a/src/services/cache/null.js +++ b/src/services/cache/null.js @@ -1,10 +1,18 @@ const Cache = require('./interface') class NullCache extends Cache { - get() { /* noop */ } - set() { /* noop */ } - remember(_, __, fn) { return fn() } - clear() { /* noop */ } + get() { + /* noop */ + } + set() { + /* noop */ + } + remember(_, __, fn) { + return fn() + } + clear() { + /* noop */ + } } module.exports = new NullCache() diff --git a/src/services/cache/redis.js b/src/services/cache/redis.js index d7bdc34403812f817f33ae75e1c8e85b12744379..c2f786379cec4be938692c40351abec0dbef2703 100644 --- a/src/services/cache/redis.js +++ b/src/services/cache/redis.js @@ -13,11 +13,10 @@ class RedisCache extends Cache { debug('Connecting to redis server %s', this._dsn) const ioredis = require('ioredis') this._client = new ioredis(this._dsn) - } _generateKey(key) { - return `${ this._prefix }:${ key }` + return `${this._prefix}:${key}` } async get(key) { @@ -28,7 +27,12 @@ class RedisCache extends Cache { async set(key, value, ttl = null) { if (ttl) { debug('Setting value %s for %s. Will expire in %d', value, key, ttl) - return this._client.set(this._generateKey(key), this.serialize(value), 'ex', ttl) + return this._client.set( + this._generateKey(key), + this.serialize(value), + 'ex', + ttl, + ) } else { debug('Setting value %s for %s', value, key) return this._client.set(this._generateKey(key), this.serialize(value)) @@ -52,7 +56,6 @@ class RedisCache extends Cache { debug('Clearing value for %s', key) return this._client.del(this._generateKey(key)) } - } module.exports = new RedisCache() diff --git a/src/services/fs/gcs.js b/src/services/fs/gcs.js index 8746df8f7d7421c39de48ffdf89da522b4e6a4f5..dba7eb2bf82190d7a1d6fda1696f6f2ae17474af 100644 --- a/src/services/fs/gcs.js +++ b/src/services/fs/gcs.js @@ -7,7 +7,7 @@ const log = require('debug')('server:services:gcs') const FS = require('./interface') const { fs, config } = require('bootstrap') -const {fromBase64} = require('core/utils/crypto') +const { fromBase64 } = require('core/utils/crypto') /** * @type GCSFS @@ -19,17 +19,19 @@ const {fromBase64} = require('core/utils/crypto') */ class GCSFS extends FS { constructor() { - super(); + super() this.bucketname = config('fs.bucket') this.path = config('fs.path') this.credentials = config('fs.credentials') if (this.path != null) { - log(`Created GCS FS with credentials from ${ this.path }`) + log(`Created GCS FS with credentials from ${this.path}`) this.storage = new Storage({ keyFilename: this.path }) } else if (this.credentials != null) { log(`Created GCS FS with base 64 credentials from environment`) - this.storage = new Storage({ credentials: JSON.parse(fromBase64(this.credentials)) }) + this.storage = new Storage({ + credentials: JSON.parse(fromBase64(this.credentials)), + }) } else { log(`Created GCS FS without specifying credentials`) this.storage = new Storage() @@ -64,9 +66,10 @@ class GCSFS extends FS { return files } async createUploadUrl(path, ttl, opts) { + const ttl_ms = ttl * 1000 const gopts = { version: 'v4', - expires: Date.now() + (ttl * 1000), + expires: Date.now() + ttl_ms, action: 'write', contentType: getContentType(opts.headers ?? {}) ?? opts.contentType, } @@ -77,13 +80,15 @@ class GCSFS extends FS { url, expires_at_ms: gopts.expires, method: 'PUT', - headers: opts.headers ? { 'Content-Type': getContentType(opts.headers) ?? opts.contentType } : {}, + headers: { + 'Content-Type': gopts.contentType, + }, } } async createDownloadUrl(path, ttl, opts) { const gopts = { version: 'v4', - expires: Date.now() + (ttl * 1000), + expires: Date.now() + ttl * 1000, action: 'read', } @@ -97,11 +102,15 @@ class GCSFS extends FS { } } async getPublicUrl(path, opts) { - return `https://storage.googleapis.com/${ this.bucketname }/${ path }` + return `https://storage.googleapis.com/${this.bucketname}/${path}` } - async makePublic(path, opts) { return this.bucket.file(path).makePublic() } - async makePrivate(path, opts) { return this.bucket.file(path).makePrivate() } + async makePublic(path, opts) { + return this.bucket.file(path).makePublic() + } + async makePrivate(path, opts) { + return this.bucket.file(path).makePrivate() + } getTmpFilename() { return fs.dir(fs.path(os.tmpdir(), 'hf')).path(uuid()) @@ -115,9 +124,12 @@ class GCSFS extends FS { } function getContentType(obj) { - return obj.headers?.['Content-Type'] ?? - obj.headers?.['content-type'] ?? - obj.headers?.contentType + return ( + obj?.headers?.['Content-Type'] ?? + obj?.headers?.['content-type'] ?? + obj?.headers?.contentType ?? + null + ) } -module.exports = new GCSFS() \ No newline at end of file +module.exports = new GCSFS() diff --git a/src/services/fs/interface.js b/src/services/fs/interface.js index 8750a3571c0ad076a04e20170ffaae2b05f15b70..6eb25003ad523a109311fce35bb652cc315f5d73 100644 --- a/src/services/fs/interface.js +++ b/src/services/fs/interface.js @@ -1,17 +1,33 @@ const { notImplemented } = require('services/utils') module.exports = class FS { - async write(path, contents, opts) { notImplemented('fs', 'write') } + async write(path, contents, opts) { + notImplemented('fs', 'write') + } async writeAll(fds, opts) { for (const fd of fds) { await this.write(fd.path, fd.contents, opts) } } - async read(path, opts) { notImplemented('fs', 'read') } - async list(path, opts) { notImplemented('fs', 'list') } - async createUploadUrl(path, ttl, opts) { notImplemented('fs', 'createUploadUrl') } - async createDownloadUrl(path, ttl, opts) { notImplemented('fs', 'createDownloadUrl') } - async getPublicUrl(path, opts) { notImplemented('fs', 'getPublicUrl') } - async makePublic(path, opts) { notImplemented('fs', 'makePublic') } - async makePrivate(path, opts) { notImplemented('fs', 'makePrivate') } + async read(path, opts) { + notImplemented('fs', 'read') + } + async list(path, opts) { + notImplemented('fs', 'list') + } + async createUploadUrl(path, ttl, opts) { + notImplemented('fs', 'createUploadUrl') + } + async createDownloadUrl(path, ttl, opts) { + notImplemented('fs', 'createDownloadUrl') + } + async getPublicUrl(path, opts) { + notImplemented('fs', 'getPublicUrl') + } + async makePublic(path, opts) { + notImplemented('fs', 'makePublic') + } + async makePrivate(path, opts) { + notImplemented('fs', 'makePrivate') + } } diff --git a/src/services/fs/local.js b/src/services/fs/local.js index 4a8ea7164ebdd8a59531e01eb7ef8903cb6ccc71..33e2be03f91d9db9a7b822b2f9183a8b1b0c3c7b 100644 --- a/src/services/fs/local.js +++ b/src/services/fs/local.js @@ -5,7 +5,7 @@ const pathUtil = require('path') class LocalFS extends FS { constructor() { - super(); + super() this.base = fs.path(config('fs.root')) this.urlRoot = fs.path(config('fs.url')) } @@ -28,29 +28,41 @@ class LocalFS extends FS { return await fs.inspectTreeAsync(filePath, opts) } async createUploadUrl(path, ttl, opts) { - const url = new URL(pathUtil.normalize(this.urlRoot + '/' + path), config('app.host.web')) + const url = new URL( + pathUtil.normalize(this.urlRoot + '/' + path), + config('app.host.web'), + ) return { url, - expires_at_ms: Date.now() + (ttl * 1000), + expires_at_ms: Date.now() + ttl * 1000, method: 'PUT', headers: opts.headers ?? {}, } } async createDownloadUrl(path, ttl, opts) { - const url = new URL(pathUtil.normalize(this.urlRoot + '/' + path), config('app.host.web')) + const url = new URL( + pathUtil.normalize(this.urlRoot + '/' + path), + config('app.host.web'), + ) return { url, - expires_at_ms: Date.now() + (ttl * 1000), + expires_at_ms: Date.now() + ttl * 1000, method: 'GET', headers: opts.headers ?? {}, } } async getPublicUrl(path, opts) { - return new URL(pathUtil.normalize(this.urlRoot + '/' + path), config('app.host.web')).toString() - + return new URL( + pathUtil.normalize(this.urlRoot + '/' + path), + config('app.host.web'), + ).toString() + } + async makePublic(path, opts) { + return true + } + async makePrivate(path, opts) { + return true } - async makePublic(path, opts) { return true } - async makePrivate(path, opts) { return true } } -module.exports = new LocalFS() \ No newline at end of file +module.exports = new LocalFS() diff --git a/src/services/index.js b/src/services/index.js index 8592613c6a50ff0ce4fbe4eb3b7184dd84634a64..bd3a963ed6aaeda939cc317a85c665c9ba85deb2 100644 --- a/src/services/index.js +++ b/src/services/index.js @@ -10,10 +10,12 @@ const SERVICES = [ const services = {} -SERVICES.forEach(([name, env, fallback]) => Object.defineProperty(services, name, { - get() { - return loadEnvService(name, env, fallback) - }, -})) +SERVICES.forEach(([name, env, fallback]) => + Object.defineProperty(services, name, { + get() { + return loadEnvService(name, env, fallback) + }, + }), +) module.exports = services diff --git a/src/services/mail/interface.js b/src/services/mail/interface.js index 3bce2d96aeb46215553127005b188fdab4255eab..dccb63645cf4d4f0b87ff84614e4466758434419 100644 --- a/src/services/mail/interface.js +++ b/src/services/mail/interface.js @@ -10,14 +10,21 @@ module.exports = class Mail { return this._renderer } - get fromAddress() { return config('mail.from') } - get replyAddress() { return config('mail.replyto') } + get fromAddress() { + return config('mail.from') + } + get replyAddress() { + return config('mail.replyto') + } - sendTo() { notImplemented('Mail', 'sendTo') } - send(view, to, subject, data = {}, cc = [], bcc = []) { notImplemented('Mail', 'send') } + sendTo() { + notImplemented('Mail', 'sendTo') + } + send(view, to, subject, data = {}, cc = [], bcc = []) { + notImplemented('Mail', 'send') + } sendTemplate(to, subject, templateId, data, opts) { - const templatePath = `templates/sg/${ templateId }` + const templatePath = `templates/sg/${templateId}` return this.send(templatePath, to, subject, data) } } - diff --git a/src/services/mail/log.js b/src/services/mail/log.js index 2ba3205f067642cc9d6a93e1bb46367692ee9a21..12d564e6b09d6c76ff852c6240e222a46b526051 100644 --- a/src/services/mail/log.js +++ b/src/services/mail/log.js @@ -1,5 +1,7 @@ const log = { - info(...args) { console.log('[Info]', ...args)} + info(...args) { + console.log('[Info]', ...args) + }, } const Mail = require('./interface') @@ -12,23 +14,18 @@ class LogMailer extends Mail { async send(view, to, subject, data = {}, cc = [], bcc = []) { // const paths = await getMailerPaths(view) + log.info('[Mailer]', `To: [${to}]`, subject) + log.info('[Mailer]', `CC: [${cc.join(', ')}]`, `BCC: [${bcc.join(', ')}]`) log.info( '[Mailer]', - `To: [${ to }]`, - subject - ) - log.info( - '[Mailer]', - `CC: [${ cc.join(', ') }]`, - `BCC: [${ bcc.join(', ') }]` + `From: [${this.fromAddress}]`, + `Reply To: [${this.replyAddress}]`, ) + // log.info('[Mailer] Text:', paths.text ? await this.renderer.render(paths.text, data) : 'null') log.info( - '[Mailer]', - `From: [${ this.fromAddress }]`, - `Reply To: [${ this.replyAddress }]` + '[Mailer] Html:', + view ? await this.renderer.render(view, data) : 'null', ) - // log.info('[Mailer] Text:', paths.text ? await this.renderer.render(paths.text, data) : 'null') - log.info('[Mailer] Html:', view ? await this.renderer.render(view, data) : 'null') } } diff --git a/src/services/mail/postmark.js b/src/services/mail/postmark.js new file mode 100644 index 0000000000000000000000000000000000000000..7171d32321b336afb00d81e734e2705674f1fdf6 --- /dev/null +++ b/src/services/mail/postmark.js @@ -0,0 +1,82 @@ +const postmark = require('postmark') +const Mail = require('./interface') +const { config } = require('bootstrap') + +class PostmarkMailer extends Mail { + constructor() { + super() + const key = config('mail.key') + this.mailer = new postmark.ServerClient(key) + } + + async sendTo(options) { + const renderer = this.renderer + + const data = Object.assign( + { + meta: { + subject: options.subject, + }, + }, + options.data, + ) + + const value = await renderer.render(options.htmlView, data) + + const message = { + To: options.to, // 'test@blackhole.postmarkapp.com', // options.to, + From: options.from, + // fromName: options.name, + Subject: options.subject, + // replyTo: options.replyto, + TextBody: value, + HtmlBody: value, + // cc: options.cc, + // bcc: options.bcc, + MessageStream: 'outbound', + } + + return this.mailer.sendEmail(message) + } + + async send(view, to, subject, data = {}, cc = [], bcc = []) { + // const paths = await getMailerPaths(view) + // if (paths.html == null || paths.text == null) { + // throw new InvalidMailerPathError(view) + // } + + return this.sendTo({ + to, + from: this.fromAddress, + subject, + name: config('mail.name'), + replyto: this.replyAddress, + textView: view, + htmlView: view, + cc, + bcc, + data, + }) + } + + async sendTemplate(to, subject, templateId, data = {}, opts = {}) { + // const baseOpts = config('mail.opts') + + await this.mailer.sendEmailWithTemplate({ + // ...baseOpts, + ...opts, + To: to, + From: opts.from ?? this.fromAddress, + TemplateId: templateId, + TemplateModel: { + product_name: 'Jetsam', + product_url: 'https://jetsam.tech', + company_name: 'Jetsam Tech Ltd', + subject, + ...data, + }, + }) + } +} + +module.exports = new PostmarkMailer() diff --git a/src/services/mail/sendgrid.js b/src/services/mail/sendgrid.js index 80b4ac00add710a02be448c22ee8596fc8f2b109..9156087925a6877cc9676709fdb13ae368a01304 100644 --- a/src/services/mail/sendgrid.js +++ b/src/services/mail/sendgrid.js @@ -12,11 +12,14 @@ class SendgridMailer extends Mail { async sendTo(options) { const renderer = this.renderer - const data = Object.assign({ - meta: { - subject: options.subject, + const data = Object.assign( + { + meta: { + subject: options.subject, + }, }, - }, options.data) + options.data, + ) const value = await renderer.render(options.htmlView, data) diff --git a/src/services/mail/smtp.js b/src/services/mail/smtp.js index c05b1120e2bda295dcc14f2b490ed50193b7aedc..f320fa36d1055ea6458e0bbd54b9a88b9a278a5b 100644 --- a/src/services/mail/smtp.js +++ b/src/services/mail/smtp.js @@ -21,25 +21,34 @@ class SmtpMailer extends Mail { async sendTo(options) { const renderer = this.renderer - const data = Object.assign({ - meta: { - subject: options.subject, + const data = Object.assign( + { + meta: { + subject: options.subject, + }, }, - }, options.data) + options.data, + ) const value = await renderer.render(options.htmlView, data) if (Array.isArray(options.to)) { - return Promise.all(options.to.map(to => this.transport.sendMail({ - to, - from: options.from, - subject: options.subject, - replyTo: options.replyto, - text: value, - html: value, - cc: options.cc, - bcc: options.bcc, - }).catch(e => e))) + return Promise.all( + options.to.map(to => + this.transport + .sendMail({ + to, + from: options.from, + subject: options.subject, + replyTo: options.replyto, + text: value, + html: value, + cc: options.cc, + bcc: options.bcc, + }) + .catch(e => e), + ), + ) } const message = { diff --git a/src/services/queue/amqp.js b/src/services/queue/amqp.js index f543de9946916b743584277ad2e473fdc4c47329..5f4268ef7ec89ad4212c9022c1d6d26bc33ddc15 100644 --- a/src/services/queue/amqp.js +++ b/src/services/queue/amqp.js @@ -10,12 +10,19 @@ class AmqpQueue extends Queue { constructor() { super() const conf = config('queue') - const params = { - protocol: conf.secure ? 'amqps' : 'amqp', - host: conf.host, - port: conf.port, - username: conf.user, - password: conf.pass, + let params = conf.url + + if (params == null) { + params = { + protocol: conf.secure ? 'amqps' : 'amqp', + host: conf.host, + port: conf.port, + username: conf.user, + password: conf.pass, + } + if (conf.vhost) { + params.vhost = conf.vhost + } } this._init = amqplib.connect(params) @@ -26,31 +33,41 @@ class AmqpQueue extends Queue { this.dlq = 'jetsam.jobs.dlq' this._handlers = {} - this._init.then(q => { - debug('Established connection to AMQP queue') - this._amqp = q - }).catch(e => { - debug('Failed to connect to AMQP queue') - console.error(e) - }) + this._init + .then(q => { + debug('Established connection to AMQP queue') + this._amqp = q + }) + .catch(e => { + debug('Failed to connect to AMQP queue') + console.error(e) + }) } bind(jobname, handler) { this._handlers[jobname] = handler } dispatch(jobname, payload, attempt = 0) { - return threadContext.profile('queue.dispatch', jobname, () => this.dispatchAfter(jobname, payload, 0, attempt)) + return threadContext.profile('queue.dispatch', jobname, () => + this.dispatchAfter(jobname, payload, 0, attempt), + ) } dispatchAfter(jobname, payload, delay, attempt = 0) { return this._initialise().then(() => { - debug(`Processing job ${ jobname } via AMQP connection`) - - this._channel.publish(this._exchange, 'jobs', Buffer.from(JSON.stringify({ - type: jobname, - payload, - delay, - attempt, - }))) + debug(`Processing job ${jobname} via AMQP connection`) + + this._channel.publish( + this._exchange, + 'jobs', + Buffer.from( + JSON.stringify({ + type: jobname, + payload, + delay, + attempt, + }), + ), + ) }) } @@ -67,7 +84,7 @@ class AmqpQueue extends Queue { debug('Starting Trace') threadContext.getTransaction({ op: 'queue.job', - name: 'AMQP Queue Handler' + name: 'AMQP Queue Handler', }) await this._handleMessage(object) } finally { @@ -78,9 +95,10 @@ class AmqpQueue extends Queue { }) }) - return () => this._init.then(q => { - q.close() - }) + return () => + this._init.then(q => { + q.close() + }) } async _handleMessage(object) { @@ -95,40 +113,46 @@ class AmqpQueue extends Queue { t.setData('job.attempt', attempt) t.setData('job.body', body) - if (!this._handlers.hasOwnProperty(type)) { t.setName(`[Q] Unknown`) - debug(`No handler for type ${ type }, discarding message`) + debug(`No handler for type ${type}, discarding message`) await this._channel.ack(object) return } - t.setName(`[Q] ${ type }`) + t.setName(`[Q] ${type}`) - debug(`Processing message ${ type }`) + debug(`Processing message ${type}`) try { const ctx = await ServiceProvider.detached() const handler = this._handlers[type] t.description = handler.name - await threadContext.profile('job.handler', undefined, () => handler(body, ctx)) + await threadContext.profile('job.handler', undefined, () => + handler(body, ctx), + ) await this._channel.ack(object) - debug(`Processed message ${ type }`) + debug(`Processed message ${type}`) } catch (e) { Sentry.withScope(scope => { scope.setContext('job', { type, body, delay, attempt }) Sentry.captureException(e) }) - debug(`Failed message ${ type }`) + debug(`Failed message ${type}`) debug(e) - if (attempt < 5) { + if (attempt < this.conf.retries ?? 5) { const next = attempt + 1 - debug(`Re-queue message ${ type } #${ next }`) - await this._channel.sendToQueue(this.dlq, Buffer.from(JSON.stringify({ - type, - payload: body, - delay, - attempt: next, - }))) + debug(`Re-queue message ${type} #${next}`) + await this._channel.sendToQueue( + this.dlq, + Buffer.from( + JSON.stringify({ + type, + payload: body, + delay, + attempt: next, + }), + ), + ) // await this.dispatchAfter(type, body, next * 500, next) } else { debug('Discarding message') @@ -152,7 +176,7 @@ class AmqpQueue extends Queue { await this._channel.assertQueue(this.dlq, { deadLetterExchange: this._exchange, deadLetterRoutingKey: 'jobs', - messageTtl: 500 + messageTtl: 500, }) } } diff --git a/src/services/queue/async.js b/src/services/queue/async.js index 98186d394710e80547f1635ca5e0ff0b96a6ef4c..8aac842ed9724d0e7e3f8c6d805fe084eba5c2ca 100644 --- a/src/services/queue/async.js +++ b/src/services/queue/async.js @@ -4,7 +4,7 @@ const debug = require('debug')('server:services:queue') class AsyncQueue extends Queue { constructor() { - super(); + super() this._emitter = new EventEmitter() this._buffer = [] this._active = false @@ -18,19 +18,19 @@ class AsyncQueue extends Queue { if (this._active) { this.dispatchAfter(jobname, payload, 0) } else { - debug(`Adding job ${ jobname } to buffer, no queue listener present`) + debug(`Adding job ${jobname} to buffer, no queue listener present`) this._buffer.push({ name: jobname, payload }) } } dispatchAfter(jobname, payload, delay) { if (this._active) { - debug(`Processing job ${ jobname } asynchronously`) + debug(`Processing job ${jobname} asynchronously`) setTimeout(() => { this._emitter.emit(jobname, payload) }, delay) } else { - debug(`Adding job ${ jobname } to buffer, no queue listener present`) + debug(`Adding job ${jobname} to buffer, no queue listener present`) this._buffer.push({ name: jobname, payload, delay }) } } diff --git a/src/services/queue/interface.js b/src/services/queue/interface.js index 909485a877109960873a66e67d381acf8d94d9b1..a8e3c7ab531d514138ac53dfa5ce4b06179cba61 100644 --- a/src/services/queue/interface.js +++ b/src/services/queue/interface.js @@ -1,8 +1,16 @@ const { notImplemented } = require('services/utils') module.exports = class Queue { - bind(jobname, handler) { notImplemented('Queue', 'bind') } - dispatch(jobname, payload) { notImplemented('Queue', 'dispatch') } - dispatchAfter(jobname, payload, delay) { notImplemented('Queue', 'dispatchAfter') } - listen() { notImplemented('Queue', 'listen') } + bind(jobname, handler) { + notImplemented('Queue', 'bind') + } + dispatch(jobname, payload) { + notImplemented('Queue', 'dispatch') + } + dispatchAfter(jobname, payload, delay) { + notImplemented('Queue', 'dispatchAfter') + } + listen() { + notImplemented('Queue', 'listen') + } } diff --git a/src/services/totp/vault.js b/src/services/totp/vault.js index eb2fac397f3d1391df100dd2f0b9ad8ac6869fcd..3baaaf1bfeba5bb653f73665627f33adc358c39c 100644 --- a/src/services/totp/vault.js +++ b/src/services/totp/vault.js @@ -2,7 +2,12 @@ const TotpProvider = require('./interface') const { config } = require('bootstrap') const { URL } = require('url') const threadContext = require('core/injection/ThreadContext') -const { VaultClient, VaultSimpleAuth, VaultKVStore, VaultTOTPStore } = require('@commander-lol/vault-client') +const { + VaultClient, + VaultSimpleAuth, + VaultKVStore, + VaultTOTPStore, +} = require('@commander-lol/vault-client') class VaultTotpProvider extends TotpProvider { constructor() { @@ -17,7 +22,7 @@ class VaultTotpProvider extends TotpProvider { options: { auth: { path: config('vault.auth_path'), - credentials: config('vault.credentials') + credentials: config('vault.credentials'), }, kv: { path: config('vault.kv_path'), @@ -38,7 +43,11 @@ class VaultTotpProvider extends TotpProvider { const email = user.email try { - const { barcode, url } = await this.client.stores.totp.createProvider(id, 'Jetsam', email) + const { barcode, url } = await this.client.stores.totp.createProvider( + id, + 'Jetsam', + email, + ) const parsed = new URL(url) const secret = parsed.searchParams.get('secret') @@ -47,7 +56,7 @@ class VaultTotpProvider extends TotpProvider { url, secret, } - } catch(e) { + } catch (e) { console.error(e) return null } @@ -77,7 +86,9 @@ class VaultTotpProvider extends TotpProvider { const hashes = await Promise.all(codes.map(c => crypto.hash(c))) try { - await this.client.stores.kv.write(`totp_recovery/${ userid }`, { codes: hashes }) + await this.client.stores.kv.write(`totp_recovery/${userid}`, { + codes: hashes, + }) } catch (e) { console.log(e) return null @@ -90,7 +101,7 @@ class VaultTotpProvider extends TotpProvider { let data = null try { - ;({ data } = await this.client.stores.kv.read(`totp_recovery/${ userid }`)) + ;({ data } = await this.client.stores.kv.read(`totp_recovery/${userid}`)) } catch (e) { console.log(e) } @@ -108,7 +119,9 @@ class VaultTotpProvider extends TotpProvider { if (found != null) { const newCodes = codes.filter(c => c !== found) - await this.client.stores.kv.write(`totp_recovery/${ userid }`, { codes: newCodes }) + await this.client.stores.kv.write(`totp_recovery/${userid}`, { + codes: newCodes, + }) return true } } @@ -117,4 +130,4 @@ class VaultTotpProvider extends TotpProvider { } } -module.exports = new VaultTotpProvider() \ No newline at end of file +module.exports = new VaultTotpProvider() diff --git a/src/services/utils.js b/src/services/utils.js index 095c78dec410d754f7577d75df19d67a95bbb53f..6fec15093d262b9e423c2cb373c9c029e16e99f0 100644 --- a/src/services/utils.js +++ b/src/services/utils.js @@ -1,23 +1,33 @@ const { env } = require('bootstrap') const debug = require('debug')('server:services') -exports.loadEnvService = function loadEnvService(serviceName, envName, fallbackName = null) { +exports.loadEnvService = function loadEnvService( + serviceName, + envName, + fallbackName = null, +) { const driverName = env(envName, fallbackName) if (driverName != null) { - const service = require(`./${ serviceName }/${ driverName }`) - const interfaze = require(`./${ serviceName }/interface`) + const service = require(`./${serviceName}/${driverName}`) + const interfaze = require(`./${serviceName}/interface`) - debug('Loading service interface %s for service type %s', driverName, serviceName) + debug( + 'Loading service interface %s for service type %s', + driverName, + serviceName, + ) if (service instanceof interfaze) { return service } - throw new Error(`Bad service implementation; expected ${ serviceName }/${ driverName } to implement interface, but did not`) + throw new Error( + `Bad service implementation; expected ${serviceName}/${driverName} to implement interface, but did not`, + ) } else { return null } } exports.notImplemented = function throwNotImplemented(clazz, methodName) { - throw new Error(`${ clazz } method not implemented: ${ methodName }`) + throw new Error(`${clazz} method not implemented: ${methodName}`) } diff --git a/src/vendor/koa-handlebars.js b/src/vendor/koa-handlebars.js index 89020322c1632288039f1cfa89480ae1c799c1b4..363b9293e19b13afa5c58e348759198cb7c971f1 100644 --- a/src/vendor/koa-handlebars.js +++ b/src/vendor/koa-handlebars.js @@ -4,23 +4,23 @@ const Handlebars = require('handlebars') function createPathsFromContext(context = '', filename) { const { name } = path.parse(filename) - return [ - path.join(context, filename), - path.join(context, name), - name, - ] + return [path.join(context, filename), path.join(context, name), name] } function loadPartials(fsinst, root, ext, debug) { const tree = fsinst.inspectTree(root) if (!tree || (tree.type !== 'dir' && tree.type !== 'file')) { - debug('[koa-handlebars] Partials directory does not exist, skipping partials') + debug( + '[koa-handlebars] Partials directory does not exist, skipping partials', + ) return [] } if (tree.type !== 'dir') { - throw new TypeError(`[koa-handlebars] Partials directory path must point to a directory, found ${ tree.type }`) + throw new TypeError( + `[koa-handlebars] Partials directory path must point to a directory, found ${tree.type}`, + ) } const processing = tree.children @@ -31,15 +31,20 @@ function loadPartials(fsinst, root, ext, debug) { if (current.type === 'dir') { for (const child of current.children) { - child.context = current.context ? path.join(current.context, current.name) : current.name + child.context = current.context + ? path.join(current.context, current.name) + : current.name processing.push(child) } } else if (current.type === 'file') { if (path.extname(current.name) === ext) { - const [pathWithExt, pathWithoutExt] = createPathsFromContext(current.context, current.name) + const [pathWithExt, pathWithoutExt] = createPathsFromContext( + current.context, + current.name, + ) const content = fsinst.read(fsinst.path(root, pathWithExt), 'utf8') - debug(`[koa-mustache] Loading partial ${ pathWithExt }`) + debug(`[koa-mustache] Loading partial ${pathWithExt}`) partials.push({ name: pathWithoutExt, content }) } @@ -50,7 +55,6 @@ function loadPartials(fsinst, root, ext, debug) { } function loadHelpers(fsinst, root, debug) { - const tree = fsinst.inspectTree(root) if (!tree || (tree.type !== 'dir' && tree.type !== 'file')) { @@ -59,29 +63,38 @@ function loadHelpers(fsinst, root, debug) { } if (tree.type !== 'dir') { - throw new TypeError(`[koa-handlebars] Helpers directory path must point to a directory, found ${ tree.type }`) + throw new TypeError( + `[koa-handlebars] Helpers directory path must point to a directory, found ${tree.type}`, + ) } const processing = tree.children const helpers = [] - processing.forEach(p => p.context = fsinst.path(root)) + processing.forEach(p => (p.context = fsinst.path(root))) while (processing.length > 0) { const current = processing.shift() if (current.type === 'dir') { for (const child of current.children) { - child.context = current.context ? path.join(current.context, current.name) : current.name + child.context = current.context + ? path.join(current.context, current.name) + : current.name processing.push(child) } } else if (current.type === 'file') { - const [pathWithExt, _, name ] = createPathsFromContext(current.context, current.name) + const [pathWithExt, _, name] = createPathsFromContext( + current.context, + current.name, + ) try { const helperMap = require(pathWithExt) helpers.push({ name, content: helperMap }) - debug(`[koa-mustache] Loading helper ${ pathWithExt }`) - } catch(e) { console.warn(e.message) } + debug(`[koa-mustache] Loading helper ${pathWithExt}`) + } catch (e) { + console.warn(e.message) + } } } @@ -91,7 +104,11 @@ function loadHelpers(fsinst, root, debug) { module.exports = function createRenderMiddleware(root, opts = {}) { const instance = module.exports.createRenderer(root, opts) return async function handlebarsMiddleware(ctx, next) { - ctx.render = async function renderTemplateData(template, data = {}, opts = {}) { + ctx.render = async function renderTemplateData( + template, + data = {}, + opts = {}, + ) { const content = await instance.render(template, data, opts) if (content == null) { this.status = 404 @@ -123,8 +140,8 @@ class Renderer { if (!template) { let fileData = await viewDir.inspectAsync(path) if (fileData == null) { - path = `${ path }${ this._ext }` - fileData = await viewDir.inspectAsync(`${ view }${ this._ext }`) + path = `${path}${this._ext}` + fileData = await viewDir.inspectAsync(`${view}${this._ext}`) if (fileData == null) { return null } @@ -151,12 +168,14 @@ class Renderer { } } -module.exports.createRenderer = function(root, opts = {}) { - const useCache = opts.hasOwnProperty('cache') ? opts.cache : process.env.NODE_ENV === 'production' +module.exports.createRenderer = function (root, opts = {}) { + const useCache = opts.hasOwnProperty('cache') + ? opts.cache + : process.env.NODE_ENV === 'production' const extension = opts.hasOwnProperty('extension') ? opts.extension : '.hbs' const partials = opts.hasOwnProperty('partials') ? opts.partials : 'partials' const helpers = opts.hasOwnProperty('helpers') ? opts.helpers : 'helpers' - const extend = opts.hasOwnProperty('extend') ? opts.extend : (i) => i + const extend = opts.hasOwnProperty('extend') ? opts.extend : i => i const debug = opts.debug || (() => {}) const fsinst = opts.hasOwnProperty('jetpack') ? opts.jetpack : fs @@ -165,13 +184,17 @@ module.exports.createRenderer = function(root, opts = {}) { const helperContent = loadHelpers(viewDir, helpers, debug) helperContent.forEach(({ name, content }) => - typeof content === 'function' ? - instance.registerHelper(name, content) : - Object.entries(content).forEach(([helper, fn]) => instance.registerHelper(helper, fn)) + typeof content === 'function' + ? instance.registerHelper(name, content) + : Object.entries(content).forEach(([helper, fn]) => + instance.registerHelper(helper, fn), + ), ) const partialContent = loadPartials(viewDir, partials, extension, debug) - partialContent.forEach(({ name, content }) => instance.registerPartial(name, content)) + partialContent.forEach(({ name, content }) => + instance.registerPartial(name, content), + ) extend(instance) diff --git a/src/vendor/sentry.js b/src/vendor/sentry.js index 50a6cacea898596ca4698ddabc2a3a082678b1b6..65441be8da47605d9155ade0ed79818b25b8e045 100644 --- a/src/vendor/sentry.js +++ b/src/vendor/sentry.js @@ -1,24 +1,22 @@ const Sentry = require('@sentry/node') const Tracing = require('@sentry/tracing') -const blockedPaths = new Set([ - '/api/.secure/jwks', - '/api', -]) +const blockedPaths = new Set(['/api/.secure/jwks', '/api', '/api/an/ev']) -exports.configure = function() { +exports.configure = function () { const pkg = require('../../package.json') const { config } = require('bootstrap') Sentry.init({ dsn: config('sentry.dsn'), - integrations: integrations => integrations.filter(itg => itg.name !== 'Console'), + integrations: integrations => + integrations.filter(itg => itg.name !== 'Console'), environment: config('app.env'), - release: `${ pkg.name }@${ pkg.version }`, - tracesSampler: (ctx) => { + release: `${pkg.name}@${pkg.version}`, + tracesSampler: ctx => { if ( - ctx.transactionContext?.op === 'http.request' - && blockedPaths.has(ctx.transactionContext?.tags?.['http.path']) + ctx.transactionContext?.op === 'http.request' && + blockedPaths.has(ctx.transactionContext?.tags?.['http.path']) ) { return 0 } @@ -26,5 +24,34 @@ exports.configure = function() { return config('sentry.samples') }, }) +} -} \ No newline at end of file +async function getUserObject(ctx) { + const user = await ctx.services['core.auth'].getUser() + const ip = ctx.ip + if (user) { + return { ip_address: ip, id: user.id, email: user.email } + } + return { ip_address: ip } +} + +exports.reportContextError = async function reportHttpToSentry(error, ctx) { + let user = await getUserObject(ctx) + + Sentry.withScope(function (scope) { + if (user) { + scope.setUser(user) + } + + scope.setContext('response', ctx.body) + + if (ctx.request.device) { + scope.setContext('device', ctx.request.device) + } + + scope.addEventProcessor(function (event) { + return Sentry.Handlers.parseRequest(event, ctx.request) + }) + Sentry.captureException(error) + }) +} diff --git a/views/auth/accept-oauth.hbs b/views/auth/accept-oauth.hbs index 5b73a73422048a9ef8a18dfd3032cd876192a5ee..7b1433a8d91cb71cc65b70ae4ec36144187c2563 100644 --- a/views/auth/accept-oauth.hbs +++ b/views/auth/accept-oauth.hbs @@ -1,33 +1,55 @@ <!DOCTYPE html> <html lang="en"> - <head> - <meta charset="utf-8"> - <title>Authenticate Your Account</title> - <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"> - </head> +<head> + <title>Authorise {{ client.name }} | Jetsam</title> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <meta name="description" content=""> + <meta name="author" content=""> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"> + <link rel="stylesheet" href="/css/jetsam.css"> - <body class="bg-white rounded-t-lg overflow-hidden border-t border-l border-r border-gray-400 p-4 px-3 py-10 bg-gray-200 flex justify-center"> - <div class="max-w-lg rounded overflow-hidden bg-white shadow"> - {{#if client.meta.name }}<h1 class="p-2 text-xl">{{ client.meta.name }}</h1>{{/if}} - {{#if client.meta.description }}<p class="p-2">{{ client.meta.description }}</p>{{/if}} - <p class="p-2 border-t border-b border-solid border-gray-400"> - {{#if client.meta.name}}{{client.meta.name}}{{else}}An application{{/if}} is requesting access to the following - permissions. Please carefully read what each does before accepting or rejecting this request. Only accept this + <style> + body, body > div { + height: 100%; + } + </style> +</head> +<body> +<div class="bg-jetsam column center-content"> + <div class="row space-1 content"> + <img src="/logo.png" width="75px"> + <h1 class="font-brand text head light">Jetsam</h1> + </div> + <div class="content focus"> + {{#if client.name }}<h1 class="text lg">{{ client.name }} wants to access your Jetsam account</h1>{{/if}} + {{#if client.description }}<p class="vertical-block text md">{{ client.description }}</p>{{/if}} + <p class="vertical-block text md italic"> + {{#if client.name}}{{client.name}}{{else}}An application{{/if}} is requesting access to the following + permissions. Please carefully read what each does before accepting or rejecting this request. Only accept + this request for access if you trust the application. </p> - <ul class="p-2"> - {{#each scopes}} - <li><strong>{{ this.name }}</strong> - {{ this.description }}</li> - {{/each}} + <ul class="vertical-block"> + {{#each scopes}} + <li class="vertical-block"><strong class="text md bold">{{ this.name }}</strong> - {{ this.description }}</li> + {{/each}} </ul> - <div class="flex justify-center"> - <form class="flex-1 flex flex-col justify-center align-stretch" method="post" action="/auth/authorize?action=accept&auth_state={{redirect}}"> - <button type="submit" class="bg-green-500 hover:bg-green-600 text-white shadow hover:shadow-md active:shadow">Accept</button> + <div class="row space-4 center-content"> + <form method="post" + action="/auth/authorize?action=accept&auth_state={{redirect}}"> + <button type="submit" + class="button success">Accept + </button> </form> - <form class="flex-1 flex flex-col justify-center align-stretch" method="post" action="/auth/authorize?action=deny&auth_state={{redirect}}"> - <button type="submit" class="bg-red-500 hover:bg-red-600 text-white shadow hover:shadow-md active:shadow">Reject</button> + <form method="post" + action="/auth/authorize?action=deny&auth_state={{redirect}}"> + <button type="submit" class="button danger"> + Reject + </button> </form> </div> </div> - </body> -</html> \ No newline at end of file +</div> +</body> +</html> diff --git a/views/auth/login-tailwind.hbs b/views/auth/login-tailwind.hbs new file mode 100644 index 0000000000000000000000000000000000000000..b4be939dad495c9c5ba254b6db298f215d952a7e --- /dev/null +++ b/views/auth/login-tailwind.hbs @@ -0,0 +1,86 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <title>Login | Jetsam</title> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <meta name="description" content=""> + <meta name="author" content=""> + <link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&display=swap" rel="stylesheet"> + <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"> + <link rel="icon" type="image/png" sizes="16x16" href="favicon-tailwind.png"> + <script src="js/main.js"></script> + + <style> + body, body > div { + height: 100%; + } + </style> +</head> +<body class="antialiased bg-body text-body font-body"> +<div class=""> + + <section> + <div class="flex flex-wrap"> + <div class="pt-6 lg:pt-16 pb-6 w-full lg:w-1/2"> + <div class="max-w-md mx-auto"> + <div class="mb-6 lg:mb-20 w-full px-3 flex items-center justify-between"> + <a class="text-3xl font-bold leading-none" href="#"> + <img class="h-12" src="atis-assets/logo/atis/atis-mono-black.svg" alt="" width="auto"></a> + <a class="py-2 px-6 text-xs rounded-l-xl rounded-t-xl bg-green-100 hover:bg-green-200 text-green-600 font-bold transition duration-200" + href="#">Sign Up</a> + </div> + <div> + <div class="mb-6 px-3"> + <span class="text-gray-500">Sign In</span> + <h3 class="text-2xl font-bold">Join our community</h3> + </div> + <form action=""> + <div class="mb-3 flex p-4 mx-3 bg-gray-100 rounded"> + <input class="w-full text-xs bg-gray-100 outline-none" type="email" + placeholder="name@email.com"> + </div> + <div class="mb-6 flex p-4 mx-3 bg-gray-100 rounded"> + <input class="w-full text-xs bg-gray-100 outline-none" type="password" + placeholder="Enter your password"> + </div> + <div class="px-3 text-center"> + <button class="mb-4 w-full py-4 bg-pink-400 hover:bg-pink-600 rounded text-sm font-bold text-gray-50 transition duration-200"> + Sign In + </button> + <a class="text-xs text-green-600 hover:underline" href="#">Forgot password?</a> + </div> + </form> + </div> + </div> + </div> + <div class="hidden lg:block relative w-full lg:w-1/2 bg-pink-400"> + <div class="absolute bottom-0 inset-x-0 mx-auto mb-12 max-w-xl text-center" style="z-index: 10;"> + <img class="max-w-xl" src="atis-assets/illustrations/pablo-coming-soon-dark-mono.png" alt=""> + <h2 class="mb-2 text-2xl text-white font-bold">Track Plastics; Make Change Happen</h2> + <div class="max-w-lg mx-auto"> + <p class="mb-6 text-gray-50 leading-loose">Lorem ipsum dolor sit amet, consectetur adipiscing + elit. Pellentesque efficitur nisl sodales egestas lobortis.</p> + </div> + <a class="inline-block py-2 px-6 leading-loose rounded-t-xl rounded-l-xl bg-white hover:bg-gray-500 text-gray-900 hover:text-white transition duration-200 font-bold" + href="#">Get Started</a> + </div> + </div> + <div class="lg:hidden bg-green-600"> + <div class="relative w-full"> + <img class="relative mx-auto max-w-sm mt-4 mb-4 block" + src="atis-assets/illustrations/pablo-coming-soon-dark-mono.png" alt=""> + </div> + <div class="py-10 px-3 text-center" style="z-index: 10;"> + <h2 class="mb-2 text-2xl text-white font-bold">So much more than a business analytics tool</h2> + <p class="mb-6 text-gray-50 leading-loose">Lorem ipsum dolor sit amet, consectetur adipiscing elit. + Pellentesque efficitur nisl sodales egestas lobortis.</p> + <a class="py-2 px-6 leading-loose rounded-t-xl rounded-l-xl rounded-l-xl bg-white hover:bg-gray-500 text-gray-900 hover:text-white transition duration-200 font-bold" + href="#">Get Started</a> + </div> + </div> + </div> + </section> +</div> +</body> +</html> diff --git a/views/auth/login.hbs b/views/auth/login.hbs index 249595d202199330e1f45b63d6161a60b70b7629..e2d1145923d3fe7ea8eee25470e84ac2601926be 100644 --- a/views/auth/login.hbs +++ b/views/auth/login.hbs @@ -1,35 +1,77 @@ <!DOCTYPE html> <html lang="en"> - <head> - <meta charset="utf-8"> - <title>Log In To Your Account</title> - <link href="https://unpkg.com/tailwindcss@^1.0/dist/tailwind.min.css" rel="stylesheet"> - </head> +<head> + <title>Login | Jetsam</title> + <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> + <meta name="description" content=""> + <meta name="author" content=""> + <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"> + <link rel="stylesheet" href="/css/jetsam.css"> - <body class="bg-white rounded-t-lg overflow-hidden border-t border-l border-r border-gray-400 p-4 px-3 py-10 bg-gray-200 flex justify-center"> - <div class="w-full max-w-xs"> - <form class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" method="post" action="/login{{#if login_state}}?login_state={{login_state}}{{/if}}"> - <div class="mb-4"> - <label class="block text-gray-700 text-sm font-bold mb-2" for="username"> - Email - </label> - <input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="email" name="email" placeholder="Email" type="email"> - </div> - <div class="mb-6"> - <label class="block text-gray-700 text-sm font-bold mb-2" for="password"> - Password - </label> - <input class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline" id="password" name="password" type="password" placeholder="Password"> - </div> - <div class="flex items-center justify-between"> - <button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="submit"> - Sign In - </button> -<!-- <a class="inline-block align-baseline font-bold text-sm text-blue-500 hover:text-blue-800" href="#">--> -<!-- Forgot Password?--> -<!-- </a>--> - </div> - </form> - </div> - </body> -</html> \ No newline at end of file + <style> + body, body > div { + height: 100%; + } + </style> +</head> +<body> +<div class="split-container"> + <div class="split-child center-content column space-2"> + <div class="row space-1"> + <img src="/logo.png" width="75px"> + <h1 class="font-brand">Jetsam</h1> + </div> + + <div class="spacer"></div> + + <div class="column space-1"> + <p class="text sm caption subtle"> + Log In + </p> + <p class="text lg bold"> + Join The Community + </p> + </div> + + <form class="form column space-1" method="post" action="/login{{#if state_string}}{{state_string}}{{/if}}"> + <div class="control column"> + <label for="email">Email Address</label> + <input id="email" name="email" type="email" placeholder="Email Address"/> + </div> + <div class="control column"> + <label for="password">Password</label> + <input id="password" name="password" type="password" placeholder="Password"/> + </div> + + <button type="submit" class="button primary"> + Log In + </button> + <div class="row center-content"> + <a href="/reset-password">Forgotten Password?</a> + </div> + </form> + </div> + <div class="split-child bg-jetsam center-content column space-2"> + <img src="/camera.png" width="50%" style="margin-left: auto; margin-right: auto"/> + <p class="text lg bold light center" style="margin-left: auto; margin-right: auto"> + Photograph Plastic; Make Change Happen + </p> + <p class="text light center"> + Download Jetsam on your phone and start snapping pictures of pesky plastics - every photo makes a difference + </p> + <div class="row center-content"> + <a href="https://apps.apple.com/gb/app/jetsam/id1494342033?ls=1"><img height="50" + alt="Download on the App Store" + src="/ios-app-store-badge-2928664fe1fc6aca88583a6f606d60ba.svg" + style="height: 50px;"></a> + <a class="centered" + href="https://play.google.com/store/apps/details?id=tech.jetsam.catalog&pcampaignid=pcampaignidMKT-Other-global-all-co-prtnr-py-PartBadge-Mar2515-1"><img + height="75" alt="Get it on Google Play" + src="https://play.google.com/intl/en_gb/badges/static/images/badges/en_badge_web_generic.png" + style="height: 74px;"></a> + </div> + </div> +</div> +</body> +</html> diff --git a/views/auth/reset-password-error.hbs b/views/auth/reset-password-error.hbs index c4af0693152653c2da9c7d90fd50e90f0174c9b0..b1a54e3c26ff450c5b895495b065fa56d6eeb48e 100644 --- a/views/auth/reset-password-error.hbs +++ b/views/auth/reset-password-error.hbs @@ -12,33 +12,25 @@ <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel="shortcut icon" type="image/png" href="https://jetsam.tech/images/logo.png"> - <link rel="stylesheet" - href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" - integrity="sha256-l85OmPOjvil/SOvVt3HnSSjzF1TUMyT9eV0c2BzEGzU=" - crossorigin="anonymous" /> - <link rel="stylesheet" - href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" - integrity="sha256-2YQRJMXD7pIAPHiXr0s+vlRWA7GYJEK0ARns7k2sbHY=" - crossorigin="anonymous" /> - - <link rel="stylesheet" href="/css/main.css?v=2"> + <link rel="shortcut icon" type="image/png" href="https://app.jetsam.tech/logo.png"> + <link rel="stylesheet" href="/main.css?v=2"> </head> <body> -<main class="container" style="max-width: 600px"> - <header class="header"> - <img class="logo" src="https://jetsam.tech/images/logo.png" width="128px" height="128px"> - <div> - <h1>Jetsam</h1> - <h3>Your World; Cleaner</h3> +<main class="container"> + <div class="inner"> + <div class="row header"> + <img class="logo" src="/logo.png" width="128px" height="128px"> + <div class="text-container"> + <h1>Jetsam</h1> + <h3>Your World; Cleaner</h3> + </div> + </div> + <h3 class="centered">Password Reset Error</h3> + <p class="centered">{{ message }}</p> + <div class="row centered"> + <a href="{{ back_link }}">Go Back</a> </div> - </header> - - <h3 class="centered">Password Reset Error</h3> - <p class="centered">{{ message }}</p> - <div class="row centered"> - <a href="{{ back_link }}">Go Back</a> </div> </main> diff --git a/views/auth/reset-password-success.hbs b/views/auth/reset-password-success.hbs index 16dee630eabb53c88ca82323eef54442adfd270f..304ff98255d15900c05090fe035ff961eb30363d 100644 --- a/views/auth/reset-password-success.hbs +++ b/views/auth/reset-password-success.hbs @@ -12,35 +12,30 @@ <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel="shortcut icon" type="image/png" href="https://jetsam.tech/images/logo.png"> - <link rel="stylesheet" - href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" - integrity="sha256-l85OmPOjvil/SOvVt3HnSSjzF1TUMyT9eV0c2BzEGzU=" - crossorigin="anonymous" /> - <link rel="stylesheet" - href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" - integrity="sha256-2YQRJMXD7pIAPHiXr0s+vlRWA7GYJEK0ARns7k2sbHY=" - crossorigin="anonymous" /> + <link rel="shortcut icon" type="image/png" href="https://app.jetsam.tech/logo.png"> - <link rel="stylesheet" href="/css/main.css?v=2"> + <link rel="stylesheet" href="/main.css?v=2"> </head> <body> -<main class="container" style="max-width: 600px"> - <header class="header"> - <img class="logo" src="https://jetsam.tech/images/logo.png" width="128px" height="128px"> - <div> - <h1>Jetsam</h1> - <h3>Your World; Cleaner</h3> - </div> - </header> - <h3 class="centered">Password Reset Successful</h3> - <p class="centered">You successfully reset your password. You can log in to the Jetsam app with the password you just created. Now go and snap some pesky plastics!</p> - <div class="row centered"> - <a href="https://jetsam.tech">Go to the Jetsam website</a> +<main class="container"> + <div class="inner"> + <div class="row header"> + <img class="logo" src="/logo.png" width="128px" height="128px"> + <div class="text-container"> + <h1>Jetsam</h1> + <h3>Your World; Cleaner</h3> + </div> + </div> + <h3 class="centered">Password Reset Successful</h3> + <p class="centered">You successfully reset your password. You can log in to the Jetsam app with the password you just created. Now go and snap some pesky plastics!</p> + <div class="row centered"> + <a href="https://jetsam.tech">Go to the Jetsam website</a> + </div> </div> </main> </body> </html> + diff --git a/views/auth/reset-password.hbs b/views/auth/reset-password.hbs index e74337f344cc347175f04d64114baa10726633e8..0b6ee245d2a631928609f6c86c278880d0f68eb2 100644 --- a/views/auth/reset-password.hbs +++ b/views/auth/reset-password.hbs @@ -12,44 +12,46 @@ <meta name="viewport" content="width=device-width, initial-scale=1"> - <link rel="shortcut icon" type="image/png" href="https://jetsam.tech/images/logo.png"> - <link rel="stylesheet" - href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css" - integrity="sha256-l85OmPOjvil/SOvVt3HnSSjzF1TUMyT9eV0c2BzEGzU=" - crossorigin="anonymous" /> - <link rel="stylesheet" - href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css" - integrity="sha256-2YQRJMXD7pIAPHiXr0s+vlRWA7GYJEK0ARns7k2sbHY=" - crossorigin="anonymous" /> + <link rel="shortcut icon" type="image/png" href="https://app.jetsam.tech/logo.png"> +<!-- <link rel="stylesheet"--> +<!-- href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.min.css"--> +<!-- integrity="sha256-l85OmPOjvil/SOvVt3HnSSjzF1TUMyT9eV0c2BzEGzU="--> +<!-- crossorigin="anonymous" />--> +<!-- <link rel="stylesheet"--> +<!-- href="https://cdnjs.cloudflare.com/ajax/libs/skeleton/2.0.4/skeleton.min.css"--> +<!-- integrity="sha256-2YQRJMXD7pIAPHiXr0s+vlRWA7GYJEK0ARns7k2sbHY="--> +<!-- crossorigin="anonymous" />--> + + <link rel="stylesheet" href="/main.css?v=2"> - <link rel="stylesheet" href="/css/main.css?v=2"> </head> <body> -<main class="container" style="max-width: 600px"> - <header class="header"> - <img class="logo" src="https://jetsam.tech/images/logo.png" width="128px" height="128px"> - <div> - <h1>Jetsam</h1> - <h3>Your World; Cleaner</h3> +<main class="container"> + <div class="inner"> + <div class="row header"> + <img class="logo" src="/logo.png" width="128px" height="128px"> + <div class="text-container"> + <h1>Jetsam</h1> + <h3>Your World; Cleaner</h3> + </div> </div> - </header> <form method="POST" action="/reset-password" id="reset_password_form"> - <h3>Reset Password</h3> - <p> + <h3 class="centered">Reset Password</h3> + <p class="centered"> You've requested a reset of your password; please use this form to choose a new one. This link is valid for 1 hour from the time we send it to you, - so if you've gone to grab a cup of tea between requesting a new password and using this form, you may need to request another password reset! + so if you've gone to grab a cup of tea between requesting a new password and using this form, you may need to request another password reset. </p> <input id=reset_token name=reset_token required type=hidden class="u-full-width" value="{{token}}"> - <div class="row"> - <div class="twelve columns"> + <div class="row centered"> + <div class="controls"> <label for=new_password><sup class="required" title="Required">*</sup>New Password:</label> <input id=new_password name=new_password class="u-full-width" required type="password"> </div> </div> - <div class="row"> - <div class="twelve columns"> + <div class="row centered"> + <div class="controls"> <label for=confirm_password><sup class="required" title="Required">*</sup>Confirm Password:</label> <input id=confirm_password name=confirm_password class="u-full-width" required type="password"> </div> @@ -61,8 +63,13 @@ </div> <div id="formmessage" class="row" style="color: red"></div> </form> + + </div> </main> + + + <script async> (function() { var script = document.createElement('script'); diff --git a/worker.js b/worker.js index 98c2c564614cfc2379675de5f5535837b944bcb3..35c30f863b8876e6295386b88aa29f51765f9063 100644 --- a/worker.js +++ b/worker.js @@ -23,7 +23,9 @@ async function main() { close = await queue.listen() await new Promise(async r => { debug('Starting worker spin loop') - while (!done) { await new Promise(rr => setTimeout(rr, 10)) } + while (!done) { + await new Promise(rr => setTimeout(rr, 10)) + } debug('Ending worker spin loop') r(true) }) @@ -35,24 +37,18 @@ function bindSentry() { debug('Binding sentry to process level errors') - process.on("error", (err) => { - Sentry.captureException(err); - }); -} - -main() - .catch(e => { - console.error(e) - Sentry.captureException(e); - process.exit(1) + process.on('error', err => { + Sentry.captureException(err) }) +} +main().catch(e => { + console.error(e) + Sentry.captureException(e) + process.exit(1) +}) -const cleanupsigs = [ - 'SIGINT', - 'SIGTERM', - 'SIGUSR2', -] +const cleanupsigs = ['SIGINT', 'SIGTERM', 'SIGUSR2'] cleanupsigs.forEach(signal => { process.on(signal, () => {