diff --git a/PROD_STAND/PG1/main.tf b/PROD_STAND/PG1/main.tf
new file mode 100644
index 0000000..3b553b7
--- /dev/null
+++ b/PROD_STAND/PG1/main.tf
@@ -0,0 +1,25 @@
+terraform {
+ required_providers {
+ nubes = {
+ source = "terra.k8c.ru/nubes/nubes"
+ version = "2.1.26"
+ }
+ }
+}
+
+variable "api_token" {
+ type = string
+ sensitive = true
+ description = "Nubes API token"
+}
+# variable "s3_uid" {
+# type = string
+# sensitive = true
+# description = "S3 Storage UUID"
+# }
+
+provider "nubes" {
+ api_token = var.api_token
+ api_endpoint = "https://deck-api.ngcloud.ru/api/v1/index.cfm"
+}
+
diff --git a/PROD_STAND/PG1/resources.tf b/PROD_STAND/PG1/resources.tf
new file mode 100644
index 0000000..f505129
--- /dev/null
+++ b/PROD_STAND/PG1/resources.tf
@@ -0,0 +1,141 @@
+resource "nubes_postgres" "db2" {
+ # Основной Postgres-кластер для демо.
+ resource_name = "pg-testing"
+ s3_uid = "6d6061cb-b0c1-44b9-8969-a70f08fe673c"
+ # s3_uid = "6d6061cb-b0c1-44b9-8969-a70f08fe673c"
+ resource_realm = "k8s-3.ext.nubes.ru"
+ resource_instances = 1
+ resource_memory = 1024
+ resource_c_p_u = 1000
+ resource_disk = "1"
+ app_version = "17"
+ json_parameters = jsonencode({
+ # Выключаем подробные логи подключений в демо.
+ log_connections = "off"
+ log_disconnections = "off"
+ })
+ enable_pg_pooler_master = false
+ enable_pg_pooler_slave = false
+ allow_no_s_s_l = false
+ auto_scale = false
+ auto_scale_percentage = 10
+ auto_scale_tech_window = 0
+ auto_scale_quota_gb = "1"
+ need_external_address_master = false
+
+ adopt_existing_on_create = true
+
+}
+
+# output "pg_vault_secrets" {
+# value = nubes_postgres.db2.vault_secrets
+# sensitive = true
+# }
+resource "nubes_lucee" "app1" {
+ # Lucee UI, который читает/пишет в Postgres.
+ resource_name = "lucy11"
+ resource_realm = nubes_postgres.db2.resource_realm
+ domain = "web07"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testlucee.git"
+
+ json_env = jsonencode({
+ # JDBC datasource для Lucee.
+ testds_class = "org.postgresql.Driver"
+ testds_bundleName = "org.postgresql.jdbc"
+ testds_bundleVersion = "42.6.0"
+ testds_connectionString = "jdbc:postgresql://${nubes_postgres.db2.state_out_flat["internalConnect.master"]}:5432/postgres?sslmode=require"
+ testds_username = nubes_postgres.db2.vault_secrets["adminUser"]
+ testds_password = nubes_postgres.db2.vault_secrets["adminPass"]
+ testds_connectionLimit = "7"
+ testds_liveTimeout = "15"
+ testds_validate = "false"
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 512
+ resource_instances = 1
+ app_version = "5.4"
+
+ depends_on = [nubes_postgres.db2]
+
+ adopt_existing_on_create = true
+
+}
+
+resource "nubes_s3bucket" "baba_bucket" {
+ resource_name = "baba-buck-test2"
+ s3_user_uid = "6d6061cb-b0c1-44b9-8969-a70f08fe673c"
+ bucket_name = "baba0"
+# adopt_existing_on_create=true
+}
+
+
+
+resource "nubes_nodejs" "app3" {
+ # NodeJS демо, работающий с тем же Postgres.
+ resource_name = "node_0111"
+ resource_realm = nubes_postgres.db2.resource_realm
+ domain = "node07"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testnode.git"
+ health_path = "/healthz"
+ app_version = "23"
+
+ json_env = jsonencode({
+ # Переменные подключения к Postgres.
+ PGHOST = nubes_postgres.db2.state_out_flat["internalConnect.master"]
+ PGPORT = "5432"
+ PGUSER = nubes_postgres.db2.vault_secrets["adminUser"]
+ PGPASSWORD = nubes_postgres.db2.vault_secrets["adminPass"]
+ PGSSLMODE = "require"
+ DATABASE_URL = format(
+ "postgresql://%s:%s@%s:5432/postgres",
+ nubes_postgres.db2.vault_secrets["adminUser"],
+ nubes_postgres.db2.vault_secrets["adminPass"],
+ nubes_postgres.db2.state_out_flat["internalConnect.master"]
+ )
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 256
+ resource_instances = 1
+
+ adopt_existing_on_create = true
+ # suspend_on_destroy = true
+
+ depends_on = [nubes_postgres.db2]
+}
+
+# resource "nubes_nodejs" "app4" {
+# # NodeJS демо, работающий с тем же Postgres.
+# resource_name = "node_0113"
+# resource_realm = nubes_postgres.db2.resource_realm
+# domain = "node07"
+# git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testnode.git"
+# health_path = "/healthz"
+# app_version = "23"
+
+# json_env = jsonencode({
+# # Переменные подключения к Postgres.
+# PGHOST = nubes_postgres.db2.state_out_flat["internalConnect.master"]
+# PGPORT = "5432"
+# PGUSER = nubes_postgres.db2.vault_secrets["adminUser"]
+# PGPASSWORD = nubes_postgres.db2.vault_secrets["adminPass"]
+# PGSSLMODE = "require"
+# DATABASE_URL = format(
+# "postgresql://%s:%s@%s:5432/postgres",
+# nubes_postgres.db2.vault_secrets["adminUser"],
+# nubes_postgres.db2.vault_secrets["adminPass"],
+# nubes_postgres.db2.state_out_flat["internalConnect.master"]
+# )
+# })
+
+# resource_c_p_u = 300
+# resource_memory = 256
+# resource_instances = 1
+
+# adopt_existing_on_create = true
+# # suspend_on_destroy = true
+
+# depends_on = [nubes_postgres.db2]
+# }
+
diff --git a/PROD_STAND/PG1/vm.tf b/PROD_STAND/PG1/vm.tf
new file mode 100644
index 0000000..a34ea65
--- /dev/null
+++ b/PROD_STAND/PG1/vm.tf
@@ -0,0 +1,15 @@
+# resource "nubes_vc_vm_v3" "vmnginx01" {
+# resource_name = "vm-nginx-auto"
+# vapp_uid = "464eb4a0-62dc-42cd-af2b-4305db3c8d1b"
+# vm_name = "vmnginx01"
+# vm_cpu = 1
+# vm_ram = 1
+# vm_disk = 10
+# image_vm = "Ubuntu_22-20G"
+# user_login = "root"
+# user_public_key = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDUd0DCo52wbKDRR6skYmwx6ffLkFewpXu/YSwtalNlVIhQaOCaEJmY5SerGVqgvXQakckptt3bTRGFPKThxr3LsOk9iftvNKQysr7HMSHWLk3nQvix8DaBIla2Ej+zGV/BfIkFA/85R/wwOC6wTLxOcByXKeJCuIx05NUXh0/5nRc3nowpwyKusUm9VBvMyLdZ4MER8bFq+QhdTaEf1sR3PWNQeDA6Oo4qn/HEU2AzqDI1zEPY8ZT9O6Uc30KdbIaEzAmKpw7F0ai0pmlqbzeDVGx4M4FewQei354d9zvu3CI2KryWQ88jm4feuMcl7wGrhD+kS2F+AUiHCJaPczeh"
+# ip_space_name = "no-needed"
+# access_ip_list = jsonencode([])
+# access_port_list = jsonencode(["22", "80", "10050"])
+# adopt_existing_on_create = true
+# }
diff --git a/PROD_STAND/POSTGRES/flask_disabled.tf b/PROD_STAND/POSTGRES/flask_disabled.tf
new file mode 100644
index 0000000..9d61a7a
--- /dev/null
+++ b/PROD_STAND/POSTGRES/flask_disabled.tf
@@ -0,0 +1,28 @@
+/*
+resource "nubes_flask" "app4" {
+ resource_name = "flask_0"
+ resource_realm = nubes_postgres.db2.resource_realm
+ domain = "flask"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testflask.git"
+
+ json_env = jsonencode({
+ PGHOST = nubes_postgres.db2.state_out_flat["internalConnect.master"]
+ PGPORT = "5432"
+ PGUSER = nubes_postgres.db2.vault_secrets["adminUser"]
+ PGPASSWORD = nubes_postgres.db2.vault_secrets["adminPass"]
+ PGSSLMODE = "require"
+ DATABASE_URL = format(
+ "postgresql://%s:%s@%s:5432/postgres",
+ nubes_postgres.db2.vault_secrets["adminUser"],
+ nubes_postgres.db2.vault_secrets["adminPass"],
+ nubes_postgres.db2.state_out_flat["internalConnect.master"]
+ )
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 256
+ resource_instances = 1
+
+ depends_on = [nubes_postgres.db2]
+}
+*/
diff --git a/PROD_STAND/POSTGRES/main.tf b/PROD_STAND/POSTGRES/main.tf
new file mode 100644
index 0000000..54bb050
--- /dev/null
+++ b/PROD_STAND/POSTGRES/main.tf
@@ -0,0 +1,20 @@
+terraform {
+ required_providers {
+ nubes = {
+ source = "terra.k8c.ru/nubes/nubes"
+ version = "2.1.12"
+ }
+ }
+}
+
+variable "api_token" {
+ type = string
+ sensitive = true
+ description = "Nubes API token"
+}
+
+provider "nubes" {
+ api_token = var.api_token
+ api_endpoint = "https://deck-api.ngcloud.ru/api/v1/index.cfm"
+}
+
diff --git a/PROD_STAND/POSTGRES/resources.tf b/PROD_STAND/POSTGRES/resources.tf
new file mode 100644
index 0000000..4d68230
--- /dev/null
+++ b/PROD_STAND/POSTGRES/resources.tf
@@ -0,0 +1,90 @@
+resource "nubes_postgres" "db2" {
+ # Основной Postgres-кластер для демо.
+ resource_name = "pg-tst0"
+ s3_uid = "6d6061cb-b0c1-44b9-8969-a70f08fe673c"
+ # s3_uid = "s3-111805"
+ resource_realm = "k8s-3.ext.nubes.ru"
+ resource_instances = 1
+ resource_memory = 512
+ resource_c_p_u = 500
+ resource_disk = "1"
+ app_version = "17"
+ json_parameters = jsonencode({
+ # Выключаем подробные логи подключений в демо.
+ log_connections = "off"
+ log_disconnections = "off"
+ })
+ enable_pg_pooler_master = false
+ enable_pg_pooler_slave = false
+ allow_no_s_s_l = false
+ auto_scale = false
+ auto_scale_percentage = 10
+ auto_scale_tech_window = 0
+ auto_scale_quota_gb = "1"
+ need_external_address_master = false
+}
+
+output "pg_vault_secrets" {
+ value = nubes_postgres.db2.vault_secrets
+ sensitive = true
+}
+
+resource "nubes_lucee" "app1" {
+ # Lucee UI, который читает/пишет в Postgres.
+ resource_name = "lucy1"
+ resource_realm = nubes_postgres.db2.resource_realm
+ domain = "web03"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testlucee.git"
+
+ json_env = jsonencode({
+ # JDBC datasource для Lucee.
+ testds_class = "org.postgresql.Driver"
+ testds_bundleName = "org.postgresql.jdbc"
+ testds_bundleVersion = "42.6.0"
+ testds_connectionString = "jdbc:postgresql://${nubes_postgres.db2.state_out_flat["internalConnect.master"]}:5432/postgres"
+ testds_username = nubes_postgres.db2.vault_secrets["adminUser"]
+ testds_password = nubes_postgres.db2.vault_secrets["adminPass"]
+ testds_connectionLimit = "5"
+ testds_liveTimeout = "15"
+ testds_validate = "false"
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 512
+ resource_instances = 1
+ app_version = "5.4"
+
+ depends_on = [nubes_postgres.db2]
+}
+
+resource "nubes_nodejs" "app3" {
+ # NodeJS демо, работающий с тем же Postgres.
+ resource_name = "node_0"
+ resource_realm = nubes_postgres.db2.resource_realm
+ domain = "node"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testnode.git"
+ health_path = "/healthz"
+ app_version = "23"
+
+ json_env = jsonencode({
+ # Переменные подключения к Postgres.
+ PGHOST = nubes_postgres.db2.state_out_flat["internalConnect.master"]
+ PGPORT = "5432"
+ PGUSER = nubes_postgres.db2.vault_secrets["adminUser"]
+ PGPASSWORD = nubes_postgres.db2.vault_secrets["adminPass"]
+ PGSSLMODE = "require"
+ DATABASE_URL = format(
+ "postgresql://%s:%s@%s:5432/postgres",
+ nubes_postgres.db2.vault_secrets["adminUser"],
+ nubes_postgres.db2.vault_secrets["adminPass"],
+ nubes_postgres.db2.state_out_flat["internalConnect.master"]
+ )
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 256
+ resource_instances = 1
+
+ depends_on = [nubes_postgres.db2]
+}
+
diff --git a/PROD_STAND/POSTGRES/testflask/.gitignore b/PROD_STAND/POSTGRES/testflask/.gitignore
new file mode 100644
index 0000000..5cdf96c
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testflask/.gitignore
@@ -0,0 +1,3 @@
+site/templates/
+site/static/
+venv/
\ No newline at end of file
diff --git a/PROD_STAND/POSTGRES/testflask/.pylintrc b/PROD_STAND/POSTGRES/testflask/.pylintrc
new file mode 100644
index 0000000..489b748
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testflask/.pylintrc
@@ -0,0 +1 @@
+disable=missing-function-docstring
diff --git a/PROD_STAND/POSTGRES/testflask/Dockerfile b/PROD_STAND/POSTGRES/testflask/Dockerfile
new file mode 100644
index 0000000..2a9fd7f
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testflask/Dockerfile
@@ -0,0 +1,14 @@
+# Базовый образ Python для Flask-приложения.
+FROM python:3.9-slim
+
+WORKDIR /app
+
+COPY requirements.txt .
+
+RUN pip install --no-cache-dir -r requirements.txt
+
+COPY site /app/site
+
+EXPOSE 5000
+
+CMD ["python", "site/app.py"]
\ No newline at end of file
diff --git a/PROD_STAND/POSTGRES/testflask/README.md b/PROD_STAND/POSTGRES/testflask/README.md
new file mode 100644
index 0000000..f340985
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testflask/README.md
@@ -0,0 +1,6 @@
+# Flask + Postgres Demo
+
+Простое CRUD-приложение на Flask, которое пишет и читает из таблицы `nubes_test_table`.
+Если поле ввода пустое, вставляется запись "Это Flask сделал".
+
+Примечание: таблица создается автоматически при первом запросе.
\ No newline at end of file
diff --git a/PROD_STAND/POSTGRES/testflask/requirements.txt b/PROD_STAND/POSTGRES/testflask/requirements.txt
new file mode 100644
index 0000000..b46927f
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testflask/requirements.txt
@@ -0,0 +1,3 @@
+Flask==2.0.1
+Werkzeug==2.3.7
+psycopg2-binary==2.9.9
\ No newline at end of file
diff --git a/PROD_STAND/POSTGRES/testlucee/Application.cfc b/PROD_STAND/POSTGRES/testlucee/Application.cfc
new file mode 100644
index 0000000..5cbfb85
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testlucee/Application.cfc
@@ -0,0 +1,58 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO nubes_test_table (test_data) VALUES ()
+
+
+
+
+ UPDATE nubes_test_table SET test_data = WHERE id =
+
+
+
+
+ DELETE FROM nubes_test_table WHERE id =
+
+
+
+
+
+
+
+
+
+
+ CREATE TABLE IF NOT EXISTS nubes_test_table (id SERIAL PRIMARY KEY, test_data TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP);
+
+
+
+
+
diff --git a/PROD_STAND/POSTGRES/testlucee/README.md b/PROD_STAND/POSTGRES/testlucee/README.md
new file mode 100644
index 0000000..142e4d4
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testlucee/README.md
@@ -0,0 +1,11 @@
+# Тестовое приложение by Terraform - Lucee & Postgres
+
+### Что здесь можно делать:
+
+* **Просмотр:** Список последних записей загружается автоматически при открытии страницы.
+* **Добавление:** Введите текст в верхнее поле и нажмите кнопку «Добавить», чтобы сохранить данные в базу.
+* **Редактирование:** Вы можете изменить текст любой записи прямо в таблице. Не забудьте нажать на кнопку с дискетой (💾), чтобы сохранить изменения.
+* **Удаление:** Нажмите на иконку корзины (🗑), чтобы навсегда удалить запись из базы данных.
+
+Примечание: таблица создается автоматически при первом открытии страницы.
+
diff --git a/PROD_STAND/POSTGRES/testlucee/index.cfm b/PROD_STAND/POSTGRES/testlucee/index.cfm
new file mode 100644
index 0000000..2221de8
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testlucee/index.cfm
@@ -0,0 +1,2 @@
+
+
diff --git a/PROD_STAND/POSTGRES/testlucee/query.cfm b/PROD_STAND/POSTGRES/testlucee/query.cfm
new file mode 100644
index 0000000..8943632
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testlucee/query.cfm
@@ -0,0 +1,77 @@
+
+
+
+
+ Nubes | Управление данными
+
+
+
+
+
+
+
+
+
+
+
+
SELECT * FROM nubes_test_table ORDER BY id DESC LIMIT 20
+
+ | ID | Содержимое | Действия |
+
+
+
+ | #id# |
+
+
+ |
+
+
+
+ |
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/PROD_STAND/POSTGRES/testlucee/tst.html b/PROD_STAND/POSTGRES/testlucee/tst.html
new file mode 100644
index 0000000..0994e3b
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testlucee/tst.html
@@ -0,0 +1 @@
+again test hello
\ No newline at end of file
diff --git a/PROD_STAND/POSTGRES/testnode/.gitignore b/PROD_STAND/POSTGRES/testnode/.gitignore
new file mode 100644
index 0000000..c2658d7
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/.gitignore
@@ -0,0 +1 @@
+node_modules/
diff --git a/PROD_STAND/POSTGRES/testnode/README.md b/PROD_STAND/POSTGRES/testnode/README.md
new file mode 100644
index 0000000..a7601bd
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/README.md
@@ -0,0 +1,6 @@
+# NodeJS + Postgres Demo
+
+Simple Node.js CRUD app that writes to `nubes_test_table` and renders a small HTML UI.
+If the input is empty, it inserts "Node did it".
+
+Примечание: таблица создается автоматически, а дубликаты подряд отсекаются по таймауту.
diff --git a/PROD_STAND/POSTGRES/testnode/package-lock.json b/PROD_STAND/POSTGRES/testnode/package-lock.json
new file mode 100644
index 0000000..4f04357
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/package-lock.json
@@ -0,0 +1,6808 @@
+{
+ "name": "loopback4-example-github",
+ "version": "0.0.1",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "loopback4-example-github",
+ "version": "0.0.1",
+ "dependencies": {
+ "@loopback/boot": "^3.4.1",
+ "@loopback/core": "^2.16.1",
+ "@loopback/repository": "^3.7.0",
+ "@loopback/rest": "^9.3.1",
+ "@loopback/rest-explorer": "^3.3.1",
+ "@loopback/service-proxy": "^3.2.1",
+ "loopback-connector-rest": "^3.7.0",
+ "pg": "^8.18.0",
+ "tslib": "^2.0.0"
+ },
+ "devDependencies": {
+ "@loopback/build": "^6.4.1",
+ "@loopback/eslint-config": "^10.2.1",
+ "@loopback/testlab": "^3.4.1",
+ "@types/node": "^10.17.60",
+ "eslint": "^7.28.0",
+ "source-map-support": "^0.5.19",
+ "typescript": "~4.3.2"
+ },
+ "engines": {
+ "node": ">=10.16"
+ }
+ },
+ "node_modules/@babel/code-frame": {
+ "version": "7.12.11",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/highlight": "^7.10.4"
+ }
+ },
+ "node_modules/@babel/compat-data": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.14.5",
+ "@babel/generator": "^7.14.5",
+ "@babel/helper-compilation-targets": "^7.14.5",
+ "@babel/helper-module-transforms": "^7.14.5",
+ "@babel/helpers": "^7.14.5",
+ "@babel/parser": "^7.14.5",
+ "@babel/template": "^7.14.5",
+ "@babel/traverse": "^7.14.5",
+ "@babel/types": "^7.14.5",
+ "convert-source-map": "^1.7.0",
+ "debug": "^4.1.0",
+ "gensync": "^1.0.0-beta.2",
+ "json5": "^2.1.2",
+ "semver": "^6.3.0",
+ "source-map": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/babel"
+ }
+ },
+ "node_modules/@babel/core/node_modules/@babel/code-frame": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/highlight": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/core/node_modules/semver": {
+ "version": "6.3.0",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/generator": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.14.5",
+ "jsesc": "^2.5.1",
+ "source-map": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/compat-data": "^7.14.5",
+ "@babel/helper-validator-option": "^7.14.5",
+ "browserslist": "^4.16.6",
+ "semver": "^6.3.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ },
+ "peerDependencies": {
+ "@babel/core": "^7.0.0"
+ }
+ },
+ "node_modules/@babel/helper-compilation-targets/node_modules/semver": {
+ "version": "6.3.0",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/@babel/helper-function-name": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-get-function-arity": "^7.14.5",
+ "@babel/template": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-get-function-arity": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-hoist-variables": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-member-expression-to-functions": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-imports": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-module-transforms": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-module-imports": "^7.14.5",
+ "@babel/helper-replace-supers": "^7.14.5",
+ "@babel/helper-simple-access": "^7.14.5",
+ "@babel/helper-split-export-declaration": "^7.14.5",
+ "@babel/helper-validator-identifier": "^7.14.5",
+ "@babel/template": "^7.14.5",
+ "@babel/traverse": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-optimise-call-expression": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-replace-supers": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-member-expression-to-functions": "^7.14.5",
+ "@babel/helper-optimise-call-expression": "^7.14.5",
+ "@babel/traverse": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-simple-access": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-split-export-declaration": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-identifier": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helper-validator-option": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/helpers": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/template": "^7.14.5",
+ "@babel/traverse": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/highlight": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.14.5",
+ "chalk": "^2.0.0",
+ "js-tokens": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/parser": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "parser": "bin/babel-parser.js"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@babel/template": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.14.5",
+ "@babel/parser": "^7.14.5",
+ "@babel/types": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/template/node_modules/@babel/code-frame": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/highlight": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "^7.14.5",
+ "@babel/generator": "^7.14.5",
+ "@babel/helper-function-name": "^7.14.5",
+ "@babel/helper-hoist-variables": "^7.14.5",
+ "@babel/helper-split-export-declaration": "^7.14.5",
+ "@babel/parser": "^7.14.5",
+ "@babel/types": "^7.14.5",
+ "debug": "^4.1.0",
+ "globals": "^11.1.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/@babel/code-frame": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/highlight": "^7.14.5"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@babel/traverse/node_modules/globals": {
+ "version": "11.12.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/@babel/types": {
+ "version": "7.14.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/helper-validator-identifier": "^7.14.5",
+ "to-fast-properties": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc": {
+ "version": "0.4.2",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.1.1",
+ "espree": "^7.3.0",
+ "globals": "^13.9.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^3.13.1",
+ "minimatch": "^3.0.4",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/ignore": {
+ "version": "4.0.6",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/@eslint/eslintrc/node_modules/js-yaml": {
+ "version": "3.14.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/@exodus/schemasafe": {
+ "version": "1.0.0-rc.3",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@hapi/hoek": {
+ "version": "9.2.0",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/@hapi/shot": {
+ "version": "5.0.5",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@hapi/hoek": "9.x.x",
+ "@hapi/validate": "1.x.x"
+ }
+ },
+ "node_modules/@hapi/topo": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@hapi/hoek": "^9.0.0"
+ }
+ },
+ "node_modules/@hapi/validate": {
+ "version": "1.1.3",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@hapi/hoek": "^9.0.0",
+ "@hapi/topo": "^5.0.0"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config": {
+ "version": "1.1.0",
+ "dev": true,
+ "license": "ISC",
+ "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/camelcase": {
+ "version": "5.3.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": {
+ "version": "4.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": {
+ "version": "3.14.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": {
+ "version": "2.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": {
+ "version": "4.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@istanbuljs/schema": {
+ "version": "0.1.3",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/@loopback/boot": {
+ "version": "3.4.1",
+ "license": "MIT",
+ "dependencies": {
+ "@loopback/model-api-builder": "^2.3.1",
+ "@loopback/repository": "^3.7.0",
+ "@loopback/service-proxy": "^3.2.1",
+ "@types/debug": "^4.1.5",
+ "@types/glob": "^7.1.3",
+ "debug": "^4.3.1",
+ "glob": "^7.1.7",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "@loopback/core": "^2.16.1"
+ }
+ },
+ "node_modules/@loopback/build": {
+ "version": "6.4.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@loopback/eslint-config": "^10.2.1",
+ "@types/mocha": "^8.2.2",
+ "@types/node": "^10.17.60",
+ "cross-spawn": "^7.0.3",
+ "debug": "^4.3.1",
+ "eslint": "^7.28.0",
+ "fs-extra": "^10.0.0",
+ "glob": "^7.1.7",
+ "lodash": "^4.17.21",
+ "mocha": "^9.0.0",
+ "nyc": "^15.1.0",
+ "prettier": "^2.3.1",
+ "rimraf": "^3.0.2",
+ "source-map-support": "^0.5.19",
+ "typescript": "~4.3.2"
+ },
+ "bin": {
+ "lb-clean": "bin/run-clean.js",
+ "lb-eslint": "bin/run-eslint.js",
+ "lb-mocha": "bin/run-mocha.js",
+ "lb-nyc": "bin/run-nyc.js",
+ "lb-prettier": "bin/run-prettier.js",
+ "lb-tsc": "bin/compile-package.js"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ }
+ },
+ "node_modules/@loopback/context": {
+ "version": "3.17.0",
+ "license": "MIT",
+ "dependencies": {
+ "@loopback/metadata": "^3.3.1",
+ "@types/debug": "^4.1.5",
+ "debug": "^4.3.1",
+ "hyperid": "^2.1.0",
+ "p-event": "^4.2.0",
+ "tslib": "^2.2.0",
+ "uuid": "^8.3.2"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ }
+ },
+ "node_modules/@loopback/core": {
+ "version": "2.16.1",
+ "license": "MIT",
+ "dependencies": {
+ "@loopback/context": "^3.17.0",
+ "debug": "^4.3.1",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ }
+ },
+ "node_modules/@loopback/eslint-config": {
+ "version": "10.2.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/eslint-plugin": "^4.26.1",
+ "@typescript-eslint/parser": "^4.26.1",
+ "eslint-config-prettier": "^8.3.0",
+ "eslint-plugin-eslint-plugin": "^3.0.3",
+ "eslint-plugin-mocha": "^9.0.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "eslint": "^7.28.0"
+ }
+ },
+ "node_modules/@loopback/express": {
+ "version": "3.3.1",
+ "license": "MIT",
+ "dependencies": {
+ "@loopback/http-server": "^2.5.1",
+ "@types/body-parser": "^1.19.0",
+ "@types/express": "^4.17.12",
+ "@types/express-serve-static-core": "^4.17.21",
+ "@types/http-errors": "^1.8.0",
+ "body-parser": "^1.19.0",
+ "debug": "^4.3.1",
+ "express": "^4.17.1",
+ "http-errors": "^1.8.0",
+ "on-finished": "^2.3.0",
+ "toposort": "^2.0.2",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "@loopback/core": "^2.16.1"
+ }
+ },
+ "node_modules/@loopback/filter": {
+ "version": "1.5.1",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ }
+ },
+ "node_modules/@loopback/http-server": {
+ "version": "2.5.1",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.1",
+ "stoppable": "^1.1.0",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ }
+ },
+ "node_modules/@loopback/metadata": {
+ "version": "3.3.1",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.1",
+ "lodash": "^4.17.21",
+ "reflect-metadata": "^0.1.13",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ }
+ },
+ "node_modules/@loopback/model-api-builder": {
+ "version": "2.3.1",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "@loopback/core": "^2.16.1",
+ "@loopback/repository": "^3.7.0"
+ }
+ },
+ "node_modules/@loopback/openapi-v3": {
+ "version": "5.3.1",
+ "license": "MIT",
+ "dependencies": {
+ "@loopback/repository-json-schema": "^3.4.1",
+ "debug": "^4.3.1",
+ "http-status": "^1.5.0",
+ "json-merge-patch": "^1.0.1",
+ "lodash": "^4.17.21",
+ "openapi3-ts": "^2.0.1",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "@loopback/core": "^2.16.1"
+ }
+ },
+ "node_modules/@loopback/repository": {
+ "version": "3.7.0",
+ "license": "MIT",
+ "dependencies": {
+ "@loopback/filter": "^1.5.1",
+ "@types/debug": "^4.1.5",
+ "debug": "^4.3.1",
+ "lodash": "^4.17.21",
+ "loopback-datasource-juggler": "^4.26.0",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "@loopback/core": "^2.16.1"
+ }
+ },
+ "node_modules/@loopback/repository-json-schema": {
+ "version": "3.4.1",
+ "license": "MIT",
+ "dependencies": {
+ "@types/json-schema": "^7.0.7",
+ "debug": "^4.3.1",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "@loopback/core": "^2.16.1",
+ "@loopback/repository": "^3.7.0"
+ }
+ },
+ "node_modules/@loopback/rest": {
+ "version": "9.3.1",
+ "license": "MIT",
+ "dependencies": {
+ "@loopback/express": "^3.3.1",
+ "@loopback/http-server": "^2.5.1",
+ "@loopback/openapi-v3": "^5.3.1",
+ "@openapi-contrib/openapi-schema-to-json-schema": "^3.1.0",
+ "@types/body-parser": "^1.19.0",
+ "@types/cors": "^2.8.10",
+ "@types/express": "^4.17.12",
+ "@types/express-serve-static-core": "^4.17.21",
+ "@types/http-errors": "^1.8.0",
+ "@types/on-finished": "^2.3.1",
+ "@types/serve-static": "1.13.9",
+ "@types/type-is": "^1.6.3",
+ "ajv": "^6.12.6",
+ "ajv-errors": "^1.0.1",
+ "ajv-keywords": "^3.5.2",
+ "body-parser": "^1.19.0",
+ "cors": "^2.8.5",
+ "debug": "^4.3.1",
+ "express": "^4.17.1",
+ "http-errors": "^1.8.0",
+ "js-yaml": "^4.1.0",
+ "json-schema-compare": "^0.2.2",
+ "lodash": "^4.17.21",
+ "on-finished": "^2.3.0",
+ "path-to-regexp": "^6.2.0",
+ "qs": "^6.10.1",
+ "strong-error-handler": "^4.0.0",
+ "tslib": "^2.2.0",
+ "type-is": "^1.6.18",
+ "validator": "^13.6.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "@loopback/core": "^2.16.1"
+ }
+ },
+ "node_modules/@loopback/rest-explorer": {
+ "version": "3.3.1",
+ "license": "MIT",
+ "dependencies": {
+ "ejs": "^3.1.6",
+ "swagger-ui-dist": "3.50.0",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "@loopback/core": "^2.16.1",
+ "@loopback/rest": "^9.3.1"
+ }
+ },
+ "node_modules/@loopback/service-proxy": {
+ "version": "3.2.1",
+ "license": "MIT",
+ "dependencies": {
+ "loopback-datasource-juggler": "^4.26.0",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ },
+ "peerDependencies": {
+ "@loopback/core": "^2.16.1"
+ }
+ },
+ "node_modules/@loopback/testlab": {
+ "version": "3.4.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@hapi/shot": "^5.0.5",
+ "@types/express": "^4.17.12",
+ "@types/fs-extra": "^9.0.11",
+ "@types/shot": "^4.0.0",
+ "@types/sinon": "^10.0.2",
+ "@types/supertest": "^2.0.11",
+ "express": "^4.17.1",
+ "fs-extra": "^10.0.0",
+ "oas-validator": "^5.0.6",
+ "should": "^13.2.3",
+ "sinon": "^11.1.1",
+ "supertest": "^6.1.3",
+ "tslib": "^2.2.0"
+ },
+ "engines": {
+ "node": "^10.16 || 12 || 14 || 16"
+ }
+ },
+ "node_modules/@nodelib/fs.scandir": {
+ "version": "2.1.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.stat": {
+ "version": "2.0.5",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@nodelib/fs.walk": {
+ "version": "1.2.7",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/@openapi-contrib/openapi-schema-to-json-schema": {
+ "version": "3.1.0",
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ }
+ },
+ "node_modules/@sinonjs/commons": {
+ "version": "1.8.3",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "type-detect": "4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/fake-timers": {
+ "version": "7.1.2",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@sinonjs/commons": "^1.7.0"
+ }
+ },
+ "node_modules/@sinonjs/samsam": {
+ "version": "6.0.2",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@sinonjs/commons": "^1.6.0",
+ "lodash.get": "^4.4.2",
+ "type-detect": "^4.0.8"
+ }
+ },
+ "node_modules/@sinonjs/text-encoding": {
+ "version": "0.7.1",
+ "dev": true,
+ "license": "(Unlicense OR Apache-2.0)"
+ },
+ "node_modules/@types/body-parser": {
+ "version": "1.19.0",
+ "license": "MIT",
+ "dependencies": {
+ "@types/connect": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/body-parser/node_modules/@types/node": {
+ "version": "15.12.2",
+ "license": "MIT"
+ },
+ "node_modules/@types/connect": {
+ "version": "3.4.34",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/connect/node_modules/@types/node": {
+ "version": "15.12.2",
+ "license": "MIT"
+ },
+ "node_modules/@types/cookiejar": {
+ "version": "2.1.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/cors": {
+ "version": "2.8.10",
+ "license": "MIT"
+ },
+ "node_modules/@types/debug": {
+ "version": "4.1.5",
+ "license": "MIT"
+ },
+ "node_modules/@types/express": {
+ "version": "4.17.12",
+ "license": "MIT",
+ "dependencies": {
+ "@types/body-parser": "*",
+ "@types/express-serve-static-core": "^4.17.18",
+ "@types/qs": "*",
+ "@types/serve-static": "*"
+ }
+ },
+ "node_modules/@types/express-serve-static-core": {
+ "version": "4.17.21",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*",
+ "@types/qs": "*",
+ "@types/range-parser": "*"
+ }
+ },
+ "node_modules/@types/express-serve-static-core/node_modules/@types/node": {
+ "version": "15.12.2",
+ "license": "MIT"
+ },
+ "node_modules/@types/fs-extra": {
+ "version": "9.0.11",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/glob": {
+ "version": "7.1.3",
+ "license": "MIT",
+ "dependencies": {
+ "@types/minimatch": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/glob/node_modules/@types/node": {
+ "version": "15.12.2",
+ "license": "MIT"
+ },
+ "node_modules/@types/http-errors": {
+ "version": "1.8.0",
+ "license": "MIT"
+ },
+ "node_modules/@types/json-schema": {
+ "version": "7.0.7",
+ "license": "MIT"
+ },
+ "node_modules/@types/mime": {
+ "version": "1.3.2",
+ "license": "MIT"
+ },
+ "node_modules/@types/minimatch": {
+ "version": "3.0.4",
+ "license": "MIT"
+ },
+ "node_modules/@types/mocha": {
+ "version": "8.2.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/node": {
+ "version": "10.17.60",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@types/on-finished": {
+ "version": "2.3.1",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/on-finished/node_modules/@types/node": {
+ "version": "15.12.2",
+ "license": "MIT"
+ },
+ "node_modules/@types/qs": {
+ "version": "6.9.6",
+ "license": "MIT"
+ },
+ "node_modules/@types/range-parser": {
+ "version": "1.2.3",
+ "license": "MIT"
+ },
+ "node_modules/@types/serve-static": {
+ "version": "1.13.9",
+ "license": "MIT",
+ "dependencies": {
+ "@types/mime": "^1",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/serve-static/node_modules/@types/node": {
+ "version": "15.12.2",
+ "license": "MIT"
+ },
+ "node_modules/@types/shot": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/sinon": {
+ "version": "10.0.2",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sinonjs/fake-timers": "^7.1.0"
+ }
+ },
+ "node_modules/@types/superagent": {
+ "version": "4.1.11",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/cookiejar": "*",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/supertest": {
+ "version": "2.0.11",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/superagent": "*"
+ }
+ },
+ "node_modules/@types/type-is": {
+ "version": "1.6.3",
+ "license": "MIT",
+ "dependencies": {
+ "@types/node": "*"
+ }
+ },
+ "node_modules/@types/type-is/node_modules/@types/node": {
+ "version": "15.12.2",
+ "license": "MIT"
+ },
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "4.26.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/experimental-utils": "4.26.1",
+ "@typescript-eslint/scope-manager": "4.26.1",
+ "debug": "^4.3.1",
+ "functional-red-black-tree": "^1.0.1",
+ "lodash": "^4.17.21",
+ "regexpp": "^3.1.0",
+ "semver": "^7.3.5",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "@typescript-eslint/parser": "^4.0.0",
+ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/experimental-utils": {
+ "version": "4.26.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/json-schema": "^7.0.7",
+ "@typescript-eslint/scope-manager": "4.26.1",
+ "@typescript-eslint/types": "4.26.1",
+ "@typescript-eslint/typescript-estree": "4.26.1",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^3.0.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "*"
+ }
+ },
+ "node_modules/@typescript-eslint/parser": {
+ "version": "4.26.1",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "4.26.1",
+ "@typescript-eslint/types": "4.26.1",
+ "@typescript-eslint/typescript-estree": "4.26.1",
+ "debug": "^4.3.1"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependencies": {
+ "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "4.26.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "4.26.1",
+ "@typescript-eslint/visitor-keys": "4.26.1"
+ },
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "4.26.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@typescript-eslint/typescript-estree": {
+ "version": "4.26.1",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "@typescript-eslint/types": "4.26.1",
+ "@typescript-eslint/visitor-keys": "4.26.1",
+ "debug": "^4.3.1",
+ "globby": "^11.0.3",
+ "is-glob": "^4.0.1",
+ "semver": "^7.3.5",
+ "tsutils": "^3.21.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ },
+ "peerDependenciesMeta": {
+ "typescript": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "4.26.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "4.26.1",
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": "^8.10.0 || ^10.13.0 || >=11.10.1"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
+ "node_modules/@ungap/promise-all-settled": {
+ "version": "1.1.2",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/accept-language": {
+ "version": "3.0.18",
+ "license": "MIT",
+ "dependencies": {
+ "bcp47": "^1.1.2",
+ "stable": "^0.1.6"
+ }
+ },
+ "node_modules/accepts": {
+ "version": "1.3.7",
+ "license": "MIT",
+ "dependencies": {
+ "mime-types": "~2.1.24",
+ "negotiator": "0.6.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/acorn": {
+ "version": "7.4.1",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-jsx": {
+ "version": "5.3.1",
+ "dev": true,
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
+ }
+ },
+ "node_modules/aggregate-error": {
+ "version": "3.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "clean-stack": "^2.0.0",
+ "indent-string": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ajv": {
+ "version": "6.12.6",
+ "license": "MIT",
+ "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/ajv-errors": {
+ "version": "1.0.1",
+ "license": "MIT",
+ "peerDependencies": {
+ "ajv": ">=5.0.0"
+ }
+ },
+ "node_modules/ajv-keywords": {
+ "version": "3.5.2",
+ "license": "MIT",
+ "peerDependencies": {
+ "ajv": "^6.9.1"
+ }
+ },
+ "node_modules/ansi-colors": {
+ "version": "4.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "3.2.1",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.2",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/append-transform": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "default-require-extensions": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/archy": {
+ "version": "1.0.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/argparse": {
+ "version": "1.0.10",
+ "license": "MIT",
+ "dependencies": {
+ "sprintf-js": "~1.0.2"
+ }
+ },
+ "node_modules/array-flatten": {
+ "version": "1.1.1",
+ "license": "MIT"
+ },
+ "node_modules/array-union": {
+ "version": "2.1.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/asn1": {
+ "version": "0.2.4",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": "~2.1.0"
+ }
+ },
+ "node_modules/assert-plus": {
+ "version": "1.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/astral-regex": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.0",
+ "license": "MIT"
+ },
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "license": "MIT"
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.4",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/aws-sign2": {
+ "version": "0.7.0",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/aws4": {
+ "version": "1.11.0",
+ "license": "MIT"
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "license": "MIT"
+ },
+ "node_modules/bcp47": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/bcrypt-pbkdf": {
+ "version": "1.0.2",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "tweetnacl": "^0.14.3"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.2.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/bl": {
+ "version": "2.2.1",
+ "license": "MIT",
+ "dependencies": {
+ "readable-stream": "^2.3.5",
+ "safe-buffer": "^5.1.1"
+ }
+ },
+ "node_modules/bluebird": {
+ "version": "3.7.2",
+ "license": "MIT"
+ },
+ "node_modules/body-parser": {
+ "version": "1.19.0",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.0",
+ "content-type": "~1.0.4",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "on-finished": "~2.3.0",
+ "qs": "6.7.0",
+ "raw-body": "2.4.0",
+ "type-is": "~1.6.17"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/body-parser/node_modules/debug": {
+ "version": "2.6.9",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/body-parser/node_modules/depd": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/body-parser/node_modules/http-errors": {
+ "version": "1.7.2",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/body-parser/node_modules/inherits": {
+ "version": "2.0.3",
+ "license": "ISC"
+ },
+ "node_modules/body-parser/node_modules/ms": {
+ "version": "2.0.0",
+ "license": "MIT"
+ },
+ "node_modules/body-parser/node_modules/qs": {
+ "version": "6.7.0",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.2",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fill-range": "^7.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/browser-stdout": {
+ "version": "1.3.1",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/browserslist": {
+ "version": "4.16.6",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "caniuse-lite": "^1.0.30001219",
+ "colorette": "^1.2.2",
+ "electron-to-chromium": "^1.3.723",
+ "escalade": "^3.1.1",
+ "node-releases": "^1.1.71"
+ },
+ "bin": {
+ "browserslist": "cli.js"
+ },
+ "engines": {
+ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ }
+ },
+ "node_modules/buffer-from": {
+ "version": "1.1.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/bytes": {
+ "version": "3.1.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/caching-transform": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "hasha": "^5.0.0",
+ "make-dir": "^3.0.0",
+ "package-hash": "^4.0.0",
+ "write-file-atomic": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.2",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/call-me-maybe": {
+ "version": "1.0.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/callsites": {
+ "version": "3.1.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/camel-case": {
+ "version": "4.1.2",
+ "license": "MIT",
+ "dependencies": {
+ "pascal-case": "^3.1.2",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/camelcase": {
+ "version": "6.2.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/caniuse-lite": {
+ "version": "1.0.30001236",
+ "dev": true,
+ "license": "CC-BY-4.0",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/browserslist"
+ }
+ },
+ "node_modules/capital-case": {
+ "version": "1.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
+ "node_modules/caseless": {
+ "version": "0.12.0",
+ "license": "Apache-2.0"
+ },
+ "node_modules/chalk": {
+ "version": "2.4.2",
+ "license": "MIT",
+ "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.2",
+ "license": "MIT",
+ "dependencies": {
+ "camel-case": "^4.1.2",
+ "capital-case": "^1.0.4",
+ "constant-case": "^3.0.4",
+ "dot-case": "^3.0.4",
+ "header-case": "^2.0.4",
+ "no-case": "^3.0.4",
+ "param-case": "^3.0.4",
+ "pascal-case": "^3.1.2",
+ "path-case": "^3.0.4",
+ "sentence-case": "^3.0.4",
+ "snake-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/charenc": {
+ "version": "0.0.2",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.5.1",
+ "dev": true,
+ "license": "MIT",
+ "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.5.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.1"
+ }
+ },
+ "node_modules/cldrjs": {
+ "version": "0.5.5"
+ },
+ "node_modules/clean-stack": {
+ "version": "2.2.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "7.0.4",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "1.9.3",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.3",
+ "license": "MIT"
+ },
+ "node_modules/colorette": {
+ "version": "1.2.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "license": "MIT",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/commondir": {
+ "version": "1.0.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/component-emitter": {
+ "version": "1.3.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "license": "MIT"
+ },
+ "node_modules/constant-case": {
+ "version": "3.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case": "^2.0.2"
+ }
+ },
+ "node_modules/content-disposition": {
+ "version": "0.5.3",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "5.1.2"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/content-disposition/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "license": "MIT"
+ },
+ "node_modules/content-type": {
+ "version": "1.0.4",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "1.7.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.1"
+ }
+ },
+ "node_modules/convert-source-map/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/cookie": {
+ "version": "0.4.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/cookie-signature": {
+ "version": "1.0.6",
+ "license": "MIT"
+ },
+ "node_modules/cookiejar": {
+ "version": "2.1.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "license": "MIT"
+ },
+ "node_modules/cors": {
+ "version": "2.8.5",
+ "license": "MIT",
+ "dependencies": {
+ "object-assign": "^4",
+ "vary": "^1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/cross-spawn": {
+ "version": "7.0.3",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.1.0",
+ "shebang-command": "^2.0.0",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/crypt": {
+ "version": "0.0.2",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/dashdash": {
+ "version": "1.14.1",
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.3.1",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decamelize": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/deep-equal": {
+ "version": "2.0.5",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "es-get-iterator": "^1.1.1",
+ "get-intrinsic": "^1.0.1",
+ "is-arguments": "^1.0.4",
+ "is-date-object": "^1.0.2",
+ "is-regex": "^1.1.1",
+ "isarray": "^2.0.5",
+ "object-is": "^1.1.4",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.2",
+ "regexp.prototype.flags": "^1.3.0",
+ "side-channel": "^1.0.3",
+ "which-boxed-primitive": "^1.0.1",
+ "which-collection": "^1.0.1",
+ "which-typed-array": "^1.1.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/deep-equal/node_modules/isarray": {
+ "version": "2.0.5",
+ "license": "MIT"
+ },
+ "node_modules/deep-is": {
+ "version": "0.1.3",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/default-require-extensions": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "strip-bom": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.1.3",
+ "license": "MIT",
+ "dependencies": {
+ "object-keys": "^1.0.12"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/depd": {
+ "version": "2.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/destroy": {
+ "version": "1.0.4",
+ "license": "MIT"
+ },
+ "node_modules/diff": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.3.1"
+ }
+ },
+ "node_modules/dir-glob": {
+ "version": "3.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "path-type": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/doctrine": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "esutils": "^2.0.2"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/dot-case": {
+ "version": "3.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/ecc-jsbn": {
+ "version": "0.1.2",
+ "license": "MIT",
+ "dependencies": {
+ "jsbn": "~0.1.0",
+ "safer-buffer": "^2.1.0"
+ }
+ },
+ "node_modules/ee-first": {
+ "version": "1.1.1",
+ "license": "MIT"
+ },
+ "node_modules/ejs": {
+ "version": "3.1.6",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "jake": "^10.6.1"
+ },
+ "bin": {
+ "ejs": "bin/cli.js"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/electron-to-chromium": {
+ "version": "1.3.752",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/encodeurl": {
+ "version": "1.0.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "license": "MIT",
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/enquirer": {
+ "version": "2.3.6",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-colors": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/es-abstract": {
+ "version": "1.18.3",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "es-to-primitive": "^1.2.1",
+ "function-bind": "^1.1.1",
+ "get-intrinsic": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.2",
+ "is-callable": "^1.2.3",
+ "is-negative-zero": "^2.0.1",
+ "is-regex": "^1.1.3",
+ "is-string": "^1.0.6",
+ "object-inspect": "^1.10.3",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.2",
+ "string.prototype.trimend": "^1.0.4",
+ "string.prototype.trimstart": "^1.0.4",
+ "unbox-primitive": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-get-iterator": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.1.0",
+ "has-symbols": "^1.0.1",
+ "is-arguments": "^1.1.0",
+ "is-map": "^2.0.2",
+ "is-set": "^2.0.2",
+ "is-string": "^1.0.5",
+ "isarray": "^2.0.5"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-get-iterator/node_modules/isarray": {
+ "version": "2.0.5",
+ "license": "MIT"
+ },
+ "node_modules/es-to-primitive": {
+ "version": "1.2.1",
+ "license": "MIT",
+ "dependencies": {
+ "is-callable": "^1.1.4",
+ "is-date-object": "^1.0.1",
+ "is-symbol": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es6-error": {
+ "version": "4.1.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/escalade": {
+ "version": "3.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-html": {
+ "version": "1.0.3",
+ "license": "MIT"
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/eslint": {
+ "version": "7.28.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@babel/code-frame": "7.12.11",
+ "@eslint/eslintrc": "^0.4.2",
+ "ajv": "^6.10.0",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.0.1",
+ "doctrine": "^3.0.0",
+ "enquirer": "^2.3.5",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^5.1.1",
+ "eslint-utils": "^2.1.0",
+ "eslint-visitor-keys": "^2.0.0",
+ "espree": "^7.3.1",
+ "esquery": "^1.4.0",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "functional-red-black-tree": "^1.0.1",
+ "glob-parent": "^5.1.2",
+ "globals": "^13.6.0",
+ "ignore": "^4.0.6",
+ "import-fresh": "^3.0.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "js-yaml": "^3.13.1",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.0.4",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.1",
+ "progress": "^2.0.0",
+ "regexpp": "^3.1.0",
+ "semver": "^7.2.1",
+ "strip-ansi": "^6.0.0",
+ "strip-json-comments": "^3.1.0",
+ "table": "^6.0.9",
+ "text-table": "^0.2.0",
+ "v8-compile-cache": "^2.0.3"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/eslint-config-prettier": {
+ "version": "8.3.0",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "eslint-config-prettier": "bin/cli.js"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-eslint-plugin": {
+ "version": "3.0.3",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-utils": "^2.1.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-eslint-plugin/node_modules/eslint-utils": {
+ "version": "2.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/eslint-plugin-eslint-plugin/node_modules/eslint-visitor-keys": {
+ "version": "1.3.0",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/eslint-plugin-mocha": {
+ "version": "9.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-utils": "^3.0.0",
+ "ramda": "^0.27.1"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "eslint": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint-scope": {
+ "version": "5.1.1",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^4.1.1"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/eslint-utils": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^2.0.0"
+ },
+ "engines": {
+ "node": "^10.0.0 || ^12.0.0 || >= 14.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ },
+ "peerDependencies": {
+ "eslint": ">=5"
+ }
+ },
+ "node_modules/eslint-visitor-keys": {
+ "version": "2.1.0",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/eslint/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/eslint/node_modules/chalk": {
+ "version": "4.1.1",
+ "dev": true,
+ "license": "MIT",
+ "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/eslint/node_modules/color-convert": {
+ "version": "2.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/eslint/node_modules/color-name": {
+ "version": "1.1.4",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/eslint/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-utils": {
+ "version": "2.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "eslint-visitor-keys": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/eslint/node_modules/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "1.3.0",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/eslint/node_modules/has-flag": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/eslint/node_modules/ignore": {
+ "version": "4.0.6",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/eslint/node_modules/js-yaml": {
+ "version": "3.14.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "esprima": "^4.0.0"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/eslint/node_modules/supports-color": {
+ "version": "7.2.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/espree": {
+ "version": "7.3.1",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "acorn": "^7.4.0",
+ "acorn-jsx": "^5.3.1",
+ "eslint-visitor-keys": "^1.3.0"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/espree/node_modules/eslint-visitor-keys": {
+ "version": "1.3.0",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esprima": {
+ "version": "4.0.1",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "bin": {
+ "esparse": "bin/esparse.js",
+ "esvalidate": "bin/esvalidate.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/esquery": {
+ "version": "1.4.0",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "estraverse": "^5.1.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/esquery/node_modules/estraverse": {
+ "version": "5.2.0",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse": {
+ "version": "4.3.0",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esrecurse/node_modules/estraverse": {
+ "version": "5.2.0",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/estraverse": {
+ "version": "4.3.0",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=4.0"
+ }
+ },
+ "node_modules/esutils": {
+ "version": "2.0.3",
+ "dev": true,
+ "license": "BSD-2-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/etag": {
+ "version": "1.8.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/execa": {
+ "version": "4.1.0",
+ "license": "MIT",
+ "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/express": {
+ "version": "4.17.1",
+ "license": "MIT",
+ "dependencies": {
+ "accepts": "~1.3.7",
+ "array-flatten": "1.1.1",
+ "body-parser": "1.19.0",
+ "content-disposition": "0.5.3",
+ "content-type": "~1.0.4",
+ "cookie": "0.4.0",
+ "cookie-signature": "1.0.6",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "finalhandler": "~1.1.2",
+ "fresh": "0.5.2",
+ "merge-descriptors": "1.0.1",
+ "methods": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "path-to-regexp": "0.1.7",
+ "proxy-addr": "~2.0.5",
+ "qs": "6.7.0",
+ "range-parser": "~1.2.1",
+ "safe-buffer": "5.1.2",
+ "send": "0.17.1",
+ "serve-static": "1.14.1",
+ "setprototypeof": "1.1.1",
+ "statuses": "~1.5.0",
+ "type-is": "~1.6.18",
+ "utils-merge": "1.0.1",
+ "vary": "~1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/express/node_modules/debug": {
+ "version": "2.6.9",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/express/node_modules/depd": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/express/node_modules/ms": {
+ "version": "2.0.0",
+ "license": "MIT"
+ },
+ "node_modules/express/node_modules/path-to-regexp": {
+ "version": "0.1.7",
+ "license": "MIT"
+ },
+ "node_modules/express/node_modules/qs": {
+ "version": "6.7.0",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/express/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "license": "MIT"
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "license": "MIT"
+ },
+ "node_modules/extsprintf": {
+ "version": "1.3.0",
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT"
+ },
+ "node_modules/fast-deep-equal": {
+ "version": "3.1.3",
+ "license": "MIT"
+ },
+ "node_modules/fast-glob": {
+ "version": "3.2.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@nodelib/fs.stat": "^2.0.2",
+ "@nodelib/fs.walk": "^1.2.3",
+ "glob-parent": "^5.1.0",
+ "merge2": "^1.3.0",
+ "micromatch": "^4.0.2",
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/fast-json-stable-stringify": {
+ "version": "2.1.0",
+ "license": "MIT"
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "2.0.6",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/fast-safe-stringify": {
+ "version": "2.0.7",
+ "license": "MIT"
+ },
+ "node_modules/fastq": {
+ "version": "1.11.0",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/filelist": {
+ "version": "1.0.2",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "minimatch": "^3.0.4"
+ }
+ },
+ "node_modules/fill-range": {
+ "version": "7.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/finalhandler": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "on-finished": "~2.3.0",
+ "parseurl": "~1.3.3",
+ "statuses": "~1.5.0",
+ "unpipe": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/finalhandler/node_modules/debug": {
+ "version": "2.6.9",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/finalhandler/node_modules/ms": {
+ "version": "2.0.0",
+ "license": "MIT"
+ },
+ "node_modules/find-cache-dir": {
+ "version": "3.3.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "commondir": "^1.0.1",
+ "make-dir": "^3.0.2",
+ "pkg-dir": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/avajs/find-cache-dir?sponsor=1"
+ }
+ },
+ "node_modules/find-up": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^6.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flat": {
+ "version": "5.0.2",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "bin": {
+ "flat": "cli.js"
+ }
+ },
+ "node_modules/flat-cache": {
+ "version": "3.0.4",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "flatted": "^3.1.0",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/flatted": {
+ "version": "3.1.1",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/foreach": {
+ "version": "2.0.5",
+ "license": "MIT"
+ },
+ "node_modules/foreground-child": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "cross-spawn": "^7.0.0",
+ "signal-exit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/forever-agent": {
+ "version": "0.6.1",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/form-data": {
+ "version": "3.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/formidable": {
+ "version": "1.2.2",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://ko-fi.com/tunnckoCore/commissions"
+ }
+ },
+ "node_modules/forwarded": {
+ "version": "0.2.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fresh": {
+ "version": "0.5.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/fromentries": {
+ "version": "1.3.2",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/fs-extra": {
+ "version": "10.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "graceful-fs": "^4.2.0",
+ "jsonfile": "^6.0.1",
+ "universalify": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "license": "ISC"
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.1",
+ "license": "MIT"
+ },
+ "node_modules/functional-red-black-tree": {
+ "version": "1.0.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/gensync": {
+ "version": "1.0.0-beta.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.1.1",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has": "^1.0.3",
+ "has-symbols": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-package-type": {
+ "version": "0.1.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "5.2.0",
+ "license": "MIT",
+ "dependencies": {
+ "pump": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/getpass": {
+ "version": "0.1.7",
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0"
+ }
+ },
+ "node_modules/glob": {
+ "version": "7.1.7",
+ "license": "ISC",
+ "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.2",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/globalize": {
+ "version": "1.6.0",
+ "license": "MIT",
+ "dependencies": {
+ "cldrjs": "^0.5.4"
+ }
+ },
+ "node_modules/globals": {
+ "version": "13.9.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/globby": {
+ "version": "11.0.3",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-union": "^2.1.0",
+ "dir-glob": "^3.0.1",
+ "fast-glob": "^3.1.1",
+ "ignore": "^5.1.4",
+ "merge2": "^1.3.0",
+ "slash": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.6",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/growl": {
+ "version": "1.10.5",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4.x"
+ }
+ },
+ "node_modules/har-schema": {
+ "version": "2.0.0",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/har-validator": {
+ "version": "5.1.5",
+ "license": "MIT",
+ "dependencies": {
+ "ajv": "^6.12.3",
+ "har-schema": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/has": {
+ "version": "1.0.3",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/has-bigints": {
+ "version": "1.0.1",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasha": {
+ "version": "5.2.2",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-stream": "^2.0.0",
+ "type-fest": "^0.8.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/hasha/node_modules/type-fest": {
+ "version": "0.8.1",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/he": {
+ "version": "1.2.0",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "he": "bin/he"
+ }
+ },
+ "node_modules/header-case": {
+ "version": "2.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "capital-case": "^1.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/html-escaper": {
+ "version": "2.0.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/http-errors": {
+ "version": "1.8.0",
+ "license": "MIT",
+ "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/depd": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/http-errors/node_modules/setprototypeof": {
+ "version": "1.2.0",
+ "license": "ISC"
+ },
+ "node_modules/http-signature": {
+ "version": "1.2.0",
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "jsprim": "^1.2.2",
+ "sshpk": "^1.7.0"
+ },
+ "engines": {
+ "node": ">=0.8",
+ "npm": ">=1.3.7"
+ }
+ },
+ "node_modules/http-status": {
+ "version": "1.5.0",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/http2-client": {
+ "version": "1.3.3",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/human-signals": {
+ "version": "1.1.1",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=8.12.0"
+ }
+ },
+ "node_modules/hyperid": {
+ "version": "2.1.0",
+ "license": "MIT",
+ "dependencies": {
+ "uuid": "^3.4.0",
+ "uuid-parse": "^1.1.0"
+ }
+ },
+ "node_modules/hyperid/node_modules/uuid": {
+ "version": "3.4.0",
+ "license": "MIT",
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.4.24",
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ignore": {
+ "version": "5.1.8",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 4"
+ }
+ },
+ "node_modules/import-fresh": {
+ "version": "3.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "parent-module": "^1.0.0",
+ "resolve-from": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/imurmurhash": {
+ "version": "0.1.4",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.19"
+ }
+ },
+ "node_modules/indent-string": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/inflection": {
+ "version": "1.13.1",
+ "engines": [
+ "node >= 0.4.0"
+ ],
+ "license": "MIT"
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "license": "ISC",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "license": "ISC"
+ },
+ "node_modules/invert-kv": {
+ "version": "3.0.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sindresorhus/invert-kv?sponsor=1"
+ }
+ },
+ "node_modules/ipaddr.js": {
+ "version": "1.9.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/is-arguments": {
+ "version": "1.1.0",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.0.2",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-boolean-object": {
+ "version": "1.1.1",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-buffer": {
+ "version": "1.1.6",
+ "license": "MIT"
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.3",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.0.4",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-map": {
+ "version": "2.0.2",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-negative-zero": {
+ "version": "2.0.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-number-object": {
+ "version": "1.0.5",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "2.1.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-regex": {
+ "version": "1.1.3",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-set": {
+ "version": "2.0.2",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "2.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-string": {
+ "version": "1.0.6",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typed-array": {
+ "version": "1.1.5",
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.2",
+ "call-bind": "^1.0.2",
+ "es-abstract": "^1.18.0-next.2",
+ "foreach": "^2.0.5",
+ "has-symbols": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-typedarray": {
+ "version": "1.0.0",
+ "license": "MIT"
+ },
+ "node_modules/is-unicode-supported": {
+ "version": "0.1.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-weakmap": {
+ "version": "2.0.1",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakset": {
+ "version": "2.0.1",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-windows": {
+ "version": "1.0.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "license": "MIT"
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "license": "ISC"
+ },
+ "node_modules/isstream": {
+ "version": "0.1.2",
+ "license": "MIT"
+ },
+ "node_modules/istanbul-lib-coverage": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-hook": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "append-transform": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-instrument": {
+ "version": "4.0.3",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "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",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/istanbul-lib-processinfo": {
+ "version": "2.0.2",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "archy": "^1.0.0",
+ "cross-spawn": "^7.0.0",
+ "istanbul-lib-coverage": "^3.0.0-alpha.1",
+ "make-dir": "^3.0.0",
+ "p-map": "^3.0.0",
+ "rimraf": "^3.0.0",
+ "uuid": "^3.3.3"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-processinfo/node_modules/uuid": {
+ "version": "3.4.0",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/istanbul-lib-report": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "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",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-report/node_modules/supports-color": {
+ "version": "7.2.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "debug": "^4.1.1",
+ "istanbul-lib-coverage": "^3.0.0",
+ "source-map": "^0.6.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/istanbul-lib-source-maps/node_modules/source-map": {
+ "version": "0.6.1",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/istanbul-reports": {
+ "version": "3.0.2",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "html-escaper": "^2.0.0",
+ "istanbul-lib-report": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/jake": {
+ "version": "10.8.2",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "async": "0.9.x",
+ "chalk": "^2.4.2",
+ "filelist": "^1.0.1",
+ "minimatch": "^3.0.4"
+ },
+ "bin": {
+ "jake": "bin/cli.js"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/jake/node_modules/async": {
+ "version": "0.9.2",
+ "license": "MIT"
+ },
+ "node_modules/js-tokens": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/js-yaml": {
+ "version": "4.1.0",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^2.0.1"
+ },
+ "bin": {
+ "js-yaml": "bin/js-yaml.js"
+ }
+ },
+ "node_modules/js-yaml/node_modules/argparse": {
+ "version": "2.0.1",
+ "license": "Python-2.0"
+ },
+ "node_modules/js2xmlparser": {
+ "version": "4.0.1",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "xmlcreate": "^2.0.3"
+ }
+ },
+ "node_modules/jsbn": {
+ "version": "0.1.1",
+ "license": "MIT"
+ },
+ "node_modules/jsesc": {
+ "version": "2.5.2",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "jsesc": "bin/jsesc"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/json-merge-patch": {
+ "version": "1.0.1",
+ "license": "MIT",
+ "dependencies": {
+ "deep-equal": "^2.0.3"
+ }
+ },
+ "node_modules/json-schema": {
+ "version": "0.2.3"
+ },
+ "node_modules/json-schema-compare": {
+ "version": "0.2.2",
+ "license": "MIT",
+ "dependencies": {
+ "lodash": "^4.17.4"
+ }
+ },
+ "node_modules/json-schema-traverse": {
+ "version": "0.4.1",
+ "license": "MIT"
+ },
+ "node_modules/json-stable-stringify-without-jsonify": {
+ "version": "1.0.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/json-stringify-safe": {
+ "version": "5.0.1",
+ "license": "ISC"
+ },
+ "node_modules/json5": {
+ "version": "2.2.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "bin": {
+ "json5": "lib/cli.js"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/jsonfile": {
+ "version": "6.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "universalify": "^2.0.0"
+ },
+ "optionalDependencies": {
+ "graceful-fs": "^4.1.6"
+ }
+ },
+ "node_modules/jsonpath-plus": {
+ "version": "1.1.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/jsprim": {
+ "version": "1.4.1",
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "1.0.0",
+ "extsprintf": "1.3.0",
+ "json-schema": "0.2.3",
+ "verror": "1.10.0"
+ }
+ },
+ "node_modules/just-extend": {
+ "version": "4.2.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lcid": {
+ "version": "3.1.1",
+ "license": "MIT",
+ "dependencies": {
+ "invert-kv": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/levn": {
+ "version": "0.4.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1",
+ "type-check": "~0.4.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/locate-path": {
+ "version": "6.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "license": "MIT"
+ },
+ "node_modules/lodash.clonedeep": {
+ "version": "4.5.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.flattendeep": {
+ "version": "4.4.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.get": {
+ "version": "4.4.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.merge": {
+ "version": "4.6.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.truncate": {
+ "version": "4.4.2",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/log-symbols": {
+ "version": "4.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chalk": "^4.1.0",
+ "is-unicode-supported": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/log-symbols/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/log-symbols/node_modules/chalk": {
+ "version": "4.1.1",
+ "dev": true,
+ "license": "MIT",
+ "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/log-symbols/node_modules/color-convert": {
+ "version": "2.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/log-symbols/node_modules/color-name": {
+ "version": "1.1.4",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/log-symbols/node_modules/has-flag": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/log-symbols/node_modules/supports-color": {
+ "version": "7.2.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/loopback-connector": {
+ "version": "5.0.1",
+ "license": "MIT",
+ "dependencies": {
+ "async": "^3.2.0",
+ "bluebird": "^3.7.2",
+ "debug": "^4.1.1",
+ "msgpack5": "^4.2.0",
+ "strong-globalize": "^6.0.4",
+ "uuid": "^8.3.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/loopback-connector-rest": {
+ "version": "3.7.0",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.1.0",
+ "jsonpath-plus": "^1.1.0",
+ "lodash": "^4.17.11",
+ "methods": "^1.1.1",
+ "mime": "^2.3.1",
+ "qs": "^6.1.0",
+ "request": "^2.53.0",
+ "strong-globalize": "^5.0.5",
+ "traverse": "^0.6.6"
+ },
+ "engines": {
+ "node": ">=8.9"
+ }
+ },
+ "node_modules/loopback-connector-rest/node_modules/mime": {
+ "version": "2.5.2",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/loopback-connector-rest/node_modules/mkdirp": {
+ "version": "0.5.5",
+ "license": "MIT",
+ "dependencies": {
+ "minimist": "^1.2.5"
+ },
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ }
+ },
+ "node_modules/loopback-connector-rest/node_modules/strong-globalize": {
+ "version": "5.1.0",
+ "license": "Artistic-2.0",
+ "dependencies": {
+ "accept-language": "^3.0.18",
+ "debug": "^4.1.1",
+ "globalize": "^1.5.0",
+ "lodash": "^4.17.15",
+ "md5": "^2.2.1",
+ "mkdirp": "^0.5.5",
+ "os-locale": "^5.0.0",
+ "yamljs": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=8.9"
+ }
+ },
+ "node_modules/loopback-datasource-juggler": {
+ "version": "4.26.0",
+ "license": "MIT",
+ "dependencies": {
+ "async": "^3.1.0",
+ "change-case": "^4.1.1",
+ "debug": "^4.1.0",
+ "depd": "^2.0.0",
+ "inflection": "^1.6.0",
+ "lodash": "^4.17.11",
+ "loopback-connector": "^5.0.0",
+ "minimatch": "^3.0.3",
+ "qs": "^6.5.0",
+ "shortid": "^2.2.6",
+ "strong-globalize": "^6.0.5",
+ "traverse": "^0.6.6",
+ "uuid": "^8.3.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/lower-case": {
+ "version": "2.0.2",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/lru-cache": {
+ "version": "6.0.0",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "yallist": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/make-dir": {
+ "version": "3.1.0",
+ "dev": true,
+ "license": "MIT",
+ "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",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/map-age-cleaner": {
+ "version": "0.1.3",
+ "license": "MIT",
+ "dependencies": {
+ "p-defer": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/md5": {
+ "version": "2.3.0",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "charenc": "0.0.2",
+ "crypt": "0.0.2",
+ "is-buffer": "~1.1.6"
+ }
+ },
+ "node_modules/media-typer": {
+ "version": "0.3.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mem": {
+ "version": "5.1.1",
+ "license": "MIT",
+ "dependencies": {
+ "map-age-cleaner": "^0.1.3",
+ "mimic-fn": "^2.1.0",
+ "p-is-promise": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/merge-descriptors": {
+ "version": "1.0.1",
+ "license": "MIT"
+ },
+ "node_modules/merge-stream": {
+ "version": "2.0.0",
+ "license": "MIT"
+ },
+ "node_modules/merge2": {
+ "version": "1.4.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/methods": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.4",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "braces": "^3.0.1",
+ "picomatch": "^2.2.3"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/mime": {
+ "version": "1.6.0",
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/mime-db": {
+ "version": "1.48.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mime-types": {
+ "version": "2.1.31",
+ "license": "MIT",
+ "dependencies": {
+ "mime-db": "1.48.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/mimic-fn": {
+ "version": "2.1.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.0.4",
+ "license": "ISC",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.5",
+ "license": "MIT"
+ },
+ "node_modules/mkdirp": {
+ "version": "1.0.4",
+ "license": "MIT",
+ "bin": {
+ "mkdirp": "bin/cmd.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/mocha": {
+ "version": "9.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@ungap/promise-all-settled": "1.1.2",
+ "ansi-colors": "4.1.1",
+ "browser-stdout": "1.3.1",
+ "chokidar": "3.5.1",
+ "debug": "4.3.1",
+ "diff": "5.0.0",
+ "escape-string-regexp": "4.0.0",
+ "find-up": "5.0.0",
+ "glob": "7.1.7",
+ "growl": "1.10.5",
+ "he": "1.2.0",
+ "js-yaml": "4.1.0",
+ "log-symbols": "4.1.0",
+ "minimatch": "3.0.4",
+ "ms": "2.1.3",
+ "nanoid": "3.1.23",
+ "serialize-javascript": "5.0.1",
+ "strip-json-comments": "3.1.1",
+ "supports-color": "8.1.1",
+ "which": "2.0.2",
+ "wide-align": "1.1.3",
+ "workerpool": "6.1.4",
+ "yargs": "16.2.0",
+ "yargs-parser": "20.2.4",
+ "yargs-unparser": "2.0.0"
+ },
+ "bin": {
+ "_mocha": "bin/_mocha",
+ "mocha": "bin/mocha"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/mochajs"
+ }
+ },
+ "node_modules/mocha/node_modules/escape-string-regexp": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/mocha/node_modules/has-flag": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/mocha/node_modules/ms": {
+ "version": "2.1.3",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/mocha/node_modules/nanoid": {
+ "version": "3.1.23",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/mocha/node_modules/supports-color": {
+ "version": "8.1.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/supports-color?sponsor=1"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "license": "MIT"
+ },
+ "node_modules/msgpack5": {
+ "version": "4.5.1",
+ "license": "MIT",
+ "dependencies": {
+ "bl": "^2.0.1",
+ "inherits": "^2.0.3",
+ "readable-stream": "^2.3.6",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "node_modules/nanoid": {
+ "version": "2.1.11",
+ "license": "MIT"
+ },
+ "node_modules/natural-compare": {
+ "version": "1.4.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/negotiator": {
+ "version": "0.6.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/nise": {
+ "version": "5.1.0",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@sinonjs/commons": "^1.7.0",
+ "@sinonjs/fake-timers": "^7.0.4",
+ "@sinonjs/text-encoding": "^0.7.1",
+ "just-extend": "^4.0.2",
+ "path-to-regexp": "^1.7.0"
+ }
+ },
+ "node_modules/nise/node_modules/isarray": {
+ "version": "0.0.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nise/node_modules/path-to-regexp": {
+ "version": "1.8.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "isarray": "0.0.1"
+ }
+ },
+ "node_modules/no-case": {
+ "version": "3.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "lower-case": "^2.0.2",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/node-fetch-h2": {
+ "version": "2.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "http2-client": "^1.2.5"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ }
+ },
+ "node_modules/node-preload": {
+ "version": "0.2.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "process-on-spawn": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/node-releases": {
+ "version": "1.1.73",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/npm-run-path": {
+ "version": "4.0.1",
+ "license": "MIT",
+ "dependencies": {
+ "path-key": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nyc": {
+ "version": "15.1.0",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@istanbuljs/load-nyc-config": "^1.0.0",
+ "@istanbuljs/schema": "^0.1.2",
+ "caching-transform": "^4.0.0",
+ "convert-source-map": "^1.7.0",
+ "decamelize": "^1.2.0",
+ "find-cache-dir": "^3.2.0",
+ "find-up": "^4.1.0",
+ "foreground-child": "^2.0.0",
+ "get-package-type": "^0.1.0",
+ "glob": "^7.1.6",
+ "istanbul-lib-coverage": "^3.0.0",
+ "istanbul-lib-hook": "^3.0.0",
+ "istanbul-lib-instrument": "^4.0.0",
+ "istanbul-lib-processinfo": "^2.0.2",
+ "istanbul-lib-report": "^3.0.0",
+ "istanbul-lib-source-maps": "^4.0.0",
+ "istanbul-reports": "^3.0.2",
+ "make-dir": "^3.0.0",
+ "node-preload": "^0.2.1",
+ "p-map": "^3.0.0",
+ "process-on-spawn": "^1.0.0",
+ "resolve-from": "^5.0.0",
+ "rimraf": "^3.0.0",
+ "signal-exit": "^3.0.2",
+ "spawn-wrap": "^2.0.0",
+ "test-exclude": "^6.0.0",
+ "yargs": "^15.0.2"
+ },
+ "bin": {
+ "nyc": "bin/nyc.js"
+ },
+ "engines": {
+ "node": ">=8.9"
+ }
+ },
+ "node_modules/nyc/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/nyc/node_modules/camelcase": {
+ "version": "5.3.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/nyc/node_modules/cliui": {
+ "version": "6.0.0",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^6.2.0"
+ }
+ },
+ "node_modules/nyc/node_modules/color-convert": {
+ "version": "2.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/nyc/node_modules/color-name": {
+ "version": "1.1.4",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nyc/node_modules/decamelize": {
+ "version": "1.2.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/nyc/node_modules/find-up": {
+ "version": "4.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^5.0.0",
+ "path-exists": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nyc/node_modules/locate-path": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nyc/node_modules/p-limit": {
+ "version": "2.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/nyc/node_modules/p-locate": {
+ "version": "4.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nyc/node_modules/resolve-from": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nyc/node_modules/wrap-ansi": {
+ "version": "6.2.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/nyc/node_modules/y18n": {
+ "version": "4.0.3",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/nyc/node_modules/yargs": {
+ "version": "15.4.1",
+ "dev": true,
+ "license": "MIT",
+ "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/nyc/node_modules/yargs-parser": {
+ "version": "18.1.3",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "camelcase": "^5.0.0",
+ "decamelize": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/oas-kit-common": {
+ "version": "1.0.8",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "fast-safe-stringify": "^2.0.7"
+ }
+ },
+ "node_modules/oas-linter": {
+ "version": "3.2.2",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@exodus/schemasafe": "^1.0.0-rc.2",
+ "should": "^13.2.1",
+ "yaml": "^1.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oas-resolver": {
+ "version": "2.5.5",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "node-fetch-h2": "^2.3.0",
+ "oas-kit-common": "^1.0.8",
+ "reftools": "^1.1.8",
+ "yaml": "^1.10.0",
+ "yargs": "^17.0.1"
+ },
+ "bin": {
+ "resolve": "resolve.js"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oas-resolver/node_modules/yargs": {
+ "version": "17.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ }
+ },
+ "node_modules/oas-schema-walker": {
+ "version": "1.1.5",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oas-validator": {
+ "version": "5.0.6",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "call-me-maybe": "^1.0.1",
+ "oas-kit-common": "^1.0.8",
+ "oas-linter": "^3.2.2",
+ "oas-resolver": "^2.5.5",
+ "oas-schema-walker": "^1.1.5",
+ "reftools": "^1.1.8",
+ "should": "^13.2.1",
+ "yaml": "^1.10.0"
+ },
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/oauth-sign": {
+ "version": "0.9.0",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "4.1.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.10.3",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-is": {
+ "version": "1.1.5",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.2",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "define-properties": "^1.1.3",
+ "has-symbols": "^1.0.1",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/on-finished": {
+ "version": "2.3.0",
+ "license": "MIT",
+ "dependencies": {
+ "ee-first": "1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "license": "ISC",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/onetime": {
+ "version": "5.1.2",
+ "license": "MIT",
+ "dependencies": {
+ "mimic-fn": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/openapi3-ts": {
+ "version": "2.0.1",
+ "license": "MIT",
+ "dependencies": {
+ "yaml": "^1.10.0"
+ }
+ },
+ "node_modules/optionator": {
+ "version": "0.9.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "deep-is": "^0.1.3",
+ "fast-levenshtein": "^2.0.6",
+ "levn": "^0.4.1",
+ "prelude-ls": "^1.2.1",
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.3"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/os-locale": {
+ "version": "5.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "execa": "^4.0.0",
+ "lcid": "^3.0.0",
+ "mem": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-defer": {
+ "version": "1.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-event": {
+ "version": "4.2.0",
+ "license": "MIT",
+ "dependencies": {
+ "p-timeout": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-finally": {
+ "version": "1.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/p-is-promise": {
+ "version": "2.1.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/p-limit": {
+ "version": "3.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-locate": {
+ "version": "5.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^3.0.2"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/p-map": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "aggregate-error": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-timeout": {
+ "version": "3.2.0",
+ "license": "MIT",
+ "dependencies": {
+ "p-finally": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/p-try": {
+ "version": "2.2.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/package-hash": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "graceful-fs": "^4.1.15",
+ "hasha": "^5.0.0",
+ "lodash.flattendeep": "^4.4.0",
+ "release-zalgo": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/param-case": {
+ "version": "3.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/parent-module": {
+ "version": "1.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "callsites": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/parseurl": {
+ "version": "1.3.3",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/pascal-case": {
+ "version": "3.1.2",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/path-case": {
+ "version": "3.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/path-exists": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-key": {
+ "version": "3.1.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/path-to-regexp": {
+ "version": "6.2.0",
+ "license": "MIT"
+ },
+ "node_modules/path-type": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "license": "MIT"
+ },
+ "node_modules/pg": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/pg/-/pg-8.18.0.tgz",
+ "integrity": "sha512-xqrUDL1b9MbkydY/s+VZ6v+xiMUmOUk7SS9d/1kpyQxoJ6U9AO1oIJyUWVZojbfe5Cc/oluutcgFG4L9RDP1iQ==",
+ "dependencies": {
+ "pg-connection-string": "^2.11.0",
+ "pg-pool": "^3.11.0",
+ "pg-protocol": "^1.11.0",
+ "pg-types": "2.2.0",
+ "pgpass": "1.0.5"
+ },
+ "engines": {
+ "node": ">= 16.0.0"
+ },
+ "optionalDependencies": {
+ "pg-cloudflare": "^1.3.0"
+ },
+ "peerDependencies": {
+ "pg-native": ">=3.0.1"
+ },
+ "peerDependenciesMeta": {
+ "pg-native": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/pg-cloudflare": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz",
+ "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==",
+ "optional": true
+ },
+ "node_modules/pg-connection-string": {
+ "version": "2.11.0",
+ "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.11.0.tgz",
+ "integrity": "sha512-kecgoJwhOpxYU21rZjULrmrBJ698U2RxXofKVzOn5UDj61BPj/qMb7diYUR1nLScCDbrztQFl1TaQZT0t1EtzQ=="
+ },
+ "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.11.0",
+ "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.11.0.tgz",
+ "integrity": "sha512-MJYfvHwtGp870aeusDh+hg9apvOe2zmpZJpyt+BMtzUWlVqbhFmMK6bOBXLBUPd7iRtIF9fZplDc7KrPN3PN7w==",
+ "peerDependencies": {
+ "pg": ">=8.0"
+ }
+ },
+ "node_modules/pg-protocol": {
+ "version": "1.11.0",
+ "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.11.0.tgz",
+ "integrity": "sha512-pfsxk2M9M3BuGgDOfuy37VNRRX3jmKgMjcvAcWqNDpZSf4cUmv8HSOl5ViRQFsfARFn0KuUQTgLxVMbNq5NW3g=="
+ },
+ "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.5",
+ "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz",
+ "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==",
+ "dependencies": {
+ "split2": "^4.1.0"
+ }
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/pkg-dir": {
+ "version": "4.2.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pkg-dir/node_modules/find-up": {
+ "version": "4.1.0",
+ "dev": true,
+ "license": "MIT",
+ "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",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^4.1.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/pkg-dir/node_modules/p-limit": {
+ "version": "2.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-try": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/pkg-dir/node_modules/p-locate": {
+ "version": "4.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "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.1",
+ "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz",
+ "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/postgres-date": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz",
+ "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==",
+ "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/prelude-ls": {
+ "version": "1.2.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/prettier": {
+ "version": "2.3.1",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "prettier": "bin-prettier.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "license": "MIT"
+ },
+ "node_modules/process-on-spawn": {
+ "version": "1.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fromentries": "^1.2.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/progress": {
+ "version": "2.0.3",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/proxy-addr": {
+ "version": "2.0.7",
+ "license": "MIT",
+ "dependencies": {
+ "forwarded": "0.2.0",
+ "ipaddr.js": "1.9.1"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/psl": {
+ "version": "1.8.0",
+ "license": "MIT"
+ },
+ "node_modules/pump": {
+ "version": "3.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "end-of-stream": "^1.1.0",
+ "once": "^1.3.1"
+ }
+ },
+ "node_modules/punycode": {
+ "version": "2.1.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/qs": {
+ "version": "6.10.1",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">=0.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/queue-microtask": {
+ "version": "1.2.3",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/ramda": {
+ "version": "0.27.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/randombytes": {
+ "version": "2.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "^5.1.0"
+ }
+ },
+ "node_modules/range-parser": {
+ "version": "1.2.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body": {
+ "version": "2.4.0",
+ "license": "MIT",
+ "dependencies": {
+ "bytes": "3.1.0",
+ "http-errors": "1.7.2",
+ "iconv-lite": "0.4.24",
+ "unpipe": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/raw-body/node_modules/depd": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body/node_modules/http-errors": {
+ "version": "1.7.2",
+ "license": "MIT",
+ "dependencies": {
+ "depd": "~1.1.2",
+ "inherits": "2.0.3",
+ "setprototypeof": "1.1.1",
+ "statuses": ">= 1.5.0 < 2",
+ "toidentifier": "1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/raw-body/node_modules/inherits": {
+ "version": "2.0.3",
+ "license": "ISC"
+ },
+ "node_modules/readable-stream": {
+ "version": "2.3.7",
+ "license": "MIT",
+ "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/readable-stream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "license": "MIT"
+ },
+ "node_modules/readdirp": {
+ "version": "3.5.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/reflect-metadata": {
+ "version": "0.1.13",
+ "license": "Apache-2.0"
+ },
+ "node_modules/reftools": {
+ "version": "1.1.8",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "funding": {
+ "url": "https://github.com/Mermade/oas-kit?sponsor=1"
+ }
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.3.1",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/regexpp": {
+ "version": "3.1.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/mysticatea"
+ }
+ },
+ "node_modules/release-zalgo": {
+ "version": "1.0.0",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "es6-error": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/request": {
+ "version": "2.88.2",
+ "license": "Apache-2.0",
+ "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/node_modules/form-data": {
+ "version": "2.3.3",
+ "license": "MIT",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.6",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 0.12"
+ }
+ },
+ "node_modules/request/node_modules/qs": {
+ "version": "6.5.2",
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/request/node_modules/uuid": {
+ "version": "3.4.0",
+ "license": "MIT",
+ "bin": {
+ "uuid": "bin/uuid"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/require-main-filename": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/resolve-from": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "3.0.2",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/run-parallel": {
+ "version": "1.2.0",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "queue-microtask": "^1.2.2"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "license": "MIT"
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "license": "MIT"
+ },
+ "node_modules/semver": {
+ "version": "7.3.5",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "lru-cache": "^6.0.0"
+ },
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/send": {
+ "version": "0.17.1",
+ "license": "MIT",
+ "dependencies": {
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "destroy": "~1.0.4",
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "http-errors": "~1.7.2",
+ "mime": "1.6.0",
+ "ms": "2.1.1",
+ "on-finished": "~2.3.0",
+ "range-parser": "~1.2.1",
+ "statuses": "~1.5.0"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/send/node_modules/debug": {
+ "version": "2.6.9",
+ "license": "MIT",
+ "dependencies": {
+ "ms": "2.0.0"
+ }
+ },
+ "node_modules/send/node_modules/debug/node_modules/ms": {
+ "version": "2.0.0",
+ "license": "MIT"
+ },
+ "node_modules/send/node_modules/depd": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/send/node_modules/http-errors": {
+ "version": "1.7.3",
+ "license": "MIT",
+ "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/send/node_modules/ms": {
+ "version": "2.1.1",
+ "license": "MIT"
+ },
+ "node_modules/sentence-case": {
+ "version": "3.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "no-case": "^3.0.4",
+ "tslib": "^2.0.3",
+ "upper-case-first": "^2.0.2"
+ }
+ },
+ "node_modules/serialize-javascript": {
+ "version": "5.0.1",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "randombytes": "^2.1.0"
+ }
+ },
+ "node_modules/serve-static": {
+ "version": "1.14.1",
+ "license": "MIT",
+ "dependencies": {
+ "encodeurl": "~1.0.2",
+ "escape-html": "~1.0.3",
+ "parseurl": "~1.3.3",
+ "send": "0.17.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/set-blocking": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/setprototypeof": {
+ "version": "1.1.1",
+ "license": "ISC"
+ },
+ "node_modules/shebang-command": {
+ "version": "2.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "shebang-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shebang-regex": {
+ "version": "3.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/shortid": {
+ "version": "2.2.16",
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^2.1.0"
+ }
+ },
+ "node_modules/should": {
+ "version": "13.2.3",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-equal": "^2.0.0",
+ "should-format": "^3.0.3",
+ "should-type": "^1.4.0",
+ "should-type-adaptors": "^1.0.1",
+ "should-util": "^1.0.0"
+ }
+ },
+ "node_modules/should-equal": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-type": "^1.4.0"
+ }
+ },
+ "node_modules/should-format": {
+ "version": "3.0.3",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-type": "^1.3.0",
+ "should-type-adaptors": "^1.0.1"
+ }
+ },
+ "node_modules/should-type": {
+ "version": "1.4.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/should-type-adaptors": {
+ "version": "1.1.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "should-type": "^1.3.0",
+ "should-util": "^1.0.0"
+ }
+ },
+ "node_modules/should-util": {
+ "version": "1.0.1",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.0",
+ "get-intrinsic": "^1.0.2",
+ "object-inspect": "^1.9.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/signal-exit": {
+ "version": "3.0.3",
+ "license": "ISC"
+ },
+ "node_modules/sinon": {
+ "version": "11.1.1",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "@sinonjs/commons": "^1.8.3",
+ "@sinonjs/fake-timers": "^7.1.0",
+ "@sinonjs/samsam": "^6.0.2",
+ "diff": "^5.0.0",
+ "nise": "^5.1.0",
+ "supports-color": "^7.2.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/sinon"
+ }
+ },
+ "node_modules/sinon/node_modules/has-flag": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/sinon/node_modules/supports-color": {
+ "version": "7.2.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slash": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/slice-ansi": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "astral-regex": "^2.0.0",
+ "is-fullwidth-code-point": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/slice-ansi?sponsor=1"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/color-convert": {
+ "version": "2.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/slice-ansi/node_modules/color-name": {
+ "version": "1.1.4",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/snake-case": {
+ "version": "3.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "dot-case": "^3.0.4",
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.5.7",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/source-map-support": {
+ "version": "0.5.19",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "buffer-from": "^1.0.0",
+ "source-map": "^0.6.0"
+ }
+ },
+ "node_modules/source-map-support/node_modules/source-map": {
+ "version": "0.6.1",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/spawn-wrap": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "foreground-child": "^2.0.0",
+ "is-windows": "^1.0.2",
+ "make-dir": "^3.0.0",
+ "rimraf": "^3.0.0",
+ "signal-exit": "^3.0.2",
+ "which": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/split2": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz",
+ "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==",
+ "engines": {
+ "node": ">= 10.x"
+ }
+ },
+ "node_modules/sprintf-js": {
+ "version": "1.0.3",
+ "license": "BSD-3-Clause"
+ },
+ "node_modules/sshpk": {
+ "version": "1.16.1",
+ "license": "MIT",
+ "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/stable": {
+ "version": "0.1.8",
+ "license": "MIT"
+ },
+ "node_modules/statuses": {
+ "version": "1.5.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/stoppable": {
+ "version": "1.1.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=4",
+ "npm": ">=6"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.1.1",
+ "license": "MIT",
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/string_decoder/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "license": "MIT"
+ },
+ "node_modules/string-width": {
+ "version": "4.2.2",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string.prototype.trimend": {
+ "version": "1.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/string.prototype.trimstart": {
+ "version": "1.0.4",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "define-properties": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "6.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-bom": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/strip-final-newline": {
+ "version": "2.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/strip-json-comments": {
+ "version": "3.1.1",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strong-error-handler": {
+ "version": "4.0.0",
+ "license": "MIT",
+ "dependencies": {
+ "@types/express": "^4.16.0",
+ "accepts": "^1.3.3",
+ "debug": "^4.1.1",
+ "ejs": "^3.1.3",
+ "fast-safe-stringify": "^2.0.6",
+ "http-status": "^1.1.2",
+ "js2xmlparser": "^4.0.0",
+ "strong-globalize": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/strong-globalize": {
+ "version": "6.0.5",
+ "license": "Artistic-2.0",
+ "dependencies": {
+ "accept-language": "^3.0.18",
+ "debug": "^4.2.0",
+ "globalize": "^1.6.0",
+ "lodash": "^4.17.20",
+ "md5": "^2.3.0",
+ "mkdirp": "^1.0.4",
+ "os-locale": "^5.0.0",
+ "yamljs": "^0.3.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/superagent": {
+ "version": "6.1.0",
+ "dev": true,
+ "license": "MIT",
+ "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/mime": {
+ "version": "2.5.2",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "mime": "cli.js"
+ },
+ "engines": {
+ "node": ">=4.0.0"
+ }
+ },
+ "node_modules/superagent/node_modules/readable-stream": {
+ "version": "3.6.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/supertest": {
+ "version": "6.1.3",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "methods": "^1.1.2",
+ "superagent": "^6.1.0"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/swagger-ui-dist": {
+ "version": "3.50.0",
+ "license": "Apache-2.0"
+ },
+ "node_modules/table": {
+ "version": "6.7.1",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "ajv": "^8.0.1",
+ "lodash.clonedeep": "^4.5.0",
+ "lodash.truncate": "^4.4.2",
+ "slice-ansi": "^4.0.0",
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/table/node_modules/ajv": {
+ "version": "8.6.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/table/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/test-exclude": {
+ "version": "6.0.0",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "@istanbuljs/schema": "^0.1.2",
+ "glob": "^7.1.4",
+ "minimatch": "^3.0.4"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/text-table": {
+ "version": "0.2.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/to-fast-properties": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/toidentifier": {
+ "version": "1.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.6"
+ }
+ },
+ "node_modules/toposort": {
+ "version": "2.0.2",
+ "license": "MIT"
+ },
+ "node_modules/tough-cookie": {
+ "version": "2.5.0",
+ "license": "BSD-3-Clause",
+ "dependencies": {
+ "psl": "^1.1.28",
+ "punycode": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/traverse": {
+ "version": "0.6.6",
+ "license": "MIT"
+ },
+ "node_modules/tslib": {
+ "version": "2.2.0",
+ "license": "0BSD"
+ },
+ "node_modules/tsutils": {
+ "version": "3.21.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^1.8.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ },
+ "peerDependencies": {
+ "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta"
+ }
+ },
+ "node_modules/tsutils/node_modules/tslib": {
+ "version": "1.14.1",
+ "dev": true,
+ "license": "0BSD"
+ },
+ "node_modules/tunnel-agent": {
+ "version": "0.6.0",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "safe-buffer": "^5.0.1"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/tweetnacl": {
+ "version": "0.14.5",
+ "license": "Unlicense"
+ },
+ "node_modules/type-check": {
+ "version": "0.4.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "prelude-ls": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.8.0"
+ }
+ },
+ "node_modules/type-detect": {
+ "version": "4.0.8",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/type-fest": {
+ "version": "0.20.2",
+ "dev": true,
+ "license": "(MIT OR CC0-1.0)",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/type-is": {
+ "version": "1.6.18",
+ "license": "MIT",
+ "dependencies": {
+ "media-typer": "0.3.0",
+ "mime-types": "~2.1.24"
+ },
+ "engines": {
+ "node": ">= 0.6"
+ }
+ },
+ "node_modules/typedarray-to-buffer": {
+ "version": "3.1.5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-typedarray": "^1.0.0"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "4.3.2",
+ "dev": true,
+ "license": "Apache-2.0",
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=4.2.0"
+ }
+ },
+ "node_modules/unbox-primitive": {
+ "version": "1.0.1",
+ "license": "MIT",
+ "dependencies": {
+ "function-bind": "^1.1.1",
+ "has-bigints": "^1.0.1",
+ "has-symbols": "^1.0.2",
+ "which-boxed-primitive": "^1.0.2"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/universalify": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">= 10.0.0"
+ }
+ },
+ "node_modules/unpipe": {
+ "version": "1.0.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/upper-case": {
+ "version": "2.0.2",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/upper-case-first": {
+ "version": "2.0.2",
+ "license": "MIT",
+ "dependencies": {
+ "tslib": "^2.0.3"
+ }
+ },
+ "node_modules/uri-js": {
+ "version": "4.4.1",
+ "license": "BSD-2-Clause",
+ "dependencies": {
+ "punycode": "^2.1.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "license": "MIT"
+ },
+ "node_modules/utils-merge": {
+ "version": "1.0.1",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "license": "MIT",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/uuid-parse": {
+ "version": "1.1.0",
+ "license": "MIT"
+ },
+ "node_modules/v8-compile-cache": {
+ "version": "2.3.0",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/validator": {
+ "version": "13.6.0",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vary": {
+ "version": "1.1.2",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/verror": {
+ "version": "1.10.0",
+ "engines": [
+ "node >=0.6.0"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "assert-plus": "^1.0.0",
+ "core-util-is": "1.0.2",
+ "extsprintf": "^1.2.0"
+ }
+ },
+ "node_modules/which": {
+ "version": "2.0.2",
+ "license": "ISC",
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "node-which": "bin/node-which"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/which-boxed-primitive": {
+ "version": "1.0.2",
+ "license": "MIT",
+ "dependencies": {
+ "is-bigint": "^1.0.1",
+ "is-boolean-object": "^1.1.0",
+ "is-number-object": "^1.0.4",
+ "is-string": "^1.0.5",
+ "is-symbol": "^1.0.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-collection": {
+ "version": "1.0.1",
+ "license": "MIT",
+ "dependencies": {
+ "is-map": "^2.0.1",
+ "is-set": "^2.0.1",
+ "is-weakmap": "^2.0.1",
+ "is-weakset": "^2.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/which-module": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/which-typed-array": {
+ "version": "1.1.4",
+ "license": "MIT",
+ "dependencies": {
+ "available-typed-arrays": "^1.0.2",
+ "call-bind": "^1.0.0",
+ "es-abstract": "^1.18.0-next.1",
+ "foreach": "^2.0.5",
+ "function-bind": "^1.1.1",
+ "has-symbols": "^1.0.1",
+ "is-typed-array": "^1.1.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/wide-align": {
+ "version": "1.1.3",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^1.0.2 || 2"
+ }
+ },
+ "node_modules/wide-align/node_modules/ansi-regex": {
+ "version": "3.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/wide-align/node_modules/is-fullwidth-code-point": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/wide-align/node_modules/string-width": {
+ "version": "2.1.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "is-fullwidth-code-point": "^2.0.0",
+ "strip-ansi": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/wide-align/node_modules/strip-ansi": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/word-wrap": {
+ "version": "1.2.3",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/workerpool": {
+ "version": "6.1.4",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/color-convert": {
+ "version": "2.0.1",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/color-name": {
+ "version": "1.1.4",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "license": "ISC"
+ },
+ "node_modules/write-file-atomic": {
+ "version": "3.0.3",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "imurmurhash": "^0.1.4",
+ "is-typedarray": "^1.0.0",
+ "signal-exit": "^3.0.2",
+ "typedarray-to-buffer": "^3.1.5"
+ }
+ },
+ "node_modules/xmlcreate": {
+ "version": "2.0.3",
+ "license": "Apache-2.0"
+ },
+ "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": "5.0.8",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yallist": {
+ "version": "4.0.0",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/yaml": {
+ "version": "1.10.2",
+ "license": "ISC",
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/yamljs": {
+ "version": "0.3.0",
+ "license": "MIT",
+ "dependencies": {
+ "argparse": "^1.0.7",
+ "glob": "^7.0.5"
+ },
+ "bin": {
+ "json2yaml": "bin/json2yaml",
+ "yaml2json": "bin/yaml2json"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "16.2.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^7.0.2",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "require-directory": "^2.1.1",
+ "string-width": "^4.2.0",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^20.2.2"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "20.2.4",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs-unparser": {
+ "version": "2.0.0",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "camelcase": "^6.0.0",
+ "decamelize": "^4.0.0",
+ "flat": "^5.0.2",
+ "is-plain-obj": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yocto-queue": {
+ "version": "0.1.0",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ }
+ }
+}
diff --git a/PROD_STAND/POSTGRES/testnode/package.json b/PROD_STAND/POSTGRES/testnode/package.json
new file mode 100644
index 0000000..fa2e5d5
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/package.json
@@ -0,0 +1,69 @@
+{
+ "name": "loopback4-example-github",
+ "version": "0.0.1",
+ "description": "loopback4-example-github",
+ "keywords": [
+ "loopback-application",
+ "loopback"
+ ],
+ "main": "server.js",
+ "engines": {
+ "node": ">=10.16"
+ },
+ "scripts": {
+ "build": "lb-tsc",
+ "build:watch": "lb-tsc --watch",
+ "lint": "npm run eslint && npm run prettier:check",
+ "lint:fix": "npm run eslint:fix && npm run prettier:fix",
+ "prettier:cli": "lb-prettier \"**/*.ts\" \"**/*.js\"",
+ "prettier:check": "npm run prettier:cli -- -l",
+ "prettier:fix": "npm run prettier:cli -- --write",
+ "eslint": "lb-eslint --report-unused-disable-directives .",
+ "eslint:fix": "npm run eslint -- --fix",
+ "pretest": "npm run rebuild",
+ "test": "lb-mocha --allow-console-logs \"dist/__tests__\"",
+ "posttest": "npm run lint",
+ "test:dev": "lb-mocha --allow-console-logs dist/__tests__/**/*.js && npm run posttest",
+ "docker:build": "docker build -t loopback4-example-github .",
+ "docker:run": "docker run -p 3000:3000 -d loopback4-example-github",
+ "premigrate": "npm run build",
+ "migrate": "node ./dist/migrate",
+ "preopenapi-spec": "npm run build",
+ "openapi-spec": "node ./dist/openapi-spec",
+ "start": "node server.js",
+ "clean": "lb-clean dist *.tsbuildinfo .eslintcache",
+ "rebuild": "npm run clean && npm run build"
+ },
+ "repository": {
+ "type": "git",
+ "url": ""
+ },
+ "author": "Diana Lau ",
+ "license": "",
+ "files": [
+ "README.md",
+ "dist",
+ "src",
+ "!*/__tests__"
+ ],
+ "dependencies": {
+ "@loopback/boot": "^3.4.1",
+ "@loopback/core": "^2.16.1",
+ "@loopback/repository": "^3.7.0",
+ "@loopback/rest": "^9.3.1",
+ "@loopback/rest-explorer": "^3.3.1",
+ "@loopback/service-proxy": "^3.2.1",
+ "loopback-connector-rest": "^3.7.0",
+ "pg": "^8.18.0",
+ "tslib": "^2.0.0"
+ },
+ "devDependencies": {
+ "@loopback/build": "^6.4.1",
+ "@loopback/eslint-config": "^10.2.1",
+ "@loopback/testlab": "^3.4.1",
+ "@types/node": "^10.17.60",
+ "eslint": "^7.28.0",
+ "source-map-support": "^0.5.19",
+ "typescript": "~4.3.2"
+ }
+}
diff --git a/PROD_STAND/POSTGRES/testnode/public/index.html b/PROD_STAND/POSTGRES/testnode/public/index.html
new file mode 100644
index 0000000..2b8f97e
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/public/index.html
@@ -0,0 +1,88 @@
+
+
+
+
+ loopback4-example-github
+
+
+
+
+
+
+
+
+
+
+
+
loopback4-example-github
+
Version 1.0.0
+
+
+
+
+
+
+
+
+
diff --git a/PROD_STAND/POSTGRES/testnode/server.js b/PROD_STAND/POSTGRES/testnode/server.js
new file mode 100644
index 0000000..d8c0fea
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/server.js
@@ -0,0 +1,204 @@
+const http = require("http");
+const { URL } = require("url");
+const { Pool } = require("pg");
+
+// Конфигурация Postgres, DATABASE_URL имеет приоритет.
+function buildPgConfig() {
+ if (process.env.DATABASE_URL) {
+ return {
+ connectionString: process.env.DATABASE_URL,
+ ssl: process.env.PGSSLMODE === "require" ? { rejectUnauthorized: false } : undefined,
+ };
+ }
+
+ return {
+ host: process.env.PGHOST,
+ port: Number(process.env.PGPORT || "5432"),
+ user: process.env.PGUSER,
+ password: process.env.PGPASSWORD,
+ database: process.env.PGDATABASE || "postgres",
+ ssl: process.env.PGSSLMODE === "require" ? { rejectUnauthorized: false } : undefined,
+ };
+}
+
+// Общий пул подключений.
+const pool = new Pool(buildPgConfig());
+
+// Таблица для демо создается автоматически.
+async function ensureTable() {
+ await pool.query(
+ "CREATE TABLE IF NOT EXISTS nubes_test_table (id SERIAL PRIMARY KEY, test_data TEXT, created_at TIMESTAMP DEFAULT NOW())"
+ );
+}
+
+// Простой парсер application/x-www-form-urlencoded.
+function parseForm(body) {
+ return body
+ .split("&")
+ .map((pair) => pair.split("="))
+ .reduce((acc, [key, value]) => {
+ acc[decodeURIComponent(key)] = decodeURIComponent((value || "").replace(/\+/g, " "));
+ return acc;
+ }, {});
+}
+
+// Рендер HTML-страницы с CRUD-формами.
+function renderPage(rows, error) {
+ const errorHtml = error ? `${error}
` : "";
+ const rowsHtml = rows
+ .map(
+ (row) => `
+
+ | ${row.id} |
+
+
+ |
+
+
+ |
+
`
+ )
+ .join("");
+
+ return `
+
+
+
+ NodeJS + Postgres Demo
+
+
+
+
+
+
+
+ ${errorHtml}
+
+
+ | ID | Content | Actions |
+
+ ${rowsHtml}
+
+
+
+
+
+`;
+}
+
+// Маршруты: /, /add, /update, /delete, /healthz.
+async function handleRequest(req, res) {
+ const url = new URL(req.url, `http://${req.headers.host}`);
+
+ if (req.method === "GET" && url.pathname === "/healthz") {
+ res.writeHead(200, { "Content-Type": "text/plain" });
+ res.end("ok");
+ return;
+ }
+
+ if (req.method === "GET" && url.pathname === "/") {
+ try {
+ await ensureTable();
+ const { rows } = await pool.query(
+ "SELECT id, test_data FROM nubes_test_table ORDER BY id DESC LIMIT 20"
+ );
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
+ res.end(renderPage(rows));
+ } catch (err) {
+ res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
+ res.end(renderPage([], err.message));
+ }
+ return;
+ }
+
+ if (req.method === "POST" && ["/add", "/update", "/delete"].includes(url.pathname)) {
+ let body = "";
+ req.on("data", (chunk) => {
+ body += chunk;
+ });
+ req.on("end", async () => {
+ const form = parseForm(body);
+ try {
+ await ensureTable();
+ if (url.pathname === "/add") {
+ const content = form.txt_content || "Node did it";
+ // Защита от быстрых дублей подряд.
+ const { rows: lastRows } = await pool.query(
+ "SELECT test_data, created_at FROM nubes_test_table ORDER BY id DESC LIMIT 1"
+ );
+ const last = lastRows[0];
+ const isDuplicate =
+ last &&
+ last.test_data === content &&
+ Date.now() - new Date(last.created_at).getTime() < 3000;
+
+ if (!isDuplicate) {
+ await pool.query("INSERT INTO nubes_test_table (test_data) VALUES ($1)", [content]);
+ }
+ }
+ if (url.pathname === "/update") {
+ await pool.query("UPDATE nubes_test_table SET test_data=$1 WHERE id=$2", [
+ form.txt_content || "",
+ form.id,
+ ]);
+ }
+ if (url.pathname === "/delete") {
+ await pool.query("DELETE FROM nubes_test_table WHERE id=$1", [form.id]);
+ }
+ res.writeHead(303, { Location: "/" });
+ res.end();
+ } catch (err) {
+ res.writeHead(500, { "Content-Type": "text/html; charset=utf-8" });
+ res.end(renderPage([], err.message));
+ }
+ });
+ return;
+ }
+
+ res.writeHead(404, { "Content-Type": "text/plain" });
+ res.end("Not found");
+}
+
+const port = process.env.PORT || 3000;
+const server = http.createServer(handleRequest);
+
+server.listen(port, () => {
+ console.log(`Server running on port ${port}`);
+});
diff --git a/PROD_STAND/POSTGRES/testnode/src/__tests__/README.md b/PROD_STAND/POSTGRES/testnode/src/__tests__/README.md
new file mode 100644
index 0000000..a88f8a5
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/__tests__/README.md
@@ -0,0 +1,3 @@
+# Tests
+
+Please place your tests in this folder.
diff --git a/PROD_STAND/POSTGRES/testnode/src/__tests__/acceptance/home-page.acceptance.ts b/PROD_STAND/POSTGRES/testnode/src/__tests__/acceptance/home-page.acceptance.ts
new file mode 100644
index 0000000..2372b04
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/__tests__/acceptance/home-page.acceptance.ts
@@ -0,0 +1,31 @@
+import {Client} from '@loopback/testlab';
+import {Loopback4ExampleGithubApplication} from '../..';
+import {setupApplication} from './test-helper';
+
+describe('HomePage', () => {
+ let app: Loopback4ExampleGithubApplication;
+ let client: Client;
+
+ before('setupApplication', async () => {
+ ({app, client} = await setupApplication());
+ });
+
+ after(async () => {
+ await app.stop();
+ });
+
+ it('exposes a default home page', async () => {
+ await client
+ .get('/')
+ .expect(200)
+ .expect('Content-Type', /text\/html/);
+ });
+
+ it('exposes self-hosted explorer', async () => {
+ await client
+ .get('/explorer/')
+ .expect(200)
+ .expect('Content-Type', /text\/html/)
+ .expect(/LoopBack API Explorer/);
+ });
+});
diff --git a/PROD_STAND/POSTGRES/testnode/src/__tests__/acceptance/ping.controller.acceptance.ts b/PROD_STAND/POSTGRES/testnode/src/__tests__/acceptance/ping.controller.acceptance.ts
new file mode 100644
index 0000000..3d56b1b
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/__tests__/acceptance/ping.controller.acceptance.ts
@@ -0,0 +1,21 @@
+import {Client, expect} from '@loopback/testlab';
+import {Loopback4ExampleGithubApplication} from '../..';
+import {setupApplication} from './test-helper';
+
+describe('PingController', () => {
+ let app: Loopback4ExampleGithubApplication;
+ let client: Client;
+
+ before('setupApplication', async () => {
+ ({app, client} = await setupApplication());
+ });
+
+ after(async () => {
+ await app.stop();
+ });
+
+ it('invokes GET /ping', async () => {
+ const res = await client.get('/ping?msg=world').expect(200);
+ expect(res.body).to.containEql({greeting: 'Hello from LoopBack'});
+ });
+});
diff --git a/PROD_STAND/POSTGRES/testnode/src/__tests__/acceptance/test-helper.ts b/PROD_STAND/POSTGRES/testnode/src/__tests__/acceptance/test-helper.ts
new file mode 100644
index 0000000..c457c53
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/__tests__/acceptance/test-helper.ts
@@ -0,0 +1,32 @@
+import {Loopback4ExampleGithubApplication} from '../..';
+import {
+ createRestAppClient,
+ givenHttpServerConfig,
+ Client,
+} from '@loopback/testlab';
+
+export async function setupApplication(): Promise {
+ const restConfig = givenHttpServerConfig({
+ // Customize the server configuration here.
+ // Empty values (undefined, '') will be ignored by the helper.
+ //
+ // host: process.env.HOST,
+ // port: +process.env.PORT,
+ });
+
+ const app = new Loopback4ExampleGithubApplication({
+ rest: restConfig,
+ });
+
+ await app.boot();
+ await app.start();
+
+ const client = createRestAppClient(app);
+
+ return {app, client};
+}
+
+export interface AppWithClient {
+ app: Loopback4ExampleGithubApplication;
+ client: Client;
+}
diff --git a/PROD_STAND/POSTGRES/testnode/src/application.ts b/PROD_STAND/POSTGRES/testnode/src/application.ts
new file mode 100644
index 0000000..d803e96
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/application.ts
@@ -0,0 +1,44 @@
+import {BootMixin} from '@loopback/boot';
+import {ApplicationConfig} from '@loopback/core';
+import {
+ RestExplorerBindings,
+ RestExplorerComponent,
+} from '@loopback/rest-explorer';
+import {RepositoryMixin} from '@loopback/repository';
+import {RestApplication} from '@loopback/rest';
+import {ServiceMixin} from '@loopback/service-proxy';
+import path from 'path';
+import {MySequence} from './sequence';
+
+export {ApplicationConfig};
+
+export class Loopback4ExampleGithubApplication extends BootMixin(
+ ServiceMixin(RepositoryMixin(RestApplication)),
+) {
+ constructor(options: ApplicationConfig = {}) {
+ super(options);
+
+ // Подключаем кастомную sequence для обработки запросов.
+ this.sequence(MySequence);
+
+ // Главная страница из папки public.
+ this.static('/', path.join(__dirname, '../public'));
+
+ // Включаем REST Explorer.
+ this.configure(RestExplorerBindings.COMPONENT).to({
+ path: '/explorer',
+ });
+ this.component(RestExplorerComponent);
+
+ this.projectRoot = __dirname;
+ // Настройки автозагрузки контроллеров.
+ this.bootOptions = {
+ controllers: {
+ // Ищем контроллеры в папке controllers.
+ dirs: ['controllers'],
+ extensions: ['.controller.js'],
+ nested: true,
+ },
+ };
+ }
+}
diff --git a/PROD_STAND/POSTGRES/testnode/src/controllers/README.md b/PROD_STAND/POSTGRES/testnode/src/controllers/README.md
new file mode 100644
index 0000000..ad4c4cc
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/controllers/README.md
@@ -0,0 +1,9 @@
+# Controllers
+
+This directory contains source files for the controllers exported by this app.
+
+To add a new empty controller, type in `lb4 controller []` from the
+command-line of your application's root directory.
+
+For more information, please visit
+[Controller generator](http://loopback.io/doc/en/lb4/Controller-generator.html).
diff --git a/PROD_STAND/POSTGRES/testnode/src/controllers/gh-query.controller.ts b/PROD_STAND/POSTGRES/testnode/src/controllers/gh-query.controller.ts
new file mode 100644
index 0000000..a3096ca
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/controllers/gh-query.controller.ts
@@ -0,0 +1,134 @@
+// Uncomment these imports to begin using these cool features!
+
+import {inject} from '@loopback/context';
+import {get, getModelSchemaRef, param} from '@loopback/openapi-v3';
+import {QueryResult, ResultIssueInfo} from '../models';
+import {GhQueryService, IssueInfo, QueryResponse} from '../services';
+
+// import {inject} from '@loopback/core';
+
+
+export class GhQueryController {
+ // inject the GhQueryService service proxy
+ constructor(@inject('services.GhQueryService') protected queryService:GhQueryService) {}
+
+ // create the API that get the issues by providing:
+ // repo: /. For example, `strongloop/loopback-next`
+ // label: If it has special characters, you need to escape it.
+ // For example, if the label is "help wanted", it will be "help+wanted".
+ @get('/issues/repo/{repo}/label/{label}', {
+ responses: {
+ '200': {
+ description: 'Array of GitHub issues info',
+ content: {
+ 'application/json': {
+ schema: getModelSchemaRef(QueryResult)
+ }
+ }
+ }
+ }
+ })
+ async getIssuesByLabel(
+ @param.path.string('repo') repo: string,
+ @param.path.string('label') label:string): Promise {
+ let result:QueryResponse = await this.queryService.getIssuesByLabel(repo, label);
+ let queryResult = new QueryResult();
+ queryResult.items = [];
+ queryResult.total_count = result.body.total_count;
+ result.body.items.forEach(issue => {
+ this.addToResult(issue, queryResult);
+ });
+
+ // check if there is next page of the results
+ const nextLink = this.getNextLink(result.headers.link);
+ if (nextLink == null) return queryResult;
+ await this.getIssueByURL(nextLink, this.queryService, queryResult);
+ return queryResult;
+ }
+
+ /**
+ * Get issues from URL
+ * @param nextLinkURL
+ * @param queryService
+ * @param queryResult
+ * @returns
+ */
+ async getIssueByURL(nextLinkURL: string, queryService: GhQueryService, queryResult:QueryResult) {
+ let result = await queryService.getIssuesByURL(nextLinkURL);
+ result.body.items.forEach(issue => {
+ this.addToResult(issue, queryResult);
+ });
+
+ const nextLink2 = this.getNextLink(result.headers.link);
+ if (nextLink2 == null) return;
+ await this.getIssueByURL(nextLink2, queryService, queryResult);
+ }
+
+ /**
+* Get the URL for the "next" page.
+* The Link header is in the format of:
+* Link: ; rel="next",
+ ; rel="last"
+* @param link
+* @returns
+*/
+getNextLink(link: string): string|null {
+ if (link == undefined) return null;
+
+ let tokens: string[] = link.split(',');
+ let url: string|null = null;
+
+ tokens.forEach(token => {
+ if (token.indexOf('rel="next"')!=-1) {
+ url = token.substring(token.indexOf('<')+1, token.indexOf(';')-1);
+ }
+ });
+
+ return url;
+ }
+ /**
+ * Add the issue to the QueryResult object
+ * @param issue
+ * @param queryResult
+ */
+ addToResult(issue: IssueInfo, queryResult: QueryResult) {
+ let issueInfo:ResultIssueInfo = new ResultIssueInfo();
+ issueInfo.html_url = issue.html_url;
+ issueInfo.title = issue.title;
+ issueInfo.state = issue.state;
+ issueInfo.age = this.getIssueAge(issue.created_at);
+ queryResult.items?.push(issueInfo);
+ }
+ /**
+ * Calculate the age of the issue
+ * i.e. take today's date and find the number of days difference from
+ * the issue creation date
+ * @param created_at
+ * @returns
+ */
+ getIssueAge(created_at: string): number {
+ let todayDate: Date = new Date();
+ let createDate: Date = new Date(created_at);
+ let differenceInTime = todayDate.getTime() - createDate.getTime();
+
+ //get the difference in day
+ return Math.floor(differenceInTime / (1000 * 3600 * 24));
+ }
+}
+
+
+
+// /**
+// * QueryResult
+// */
+// class QueryResult {
+// total_count: number;
+// items: ResultIssueInfo[];
+// }
+
+// class ResultIssueInfo {
+// title: string;
+// html_url: string;
+// state: string;
+// age: number;
+// }
diff --git a/PROD_STAND/POSTGRES/testnode/src/controllers/index.ts b/PROD_STAND/POSTGRES/testnode/src/controllers/index.ts
new file mode 100644
index 0000000..41430f1
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/controllers/index.ts
@@ -0,0 +1,2 @@
+export * from './ping.controller';
+export * from './gh-query.controller';
diff --git a/PROD_STAND/POSTGRES/testnode/src/controllers/ping.controller.ts b/PROD_STAND/POSTGRES/testnode/src/controllers/ping.controller.ts
new file mode 100644
index 0000000..2ff11ed
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/controllers/ping.controller.ts
@@ -0,0 +1,55 @@
+import {inject} from '@loopback/core';
+import {
+ Request,
+ RestBindings,
+ get,
+ response,
+ ResponseObject,
+} from '@loopback/rest';
+
+/**
+ * OpenAPI response for ping()
+ */
+const PING_RESPONSE: ResponseObject = {
+ description: 'Ping Response',
+ content: {
+ 'application/json': {
+ schema: {
+ type: 'object',
+ title: 'PingResponse',
+ properties: {
+ greeting: {type: 'string'},
+ date: {type: 'string'},
+ url: {type: 'string'},
+ headers: {
+ type: 'object',
+ properties: {
+ 'Content-Type': {type: 'string'},
+ },
+ additionalProperties: true,
+ },
+ },
+ },
+ },
+ },
+};
+
+/**
+ * A simple controller to bounce back http requests
+ */
+export class PingController {
+ constructor(@inject(RestBindings.Http.REQUEST) private req: Request) {}
+
+ // Map to `GET /ping`
+ @get('/ping')
+ @response(200, PING_RESPONSE)
+ ping(): object {
+ // Reply with a greeting, the current time, the url, and request headers
+ return {
+ greeting: 'Hello from LoopBack',
+ date: new Date(),
+ url: this.req.url,
+ headers: Object.assign({}, this.req.headers),
+ };
+ }
+}
diff --git a/PROD_STAND/POSTGRES/testnode/src/datasources/README.md b/PROD_STAND/POSTGRES/testnode/src/datasources/README.md
new file mode 100644
index 0000000..57ae382
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/datasources/README.md
@@ -0,0 +1,3 @@
+# Datasources
+
+This directory contains config for datasources used by this app.
diff --git a/PROD_STAND/POSTGRES/testnode/src/datasources/githubds.datasource.ts b/PROD_STAND/POSTGRES/testnode/src/datasources/githubds.datasource.ts
new file mode 100644
index 0000000..a42f7a9
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/datasources/githubds.datasource.ts
@@ -0,0 +1,66 @@
+import {inject, lifeCycleObserver, LifeCycleObserver} from '@loopback/core';
+import {juggler} from '@loopback/repository';
+
+const config = {
+ name: 'githubds',
+ connector: 'rest',
+ baseURL: 'https://api.github.ibm.com',
+ crud: false,
+ options: {
+ headers: {
+ accept: 'application/json',
+ Authorization: process.env.TOKEN,
+ 'User-Agent': 'loopback4-example-github',
+ 'X-RateLimit-Limit': 5000,
+ 'content-type': 'application/json'
+ }
+ },
+ operations: [
+ {
+ template: {
+ method: 'GET',
+ fullResponse: true,
+ url: 'https://api.github.com/search/issues?q=repo:{repo}+label:"{label}"'
+ },
+ functions: {
+ getIssuesByLabel: ['repo','label']
+ }
+ }, {
+ template: {
+ method: 'GET',
+ fullResponse: true,
+ url: '{url}'
+ },
+ functions: {
+ getIssuesByURL: ['url']
+ }
+ }, {
+ template: {
+ method: 'GET',
+ fullResponse: true,
+ url: 'https://api.github.com/search/issues?q=repo:{repo}+{querystring}'
+ },
+ functions: {
+ getIssuesWithQueryString: ['repo','querystring']
+ }
+ }
+ ]
+};
+
+// Observe application's life cycle to disconnect the datasource when
+// application is stopped. This allows the application to be shut down
+// gracefully. The `stop()` method is inherited from `juggler.DataSource`.
+// Learn more at https://loopback.io/doc/en/lb4/Life-cycle.html
+@lifeCycleObserver('datasource')
+export class GithubdsDataSource extends juggler.DataSource
+ implements LifeCycleObserver {
+ static dataSourceName = 'githubds';
+ static readonly defaultConfig = config;
+
+ constructor(
+ @inject('datasources.config.githubds', {optional: true})
+ dsConfig: object = config,
+ ) {
+ super(dsConfig);
+ }
+}
diff --git a/PROD_STAND/POSTGRES/testnode/src/datasources/index.ts b/PROD_STAND/POSTGRES/testnode/src/datasources/index.ts
new file mode 100644
index 0000000..075ed6d
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/datasources/index.ts
@@ -0,0 +1 @@
+export * from './githubds.datasource';
diff --git a/PROD_STAND/POSTGRES/testnode/src/index.ts b/PROD_STAND/POSTGRES/testnode/src/index.ts
new file mode 100644
index 0000000..f7aa6bd
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/index.ts
@@ -0,0 +1,40 @@
+import {ApplicationConfig, Loopback4ExampleGithubApplication} from './application';
+
+export * from './application';
+
+export async function main(options: ApplicationConfig = {}) {
+ // Создаем и запускаем LoopBack приложение.
+ const app = new Loopback4ExampleGithubApplication(options);
+ await app.boot();
+ await app.start();
+
+ const url = app.restServer.url;
+ console.log(`Server is running at ${url}`);
+ console.log(`Try ${url}/ping`);
+
+ return app;
+}
+
+if (require.main === module) {
+ // Локальный запуск с базовой конфигурацией REST.
+ const config = {
+ rest: {
+ port: +(process.env.PORT ?? 3000),
+ host: process.env.HOST,
+ // The `gracePeriodForClose` provides a graceful close for http/https
+ // servers with keep-alive clients. The default value is `Infinity`
+ // (don't force-close). If you want to immediately destroy all sockets
+ // upon stop, set its value to `0`.
+ // See https://www.npmjs.com/package/stoppable
+ gracePeriodForClose: 5000, // 5 seconds
+ openApiSpec: {
+ // useful when used with OpenAPI-to-GraphQL to locate your application
+ setServersFromRequest: true,
+ },
+ },
+ };
+ main(config).catch(err => {
+ console.error('Cannot start the application.', err);
+ process.exit(1);
+ });
+}
diff --git a/PROD_STAND/POSTGRES/testnode/src/migrate.ts b/PROD_STAND/POSTGRES/testnode/src/migrate.ts
new file mode 100644
index 0000000..7c5c806
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/migrate.ts
@@ -0,0 +1,20 @@
+import {Loopback4ExampleGithubApplication} from './application';
+
+export async function migrate(args: string[]) {
+ const existingSchema = args.includes('--rebuild') ? 'drop' : 'alter';
+ console.log('Migrating schemas (%s existing schema)', existingSchema);
+
+ const app = new Loopback4ExampleGithubApplication();
+ await app.boot();
+ await app.migrateSchema({existingSchema});
+
+ // Connectors usually keep a pool of opened connections,
+ // this keeps the process running even after all work is done.
+ // We need to exit explicitly.
+ process.exit(0);
+}
+
+migrate(process.argv).catch(err => {
+ console.error('Cannot migrate database schema', err);
+ process.exit(1);
+});
diff --git a/PROD_STAND/POSTGRES/testnode/src/models/README.md b/PROD_STAND/POSTGRES/testnode/src/models/README.md
new file mode 100644
index 0000000..f5ea972
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/models/README.md
@@ -0,0 +1,3 @@
+# Models
+
+This directory contains code for models provided by this app.
diff --git a/PROD_STAND/POSTGRES/testnode/src/models/index.ts b/PROD_STAND/POSTGRES/testnode/src/models/index.ts
new file mode 100644
index 0000000..7691854
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/models/index.ts
@@ -0,0 +1,2 @@
+export * from './query-result.model';
+export * from './result-issue-info.model';
diff --git a/PROD_STAND/POSTGRES/testnode/src/models/query-result.model.ts b/PROD_STAND/POSTGRES/testnode/src/models/query-result.model.ts
new file mode 100644
index 0000000..e0193c7
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/models/query-result.model.ts
@@ -0,0 +1,24 @@
+import {Model, model, property} from '@loopback/repository';
+import {ResultIssueInfo} from './result-issue-info.model';
+
+@model()
+export class QueryResult extends Model {
+ @property({
+ type: 'number',
+ })
+ total_count?: number;
+
+ @property.array(ResultIssueInfo)
+ items?: ResultIssueInfo[];
+
+
+ constructor(data?: Partial) {
+ super(data);
+ }
+}
+
+export interface QueryResultRelations {
+ // describe navigational properties here
+}
+
+export type QueryResultWithRelations = QueryResult & QueryResultRelations;
diff --git a/PROD_STAND/POSTGRES/testnode/src/models/result-issue-info.model.ts b/PROD_STAND/POSTGRES/testnode/src/models/result-issue-info.model.ts
new file mode 100644
index 0000000..3343f1a
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/models/result-issue-info.model.ts
@@ -0,0 +1,35 @@
+import {Model, model, property} from '@loopback/repository';
+
+@model()
+export class ResultIssueInfo extends Model {
+ @property({
+ type: 'string',
+ })
+ title?: string;
+
+ @property({
+ type: 'string',
+ })
+ html_url?: string;
+
+ @property({
+ type: 'string',
+ })
+ state?: string;
+
+ @property({
+ type: 'number',
+ })
+ age?: number;
+
+
+ constructor(data?: Partial) {
+ super(data);
+ }
+}
+
+export interface ResultIssueInfoRelations {
+ // describe navigational properties here
+}
+
+export type ResultIssueInfoWithRelations = ResultIssueInfo & ResultIssueInfoRelations;
diff --git a/PROD_STAND/POSTGRES/testnode/src/openapi-spec.ts b/PROD_STAND/POSTGRES/testnode/src/openapi-spec.ts
new file mode 100644
index 0000000..e525841
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/openapi-spec.ts
@@ -0,0 +1,23 @@
+import {ApplicationConfig} from '@loopback/core';
+import {Loopback4ExampleGithubApplication} from './application';
+
+/**
+ * Export the OpenAPI spec from the application
+ */
+async function exportOpenApiSpec(): Promise {
+ const config: ApplicationConfig = {
+ rest: {
+ port: +(process.env.PORT ?? 3000),
+ host: process.env.HOST ?? 'localhost',
+ },
+ };
+ const outFile = process.argv[2] ?? '';
+ const app = new Loopback4ExampleGithubApplication(config);
+ await app.boot();
+ await app.exportOpenApiSpec(outFile);
+}
+
+exportOpenApiSpec().catch(err => {
+ console.error('Fail to export OpenAPI spec from the application.', err);
+ process.exit(1);
+});
diff --git a/PROD_STAND/POSTGRES/testnode/src/repositories/README.md b/PROD_STAND/POSTGRES/testnode/src/repositories/README.md
new file mode 100644
index 0000000..08638a7
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/repositories/README.md
@@ -0,0 +1,3 @@
+# Repositories
+
+This directory contains code for repositories provided by this app.
diff --git a/PROD_STAND/POSTGRES/testnode/src/sequence.ts b/PROD_STAND/POSTGRES/testnode/src/sequence.ts
new file mode 100644
index 0000000..30b28d6
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/sequence.ts
@@ -0,0 +1,4 @@
+import {MiddlewareSequence} from '@loopback/rest';
+
+// Стандартная sequence без кастомной логики.
+export class MySequence extends MiddlewareSequence {}
diff --git a/PROD_STAND/POSTGRES/testnode/src/services/gh-query-service.service.ts b/PROD_STAND/POSTGRES/testnode/src/services/gh-query-service.service.ts
new file mode 100644
index 0000000..99e0e25
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/services/gh-query-service.service.ts
@@ -0,0 +1,45 @@
+import {inject, Provider} from '@loopback/core';
+import {getService} from '@loopback/service-proxy';
+import {GithubdsDataSource} from '../datasources';
+
+export interface GhQueryService {
+ // this is where you define the Node.js methods that will be
+ // mapped to REST/SOAP/gRPC operations as stated in the datasource
+ // json file.
+
+ // Add the three methods here.
+ // Make sure the function names and the parameter names matches
+ // the ones you defined in the datasource
+ getIssuesByLabel(repo: string, label: string): Promise;
+ getIssuesByURL(url: string): Promise;
+ getIssuesWithQueryString(repo:string, querystring: string): Promise;
+}
+
+export interface QueryResponse {
+ headers: any;
+ body: QueryResponseBody;
+}
+export interface QueryResponseBody {
+ total_count: number;
+ items: IssueInfo[];
+}
+
+export class IssueInfo {
+ title: string;
+ html_url: string;
+ state: string;
+ created_at: string;
+}
+
+
+export class GhQueryServiceProvider implements Provider {
+ constructor(
+ // githubds must match the name property in the datasource json file
+ @inject('datasources.githubds')
+ protected dataSource: GithubdsDataSource = new GithubdsDataSource(),
+ ) {}
+
+ value(): Promise {
+ return getService(this.dataSource);
+ }
+}
diff --git a/PROD_STAND/POSTGRES/testnode/src/services/index.ts b/PROD_STAND/POSTGRES/testnode/src/services/index.ts
new file mode 100644
index 0000000..52b6336
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/src/services/index.ts
@@ -0,0 +1 @@
+export * from './gh-query-service.service';
diff --git a/PROD_STAND/POSTGRES/testnode/tsconfig.json b/PROD_STAND/POSTGRES/testnode/tsconfig.json
new file mode 100644
index 0000000..c7b8e49
--- /dev/null
+++ b/PROD_STAND/POSTGRES/testnode/tsconfig.json
@@ -0,0 +1,9 @@
+{
+ "$schema": "http://json.schemastore.org/tsconfig",
+ "extends": "@loopback/build/config/tsconfig.common.json",
+ "compilerOptions": {
+ "outDir": "dist",
+ "rootDir": "src"
+ },
+ "include": ["src"]
+}
diff --git a/PROD_STAND/RABBIT/main.tf b/PROD_STAND/RABBIT/main.tf
new file mode 100644
index 0000000..dc450fc
--- /dev/null
+++ b/PROD_STAND/RABBIT/main.tf
@@ -0,0 +1,22 @@
+// Фиксируем провайдер и версию, чтобы поведение было стабильным.
+terraform {
+ required_providers {
+ nubes = {
+ source = "terra.k8c.ru/nubes/nubes"
+ version = "2.1.10"
+ }
+ }
+}
+
+// Провайдер Nubes для создания ресурсов.
+provider "nubes" {
+ api_token = var.api_token
+ api_endpoint = "https://deck-api.ngcloud.ru/api/v1/index.cfm"
+}
+
+// Токен доступа к Nubes API.
+variable "api_token" {
+ type = string
+ sensitive = true
+ description = "Nubes API token"
+}
diff --git a/PROD_STAND/RABBIT/rabbit-lsd/Application.cfc b/PROD_STAND/RABBIT/rabbit-lsd/Application.cfc
new file mode 100644
index 0000000..5639a44
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-lsd/Application.cfc
@@ -0,0 +1,209 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ CREATE TABLE IF NOT EXISTS #request.tableName# (id SERIAL PRIMARY KEY, test_data TEXT, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)
+
+
+
+
+
+
+
+ CREATE TABLE IF NOT EXISTS #request.logTableName# (
+ id SERIAL PRIMARY KEY,
+ action TEXT NOT NULL,
+ text TEXT,
+ request_id TEXT,
+ target_id INTEGER,
+ queued_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+ processed_at TIMESTAMP,
+ status TEXT DEFAULT 'queued',
+ error_reason TEXT
+ )
+
+
+ ALTER TABLE #request.logTableName# ADD COLUMN IF NOT EXISTS error_reason TEXT
+
+
+ UPDATE #request.logTableName#
+ SET processed_at = NOW(), status = 'done'
+ WHERE status = 'queued'
+ AND action IN ('create','update')
+ AND request_id IS NOT NULL
+ AND EXISTS (
+ SELECT 1 FROM #request.tableName#
+ WHERE test_data LIKE '%' || '[req:' || request_id || ']%'
+ )
+
+
+ UPDATE #request.logTableName#
+ SET processed_at = NOW(), status = 'done'
+ WHERE status = 'queued'
+ AND action = 'delete'
+ AND target_id IS NOT NULL
+ AND NOT EXISTS (
+ SELECT 1 FROM #request.tableName# WHERE id = target_id
+ )
+
+
+ UPDATE #request.logTableName#
+ SET status = 'failed', error_reason = 'target not found'
+ WHERE status = 'queued'
+ AND action = 'update'
+ AND target_id IS NOT NULL
+ AND NOT EXISTS (
+ SELECT 1 FROM #request.tableName# WHERE id = target_id
+ )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ INSERT INTO #request.logTableName# (action, text, request_id, target_id, queued_at, status)
+ VALUES (
+ ,
+ ,
+ ,
+ ,
+ NOW(),
+ 'queued'
+ )
+
+
+
+
+
+
+
+
+
+
+
diff --git a/PROD_STAND/RABBIT/rabbit-lsd/README.md b/PROD_STAND/RABBIT/rabbit-lsd/README.md
new file mode 100644
index 0000000..cf8802f
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-lsd/README.md
@@ -0,0 +1,45 @@
+# Lucee UI for Rabbit CRUD
+
+UI publishes CRUD actions to RabbitMQ and reads results from Postgres.
+
+Коротко: интерфейс пишет в RabbitMQ, а фактическое состояние берет из Postgres, чтобы показать разницу между "поставлено в очередь" и "исполнено".
+
+## Behavior
+
+- Insert/Update/Delete actions are queued via RabbitMQ.
+- A status banner shows when the action was queued and when it appears in Postgres.
+- The UI reads the latest rows from the table defined by `PG_TABLE`.
+
+## Environment variables
+
+Lucee datasource (required):
+- `testds_connectionString`
+- `testds_username`
+- `testds_password`
+- `testds_class` (org.postgresql.Driver)
+- `testds_bundleName` (org.postgresql.jdbc)
+- `testds_bundleVersion` (42.6.0)
+- `testds_connectionLimit` (5)
+- `testds_liveTimeout` (15)
+- `testds_validate` (false)
+
+RabbitMQ (required):
+- `RABBIT_HOST`
+- `RABBIT_PORT` (default 5672)
+- `RABBIT_USER`
+- `RABBIT_PASSWORD`
+- `RABBIT_VHOST` (default `/`)
+- `RABBIT_QUEUES` (default `crud_queue`)
+- `RABBIT_DURABLE` (default `true`)
+
+Optional:
+- `PG_TABLE` (default `rabbit_messages`)
+
+Optional:
+- `UI_LOG_TABLE` (default `rabbit_ui_log`) — таблица лога для статуса запросов UI.
+
+## Notes
+
+This app uses RabbitMQ Java client JARs located in `lib/`.
+
+Комментарий: JAR-ы подключены через `this.javaSettings.loadPaths`, поэтому важно держать `lib/` рядом с приложением.
diff --git a/PROD_STAND/RABBIT/rabbit-lsd/index.cfm b/PROD_STAND/RABBIT/rabbit-lsd/index.cfm
new file mode 100644
index 0000000..a865783
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-lsd/index.cfm
@@ -0,0 +1,2 @@
+
+
diff --git a/PROD_STAND/RABBIT/rabbit-lsd/lib/amqp-client-5.21.0.jar b/PROD_STAND/RABBIT/rabbit-lsd/lib/amqp-client-5.21.0.jar
new file mode 100644
index 0000000..129b03b
Binary files /dev/null and b/PROD_STAND/RABBIT/rabbit-lsd/lib/amqp-client-5.21.0.jar differ
diff --git a/PROD_STAND/RABBIT/rabbit-lsd/lib/slf4j-api-1.7.36.jar b/PROD_STAND/RABBIT/rabbit-lsd/lib/slf4j-api-1.7.36.jar
new file mode 100644
index 0000000..7d3ce68
Binary files /dev/null and b/PROD_STAND/RABBIT/rabbit-lsd/lib/slf4j-api-1.7.36.jar differ
diff --git a/PROD_STAND/RABBIT/rabbit-lsd/query.cfm b/PROD_STAND/RABBIT/rabbit-lsd/query.cfm
new file mode 100644
index 0000000..57d1afe
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-lsd/query.cfm
@@ -0,0 +1,219 @@
+
+
+
+
+ Nubes | Rabbit CRUD UI
+
+
+
+
+
+
+
+
+
+
+
+
+
+ SELECT id, action, text, request_id, target_id, queued_at, processed_at, status, error_reason
+ FROM #request.logTableName#
+ ORDER BY id DESC
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
RabbitMQ UI
+
+
Логин / Пароль
+
#rabbitUser# / #rabbitPassword#
+
+
+
+
+
+
+
+
+ Ошибка базы данных: #request.db_error#
+
+
+
+ #status.message#
+
+
+
+
+
💾 — сохранить (update), 🗑 — удалить
+
+
+
+
+
+
Очередь (лог отправки)
+
+
+
+
+
База (фактические записи)
+
+
SELECT * FROM #request.tableName# ORDER BY id DESC
+
+
+
+
+
+
diff --git a/PROD_STAND/RABBIT/rabbit-nodeworker/.gitignore b/PROD_STAND/RABBIT/rabbit-nodeworker/.gitignore
new file mode 100644
index 0000000..5773660
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-nodeworker/.gitignore
@@ -0,0 +1,3 @@
+node_modules/
+.npmrc
+.env
diff --git a/PROD_STAND/RABBIT/rabbit-nodeworker/README.md b/PROD_STAND/RABBIT/rabbit-nodeworker/README.md
new file mode 100644
index 0000000..6a4238f
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-nodeworker/README.md
@@ -0,0 +1,26 @@
+# Rabbit NodeJS Worker
+
+Consumes CRUD messages from RabbitMQ and writes to Postgres.
+
+Комментарий: воркер специально пишет в таблицу демо и не хранит собственное состояние, кроме метрик в памяти.
+
+## Environment variables
+
+RabbitMQ:
+- `AMQP_URL` (preferred), example: `amqp://user:pass@host:5672/vhost`
+- or `RABBIT_HOST`, `RABBIT_PORT` (default 5672), `RABBIT_USER`, `RABBIT_PASSWORD`, `RABBIT_VHOST` (default `/`)
+- `RABBIT_QUEUES` (default `crud_queue`)
+- `RABBIT_DURABLE` (default `true`)
+- `RABBIT_PREFETCH` (default `1`)
+- `REQUEUE_ON_ERROR` (default `true`)
+
+Postgres:
+- `DATABASE_URL` (optional)
+- or `PGHOST`, `PGPORT` (default 5432), `PGUSER`, `PGPASSWORD`, `PGDATABASE` (default `postgres`), `PGSSLMODE` (default `require`)
+- `PG_TABLE` (default `rabbit_messages`)
+
+## Notes
+
+Health endpoint: `/healthz`.
+
+HTML-страница со статусом доступна на `/`.
diff --git a/PROD_STAND/RABBIT/rabbit-nodeworker/package.json b/PROD_STAND/RABBIT/rabbit-nodeworker/package.json
new file mode 100644
index 0000000..3413215
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-nodeworker/package.json
@@ -0,0 +1,13 @@
+{
+ "name": "rabbit-nodeworker",
+ "version": "0.1.0",
+ "description": "RabbitMQ worker for CRUD demo",
+ "main": "server.js",
+ "scripts": {
+ "start": "node server.js"
+ },
+ "dependencies": {
+ "amqplib": "^0.10.4",
+ "pg": "^8.12.0"
+ }
+}
diff --git a/PROD_STAND/RABBIT/rabbit-nodeworker/server.js b/PROD_STAND/RABBIT/rabbit-nodeworker/server.js
new file mode 100644
index 0000000..e92e1aa
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-nodeworker/server.js
@@ -0,0 +1,264 @@
+const http = require("http");
+const amqp = require("amqplib");
+const { Pool } = require("pg");
+
+// Состояние процесса для /healthz и статуса в UI.
+const status = {
+ state: "starting",
+ error: "",
+ lastSuccess: "",
+};
+
+// Метрики обработки сообщений (показываются на HTML-странице).
+const metrics = {
+ processed: 0,
+ failed: 0,
+ lastError: "",
+ lastMessageAt: "",
+ lastAction: "",
+};
+
+// Унифицированное обновление состояния.
+function setStatus(state, error) {
+ status.state = state;
+ status.error = error || "";
+ if (!error) {
+ status.lastSuccess = new Date().toISOString();
+ }
+}
+
+// HTML-страница со статусом и счетчиками.
+function renderStatusPage() {
+ const queueName = (process.env.RABBIT_QUEUES || "crud_queue").split(",")[0] || "crud_queue";
+ const tableName = process.env.PG_TABLE || "rabbit_messages";
+ return `
+
+
+
+ Rabbit NodeJS Worker
+
+
+
+
+
+
NodeJS Worker
+
Queue: ${queueName} | Table: ${tableName}
+
+ ${status.state}
+
+
+
+
Processed
+
${metrics.processed}
+
+
+
Failed
+
${metrics.failed}
+
+
+
Last Action
+
${metrics.lastAction || "-"}
+
${metrics.lastMessageAt || ""}
+
+
+
Last Error
+
${metrics.lastError || "-"}
+
${status.lastSuccess || ""}
+
+
+
+
+
+`;
+}
+
+// Подготовка конфигурации PG (DATABASE_URL имеет приоритет).
+function buildPgConfig() {
+ if (process.env.DATABASE_URL) {
+ return {
+ connectionString: process.env.DATABASE_URL,
+ ssl: process.env.PGSSLMODE === "require" ? { rejectUnauthorized: false } : undefined,
+ };
+ }
+
+ return {
+ host: process.env.PGHOST,
+ port: Number(process.env.PGPORT || "5432"),
+ user: process.env.PGUSER,
+ password: process.env.PGPASSWORD,
+ database: process.env.PGDATABASE || "postgres",
+ ssl: process.env.PGSSLMODE === "require" ? { rejectUnauthorized: false } : undefined,
+ };
+}
+
+// Собираем AMQP URL из переменных окружения.
+function buildAmqpUrl() {
+ if (process.env.AMQP_URL) {
+ return process.env.AMQP_URL;
+ }
+ const host = process.env.RABBIT_HOST || "";
+ const port = process.env.RABBIT_PORT || "5672";
+ const user = process.env.RABBIT_USER || "";
+ const pass = process.env.RABBIT_PASSWORD || "";
+ const vhost = process.env.RABBIT_VHOST || "/";
+ if (!host || !user || !pass) {
+ throw new Error("Missing RABBIT_HOST/RABBIT_USER/RABBIT_PASSWORD or AMQP_URL");
+ }
+ return `amqp://${user}:${pass}@${host}:${port}${vhost}`;
+}
+
+const pool = new Pool(buildPgConfig());
+
+// Минимальная таблица для демо, если БД пустая.
+async function ensureTable(table) {
+ await pool.query(
+ `CREATE TABLE IF NOT EXISTS ${table} (id SERIAL PRIMARY KEY, test_data TEXT, created_at TIMESTAMP DEFAULT NOW())`
+ );
+}
+
+// Парсим JSON, нормализуем ключи, иначе считаем текстом.
+function parseMessage(buffer) {
+ const body = buffer.toString("utf8");
+ try {
+ const parsed = JSON.parse(body);
+ const normalized = Object.keys(parsed || {}).reduce((acc, key) => {
+ acc[key.toLowerCase()] = parsed[key];
+ return acc;
+ }, {});
+ return {
+ action: normalized.action || "create",
+ id: normalized.id,
+ text: normalized.text,
+ requestId: normalized.request_id || normalized.requestid,
+ };
+ } catch {
+ return {
+ action: "create",
+ text: body.trim() || "(empty)",
+ };
+ }
+}
+
+// CRUD-операции по сообщению.
+async function handleMessage(table, msg) {
+ const action = (msg.action || "create").toLowerCase();
+ if (action === "create") {
+ const text = msg.text || "(empty)";
+ await pool.query(`INSERT INTO ${table} (test_data) VALUES ($1)`, [text]);
+ return;
+ }
+ if (action === "update") {
+ if (!msg.id) {
+ throw new Error("missing id for update");
+ }
+ await pool.query(`UPDATE ${table} SET test_data=$1 WHERE id=$2`, [msg.text || "", msg.id]);
+ return;
+ }
+ if (action === "delete") {
+ if (!msg.id) {
+ throw new Error("missing id for delete");
+ }
+ await pool.query(`DELETE FROM ${table} WHERE id=$1`, [msg.id]);
+ return;
+ }
+ throw new Error("invalid action");
+}
+
+// Небольшой HTTP-сервер для /healthz и HTML-статуса.
+function startHttpServer() {
+ const port = process.env.PORT || 3000;
+ const server = http.createServer((req, res) => {
+ if (req.url === "/healthz") {
+ res.writeHead(200, { "Content-Type": "application/json" });
+ res.end(JSON.stringify(status));
+ return;
+ }
+ res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
+ res.end(renderStatusPage());
+ });
+ server.listen(port, () => {
+ console.log(`health server listening on ${port}`);
+ });
+}
+
+// Основной цикл: подключение к RabbitMQ и обработка сообщений.
+async function consumeLoop() {
+ const table = process.env.PG_TABLE || "rabbit_messages";
+ const queueName = (process.env.RABBIT_QUEUES || "crud_queue")
+ .split(",")
+ .map((q) => q.trim())
+ .filter(Boolean)[0] || "crud_queue";
+ const durable = String(process.env.RABBIT_DURABLE || "true").toLowerCase() === "true";
+ const prefetch = Number(process.env.RABBIT_PREFETCH || "1");
+ const requeueOnError = String(process.env.REQUEUE_ON_ERROR || "true").toLowerCase() === "true";
+
+ // Гарантируем наличие таблицы перед стартом консьюмера.
+ await ensureTable(table);
+
+ let backoffMs = 2000;
+ while (true) {
+ try {
+ const amqpUrl = buildAmqpUrl();
+ const connection = await amqp.connect(amqpUrl);
+ const channel = await connection.createChannel();
+ await channel.prefetch(prefetch);
+ await channel.assertQueue(queueName, { durable });
+
+ setStatus("running", "");
+
+ // Обрабатываем сообщения и фиксируем успех/ошибки.
+ channel.consume(queueName, async (msg) => {
+ if (!msg) {
+ return;
+ }
+ try {
+ const parsed = parseMessage(msg.content);
+ await handleMessage(table, parsed);
+ metrics.processed += 1;
+ metrics.lastAction = parsed.action || "create";
+ metrics.lastMessageAt = new Date().toISOString();
+ channel.ack(msg);
+ } catch (err) {
+ metrics.failed += 1;
+ metrics.lastError = String(err.message || err);
+ metrics.lastMessageAt = new Date().toISOString();
+ if (String(err.message || "").includes("missing id") || String(err.message || "").includes("invalid action")) {
+ channel.nack(msg, false, false);
+ return;
+ }
+ channel.nack(msg, false, requeueOnError);
+ }
+ });
+
+ await new Promise((resolve, reject) => {
+ connection.on("close", resolve);
+ connection.on("error", reject);
+ });
+ } catch (err) {
+ setStatus("degraded", String(err.message || err));
+ await new Promise((r) => setTimeout(r, backoffMs));
+ if (backoffMs < 30000) {
+ backoffMs *= 2;
+ }
+ continue;
+ }
+ }
+}
+
+startHttpServer();
+consumeLoop().catch((err) => {
+ setStatus("failed", String(err.message || err));
+ console.error(err);
+});
diff --git a/PROD_STAND/RABBIT/rabbit-worker/.gitignore b/PROD_STAND/RABBIT/rabbit-worker/.gitignore
new file mode 100644
index 0000000..1dda6e5
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-worker/.gitignore
@@ -0,0 +1,3 @@
+bin/
+*.log
+.env
diff --git a/PROD_STAND/RABBIT/rabbit-worker/Dockerfile b/PROD_STAND/RABBIT/rabbit-worker/Dockerfile
new file mode 100644
index 0000000..34eda5f
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-worker/Dockerfile
@@ -0,0 +1,23 @@
+# Сборочный этап: собираем статический бинарник.
+FROM golang:1.22-alpine AS build
+
+WORKDIR /src
+
+COPY go.mod ./
+RUN go mod download
+
+COPY . .
+
+RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o /out/worker ./
+
+# Рантайм-этап: минимальный образ с ca-certificates.
+FROM alpine:3.20
+
+RUN apk add --no-cache ca-certificates
+
+WORKDIR /app
+COPY --from=build /out/worker /app/worker
+
+EXPOSE 8080
+
+CMD ["/app/worker"]
diff --git a/PROD_STAND/RABBIT/rabbit-worker/README.md b/PROD_STAND/RABBIT/rabbit-worker/README.md
new file mode 100644
index 0000000..4cd1039
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-worker/README.md
@@ -0,0 +1,44 @@
+# Rabbit Worker (Go)
+
+Consumes CRUD messages from RabbitMQ and writes to Postgres.
+
+Комментарий: HTTP-эндпоинт нужен только для health-check, остальная логика работает через RabbitMQ.
+
+## Environment variables
+
+RabbitMQ:
+- `AMQP_URL` (preferred), example: `amqp://user:pass@host:5672/vhost`
+- or `RABBIT_HOST`, `RABBIT_PORT` (default 5672), `RABBIT_USER`, `RABBIT_PASSWORD`, `RABBIT_VHOST` (default `/`)
+- `RABBIT_QUEUES` (comma-separated, default `crud_queue`)
+- `RABBIT_DURABLE` (default `true`)
+- `RABBIT_PREFETCH` (default `1`)
+- `REQUEUE_ON_ERROR` (default `true`)
+
+Postgres:
+- `DATABASE_URL` (preferred)
+- or `PGHOST`, `PGPORT` (default 5432), `PGUSER`, `PGPASSWORD`, `PGDATABASE` (default `postgres`), `PGSSLMODE` (default `require`)
+- `PG_TABLE` (default `nubes_test_table`)
+
+## Message format
+
+JSON payload:
+```json
+{"action":"create","text":"hello","id":1}
+```
+
+Fields:
+- `action`: `create` | `update` | `delete`
+- `id`: required for `update` and `delete`
+- `text`: used by `create` and `update`
+
+If the payload is not JSON, it is treated as `create` with body as text.
+
+Примечание: сообщения без `id` для update/delete считаются некорректными и отбрасываются.
+
+## Build
+
+```bash
+cd PROD_STAND/RABBIT/rabbit-worker
+
+docker build -t /: .
+```
diff --git a/PROD_STAND/RABBIT/rabbit-worker/go.mod b/PROD_STAND/RABBIT/rabbit-worker/go.mod
new file mode 100644
index 0000000..4780409
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-worker/go.mod
@@ -0,0 +1,17 @@
+module gitea-naeel.giteak8s.services.ngcloud.ru/naeel/rabbit-worker
+
+go 1.22
+
+require (
+ github.com/jackc/pgx/v5 v5.5.5
+ github.com/rabbitmq/amqp091-go v1.10.0
+)
+
+require (
+ github.com/jackc/pgpassfile v1.0.0 // indirect
+ github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
+ github.com/jackc/puddle/v2 v2.2.1 // indirect
+ golang.org/x/crypto v0.17.0 // indirect
+ golang.org/x/sync v0.1.0 // indirect
+ golang.org/x/text v0.14.0 // indirect
+)
diff --git a/PROD_STAND/RABBIT/rabbit-worker/go.sum b/PROD_STAND/RABBIT/rabbit-worker/go.sum
new file mode 100644
index 0000000..242ae45
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-worker/go.sum
@@ -0,0 +1,32 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk=
+github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw=
+github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A=
+github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
+github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rabbitmq/amqp091-go v1.10.0 h1:STpn5XsHlHGcecLmMFCtg7mqq0RnD+zFr4uzukfVhBw=
+github.com/rabbitmq/amqp091-go v1.10.0/go.mod h1:Hy4jKW5kQART1u+JkDTF9YYOQUHXqMuhrgxOEeS7G4o=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
+go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
+golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
+golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
+golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/PROD_STAND/RABBIT/rabbit-worker/main.go b/PROD_STAND/RABBIT/rabbit-worker/main.go
new file mode 100644
index 0000000..7cefc9c
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit-worker/main.go
@@ -0,0 +1,341 @@
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "os/signal"
+ "strconv"
+ "strings"
+ "sync"
+ "syscall"
+ "time"
+
+ "github.com/jackc/pgx/v5/pgxpool"
+ amqp "github.com/rabbitmq/amqp091-go"
+)
+
+// Воркер держит HTTP /healthz и параллельно слушает RabbitMQ,
+// записывая события в Postgres. Даже при ошибках контейнер остается живым.
+
+type Message struct {
+ Action string `json:"action"`
+ ID *int64 `json:"id,omitempty"`
+ Text string `json:"text,omitempty"`
+ Source string `json:"source,omitempty"`
+ RequestID string `json:"request_id,omitempty"`
+}
+
+type workerStatus struct {
+ mu sync.Mutex
+ state string
+ lastError string
+ lastSuccess time.Time
+}
+
+func (s *workerStatus) set(state, err string) {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ s.state = state
+ s.lastError = err
+ if err == "" {
+ s.lastSuccess = time.Now()
+ }
+}
+
+func (s *workerStatus) snapshot() map[string]string {
+ s.mu.Lock()
+ defer s.mu.Unlock()
+ result := map[string]string{
+ "state": s.state,
+ "error": s.lastError,
+ "timestamp": s.lastSuccess.Format(time.RFC3339),
+ }
+ return result
+}
+
+// getenv читает переменную окружения с дефолтом.
+func getenv(key, def string) string {
+ val := os.Getenv(key)
+ if val == "" {
+ return def
+ }
+ return val
+}
+
+// getenvInt читает int-переменную окружения с дефолтом.
+func getenvInt(key string, def int) int {
+ val := os.Getenv(key)
+ if val == "" {
+ return def
+ }
+ parsed, err := strconv.Atoi(val)
+ if err != nil {
+ return def
+ }
+ return parsed
+}
+
+// buildAMQPURL собирает URL для RabbitMQ.
+func buildAMQPURL() (string, error) {
+ if url := os.Getenv("AMQP_URL"); url != "" {
+ return url, nil
+ }
+
+ host := getenv("RABBIT_HOST", "")
+ port := getenv("RABBIT_PORT", "5672")
+ user := getenv("RABBIT_USER", "")
+ pass := getenv("RABBIT_PASSWORD", "")
+ vhost := getenv("RABBIT_VHOST", "/")
+
+ if host == "" || user == "" || pass == "" {
+ return "", errors.New("missing RABBIT_HOST/RABBIT_USER/RABBIT_PASSWORD or AMQP_URL")
+ }
+
+ return fmt.Sprintf("amqp://%s:%s@%s:%s%s", user, pass, host, port, vhost), nil
+}
+
+// buildPgConnString собирает строку подключения к Postgres.
+func buildPgConnString() (string, error) {
+ if url := os.Getenv("DATABASE_URL"); url != "" {
+ return url, nil
+ }
+
+ host := getenv("PGHOST", "")
+ if host == "" {
+ return "", errors.New("missing PGHOST or DATABASE_URL")
+ }
+ port := getenv("PGPORT", "5432")
+ user := getenv("PGUSER", "")
+ pass := getenv("PGPASSWORD", "")
+ db := getenv("PGDATABASE", "postgres")
+ ssl := getenv("PGSSLMODE", "require")
+
+ if user == "" || pass == "" {
+ return "", errors.New("missing PGUSER/PGPASSWORD or DATABASE_URL")
+ }
+
+ return fmt.Sprintf(
+ "postgresql://%s:%s@%s:%s/%s?sslmode=%s",
+ user,
+ pass,
+ host,
+ port,
+ db,
+ ssl,
+ ), nil
+}
+
+// ensureTable гарантирует наличие таблицы для демо.
+func ensureTable(ctx context.Context, pool *pgxpool.Pool, table string) error {
+ query := fmt.Sprintf(
+ "CREATE TABLE IF NOT EXISTS %s (id SERIAL PRIMARY KEY, test_data TEXT, created_at TIMESTAMP DEFAULT NOW())",
+ table,
+ )
+ _, err := pool.Exec(ctx, query)
+ return err
+}
+
+// parseMessage принимает JSON и fallback-ит в текст.
+func parseMessage(body []byte) Message {
+ msg := Message{Action: "create"}
+ if err := json.Unmarshal(body, &msg); err != nil {
+ msg.Text = strings.TrimSpace(string(body))
+ if msg.Text == "" {
+ msg.Text = "(empty)"
+ }
+ return msg
+ }
+ if msg.Action == "" {
+ msg.Action = "create"
+ }
+ return msg
+}
+
+var errInvalidMessage = errors.New("invalid message")
+
+// handleMessage выполняет CRUD над таблицей.
+func handleMessage(ctx context.Context, pool *pgxpool.Pool, table string, msg Message) error {
+ ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
+ defer cancel()
+
+ switch strings.ToLower(msg.Action) {
+ case "create":
+ text := msg.Text
+ if text == "" {
+ text = "(empty)"
+ }
+ query := fmt.Sprintf("INSERT INTO %s (test_data) VALUES ($1)", table)
+ _, err := pool.Exec(ctx, query, text)
+ return err
+ case "update":
+ if msg.ID == nil {
+ return errInvalidMessage
+ }
+ query := fmt.Sprintf("UPDATE %s SET test_data=$1 WHERE id=$2", table)
+ _, err := pool.Exec(ctx, query, msg.Text, *msg.ID)
+ return err
+ case "delete":
+ if msg.ID == nil {
+ return errInvalidMessage
+ }
+ query := fmt.Sprintf("DELETE FROM %s WHERE id=$1", table)
+ _, err := pool.Exec(ctx, query, *msg.ID)
+ return err
+ default:
+ return errInvalidMessage
+ }
+}
+
+// startHTTPServer поднимает /healthz и базовый ответ на /.
+func startHTTPServer(port string, status *workerStatus) {
+ http.HandleFunc("/healthz", func(w http.ResponseWriter, _ *http.Request) {
+ payload, _ := json.Marshal(status.snapshot())
+ w.Header().Set("Content-Type", "application/json")
+ w.WriteHeader(http.StatusOK)
+ _, _ = w.Write(payload)
+ })
+
+ http.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ _, _ = w.Write([]byte("rabbit-worker ready"))
+ })
+
+ log.Printf("listening on :%s", port)
+ if err := http.ListenAndServe(fmt.Sprintf(":%s", port), nil); err != nil {
+ log.Fatal(err)
+ }
+}
+
+// runWorker подключается к Rabbit и обрабатывает сообщения.
+func runWorker(ctx context.Context, status *workerStatus) error {
+ amqpURL, err := buildAMQPURL()
+ if err != nil {
+ return err
+ }
+
+ pgConn, err := buildPgConnString()
+ if err != nil {
+ return err
+ }
+
+ // Список очередей поддерживает несколько значений через запятую.
+ queues := strings.Split(getenv("RABBIT_QUEUES", "crud_queue"), ",")
+ for i := range queues {
+ queues[i] = strings.TrimSpace(queues[i])
+ }
+ queueDurable := getenv("RABBIT_DURABLE", "true") == "true"
+ prefetch := getenvInt("RABBIT_PREFETCH", 1)
+ requeueOnError := getenv("REQUEUE_ON_ERROR", "true") == "true"
+ table := getenv("PG_TABLE", "nubes_test_table")
+
+ pool, err := pgxpool.New(ctx, pgConn)
+ if err != nil {
+ return fmt.Errorf("pg pool: %w", err)
+ }
+ defer pool.Close()
+
+ if err := pool.Ping(ctx); err != nil {
+ return fmt.Errorf("pg ping: %w", err)
+ }
+ if err := ensureTable(ctx, pool, table); err != nil {
+ return fmt.Errorf("ensure table: %w", err)
+ }
+
+ conn, err := amqp.Dial(amqpURL)
+ if err != nil {
+ return fmt.Errorf("amqp dial: %w", err)
+ }
+ defer conn.Close()
+
+ ch, err := conn.Channel()
+ if err != nil {
+ return fmt.Errorf("amqp channel: %w", err)
+ }
+ defer ch.Close()
+
+ if err := ch.Qos(prefetch, 0, false); err != nil {
+ return fmt.Errorf("amqp qos: %w", err)
+ }
+
+ for _, q := range queues {
+ if q == "" {
+ continue
+ }
+ if _, err := ch.QueueDeclare(q, queueDurable, false, false, false, nil); err != nil {
+ return fmt.Errorf("queue declare %s: %w", q, err)
+ }
+ }
+
+ // Сливаем несколько очередей в один канал сообщений.
+ msgs := make(chan amqp.Delivery)
+ for _, q := range queues {
+ if q == "" {
+ continue
+ }
+ delivery, err := ch.Consume(q, "", false, false, false, false, nil)
+ if err != nil {
+ return fmt.Errorf("consume %s: %w", q, err)
+ }
+
+ go func(d <-chan amqp.Delivery) {
+ for m := range d {
+ msgs <- m
+ }
+ }(delivery)
+ }
+
+ status.set("running", "")
+ for {
+ select {
+ case <-ctx.Done():
+ return nil
+ case m := <-msgs:
+ msg := parseMessage(m.Body)
+ if err := handleMessage(ctx, pool, table, msg); err != nil {
+ if errors.Is(err, errInvalidMessage) {
+ _ = m.Nack(false, false)
+ log.Printf("reject message: %v", err)
+ continue
+ }
+ _ = m.Nack(false, requeueOnError)
+ log.Printf("error handling message: %v", err)
+ continue
+ }
+ _ = m.Ack(false)
+ }
+ }
+}
+
+func main() {
+ port := getenv("PORT", "8080")
+ status := &workerStatus{state: "starting"}
+
+ ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGINT, syscall.SIGTERM)
+ defer stop()
+
+ go startHTTPServer(port, status)
+
+ // Экспоненциальный backoff при ошибках подключения.
+ backoff := 2 * time.Second
+ for {
+ if ctx.Err() != nil {
+ return
+ }
+ if err := runWorker(ctx, status); err != nil {
+ status.set("degraded", err.Error())
+ log.Printf("worker error: %v", err)
+ time.Sleep(backoff)
+ if backoff < 30*time.Second {
+ backoff *= 2
+ }
+ continue
+ }
+ status.set("stopped", "")
+ return
+ }
+}
diff --git a/PROD_STAND/RABBIT/rabbit_worker_disabled.tf b/PROD_STAND/RABBIT/rabbit_worker_disabled.tf
new file mode 100644
index 0000000..a647584
--- /dev/null
+++ b/PROD_STAND/RABBIT/rabbit_worker_disabled.tf
@@ -0,0 +1,33 @@
+# Disabled rabbit worker resource (create-only json_env issue).
+# Отключено из-за create-only json_env у nubes_http.
+#
+# resource "nubes_http" "rabbit_worker" {
+# resource_name = "rb-worker-02"
+# resource_realm = "k8s-3.ext.nubes.ru"
+# domain = "rb-worker-02"
+# registry_path = "naeel/rabbit-worker:0.3"
+# resource_c_p_u = 100
+# resource_memory = 128
+# resource_instances = 1
+#
+# json_env = jsonencode({
+# RABBIT_HOST = try(nubes_rabbitmq.rb1.state_out_flat["internalConnect.master"], nubes_rabbitmq.rb1.state_out_flat["inernalConnect.master"])
+# RABBIT_PORT = "5672"
+# RABBIT_USER = nubes_rabbitmq.rb1.vault_secrets["adminUser"]
+# RABBIT_PASSWORD = nubes_rabbitmq.rb1.vault_secrets["adminPass"]
+# RABBIT_VHOST = "/"
+# RABBIT_QUEUES = "crud_queue"
+# RABBIT_DURABLE = "true"
+# RABBIT_PREFETCH = "1"
+# REQUEUE_ON_ERROR = "true"
+# PGHOST = var.PGHOST
+# PGPORT = "5432"
+# PGUSER = var.PGUSER
+# PGPASSWORD = var.PGPASSWORD
+# PGDATABASE = "postgres"
+# PGSSLMODE = "require"
+# PG_TABLE = "rabbit_messages"
+# })
+#
+# depends_on = [nubes_rabbitmq.rb1]
+# }
diff --git a/PROD_STAND/RABBIT/resources.tf b/PROD_STAND/RABBIT/resources.tf
new file mode 100644
index 0000000..ccde7ff
--- /dev/null
+++ b/PROD_STAND/RABBIT/resources.tf
@@ -0,0 +1,104 @@
+# RabbitMQ кластер для демо.
+resource "nubes_rabbitmq" "rb1" {
+ resource_name = "rabbit_0"
+ resource_realm = "k8s-3.ext.nubes.ru"
+ resource_instances = 1
+ resource_memory = 512
+ resource_c_p_u = 500
+ resource_disk = 5
+ need_external_address_master = false
+ need_external_address_slave = false
+}
+
+# Lucee UI, который пишет в Rabbit и читает из Postgres.
+resource "nubes_lucee" "rabbit_ui" {
+ resource_name = "rb-lucee-ui"
+ resource_realm = "k8s-3.ext.nubes.ru"
+ domain = "rb-ui"
+ app_version = "5.4"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/rabbit-lsd.git"
+ resource_c_p_u = 300
+ resource_memory = 512
+ resource_instances = 1
+
+ # Переменные окружения для datasource, Rabbit и UI.
+ json_env = jsonencode({
+ testds_bundleName = "org.postgresql.jdbc"
+ testds_bundleVersion = "42.6.0"
+ testds_class = "org.postgresql.Driver"
+ testds_connectionLimit = "5"
+ testds_connectionString = "jdbc:postgresql://${var.PGHOST}:5432/postgres"
+ testds_liveTimeout = "15"
+ testds_username = var.PGUSER
+ testds_password = var.PGPASSWORD
+ testds_validate = "false"
+ PG_TABLE = "rabbit_messages"
+ UI_LOG_TABLE = "rabbit_ui_log"
+ RABBIT_HOST = try(nubes_rabbitmq.rb1.state_out_flat["internalConnect.master"], nubes_rabbitmq.rb1.state_out_flat["inernalConnect.master"])
+ RABBIT_PORT = "5672"
+ RABBIT_USER = nubes_rabbitmq.rb1.vault_secrets["adminUser"]
+ RABBIT_PASSWORD = nubes_rabbitmq.rb1.vault_secrets["adminPass"]
+ RABBIT_VHOST = "/"
+ RABBIT_QUEUES = "crud_queue"
+ RABBIT_DURABLE = "true"
+ RABBIT_ADMIN_URL = "https://${nubes_rabbitmq.rb1.state_out_flat["externalConnect.admin.fqdn"]}/#/"
+ NODEWORKER_URL = "https://nodeworker.nodejsk8s.services.ngcloud.ru/"
+ })
+
+ depends_on = [nubes_rabbitmq.rb1]
+}
+
+# NodeJS воркер, который переносит CRUD из очереди в Postgres.
+resource "nubes_nodejs" "rabbit_nodeworker" {
+ resource_name = "nodeworker"
+ resource_realm = "k8s-3.ext.nubes.ru"
+ domain = "nodeworker"
+ app_version = "23"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/rabbit-nodeworker.git"
+ health_path = "/healthz"
+ resource_c_p_u = 100
+ resource_memory = 256
+ resource_instances = 1
+
+ # Параметры подключения к Rabbit и Postgres.
+ json_env = jsonencode({
+ RABBIT_HOST = try(nubes_rabbitmq.rb1.state_out_flat["internalConnect.master"], nubes_rabbitmq.rb1.state_out_flat["inernalConnect.master"])
+ RABBIT_PORT = "5672"
+ RABBIT_USER = nubes_rabbitmq.rb1.vault_secrets["adminUser"]
+ RABBIT_PASSWORD = nubes_rabbitmq.rb1.vault_secrets["adminPass"]
+ RABBIT_VHOST = "/"
+ RABBIT_QUEUES = "crud_queue"
+ RABBIT_DURABLE = "true"
+ RABBIT_PREFETCH = "1"
+ REQUEUE_ON_ERROR = "true"
+ PGHOST = var.PGHOST
+ PGPORT = "5432"
+ PGUSER = var.PGUSER
+ PGPASSWORD = var.PGPASSWORD
+ PGDATABASE = "postgres"
+ PGSSLMODE = "require"
+ PG_TABLE = "rabbit_messages"
+ })
+
+ depends_on = [nubes_rabbitmq.rb1]
+}
+
+# # Ручной триггер redeploy для воркера.
+# resource "nubes_nodejs_redeploy" "rabbit_nodeworker_redeploy" {
+# nodejs_id = nubes_nodejs.rabbit_nodeworker.id
+# resource_realm = "k8s-3.ext.nubes.ru"
+# run_id = "redeploy-2026-02-2-01134"
+# }
+
+# # Ручной триггер restart для Lucee UI.
+# resource "nubes_lucee_restart" "rabbit_ui_restart" {
+# lucee_id = nubes_lucee.rabbit_ui.id
+# run_id = "restart-2026-02-23-023"
+# }
+
+# S3 бакет baba.
+resource "nubes_s3bucket" "baba_bucket" {
+ resource_name = "baba-buck"
+ s3_user_uid = "s3-111805"
+ bucket_name = "baba"
+}
diff --git a/PROD_STAND/RABBIT/variables.tf b/PROD_STAND/RABBIT/variables.tf
new file mode 100644
index 0000000..9135d58
--- /dev/null
+++ b/PROD_STAND/RABBIT/variables.tf
@@ -0,0 +1,18 @@
+// Пользователь Postgres для воркера и UI.
+// Важно: Postgres здесь внешний, уже запущенный — параметры берутся из ЛК.
+variable "PGUSER" {
+ type = string
+ default = "postgres"
+}
+// Пароль Postgres для воркера и UI.
+// Узнайте пароль в UI Личного кабинета и укажите здесь.
+variable "PGPASSWORD" {
+ type = string
+ default = "TMGMCN5GYzx8gj1GiqA4rmf19HEJKgQXSUHcN17hJNnbyZmicfhU5AfFpLQyF22I"
+}
+// FQDN мастера Postgres (важно для DNS внутри кластера).
+// Значение берется из UI Личного кабинета для уже созданного Postgres.
+variable "PGHOST" {
+ type = string
+ default = "postgresqlk8s-master.a71094c1-b0ed-4bfb-a264-37b41d279567.svc.k8s-3.ext.nubes.ru"
+}
diff --git a/RABBIT/main.tf b/RABBIT/main.tf
new file mode 100644
index 0000000..4384dfc
--- /dev/null
+++ b/RABBIT/main.tf
@@ -0,0 +1,30 @@
+// 2026-03-19
+// main.tf — провайдер и переменные для managed RabbitMQ в облаке Nubes.
+// Тест-стенд: deck-api-test.ngcloud.ru
+terraform {
+ required_providers {
+ nubes = {
+ source = "terra.k8c.ru/nubes/nubes"
+ version = "5.0.19"
+ }
+ }
+}
+
+// Токен доступа к Nubes API.
+variable "api_token" {
+ type = string
+ sensitive = true
+ description = "Nubes API token"
+}
+
+// Реалм, в котором создаётся RabbitMQ (например, k8s-5.ext.nubes.ru).
+variable "realm" {
+ type = string
+ sensitive = true
+ description = "resource_realm для nubes_rabbitmq"
+}
+
+provider "nubes" {
+ api_token = var.api_token
+ api_endpoint = "https://deck-api-test.ngcloud.ru/api/v1/index.cfm"
+}
diff --git a/RABBIT/resources.tf b/RABBIT/resources.tf
new file mode 100644
index 0000000..160df98
--- /dev/null
+++ b/RABBIT/resources.tf
@@ -0,0 +1,41 @@
+// 2026-03-19
+// resources.tf — managed RabbitMQ в облаке Nubes для sless и других сервисов.
+
+resource "nubes_rabbitmq" "rmq" {
+ // Общий брокер для sless event-triggers и других сервисов облака.
+ resource_name = "sless-rabbit"
+ resource_realm = var.realm
+ resource_instances = 1
+ resource_memory = 512
+ resource_c_p_u = 500
+ resource_disk = 5
+ need_external_address_master = false
+ need_external_address_slave = false
+}
+
+locals {
+ // try() — обходим опечатку в API: поле называется как internalConnect, так и inernalConnect.
+ rmq_host = try(nubes_rabbitmq.rmq.state_out_flat["internalConnect.master"], nubes_rabbitmq.rmq.state_out_flat["inernalConnect.master"])
+ rmq_user = nubes_rabbitmq.rmq.vault_secrets["adminUser"]
+ rmq_password = nubes_rabbitmq.rmq.vault_secrets["adminPass"]
+}
+
+output "rabbitmq_host" {
+ value = local.rmq_host
+}
+
+output "rabbitmq_user" {
+ value = local.rmq_user
+ sensitive = true
+}
+
+output "rabbitmq_password" {
+ value = local.rmq_password
+ sensitive = true
+}
+
+output "rabbitmq_amqp_url" {
+ // Готовый URL для передачи в оператор sless (env RABBITMQ_URL).
+ value = "amqp://${local.rmq_user}:${local.rmq_password}@${local.rmq_host}:5672/"
+ sensitive = true
+}
diff --git a/TEST_STAND/LUCEE/main.tf b/TEST_STAND/LUCEE/main.tf
new file mode 100644
index 0000000..b3ea881
--- /dev/null
+++ b/TEST_STAND/LUCEE/main.tf
@@ -0,0 +1,20 @@
+terraform {
+ required_providers {
+ nubes = {
+ source = "terra.k8c.ru/nubes/nubes"
+ version = "2.0.6"
+ }
+ }
+}
+
+variable "api_token" {
+ type = string
+ sensitive = true
+ description = "Nubes API token"
+}
+
+provider "nubes" {
+ api_token = var.api_token
+ api_endpoint = "https://deck-api-test.ngcloud.ru/api/v1/index.cfm"
+}
+
diff --git a/TEST_STAND/LUCEE/resources.tf b/TEST_STAND/LUCEE/resources.tf
new file mode 100644
index 0000000..ebca5a2
--- /dev/null
+++ b/TEST_STAND/LUCEE/resources.tf
@@ -0,0 +1,95 @@
+resource "nubes_postgres" "db2" {
+ resource_name = "pg-tst0"
+ s3_uid = "s01325"
+ # s3_uid = "s3-111805"
+ resource_realm = "k8s-4-sandbox-nubes-ru"
+ # resource_realm = "k8s-3.ext.nubes.ru"
+ resource_instances = 1
+ resource_memory = 512
+ resource_c_p_u = 500
+ resource_disk = "1"
+ app_version = "17"
+ json_parameters = jsonencode({
+ log_connections = "off"
+ log_disconnections = "off"
+ })
+ enable_pg_pooler_master = false
+ enable_pg_pooler_slave = false
+ allow_no_s_s_l = false
+ auto_scale = false
+ auto_scale_percentage = 10
+ auto_scale_tech_window = 0
+ auto_scale_quota_gb = "1"
+ need_external_address_master = false
+}
+
+resource "nubes_lucee" "app1" {
+ # Lucee-приложение, зависит от Postgres
+ resource_name = "lucy_0"
+ # resource_realm = "k8s-3.ext.nubes.ru"
+ resource_realm = "k8s-4-sandbox-nubes-ru"
+ domain = "web03"
+
+ # git_path = "https://gitea.services.ngcloud.ru/naeel/testlucee-mirror"
+ # git_path = "https://gitea.services.ngcloud.ru/smishchuk/testlucee"
+ # ⬆️ даёт ошибку, с том числе и при обращении к API by CURL
+ # Приложение не запустилось. Производится полный откат установки.
+ # Ошибка: jlib.k8s [correctReplicaActive] | ERROR | Под(ы) не работают: 'luceek8s' (Deployment).
+
+ # ⬇️ клон "https://gitea.services.ngcloud.ru/smishchuk/testlucee.git"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testlucee"
+
+ # ⬇️ OK
+ # git_path = "https://github.com/xahys/testlucee"
+
+json_env = jsonencode({
+ # 🔗 Настройки Data Source 'testds' для Lucee (Application.cfc)
+ testds_class = "org.postgresql.Driver" # 📂 Драйвер БД
+ testds_bundleName = "org.postgresql.jdbc" # 📦 Имя бандла JDBC
+ testds_bundleVersion = "42.6.0" # 🔢 Версия драйвера
+ testds_connectionString = "jdbc:postgresql://${nubes_postgres.db2.state_out_flat["internalConnect.master"]}:5432/postgres" # 🚀 Строка подключения
+ testds_username = nubes_postgres.db2.vault_secrets["adminUser"]# 👤 Логин
+ testds_password = nubes_postgres.db2.vault_secrets["adminPass"] # 🔑 Пароль
+ testds_connectionLimit = "5" # 🚦 Лимит соединений
+ testds_liveTimeout = "15" # ⏳ Таймаут жизни
+ testds_validate = "false" # ✅ Валидация при запросе
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 512
+ resource_instances = 1
+ app_version = "5.4"
+
+ depends_on = [nubes_postgres.db2]
+}
+
+resource "nubes_nodejs" "app2" {
+ # NodeJS-приложение, использует тот же Postgres
+ resource_name = "node_0"
+ # resource_realm = "k8s-3.ext.nubes.ru"
+ resource_realm = "k8s-4-sandbox-nubes-ru"
+ domain = "node"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testnode"
+ health_path = "/healthz"
+ app_version = "23"
+
+ json_env = jsonencode({
+ PGHOST = nubes_postgres.db2.state_out_flat["internalConnect.master"]
+ PGPORT = "5432"
+ PGUSER = nubes_postgres.db2.vault_secrets["adminUser"]
+ PGPASSWORD = nubes_postgres.db2.vault_secrets["adminPass"]
+ PGSSLMODE = "require"
+ DATABASE_URL = format(
+ "postgresql://%s:%s@%s:5432/postgres",
+ nubes_postgres.db2.vault_secrets["adminUser"],
+ nubes_postgres.db2.vault_secrets["adminPass"],
+ nubes_postgres.db2.state_out_flat["internalConnect.master"]
+ )
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 256
+ resource_instances = 1
+
+ depends_on = [nubes_postgres.db2]
+}
diff --git a/TEST_STAND/LUCEE/terraform.tfvars.example b/TEST_STAND/LUCEE/terraform.tfvars.example
new file mode 100644
index 0000000..9881877
--- /dev/null
+++ b/TEST_STAND/LUCEE/terraform.tfvars.example
@@ -0,0 +1 @@
+api_token = ""
diff --git a/TEST_STAND/MARIA_DB/main.tf b/TEST_STAND/MARIA_DB/main.tf
new file mode 100644
index 0000000..9417488
--- /dev/null
+++ b/TEST_STAND/MARIA_DB/main.tf
@@ -0,0 +1,20 @@
+terraform {
+ required_providers {
+ nubes = {
+ source = "terra.k8c.ru/nubes/nubes"
+ version = "2.0.8"
+ }
+ }
+}
+
+variable "api_token" {
+ type = string
+ sensitive = true
+ description = "Nubes API token"
+}
+
+provider "nubes" {
+ api_token = var.api_token
+ api_endpoint = "https://deck-api-test.ngcloud.ru/api/v1/index.cfm"
+}
+
diff --git a/TEST_STAND/MARIA_DB/resources.tf b/TEST_STAND/MARIA_DB/resources.tf
new file mode 100644
index 0000000..9fdae80
--- /dev/null
+++ b/TEST_STAND/MARIA_DB/resources.tf
@@ -0,0 +1,126 @@
+
+resource "nubes_mariadb" "db2" {
+ resource_name = "mariadb-ops-01"
+ resource_realm = "k8s-4-sandbox-nubes-ru"
+ resource_instances = 1
+ resource_memory = 1024
+ resource_c_p_u = 500
+ resource_disk = 1
+ app_version = "9.4.0"
+ need_external_address_master = false
+ auto_scale = false
+ s3_uid = "s01325"
+}
+
+resource "nubes_lucee" "app1" {
+ # Lucee-prilozhenie, zavisit ot MariaDB
+ resource_name = "lucy_0"
+ resource_realm = nubes_mariadb.db2.resource_realm
+ domain = "web03"
+
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testlucee"
+
+ json_env = jsonencode({
+ # Nastroyki Data Source 'testds' dlya Lucee (Application.cfc)
+ testds_class = "org.mariadb.jdbc.Driver"
+ testds_bundleName = "org.mariadb.jdbc"
+ testds_bundleVersion = "3.3.2"
+ testds_connectionString = "jdbc:mariadb://${nubes_mariadb.db2.state_out_flat["internalConnect.master"]}:3306/postgres"
+ testds_username = nubes_mariadb.db2.vault_secrets["adminUser"]
+ testds_password = nubes_mariadb.db2.vault_secrets["adminPass"]
+ testds_connectionLimit = "5"
+ testds_liveTimeout = "15"
+ testds_validate = "false"
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 512
+ resource_instances = 1
+ app_version = "5.4"
+
+ depends_on = [nubes_mariadb.db2]
+}
+
+resource "nubes_lucee_restart" "app1_restart" {
+ lucee_id = nubes_lucee.app1.id
+ # Bump run_id to trigger another restart.
+ run_id = "restart-1"
+}
+
+resource "nubes_flask" "app2" {
+ resource_name = "flask_0"
+ resource_realm = nubes_mariadb.db2.resource_realm
+ domain = "flask"
+ git_path = "https://github.com/Foxyhhd/Baldurs-Gate-test.git"
+
+ json_env = jsonencode({
+ DB_HOST = nubes_mariadb.db2.state_out_flat["internalConnect.master"]
+ DB_PORT = "3306"
+ DB_USER = nubes_mariadb.db2.vault_secrets["adminUser"]
+ DB_PASSWORD = nubes_mariadb.db2.vault_secrets["adminPass"]
+ DB_NAME = "postgres"
+ DATABASE_URL = format(
+ "mysql+pymysql://%s:%s@%s:3306/postgres",
+ nubes_mariadb.db2.vault_secrets["adminUser"],
+ nubes_mariadb.db2.vault_secrets["adminPass"],
+ nubes_mariadb.db2.state_out_flat["internalConnect.master"]
+ )
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 256
+ resource_instances = 1
+
+ depends_on = [nubes_mariadb.db2]
+}
+
+resource "nubes_nodejs" "app3" {
+ resource_name = "node_0"
+ resource_realm = nubes_mariadb.db2.resource_realm
+ domain = "node"
+ git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testnode"
+ health_path = "/healthz"
+ app_version = "23"
+
+ json_env = jsonencode({
+ DB_HOST = nubes_mariadb.db2.state_out_flat["internalConnect.master"]
+ DB_PORT = "3306"
+ DB_USER = nubes_mariadb.db2.vault_secrets["adminUser"]
+ DB_PASSWORD = nubes_mariadb.db2.vault_secrets["adminPass"]
+ DB_NAME = "postgres"
+ DATABASE_URL = format(
+ "mysql://%s:%s@%s:3306/postgres",
+ nubes_mariadb.db2.vault_secrets["adminUser"],
+ nubes_mariadb.db2.vault_secrets["adminPass"],
+ nubes_mariadb.db2.state_out_flat["internalConnect.master"]
+ )
+ })
+
+ resource_c_p_u = 300
+ resource_memory = 256
+ resource_instances = 1
+
+ depends_on = [nubes_mariadb.db2]
+}
+
+resource "nubes_http" "mariadb_check" {
+ resource_name = "mariadb-check-01"
+ resource_realm = nubes_mariadb.db2.resource_realm
+ domain = "mariadb-check"
+ registry_path = "naeel/mariadb-check:0.1"
+ resource_c_p_u = 100
+ resource_memory = 256
+ resource_instances = 1
+
+ json_env = jsonencode({
+ DB_HOST = nubes_mariadb.db2.state_out_flat["internalConnect.master"]
+ DB_PORT = "3306"
+ DB_USER = nubes_mariadb.db2.vault_secrets["adminUser"]
+ DB_PASSWORD = nubes_mariadb.db2.vault_secrets["adminPass"]
+ DB_NAME = "postgres"
+ })
+
+ depends_on = [nubes_mariadb.db2]
+}
+
+
diff --git a/TEST_STAND/MARIA_DB/terraform.tfvars.example b/TEST_STAND/MARIA_DB/terraform.tfvars.example
new file mode 100644
index 0000000..9881877
--- /dev/null
+++ b/TEST_STAND/MARIA_DB/terraform.tfvars.example
@@ -0,0 +1 @@
+api_token = ""
diff --git a/TEST_STAND/MARIA_DB/terraformrc.dev b/TEST_STAND/MARIA_DB/terraformrc.dev
new file mode 100644
index 0000000..f53903b
--- /dev/null
+++ b/TEST_STAND/MARIA_DB/terraformrc.dev
@@ -0,0 +1,6 @@
+provider_installation {
+ dev_overrides {
+ "terra.k8c.ru/nubes/nubes" = "../../universal_rebuild/bin"
+ }
+ direct {}
+}
diff --git a/TEST_STAND/POSTGRES/luceUNDnode.tf b/TEST_STAND/POSTGRES/luceUNDnode.tf
new file mode 100644
index 0000000..033fbab
--- /dev/null
+++ b/TEST_STAND/POSTGRES/luceUNDnode.tf
@@ -0,0 +1,71 @@
+
+# resource "nubes_lucee" "app1" {
+# # Lucee-приложение, зависит от Postgres
+# resource_name = "lucy_teststand_0"
+# resource_realm = nubes_postgres.npg.resource_realm
+# domain = "web-test-stand"
+
+# git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testlucee.git"
+
+# json_env = jsonencode({
+# # 🔗 Настройки Data Source 'testds' для Lucee (Application.cfc)
+# testds_class = "org.postgresql.Driver" # 📂 Драйвер БД
+# testds_bundleName = "org.postgresql.jdbc" # 📦 Имя бандла JDBC
+# testds_bundleVersion = "42.6.0" # 🔢 Версия драйвера
+# testds_connectionString = "jdbc:postgresql://${nubes_postgres.npg.state_out_flat["internalConnect.master"]}:5432/${nubes_postgres_database.db2_app.db_name}?sslmode=require" # 🚀 Строка подключения
+# testds_username = nubes_postgres_user.pg_user.username # 👤 Логин
+# testds_password = jsondecode(nubes_postgres.npg.vault_secrets["users"])[nubes_postgres_user.pg_user.username]["password"] # 🔑 Пароль
+# testds_connectionLimit = "5" # 🚦 Лимит соединений
+# testds_liveTimeout = "15" # ⏳ Таймаут жизни
+# testds_validate = "false" # ✅ Валидация при запросе
+# })
+
+# resource_c_p_u = 300
+# resource_memory = 512
+# resource_instances = 1
+# app_version = "5.4"
+
+# depends_on = [nubes_postgres.npg]
+# }
+
+# resource "nubes_nodejs" "app3" {
+# # NodeJS демо, работающий с тем же Postgres.
+# resource_name = "node_01"
+# resource_realm = nubes_postgres.npg.resource_realm
+# domain = "node07"
+# git_path = "https://gitea-naeel.giteak8s.services.ngcloud.ru/naeel/testnode.git"
+# health_path = "/healthz"
+# app_version = "23"
+
+# json_env = jsonencode({
+# # Переменные подключения к Postgres.
+# PGHOST = nubes_postgres.npg.state_out_flat["internalConnect.master"]
+# PGPORT = "5432"
+# PGUSER = nubes_postgres_user.pg_user.username
+# PGPASSWORD = jsondecode(nubes_postgres.npg.vault_secrets["users"])[nubes_postgres_user.pg_user.username]["password"]
+# PGDATABASE = nubes_postgres_database.db2_app.db_name
+# PGSSLMODE = "require"
+# DATABASE_URL = format(
+# "postgresql://%s:%s@%s:5432/%s?sslmode=require",
+# nubes_postgres_user.pg_user.username,
+# jsondecode(nubes_postgres.npg.vault_secrets["users"])[nubes_postgres_user.pg_user.username]["password"],
+# nubes_postgres.npg.state_out_flat["internalConnect.master"],
+# nubes_postgres_database.db2_app.db_name
+# )
+# })
+
+# resource_c_p_u = 300
+# resource_memory = 256
+# resource_instances = 1
+
+# depends_on = [nubes_postgres.npg]
+# }
+
+# output "pg_vault_secrets" {
+# value = nubes_postgres.npg.vault_secrets
+# sensitive = true
+# }
+
+# terraform output -json pg_vault_secrets
+
+
diff --git a/TEST_STAND/POSTGRES/main.tf b/TEST_STAND/POSTGRES/main.tf
new file mode 100644
index 0000000..48ffc70
--- /dev/null
+++ b/TEST_STAND/POSTGRES/main.tf
@@ -0,0 +1,31 @@
+terraform {
+ required_providers {
+ nubes = {
+ source = "terra.k8c.ru/nubes/nubes"
+ version = "5.0.52"
+ }
+ }
+}
+
+variable "api_token" {
+ type = string
+ sensitive = true
+ description = "Nubes API token"
+}
+variable "s3_uid" {
+ type = string
+ sensitive = true
+ description = "Nubes S3 UID"
+}
+variable "realm" {
+ type = string
+ sensitive = true
+ description = "resource_realm parameter for nubes_postgres resource"
+}
+
+provider "nubes" {
+ api_token = var.api_token
+ api_endpoint = "https://deck-api-test.ngcloud.ru/api/v1/index.cfm"
+ log_level = "debug" # none | info | debug, default = "none"
+}
+
diff --git a/TEST_STAND/POSTGRES/resources.tf b/TEST_STAND/POSTGRES/resources.tf
new file mode 100644
index 0000000..bb34f43
--- /dev/null
+++ b/TEST_STAND/POSTGRES/resources.tf
@@ -0,0 +1,50 @@
+resource "nubes_postgres" "npg" {
+ resource_name = "pg4tf033"
+ s3_uid = var.s3_uid
+ resource_realm = var.realm
+ resource_instances = 1
+ resource_memory = 512
+ resource_c_p_u = 500
+ resource_disk = "1"
+ app_version = "17"
+ json_parameters = jsonencode({
+ log_connections = "off"
+ log_disconnections = "off"
+ })
+ enable_pg_pooler_master = false
+ enable_pg_pooler_slave = false
+ allow_no_s_s_l = false
+ auto_scale = false
+ auto_scale_percentage = 10
+ auto_scale_tech_window = 0
+ auto_scale_quota_gb = "1"
+ need_external_address_master = false
+
+ # suspend_on_destroy = false
+ operation_timeout = "11m"
+ adopt_existing_on_create = true
+}
+
+
+# resource "nubes_s3bucket" "baba_bucket" {
+# resource_name = "baba-buck-test1"
+# s3_user_uid = var.s3_uid
+# bucket_name = "baba000"
+# adopt_existing_on_create=true
+# }
+
+resource "nubes_postgres_user" "pg_user" {
+ postgres_id = nubes_postgres.npg.id
+ username = "user0"
+ role = "ddl_user"
+ adopt_existing_on_create = true
+}
+
+resource "nubes_postgres_database" "db2_app" {
+ postgres_id = nubes_postgres.npg.id
+ db_name = "db_terra"
+ db_owner = nubes_postgres_user.pg_user.username
+ adopt_existing_on_create = true
+ # suspend_on_destroy = false
+}
+
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/README.md b/TEST_STAND/S3_EVENT_FUNCTION_POC/README.md
new file mode 100644
index 0000000..04a3999
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/README.md
@@ -0,0 +1,45 @@
+# S3 Event Function PoC (один apply, без создания `nubes_s3`)
+
+Стенд делает всё в рамках одного `terraform apply`:
+
+1. Создаёт `nubes_s3bucket` на существующем `s3_uid`.
+2. Автоматически запускает demo-check (`terraform_data + local-exec`).
+3. Demo-check пишет тестовый объект в бакет.
+4. Событие бакета доставляется в простую функцию, и apply печатает `CONFIRMED`.
+
+## Подготовка
+
+- Нужны: `terraform`, `python3`, `mc`.
+- В `terraform.tfvars` задайте `api_token`, `s3_uid`, `bucket_name`.
+- Путь к `.s3cfg_registry` можно оставить по умолчанию или задать переменной `s3cfg_path`.
+
+Можно взять `api_token` и `s3_uid` из `TEST_STAND/POSTGRES/terraform.tfvars`.
+
+## Запуск (одна команда apply)
+
+```bash
+cd TEST_STAND/S3_EVENT_FUNCTION_POC
+terraform init
+terraform apply -auto-approve
+```
+
+## Подтверждение, что сработало
+
+- Во время `apply` появится строка:
+ - `CONFIRMED: bucket event reached function ...`
+- После `apply` доступен output:
+ - `event_demo_confirmation`
+
+Проверить output:
+
+```bash
+terraform output event_demo_confirmation
+```
+
+## Отладка (если failed)
+
+Смотрите файлы в каталоге стенда:
+
+- `function_stdout.log`
+- `watcher_stdout.log`
+- `function.log`
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/apply_confirmation.txt b/TEST_STAND/S3_EVENT_FUNCTION_POC/apply_confirmation.txt
new file mode 100644
index 0000000..2f589ef
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/apply_confirmation.txt
@@ -0,0 +1,13 @@
+CONFIRMED ✓
+
+Source bucket : poc-s3evt-src
+Dest bucket : poc-s3evt-dst
+Object : event-trigger-1773587291.txt
+Time : Sun Mar 15 03:08:32 PM UTC 2026
+
+Что произошло:
+ 1. terraform создал два бакета: poc-s3evt-src и poc-s3evt-dst
+ 2. Скрипт написал 'event-trigger-1773587291.txt' в poc-s3evt-src
+ 3. Срабатывание подтверждено через: fallback check
+ 4. «Функция» скопировала объект в poc-s3evt-dst
+ 5. Копия подтверждена — тест пройден
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/main.tf b/TEST_STAND/S3_EVENT_FUNCTION_POC/main.tf
new file mode 100644
index 0000000..7fa2a0d
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/main.tf
@@ -0,0 +1,51 @@
+provider "nubes" {
+ api_token = var.api_token
+ api_endpoint = var.api_endpoint
+}
+
+# Бакет-источник — сюда пишем объект
+resource "nubes_s3bucket" "source" {
+ resource_name = "${var.bucket_name}-src"
+ s3_user_uid = var.s3_uid
+ bucket_name = "${var.bucket_name}-src"
+ adopt_existing_on_create = true # бакет уже создан предыдущим apply
+
+ max_size = -1
+ read_all = false
+ list_all = false
+ cors_all = false
+ placement = "HOT"
+}
+
+# Бакет-назначение — сюда копирует «функция» по событию
+resource "nubes_s3bucket" "dest" {
+ resource_name = "${var.bucket_name}-dst"
+ s3_user_uid = var.s3_uid
+ bucket_name = "${var.bucket_name}-dst"
+
+ max_size = -1
+ read_all = false
+ list_all = false
+ cors_all = false
+ placement = "HOT"
+}
+
+locals {
+ src_bucket = try(nubes_s3bucket.source.state_params["bucketName"], "${var.bucket_name}-src")
+ dst_bucket = try(nubes_s3bucket.dest.state_params["bucketName"], "${var.bucket_name}-dst")
+}
+
+# «Функция»: mc watch ловит событие в source → копирует объект в dest
+resource "terraform_data" "event_delivery_check" {
+ depends_on = [nubes_s3bucket.source, nubes_s3bucket.dest]
+
+ triggers_replace = {
+ src = local.src_bucket
+ dst = local.dst_bucket
+ s3cfg_path = var.s3cfg_path
+ }
+
+ provisioner "local-exec" {
+ command = "bash ${path.module}/scripts/copy_on_event.sh \"${var.s3cfg_path}\" \"${local.src_bucket}\" \"${local.dst_bucket}\" \"${var.demo_timeout_sec}\""
+ }
+}
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/outputs.tf b/TEST_STAND/S3_EVENT_FUNCTION_POC/outputs.tf
new file mode 100644
index 0000000..f372a89
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/outputs.tf
@@ -0,0 +1,11 @@
+output "source_bucket" {
+ value = nubes_s3bucket.source.state_params["bucketName"]
+}
+
+output "dest_bucket" {
+ value = nubes_s3bucket.dest.state_params["bucketName"]
+}
+
+output "event_demo_confirmation" {
+ value = try(trimspace(file("${path.module}/apply_confirmation.txt")), "confirmation file not found")
+}
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/apply_and_test.sh b/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/apply_and_test.sh
new file mode 100644
index 0000000..fcfc946
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/apply_and_test.sh
@@ -0,0 +1,27 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+
+if [[ ! -f "$ROOT_DIR/terraform.tfvars" ]]; then
+ echo "ERROR: $ROOT_DIR/terraform.tfvars not found"
+ echo "Create it from terraform.tfvars.example or reuse values from TEST_STAND/POSTGRES/terraform.tfvars"
+ exit 1
+fi
+
+cd "$ROOT_DIR"
+terraform init
+terraform apply -auto-approve
+
+BUCKET="$(terraform output -raw bucket_name 2>/dev/null || true)"
+if [[ -z "$BUCKET" ]]; then
+ echo "ERROR: bucket_name output is empty"
+ exit 1
+fi
+
+echo "Bucket created: $BUCKET"
+
+echo "Running event->function demo..."
+export S3CFG="${S3CFG:-/home/naeel/remote_dev/terraform/secrets/.s3cfg_registry}"
+export BUCKET
+bash "$ROOT_DIR/scripts/run_demo.sh"
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/copy_on_event.sh b/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/copy_on_event.sh
new file mode 100755
index 0000000..60e4bd3
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/copy_on_event.sh
@@ -0,0 +1,138 @@
+#!/usr/bin/env bash
+# Симуляция event-driven функции:
+# 1. mc watch следит за SOURCE бакетом (как S3 notification)
+# 2. При появлении объекта — "функция" копирует его в DEST бакет
+# 3. Подтверждение записывается в apply_confirmation.txt
+#
+# Аргументы: [timeout_sec]
+
+set -euo pipefail
+
+S3CFG="${1:?s3cfg_path required}"
+SRC_BUCKET="${2:?src_bucket required}"
+DST_BUCKET="${3:?dst_bucket required}"
+TIMEOUT="${4:-35}"
+
+SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
+POC_DIR="$(dirname "$SCRIPT_DIR")"
+CONFIRM_FILE="${POC_DIR}/apply_confirmation.txt"
+EVENTS_FILE="/tmp/poc_events_$$.json"
+ALIAS="poc$$"
+
+cleanup() {
+ kill "$WATCHER_PID" 2>/dev/null || true
+ rm -f "$EVENTS_FILE"
+ mc alias rm "$ALIAS" >/dev/null 2>&1 || true
+}
+trap cleanup EXIT
+
+echo "[poc] S3CFG: $S3CFG"
+echo "[poc] Source bucket : $SRC_BUCKET"
+echo "[poc] Dest bucket : $DST_BUCKET"
+echo "[poc] Timeout : ${TIMEOUT}s"
+
+# Парсим .s3cfg
+HOST=$(grep -E '^\s*host_base\s*=' "$S3CFG" | head -1 | sed 's/.*=\s*//' | tr -d '[:space:]')
+AK=$(grep -E '^\s*access_key\s*=' "$S3CFG" | head -1 | sed 's/.*=\s*//' | tr -d '[:space:]')
+SK=$(grep -E '^\s*secret_key\s*=' "$S3CFG" | head -1 | sed 's/.*=\s*//' | tr -d '[:space:]')
+USE_HTTPS=$(grep -E '^\s*use_https\s*=' "$S3CFG" | head -1 | sed 's/.*=\s*//' | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
+
+if [[ -z "$HOST" || -z "$AK" || -z "$SK" ]]; then
+ echo "[poc] ERROR: не удалось разобрать .s3cfg" >&2; exit 1
+fi
+
+SCHEME="https"
+if [[ "$USE_HTTPS" == "false" || "$USE_HTTPS" == "0" || "$USE_HTTPS" == "no" ]]; then
+ SCHEME="http"
+fi
+
+if [[ "$HOST" == http://* || "$HOST" == https://* ]]; then
+ ENDPOINT="$HOST"
+else
+ ENDPOINT="${SCHEME}://${HOST}"
+fi
+
+# Настраиваем mc alias
+mc alias set "$ALIAS" "$ENDPOINT" "$AK" "$SK" --api S3v4 >/dev/null 2>&1
+echo "[poc] mc alias '$ALIAS' → ${ENDPOINT}"
+
+# Запускаем mc watch на SOURCE (стримит события в файл)
+touch "$EVENTS_FILE"
+mc watch --json "${ALIAS}/${SRC_BUCKET}" >"$EVENTS_FILE" 2>&1 &
+WATCHER_PID=$!
+echo "[poc] mc watch запущен (pid=$WATCHER_PID)"
+sleep 2 # даём watch время подключиться
+
+# Имя триггерного объекта
+TRIGGER_KEY="event-trigger-$(date +%s).txt"
+echo "[poc] Пишем объект '${TRIGGER_KEY}' в ${SRC_BUCKET} (trigger)..."
+echo "S3 event PoC trigger — $(date -u)" | mc pipe "${ALIAS}/${SRC_BUCKET}/${TRIGGER_KEY}"
+echo "[poc] Объект записан. Ждём события через mc watch (макс ${TIMEOUT}s)..."
+
+# Ждём появления ключа в потоке событий mc watch
+ELAPSED=0
+EVENT_DETECTED=false
+EVENT_METHOD=""
+while [[ $ELAPSED -lt $TIMEOUT ]]; do
+ if grep -q "${TRIGGER_KEY}" "$EVENTS_FILE" 2>/dev/null; then
+ EVENT_DETECTED=true
+ EVENT_METHOD="mc watch"
+ echo "[poc] Событие обнаружено в потоке mc watch (через ${ELAPSED}s)"
+ break
+ fi
+ sleep 2
+ ELAPSED=$((ELAPSED + 2))
+done
+
+if [[ "$EVENT_DETECTED" != "true" ]]; then
+ echo "[poc] WARN: mc watch не поймал объект за ${TIMEOUT}s, проверяем напрямую..."
+ if mc ls "${ALIAS}/${SRC_BUCKET}/${TRIGGER_KEY}" >/dev/null 2>&1; then
+ EVENT_DETECTED=true
+ EVENT_METHOD="fallback check"
+ echo "[poc] Объект есть в source — выполняем копирование (fallback)"
+ fi
+fi
+
+if [[ "$EVENT_DETECTED" != "true" ]]; then
+ echo "[poc] FAILED: объект не найден в source bucket" >&2
+ cat >"$CONFIRM_FILE" </dev/null 2>&1; then
+ echo "[poc] FAILED: файл не найден в dest bucket" >&2
+ cat >"$CONFIRM_FILE" <"$CONFIRM_FILE" < ")
+ sys.exit(1)
+
+alias = sys.argv[1]
+bucket = sys.argv[2]
+
+cmd = ["mc", "watch", "--json", f"{alias}/{bucket}"]
+proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
+
+print(f"Watcher started for {alias}/{bucket}")
+
+for line in proc.stdout:
+ line = line.strip()
+ if not line:
+ continue
+
+ try:
+ payload = json.loads(line)
+ except json.JSONDecodeError:
+ continue
+
+ event = payload.get("eventName", "")
+ if not event:
+ continue
+
+ data = json.dumps(payload).encode("utf-8")
+ req = urllib.request.Request(
+ "http://127.0.0.1:8787/invoke",
+ method="POST",
+ data=data,
+ headers={"Content-Type": "application/json"},
+ )
+
+ with urllib.request.urlopen(req, timeout=5) as r:
+ _ = r.read()
+
+ print(f"forwarded event: {event}")
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/run_demo.sh b/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/run_demo.sh
new file mode 100644
index 0000000..b1dab96
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/run_demo.sh
@@ -0,0 +1,74 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+if ! command -v mc >/dev/null 2>&1; then
+ echo "ERROR: mc is not installed"
+ exit 1
+fi
+
+if [[ -z "${S3CFG:-}" ]]; then
+ echo "ERROR: set S3CFG (path to .s3cfg_registry)"
+ exit 1
+fi
+
+if [[ -z "${BUCKET:-}" ]]; then
+ echo "ERROR: set BUCKET"
+ exit 1
+fi
+
+RUNTIME_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+PROJECT_DIR="$(dirname "$RUNTIME_DIR")"
+
+python3 - < "$PROJECT_DIR/.mc_creds.tmp"
+import configparser
+cfg=configparser.RawConfigParser(); cfg.read("$S3CFG")
+sec=cfg["default"]
+print(sec.get("access_key",""))
+print(sec.get("secret_key",""))
+print(sec.get("host_base",""))
+PY
+
+ACCESS_KEY="$(sed -n '1p' "$PROJECT_DIR/.mc_creds.tmp")"
+SECRET_KEY="$(sed -n '2p' "$PROJECT_DIR/.mc_creds.tmp")"
+HOST_BASE="$(sed -n '3p' "$PROJECT_DIR/.mc_creds.tmp")"
+rm -f "$PROJECT_DIR/.mc_creds.tmp"
+
+if [[ -z "$ACCESS_KEY" || -z "$SECRET_KEY" || -z "$HOST_BASE" ]]; then
+ echo "ERROR: failed to read credentials from S3CFG"
+ exit 1
+fi
+
+ALIAS="poc"
+mc alias rm "$ALIAS" >/dev/null 2>&1 || true
+mc alias set "$ALIAS" "https://$HOST_BASE" "$ACCESS_KEY" "$SECRET_KEY" >/dev/null
+
+cd "$PROJECT_DIR"
+rm -f function.log .function.pid .watcher.pid
+
+python3 "$RUNTIME_DIR/function_server.py" > function_stdout.log 2>&1 &
+echo $! > .function.pid
+
+sleep 1
+python3 "$RUNTIME_DIR/poc_watch_and_invoke.py" "$ALIAS" "$BUCKET" > watcher_stdout.log 2>&1 &
+echo $! > .watcher.pid
+
+sleep 2
+printf "demo-%s\n" "$(date -u +%s)" > /tmp/poc_object.txt
+mc cp /tmp/poc_object.txt "$ALIAS/$BUCKET/poc/demo-$(date -u +%s).txt" >/dev/null
+
+sleep 3
+
+echo "=== function.log ==="
+if [[ -f function.log ]]; then
+ cat function.log
+else
+ echo "function.log is empty"
+fi
+
+echo "=== watcher_stdout.log (tail) ==="
+tail -n 20 watcher_stdout.log || true
+
+echo "Done. To stop background processes:"
+WATCHER_PID="$(cat .watcher.pid)"
+FUNCTION_PID="$(cat .function.pid)"
+echo " kill $WATCHER_PID $FUNCTION_PID"
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/single_apply_demo.sh b/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/single_apply_demo.sh
new file mode 100644
index 0000000..f5eba40
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/scripts/single_apply_demo.sh
@@ -0,0 +1,90 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+if [[ $# -lt 2 ]]; then
+ echo "usage: single_apply_demo.sh [timeout_sec]"
+ exit 1
+fi
+
+S3CFG="$1"
+BUCKET="$2"
+TIMEOUT_SEC="${3:-25}"
+
+WORKDIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
+ALIAS="applypoc"
+
+cleanup() {
+ set +e
+ if [[ -f "$WORKDIR/.watcher.pid" ]]; then kill "$(cat "$WORKDIR/.watcher.pid")" >/dev/null 2>&1 || true; fi
+ if [[ -f "$WORKDIR/.function.pid" ]]; then kill "$(cat "$WORKDIR/.function.pid")" >/dev/null 2>&1 || true; fi
+ mc alias rm "$ALIAS" >/dev/null 2>&1 || true
+}
+trap cleanup EXIT
+
+if ! command -v mc >/dev/null 2>&1; then
+ echo "FAILED: mc is not installed"
+ exit 1
+fi
+
+if [[ ! -f "$S3CFG" ]]; then
+ echo "FAILED: S3 cfg not found: $S3CFG"
+ exit 1
+fi
+
+readarray -t CREDS < <(python3 - </dev/null
+
+cd "$WORKDIR"
+rm -f function.log function_stdout.log watcher_stdout.log .function.pid .watcher.pid apply_confirmation.txt
+
+python3 "$WORKDIR/scripts/function_server.py" > "$WORKDIR/function_stdout.log" 2>&1 &
+echo $! > "$WORKDIR/.function.pid"
+
+sleep 1
+python3 "$WORKDIR/scripts/poc_watch_and_invoke.py" "$ALIAS" "$BUCKET" > "$WORKDIR/watcher_stdout.log" 2>&1 &
+echo $! > "$WORKDIR/.watcher.pid"
+
+sleep 2
+OBJ="poc/terraform-apply-$(date -u +%s).txt"
+printf "poc-%s\n" "$(date -u +%s)" > /tmp/s3_event_poc_payload.txt
+mc cp /tmp/s3_event_poc_payload.txt "$ALIAS/$BUCKET/$OBJ" >/dev/null
+
+FOUND=0
+for _i in $(seq 1 "$TIMEOUT_SEC"); do
+ if [[ -s "$WORKDIR/function.log" ]] && grep -q "eventName" "$WORKDIR/function.log"; then
+ FOUND=1
+ break
+ fi
+ sleep 1
+done
+
+if [[ "$FOUND" -eq 1 ]]; then
+ MSG="CONFIRMED: bucket event reached function for bucket=$BUCKET object=$OBJ"
+ echo "$MSG"
+ echo "$MSG" > "$WORKDIR/apply_confirmation.txt"
+ exit 0
+fi
+
+echo "FAILED: no event received by function within ${TIMEOUT_SEC}s"
+echo "--- function_stdout.log ---"
+tail -n 40 "$WORKDIR/function_stdout.log" || true
+echo "--- watcher_stdout.log ---"
+tail -n 40 "$WORKDIR/watcher_stdout.log" || true
+exit 1
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/terraform.tfvars.example b/TEST_STAND/S3_EVENT_FUNCTION_POC/terraform.tfvars.example
new file mode 100644
index 0000000..634f873
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/terraform.tfvars.example
@@ -0,0 +1,7 @@
+# Используйте существующий token/s3_uid из:
+# TEST_STAND/POSTGRES/terraform.tfvars
+
+api_token = ""
+api_endpoint = "https://deck-api-test.ngcloud.ru/api/v1/index.cfm"
+s3_uid = "332cdb0d-34bf-43bf-864d-4adcc3b556fb"
+bucket_name = "poc-s3-event-demo-001"
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/variables.tf b/TEST_STAND/S3_EVENT_FUNCTION_POC/variables.tf
new file mode 100644
index 0000000..690637d
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/variables.tf
@@ -0,0 +1,33 @@
+variable "api_token" {
+ description = "Nubes API token"
+ type = string
+ sensitive = true
+}
+
+variable "api_endpoint" {
+ description = "Deck API endpoint"
+ type = string
+ default = "https://deck-api-test.ngcloud.ru/api/v1/index.cfm"
+}
+
+variable "s3_uid" {
+ description = "UID существующего nubes_s3 (root S3 service)"
+ type = string
+}
+
+variable "bucket_name" {
+ description = "Имя создаваемого бакета"
+ type = string
+}
+
+variable "s3cfg_path" {
+ description = "Путь до .s3cfg_registry для доступа к S3"
+ type = string
+ default = "/home/naeel/remote_dev/terraform/secrets/.s3cfg_registry"
+}
+
+variable "demo_timeout_sec" {
+ description = "Таймаут ожидания события в функции"
+ type = number
+ default = 25
+}
diff --git a/TEST_STAND/S3_EVENT_FUNCTION_POC/versions.tf b/TEST_STAND/S3_EVENT_FUNCTION_POC/versions.tf
new file mode 100644
index 0000000..742ad35
--- /dev/null
+++ b/TEST_STAND/S3_EVENT_FUNCTION_POC/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = ">= 1.5.0"
+
+ required_providers {
+ nubes = {
+ source = "terra.k8c.ru/nubes/nubes"
+ version = "2.1.23"
+ }
+ }
+}