From 3009573b7b97905b9f82c5dd17bbc7e3f7060191 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Mon, 18 Mar 2024 17:12:46 +0530 Subject: [PATCH 001/102] Onix Version 0.2 - migrate from beckn-utilities --- README.md | 9 +- install/.gitignore | 11 + install/ENV/.env-generic-client-layer-sample | 19 ++ install/ENV/.env-webhook | 2 + install/RELEASE.md | 51 +++ install/START_BECKN.md | 101 ++++++ install/docker-compose-app.yml | 46 +++ install/docker-compose-v2.yml | 112 +++++++ install/docker-compose.yml | 118 +++++++ install/gateway_data/config/envvars | 2 + install/gateway_data/config/logger.properties | 20 ++ .../gateway_data/config/swf.properties-sample | 42 +++ install/gateway_data/database/.gitignore | 11 + .../bap-client.yaml-sample | 133 ++++++++ .../bap-network.yaml-sample | 133 ++++++++ .../bpp-client.yaml-sample | 131 ++++++++ .../bpp-network.yaml-sample | 131 ++++++++ install/registry_data/config/envvars | 2 + .../registry_data/config/logger.properties | 20 ++ .../config/swf.properties-sample | 39 +++ install/registry_data/database/.gitignore | 11 + install/release/RELEASE_0.1.0.md | 45 +++ install/scripts/banner.sh | 27 ++ install/scripts/generate_keys.sh | 27 ++ install/scripts/generic-client-layer.sh | 21 ++ install/scripts/get_container_details.sh | 8 + install/scripts/k8s/ConfigMap.yaml | 7 + install/scripts/k8s/deployment.yaml | 59 ++++ install/scripts/k8s/ingress.yaml | 24 ++ install/scripts/k8s/service.yaml | 33 ++ install/scripts/package_manager.sh | 152 +++++++++ install/scripts/register_gateway.sh | 32 ++ install/scripts/registry_entry.sh | 44 +++ install/scripts/update_bap_config.sh | 124 ++++++++ install/scripts/update_bpp_config.sh | 124 ++++++++ install/scripts/update_gateway_details.sh | 82 +++++ install/scripts/variables.sh | 53 ++++ install/start_beckn.sh | 117 +++++++ install/start_beckn_v2.sh | 296 ++++++++++++++++++ 39 files changed, 2417 insertions(+), 2 deletions(-) create mode 100644 install/.gitignore create mode 100644 install/ENV/.env-generic-client-layer-sample create mode 100644 install/ENV/.env-webhook create mode 100644 install/RELEASE.md create mode 100644 install/START_BECKN.md create mode 100644 install/docker-compose-app.yml create mode 100644 install/docker-compose-v2.yml create mode 100644 install/docker-compose.yml create mode 100644 install/gateway_data/config/envvars create mode 100644 install/gateway_data/config/logger.properties create mode 100644 install/gateway_data/config/swf.properties-sample create mode 100644 install/gateway_data/database/.gitignore create mode 100644 install/protocol-server-data/bap-client.yaml-sample create mode 100644 install/protocol-server-data/bap-network.yaml-sample create mode 100644 install/protocol-server-data/bpp-client.yaml-sample create mode 100644 install/protocol-server-data/bpp-network.yaml-sample create mode 100644 install/registry_data/config/envvars create mode 100644 install/registry_data/config/logger.properties create mode 100644 install/registry_data/config/swf.properties-sample create mode 100644 install/registry_data/database/.gitignore create mode 100644 install/release/RELEASE_0.1.0.md create mode 100755 install/scripts/banner.sh create mode 100755 install/scripts/generate_keys.sh create mode 100755 install/scripts/generic-client-layer.sh create mode 100755 install/scripts/get_container_details.sh create mode 100644 install/scripts/k8s/ConfigMap.yaml create mode 100644 install/scripts/k8s/deployment.yaml create mode 100644 install/scripts/k8s/ingress.yaml create mode 100644 install/scripts/k8s/service.yaml create mode 100755 install/scripts/package_manager.sh create mode 100755 install/scripts/register_gateway.sh create mode 100755 install/scripts/registry_entry.sh create mode 100755 install/scripts/update_bap_config.sh create mode 100755 install/scripts/update_bpp_config.sh create mode 100755 install/scripts/update_gateway_details.sh create mode 100755 install/scripts/variables.sh create mode 100755 install/start_beckn.sh create mode 100755 install/start_beckn_v2.sh diff --git a/README.md b/README.md index 0512dd0..b2677ad 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ -# onix -beckn onix +# ONIX + +ONIX - Open Network In A Box, is a project designed to effortlessly set up and maintain Beckn network that is scalable, secure and easy to maintain. + +In the install folder, you find a tool that helps install a Beckn network. This tool serves as a valuable resource for developers and network participants eager to explore BECKN protocols or join open networks supported by the BECKN protocol. By simplifying the installation process, ONIX streamlines the onboarding experience. For more details, refer to [release notes](./install/RELEASE.md) and [start with Beckn](./install/START_BECKN.md) + +Experience the convenience and efficiency of ONIX as you embark on your journey with BECKN protocols and open networks. diff --git a/install/.gitignore b/install/.gitignore new file mode 100644 index 0000000..38d6f13 --- /dev/null +++ b/install/.gitignore @@ -0,0 +1,11 @@ +docker_data +gateway_data/config/swf.properties +registry_data/config/swf.properties +.vscode +protocol-server-data/bap-client.yml +protocol-server-data/bap-network.yml +protocol-server-data/bpp-client.yml +protocol-server-data/bpp-network.yml +ENV/.env-generic-client-layer +registry.lock* +gateway.lock* diff --git a/install/ENV/.env-generic-client-layer-sample b/install/ENV/.env-generic-client-layer-sample new file mode 100644 index 0000000..f92d5bd --- /dev/null +++ b/install/ENV/.env-generic-client-layer-sample @@ -0,0 +1,19 @@ +APP_NAME="Generic Client Layer" +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_PORT=3000 +APP_URL=http://localhost + +LOG_CHANNEL=stack +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +PS_BASE_URI=BAP_CLIENT_URL +PS_BAP_ID=BAP_SUBSCRIBER_ID +PS_BAP_URI=BAP_SUBSCRIBER_URL + +PS_CITY_NAME=Bangalore +PS_CITY_CODE=std:080 +PS_COUNTRY_NAME=India +PS_COUNTRY_CODE=IND \ No newline at end of file diff --git a/install/ENV/.env-webhook b/install/ENV/.env-webhook new file mode 100644 index 0000000..880b376 --- /dev/null +++ b/install/ENV/.env-webhook @@ -0,0 +1,2 @@ +SANDBOXURL=http://sandbox-api:3000 +BPPCLIENTURL=http://bpp-client:6001 diff --git a/install/RELEASE.md b/install/RELEASE.md new file mode 100644 index 0000000..7fb2bd6 --- /dev/null +++ b/install/RELEASE.md @@ -0,0 +1,51 @@ +# Release Notes + +### Objective + +ONIX - Open Network In A Box. This install utility is designed to effortlessly set up all BECKN components on a machine using a one-click installer. This tool serves as a valuable resource for developers and network participants eager to explore BECKN protocols or join open networks supported by the BECKN protocol. By simplifying the installation process, ONIX streamlines the onboarding experience. + +Experience the convenience and efficiency of ONIX as you embark on your journey with BECKN protocols and open networks. + +| Version | Release Date | +| ------------------------------------------------------------------------------------------ | ------------ | +| [v0.1.0](https://github.com/beckn/beckn-utilities/blob/main/onix/release/RELEASE_0.1.0.md) | 2024-02-16 | + +## ONIX Version 0.2.0 (2024-03-01) + +### New Features + +- This release focuses on enabling the installation of individual components with user-provided configurations. +- It extends support to the Windows operating system, specifically Windows 10. +- Additionally, it now supports the Mac operating system. + +This release is specifically designed to facilitate the deployment of individual components, offering users the flexibility to customize configurations. Furthermore, it ensures seamless compatibility with both Windows and Mac operating systems. + +For a comprehensive summary of the features, refer [here](https://github.com/beckn/beckn-utilities/milestone/1?closed=1) + +### Enhancements + +- Support for Windows operating system. +- Support for Mac operating system. +- Can be used to install specific components with custom configuration. + +### Bug Fixes + +- None + +### Known Issues + +- None + +### Limitations + +- The current installer is tested only for Linux (Ubuntu) / Windows (windows 10) / Mac, it might support other flavors also. +- The current version supports only vertical scaling, horizontal scaling (ECS / EKS) is planned for an upcoming release +- When installing individual components, registration with the registry has to be done manually, this is explicitly done to avoid confusion and to prevent the network from incorrect or wrong registrations. + +### Upcoming Version + +- Support for horizontal scaling using Elastic Kubernetes Cluster. + +### Release Date + +- 2024-03-01 diff --git a/install/START_BECKN.md b/install/START_BECKN.md new file mode 100644 index 0000000..b7e3b13 --- /dev/null +++ b/install/START_BECKN.md @@ -0,0 +1,101 @@ +# ONIX Setup Script + +## Overview + +This shell script, `start_beckn_v2.sh`, automates the setup of Beckn components, including the Registry, Gateway, Protocol Server BAP, Protocol Server BPP, Sandbox, Webhook, and supporting services such as MongoDB, Redis, and RabbitMQ. + +## How to Use + +1. **Clone the Repository:** + + ```bash + git clone -b main https://github.com/beckn/onix.git + ``` + +2. **Navigate to the Script Directory:** + + ```bash + cd onix/install + ``` + +3. **Run the Setup Script:** + + ```bash + ./start_beckn_v2.sh + ``` + + The script will guide you through the installation. + +## Installation Sequence - Design + +1. **Install Required Packages:** + It will install Docker, Docker-Compose, and jq packages which are required for this setup. + + ```bash + ./package_manager.sh + ``` + +2. **Install Registry Service:** + + ```bash + ./start_container registry + ``` + +3. **Install Gateway Service:** + + ```bash + ./update_gateway_details.sh registry + ./start_container gateway + ./register_gateway.sh + ``` + +4. **Start Supporting Services:** + + - MongoDB + - RabbitMQ + - Redis + + ```bash + ./start_support_services + ``` + +5. **Install Protocol Server for BAP:** + + ```bash + ./update_bap_config.sh + ./start_container "bap-client" + ./start_container "bap-network" + ``` + +6. **Install Sandbox:** + + ```bash + ./start_container "sandbox-api" + ``` + +7. **Install Webhook:** + + ```bash + ./start_container "sandbox-webhook" + ``` + +8. **Install Protocol Server for BPP:** + + ```bash + ./update_bpp_config.sh + ./start_container "bpp-client" + ./start_container "bpp-network" + ``` + +## Post-Installation Details + +Upon successful execution, the script provides the following details for use in the Postman collection: +For Example + +```bash +BASE_URL=http://172.18.0.7:5001/ +BAP_ID=bap-network +BAP_URI=http://172.18.0.11:5002/ +BPP_ID=bpp-network +BPP_URI=http://172.18.0.12:6002/ +``` diff --git a/install/docker-compose-app.yml b/install/docker-compose-app.yml new file mode 100644 index 0000000..b31bac4 --- /dev/null +++ b/install/docker-compose-app.yml @@ -0,0 +1,46 @@ +version: "3" + +services: + mongo_db: + image: mongo + restart: unless-stopped + container_name: mongoDB + volumes: + - ./docker_data/mongo_DB:/data/db + networks: + - beckn_network + ports: + - "27017:27017" + environment: + - MONGO_INITDB_ROOT_USERNAME=beckn + - MONGO_INITDB_ROOT_PASSWORD=beckn123 + - MONGO_INITDB_DATABASE=protocol_server + + redis_db: + image: redis:6.2.5-alpine + restart: unless-stopped + container_name: redis + networks: + - beckn_network + ports: + - "6379:6379" + volumes: + - ./docker_data/redis_DB:/data + + queue_service: + image: rabbitmq:3.9.11-management-alpine + restart: unless-stopped + container_name: rabbitmq + networks: + - beckn_network + ports: + - "5672:5672" + - "15672:15672" + environment: + AMQP_URL: "amqp://queue_service?connection_attempts=3&retry_delay=5" + RABBITMQ_DEFAULT_USER: beckn + RABBITMQ_DEFAULT_PASS: beckn123 + +networks: + beckn_network: + driver: bridge \ No newline at end of file diff --git a/install/docker-compose-v2.yml b/install/docker-compose-v2.yml new file mode 100644 index 0000000..c6c906c --- /dev/null +++ b/install/docker-compose-v2.yml @@ -0,0 +1,112 @@ +version: '3' + +services: + registry: + image: fidedocker/registry + container_name: registry + networks: + - beckn_network + ports: + - 3000:3000 + - 3030:3030 + restart: unless-stopped + volumes: + - ./registry_data/config/swf.properties:/registry/overrideProperties/config/swf.properties + - ./registry_data/database:/registry/database + + gateway: + image: fidedocker/gateway + depends_on: + - registry + container_name: gateway + networks: + - beckn_network + ports: + - 4000:4000 + - 4030:4030 + restart: unless-stopped + volumes: + - ./gateway_data/config/swf.properties:/gateway/overrideProperties/config/swf.properties + - ./gateway_data/database:/gateway/database + + bap-client: + image: fidedocker/protocol-server + container_name: bap-client + networks: + - beckn_network + ports: + - 5001:5001 + restart: unless-stopped + volumes: + - ./protocol-server-data/bap-client.yml:/usr/src/app/config/default.yml + + bap-network: + image: fidedocker/protocol-server + container_name: bap-network + networks: + - beckn_network + ports: + - 5002:5002 + restart: unless-stopped + volumes: + - ./protocol-server-data/bap-network.yml:/usr/src/app/config/default.yml + + sandbox-api: + image: fidedocker/sandbox-api + container_name: sandbox-api + networks: + - beckn_network + ports: + - 4010:4000 + restart: unless-stopped + + sandbox-webhook: + image: fidedocker/sandbox-webhook-api + depends_on: + - sandbox-api + container_name: sandbox-webhook + networks: + - beckn_network + ports: + - 3005:3005 + restart: unless-stopped + volumes: + - ./ENV/.env-webhook:/usr/src/app/.env + + bpp-client: + image: fidedocker/protocol-server + container_name: bpp-client + networks: + - beckn_network + ports: + - 6001:6001 + restart: unless-stopped + volumes: + - ./protocol-server-data/bpp-client.yml:/usr/src/app/config/default.yml + + bpp-network: + image: fidedocker/protocol-server + container_name: bpp-network + networks: + - beckn_network + ports: + - 6002:6002 + restart: unless-stopped + volumes: + - ./protocol-server-data/bpp-network.yml:/usr/src/app/config/default.yml + + generic-client-layer: + image: fidedocker/generic-client-layer + container_name: generic-client-layer + networks: + - beckn_network + ports: + - 3015:3000 + restart: unless-stopped + volumes: + - ./ENV/.env-generic-client-layer:/app/.env + +networks: + beckn_network: + driver: bridge + diff --git a/install/docker-compose.yml b/install/docker-compose.yml new file mode 100644 index 0000000..eb44d7f --- /dev/null +++ b/install/docker-compose.yml @@ -0,0 +1,118 @@ +version: '3' + +services: + registry: + image: fidedocker/registry + container_name: registry + networks: + - beckn_network + ports: + - 3000:3000 + - 3030:3030 + restart: unless-stopped + volumes: + - ./registry_data/config/swf.properties:/registry/overrideProperties/config/swf.properties + - ./registry_data/database:/registry/database + + gateway: + image: fidedocker/gateway + depends_on: + - registry + container_name: gateway + networks: + - beckn_network + ports: + - 4000:4000 + - 4030:4030 + restart: unless-stopped + volumes: + - ./gateway_data/config/swf.properties:/gateway/overrideProperties/config/swf.properties + - ./gateway_data/database:/gateway/database + + bap-client: + image: fidedocker/protocol-server + depends_on: + - registry + - gateway + container_name: bap-client + networks: + - beckn_network + ports: + - 5001:5001 + restart: unless-stopped + volumes: + - ./protocol-server-data/bap-client.yml:/usr/src/app/config/default.yml + + bap-network: + image: fidedocker/protocol-server + depends_on: + - registry + - gateway + container_name: bap-network + networks: + - beckn_network + ports: + - 5002:5002 + restart: unless-stopped + volumes: + - ./protocol-server-data/bap-network.yml:/usr/src/app/config/default.yml + + sandbox-api: + image: fidedocker/sandbox-api + depends_on: + - registry + - gateway + container_name: sandbox-api + networks: + - beckn_network + ports: + - 4010:4000 + restart: unless-stopped + + sandbox-webhook: + image: fidedocker/sandbox-webhook-api + depends_on: + - registry + - gateway + - sandbox-api + container_name: sandbox-webhook + networks: + - beckn_network + ports: + - 3005:3005 + restart: unless-stopped + volumes: + - ./ENV/.env-webhook:/usr/src/app/.env + + bpp-client: + image: fidedocker/protocol-server + depends_on: + - registry + - gateway + container_name: bpp-client + networks: + - beckn_network + ports: + - 6001:6001 + restart: unless-stopped + volumes: + - ./protocol-server-data/bpp-client.yml:/usr/src/app/config/default.yml + + bpp-network: + image: fidedocker/protocol-server + depends_on: + - registry + - gateway + container_name: bpp-network + networks: + - beckn_network + ports: + - 6002:6002 + restart: unless-stopped + volumes: + - ./protocol-server-data/bpp-network.yml:/usr/src/app/config/default.yml + +networks: + beckn_network: + driver: bridge + diff --git a/install/gateway_data/config/envvars b/install/gateway_data/config/envvars new file mode 100644 index 0000000..b078dd9 --- /dev/null +++ b/install/gateway_data/config/envvars @@ -0,0 +1,2 @@ +export dport=4000 +export wport=4030 diff --git a/install/gateway_data/config/logger.properties b/install/gateway_data/config/logger.properties new file mode 100644 index 0000000..a9711be --- /dev/null +++ b/install/gateway_data/config/logger.properties @@ -0,0 +1,20 @@ +com.venky.core.log.InfoFileHandler.limit=500000 +com.venky.core.log.InfoFileHandler.count=2 +com.venky.core.log.InfoFileHandler.formatter=java.util.logging.SimpleFormatter +com.venky.core.log.InfoFileHandler.pattern=tmp/java_info%u.log +com.venky.core.log.InfoFileHandler.level=ALL + +com.venky.core.log.WarningFileHandler.limit=500000 +com.venky.core.log.WarningFileHandler.count=2 +com.venky.core.log.WarningFileHandler.formatter=java.util.logging.SimpleFormatter +com.venky.core.log.WarningFileHandler.pattern=tmp/java_warn%u.log +com.venky.core.log.WarningFileHandler.level=WARNING + + +handlers=com.venky.core.log.WarningFileHandler com.venky.core.log.InfoFileHandler +logger.useParentHandlers=false + +.level=INFO +com.venky.swf.plugins.background.core.level=FINEST +com.venky.swf.db.Database.level=FINEST +#com.venky.core.log.TimerStatistics.level=FINE diff --git a/install/gateway_data/config/swf.properties-sample b/install/gateway_data/config/swf.properties-sample new file mode 100644 index 0000000..33a2e14 --- /dev/null +++ b/install/gateway_data/config/swf.properties-sample @@ -0,0 +1,42 @@ +swf.load.complete.config.tables.if.count.less.than=500 +swf.user.password.encrypted=false +swf.plugins.background.core.workers.numThreads=1 +swf.application.authentication.required=false +beckn.network.timeout=10000 + + +#swf.host=localhost +swf.host=GATEWAY_URL +swf.external.port=GATEWAY_PORT +swf.external.scheme=PROTOCOL + + +swf.jdbc.driver=org.h2.Driver +swf.jdbc.url=jdbc:h2:./database/gateway;AUTO_SERVER=TRUE; +swf.jdbc.userid=gateway +swf.jdbc.password=gateway +swf.jdbc.validationQuery=values(1) +swf.jdbc.dbschema=PUBLIC +swf.jdbc.dbschema.setonconnection=true +swf.jdbc.set.dbschema.command=set schema public + + +# These keys are needed if you want to in.succinct.beckn.gateway.subscriber_iduse push notifications. +# you can generate this from https://d3v.one/vapid-key-generator/ or similiar sites. +# you also need to specify the public key in src/main/resources/scripts/application.js + +#push.server.private.key=your_private_key +#push.server.public.key=your_public_key + +## Beckn Gateway configurations. + +beckn.auth.enabled=true +in.succinct.beckn.gateway.subscriber_id=SUBSCRIBER_ID +in.succinct.beckn.gateway.public_key_id=SUBSCRIBER_ID.k1 +in.succinct.beckn.registry.url=REGISTRY_URL +in.succinct.beckn.registry.signing_public_key=SIGNING_PUBLIC_KEY +in.succinct.beckn.registry.encryption_public_key=ENCRYPTION_PUBLIC_KEY + +swf.encryption.support=false +#swf.key.store.directory=./.keystore + diff --git a/install/gateway_data/database/.gitignore b/install/gateway_data/database/.gitignore new file mode 100644 index 0000000..38d6f13 --- /dev/null +++ b/install/gateway_data/database/.gitignore @@ -0,0 +1,11 @@ +docker_data +gateway_data/config/swf.properties +registry_data/config/swf.properties +.vscode +protocol-server-data/bap-client.yml +protocol-server-data/bap-network.yml +protocol-server-data/bpp-client.yml +protocol-server-data/bpp-network.yml +ENV/.env-generic-client-layer +registry.lock* +gateway.lock* diff --git a/install/protocol-server-data/bap-client.yaml-sample b/install/protocol-server-data/bap-client.yaml-sample new file mode 100644 index 0000000..610c5c8 --- /dev/null +++ b/install/protocol-server-data/bap-client.yaml-sample @@ -0,0 +1,133 @@ +# Mandatory +server: + port: BAP_CLIENT_PORT + +# Mandatory. +cache: + host: "REDIS_URL" + port: 6379 + ttl: "PT10M" + # Optional. Default is 0. + db: 1 + +# Optional. +responseCache: + mongoURL: "mongodb://MONGO_USERNAME:MONGO_PASSWORD@MONOG_URL/MONGO_DB_NAME?authSource=admin" + ttl: "PT10M" + +# Mandatory. +# Priority order will be +# 1. Synchronous +# 2. webhook +# 3. pubSub +client: + synchronous: + mongoURL: "mongodb://MONGO_USERNAME:MONGO_PASSWORD@MONOG_URL/MONGO_DB_NAME?authSource=admin" + + #webhook: + # url: "https://beckn.free.beeceptor.com/clientURL" + + #messageQueue: + # amqpURL: "amqp://guest:guest@localhost:5672" + # incomingQueue: "protocol-server-incoming" + # outgoingQueue: "protocol-server-outgoing" + +# Mandatory. +app: + # Mandatory. + mode: bap + + # Two types of gateway mode present. + # client and network. + gateway: + mode: client + inboxQueue: "inbox" + outboxQueue: "outbox" + amqpURL: "amqp://RABBITMQ_USERNAME:RABBITMQ_PASSWORD@RABBITMQ_URL:5672" + + # Mandatory. + actions: + requests: + search: + ttl : "PT15S" + init: + ttl : "PT10S" + select: + ttl : "PT10S" + confirm: + ttl : "PT10S" + status: + ttl : "PT10S" + track: + ttl : "PT10S" + cancel: + ttl : "PT10S" + update: + ttl : "PT10S" + rating: + ttl : "PT10S" + support: + ttl : "PT10S" + get_cancellation_reasons: + ttl : "PT10S" + get_rating_categories: + ttl : "PT10S" + cancellation: + ttl : "PT10S" + + responses: + on_search: + ttl: "PT15S" + on_init: + ttl: "PT10S" + on_select: + ttl: "PT10S" + on_confirm: + ttl: "PT10S" + on_status: + ttl: "PT10S" + on_track: + ttl: "PT10S" + on_cancel: + ttl: "PT10S" + on_update: + ttl: "PT10S" + on_rating: + ttl: "PT10S" + on_support: + ttl: "PT10S" + cancellation_reasons: + ttl: "PT10S" + rating_categories: + ttl: "PT10S" + + # Mandatory. + privateKey: "PRIVATE_KEY" + publicKey: "PUBLIC_KEY" + + # Mandatory. + subscriberId: "BAP_SUBSCRIBER_ID" + subscriberUri: "BAP_SUBSCRIBER_URL" + + # Mandatory. + registryUrl: REGISTRY_URL + auth: false + uniqueKey: "BAP_SUBSCRIBER_ID_KEY" + + # Mandatory. + city: "std:080" + country: "IND" + + # Mandatory. + ttl: "PT10M" + + # Mandatory. + httpTimeout: "PT3S" + httpRetryCount: 2 + telemetry: + enabled: false + url: "" + batchSize: 100 + # In minutes + syncInterval: 30 + redis_db: 3 \ No newline at end of file diff --git a/install/protocol-server-data/bap-network.yaml-sample b/install/protocol-server-data/bap-network.yaml-sample new file mode 100644 index 0000000..ec34c41 --- /dev/null +++ b/install/protocol-server-data/bap-network.yaml-sample @@ -0,0 +1,133 @@ +# Mandatory +server: + port: BAP_NETWORK_PORT + +# Mandatory. +cache: + host: "REDIS_URL" + port: 6379 + ttl: "PT10M" + # Optional. Default is 0. + db: 1 + +# Optional. +responseCache: + mongoURL: "mongodb://MONGO_USERNAME:MONGO_PASSWORD@MONOG_URL/MONGO_DB_NAME?authSource=admin" + ttl: "PT10M" + +# Mandatory. +# Priority order will be +# 1. Synchronous +# 2. webhook +# 3. pubSub +client: + synchronous: + mongoURL: "mongodb://MONGO_USERNAME:MONGO_PASSWORD@MONOG_URL/MONGO_DB_NAME?authSource=admin" + + #webhook: + # url: "https://beckn.free.beeceptor.com/clientURL" + + #messageQueue: + # amqpURL: "amqp://guest:guest@localhost:5672" + # incomingQueue: "protocol-server-incoming" + # outgoingQueue: "protocol-server-outgoing" + +# Mandatory. +app: + # Mandatory. + mode: bap + + # Two types of gateway mode present. + # client and network. + gateway: + mode: network + inboxQueue: "inbox" + outboxQueue: "outbox" + amqpURL: "amqp://RABBITMQ_USERNAME:RABBITMQ_PASSWORD@RABBITMQ_URL:5672" + + # Mandatory. + actions: + requests: + search: + ttl : "PT15S" + init: + ttl : "PT10S" + select: + ttl : "PT10S" + confirm: + ttl : "PT10S" + status: + ttl : "PT10S" + track: + ttl : "PT10S" + cancel: + ttl : "PT10S" + update: + ttl : "PT10S" + rating: + ttl : "PT10S" + support: + ttl : "PT10S" + get_cancellation_reasons: + ttl : "PT10S" + get_rating_categories: + ttl : "PT10S" + cancellation: + ttl : "PT10S" + + responses: + on_search: + ttl: "PT15S" + on_init: + ttl: "PT10S" + on_select: + ttl: "PT10S" + on_confirm: + ttl: "PT10S" + on_status: + ttl: "PT10S" + on_track: + ttl: "PT10S" + on_cancel: + ttl: "PT10S" + on_update: + ttl: "PT10S" + on_rating: + ttl: "PT10S" + on_support: + ttl: "PT10S" + cancellation_reasons: + ttl: "PT10S" + rating_categories: + ttl: "PT10S" + + # Mandatory. + privateKey: "PRIVATE_KEY" + publicKey: "PUBLIC_KEY" + + # Mandatory. + subscriberId: "BAP_SUBSCRIBER_ID" + subscriberUri: "BAP_SUBSCRIBER_URL" + + # Mandatory. + registryUrl: REGISTRY_URL + auth: false + uniqueKey: "BAP_SUBSCRIBER_ID_KEY" + + # Mandatory. + city: "std:080" + country: "IND" + + # Mandatory. + ttl: "PT10M" + + # Mandatory. + httpTimeout: "PT3S" + httpRetryCount: 2 + telemetry: + enabled: false + url: "" + batchSize: 100 + # In minutes + syncInterval: 30 + redis_db: 3 \ No newline at end of file diff --git a/install/protocol-server-data/bpp-client.yaml-sample b/install/protocol-server-data/bpp-client.yaml-sample new file mode 100644 index 0000000..d3dd737 --- /dev/null +++ b/install/protocol-server-data/bpp-client.yaml-sample @@ -0,0 +1,131 @@ +# Mandatory +server: + port: BPP_CLIENT_PORT + +# Mandatory. +cache: + host: "REDIS_URL" + port: 6379 + ttl: "PT10M" + # Optional. Default is 0. + db: 0 + +# Optional. +responseCache: + mongoURL: "mongodb://MONGO_USERNAME:MONGO_PASSWORD@MONOG_URL/MONGO_DB_NAME?authSource=admin" + ttl: "PT10M" + +# Mandatory. +# Priority order will be +# 1. Synchronous +# 2. webhook +# 3. pubSub +client: +# synchronous: +# mongoURL: "mongodb://tvast:password@mongoDB:27017/ps?authSource=admin" + + webhook: + url: "WEBHOOK_URL" + + #messageQueue: + # amqpURL: "amqp://guest:guest@localhost:5672" + # incomingQueue: "protocol-server-incoming" + # outgoingQueue: "protocol-server-outgoing" + +# Mandatory. +app: + # Mandatory. + mode: bpp + + # Two types of gateway mode present. + # client and network. + gateway: + mode: client + inboxQueue: "inbox-bpp" + outboxQueue: "outbox-bpp" + amqpURL: "amqp://RABBITMQ_USERNAME:RABBITMQ_PASSWORD@RABBITMQ_URL:5672" + + # Mandatory. + actions: + requests: + search: + ttl : "PT15S" + init: + ttl : "PT10S" + select: + ttl : "PT10S" + confirm: + ttl : "PT10S" + status: + ttl : "PT10S" + track: + ttl : "PT10S" + cancel: + ttl : "PT10S" + update: + ttl : "PT10S" + rating: + ttl : "PT10S" + support: + ttl : "PT10S" + get_cancellation_reasons: + ttl: "PT10S" + get_rating_categories: + ttl: "PT10S" + + responses: + on_search: + ttl: "PT15S" + on_init: + ttl: "PT10S" + on_select: + ttl: "PT10S" + on_confirm: + ttl: "PT10S" + on_status: + ttl: "PT10S" + on_track: + ttl: "PT10S" + on_cancel: + ttl: "PT10S" + on_update: + ttl: "PT10S" + on_rating: + ttl: "PT10S" + on_support: + ttl: "PT10S" + cancellation_reasons: + ttl: "PT10S" + rating_categories: + ttl: "PT10S" + + # Mandatory. + privateKey: "PRIVATE_KEY" + publicKey: "PUBLIC_KEY" + + # Mandatory. + subscriberId: "BPP_SUBSCRIBER_ID" + subscriberUri: "BPP_SUBSCRIBER_URL" + + # Mandatory. + registryUrl: REGISTRY_URL + auth: true + uniqueKey: "BPP_SUBSCRIBER_ID_KEY" + + # Mandatory. + city: "std:080" + country: "IND" + + # Mandatory. + ttl: "PT10M" + + # Mandatory. + httpTimeout: "PT3S" + httpRetryCount: 2 + telemetry: + enabled: false + url: "" + batchSize: 100 + # In minutes + syncInterval: 30 + redis_db: 3 \ No newline at end of file diff --git a/install/protocol-server-data/bpp-network.yaml-sample b/install/protocol-server-data/bpp-network.yaml-sample new file mode 100644 index 0000000..0987b21 --- /dev/null +++ b/install/protocol-server-data/bpp-network.yaml-sample @@ -0,0 +1,131 @@ +# Mandatory +server: + port: BPP_NETWORK_PORT + +# Mandatory. +cache: + host: "REDIS_URL" + port: 6379 + ttl: "PT10M" + # Optional. Default is 0. + db: 0 + +# Optional. +responseCache: + mongoURL: "mongodb://MONGO_USERNAME:MONGO_PASSWORD@MONOG_URL/MONGO_DB_NAME?authSource=admin" + ttl: "PT10M" + +# Mandatory. +# Priority order will be +# 1. Synchronous +# 2. webhook +# 3. pubSub +client: +# synchronous: +# mongoURL: "mongodb://tvast:password@mongoDB:27017/ps?authSource=admin" + + webhook: + url: "WEBHOOK_URL" + + #messageQueue: + # amqpURL: "amqp://guest:guest@localhost:5672" + # incomingQueue: "protocol-server-incoming" + # outgoingQueue: "protocol-server-outgoing" + +# Mandatory. +app: + # Mandatory. + mode: bpp + + # Two types of gateway mode present. + # client and network. + gateway: + mode: network + inboxQueue: "inbox-bpp" + outboxQueue: "outbox-bpp" + amqpURL: "amqp://RABBITMQ_USERNAME:RABBITMQ_PASSWORD@RABBITMQ_URL:5672" + + # Mandatory. + actions: + requests: + search: + ttl : "PT15S" + init: + ttl : "PT10S" + select: + ttl : "PT10S" + confirm: + ttl : "PT10S" + status: + ttl : "PT10S" + track: + ttl : "PT10S" + cancel: + ttl : "PT10S" + update: + ttl : "PT10S" + rating: + ttl : "PT10S" + support: + ttl : "PT10S" + get_cancellation_reasons: + ttl: "PT10S" + get_rating_categories: + ttl: "PT10S" + + responses: + on_search: + ttl: "PT15S" + on_init: + ttl: "PT10S" + on_select: + ttl: "PT10S" + on_confirm: + ttl: "PT10S" + on_status: + ttl: "PT10S" + on_track: + ttl: "PT10S" + on_cancel: + ttl: "PT10S" + on_update: + ttl: "PT10S" + on_rating: + ttl: "PT10S" + on_support: + ttl: "PT10S" + cancellation_reasons: + ttl: "PT10S" + rating_categories: + ttl: "PT10S" + + # Mandatory. + privateKey: "PRIVATE_KEY" + publicKey: "PUBLIC_KEY" + + # Mandatory. + subscriberId: "BPP_SUBSCRIBER_ID" + subscriberUri: "BPP_SUBSCRIBER_URL" + + # Mandatory. + registryUrl: REGISTRY_URL + auth: true + uniqueKey: "BPP_SUBSCRIBER_ID_KEY" + + # Mandatory. + city: "std:080" + country: "IND" + + # Mandatory. + ttl: "PT10M" + + # Mandatory. + httpTimeout: "PT3S" + httpRetryCount: 2 + telemetry: + enabled: false + url: "" + batchSize: 100 + # In minutes + syncInterval: 30 + redis_db: 3 \ No newline at end of file diff --git a/install/registry_data/config/envvars b/install/registry_data/config/envvars new file mode 100644 index 0000000..0965d04 --- /dev/null +++ b/install/registry_data/config/envvars @@ -0,0 +1,2 @@ +export dport=3000 +export wport=3030 diff --git a/install/registry_data/config/logger.properties b/install/registry_data/config/logger.properties new file mode 100644 index 0000000..a9711be --- /dev/null +++ b/install/registry_data/config/logger.properties @@ -0,0 +1,20 @@ +com.venky.core.log.InfoFileHandler.limit=500000 +com.venky.core.log.InfoFileHandler.count=2 +com.venky.core.log.InfoFileHandler.formatter=java.util.logging.SimpleFormatter +com.venky.core.log.InfoFileHandler.pattern=tmp/java_info%u.log +com.venky.core.log.InfoFileHandler.level=ALL + +com.venky.core.log.WarningFileHandler.limit=500000 +com.venky.core.log.WarningFileHandler.count=2 +com.venky.core.log.WarningFileHandler.formatter=java.util.logging.SimpleFormatter +com.venky.core.log.WarningFileHandler.pattern=tmp/java_warn%u.log +com.venky.core.log.WarningFileHandler.level=WARNING + + +handlers=com.venky.core.log.WarningFileHandler com.venky.core.log.InfoFileHandler +logger.useParentHandlers=false + +.level=INFO +com.venky.swf.plugins.background.core.level=FINEST +com.venky.swf.db.Database.level=FINEST +#com.venky.core.log.TimerStatistics.level=FINE diff --git a/install/registry_data/config/swf.properties-sample b/install/registry_data/config/swf.properties-sample new file mode 100644 index 0000000..7049488 --- /dev/null +++ b/install/registry_data/config/swf.properties-sample @@ -0,0 +1,39 @@ +swf.load.complete.config.tables.if.count.less.than=500 +swf.user.password.encrypted=false +swf.plugins.background.core.workers.numThreads=1 +swf.application.authentication.required=false + + + +#swf.host=localhost +swf.host=REGISTRY_URL +swf.external.port=REGISTRY_PORT +swf.external.scheme=PROTOCOL + + +swf.jdbc.driver=org.h2.Driver +swf.jdbc.url=jdbc:h2:./database/registry;AUTO_SERVER=TRUE; +swf.jdbc.userid=registry +swf.jdbc.password=registry +swf.jdbc.validationQuery=values(1) +swf.jdbc.dbschema=PUBLIC +swf.jdbc.dbschema.setonconnection=true +swf.jdbc.set.dbschema.command=set schema public + + +# These keys are needed if you want to use push notifications. +# you can generate this from https://d3v.one/vapid-key-generator/ or similiar sites. +# you also need to specify the public key in src/main/resources/scripts/application.js + +#push.server.private.key=your_private_key +#push.server.public.key=your_public_key + +swf.api.keys.case=SNAKE +swf.api.root.required=false + +swf.encryption.support=false +#swf.key.store.directory=./.keystore + +# Needed for Google Login +#swf.GOOGLE.client.id= +#swf.GOOGLE.client.secret= diff --git a/install/registry_data/database/.gitignore b/install/registry_data/database/.gitignore new file mode 100644 index 0000000..38d6f13 --- /dev/null +++ b/install/registry_data/database/.gitignore @@ -0,0 +1,11 @@ +docker_data +gateway_data/config/swf.properties +registry_data/config/swf.properties +.vscode +protocol-server-data/bap-client.yml +protocol-server-data/bap-network.yml +protocol-server-data/bpp-client.yml +protocol-server-data/bpp-network.yml +ENV/.env-generic-client-layer +registry.lock* +gateway.lock* diff --git a/install/release/RELEASE_0.1.0.md b/install/release/RELEASE_0.1.0.md new file mode 100644 index 0000000..e8fc5bd --- /dev/null +++ b/install/release/RELEASE_0.1.0.md @@ -0,0 +1,45 @@ +# Release Notes + +## ONIX Version 0.1.0 (2024-02-16) + +### Objective +ONIX - Open Network In A Box, is a utility designed to effortlessly set up all BECKN components on a machine using a one-click installer. This tool serves as a valuable resource for developers and network participants eager to explore BECKN protocols or join open networks supported by the BECKN protocol. By simplifying the installation process, ONIX streamlines the onboarding experience. + +The current version installs all components automatically without requiring user input, facilitating a seamless setup process. However, we are committed to further enhancing ONIX's functionality. In the upcoming release, we will introduce the capability to selectively install specific components and accommodate user-provided configurations. + +For a comprehensive summary of the features, refer [here](https://github.com/beckn/beckn-utilities/milestone/2?closed=1) + +Experience the convenience and efficiency of ONIX as you embark on your journey with BECKN protocols and open networks. + +### New Features +- Implemented installation support for the following BECKN components: + - Protocol Server BAP + - Protocol Server BPP + - Webhook BPP + - Sandbox + - Registry + - Gateway + - Infrastructure required for the above services + +This release is specifically tailored for deployment on Linux machines, encompassing all aforementioned components with default configurations. + +### Enhancements +- None + +### Bug Fixes +- None + +### Known Issues +- None + +### Limitations +- The current installer is tested only for Linux (Ubuntu), it might support other flavors also. +- The current version installs all the components with the default configurations. + + +### Upcoming Version +- Installation of individual components with user-provided configuration. +- Support for Windows and Mac OS will be added. + +### Release Date +- 2024-02-16 diff --git a/install/scripts/banner.sh b/install/scripts/banner.sh new file mode 100755 index 0000000..1043418 --- /dev/null +++ b/install/scripts/banner.sh @@ -0,0 +1,27 @@ +#!/bin/bash +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source $SCRIPT_DIR/variables.sh + +# Define the text to print in the banner +text=" + ###### ####### ##### # # # # + # # # # # # # ## # + # # # # # # # # # + ###### ##### # ### # # # + # # # # # # # # # + # # # # # # # # ## + ###### ####### ##### # # # # +" + +text2=" + ######## ######## ###### ## ## ## ## + ## ## ## ## ## ## ## ### ## + ## ## ## ## ## ## #### ## + ######## ###### ## ##### ## ## ## + ## ## ## ## ## ## ## #### + ## ## ## ## ## ## ## ## ### + ######## ######## ###### ## ## ## ## +" +# Clear the terminal screen +clear +echo "${GREEN}$text2${NC}" diff --git a/install/scripts/generate_keys.sh b/install/scripts/generate_keys.sh new file mode 100755 index 0000000..f887fcf --- /dev/null +++ b/install/scripts/generate_keys.sh @@ -0,0 +1,27 @@ +#!/bin/bash +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source $SCRIPT_DIR/variables.sh + +# Run the script that generates keys and capture the output +get_keys() { + docker pull fidedocker/protocol-server > /dev/null 2>&1 + docker run --name temp -itd fidedocker/protocol-server > /dev/null 2>&1 + output=$(docker exec -it temp node /usr/src/app/scripts/generate-keys 2>&1) + docker stop temp > /dev/null 2>&1 + docker rm temp > /dev/null 2>&1 +# Check if the script executed successfully +if [ $? -eq 0 ]; then + # Extract Public Key and Private Key using grep and awk + public_key=$(echo "$output" | awk '/Your Public Key/ {getline; print $0}') + private_key=$(echo "$output" | awk '/Your Private Key/ {getline; print $0}') + # Remove leading and trailing whitespaces + public_key=$(echo "$public_key" | tr -d '[:space:]') + private_key=$(echo "$private_key" | tr -d '[:space:]') + +else + # Print an error message if the script failed + echo "${RED}Error: Key generation script failed. Please check the script output.${NC}" +fi +} + +#get_keys \ No newline at end of file diff --git a/install/scripts/generic-client-layer.sh b/install/scripts/generic-client-layer.sh new file mode 100755 index 0000000..f8dc7f4 --- /dev/null +++ b/install/scripts/generic-client-layer.sh @@ -0,0 +1,21 @@ +#!/bin/bash +update_env_file(){ + cp ../ENV/.env-generic-client-layer-sample ../ENV/.env-generic-client-layer + envFile=../ENV/.env-generic-client-layer + bap_subscriber_id=$1 + bap_subscriber_url=$2 + bap_client_url=$3 + + if [[ $(uname) == "Darwin" ]]; then + sed -i '' "s|BAP_SUBSCRIBER_ID|$bap_subscriber_id|" $envFile + sed -i '' "s|BAP_SUBSCRIBER_URL|$bap_subscriber_url|" $envFile + sed -i '' "s|BAP_CLIENT_URL|$bap_client_url|" $envFile + else + sed -i "s|BAP_SUBSCRIBER_ID|$bap_subscriber_id|" $envFile + sed -i "s|BAP_SUBSCRIBER_URL|$bap_subscriber_url|" $envFile + sed -i "s|BAP_CLIENT_URL|$bap_client_url|" $envFile + fi + +} + +update_env_file $1 $2 $3 \ No newline at end of file diff --git a/install/scripts/get_container_details.sh b/install/scripts/get_container_details.sh new file mode 100755 index 0000000..4b093e6 --- /dev/null +++ b/install/scripts/get_container_details.sh @@ -0,0 +1,8 @@ +#!/bin/bash +get_container_ip() { + container_name=$1 + container_ip=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' $container_name) + echo $container_ip +} + +#get_container_ip $1 \ No newline at end of file diff --git a/install/scripts/k8s/ConfigMap.yaml b/install/scripts/k8s/ConfigMap.yaml new file mode 100644 index 0000000..04ef557 --- /dev/null +++ b/install/scripts/k8s/ConfigMap.yaml @@ -0,0 +1,7 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: swf-config +data: + swf.properties: | + # Content of swf.properties file for registry diff --git a/install/scripts/k8s/deployment.yaml b/install/scripts/k8s/deployment.yaml new file mode 100644 index 0000000..012efed --- /dev/null +++ b/install/scripts/k8s/deployment.yaml @@ -0,0 +1,59 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: registry-deployment +spec: + replicas: 1 + selector: + matchLabels: + app: registry + template: + metadata: + labels: + app: registry + spec: + containers: + - name: registry + image: fidedocker/registry + ports: + - containerPort: 3000 + - containerPort: 3030 + volumeMounts: + - name: registry-data + mountPath: /registry + volumes: + - name: registry-data + hostPath: + path: /absolute/path/to/registry_data/ + +--- + +apiVersion: apps/v1 +kind: Deployment +metadata: + name: gateway-deployment +spec: + replicas: 1 + selector: + matchLabels: + app: gateway + template: + metadata: + labels: + app: gateway + spec: + containers: + - name: gateway + image: fidedocker/gateway + ports: + - containerPort: 4000 + - containerPort: 4030 + volumeMounts: + - name: gateway-data + mountPath: /gateway + volumes: + - name: gateway-data + hostPath: + path: /path/to/gateway_data + +# Repeat the above structure for other services diff --git a/install/scripts/k8s/ingress.yaml b/install/scripts/k8s/ingress.yaml new file mode 100644 index 0000000..67888e5 --- /dev/null +++ b/install/scripts/k8s/ingress.yaml @@ -0,0 +1,24 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: beckn-ingress +spec: + rules: + - host: localhost + http: + paths: + - path: /registry + pathType: Prefix + backend: + service: + name: registry-service + port: + number: 3000 + - path: /gateway + pathType: Prefix + backend: + service: + name: gateway-service + port: + number: 4000 + # Repeat the above structure for other services diff --git a/install/scripts/k8s/service.yaml b/install/scripts/k8s/service.yaml new file mode 100644 index 0000000..bdd818c --- /dev/null +++ b/install/scripts/k8s/service.yaml @@ -0,0 +1,33 @@ +apiVersion: v1 +kind: Service +metadata: + name: registry-service +spec: + selector: + app: registry + ports: + - protocol: TCP + port: 3000 + targetPort: 3000 + - protocol: TCP + port: 3030 + targetPort: 3030 + +--- + +apiVersion: v1 +kind: Service +metadata: + name: gateway-service +spec: + selector: + app: gateway + ports: + - protocol: TCP + port: 4000 + targetPort: 4000 + - protocol: TCP + port: 4030 + targetPort: 4030 + +# Repeat the above structure for other services diff --git a/install/scripts/package_manager.sh b/install/scripts/package_manager.sh new file mode 100755 index 0000000..df49060 --- /dev/null +++ b/install/scripts/package_manager.sh @@ -0,0 +1,152 @@ +#!/bin/bash +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source $SCRIPT_DIR/variables.sh + +#Required packages list as below. +package_list=("docker" "docker-compose" "jq") + +command_exists() { + command -v "$1" &>/dev/null +} + +# Redirect input from /dev/null to silence prompts +export DEBIAN_FRONTEND=noninteractive +export APT_KEY_DONT_WARN_ON_DANGEROUS_USAGE=1 + + +#Install Package +install_package() { + if [ -x "$(command -v apt-get)" ]; then + # APT (Debian/Ubuntu) + if [ "$1" == "docker" ]; then + docker > /dev/null 2>&1 + if [ $? -ne 0 ]; then + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + sudo apt update >/dev/null 2>&1 + sudo apt install -y docker-ce docker-ce-cli containerd.io >/dev/null 2>&1 + sudo usermod -aG docker $USER + source ~/.bashrc + command_exists docker + if [ $? -eq 0 ]; then + sleep 10 + sudo systemctl enable docker.service + sudo systemctl restart docker.service + fi + else + echo "Docker is already installed." + fi + else + if ! dpkg -l | grep -q "^ii $1 "; then + sudo apt-get update >/dev/null 2>&1 + sudo apt-get install -y $1 > /dev/null 2>&1 + else + echo "$1 is already installed." + fi + fi + elif [ -x "$(command -v yum)" ]; then + # YUM (Red Hat/CentOS) + if [ "$1" == "docker" ]; then + if ! rpm -qa | grep -q docker-ce; then + sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo + # Install Docker + sudo yum install -y docker >/dev/null 2>&1 + sudo systemctl enable docker.service + sudo systemctl start docker.service + sudo usermod -aG docker $USER + source ~/.bashrc + else + echo "Docker is already installed." + fi + else + if ! rpm -qa | grep -q "^$1-"; then + sudo yum install -y $1 >/dev/null 2>&1 + else + echo "$1 is already installed." + fi + fi + elif [ -x "$(command -v amazon-linux-extras)" ]; then + # Amazon Linux 2 + if ! amazon-linux-extras list | grep -q "^$1 "; then + sudo amazon-linux-extras install $1 >/dev/null 2>&1 + else + echo "$1 is already installed." + fi + else + echo "${RED}Unsupported package manager. Please install $1 manually.${NC}" + exit 1 + fi +} + + +remove_package(){ + if [ -x "$(command -v apt-get)" ]; then + # APT (Debian/Ubuntu) + sudo apt-get purge -y $1 >/dev/null 2>&1 + sudo apt autoremove -y >/dev/null 2>&1 + elif [ -x "$(command -v yum)" ]; then + # YUM (Red Hat/CentOS) + sudo yum remove -y $1 >/dev/null 2>&1 + sudo yum autoremove -y >/dev/null 2>&1 + fi +} + +# Function to install Docker +install_docker_bash() { + # Install Docker Bash completion + echo "Installing Docker Bash completion..." + sudo curl -L https://raw.githubusercontent.com/docker/cli/master/contrib/completion/bash/docker -o /etc/bash_completion.d/docker +} + +# Function to install Docker Compose +install_docker_compose() { + command_exists docker-compose + if [ $? -eq 0 ]; then + echo "docker-compose is already installed." + return + else + echo "Installing Docker Compose..." + sudo curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose + sudo chmod +x /usr/local/bin/docker-compose + fi + + # Check if Docker Compose installation was successful + if [ $? -eq 0 ]; then + echo "Docker Compose installed successfully." + else + echo "${RED}Failed to install Docker Compose. Exiting.${NC}" + exit 1 + fi + + if [ -f /etc/bash_completion.d/docker-compose ]; then + echo "Docker Compose Bash completion is already installed." + else + # Install Docker Compose Bash completion + echo "Installing Docker Compose Bash completion..." + sudo curl -L https://raw.githubusercontent.com/docker/compose/master/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose + fi +} + + +# Check if package is already installed + +for package in "${package_list[@]}"; do + if ! command_exists $package; then + install_package "$package" + fi + if [ "$package" == "docker" ]; then + if [[ $(uname -s ) == 'Linux' ]];then + if [ -f /etc/bash_completion.d/docker ]; then + echo "Docker Bash completion is already installed." + else + install_docker_bash + fi + fi + fi + if [ "$package" == "docker-compose" ]; then + if [[ $(uname -s ) == 'Linux' ]];then + install_docker_compose + fi + fi +done + diff --git a/install/scripts/register_gateway.sh b/install/scripts/register_gateway.sh new file mode 100755 index 0000000..3d19407 --- /dev/null +++ b/install/scripts/register_gateway.sh @@ -0,0 +1,32 @@ +#!/bin/bash +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source $SCRIPT_DIR/get_container_details.sh + +register_gw() { +cookie_file="cookies.txt" +# Step 1: Perform login and save the session cookies to a file +curl --cookie-jar $cookie_file --request POST $login_url + +curl --request GET --cookie $cookie_file $subscribe_url +rm -rf $cookie_file +} + +if [[ $(uname -s) == 'Darwin' ]]; then + ip=localhost +elif [[ $(systemd-detect-virt) == 'wsl' ]]; then + ip=$(hostname -I | awk '{print $1}') +else + ip=$(get_container_ip gateway) +fi + +if [[ $1 ]]; then + if [[ $1 == https://* ]]; then + login_url="$1/login?name=root&password=root&_LOGIN=Login" + subscribe_url="$1/bg/subscribe" + register_gw + fi +else + login_url="http://$ip:4030/login?name=root&password=root&_LOGIN=Login" + subscribe_url="http://$ip:4030/bg/subscribe" + register_gw +fi diff --git a/install/scripts/registry_entry.sh b/install/scripts/registry_entry.sh new file mode 100755 index 0000000..59bac0d --- /dev/null +++ b/install/scripts/registry_entry.sh @@ -0,0 +1,44 @@ +#!/bin/bash +source $SCRIPT_DIR/variables.sh + +create_network_participant() { + # Set your variables + registry_url="$1" + content_type="$2" + subscriber_id="$3" + pub_key_id="$4" + subscriber_url="$5" + encr_public_key="$6" + signing_public_key="$7" + valid_from="$8" + valid_until="$9" + type="${10}" + + json_data=$(cat <&1) + + if [ $? -eq 0 ]; then + + echo "${GREEN}Network Participant Entry is created. Please login to registry $registry_url and subscribe you Network Participant.${NC}" + else + echo "${RED}Error: $response${NC}" + fi +} diff --git a/install/scripts/update_bap_config.sh b/install/scripts/update_bap_config.sh new file mode 100755 index 0000000..261fb45 --- /dev/null +++ b/install/scripts/update_bap_config.sh @@ -0,0 +1,124 @@ +#!/bin/bash +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source $SCRIPT_DIR/registry_entry.sh +source $SCRIPT_DIR/generate_keys.sh +source $SCRIPT_DIR/variables.sh +source $SCRIPT_DIR/get_container_details.sh + + +newClientFile=$(echo "$bapClientFile" | sed 's/yaml-sample/yml/') +newNetworkFile=$(echo "$bapNetworkFile" | sed 's/yaml-sample/yml/') + +cp $bapClientFile $newClientFile +cp $bapNetworkFile $newNetworkFile + +clientFile=$newClientFile +networkFile=$newNetworkFile + +client_port=$bap_client_port +network_port=$bap_network_port + +if [[ $(uname) == "Darwin" ]]; then + sed -i '' "s|BAP_NETWORK_PORT|$network_port|" $networkFile + sed -i '' "s|BAP_CLIENT_PORT|$client_port|" $clientFile +else + sed -i "s|BAP_NETWORK_PORT|$network_port|" $networkFile + sed -i "s|BAP_CLIENT_PORT|$client_port|" $clientFile +fi + +if [[ $1 ]]; then + registry_url=$1 + bap_subscriber_id=$2 + bap_subscriber_id_key=$3 + bap_subscriber_url=$4 +else + if [[ $(uname -s) == 'Darwin' ]]; then + ip=localhost + registry_url="http://$ip:3030/subscribers" + elif [[ $(systemd-detect-virt) == 'wsl' ]]; then + ip=$(hostname -I | awk '{print $1}') + registry_url="http://$ip:3030/subscribers" + else + registry_url="http://$(get_container_ip registry):3030/subscribers" + fi +fi + +echo "Generating public/private key pair" +get_keys +echo "Your Private Key: $private_key" +echo "Your Public Key: $public_key" + + +valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ") + +if [[ $(uname -s ) == 'Darwin' ]];then + valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%000Z") + valid_until=$(date -u -v+1y +"%Y-%m-%dT%H:%M:%S.%000Z") +else + valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ") + valid_until=$(date -u -d "+1 year" +"%Y-%m-%dT%H:%M:%S.%3NZ") +fi + +type=BAP + + +# Define an associative array for replacements +if [[ $(uname -s ) == 'Darwin' ]];then + replacements=( + "REDIS_URL=$redisUrl" + "REGISTRY_URL=$registry_url" + "MONGO_USERNAME=$mongo_initdb_root_username" + "MONGO_PASSWORD=$mongo_initdb_root_password" + "MONGO_DB_NAME=$mongo_initdb_database" + "MONOG_URL=$mongoUrl" + "RABBITMQ_USERNAME=$rabbitmq_default_user" + "RABBITMQ_PASSWORD=$rabbitmq_default_pass" + "RABBITMQ_URL=$rabbitmqUrl" + "PRIVATE_KEY=$private_key" + "PUBLIC_KEY=$public_key" + "BAP_SUBSCRIBER_ID=$bap_subscriber_id" + "BAP_SUBSCRIBER_URL=$bap_subscriber_url" + "BAP_SUBSCRIBER_ID_KEY=$bap_subscriber_id_key" + ) + + echo "Configuring BAP protocol server" + # Apply replacements in both files + for file in "$clientFile" "$networkFile"; do + for line in "${replacements[@]}"; do + key=$(echo "$line" | cut -d '=' -f1) + value=$(echo "$line" | cut -d '=' -f2) + sed -i '' "s|$key|$value|" "$file" + done + + done +else + declare -A replacements=( + ["REDIS_URL"]=$redisUrl + ["REGISTRY_URL"]=$registry_url + ["MONGO_USERNAME"]=$mongo_initdb_root_username + ["MONGO_PASSWORD"]=$mongo_initdb_root_password + ["MONGO_DB_NAME"]=$mongo_initdb_database + ["MONOG_URL"]=$mongoUrl + ["RABBITMQ_USERNAME"]=$rabbitmq_default_user + ["RABBITMQ_PASSWORD"]=$rabbitmq_default_pass + ["RABBITMQ_URL"]=$rabbitmqUrl + ["PRIVATE_KEY"]=$private_key + ["PUBLIC_KEY"]=$public_key + ["BAP_SUBSCRIBER_ID"]=$bap_subscriber_id + ["BAP_SUBSCRIBER_URL"]=$bap_subscriber_url + ["BAP_SUBSCRIBER_ID_KEY"]=$bap_subscriber_id_key + ) + + echo "Configuring BAP protocol server" + # Apply replacements in both files + for file in "$clientFile" "$networkFile"; do + for key in "${!replacements[@]}"; do + sed -i "s|$key|${replacements[$key]}|" "$file" + done + done +fi + +echo "Registering BAP protocol server on the registry" + +create_network_participant "$registry_url" "application/json" "$bap_subscriber_id" "$bap_subscriber_id_key" "$bap_subscriber_url" "$public_key" "$public_key" "$valid_from" "$valid_until" "$type" \ No newline at end of file diff --git a/install/scripts/update_bpp_config.sh b/install/scripts/update_bpp_config.sh new file mode 100755 index 0000000..b04a0ff --- /dev/null +++ b/install/scripts/update_bpp_config.sh @@ -0,0 +1,124 @@ +#!/bin/bash +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +source $SCRIPT_DIR/registry_entry.sh +source $SCRIPT_DIR/generate_keys.sh +source $SCRIPT_DIR/variables.sh +source $SCRIPT_DIR/get_container_details.sh + + +newClientFile=$(echo "$bppClientFile" | sed 's/yaml-sample/yml/') +newNetworkFile=$(echo "$bppNetworkFile" | sed 's/yaml-sample/yml/') + +cp $bppClientFile $newClientFile +cp $bppNetworkFile $newNetworkFile + +clientFile=$newClientFile +networkFile=$newNetworkFile + +client_port=$bpp_client_port +network_port=$bpp_network_port + +if [[ $(uname) == "Darwin" ]]; then + sed -i '' "s|BPP_NETWORK_PORT|$network_port|" $networkFile + sed -i '' "s|BPP_CLIENT_PORT|$client_port|" $clientFile +else + sed -i "s|BPP_NETWORK_PORT|$network_port|" $networkFile + sed -i "s|BPP_CLIENT_PORT|$client_port|" $clientFile +fi + +if [[ $1 ]]; then + registry_url=$1 + bpp_subscriber_id=$2 + bpp_subscriber_id_key=$3 + bpp_subscriber_url=$4 +else + if [[ $(uname -s) == 'Darwin' ]]; then + ip=localhost + registry_url="http://$ip:3030/subscribers" + elif [[ $(systemd-detect-virt) == 'wsl' ]]; then + ip=$(hostname -I | awk '{print $1}') + registry_url="http://$ip:3030/subscribers" + else + registry_url="http://$(get_container_ip registry):3030/subscribers" + fi +fi + +echo "Generating public/private key pair" +get_keys +#echo "Your Private Key: $private_key" +#echo "Your Public Key: $public_key" + + +if [[ $(uname -s ) == 'Darwin' ]];then + valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%000Z") + valid_until=$(date -u -v+1y +"%Y-%m-%dT%H:%M:%S.%000Z") +else + valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ") + valid_until=$(date -u -d "+1 year" +"%Y-%m-%dT%H:%M:%S.%3NZ") +fi +type=BPP + + +# Define an associative array for replacements +if [[ $(uname -s ) == 'Darwin' ]];then + replacements=( + "REDIS_URL=$redisUrl" + "REGISTRY_URL=$registry_url" + "MONGO_USERNAME=$mongo_initdb_root_username" + "MONGO_PASSWORD=$mongo_initdb_root_password" + "MONGO_DB_NAME=$mongo_initdb_database" + "MONOG_URL=$mongoUrl" + "RABBITMQ_USERNAME=$rabbitmq_default_user" + "RABBITMQ_PASSWORD=$rabbitmq_default_pass" + "RABBITMQ_URL=$rabbitmqUrl" + "PRIVATE_KEY=$private_key" + "PUBLIC_KEY=$public_key" + "BPP_SUBSCRIBER_URL=$bpp_subscriber_url" + "BPP_SUBSCRIBER_ID=$bpp_subscriber_id" + "BPP_SUBSCRIBER_ID_KEY=$bpp_subscriber_id_key" + "WEBHOOK_URL=$webhook_url" + ) + + echo "Configuring BPP protocol server" + # Apply replacements in both files + for file in "$clientFile" "$networkFile"; do + for line in "${replacements[@]}"; do + key=$(echo "$line" | cut -d '=' -f1) + value=$(echo "$line" | cut -d '=' -f2) + sed -i '' "s|$key|$value|" "$file" + done + + done + +else + declare -A replacements=( + ["REDIS_URL"]=$redisUrl + ["REGISTRY_URL"]=$registry_url + ["MONGO_USERNAME"]=$mongo_initdb_root_username + ["MONGO_PASSWORD"]=$mongo_initdb_root_password + ["MONGO_DB_NAME"]=$mongo_initdb_database + ["MONOG_URL"]=$mongoUrl + ["RABBITMQ_USERNAME"]=$rabbitmq_default_user + ["RABBITMQ_PASSWORD"]=$rabbitmq_default_pass + ["RABBITMQ_URL"]=$rabbitmqUrl + ["PRIVATE_KEY"]=$private_key + ["PUBLIC_KEY"]=$public_key + ["BPP_SUBSCRIBER_URL"]=$bpp_subscriber_url + ["BPP_SUBSCRIBER_ID"]=$bpp_subscriber_id + ["BPP_SUBSCRIBER_ID_KEY"]=$bpp_subscriber_id_key + ["WEBHOOK_URL"]=$webhook_url + ) + + echo "Configuring BAP protocol server" + # Apply replacements in both files + for file in "$clientFile" "$networkFile"; do + for key in "${!replacements[@]}"; do + sed -i "s|$key|${replacements[$key]}|" "$file" + done + done +fi + +echo "Registering BPP protocol server on the registry" + +create_network_participant "$registry_url" "application/json" "$bpp_subscriber_id" "$bpp_subscriber_id_key" "$bpp_subscriber_url" "$public_key" "$public_key" "$valid_from" "$valid_until" "$type" \ No newline at end of file diff --git a/install/scripts/update_gateway_details.sh b/install/scripts/update_gateway_details.sh new file mode 100755 index 0000000..49ba577 --- /dev/null +++ b/install/scripts/update_gateway_details.sh @@ -0,0 +1,82 @@ +#!/bin/bash +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +source $SCRIPT_DIR/get_container_details.sh + +gateway_url=gateway +gateway_port=4030 +protocol=http +reg_url=http://$1:3030/subscribers/lookup + +get_details_registry() { + # Make the curl request and store the output in a variable + response=$(curl --location --request POST "$reg_url" \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "type": "LREG" +}') + # Check if the curl command was successful (HTTP status code 2xx) + if [ $? -eq 0 ]; then + # Extract signing_public_key and encr_public_key using jq + signing_public_key=$(echo "$response" | jq -r '.[0].signing_public_key') + encr_public_key=$(echo "$response" | jq -r '.[0].encr_public_key') + subscriber_url=$(echo "$response" | jq -r '.[0].subscriber_url') + + else + echo "Error: Unable to fetch data from the server." + fi +} + +update_gateway_config() { + # Print the extracted keys + echo "Signing Public Key: $signing_public_key" + echo "Encryption Public Key: $encr_public_key" + echo "URL $subscriber_url" + + cp $SCRIPT_DIR/../gateway_data/config/swf.properties-sample $SCRIPT_DIR/../gateway_data/config/swf.properties + config_file="$SCRIPT_DIR/../gateway_data/config/swf.properties" + + tmp_file=$(mktemp "tempfile.XXXXXXXXXX") + sed " s|SUBSCRIBER_ID|$gateway_url|g; s|SIGNING_PUBLIC_KEY|$signing_public_key|g; s|ENCRYPTION_PUBLIC_KEY|$encr_public_key|g; s|GATEWAY_URL|$gateway_url|g; s|GATEWAY_PORT|$gateway_port|g; s|PROTOCOL|$protocol|g; s|REGISTRY_URL|$subscriber_url|g" "$config_file" > "$tmp_file" + mv "$tmp_file" "$config_file" +} + +if [[ $1 == https://* ]]; then + reg_url=$1/subscribers/lookup + get_details_registry $reg_url +else + service_name=$1 + if [[ $(uname -s) == 'Darwin' ]]; then + ip=localhost + elif [[ $(systemd-detect-virt) == 'wsl' ]]; then + ip=$(hostname -I | awk '{print $1}') + else + ip=$(get_container_ip $service_name) + fi + reg_url=http://$ip:3030/subscribers/lookup + get_details_registry $reg_url +fi + + +if [[ $2 ]]; then + if [[ $2 == https://* ]]; then + if [[ $(uname -s) == 'Darwin' ]]; then + gateway_url=$(echo "$2" | sed -E 's/https:\/\///') + else + gateway_url=$(echo "$2" | sed 's/https:\/\///') + fi + gateway_port=443 + protocol=https + update_gateway_config + elif [[ $2 == http://* ]]; then + if [[ $(uname -s) == 'Darwin' ]]; then + gateway_url=$(echo "$2" | sed -E 's/http:\/\///') + else + gateway_url=$(echo "$2" | sed 's/http:\/\///') + fi + gateway_port=80 + protocol=http + update_gateway_config + fi +else + update_gateway_config +fi \ No newline at end of file diff --git a/install/scripts/variables.sh b/install/scripts/variables.sh new file mode 100755 index 0000000..d5d2f8c --- /dev/null +++ b/install/scripts/variables.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +#Colour Code +RED=$(tput setaf 1) +GREEN=$(tput setaf 2) +YELLOW=$(tput setaf 3) +NC=$(tput sgr0) + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +#Comman Variables with Default values +mongo_initdb_root_username="beckn" +mongo_initdb_root_password="beckn123" +mongo_initdb_database="protocol_server" +mongoUrl="mongoDB:27017" + +rabbitmq_default_user="beckn" +rabbitmq_default_pass="beckn123" +rabbitmqUrl="rabbitmq" + +redisUrl="redis" + +registry_url="http://registry:3030/subscribers" +beckn_registry_url="https://registry.becknprotocol.io/subscribers" + +#public_key="KKHOpMKQCbJHzjme+CPKI3HQxIhzKMpcLLRGMhzf7rk=" +#private_key="W7HkCMPWvxv6/jWqHlyUI4vWX8704+rN3kCwBGIA7rcooc6kwpAJskfOOZ74I8ojcdDEiHMoylwstEYyHN/uuQ==" + +#BAP varibales. + +bapClientFile="$SCRIPT_DIR/../protocol-server-data/bap-client.yaml-sample" +bapNetworkFile="$SCRIPT_DIR/../protocol-server-data/bap-network.yaml-sample" + +bap_client_port=5001 +bap_network_port=5002 + +bap_subscriber_id="bap-network" +bap_subscriber_id_key="bap-network-key" +bap_subscriber_url="http://bap-network:5002" +bap_client_url="http://bap-client:5002" + +#BPP varibales. + +bppClientFile="$SCRIPT_DIR/../protocol-server-data/bpp-client.yaml-sample" +bppNetworkFile="$SCRIPT_DIR/../protocol-server-data/bpp-network.yaml-sample" + +bpp_client_port=6001 +bpp_network_port=6002 + +bpp_subscriber_id="bpp-network" +bpp_subscriber_id_key="bpp-network-key" +bpp_subscriber_url="http://bpp-network:6002" +webhook_url="http://sandbox-webhook:3005" diff --git a/install/start_beckn.sh b/install/start_beckn.sh new file mode 100755 index 0000000..57c74b4 --- /dev/null +++ b/install/start_beckn.sh @@ -0,0 +1,117 @@ +#!/bin/bash +source ./scripts/variables.sh +source ./scripts/get_container_details.sh + +#below function will start specifice service inside docker-compose file +start_container(){ + echo "$1" + docker-compose up -d $1 + +} + +#below function will start the MongoDB, Redis and RabbitMQ Services. +start_support_services(){ + echo "${GREEN}................Installing MongoDB................${NC}" + docker-compose -f docker-compose-app.yml up -d mongo_db + echo "MongoDB installation successful" + + echo "${GREEN}................Installing RabbitMQ................${NC}" + docker-compose -f docker-compose-app.yml up -d queue_service + echo "RabbitMQ installation successful" + + echo "${GREEN}................Installing Redis................${NC}" + docker-compose -f docker-compose-app.yml up -d redis_db + echo "Redis installation successful" +} +# Main script starts here +text=" +Welcome to ONIX! +The following components will be installed + +1. MongoDB, RabbitMQ and Redis +2. Registry +3. Gateway +4. Sandbox +5. Sandbox Webhook +6. Protocol Server for BAP +7. Protocol Server for BPP +" +echo "$text" +sleep 5 +echo "${GREEN}................Installing required packages................${NC}" +./scripts/package_manager.sh +echo "Package Installation is done" + +export COMPOSE_IGNORE_ORPHANS=1 + +echo "${GREEN}................Installing Registry service................${NC}" +start_container registry +sleep 10 +echo "Registry installation successful" +sleep 5 +./scripts/update_gateway_details.sh registry +echo "${GREEN}................Installing Gateway service................${NC}" +start_container gateway +echo "Registering Gateway in the registry" +sleep 5 +./scripts/register_gateway.sh +echo " " +echo "Gateway installation successful" + +#Start the MongoDB, Redis and RabbitMQ Services. +start_support_services +sleep 10 + +echo "${GREEN}................Installing Protocol Server for BAP................${NC}" +./scripts/update_bap_config.sh +sleep 10 +start_container "bap-client" +start_container "bap-network" +sleep 10 +echo "Protocol server BAP installation successful" + +echo "${GREEN}................Installing Sandbox................${NC}" +start_container "sandbox-api" +sleep 5 +echo "Sandbox installation successful" + +echo "${GREEN}................Installing Webhook................${NC}" +start_container "sandbox-webhook" +sleep +echo "Webhook installation successful" + +echo "${GREEN}................Installing Protocol Server for BPP................${NC}" +bash scripts/update_bpp_config.sh +sleep 10 +start_container "bpp-client" +start_container "bpp-network" +sleep 10 +echo "Protocol server BPP installation successful" + +if [[ $(uname -s) == 'Darwin' ]]; then + ip=localhost + bap_network_ip=$ip + bap_client_ip=$ip + bpp_network_ip=$ip + bap_network_ip=$ip +elif [[ $(systemd-detect-virt) == 'wsl' ]]; then + ip=$(hostname -I | awk '{print $1}') + bap_network_ip=$ip + bap_client_ip=$ip + bpp_network_ip=$ip + bap_network_ip=$ip +else + bap_network_ip=$(get_container_ip bap-network) + bap_client_ip=$(get_container_ip bap-client) + bpp_network_ip=$(get_container_ip bpp-network) + bap_network_ip=$(get_container_ip bpp-client) +fi + +echo " " +echo "##########################################################" +echo "${GREEN}Please find below details of protocol server which required in postman collection${NC}" +echo "BASE_URL=http://$bap_client_ip:$bap_client_port/" +echo "BAP_ID=$bap_subscriber_id" +echo "BAP_URI=http://$bap_network_ip:$bap_network_port/" +echo "BPP_ID=$bpp_subscriber_id" +echo "BPP_URI=http://$bpp_network_ip:$bpp_network_port/" \ No newline at end of file diff --git a/install/start_beckn_v2.sh b/install/start_beckn_v2.sh new file mode 100755 index 0000000..3436d4a --- /dev/null +++ b/install/start_beckn_v2.sh @@ -0,0 +1,296 @@ +#!/bin/bash +source scripts/variables.sh +source scripts/get_container_details.sh + +# Function to start a specific service inside docker-compose file +install_package(){ + echo "${GREEN}................Installing required packages................${NC}" + bash scripts/package_manager.sh + echo "Package Installation is done" + +} +start_container(){ + #ignore orphaned containers warning + export COMPOSE_IGNORE_ORPHANS=1 + docker-compose -f docker-compose-v2.yml up -d $1 +} + +update_registry_details() { + if [[ $1 ]];then + if [[ $1 == https://* ]]; then + if [[ $(uname -s) == 'Darwin' ]]; then + registry_url=$(echo "$1" | sed -E 's/https:\/\///') + else + registry_url=$(echo "$1" | sed 's/https:\/\///') + fi + registry_port=443 + protocol=https + elif [[ $1 == http://* ]]; then + if [[ $(uname -s) == 'Darwin' ]]; then + registry_url=$(echo "$1" | sed -E 's/http:\/\///') + else + registry_url=$(echo "$1" | sed 's/http:\/\///') + fi + registry_port=80 + protocol=http + fi + + else + registry_url=registry + registry_port=3030 + protocol=http + fi + echo $registry_url + cp $SCRIPT_DIR/../registry_data/config/swf.properties-sample $SCRIPT_DIR/../registry_data/config/swf.properties + config_file="$SCRIPT_DIR/../registry_data/config/swf.properties" + + tmp_file=$(mktemp "tempfile.XXXXXXXXXX") + sed "s|REGISTRY_URL|$registry_url|g; s|REGISTRY_PORT|$registry_port|g; s|PROTOCOL|$protocol|g" "$config_file" > "$tmp_file" + mv "$tmp_file" "$config_file" + +} +# Function to start the MongoDB, Redis, and RabbitMQ Services +start_support_services(){ + #ignore orphaned containers warning + export COMPOSE_IGNORE_ORPHANS=1 + echo "${GREEN}................Installing MongoDB................${NC}" + docker-compose -f docker-compose-app.yml up -d mongo_db + echo "MongoDB installation successful" + + echo "${GREEN}................Installing RabbitMQ................${NC}" + docker-compose -f docker-compose-app.yml up -d queue_service + echo "RabbitMQ installation successful" + + echo "${GREEN}................Installing Redis................${NC}" + docker-compose -f docker-compose-app.yml up -d redis_db + echo "Redis installation successful" +} + +install_gateway() { + if [[ $1 && $2 ]]; then + bash scripts/update_gateway_details.sh $1 $2 + else + bash scripts/update_gateway_details.sh registry + fi + echo "${GREEN}................Installing Gateway service................${NC}" + start_container gateway + echo "Registering Gateway in the registry" + + sleep 10 + if [[ $1 && $2 ]]; then + bash scripts/register_gateway.sh $2 + else + bash scripts/register_gateway.sh + fi + echo " " + echo "Gateway installation successful" +} + +# Function to install Beckn Gateway and Beckn Registry +install_registry(){ + if [[ $1 ]]; then + update_registry_details $1 + else + update_registry_details + fi + + echo "${GREEN}................Installing Registry service................${NC}" + start_container registry + sleep 10 + echo "Registry installation successful" +} + +# Function to install BAP Protocol Server +install_bap_protocol_server(){ + start_support_services + if [[ $1 ]];then + registry_url=$1 + bap_subscriber_id=$2 + bap_subscriber_id_key=$3 + bap_subscriber_url=$4 + bash scripts/update_bap_config.sh $registry_url $bap_subscriber_id $bap_subscriber_id_key $bap_subscriber_url + else + bash scripts/update_bap_config.sh + fi + sleep 10 + start_container "bap-client" + start_container "bap-network" + sleep 10 + echo "Protocol server BAP installation successful" +} + +# Function to install BPP Protocol Server with BPP Sandbox +install_bpp_protocol_server_with_sandbox(){ + start_support_services + echo "${GREEN}................Installing Sandbox................${NC}" + start_container "sandbox-api" + sleep 5 + echo "Sandbox installation successful" + + echo "${GREEN}................Installing Webhook................${NC}" + start_container "sandbox-webhook" + sleep + echo "Webhook installation successful" + + echo "${GREEN}................Installing Protocol Server for BPP................${NC}" + + if [[ $1 ]];then + registry_url=$1 + bpp_subscriber_id=$2 + bpp_subscriber_id_key=$3 + bpp_subscriber_url=$4 + bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url + else + bash scripts/update_bpp_config.sh + fi + + sleep 10 + start_container "bpp-client" + start_container "bpp-network" + sleep 10 + echo "Protocol server BPP installation successful" +} + +# Function to install BPP Protocol Server without Sandbox +install_bpp_protocol_server(){ + start_support_services + echo "${GREEN}................Installing Protocol Server for BPP................${NC}" + + if [[ $1 ]];then + registry_url=$1 + bpp_subscriber_id=$2 + bpp_subscriber_id_key=$3 + bpp_subscriber_url=$4 + webhook_url=$5 + bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url $$webhook_url + else + bash scripts/update_bpp_config.sh + fi + + sleep 10 + start_container "bpp-client" + start_container "bpp-network" + sleep 10 + echo "Protocol server BPP installation successful" +} + +text=" +The following components will be installed + +1. Registry +2. Gateway +3. Sandbox +4. Sandbox Webhook +5. Protocol Server for BAP +6. Protocol Server for BPP +" + +# Main script starts here +bash scripts/banner.sh +echo "Welcome to ONIX" +echo "$text" + +read -p "${GREEN}Do you want to install all the components on the local system? (Y/n): ${NC}" install_all + +if [[ $install_all =~ ^[Yy]$ ]]; then + # Install and bring up everything + install_package + install_registry + install_gateway + start_support_services + install_bap_protocol_server + install_bpp_protocol_server_with_sandbox +else + # User selects specific components to install + echo "Please select the components that you want to install" + echo "1. Beckn Gateway & Beckn Registry" + echo "2. BAP Protocol Server" + echo "3. BPP Protocol Server with BPP Sandbox" + echo "4. BPP Protocol Server" + echo "5. Generic Client Layer" + echo "6. Exit" + + read -p "Enter your choice (1-6): " user_choice + + case $user_choice in + 1) + echo "${GREEN}Default Registry URL: $registry_url" + echo "Default Gateway URL will be docker URL" + read -p "Do you want to change Registry and Gateway URL? (Y/N): ${NC}" change_url + if [[ $change_url =~ ^[Yy]$ ]]; then + read -p "Enter publicly accessible registry URL: " registry_url + read -p "Enter publicly accessible gateway URL: " gateway_url + + if [[ $registry_url =~ /$ ]]; then + new_registry_url=${registry_url%/} + else + new_registry_url=$registry_url + fi + if [[ $gateway_url =~ /$ ]]; then + gateway_url=${gateway_url%/} + fi + + install_package + install_registry $new_registry_url + install_gateway $new_registry_url $gateway_url + + else + install_package + install_registry + install_gateway + fi + ;; + 2) + echo "${GREEN}................Installing Protocol Server for BAP................${NC}" + + read -p "Enter BAP Subscriber ID: " bap_subscriber_id + read -p "Enter BAP Subscriber URL: " bap_subscriber_url + # Ask the user if they want to change the registry_url + read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url + registry_url=${custom_registry_url:-$beckn_registry_url} + bap_subscriber_id_key=$bap_subscriber_id-key + install_package + install_bap_protocol_server $registry_url $bap_subscriber_id $bap_subscriber_id_key $bap_subscriber_url + ;; + 3) + read -p "Enter BPP Subscriber ID: " bpp_subscriber_id + read -p "Enter BPP Subscriber URL: " bpp_subscriber_url + # Ask the user if they want to change the registry_url + read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url + registry_url=${custom_registry_url:-$beckn_registry_url} + bpp_subscriber_id_key=$bpp_subscriber_id-key + install_package + install_bpp_protocol_server_with_sandbox $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url + ;; + 4) + read -p "Enter BPP Subscriber ID: " bpp_subscriber_id + read -p "Enter BPP Subscriber URL: " bpp_subscriber_url + read -p "Enter Webhook URL: " webhook_url + + # Ask the user if they want to change the registry_url + read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url + registry_url=${custom_registry_url:-$beckn_registry_url} + bpp_subscriber_id_key=$bpp_subscriber_id-key + install_package + install_bpp_protocol_server $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url $webhook_url + ;; + + 5) + echo "${GREEN}................Installing GENERIC CLIENT LAYER................${NC}" + read -p "Enter BAP Subscriber ID: " bap_subscriber_id + read -p "Enter BAP Subscriber URL: " bap_subscriber_url + read -p "Enter BAP Client URL: " bap_client_url + bash scripts/generic-client-layer.sh $bap_subscriber_id $bap_subscriber_url $bap_client_url + start_container "generic-client-layer" + ;; + + 6) + echo "Exiting ONIX" + exit 0 + ;; + *) + echo "Invalid choice. Exiting ONIX." + exit 1 + ;; + esac +fi From f02fb5dc28621f94a674f1f759146678b1e1ea81 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Tue, 19 Mar 2024 12:02:53 +0530 Subject: [PATCH 002/102] Fixed typo in start_beckn_v2.sh --- install/start_beckn_v2.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/start_beckn_v2.sh b/install/start_beckn_v2.sh index 3436d4a..4e480b0 100755 --- a/install/start_beckn_v2.sh +++ b/install/start_beckn_v2.sh @@ -162,7 +162,7 @@ install_bpp_protocol_server(){ bpp_subscriber_id_key=$3 bpp_subscriber_url=$4 webhook_url=$5 - bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url $$webhook_url + bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url $webhook_url else bash scripts/update_bpp_config.sh fi From fbddde2b310e9214e942f30b6326994e1747f096 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Tue, 19 Mar 2024 15:46:53 +0530 Subject: [PATCH 003/102] Fixed issue for Webhook URL --- install/scripts/update_bpp_config.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install/scripts/update_bpp_config.sh b/install/scripts/update_bpp_config.sh index b04a0ff..07b2f75 100755 --- a/install/scripts/update_bpp_config.sh +++ b/install/scripts/update_bpp_config.sh @@ -32,6 +32,7 @@ if [[ $1 ]]; then bpp_subscriber_id=$2 bpp_subscriber_id_key=$3 bpp_subscriber_url=$4 + webhook_url=$5 else if [[ $(uname -s) == 'Darwin' ]]; then ip=localhost From 761b68864d882a5e9de9bef3ea6f8d3a471cd737 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 20 Mar 2024 01:53:09 +0530 Subject: [PATCH 004/102] Fixed the subscriber key issue --- .../bap-client.yaml-sample | 2 +- .../bap-network.yaml-sample | 2 +- .../bpp-client.yaml-sample | 2 +- .../bpp-network.yaml-sample | 2 +- install/scripts/update_bap_config.sh | 8 +++---- install/scripts/update_bpp_config.sh | 8 +++---- install/scripts/variables.sh | 4 ++-- install/start_beckn_v2.sh | 24 +++++++++---------- 8 files changed, 26 insertions(+), 26 deletions(-) diff --git a/install/protocol-server-data/bap-client.yaml-sample b/install/protocol-server-data/bap-client.yaml-sample index 610c5c8..96b1e35 100644 --- a/install/protocol-server-data/bap-client.yaml-sample +++ b/install/protocol-server-data/bap-client.yaml-sample @@ -112,7 +112,7 @@ app: # Mandatory. registryUrl: REGISTRY_URL auth: false - uniqueKey: "BAP_SUBSCRIBER_ID_KEY" + uniqueKey: "BAP_SUBSCRIBER_KEY_ID" # Mandatory. city: "std:080" diff --git a/install/protocol-server-data/bap-network.yaml-sample b/install/protocol-server-data/bap-network.yaml-sample index ec34c41..1af96fd 100644 --- a/install/protocol-server-data/bap-network.yaml-sample +++ b/install/protocol-server-data/bap-network.yaml-sample @@ -112,7 +112,7 @@ app: # Mandatory. registryUrl: REGISTRY_URL auth: false - uniqueKey: "BAP_SUBSCRIBER_ID_KEY" + uniqueKey: "BAP_SUBSCRIBER_KEY_ID" # Mandatory. city: "std:080" diff --git a/install/protocol-server-data/bpp-client.yaml-sample b/install/protocol-server-data/bpp-client.yaml-sample index d3dd737..6e2fe75 100644 --- a/install/protocol-server-data/bpp-client.yaml-sample +++ b/install/protocol-server-data/bpp-client.yaml-sample @@ -110,7 +110,7 @@ app: # Mandatory. registryUrl: REGISTRY_URL auth: true - uniqueKey: "BPP_SUBSCRIBER_ID_KEY" + uniqueKey: "BPP_SUBSCRIBER_KEY_ID" # Mandatory. city: "std:080" diff --git a/install/protocol-server-data/bpp-network.yaml-sample b/install/protocol-server-data/bpp-network.yaml-sample index 0987b21..b837568 100644 --- a/install/protocol-server-data/bpp-network.yaml-sample +++ b/install/protocol-server-data/bpp-network.yaml-sample @@ -110,7 +110,7 @@ app: # Mandatory. registryUrl: REGISTRY_URL auth: true - uniqueKey: "BPP_SUBSCRIBER_ID_KEY" + uniqueKey: "BPP_SUBSCRIBER_KEY_ID" # Mandatory. city: "std:080" diff --git a/install/scripts/update_bap_config.sh b/install/scripts/update_bap_config.sh index 261fb45..ec4530e 100755 --- a/install/scripts/update_bap_config.sh +++ b/install/scripts/update_bap_config.sh @@ -30,7 +30,7 @@ fi if [[ $1 ]]; then registry_url=$1 bap_subscriber_id=$2 - bap_subscriber_id_key=$3 + bap_subscriber_key_id=$3 bap_subscriber_url=$4 else if [[ $(uname -s) == 'Darwin' ]]; then @@ -79,7 +79,7 @@ if [[ $(uname -s ) == 'Darwin' ]];then "PUBLIC_KEY=$public_key" "BAP_SUBSCRIBER_ID=$bap_subscriber_id" "BAP_SUBSCRIBER_URL=$bap_subscriber_url" - "BAP_SUBSCRIBER_ID_KEY=$bap_subscriber_id_key" + "BAP_SUBSCRIBER_KEY_ID=$bap_subscriber_key_id" ) echo "Configuring BAP protocol server" @@ -107,7 +107,7 @@ else ["PUBLIC_KEY"]=$public_key ["BAP_SUBSCRIBER_ID"]=$bap_subscriber_id ["BAP_SUBSCRIBER_URL"]=$bap_subscriber_url - ["BAP_SUBSCRIBER_ID_KEY"]=$bap_subscriber_id_key + ["BAP_SUBSCRIBER_KEY_ID"]=$bap_subscriber_key_id ) echo "Configuring BAP protocol server" @@ -121,4 +121,4 @@ fi echo "Registering BAP protocol server on the registry" -create_network_participant "$registry_url" "application/json" "$bap_subscriber_id" "$bap_subscriber_id_key" "$bap_subscriber_url" "$public_key" "$public_key" "$valid_from" "$valid_until" "$type" \ No newline at end of file +create_network_participant "$registry_url" "application/json" "$bap_subscriber_id" "$bap_subscriber_key_id" "$bap_subscriber_url" "$public_key" "$public_key" "$valid_from" "$valid_until" "$type" \ No newline at end of file diff --git a/install/scripts/update_bpp_config.sh b/install/scripts/update_bpp_config.sh index 07b2f75..2166dd4 100755 --- a/install/scripts/update_bpp_config.sh +++ b/install/scripts/update_bpp_config.sh @@ -30,7 +30,7 @@ fi if [[ $1 ]]; then registry_url=$1 bpp_subscriber_id=$2 - bpp_subscriber_id_key=$3 + bpp_subscriber_key_id=$3 bpp_subscriber_url=$4 webhook_url=$5 else @@ -77,7 +77,7 @@ if [[ $(uname -s ) == 'Darwin' ]];then "PUBLIC_KEY=$public_key" "BPP_SUBSCRIBER_URL=$bpp_subscriber_url" "BPP_SUBSCRIBER_ID=$bpp_subscriber_id" - "BPP_SUBSCRIBER_ID_KEY=$bpp_subscriber_id_key" + "BPP_SUBSCRIBER_KEY_ID=$bpp_subscriber_key_id" "WEBHOOK_URL=$webhook_url" ) @@ -107,7 +107,7 @@ else ["PUBLIC_KEY"]=$public_key ["BPP_SUBSCRIBER_URL"]=$bpp_subscriber_url ["BPP_SUBSCRIBER_ID"]=$bpp_subscriber_id - ["BPP_SUBSCRIBER_ID_KEY"]=$bpp_subscriber_id_key + ["BPP_SUBSCRIBER_KEY_ID"]=$bpp_subscriber_key_id ["WEBHOOK_URL"]=$webhook_url ) @@ -122,4 +122,4 @@ fi echo "Registering BPP protocol server on the registry" -create_network_participant "$registry_url" "application/json" "$bpp_subscriber_id" "$bpp_subscriber_id_key" "$bpp_subscriber_url" "$public_key" "$public_key" "$valid_from" "$valid_until" "$type" \ No newline at end of file +create_network_participant "$registry_url" "application/json" "$bpp_subscriber_id" "$bpp_subscriber_key_id" "$bpp_subscriber_url" "$public_key" "$public_key" "$valid_from" "$valid_until" "$type" \ No newline at end of file diff --git a/install/scripts/variables.sh b/install/scripts/variables.sh index d5d2f8c..94e1f64 100755 --- a/install/scripts/variables.sh +++ b/install/scripts/variables.sh @@ -35,7 +35,7 @@ bap_client_port=5001 bap_network_port=5002 bap_subscriber_id="bap-network" -bap_subscriber_id_key="bap-network-key" +bap_subscriber_key_id="bap-network-key" bap_subscriber_url="http://bap-network:5002" bap_client_url="http://bap-client:5002" @@ -48,6 +48,6 @@ bpp_client_port=6001 bpp_network_port=6002 bpp_subscriber_id="bpp-network" -bpp_subscriber_id_key="bpp-network-key" +bpp_subscriber_key_id="bpp-network-key" bpp_subscriber_url="http://bpp-network:6002" webhook_url="http://sandbox-webhook:3005" diff --git a/install/start_beckn_v2.sh b/install/start_beckn_v2.sh index 4e480b0..7864b45 100755 --- a/install/start_beckn_v2.sh +++ b/install/start_beckn_v2.sh @@ -106,9 +106,9 @@ install_bap_protocol_server(){ if [[ $1 ]];then registry_url=$1 bap_subscriber_id=$2 - bap_subscriber_id_key=$3 + bap_subscriber_key_id=$3 bap_subscriber_url=$4 - bash scripts/update_bap_config.sh $registry_url $bap_subscriber_id $bap_subscriber_id_key $bap_subscriber_url + bash scripts/update_bap_config.sh $registry_url $bap_subscriber_id $bap_subscriber_key_id $bap_subscriber_url else bash scripts/update_bap_config.sh fi @@ -137,9 +137,9 @@ install_bpp_protocol_server_with_sandbox(){ if [[ $1 ]];then registry_url=$1 bpp_subscriber_id=$2 - bpp_subscriber_id_key=$3 + bpp_subscriber_key_id=$3 bpp_subscriber_url=$4 - bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url + bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url else bash scripts/update_bpp_config.sh fi @@ -159,10 +159,10 @@ install_bpp_protocol_server(){ if [[ $1 ]];then registry_url=$1 bpp_subscriber_id=$2 - bpp_subscriber_id_key=$3 + bpp_subscriber_key_id=$3 bpp_subscriber_url=$4 webhook_url=$5 - bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url $webhook_url + bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url else bash scripts/update_bpp_config.sh fi @@ -248,9 +248,9 @@ else # Ask the user if they want to change the registry_url read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url registry_url=${custom_registry_url:-$beckn_registry_url} - bap_subscriber_id_key=$bap_subscriber_id-key + bap_subscriber_key_id=$bap_subscriber_id-key install_package - install_bap_protocol_server $registry_url $bap_subscriber_id $bap_subscriber_id_key $bap_subscriber_url + install_bap_protocol_server $registry_url $bap_subscriber_id $bap_subscriber_key_id $bap_subscriber_url ;; 3) read -p "Enter BPP Subscriber ID: " bpp_subscriber_id @@ -258,9 +258,9 @@ else # Ask the user if they want to change the registry_url read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url registry_url=${custom_registry_url:-$beckn_registry_url} - bpp_subscriber_id_key=$bpp_subscriber_id-key + bpp_subscriber_key_id=$bpp_subscriber_id-key install_package - install_bpp_protocol_server_with_sandbox $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url + install_bpp_protocol_server_with_sandbox $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url ;; 4) read -p "Enter BPP Subscriber ID: " bpp_subscriber_id @@ -270,9 +270,9 @@ else # Ask the user if they want to change the registry_url read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url registry_url=${custom_registry_url:-$beckn_registry_url} - bpp_subscriber_id_key=$bpp_subscriber_id-key + bpp_subscriber_key_id=$bpp_subscriber_id-key install_package - install_bpp_protocol_server $registry_url $bpp_subscriber_id $bpp_subscriber_id_key $bpp_subscriber_url $webhook_url + install_bpp_protocol_server $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url ;; 5) From 0ba9d431861cf7b8efa329f458aa6c32a411aa7c Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 20 Mar 2024 02:25:32 +0530 Subject: [PATCH 005/102] Updated the latest change for gateway and registry --- install/docker-compose-v2.yml | 1 + .../gateway_data/config/networks/onix.json | 11 ++++++++ .../gateway_data/config/swf.properties-sample | 25 ++++++++++--------- .../config/swf.properties-sample | 13 +++++++--- 4 files changed, 34 insertions(+), 16 deletions(-) create mode 100644 install/gateway_data/config/networks/onix.json diff --git a/install/docker-compose-v2.yml b/install/docker-compose-v2.yml index c6c906c..435ecfe 100644 --- a/install/docker-compose-v2.yml +++ b/install/docker-compose-v2.yml @@ -27,6 +27,7 @@ services: restart: unless-stopped volumes: - ./gateway_data/config/swf.properties:/gateway/overrideProperties/config/swf.properties + - ./gateway_data/config/networks:/gateway/overrideProperties/config/networks #Update varibales post demo - ./gateway_data/database:/gateway/database bap-client: diff --git a/install/gateway_data/config/networks/onix.json b/install/gateway_data/config/networks/onix.json new file mode 100644 index 0000000..dfc401b --- /dev/null +++ b/install/gateway_data/config/networks/onix.json @@ -0,0 +1,11 @@ +{ + "core_version" : "1.1.0", + "registry_id": "registry-energy.becknprotocol.io..LREG", + "search_provider_id" : "gateway-energy.becknprotocol.io", + "self_registration_supported": true, + "subscription_needed_post_registration" : true, + "base_url": "https://registry-energy.becknprotocol.io", + "registry_url" : "https://registry-energy.becknprotocol.io/subscribers", + "extension_package": "in.succinct.beckn.boc", + "wild_card" : "" +} \ No newline at end of file diff --git a/install/gateway_data/config/swf.properties-sample b/install/gateway_data/config/swf.properties-sample index 33a2e14..0c4c6e2 100644 --- a/install/gateway_data/config/swf.properties-sample +++ b/install/gateway_data/config/swf.properties-sample @@ -1,20 +1,22 @@ swf.load.complete.config.tables.if.count.less.than=500 swf.user.password.encrypted=false -swf.plugins.background.core.workers.numThreads=1 +swf.plugins.background.core.workers.numThreads=2 swf.application.authentication.required=false -beckn.network.timeout=10000 + +swf.encryption.support=false +swf.key.store.directory=./.keystore +swf.key.store.password=venky12 +swf.key.entry.succinct.password=succinct12 -#swf.host=localhost swf.host=GATEWAY_URL swf.external.port=GATEWAY_PORT swf.external.scheme=PROTOCOL - swf.jdbc.driver=org.h2.Driver -swf.jdbc.url=jdbc:h2:./database/gateway;AUTO_SERVER=TRUE; -swf.jdbc.userid=gateway -swf.jdbc.password=gateway +swf.jdbc.url=jdbc:h2:./database/standalone;AUTO_SERVER=TRUE; +swf.jdbc.userid=standalone +swf.jdbc.password=standalone swf.jdbc.validationQuery=values(1) swf.jdbc.dbschema=PUBLIC swf.jdbc.dbschema.setonconnection=true @@ -31,12 +33,11 @@ swf.jdbc.set.dbschema.command=set schema public ## Beckn Gateway configurations. beckn.auth.enabled=true + in.succinct.beckn.gateway.subscriber_id=SUBSCRIBER_ID in.succinct.beckn.gateway.public_key_id=SUBSCRIBER_ID.k1 -in.succinct.beckn.registry.url=REGISTRY_URL -in.succinct.beckn.registry.signing_public_key=SIGNING_PUBLIC_KEY -in.succinct.beckn.registry.encryption_public_key=ENCRYPTION_PUBLIC_KEY -swf.encryption.support=false -#swf.key.store.directory=./.keystore +in.succinct.onet.country.iso.3=IND +in.succinct.onet.country.iso.2=IN +in.succinct.onet.name=onix \ No newline at end of file diff --git a/install/registry_data/config/swf.properties-sample b/install/registry_data/config/swf.properties-sample index 7049488..3e2b112 100644 --- a/install/registry_data/config/swf.properties-sample +++ b/install/registry_data/config/swf.properties-sample @@ -1,6 +1,6 @@ swf.load.complete.config.tables.if.count.less.than=500 swf.user.password.encrypted=false -swf.plugins.background.core.workers.numThreads=1 +swf.plugins.background.core.workers.numThreads=3 swf.application.authentication.required=false @@ -31,9 +31,14 @@ swf.jdbc.set.dbschema.command=set schema public swf.api.keys.case=SNAKE swf.api.root.required=false -swf.encryption.support=false -#swf.key.store.directory=./.keystore - # Needed for Google Login #swf.GOOGLE.client.id= #swf.GOOGLE.client.secret= + +swf.encryption.support=false +## Uncomment below if encryption is needed and set appropriate passwords +#swf.key.store.directory=./.keystore +#swf.key.store.password=venky12 +#swf.key.entry.succinct.password=succinct12 + +swf.ftl.dir=src/main/resources/templates \ No newline at end of file From aee08d88e4d044d9209690a8f4632e4da8833fea Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 20 Mar 2024 03:02:41 +0530 Subject: [PATCH 006/102] Added more variables to registry --- install/scripts/registry_entry.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/install/scripts/registry_entry.sh b/install/scripts/registry_entry.sh index 59bac0d..ee9cd2f 100755 --- a/install/scripts/registry_entry.sh +++ b/install/scripts/registry_entry.sh @@ -19,7 +19,8 @@ create_network_participant() { "subscriber_id": "$subscriber_id", "pub_key_id": "$pub_key_id", "subscriber_url": "$subscriber_url", - "domain": " ", + "domain": "", + "extended_attributes": {"domains": []} "encr_public_key": "$encr_public_key", "signing_public_key": "$signing_public_key", "valid_from": "$valid_from", From 486a540ef8d86e3571dc134d107e4644ef27a173 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 20 Mar 2024 03:08:18 +0530 Subject: [PATCH 007/102] Added more variables to registry --- install/scripts/registry_entry.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/scripts/registry_entry.sh b/install/scripts/registry_entry.sh index ee9cd2f..fa29e7d 100755 --- a/install/scripts/registry_entry.sh +++ b/install/scripts/registry_entry.sh @@ -20,7 +20,7 @@ create_network_participant() { "pub_key_id": "$pub_key_id", "subscriber_url": "$subscriber_url", "domain": "", - "extended_attributes": {"domains": []} + "extended_attributes": {"domains": []}, "encr_public_key": "$encr_public_key", "signing_public_key": "$signing_public_key", "valid_from": "$valid_from", From 91988d40d97bf00b38986309293ab0bcaa5cec3d Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 20 Mar 2024 03:11:13 +0530 Subject: [PATCH 008/102] Added more variables to registry --- install/scripts/registry_entry.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/scripts/registry_entry.sh b/install/scripts/registry_entry.sh index fa29e7d..81fca05 100755 --- a/install/scripts/registry_entry.sh +++ b/install/scripts/registry_entry.sh @@ -19,7 +19,7 @@ create_network_participant() { "subscriber_id": "$subscriber_id", "pub_key_id": "$pub_key_id", "subscriber_url": "$subscriber_url", - "domain": "", + "domain": " ", "extended_attributes": {"domains": []}, "encr_public_key": "$encr_public_key", "signing_public_key": "$signing_public_key", From 3af62d296588c235fc1d3f0db9ced1d0888894ff Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 20 Mar 2024 03:21:56 +0530 Subject: [PATCH 009/102] Added more variables to registry --- install/scripts/registry_entry.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/install/scripts/registry_entry.sh b/install/scripts/registry_entry.sh index 81fca05..0a8f66b 100755 --- a/install/scripts/registry_entry.sh +++ b/install/scripts/registry_entry.sh @@ -18,6 +18,7 @@ create_network_participant() { { "subscriber_id": "$subscriber_id", "pub_key_id": "$pub_key_id", + "unique_key_id": "$pub_key_id", "subscriber_url": "$subscriber_url", "domain": " ", "extended_attributes": {"domains": []}, From 3acfccaee95ec38c4211ab21bd0f529501d32221 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 20 Mar 2024 03:58:00 +0530 Subject: [PATCH 010/102] Add onix.sh --- install/onix.sh | 344 +++++++++++++++++++++++++++++++++++++ install/onix_ascii_art.txt | 27 +++ 2 files changed, 371 insertions(+) create mode 100755 install/onix.sh create mode 100644 install/onix_ascii_art.txt diff --git a/install/onix.sh b/install/onix.sh new file mode 100755 index 0000000..b6b6ca0 --- /dev/null +++ b/install/onix.sh @@ -0,0 +1,344 @@ +#!/bin/bash +source scripts/variables.sh +source scripts/get_container_details.sh + +# Function to start a specific service inside docker-compose file +install_package(){ + echo "${GREEN}................Installing required packages................${NC}" + bash scripts/package_manager.sh + echo "Package Installation is done" + +} +start_container(){ + #ignore orphaned containers warning + export COMPOSE_IGNORE_ORPHANS=1 + docker-compose -f docker-compose-v2.yml up -d $1 +} + +update_registry_details() { + if [[ $1 ]];then + if [[ $1 == https://* ]]; then + if [[ $(uname -s) == 'Darwin' ]]; then + registry_url=$(echo "$1" | sed -E 's/https:\/\///') + else + registry_url=$(echo "$1" | sed 's/https:\/\///') + fi + registry_port=443 + protocol=https + elif [[ $1 == http://* ]]; then + if [[ $(uname -s) == 'Darwin' ]]; then + registry_url=$(echo "$1" | sed -E 's/http:\/\///') + else + registry_url=$(echo "$1" | sed 's/http:\/\///') + fi + registry_port=80 + protocol=http + fi + + else + registry_url=registry + registry_port=3030 + protocol=http + fi + echo $registry_url + cp $SCRIPT_DIR/../registry_data/config/swf.properties-sample $SCRIPT_DIR/../registry_data/config/swf.properties + config_file="$SCRIPT_DIR/../registry_data/config/swf.properties" + + tmp_file=$(mktemp "tempfile.XXXXXXXXXX") + sed "s|REGISTRY_URL|$registry_url|g; s|REGISTRY_PORT|$registry_port|g; s|PROTOCOL|$protocol|g" "$config_file" > "$tmp_file" + mv "$tmp_file" "$config_file" + +} +# Function to start the MongoDB, Redis, and RabbitMQ Services +start_support_services(){ + #ignore orphaned containers warning + export COMPOSE_IGNORE_ORPHANS=1 + echo "${GREEN}................Installing MongoDB................${NC}" + docker-compose -f docker-compose-app.yml up -d mongo_db + echo "MongoDB installation successful" + + echo "${GREEN}................Installing RabbitMQ................${NC}" + docker-compose -f docker-compose-app.yml up -d queue_service + echo "RabbitMQ installation successful" + + echo "${GREEN}................Installing Redis................${NC}" + docker-compose -f docker-compose-app.yml up -d redis_db + echo "Redis installation successful" +} + +install_gateway() { + if [[ $1 && $2 ]]; then + bash scripts/update_gateway_details.sh $1 $2 + else + bash scripts/update_gateway_details.sh registry + fi + echo "${GREEN}................Installing Gateway service................${NC}" + start_container gateway + echo "Registering Gateway in the registry" + + sleep 10 + if [[ $1 && $2 ]]; then + bash scripts/register_gateway.sh $2 + else + bash scripts/register_gateway.sh + fi + echo " " + echo "Gateway installation successful" +} + +# Function to install Beckn Gateway and Beckn Registry +install_registry(){ + if [[ $1 ]]; then + update_registry_details $1 + else + update_registry_details + fi + + echo "${GREEN}................Installing Registry service................${NC}" + start_container registry + sleep 10 + echo "Registry installation successful" +} + +# Function to install BAP Protocol Server +install_bap_protocol_server(){ + start_support_services + if [[ $1 ]];then + registry_url=$1 + bap_subscriber_id=$2 + bap_subscriber_key_id=$3 + bap_subscriber_url=$4 + bash scripts/update_bap_config.sh $registry_url $bap_subscriber_id $bap_subscriber_key_id $bap_subscriber_url + else + bash scripts/update_bap_config.sh + fi + sleep 10 + start_container "bap-client" + start_container "bap-network" + sleep 10 + echo "Protocol server BAP installation successful" +} + +# Function to install BPP Protocol Server with BPP Sandbox +install_bpp_protocol_server_with_sandbox(){ + start_support_services + echo "${GREEN}................Installing Sandbox................${NC}" + start_container "sandbox-api" + sleep 5 + echo "Sandbox installation successful" + + echo "${GREEN}................Installing Webhook................${NC}" + start_container "sandbox-webhook" + sleep + echo "Webhook installation successful" + + echo "${GREEN}................Installing Protocol Server for BPP................${NC}" + + if [[ $1 ]];then + registry_url=$1 + bpp_subscriber_id=$2 + bpp_subscriber_key_id=$3 + bpp_subscriber_url=$4 + bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url + else + bash scripts/update_bpp_config.sh + fi + + sleep 10 + start_container "bpp-client" + start_container "bpp-network" + sleep 10 + echo "Protocol server BPP installation successful" +} + +# Function to install BPP Protocol Server without Sandbox +install_bpp_protocol_server(){ + start_support_services + echo "${GREEN}................Installing Protocol Server for BPP................${NC}" + + if [[ $1 ]];then + registry_url=$1 + bpp_subscriber_id=$2 + bpp_subscriber_key_id=$3 + bpp_subscriber_url=$4 + webhook_url=$5 + bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url + else + bash scripts/update_bpp_config.sh + fi + + sleep 10 + start_container "bpp-client" + start_container "bpp-network" + sleep 10 + echo "Protocol server BPP installation successful" +} + + + +# MAIN SCRIPT STARTS HERE +#!/bin/bash + +# echo "$(ls /home/ravi/onix)" +echo "Welcome to Onix!" +if [ -f ./onix_ascii_art.txt ]; then + cat ./onix_ascii_art.txt +else + echo "[Display ONIX ASCII Art]" +fi + +echo "ONIX is a platform that helps you quickly launch and configure beckn-enabled networks." +echo -e "\nWhat would you like to do?\n1. Join an existing network\n2. Create new production network\n3. Set up a network on your local machine\n4. Merge multiple networks\n5. Configure Existing Network\n(Press Ctrl+C to exit)" +read -p "Enter your choice: " choice + +boldGreen="\e[1m\e[92m" +reset="\e[0m" + +# Function to request network configuration URL +requestNetworkConfig() { + echo "Please provide the network-specific configuration URL." + read -p "Paste the URL of the network configuration here (or press Enter to skip): " config_url + if [ -n "$config_url" ]; then + echo "Network configuration URL provided: $config_url" + else + echo "No network configuration URL provided, proceeding without it." + fi + echo "" +} + +# Function to handle the setup process for each platform +completeSetup() { + platform=$1 + config_url=$2 # Passing this as an argument, though it could be optional or ignored by some setups + + echo "Proceeding with the setup for $platform..." + if [ -n "$config_url" ]; then + echo "Using network configuration from: $config_url" + fi + + # Insert the specific commands for each platform, including requesting network config if necessary + case $platform in + "Registry") + requestNetworkConfig + read -p "Enter publicly accessible registry URL: " registry_url + if [[ $registry_url =~ /$ ]]; then + new_registry_url=${registry_url%/} + else + new_registry_url=$registry_url + fi + install_package + install_registry $new_registry_url + ;; + "Gateway"|"Beckn Gateway") + requestNetworkConfig + read -p "Enter your registry URL: " registry_url + read -p "Enter publicly accessible gateway URL: " gateway_url + + if [[ $registry_url =~ /$ ]]; then + new_registry_url=${registry_url%/} + else + new_registry_url=$registry_url + fi + if [[ $gateway_url =~ /$ ]]; then + gateway_url=${gateway_url%/} + fi + + install_package + install_gateway $new_registry_url $gateway_url + ;; + "BAP") + requestNetworkConfig + echo "${GREEN}................Installing Protocol Server for BAP................${NC}" + + read -p "Enter BAP Subscriber ID: " bap_subscriber_id + read -p "Enter BAP Subscriber URL: " bap_subscriber_url + read -p "Enter the registry_url(e.g. https://registry.becknprotocol.io/subscribers): " registry_url + bap_subscriber_key_id=$bap_subscriber_id-key + install_package + install_bap_protocol_server $registry_url $bap_subscriber_id $bap_subscriber_key_id $bap_subscriber_url + ;; + "BPP") + requestNetworkConfig + echo "${GREEN}................Installing Protocol Server for BAP................${NC}" + read -p "Enter BPP Subscriber ID: " bpp_subscriber_id + read -p "Enter BPP Subscriber URL: " bpp_subscriber_url + read -p "Enter the registry_url(e.g. https://registry.becknprotocol.io/subscribers): " registry_url + bpp_subscriber_key_id=$bpp_subscriber_id-key + install_package + install_bpp_protocol_server_with_sandbox $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url + ;; + *) + echo "Invalid platform selected." + exit 1 + ;; + esac + + echo "[Installation Logs]" + echo -e "${boldGreen}Your $platform setup is complete.${reset}" + echo -e "${boldGreen}You can access your $platform at http://${reset}" + # Key generation and subscription logic follows here +} + +# Determine the platforms available based on the initial choice +platforms=("Gateway" "BAP" "BPP") +[ "$choice" -eq 2 ] && platforms=("Registry" "${platforms[@]}") # Add Registry for new network setups + +echo "Great choice! Get ready." +echo -e "\nWhich platform would you like to set up?" +for i in "${!platforms[@]}"; do + echo "$((i+1)). ${platforms[$i]}" +done + +read -p "Enter your choice: " platform_choice + +selected_platform="${platforms[$((platform_choice-1))]}" + +if [[ -n $selected_platform ]]; then + # Note: Passing an empty string for config_url since it's optionally handled within `completeSetup` + completeSetup "$selected_platform" "" +else + echo "Invalid option. Please restart the script and select a valid option." + exit 1 +fi + +echo "Process complete. Thank you for using Onix!" + + + +# text=" +# The following components will be installed + +# 1. Registry +# 2. Gateway +# 3. Sandbox +# 4. Sandbox Webhook +# 5. Protocol Server for BAP +# 6. Protocol Server for BPP +# " + +# # Main script starts here +# bash scripts/banner.sh +# echo "Welcome to ONIX" +# echo "$text" + +# read -p "${GREEN}Do you want to install all the components on the local system? (Y/n): ${NC}" install_all + +# if [[ $install_all =~ ^[Yy]$ ]]; then +# # Install and bring up everything +# install_package +# install_registry +# install_gateway +# start_support_services +# install_bap_protocol_server +# install_bpp_protocol_server_with_sandbox +# else +# # User selects specific components to install +# echo "Please select the components that you want to install" +# echo "1. Beckn Gateway & Beckn Registry" +# echo "2. BAP Protocol Server" +# echo "3. BPP Protocol Server with BPP Sandbox" +# echo "4. BPP Protocol Server" +# echo "5. Generic Client Layer" +# echo "6. Exit" + +# read -p "Enter your choice (1-6): " user_choice diff --git a/install/onix_ascii_art.txt b/install/onix_ascii_art.txt new file mode 100644 index 0000000..f8975a8 --- /dev/null +++ b/install/onix_ascii_art.txt @@ -0,0 +1,27 @@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@::;;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@:;;;;:;;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@;;::;:::;;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@......@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@;:;;;;:;@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@............@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@::::@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@..................@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@.........,,::,,.........@@@@@........@@.......@@@@@@@........@.........@@@@@........@@@@@@@ +@@@@@@.........,,::;;;;::,.........@@@...................@@@@@........@..........@@@.........@@@@@@@ +@@@@@@.......,::;;;:,::;;;::,......@@@....................@@@@........@@..........@.........@@@@@@@@ +@@@@@@.....,:;;;::,....,::;;;:,....@@@.....................@@@........@@@..................@@@@@@@@@ +@@@@@@.....:;;:,..........,:;;,....@@@.....................@@@........@@@@................@@@@@@@@@@ +@@@@@@.....:;;:............:;;,....@@@........@@@@@........@@@........@@@@@@.............@@@@@@@@@@@ +@@@@@@.....:;;:............:;;,....@@@........@@@@@........@@@........@@@@@@@..........@@@@@@@@@@@@@ +@@@@@@.....:;;:............:;;,....@@@........@@@@@........@@@........@@@@@@............@@@@@@@@@@@@ +@@@@@@.....:;;:............:;;,....@@@........@@@@@........@@@........@@@@@..............@@@@@@@@@@@ +@@@@@@.....,;;;:,,......,::;;;,....@@@........@@@@@........@@@........@@@@................@@@@@@@@@@ +@@@@@@......,::;;;:,,,::;;;::,.....@@@........@@@@@........@@@........@@@..................@@@@@@@@@ +@@@@@@........,,:;;;;;;;::,........@@@........@@@@@........@@@........@@.........@@.........@@@@@@@@ +@@@@@@@@.........,,::::,,.........@@@@........@@@@@........@@@........@.........@@@@.........@@@@@@@ +@@@@@@@@@@@.........,..........@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@..............@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@........@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@...@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ +@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ + + From 8c0e994138656442ff813813c3ab42ab7fac4e51 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 20 Mar 2024 05:04:24 +0530 Subject: [PATCH 011/102] Separated setup for Registry and Gateway --- install/start_beckn_v2.sh | 47 ++++++++++++++++++++++++++++----------- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/install/start_beckn_v2.sh b/install/start_beckn_v2.sh index 7864b45..069d949 100755 --- a/install/start_beckn_v2.sh +++ b/install/start_beckn_v2.sh @@ -203,17 +203,40 @@ if [[ $install_all =~ ^[Yy]$ ]]; then else # User selects specific components to install echo "Please select the components that you want to install" - echo "1. Beckn Gateway & Beckn Registry" - echo "2. BAP Protocol Server" - echo "3. BPP Protocol Server with BPP Sandbox" - echo "4. BPP Protocol Server" - echo "5. Generic Client Layer" - echo "6. Exit" + echo "1. Beckn Registry" + echo "2. Beckn Gateway" + echo "3. BAP Protocol Server" + echo "4. BPP Protocol Server with BPP Sandbox" + echo "5. BPP Protocol Server" + echo "6. Generic Client Layer" + echo "7. Exit" read -p "Enter your choice (1-6): " user_choice case $user_choice in 1) + echo "${GREEN}Default Registry URL: $registry_url" + read -p "Do you want to change Registry URL? (Y/N): ${NC}" change_url + if [[ $change_url =~ ^[Yy]$ ]]; then + read -p "Enter publicly accessible registry URL: " registry_url + + if [[ $registry_url =~ /$ ]]; then + new_registry_url=${registry_url%/} + else + new_registry_url=$registry_url + fi + + install_package + install_registry $new_registry_url + #install_gateway $new_registry_url $gateway_url + + else + install_package + install_registry + #install_gateway + fi + ;; + 2) echo "${GREEN}Default Registry URL: $registry_url" echo "Default Gateway URL will be docker URL" read -p "Do you want to change Registry and Gateway URL? (Y/N): ${NC}" change_url @@ -231,16 +254,14 @@ else fi install_package - install_registry $new_registry_url install_gateway $new_registry_url $gateway_url else install_package - install_registry install_gateway fi ;; - 2) + 3) echo "${GREEN}................Installing Protocol Server for BAP................${NC}" read -p "Enter BAP Subscriber ID: " bap_subscriber_id @@ -252,7 +273,7 @@ else install_package install_bap_protocol_server $registry_url $bap_subscriber_id $bap_subscriber_key_id $bap_subscriber_url ;; - 3) + 4) read -p "Enter BPP Subscriber ID: " bpp_subscriber_id read -p "Enter BPP Subscriber URL: " bpp_subscriber_url # Ask the user if they want to change the registry_url @@ -262,7 +283,7 @@ else install_package install_bpp_protocol_server_with_sandbox $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url ;; - 4) + 5) read -p "Enter BPP Subscriber ID: " bpp_subscriber_id read -p "Enter BPP Subscriber URL: " bpp_subscriber_url read -p "Enter Webhook URL: " webhook_url @@ -275,7 +296,7 @@ else install_bpp_protocol_server $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url ;; - 5) + 6) echo "${GREEN}................Installing GENERIC CLIENT LAYER................${NC}" read -p "Enter BAP Subscriber ID: " bap_subscriber_id read -p "Enter BAP Subscriber URL: " bap_subscriber_url @@ -284,7 +305,7 @@ else start_container "generic-client-layer" ;; - 6) + 7) echo "Exiting ONIX" exit 0 ;; From 442aab743e6492abecb61aed5af3502d99581d83 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 20 Mar 2024 05:16:47 +0530 Subject: [PATCH 012/102] Separated setup for Registry and Gateway --- install/docker-compose-v2.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/install/docker-compose-v2.yml b/install/docker-compose-v2.yml index 435ecfe..79981a8 100644 --- a/install/docker-compose-v2.yml +++ b/install/docker-compose-v2.yml @@ -16,8 +16,6 @@ services: gateway: image: fidedocker/gateway - depends_on: - - registry container_name: gateway networks: - beckn_network From ff2a0ae900a65bfff0740ed943a2eb06e47c3d9b Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 20 Mar 2024 09:19:21 +0530 Subject: [PATCH 013/102] Added postman collection --- .../ONIX - PS Client.postman_collection.json | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 artifacts/ONIX - PS Client.postman_collection.json diff --git a/artifacts/ONIX - PS Client.postman_collection.json b/artifacts/ONIX - PS Client.postman_collection.json new file mode 100644 index 0000000..82a2ad8 --- /dev/null +++ b/artifacts/ONIX - PS Client.postman_collection.json @@ -0,0 +1,237 @@ +{ + "info": { + "_postman_id": "cacfa6d5-ccdd-4225-9fdd-3d4a507e9884", + "name": "ONIX - PS Client", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "13127879" + }, + "item": [ + { + "name": "Industry-4.0", + "item": [ + { + "name": "Search", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"{{supply_chain}}\",\n \"location\": {\n \"city\": {\n \"name\": \"Bangalore\",\n \"code\": \"std:080\"\n },\n \"country\": {\n \"name\": \"India\",\n \"code\": \"IND\"\n }\n },\n \"action\": \"search\",\n \"version\": \"1.1.0\",\n \"timestamp\": \"2023-10-09T04:46:28.012Z\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"a9aaecca-10b7-4d19-b640-b047a7c62195\",\n \"message_id\": \"{{$randomUUID}}\"\n },\n \"message\": {\n \"intent\": {\n \"category\": {\n \"descriptor\": {\n \"name\": \"assembly\"\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url_assembly}}/search", + "host": [ + "{{base_url_assembly}}" + ], + "path": [ + "search" + ] + } + }, + "response": [] + }, + { + "name": "Select", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"{{supply_chain}}\",\n \"location\": {\n \"country\": {\n \"code\": \"IND\"\n }\n },\n \"action\": \"select\",\n \"timestamp\": \"2023-05-25T05:23:03.443Z\",\n \"version\": \"1.1.0\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"a9aaecca-10b7-4d19-b640-b047a7c62195\",\n \"message_id\": \"{{$randomUUID}}\",\n \"ttl\": \"PT10M\"\n },\n \"message\": {\n \"order\": {\n \"provider\":{\n \"id\":\"6\"\n },\n \"items\": [\n {\n \"id\": \"11\"\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url_assembly}}/select", + "host": [ + "{{base_url_assembly}}" + ], + "path": [ + "select" + ] + } + }, + "response": [] + }, + { + "name": "Init", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"{{supply_chain}}\",\n \"location\": {\n \"country\": {\n \"code\": \"IND\"\n }\n },\n \"action\": \"init\",\n \"timestamp\": \"2023-05-25T05:23:03.443Z\",\n \"version\": \"1.1.0\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"a9aaecca-10b7-4d19-b640-b047a7c62195\",\n \"message_id\": \"{{$randomUUID}}\",\n \"ttl\": \"PT10M\"\n },\n \"message\": {\n \"order\": {\n \"provider\": {\n \"id\": \"6\"\n },\n \"items\": [\n {\n \"id\": \"11\"\n }\n ],\n \"billing\": {\n \"name\": \"Alice Smith\",\n \"address\": \"Apt 303, Maple Towers, Richmond Road, 560001\",\n \"state\": {\n \"name\": \"Jurong East\"\n },\n \"city\": {\n \"name\": \"Jurong East\"\n },\n \"email\": \"alice.smith@example.com\",\n \"phone\": \"9886098860\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url_assembly}}/init", + "host": [ + "{{base_url_assembly}}" + ], + "path": [ + "init" + ] + } + }, + "response": [] + }, + { + "name": "Confirm", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"{{supply_chain}}\",\n \"location\": {\n \"country\": {\n \"code\": \"IND\"\n }\n },\n \"action\": \"confirm\",\n \"timestamp\": \"2023-05-25T05:23:03.443Z\",\n \"version\": \"1.1.0\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"a9aaecca-10b7-4d19-b640-b047a7c62195\",\n \"message_id\": \"{{$randomUUID}}\",\n \"ttl\": \"PT10M\"\n },\n \"message\": {\n \"order\": {\n \"items\": [\n {\n \"id\": \"11\"\n }\n ],\n \"fulfillments\": [\n {\n \"id\": \"10\",\n \"customer\": {\n \"contact\": {\n \"email\": \"fox.judie61234@abc.org\",\n \"phone\": \"+91-9999999999\"\n },\n \"person\": {\n \"name\": \"Judie Fox6\"\n }\n }\n }\n ],\n \"billing\": {\n \"name\": \"Industry buyer\",\n \"address\": \"B005 aspire heights, Jurong East, SGP, 680230\",\n \"state\": {\n \"name\": \"Jurong East\"\n },\n \"city\": {\n \"name\": \"Jurong East\"\n },\n \"email\": \"nobody@nomail.com\",\n \"phone\": \"9886098860\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url_assembly}}/confirm", + "host": [ + "{{base_url_assembly}}" + ], + "path": [ + "confirm" + ] + } + }, + "response": [] + }, + { + "name": "Status", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"{{supply_chain}}\",\n \"location\": {\n \"country\": {\n \"code\": \"DE\"\n }\n },\n \"action\": \"status\",\n \"version\": \"1.1.0\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"transaction_id\": \"a9aaecca-10b7-4d19-b640-b047a7c62195\",\n \"message_id\": \"{{$randomUUID}}\",\n \"timestamp\": \"2023-05-25T05:23:03.443Z\",\n \"ttl\": \"P30M\"\n },\n \"message\": {\n \"order_id\": \"9\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url_assembly}}/status", + "host": [ + "{{base_url_assembly}}" + ], + "path": [ + "status" + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "base_url_prod", + "value": "https://strapi-bpp.becknprotocol.io/beckn-bpp-adapter/health-check", + "type": "string" + }, + { + "key": "base_url_dev", + "value": "https://strapi-bpp-dev.becknprotocol.io/beckn-bpp-adapter", + "type": "string" + }, + { + "key": "base_url_local", + "value": "http://localhost:1337/beckn-bpp-adapter", + "type": "string" + }, + { + "key": "dhp_consultation", + "value": "dhp:consultation:0.1.0", + "type": "string" + }, + { + "key": "supply_chain", + "value": "supply-chain-services:assembly", + "type": "string" + }, + { + "key": "odr", + "value": "online-dispute-resolution:0.1.0", + "type": "string" + }, + { + "key": "bpp_id", + "value": "onix-bpp.becknprotocol.io", + "type": "string" + }, + { + "key": "bpp_uri", + "value": "https://onix-bpp.becknprotocol.io", + "type": "string" + }, + { + "key": "bap_id", + "value": "onix-bap.becknprotocol.io", + "type": "string" + }, + { + "key": "bap_uri", + "value": "https://onix-bap.becknprotocol.io", + "type": "string" + }, + { + "key": "core_version", + "value": "1.1.0", + "type": "string" + }, + { + "key": "uei", + "value": "uei:charging", + "type": "string" + }, + { + "key": "base_url_ev", + "value": "http://ec2-13-126-143-70.ap-south-1.compute.amazonaws.com:5001", + "type": "string" + }, + { + "key": "base_url_assembly", + "value": "https://onix-bap-client.becknprotocol.io", + "type": "string" + } + ] +} \ No newline at end of file From 20cf0d4aa25b2c27eec3fed370ef5850018484f1 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 20 Mar 2024 09:22:21 +0530 Subject: [PATCH 014/102] Add layer2 --- layer2/download_layer_2_config_bap.sh | 42 + layer2/download_layer_2_config_bpp.sh | 42 + layer2/samples/uei:charging_1.1.0.yml | 3989 +++++++++++++++++++++++++ 3 files changed, 4073 insertions(+) create mode 100644 layer2/download_layer_2_config_bap.sh create mode 100644 layer2/download_layer_2_config_bpp.sh create mode 100644 layer2/samples/uei:charging_1.1.0.yml diff --git a/layer2/download_layer_2_config_bap.sh b/layer2/download_layer_2_config_bap.sh new file mode 100644 index 0000000..bdf53aa --- /dev/null +++ b/layer2/download_layer_2_config_bap.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +read -p "Enter the path from where to download the layer 2 configuration file:" FILE_URL + +CONTAINER_NAME="bap-network" +CONTAINER_ID=`docker ps -aqf "name=$CONTAINER_NAME"` +CONTAINER_PATH="/usr/src/app/schemas" +wget -O "$(basename "$FILE_URL")" "$FILE_URL" + +echo + +if [ $? -eq 0 ]; then + echo "File downloaded successfully." + FILENAME="$(basename "$FILE_URL")" + CONTAINER_NAME="bap-network" + CONTAINER_ID=`docker ps -aqf "name=$CONTAINER_NAME"` + CONTAINER_PATH="/usr/src/app/schemas" + + docker cp "$FILENAME" "$CONTAINER_NAME":"$CONTAINER_PATH/$FILENAME" + if [ $? -eq 0 ]; then + echo "File copied to Docker container $CONTAINER_NAME successfully." + fi + + CONTAINER_NAME="bap-client" + CONTAINER_ID=`docker ps -aqf "name=$CONTAINER_NAME"` + + docker cp "$FILENAME" "$CONTAINER_NAME":"$CONTAINER_PATH/$FILENAME" + + if [ $? -eq 0 ]; then + echo "File copied to Docker container $CONTAINER_NAME successfully." + rm "$(basename "$FILE_URL")" + if [ $? -eq 0 ]; then + echo "Local copy of the file deleted successfully." + else + echo "Failed to delete the local copy of the file." + fi + else + echo "Failed to copy the file to Docker container." + fi +else + echo "Failed to download the file." +fi \ No newline at end of file diff --git a/layer2/download_layer_2_config_bpp.sh b/layer2/download_layer_2_config_bpp.sh new file mode 100644 index 0000000..6853be5 --- /dev/null +++ b/layer2/download_layer_2_config_bpp.sh @@ -0,0 +1,42 @@ +#!/bin/bash + +read -p "Enter the path from where to download the layer 2 configuration file:" FILE_URL + +CONTAINER_NAME="bap-network" +CONTAINER_ID=`docker ps -aqf "name=$CONTAINER_NAME"` +CONTAINER_PATH="/usr/src/app/schemas" +wget -O "$(basename "$FILE_URL")" "$FILE_URL" + +echo + +if [ $? -eq 0 ]; then + echo "File downloaded successfully." + FILENAME="$(basename "$FILE_URL")" + CONTAINER_NAME="bpp-network" + CONTAINER_ID=`docker ps -aqf "name=$CONTAINER_NAME"` + CONTAINER_PATH="/usr/src/app/schemas" + + docker cp "$FILENAME" "$CONTAINER_NAME":"$CONTAINER_PATH/$FILENAME" + if [ $? -eq 0 ]; then + echo "File copied to Docker container $CONTAINER_NAME successfully." + fi + + CONTAINER_NAME="bpp-client" + CONTAINER_ID=`docker ps -aqf "name=$CONTAINER_NAME"` + + docker cp "$FILENAME" "$CONTAINER_NAME":"$CONTAINER_PATH/$FILENAME" + + if [ $? -eq 0 ]; then + echo "File copied to Docker container $CONTAINER_NAME successfully." + rm "$(basename "$FILE_URL")" + if [ $? -eq 0 ]; then + echo "Local copy of the file deleted successfully." + else + echo "Failed to delete the local copy of the file." + fi + else + echo "Failed to copy the file to Docker container." + fi +else + echo "Failed to download the file." +fi \ No newline at end of file diff --git a/layer2/samples/uei:charging_1.1.0.yml b/layer2/samples/uei:charging_1.1.0.yml new file mode 100644 index 0000000..5a8e14f --- /dev/null +++ b/layer2/samples/uei:charging_1.1.0.yml @@ -0,0 +1,3989 @@ +openapi: 3.0.0 +info: + title: Beckn Energy API Specification + description: Adaptation of Beckn protocol for the Energy sector. + version: 1.1.0 +security: + - SubscriberAuth: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: This allows the customer to search for energy service providers. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + examples: + The BAP looks for EV charging providers: + value: + context: + domain: uei:charging + action: search + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + intent: + item: + descriptor: + code: energy + quantity: + required: + value: "4.0" + unit: kWH + category: + descriptor: + code: green-tariff + location: + gps: 12.423423,77.325647 + radius: + type: CONSTANT + value: "5" + unit: km + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: BAP selects a provider and their energy service. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + examples: + The BAP selects an EV charging service from a provider: + value: + context: + domain: uei:charging + action: select + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + provider: + id: chargezone.in + items: + - id: pe-charging-01 + quantity: + selected: + measure: + value: "4" + unit: kWh + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details to the energy service provider + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + examples: + The BAP initiates an order for the EV charging service from a provider: + value: + context: + domain: uei:charging + action: init + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + provider: + id: chargezone.in + items: + - id: pe-charging-01 + billing: + name: John Doe + email: abc@example.com + phone: +91-9876522222 + fulfillments: + - id: "1" + customer: + person: + name: John Doe + contact: + phone: +91-9887766554 + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Confirms the order, completes the payment and waits for order confirmation. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + examples: + The BAP confirms the order to charge the EV: + value: + context: + domain: uei:charging + action: confirm + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + providers: + id: chargezone.in + items: + - id: pe-charging-01 + billing: + name: John Doe + email: abc@example.com + number: +91-9876522222 + fulfillments: + - id: "1" + customer: + person: + name: John Doe + contact: + phone: +91-9887766554 + payments: + - collected_by: BPP + params: + amount: "40" + currency: INR + status: PAID + type: PRE-ORDER + quote: + price: + value: "40" + currency: INR + breakup: + - item: + descriptor: + name: Estimated units consumed + quantity: + selected: + measure: + value: "4" + unit: kWh + price: + value: "32" + currency: INR + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object status + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + examples: + The BAP checks for the status of the charging: + value: + context: + domain: uei:charging + action: status + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order_id: 6743e9e2-4fb5-487c-92b7 + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + examples: + The BAP cancels the order for the EV charging: + value: + context: + domain: uei:charging + action: cancel + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + cancellation_reason_id: "5" + descriptor: + short_desc: can't attend booking + order_id: 6743e9e2-4fb5-487c-92b7 + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Update a criteria of the order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + description: Updated order object + allOf: + - $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + examples: + The BAP sends an update to start charging the EV: + value: + context: + domain: uei:charging + action: update + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + update_target: order.fulfillments[0].state + order: + fulfillments: + - id: "1" + type: CHARGING + state: + descriptor: + code: start-charging + The BAP sends an update to stop charging the EV: + value: + context: + domain: uei:charging + action: update + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + update_target: order.fulfillments[0].state + order: + fulfillments: + - id: "1" + type: CHARGING + state: + descriptor: + code: end-charging + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + examples: + The BAP rates the service provided: + value: + context: + domain: uei:charging + action: rating + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + ratings: + - id: 6743e9e2-4fb5-487c-92b7 + rating_category: charger + value: "5" + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + examples: + The BAP wants to contact support: + value: + context: + domain: uei:charging + action: support + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + support: + order_id: 6743e9e2-4fb5-487c-92b7 + phone: "+919876543210" + email: john.doe@gmail.com + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_search: + post: + tags: + - Beckn Application Platform (BAP) + - Beckn Gateway (BG) + description: The BPP sends its energy catalog in response to a search request. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + The provider returns a list of catalogs: + value: + context: + domain: uei:charging + action: on_search + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: example-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + catalog: + providers: + - id: chargezone.in + descriptor: + name: Chargezone + short_desc: Chargezone Technologies Pvt Ltd + images: + - url: https://chargezone.in/images/logo.png + categories: + - id: "1" + descriptor: + code: green-tariff + name: green tariff + locations: + - id: "1" + gps: 12.345345,77.389754 + - id: "2" + gps: 12.247934,77.876987 + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "8" + currency: INR / kWH + quantity: + available: + measure: + value: "100" + unit: kWH + category_ids: + - "1" + location_ids: + - "1" + - "2" + fulfillment_ids: + - "1" + - "2" + add_ons: + - id: pe-charging-01-addon-1 + descriptor: + name: Free car wash + price: + value: "0" + currency: INR + fulfillments: + - id: "1" + type: CHARGING + stops: + - type: start + time: + timestamp: 01-06-2023 10:00:00 + - type: end + time: + timestamp: 01-06-2023 10:30:00 + tags: + - descriptor: + name: Charging Point Specifications + list: + - descriptor: + name: Charger type + code: charger-type + value: AC + - descriptor: + name: Connector type + code: connector-type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + - id: "2" + type: CHARGING + stops: + - type: start + time: + timestamp: 01-06-2023 10:00:00 + - type: end + time: + timestamp: 01-06-2023 10:30:00 + tags: + - descriptor: + name: Charging Point + list: + - descriptor: + name: Charger type + value: AC + - descriptor: + name: Connector type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + - id: log9.in + descriptor: + name: Log9 Inc + categories: + - id: "1" + descriptor: + code: green-tariff + name: green tariff + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "10" + currency: INR / kWH + quantity: + available: "1000" + category_ids: + - "1" + fulfillment_ids: + - "3" + - "4" + add_ons: + - id: pe-charging-01-addon-1 + descriptor: + name: Free tyre pressure check + price: + value: "0" + currency: INR + fulfillments: + - id: "3" + type: BATTERY-SWAP + stops: + - location: + gps: 12.745675, 77.987393 + - id: "4" + type: MOBILE-BATTERY-SWAP + stops: + - location: + url: https://log9.in/track/bswap/3234242 + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_select: + post: + tags: + - Beckn Application Platform (BAP) + description: Send details along with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + The provider sends the details of the item selected, along with a quote: + value: + context: + domain: uei:charging + action: on_select + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: example-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + providers: + id: chargezone.in + descriptor: + name: Chargezone + short_desc: Chargezone Technologies Pvt Ltd + images: + - url: https://chargezone.in/images/logo.png + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "8" + currency: INR/kWH + quantity: + available: + measure: + value: "100" + unit: kWh + selected: + measure: + value: "4" + unit: kWh + - id: pe-charging-01-addon-1 + descriptor: + code: add-on-item + name: Free car wash + price: + value: "0" + currency: INR + fulfillments: + - id: "1" + type: CHARGING + stops: + - type: start + time: + timestamp: 01-06-2023 10:00:00 + - type: end + time: + timestamp: 01-06-2023 10:30:00 + tags: + - descriptor: + name: Charging Point Specifications + list: + - descriptor: + name: Charger type + code: charger-type + value: AC + - descriptor: + name: Connector type + code: connector-type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + quote: + price: + value: "32" + currency: INR + breakup: + - item: + descriptor: + name: Estimated units consumed + quantity: + selected: + measure: + value: "4" + unit: kWh + price: + value: "32" + currency: INR + - item: + descriptor: + name: Free car wash + price: + value: "0" + currency: INR + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_init: + post: + tags: + - Beckn Application Platform (BAP) + description: Send draft order object with payment details updated for the service. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + The BPP intiates the order, sends the payment link: + value: + context: + domain: uei:charging + action: on_init + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: example-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + providers: + id: chargezone.in + descriptor: + name: Chargezone + short_desc: Chargezone Technologies Pvt Ltd + images: + - url: https://chargezone.in/images/logo.png + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "8" + currency: INR/kWH + quantity: + available: + measure: + value: "100" + unit: kWh + selected: + measure: + value: "4" + unit: kWh + fulfillments: + - "1" + fulfillments: + - id: "1" + customer: + person: + name: John Doe + contact: + phone: +91-9887766554 + type: CHARGING + state: + descriptor: + code: order-initiated + stops: + - type: start + time: + timestamp: 01-06-2023 10:00:00 + - type: end + time: + timestamp: 01-06-2023 10:30:00 + tags: + - descriptor: + name: Charging Point + list: + - descriptor: + name: Charger type + value: AC + - descriptor: + name: Connector type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + billing: + email: abc@example.com + number: +91-9876522222 + quote: + price: + value: "32" + currency: INR + breakup: + - item: + descriptor: + name: Estimated units consumed + quantity: + selected: + measure: + value: "4" + unit: kWh + price: + value: "32" + currency: INR + payments: + - url: https://payment.gateway.in + type: PRE-ORDER + status: NOT-PAID + params: + amount: "40" + currency: INR + time: + range: + start: "2023-08-10T10:00:00Z" + end: "2023-08-10T10:30:00Z" + cancellation_terms: + - fulfillment_state: + descriptor: + code: charging-start + cancellation_fee: + percentage: 30% + external_ref: + mimetype: text/html + url: https://chargezone.in/charge/tnc.html + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_confirm: + post: + tags: + - Beckn Application Platform (BAP) + description: Send active order object with the confirmed order ID + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + The BAP sends an order confirmation: + value: + context: + domain: uei:charging + action: on_confirm + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: example-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + id: 6743e9e2-4fb5-487c-92b7 + providers: + id: chargezone.in + descriptor: + name: Chargezone + short_desc: Chargezone Technologies Pvt Ltd + images: + - url: https://chargezone.in/images/logo.png + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "8" + currency: INR/kWH + quantity: + available: + measure: + value: "100" + unit: kWh + selected: + measure: + value: "4" + unit: kWh + fulfillments: + - "1" + fulfillments: + - id: "1" + customer: + person: + name: John Doe + contact: + phone: +91-9887766554 + type: CHARGING + state: + descriptor: + code: payment-completed + stops: + - type: start + location: + gps: 12.423423,77.325647 + time: + timestamp: 01-06-2023 10:00:00 + range: + start: 01-06-2023 10:00:00 + end: 01-06-2023 10:10:00 + instructions: + name: Charging instructions + short_desc: To start your charging, go to charger number 987, and click on 'start' on your app + - type: end + time: + timestamp: 01-06-2023 10:30:00 + range: + start: 01-06-2023 10:30:00 + end: 01-06-2023 10:40:00 + tags: + - descriptor: + name: Charging Point + list: + - descriptor: + name: Charger type + value: AC + - descriptor: + name: Connector type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + billing: + email: abc@example.com + number: +91-9876522222 + quote: + price: + value: "40" + currency: INR + breakup: + - item: + descriptor: + name: Estimated units consumed + quantity: + selected: + measure: + value: "4" + unit: kWh + price: + value: "32" + currency: INR + payments: + - type: PRE-ORDER + status: PAID + params: + amount: "40" + currency: INR + time: + range: + start: "2023-08-10T10:00:00Z" + end: "2023-08-10T10:30:00Z" + cancellation_terms: + - fulfillment_state: + descriptor: + code: charging-start + cancellation_fee: + percentage: 30% + external_ref: + mimetype: text/html + url: https://chargezone.in/charge/tnc.html + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_cancel: + post: + tags: + - Beckn Application Platform (BAP) + description: Sends cancelled order object with the reason. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + The provider cancels the order after the BAP requested for a cancellation: + value: + context: + domain: uei:charging + action: on_cancel + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: example-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + id: 6743e9e2-4fb5-487c-92b7 + status: CANCELLED + providers: + id: chargezone.in + descriptor: + name: Chargezone + short_desc: Chargezone Technologies Pvt Ltd + images: + - url: https://chargezone.in/images/logo.png + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "8" + currency: INR/kWH + quantity: + available: + measure: + value: "100" + unit: kWh + selected: + measure: + value: "4" + unit: kWh + fulfillments: + - "1" + fulfillments: + - id: "1" + customer: + person: + name: John Doe + contact: + phone: +91-9887766554 + type: CHARGING + state: + descriptor: + code: order-cancelled + stops: + - time: + range: + start: "10:00" + end: "10:30" + tags: + - descriptor: + name: Charging Point + list: + - descriptor: + name: Charger type + value: AC + - descriptor: + name: Connector type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + billing: + email: abc@example.com + number: +91-9876522222 + quote: + price: + value: "-32" + currency: INR + breakup: + - item: + descriptor: + name: payment refund + quantity: + selected: + measure: + value: "4" + unit: kWh + price: + value: "-32" + currency: INR + payments: + - type: PRE-ORDER + status: PAID + params: + amount: "40" + currency: INR + time: + range: + start: "2023-08-10T10:00:00Z" + end: "2023-08-10T10:30:00Z" + cancellation_terms: + - fulfillment_state: + descriptor: + code: charging-start + cancellation_fee: + percentage: 30% + external_ref: + mimetype: text/html + url: https://chargezone.in/charge/tnc.html + The provider cancels the order after the there was an error in the charger: + value: + context: + domain: uei:charging + action: on_cancel + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: example-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + id: 6743e9e2-4fb5-487c-92b7 + status: CANCELLED + providers: + id: chargezone.in + descriptor: + name: Chargezone + short_desc: Chargezone Technologies Pvt Ltd + images: + - url: https://chargezone.in/images/logo.png + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "8" + currency: INR/kWH + quantity: + available: + measure: + value: "100" + unit: kWh + selected: + measure: + value: "4" + unit: kWh + allocated: + measure: + value: "2" + unit: kWh + fulfillments: + - "1" + fulfillments: + - id: "1" + customer: + person: + name: John Doe + contact: + phone: +91-9887766554 + type: CHARGING + state: + descriptor: + code: charger-error + stops: + - time: + range: + start: "10:00" + end: "10:30" + tags: + - descriptor: + name: Charging Point + list: + - descriptor: + name: Charger type + value: AC + - descriptor: + name: Connector type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + billing: + email: abc@example.com + number: +91-9876522222 + quote: + price: + value: "-12" + currency: INR + breakup: + - item: + descriptor: + name: payment refund + quantity: + selected: + measure: + value: "4" + unit: kWh + price: + value: "-12" + currency: INR + payments: + - type: PRE-ORDER + status: PAID + params: + amount: "40" + currency: INR + time: + range: + start: "2023-08-10T10:00:00Z" + end: "2023-08-10T10:30:00Z" + cancellation_terms: + - fulfillment_state: + descriptor: + code: charging-start + cancellation_fee: + percentage: 30% + external_ref: + mimetype: text/html + url: https://chargezone.in/charge/tnc.html + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_update: + post: + tags: + - Beckn Application Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + The provider sends an updated object to start charging: + value: + context: + domain: uei:charging + action: on_update + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: example-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + id: 6743e9e2-4fb5-487c-92b7 + providers: + id: chargezone.in + descriptor: + name: Chargezone + short_desc: Chargezone Technologies Pvt Ltd + images: + - url: https://chargezone.in/images/logo.png + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "8" + currency: INR/kWH + quantity: + available: + measure: + value: "100" + unit: kWh + selected: + measure: + value: "4" + unit: kWh + fulfillments: + - "1" + fulfillments: + - id: "1" + customer: + person: + name: John Doe + contact: + phone: +91-9887766554 + type: CHARGING + state: + descriptor: + code: charging-started + stops: + - type: start + location: + gps: 12.423423,77.325647 + time: + timestamp: 01-06-2023 10:00:00 + range: + start: 01-06-2023 10:00:00 + end: 01-06-2023 10:10:00 + - type: end + time: + timestamp: 01-06-2023 10:30:00 + range: + start: 01-06-2023 10:30:00 + end: 01-06-2023 10:40:00 + tags: + - descriptor: + name: Charging Point + list: + - descriptor: + name: Charger type + value: AC + - descriptor: + name: Connector type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + billing: + email: abc@example.com + number: +91-9876522222 + quote: + price: + value: "40" + currency: INR + breakup: + - item: + descriptor: + name: Estimated units consumed + quantity: + selected: + measure: + value: "4" + unit: kWh + price: + value: "32" + currency: INR + payments: + - type: PRE-ORDER + status: PAID + params: + amount: "40" + currency: INR + time: + range: + start: "2023-08-10T10:00:00Z" + end: "2023-08-10T10:30:00Z" + cancellation_terms: + - fulfillment_state: + descriptor: + code: charging-start + cancellation_fee: + percentage: 30% + external_ref: + mimetype: text/html + url: https://chargezone.in/charge/tnc.html + The provider sends an updated object to stop charging: + value: + context: + domain: uei:charging + action: on_update + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: example-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + id: 6743e9e2-4fb5-487c-92b7 + providers: + id: chargezone.in + descriptor: + name: Chargezone + short_desc: Chargezone Technologies Pvt Ltd + images: + - url: https://chargezone.in/images/logo.png + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "8" + currency: INR/kWH + quantity: + available: + measure: + value: "100" + unit: kWh + selected: + measure: + value: "4" + unit: kWh + fulfillments: + - "1" + fulfillments: + - id: "1" + customer: + person: + name: John Doe + contact: + phone: +91-9887766554 + type: CHARGING + state: + descriptor: + code: charging-ended + stops: + - type: start + location: + gps: 12.423423,77.325647 + time: + timestamp: 01-06-2023 10:00:00 + range: + start: 01-06-2023 10:00:00 + end: 01-06-2023 10:10:00 + - type: end + time: + timestamp: 01-06-2023 10:30:00 + range: + start: 01-06-2023 10:30:00 + end: 01-06-2023 10:40:00 + tags: + - descriptor: + name: Charging Point + list: + - descriptor: + name: Charger type + value: AC + - descriptor: + name: Connector type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + billing: + email: abc@example.com + number: +91-9876522222 + quote: + price: + value: "40" + currency: INR + breakup: + - item: + descriptor: + name: Estimated units consumed + quantity: + selected: + measure: + value: "4" + unit: kWh + price: + value: "32" + currency: INR + payments: + - type: PRE-ORDER + status: PAID + params: + amount: "40" + currency: INR + time: + range: + start: "2023-08-10T10:00:00Z" + end: "2023-08-10T10:30:00Z" + cancellation_terms: + - fulfillment_state: + descriptor: + code: charging-start + cancellation_fee: + percentage: 30% + external_ref: + mimetype: text/html + url: https://chargezone.in/charge/tnc.html + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_status: + post: + tags: + - Beckn Application Platform (BAP) + description: Fetch the status of a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + The provider sends status of the charging: + value: + context: + domain: uei:charging + action: on_status + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: example-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + order: + id: 6743e9e2-4fb5-487c-92b7 + providers: + id: chargezone.in + descriptor: + name: Chargezone + short_desc: Chargezone Technologies Pvt Ltd + images: + - url: https://chargezone.in/images/logo.png + items: + - id: pe-charging-01 + descriptor: + code: energy + price: + value: "8" + currency: INR/kWH + quantity: + available: + measure: + value: "100" + unit: kWh + selected: + measure: + value: "4" + unit: kWh + fulfillments: + - "1" + fulfillments: + - id: "1" + customer: + person: + name: John Doe + contact: + phone: +91-9887766554 + type: CHARGING + state: + descriptor: + name: vehicle 65% charged + stops: + - type: start + location: + gps: 12.423423,77.325647 + time: + timestamp: 01-06-2023 10:00:00 + range: + start: 01-06-2023 10:00:00 + end: 01-06-2023 10:10:00 + - type: end + time: + timestamp: 01-06-2023 10:30:00 + range: + start: 01-06-2023 10:30:00 + end: 01-06-2023 10:40:00 + tags: + - descriptor: + name: Charging Point + list: + - descriptor: + name: Charger type + value: AC + - descriptor: + name: Connector type + value: CCS2 + - descriptor: + name: Power Rating + value: greater than 50kW + - descriptor: + name: Availability + value: Available + display: true + billing: + email: abc@example.com + number: +91-9876522222 + quote: + price: + value: "32" + currency: INR + breakup: + - item: + descriptor: + name: Estimated units consumed + quantity: + selected: + measure: + value: "4" + unit: kWh + price: + value: "32" + currency: INR + payments: + - type: PRE-ORDER + status: PAID + params: + amount: "40" + currency: INR + time: + range: + start: "2023-08-10T10:00:00Z" + end: "2023-08-10T10:30:00Z" + cancellation_terms: + - fulfillment_state: + descriptor: + code: charging-start + cancellation_fee: + percentage: 30% + external_ref: + mimetype: text/html + url: https://chargezone.in/charge/tnc.html + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_rating: + post: + tags: + - Beckn Application Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + - message + examples: + The provider responds with a form URL for rating: + value: + context: + domain: uei:charging + action: on_rating + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + feedback_form: + xinput: + form: + url: https://api.example-bpp.com/pilot/bpp/feedback/portal + required: "false" + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_support: + post: + tags: + - Beckn Application Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + The provider returns support details: + value: + context: + domain: uei:charging + action: on_support + location: + country: + name: India + code: IND + city: std:080 + version: 1.1.0 + bap_id: example-bap.com + bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 + bpp_id: chargezone-energy-bpp.com + bpp_uri: https://api.example-bpp.com/pilot/bpp/ + transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 + timestamp: "2023-07-16T04:41:16Z" + message: + support: + order_id: 6743e9e2-4fb5-487c-92b7 + phone: 1800 1080 + email: customer.care@chargezone.com + url: https://www.chargezone.com/helpdesk + responses: + "200": + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: "Describes the acknowledgement sent in response to an API call. If the implementation uses HTTP/S, then Ack must be returned in the same session. Every API call to a BPP must be responded to with an Ack whether the BPP intends to respond with a callback or not. This has one property called `status` that indicates the status of the Acknowledgement." + type: object + properties: + status: + type: string + description: "The status of the acknowledgement. If the request passes the validation criteria of the BPP, then this is set to ACK. If a BPP responds with status = `ACK` to a request, it is required to respond with a callback. If the request fails the validation criteria, then this is set to NACK. Additionally, if a BPP does not intend to respond with a callback even after the request meets the validation criteria, it should set this value to `NACK`." + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: Describes an additional item offered as a value-addition to a product or service. This does not exist independently in a catalog and is always associated with an item. + type: object + properties: + id: + description: Provider-defined ID of the add-on + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes the direct performer, driver or executor that fulfills an order. It is usually a person. But in some rare cases, it could be a non-living entity like a drone, or a bot. Some examples of agents are Doctor in the healthcare sector, a driver in the mobility sector, or a delivery person in the logistics sector. This object can be set at any stage of the order lifecycle. This can be set at the discovery stage when the BPP wants to provide details on the agent fulfilling the order, like in healthcare, where the doctor's name appears during search. This object can also used to search for a particular person that the customer wants fulfilling an order. Sometimes, this object gets instantiated after the order is confirmed, like in the case of on-demand taxis, where the driver is assigned after the user confirms the ride." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: "Describes the billing details of an entity.
This has properties like name,organization,address,email,phone,time,tax_number, created_at,updated_at" + type: object + properties: + name: + description: Name of the billable entity + type: string + organization: + description: Details of the organization being billed. + allOf: + - $ref: "#/components/schemas/Organization" + address: + description: The address of the billable entity + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address where the bill is sent to + type: string + format: email + phone: + description: Phone number of the billable entity + type: string + time: + description: Details regarding the billing period + allOf: + - $ref: "#/components/schemas/Time" + tax_id: + description: ID of the billable entity as recognized by the taxation authority + type: string + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the buyer + type: string + format: date-time + cancelled_by: + type: string + enum: + - CONSUMER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + CancellationTerm: + description: Describes the cancellation terms of an item or an order. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes the products or services offered by a BPP. This is typically sent as the response to a search intent from a BAP. The payment terms, offers and terms of fulfillment supported by the BPP can also be included here. The BPP can show hierarchical nature of products/services in its catalog using the parent_category_id in categories. The BPP can also send a ttl (time to live) in the context which is the duration for which a BAP can cache the catalog and use the cached catalog.
This has properties like bbp/descriptor,bbp/categories,bbp/fulfillments,bbp/payments,bbp/offers,bbp/providers and exp
This is used in the following situations.
  • This is typically used in the discovery stage when the BPP sends the details of the products and services it offers as response to a search intent from the BAP.
" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: A label under which a collection of items can be grouped. + type: object + properties: + id: + description: ID of the category + type: string + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular region of a specified radius centered at a specified GPS coordinate. + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + -allOf + - $ref: "#/components/schemas/Scalar" + - properties: + type: + type: string + value: + type: string + unit: + type: string + required: + - type + - value + allOf: + - anyOf: + - not: + properties: + type: + const: CONSTANT + required: + - type + - required: + - unit + City: + description: Describes a city + type: object + properties: + name: + description: Name of the city + type: string + code: + description: City code + type: string + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: "Every API call in beckn protocol has a context. It provides a high-level overview to the receiver about the nature of the intended transaction. Typically, it is the BAP that sets the transaction context based on the consumer's location and action on their UI. But sometimes, during unsolicited callbacks, the BPP also sets the transaction context but it is usually the same as the context of a previous full-cycle, request-callback interaction between the BAP and the BPP. The context object contains four types of fields.
  1. Demographic information about the transaction using fields like `domain`, `country`, and `region`.
  2. Addressing details like the sending and receiving platform's ID and API URL.
  3. Interoperability information like the protocol version that implemented by the sender and,
  4. Transaction details like the method being called at the receiver's endpoint, the transaction_id that represents an end-to-end user session at the BAP, a message ID to pair requests with callbacks, a timestamp to capture sending times, a ttl to specifiy the validity of the request, and a key to encrypt information if necessary.
This object must be passed in every interaction between a BAP and a BPP. In HTTP/S implementations, it is not necessary to send the context during the synchronous response. However, in asynchronous protocols, the context must be sent during all interactions," + type: object + properties: + domain: + description: Domain code that is relevant to this transaction context + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + description: The Beckn protocol method being called by the sender and executed at the receiver. + type: string + version: + type: string + description: Version of transaction protocol being used by the sender. + bap_id: + description: Subscriber ID of the BAP + allOf: + - description: "A globally unique identifier of the platform, Typically it is the fully qualified domain name (FQDN) of the platform." + type: string + bap_uri: + description: Subscriber URL of the BAP for accepting callbacks from BPPs. + allOf: + - description: The callback URL of the Subscriber. This should necessarily contain the same domain name as set in `subscriber_id``. + type: string + format: uri + bpp_id: + description: Subscriber ID of the BPP + allOf: + - $ref: "#/components/schemas/Context/properties/bap_id/allOf/0" + bpp_uri: + description: Subscriber URL of the BPP for accepting calls from BAPs. + allOf: + - $ref: "#/components/schemas/Context/properties/bap_uri/allOf/0" + transaction_id: + description: "This is a unique value which persists across all API calls from `search` through `confirm`. This is done to indicate an active user session across multiple requests. The BPPs can use this value to push personalized recommendations, and dynamic offerings related to an ongoing transaction despite being unaware of the user active on the BAP." + type: string + format: uuid + message_id: + description: "This is a unique value which persists during a request / callback cycle. Since beckn protocol APIs are asynchronous, BAPs need a common value to match an incoming callback from a BPP to an earlier call. This value can also be used to ignore duplicate messages coming from the BPP. It is recommended to generate a fresh message_id for every new interaction. When sending unsolicited callbacks, BPPs must generate a new message_id." + type: string + format: uuid + timestamp: + description: Time of request generation in RFC3339 format + type: string + format: date-time + key: + description: The encryption public key of the sender + type: string + ttl: + description: The duration in ISO8601 format after timestamp for which this message holds valid + type: string + Country: + description: Describes a country + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + DecimalValue: + description: Describes a numerical value in decimal form + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: "Describes an error object that is returned by a BAP, BPP or BG as a response or callback to an action by another network participant. This object is sent when any request received by a network participant is unacceptable. This object can be sent either during Ack or with the callback." + type: object + properties: + code: + type: string + description: 'Standard error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-005-ERROR-CODES-DRAFT-01.md of this repo"' + paths: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error. Used mainly for logging. Not recommended to be shown to the user. + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to buy or avail a product or a service. The BAP can declare the intent of the consumer containing
  • What they want (A product, service, offer)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + location: + description: Location of the request that needs fulfillment. + allOf: + - $ref: "#/components/schemas/Location" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of a business. + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + type: string + Region: + description: Describes an arbitrary region of space. The network policy should contain a published list of supported regions by the network. + type: object + properties: + dimensions: + description: "The number of dimensions that are used to describe any point inside that region. The most common dimensionality of a region is 2, that represents an area on a map. There are regions on the map that can be approximated to one-dimensional regions like roads, railway lines, or shipping lines. 3 dimensional regions are rarer, but are gaining popularity as flying drones are being adopted for various fulfillment services." + type: string + enum: + - "1" + - "2" + - "3" + type: + description: "The type of region. This is used to specify the granularity of the region represented by this object. Various examples of two-dimensional region types are city, country, state, district, and so on. The network policy should contain a list of all possible region types supported by the network." + type: string + name: + type: string + description: Name of the region as specified on the map where that region exists. + code: + type: string + description: A standard code representing the region. This should be interpreted in the same way by all network participants. + boundary: + type: string + description: "A string representing the boundary of the region. One-dimensional regions are represented by polylines. Two-dimensional regions are represented by polygons, and three-dimensional regions can represented by polyhedra." + map_url: + type: string + description: The url to the map of the region. This can be a globally recognized map or the one specified by the network policy. + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: "Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations
This has properties like label, time stamp,duration,range, days, schedule" + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Contains tracking information that can be used by the BAP to track the fulfillment of an order in real-time. which is useful for knowing the location of time sensitive deliveries. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required to confirm an order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, to confirm a flight ticket, the airline requires details of the passengers along with information on baggage, identity, in addition to the class of ticket. Similarly, a logistics company may require details on the nature of shipment in order to confirm the shipping. A recruiting firm may require additional details on the applicant in order to confirm a job application. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean From 9b518b5bc6caa19feedb998a6b163fd5809698b3 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 20 Mar 2024 09:30:36 +0530 Subject: [PATCH 015/102] rename charging yaml file --- .../samples/{uei:charging_1.1.0.yml => uei:charging_1.1.0.yaml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename layer2/samples/{uei:charging_1.1.0.yml => uei:charging_1.1.0.yaml} (100%) diff --git a/layer2/samples/uei:charging_1.1.0.yml b/layer2/samples/uei:charging_1.1.0.yaml similarity index 100% rename from layer2/samples/uei:charging_1.1.0.yml rename to layer2/samples/uei:charging_1.1.0.yaml From ae61e19282f464936917620e8ddecefef43a1082 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Tue, 26 Mar 2024 13:10:26 +0530 Subject: [PATCH 016/102] Mandatory layer 2 config required --- install/protocol-server-data/bap-client.yaml-sample | 7 ++++++- install/scripts/update_bap_config.sh | 4 ++++ .../{uei:charging_1.1.0.yaml => uei_charging_1.1.0.yaml} | 0 3 files changed, 10 insertions(+), 1 deletion(-) rename layer2/samples/{uei:charging_1.1.0.yaml => uei_charging_1.1.0.yaml} (100%) diff --git a/install/protocol-server-data/bap-client.yaml-sample b/install/protocol-server-data/bap-client.yaml-sample index 96b1e35..ad3e1cc 100644 --- a/install/protocol-server-data/bap-client.yaml-sample +++ b/install/protocol-server-data/bap-client.yaml-sample @@ -130,4 +130,9 @@ app: batchSize: 100 # In minutes syncInterval: 30 - redis_db: 3 \ No newline at end of file + redis_db: 3 + + useLayer2Config: USE_LAYER_2_CONFIG + mandateLayer2Config: MANDATE_LAYER_2_CONFIG + + diff --git a/install/scripts/update_bap_config.sh b/install/scripts/update_bap_config.sh index ec4530e..c4aa61a 100755 --- a/install/scripts/update_bap_config.sh +++ b/install/scripts/update_bap_config.sh @@ -80,6 +80,8 @@ if [[ $(uname -s ) == 'Darwin' ]];then "BAP_SUBSCRIBER_ID=$bap_subscriber_id" "BAP_SUBSCRIBER_URL=$bap_subscriber_url" "BAP_SUBSCRIBER_KEY_ID=$bap_subscriber_key_id" + "USE_LAYER_2_CONFIG"=true + "MANDATE_LAYER_2_CONFIG"=true ) echo "Configuring BAP protocol server" @@ -108,6 +110,8 @@ else ["BAP_SUBSCRIBER_ID"]=$bap_subscriber_id ["BAP_SUBSCRIBER_URL"]=$bap_subscriber_url ["BAP_SUBSCRIBER_KEY_ID"]=$bap_subscriber_key_id + ["USE_LAYER_2_CONFIG"]=true + ["MANDATE_LAYER_2_CONFIG"]=true ) echo "Configuring BAP protocol server" diff --git a/layer2/samples/uei:charging_1.1.0.yaml b/layer2/samples/uei_charging_1.1.0.yaml similarity index 100% rename from layer2/samples/uei:charging_1.1.0.yaml rename to layer2/samples/uei_charging_1.1.0.yaml From ed6561988d9bf8b1f3a8f547d5c942565efe7378 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Tue, 26 Mar 2024 13:12:06 +0530 Subject: [PATCH 017/102] Rename onix.sh to beckn-onix.sh --- install/{onix.sh => beckn-onix.sh} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename install/{onix.sh => beckn-onix.sh} (100%) diff --git a/install/onix.sh b/install/beckn-onix.sh similarity index 100% rename from install/onix.sh rename to install/beckn-onix.sh From 15993b637c8d4f4f59fb12a97de5f1994d2b48c8 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Tue, 26 Mar 2024 17:50:18 +0530 Subject: [PATCH 018/102] Mandate layer 2 config also for bpp: --- .../bpp-client.yaml-sample | 5 +- install/scripts/update_bpp_config.sh | 6 + layer2/download_layer_2_config_bap.sh | 0 layer2/download_layer_2_config_bpp.sh | 0 layer2/samples/retail_1.1.0.yaml | 2164 ++++++ layer2/samples/uei_charging_1.1.0.yaml | 6119 ++++++----------- 6 files changed, 4321 insertions(+), 3973 deletions(-) mode change 100644 => 100755 layer2/download_layer_2_config_bap.sh mode change 100644 => 100755 layer2/download_layer_2_config_bpp.sh create mode 100644 layer2/samples/retail_1.1.0.yaml diff --git a/install/protocol-server-data/bpp-client.yaml-sample b/install/protocol-server-data/bpp-client.yaml-sample index 6e2fe75..2da36ac 100644 --- a/install/protocol-server-data/bpp-client.yaml-sample +++ b/install/protocol-server-data/bpp-client.yaml-sample @@ -128,4 +128,7 @@ app: batchSize: 100 # In minutes syncInterval: 30 - redis_db: 3 \ No newline at end of file + redis_db: 3 + + useLayer2Config: USE_LAYER_2_CONFIG + mandateLayer2Config: MANDATE_LAYER_2_CONFIG \ No newline at end of file diff --git a/install/scripts/update_bpp_config.sh b/install/scripts/update_bpp_config.sh index 2166dd4..88106a6 100755 --- a/install/scripts/update_bpp_config.sh +++ b/install/scripts/update_bpp_config.sh @@ -79,6 +79,9 @@ if [[ $(uname -s ) == 'Darwin' ]];then "BPP_SUBSCRIBER_ID=$bpp_subscriber_id" "BPP_SUBSCRIBER_KEY_ID=$bpp_subscriber_key_id" "WEBHOOK_URL=$webhook_url" + "USE_LAYER_2_CONFIG"=true + "MANDATE_LAYER_2_CONFIG"=true + ) echo "Configuring BPP protocol server" @@ -109,6 +112,9 @@ else ["BPP_SUBSCRIBER_ID"]=$bpp_subscriber_id ["BPP_SUBSCRIBER_KEY_ID"]=$bpp_subscriber_key_id ["WEBHOOK_URL"]=$webhook_url + ["USE_LAYER_2_CONFIG"]=true + ["MANDATE_LAYER_2_CONFIG"]=true + ) echo "Configuring BAP protocol server" diff --git a/layer2/download_layer_2_config_bap.sh b/layer2/download_layer_2_config_bap.sh old mode 100644 new mode 100755 diff --git a/layer2/download_layer_2_config_bpp.sh b/layer2/download_layer_2_config_bpp.sh old mode 100644 new mode 100755 diff --git a/layer2/samples/retail_1.1.0.yaml b/layer2/samples/retail_1.1.0.yaml new file mode 100644 index 0000000..b3ae63c --- /dev/null +++ b/layer2/samples/retail_1.1.0.yaml @@ -0,0 +1,2164 @@ +openapi: 3.0.0 +info: + title: Beckn Protocol Core + description: retail layer 2 config from core yaml + version: 1.1.0 +security: + - SubscriberAuth: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: BAP declares the customer's intent to buy/avail products or services + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: BAP declares the customer's cart (or equivalent) created by selecting objects from the catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + description: Updated order object + allOf: + - $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_search: + post: + tags: + - Beckn Application Platform (BAP) + - Beckn Gateway (BG) + description: BPP sends its catalog in response to a search request. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_select: + post: + tags: + - Beckn Application Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_init: + post: + tags: + - Beckn Application Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_confirm: + post: + tags: + - Beckn Application Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_track: + post: + tags: + - Beckn Application Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_cancel: + post: + tags: + - Beckn Application Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_update: + post: + tags: + - Beckn Application Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_status: + post: + tags: + - Beckn Application Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_rating: + post: + tags: + - Beckn Application Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_support: + post: + tags: + - Beckn Application Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: "Describes the acknowledgement sent in response to an API call. If the implementation uses HTTP/S, then Ack must be returned in the same session. Every API call to a BPP must be responded to with an Ack whether the BPP intends to respond with a callback or not. This has one property called `status` that indicates the status of the Acknowledgement." + type: object + properties: + status: + type: string + description: "The status of the acknowledgement. If the request passes the validation criteria of the BPP, then this is set to ACK. If a BPP responds with status = `ACK` to a request, it is required to respond with a callback. If the request fails the validation criteria, then this is set to NACK. Additionally, if a BPP does not intend to respond with a callback even after the request meets the validation criteria, it should set this value to `NACK`." + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: Describes an additional item offered as a value-addition to a product or service. This does not exist independently in a catalog and is always associated with an item. + type: object + properties: + id: + description: Provider-defined ID of the add-on + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes the direct performer, driver or executor that fulfills an order. It is usually a person. But in some rare cases, it could be a non-living entity like a drone, or a bot. Some examples of agents are Doctor in the healthcare sector, a driver in the mobility sector, or a delivery person in the logistics sector. This object can be set at any stage of the order lifecycle. This can be set at the discovery stage when the BPP wants to provide details on the agent fulfilling the order, like in healthcare, where the doctor's name appears during search. This object can also used to search for a particular person that the customer wants fulfilling an order. Sometimes, this object gets instantiated after the order is confirmed, like in the case of on-demand taxis, where the driver is assigned after the user confirms the ride." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: "Describes the billing details of an entity.
This has properties like name,organization,address,email,phone,time,tax_number, created_at,updated_at" + type: object + properties: + name: + description: Name of the billable entity + type: string + organization: + description: Details of the organization being billed. + allOf: + - $ref: "#/components/schemas/Organization" + address: + description: The address of the billable entity + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address where the bill is sent to + type: string + format: email + phone: + description: Phone number of the billable entity + type: string + time: + description: Details regarding the billing period + allOf: + - $ref: "#/components/schemas/Time" + tax_id: + description: ID of the billable entity as recognized by the taxation authority + type: string + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the buyer + type: string + format: date-time + cancelled_by: + type: string + enum: + - CONSUMER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + CancellationTerm: + description: Describes the cancellation terms of an item or an order. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes the products or services offered by a BPP. This is typically sent as the response to a search intent from a BAP. The payment terms, offers and terms of fulfillment supported by the BPP can also be included here. The BPP can show hierarchical nature of products/services in its catalog using the parent_category_id in categories. The BPP can also send a ttl (time to live) in the context which is the duration for which a BAP can cache the catalog and use the cached catalog.
This has properties like bbp/descriptor,bbp/categories,bbp/fulfillments,bbp/payments,bbp/offers,bbp/providers and exp
This is used in the following situations.
  • This is typically used in the discovery stage when the BPP sends the details of the products and services it offers as response to a search intent from the BAP.
" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: A label under which a collection of items can be grouped. + type: object + properties: + id: + description: ID of the category + type: string + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular region of a specified radius centered at a specified GPS coordinate. + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + description: Name of the city + type: string + code: + description: City code + type: string + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: "Every API call in beckn protocol has a context. It provides a high-level overview to the receiver about the nature of the intended transaction. Typically, it is the BAP that sets the transaction context based on the consumer's location and action on their UI. But sometimes, during unsolicited callbacks, the BPP also sets the transaction context but it is usually the same as the context of a previous full-cycle, request-callback interaction between the BAP and the BPP. The context object contains four types of fields.
  1. Demographic information about the transaction using fields like `domain`, `country`, and `region`.
  2. Addressing details like the sending and receiving platform's ID and API URL.
  3. Interoperability information like the protocol version that implemented by the sender and,
  4. Transaction details like the method being called at the receiver's endpoint, the transaction_id that represents an end-to-end user session at the BAP, a message ID to pair requests with callbacks, a timestamp to capture sending times, a ttl to specifiy the validity of the request, and a key to encrypt information if necessary.
This object must be passed in every interaction between a BAP and a BPP. In HTTP/S implementations, it is not necessary to send the context during the synchronous response. However, in asynchronous protocols, the context must be sent during all interactions," + type: object + properties: + domain: + description: Domain code that is relevant to this transaction context + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + description: The Beckn protocol method being called by the sender and executed at the receiver. + type: string + version: + type: string + description: Version of transaction protocol being used by the sender. + bap_id: + description: Subscriber ID of the BAP + allOf: + - description: "A globally unique identifier of the platform, Typically it is the fully qualified domain name (FQDN) of the platform." + type: string + bap_uri: + description: Subscriber URL of the BAP for accepting callbacks from BPPs. + allOf: + - description: The callback URL of the Subscriber. This should necessarily contain the same domain name as set in `subscriber_id``. + type: string + format: uri + bpp_id: + description: Subscriber ID of the BPP + allOf: + - $ref: "#/components/schemas/Context/properties/bap_id/allOf/0" + bpp_uri: + description: Subscriber URL of the BPP for accepting calls from BAPs. + allOf: + - $ref: "#/components/schemas/Context/properties/bap_uri/allOf/0" + transaction_id: + description: "This is a unique value which persists across all API calls from `search` through `confirm`. This is done to indicate an active user session across multiple requests. The BPPs can use this value to push personalized recommendations, and dynamic offerings related to an ongoing transaction despite being unaware of the user active on the BAP." + type: string + format: uuid + message_id: + description: "This is a unique value which persists during a request / callback cycle. Since beckn protocol APIs are asynchronous, BAPs need a common value to match an incoming callback from a BPP to an earlier call. This value can also be used to ignore duplicate messages coming from the BPP. It is recommended to generate a fresh message_id for every new interaction. When sending unsolicited callbacks, BPPs must generate a new message_id." + type: string + format: uuid + timestamp: + description: Time of request generation in RFC3339 format + type: string + format: date-time + key: + description: The encryption public key of the sender + type: string + ttl: + description: The duration in ISO8601 format after timestamp for which this message holds valid + type: string + Country: + description: Describes a country + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + DecimalValue: + description: Describes a numerical value in decimal form + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: "Describes an error object that is returned by a BAP, BPP or BG as a response or callback to an action by another network participant. This object is sent when any request received by a network participant is unacceptable. This object can be sent either during Ack or with the callback." + type: object + properties: + code: + type: string + description: 'Standard error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-005-ERROR-CODES-DRAFT-01.md of this repo"' + paths: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error. Used mainly for logging. Not recommended to be shown to the user. + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to buy or avail a product or a service. The BAP can declare the intent of the consumer containing
  • What they want (A product, service, offer)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of a business. + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + type: string + Region: + description: Describes an arbitrary region of space. The network policy should contain a published list of supported regions by the network. + type: object + properties: + dimensions: + description: "The number of dimensions that are used to describe any point inside that region. The most common dimensionality of a region is 2, that represents an area on a map. There are regions on the map that can be approximated to one-dimensional regions like roads, railway lines, or shipping lines. 3 dimensional regions are rarer, but are gaining popularity as flying drones are being adopted for various fulfillment services." + type: string + enum: + - "1" + - "2" + - "3" + type: + description: "The type of region. This is used to specify the granularity of the region represented by this object. Various examples of two-dimensional region types are city, country, state, district, and so on. The network policy should contain a list of all possible region types supported by the network." + type: string + name: + type: string + description: Name of the region as specified on the map where that region exists. + code: + type: string + description: A standard code representing the region. This should be interpreted in the same way by all network participants. + boundary: + type: string + description: "A string representing the boundary of the region. One-dimensional regions are represented by polylines. Two-dimensional regions are represented by polygons, and three-dimensional regions can represented by polyhedra." + map_url: + type: string + description: The url to the map of the region. This can be a globally recognized map or the one specified by the network policy. + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: "Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations
This has properties like label, time stamp,duration,range, days, schedule" + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Contains tracking information that can be used by the BAP to track the fulfillment of an order in real-time. which is useful for knowing the location of time sensitive deliveries. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required to confirm an order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, to confirm a flight ticket, the airline requires details of the passengers along with information on baggage, identity, in addition to the class of ticket. Similarly, a logistics company may require details on the nature of shipment in order to confirm the shipping. A recruiting firm may require additional details on the applicant in order to confirm a job application. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean diff --git a/layer2/samples/uei_charging_1.1.0.yaml b/layer2/samples/uei_charging_1.1.0.yaml index 5a8e14f..b92a4a7 100644 --- a/layer2/samples/uei_charging_1.1.0.yaml +++ b/layer2/samples/uei_charging_1.1.0.yaml @@ -1,3989 +1,2164 @@ openapi: 3.0.0 info: - title: Beckn Energy API Specification - description: Adaptation of Beckn protocol for the Energy sector. - version: 1.1.0 + title: Beckn Protocol Core + description: uei:charging layer 2 config from core yaml + version: 1.1.0 security: - - SubscriberAuth: [] + - SubscriberAuth: [] paths: - /search: - post: - tags: - - Beckn Provider Platform (BPP) - - Beckn Gateway (BG) - description: This allows the customer to search for energy service providers. - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - search - message: - type: object - properties: - intent: - $ref: "#/components/schemas/Intent" - required: - - context - - message - examples: - The BAP looks for EV charging providers: - value: - context: - domain: uei:charging - action: search - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - intent: - item: - descriptor: - code: energy - quantity: - required: - value: "4.0" - unit: kWH - category: - descriptor: - code: green-tariff - location: - gps: 12.423423,77.325647 - radius: - type: CONSTANT - value: "5" - unit: km - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /select: - post: - tags: - - Beckn Provider Platform (BPP) - description: BAP selects a provider and their energy service. - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - select - required: - - action - message: - type: object - properties: - order: - $ref: "#/components/schemas/Order" - required: - - order - required: - - context - - message - examples: - The BAP selects an EV charging service from a provider: - value: - context: - domain: uei:charging - action: select - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - provider: - id: chargezone.in - items: - - id: pe-charging-01 - quantity: - selected: - measure: - value: "4" - unit: kWh - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /init: - post: - tags: - - Beckn Provider Platform (BPP) - description: Initialize an order by providing billing and/or shipping details to the energy service provider - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - init - required: - - action - message: - type: object - properties: - order: - $ref: "#/components/schemas/Order" - required: - - order - required: - - context - - message - examples: - The BAP initiates an order for the EV charging service from a provider: - value: - context: - domain: uei:charging - action: init - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - provider: - id: chargezone.in - items: - - id: pe-charging-01 - billing: - name: John Doe - email: abc@example.com - phone: +91-9876522222 - fulfillments: - - id: "1" - customer: - person: - name: John Doe - contact: - phone: +91-9887766554 - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /confirm: - post: - tags: - - Beckn Provider Platform (BPP) - description: Confirms the order, completes the payment and waits for order confirmation. - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - confirm - required: - - action - message: - type: object - properties: - order: - $ref: "#/components/schemas/Order" - required: - - order - required: - - context - - message - examples: - The BAP confirms the order to charge the EV: - value: - context: - domain: uei:charging - action: confirm - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - providers: - id: chargezone.in - items: - - id: pe-charging-01 - billing: - name: John Doe - email: abc@example.com - number: +91-9876522222 - fulfillments: - - id: "1" - customer: - person: - name: John Doe - contact: - phone: +91-9887766554 - payments: - - collected_by: BPP - params: - amount: "40" - currency: INR - status: PAID - type: PRE-ORDER - quote: - price: - value: "40" - currency: INR - breakup: - - item: - descriptor: - name: Estimated units consumed - quantity: - selected: - measure: - value: "4" - unit: kWh - price: - value: "32" - currency: INR - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /status: - post: - tags: - - Beckn Provider Platform (BPP) - description: Fetch the latest order object status - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - status - required: - - action - message: - type: object - properties: - order_id: - $ref: "#/components/schemas/Order/properties/id" - required: - - order_id - required: - - context - - message - examples: - The BAP checks for the status of the charging: - value: - context: - domain: uei:charging - action: status - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order_id: 6743e9e2-4fb5-487c-92b7 - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /cancel: - post: - tags: - - Beckn Provider Platform (BPP) - description: Cancel an order - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - cancel - required: - - action - message: - type: object - properties: - order_id: - $ref: "#/components/schemas/Order/properties/id" - cancellation_reason_id: - $ref: "#/components/schemas/Option/properties/id" - descriptor: - $ref: "#/components/schemas/Descriptor" - required: - - order_id - required: - - context - - message - examples: - The BAP cancels the order for the EV charging: - value: - context: - domain: uei:charging - action: cancel - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - cancellation_reason_id: "5" - descriptor: - short_desc: can't attend booking - order_id: 6743e9e2-4fb5-487c-92b7 - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /update: - post: - tags: - - Beckn Provider Platform (BPP) - description: Update a criteria of the order - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - update - required: - - action - message: - type: object - properties: - update_target: - description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' - type: string - order: - description: Updated order object - allOf: - - $ref: "#/components/schemas/Order" - required: - - update_target - - order - required: - - context - - message - examples: - The BAP sends an update to start charging the EV: - value: - context: - domain: uei:charging - action: update - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - update_target: order.fulfillments[0].state - order: - fulfillments: - - id: "1" - type: CHARGING - state: - descriptor: - code: start-charging - The BAP sends an update to stop charging the EV: - value: - context: - domain: uei:charging - action: update - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - update_target: order.fulfillments[0].state - order: - fulfillments: - - id: "1" - type: CHARGING - state: - descriptor: - code: end-charging - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /rating: - post: - tags: - - Beckn Provider Platform (BPP) - description: Provide feedback on a service - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - rating - required: - - action - message: - type: object - properties: - ratings: - type: array - items: - $ref: "#/components/schemas/Rating" - required: - - context - - message - examples: - The BAP rates the service provided: - value: - context: - domain: uei:charging - action: rating - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - ratings: - - id: 6743e9e2-4fb5-487c-92b7 - rating_category: charger - value: "5" - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /support: - post: - tags: - - Beckn Provider Platform (BPP) - description: Contact support - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - support - required: - - action - message: - type: object - properties: - support: - $ref: "#/components/schemas/Support" - required: - - context - - message - examples: - The BAP wants to contact support: - value: - context: - domain: uei:charging - action: support - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - support: - order_id: 6743e9e2-4fb5-487c-92b7 - phone: "+919876543210" - email: john.doe@gmail.com - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /on_search: - post: - tags: - - Beckn Application Platform (BAP) - - Beckn Gateway (BG) - description: The BPP sends its energy catalog in response to a search request. - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - on_search - required: - - action - message: - type: object - properties: - catalog: - $ref: "#/components/schemas/Catalog" - required: - - catalog - error: - $ref: "#/components/schemas/Error" - required: - - context - examples: - The provider returns a list of catalogs: - value: - context: - domain: uei:charging - action: on_search - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: example-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - catalog: - providers: - - id: chargezone.in - descriptor: - name: Chargezone - short_desc: Chargezone Technologies Pvt Ltd - images: - - url: https://chargezone.in/images/logo.png - categories: - - id: "1" - descriptor: - code: green-tariff - name: green tariff - locations: - - id: "1" - gps: 12.345345,77.389754 - - id: "2" - gps: 12.247934,77.876987 - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "8" - currency: INR / kWH - quantity: - available: - measure: - value: "100" - unit: kWH - category_ids: - - "1" - location_ids: - - "1" - - "2" - fulfillment_ids: - - "1" - - "2" - add_ons: - - id: pe-charging-01-addon-1 - descriptor: - name: Free car wash - price: - value: "0" - currency: INR - fulfillments: - - id: "1" - type: CHARGING - stops: - - type: start - time: - timestamp: 01-06-2023 10:00:00 - - type: end - time: - timestamp: 01-06-2023 10:30:00 - tags: - - descriptor: - name: Charging Point Specifications - list: - - descriptor: - name: Charger type - code: charger-type - value: AC - - descriptor: - name: Connector type - code: connector-type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - - id: "2" - type: CHARGING - stops: - - type: start - time: - timestamp: 01-06-2023 10:00:00 - - type: end - time: - timestamp: 01-06-2023 10:30:00 - tags: - - descriptor: - name: Charging Point - list: - - descriptor: - name: Charger type - value: AC - - descriptor: - name: Connector type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - - id: log9.in - descriptor: - name: Log9 Inc - categories: - - id: "1" - descriptor: - code: green-tariff - name: green tariff - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "10" - currency: INR / kWH - quantity: - available: "1000" - category_ids: - - "1" - fulfillment_ids: - - "3" - - "4" - add_ons: - - id: pe-charging-01-addon-1 - descriptor: - name: Free tyre pressure check - price: - value: "0" - currency: INR - fulfillments: - - id: "3" - type: BATTERY-SWAP - stops: - - location: - gps: 12.745675, 77.987393 - - id: "4" - type: MOBILE-BATTERY-SWAP - stops: - - location: - url: https://log9.in/track/bswap/3234242 - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /on_select: - post: - tags: - - Beckn Application Platform (BAP) - description: Send details along with quoted price for selected items - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - on_select - required: - - action - message: - type: object - properties: - order: - $ref: "#/components/schemas/Order" - error: - $ref: "#/components/schemas/Error" - required: - - context - examples: - The provider sends the details of the item selected, along with a quote: - value: - context: - domain: uei:charging - action: on_select - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: example-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - providers: - id: chargezone.in - descriptor: - name: Chargezone - short_desc: Chargezone Technologies Pvt Ltd - images: - - url: https://chargezone.in/images/logo.png - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "8" - currency: INR/kWH - quantity: - available: - measure: - value: "100" - unit: kWh - selected: - measure: - value: "4" - unit: kWh - - id: pe-charging-01-addon-1 - descriptor: - code: add-on-item - name: Free car wash - price: - value: "0" - currency: INR - fulfillments: - - id: "1" - type: CHARGING - stops: - - type: start - time: - timestamp: 01-06-2023 10:00:00 - - type: end - time: - timestamp: 01-06-2023 10:30:00 - tags: - - descriptor: - name: Charging Point Specifications - list: - - descriptor: - name: Charger type - code: charger-type - value: AC - - descriptor: - name: Connector type - code: connector-type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - quote: - price: - value: "32" - currency: INR - breakup: - - item: - descriptor: - name: Estimated units consumed - quantity: - selected: - measure: - value: "4" - unit: kWh - price: - value: "32" - currency: INR - - item: - descriptor: - name: Free car wash - price: - value: "0" - currency: INR - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /on_init: - post: - tags: - - Beckn Application Platform (BAP) - description: Send draft order object with payment details updated for the service. - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - on_init - required: - - action - message: - type: object - properties: - order: - $ref: "#/components/schemas/Order" - required: - - order - error: - $ref: "#/components/schemas/Error" - required: - - context - examples: - The BPP intiates the order, sends the payment link: - value: - context: - domain: uei:charging - action: on_init - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: example-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - providers: - id: chargezone.in - descriptor: - name: Chargezone - short_desc: Chargezone Technologies Pvt Ltd - images: - - url: https://chargezone.in/images/logo.png - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "8" - currency: INR/kWH - quantity: - available: - measure: - value: "100" - unit: kWh - selected: - measure: - value: "4" - unit: kWh - fulfillments: - - "1" - fulfillments: - - id: "1" - customer: - person: - name: John Doe - contact: - phone: +91-9887766554 - type: CHARGING - state: - descriptor: - code: order-initiated - stops: - - type: start - time: - timestamp: 01-06-2023 10:00:00 - - type: end - time: - timestamp: 01-06-2023 10:30:00 - tags: - - descriptor: - name: Charging Point - list: - - descriptor: - name: Charger type - value: AC - - descriptor: - name: Connector type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - billing: - email: abc@example.com - number: +91-9876522222 - quote: - price: - value: "32" - currency: INR - breakup: - - item: - descriptor: - name: Estimated units consumed - quantity: - selected: - measure: - value: "4" - unit: kWh - price: - value: "32" - currency: INR - payments: - - url: https://payment.gateway.in - type: PRE-ORDER - status: NOT-PAID - params: - amount: "40" - currency: INR - time: - range: - start: "2023-08-10T10:00:00Z" - end: "2023-08-10T10:30:00Z" - cancellation_terms: - - fulfillment_state: - descriptor: - code: charging-start - cancellation_fee: - percentage: 30% - external_ref: - mimetype: text/html - url: https://chargezone.in/charge/tnc.html - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /on_confirm: - post: - tags: - - Beckn Application Platform (BAP) - description: Send active order object with the confirmed order ID - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - on_confirm - required: - - action - message: - type: object - properties: - order: - $ref: "#/components/schemas/Order" - required: - - order - error: - $ref: "#/components/schemas/Error" - required: - - context - examples: - The BAP sends an order confirmation: - value: - context: - domain: uei:charging - action: on_confirm - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: example-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - id: 6743e9e2-4fb5-487c-92b7 - providers: - id: chargezone.in - descriptor: - name: Chargezone - short_desc: Chargezone Technologies Pvt Ltd - images: - - url: https://chargezone.in/images/logo.png - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "8" - currency: INR/kWH - quantity: - available: - measure: - value: "100" - unit: kWh - selected: - measure: - value: "4" - unit: kWh - fulfillments: - - "1" - fulfillments: - - id: "1" - customer: - person: - name: John Doe - contact: - phone: +91-9887766554 - type: CHARGING - state: - descriptor: - code: payment-completed - stops: - - type: start - location: - gps: 12.423423,77.325647 - time: - timestamp: 01-06-2023 10:00:00 - range: - start: 01-06-2023 10:00:00 - end: 01-06-2023 10:10:00 - instructions: - name: Charging instructions - short_desc: To start your charging, go to charger number 987, and click on 'start' on your app - - type: end - time: - timestamp: 01-06-2023 10:30:00 - range: - start: 01-06-2023 10:30:00 - end: 01-06-2023 10:40:00 - tags: - - descriptor: - name: Charging Point - list: - - descriptor: - name: Charger type - value: AC - - descriptor: - name: Connector type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - billing: - email: abc@example.com - number: +91-9876522222 - quote: - price: - value: "40" - currency: INR - breakup: - - item: - descriptor: - name: Estimated units consumed - quantity: - selected: - measure: - value: "4" - unit: kWh - price: - value: "32" - currency: INR - payments: - - type: PRE-ORDER - status: PAID - params: - amount: "40" - currency: INR - time: - range: - start: "2023-08-10T10:00:00Z" - end: "2023-08-10T10:30:00Z" - cancellation_terms: - - fulfillment_state: - descriptor: - code: charging-start - cancellation_fee: - percentage: 30% - external_ref: - mimetype: text/html - url: https://chargezone.in/charge/tnc.html - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /on_cancel: - post: - tags: - - Beckn Application Platform (BAP) - description: Sends cancelled order object with the reason. - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - on_cancel - required: - - action - message: - type: object - properties: - order: - $ref: "#/components/schemas/Order" - required: - - order - error: - $ref: "#/components/schemas/Error" - required: - - context - examples: - The provider cancels the order after the BAP requested for a cancellation: - value: - context: - domain: uei:charging - action: on_cancel - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: example-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - id: 6743e9e2-4fb5-487c-92b7 - status: CANCELLED - providers: - id: chargezone.in - descriptor: - name: Chargezone - short_desc: Chargezone Technologies Pvt Ltd - images: - - url: https://chargezone.in/images/logo.png - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "8" - currency: INR/kWH - quantity: - available: - measure: - value: "100" - unit: kWh - selected: - measure: - value: "4" - unit: kWh - fulfillments: - - "1" - fulfillments: - - id: "1" - customer: - person: - name: John Doe - contact: - phone: +91-9887766554 - type: CHARGING - state: - descriptor: - code: order-cancelled - stops: - - time: - range: - start: "10:00" - end: "10:30" - tags: - - descriptor: - name: Charging Point - list: - - descriptor: - name: Charger type - value: AC - - descriptor: - name: Connector type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - billing: - email: abc@example.com - number: +91-9876522222 - quote: - price: - value: "-32" - currency: INR - breakup: - - item: - descriptor: - name: payment refund - quantity: - selected: - measure: - value: "4" - unit: kWh - price: - value: "-32" - currency: INR - payments: - - type: PRE-ORDER - status: PAID - params: - amount: "40" - currency: INR - time: - range: - start: "2023-08-10T10:00:00Z" - end: "2023-08-10T10:30:00Z" - cancellation_terms: - - fulfillment_state: - descriptor: - code: charging-start - cancellation_fee: - percentage: 30% - external_ref: - mimetype: text/html - url: https://chargezone.in/charge/tnc.html - The provider cancels the order after the there was an error in the charger: - value: - context: - domain: uei:charging - action: on_cancel - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: example-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - id: 6743e9e2-4fb5-487c-92b7 - status: CANCELLED - providers: - id: chargezone.in - descriptor: - name: Chargezone - short_desc: Chargezone Technologies Pvt Ltd - images: - - url: https://chargezone.in/images/logo.png - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "8" - currency: INR/kWH - quantity: - available: - measure: - value: "100" - unit: kWh - selected: - measure: - value: "4" - unit: kWh - allocated: - measure: - value: "2" - unit: kWh - fulfillments: - - "1" - fulfillments: - - id: "1" - customer: - person: - name: John Doe - contact: - phone: +91-9887766554 - type: CHARGING - state: - descriptor: - code: charger-error - stops: - - time: - range: - start: "10:00" - end: "10:30" - tags: - - descriptor: - name: Charging Point - list: - - descriptor: - name: Charger type - value: AC - - descriptor: - name: Connector type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - billing: - email: abc@example.com - number: +91-9876522222 - quote: - price: - value: "-12" - currency: INR - breakup: - - item: - descriptor: - name: payment refund - quantity: - selected: - measure: - value: "4" - unit: kWh - price: - value: "-12" - currency: INR - payments: - - type: PRE-ORDER - status: PAID - params: - amount: "40" - currency: INR - time: - range: - start: "2023-08-10T10:00:00Z" - end: "2023-08-10T10:30:00Z" - cancellation_terms: - - fulfillment_state: - descriptor: - code: charging-start - cancellation_fee: - percentage: 30% - external_ref: - mimetype: text/html - url: https://chargezone.in/charge/tnc.html - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /on_update: - post: - tags: - - Beckn Application Platform (BAP) - description: Returns updated service with updated runtime object - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - on_update - required: - - action - message: - type: object - properties: - order: - $ref: "#/components/schemas/Order" - required: - - order - error: - $ref: "#/components/schemas/Error" - required: - - context - examples: - The provider sends an updated object to start charging: - value: - context: - domain: uei:charging - action: on_update - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: example-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - id: 6743e9e2-4fb5-487c-92b7 - providers: - id: chargezone.in - descriptor: - name: Chargezone - short_desc: Chargezone Technologies Pvt Ltd - images: - - url: https://chargezone.in/images/logo.png - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "8" - currency: INR/kWH - quantity: - available: - measure: - value: "100" - unit: kWh - selected: - measure: - value: "4" - unit: kWh - fulfillments: - - "1" - fulfillments: - - id: "1" - customer: - person: - name: John Doe - contact: - phone: +91-9887766554 - type: CHARGING - state: - descriptor: - code: charging-started - stops: - - type: start - location: - gps: 12.423423,77.325647 - time: - timestamp: 01-06-2023 10:00:00 - range: - start: 01-06-2023 10:00:00 - end: 01-06-2023 10:10:00 - - type: end - time: - timestamp: 01-06-2023 10:30:00 - range: - start: 01-06-2023 10:30:00 - end: 01-06-2023 10:40:00 - tags: - - descriptor: - name: Charging Point - list: - - descriptor: - name: Charger type - value: AC - - descriptor: - name: Connector type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - billing: - email: abc@example.com - number: +91-9876522222 - quote: - price: - value: "40" - currency: INR - breakup: - - item: - descriptor: - name: Estimated units consumed - quantity: - selected: - measure: - value: "4" - unit: kWh - price: - value: "32" - currency: INR - payments: - - type: PRE-ORDER - status: PAID - params: - amount: "40" - currency: INR - time: - range: - start: "2023-08-10T10:00:00Z" - end: "2023-08-10T10:30:00Z" - cancellation_terms: - - fulfillment_state: - descriptor: - code: charging-start - cancellation_fee: - percentage: 30% - external_ref: - mimetype: text/html - url: https://chargezone.in/charge/tnc.html - The provider sends an updated object to stop charging: - value: - context: - domain: uei:charging - action: on_update - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: example-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - id: 6743e9e2-4fb5-487c-92b7 - providers: - id: chargezone.in - descriptor: - name: Chargezone - short_desc: Chargezone Technologies Pvt Ltd - images: - - url: https://chargezone.in/images/logo.png - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "8" - currency: INR/kWH - quantity: - available: - measure: - value: "100" - unit: kWh - selected: - measure: - value: "4" - unit: kWh - fulfillments: - - "1" - fulfillments: - - id: "1" - customer: - person: - name: John Doe - contact: - phone: +91-9887766554 - type: CHARGING - state: - descriptor: - code: charging-ended - stops: - - type: start - location: - gps: 12.423423,77.325647 - time: - timestamp: 01-06-2023 10:00:00 - range: - start: 01-06-2023 10:00:00 - end: 01-06-2023 10:10:00 - - type: end - time: - timestamp: 01-06-2023 10:30:00 - range: - start: 01-06-2023 10:30:00 - end: 01-06-2023 10:40:00 - tags: - - descriptor: - name: Charging Point - list: - - descriptor: - name: Charger type - value: AC - - descriptor: - name: Connector type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - billing: - email: abc@example.com - number: +91-9876522222 - quote: - price: - value: "40" - currency: INR - breakup: - - item: - descriptor: - name: Estimated units consumed - quantity: - selected: - measure: - value: "4" - unit: kWh - price: - value: "32" - currency: INR - payments: - - type: PRE-ORDER - status: PAID - params: - amount: "40" - currency: INR - time: - range: - start: "2023-08-10T10:00:00Z" - end: "2023-08-10T10:30:00Z" - cancellation_terms: - - fulfillment_state: - descriptor: - code: charging-start - cancellation_fee: - percentage: 30% - external_ref: - mimetype: text/html - url: https://chargezone.in/charge/tnc.html - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /on_status: - post: - tags: - - Beckn Application Platform (BAP) - description: Fetch the status of a service - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - on_status - required: - - action - message: - type: object - properties: - order: - $ref: "#/components/schemas/Order" - required: - - order - error: - $ref: "#/components/schemas/Error" - required: - - context - examples: - The provider sends status of the charging: - value: - context: - domain: uei:charging - action: on_status - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: example-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - order: - id: 6743e9e2-4fb5-487c-92b7 - providers: - id: chargezone.in - descriptor: - name: Chargezone - short_desc: Chargezone Technologies Pvt Ltd - images: - - url: https://chargezone.in/images/logo.png - items: - - id: pe-charging-01 - descriptor: - code: energy - price: - value: "8" - currency: INR/kWH - quantity: - available: - measure: - value: "100" - unit: kWh - selected: - measure: - value: "4" - unit: kWh - fulfillments: - - "1" - fulfillments: - - id: "1" - customer: - person: - name: John Doe - contact: - phone: +91-9887766554 - type: CHARGING - state: - descriptor: - name: vehicle 65% charged - stops: - - type: start - location: - gps: 12.423423,77.325647 - time: - timestamp: 01-06-2023 10:00:00 - range: - start: 01-06-2023 10:00:00 - end: 01-06-2023 10:10:00 - - type: end - time: - timestamp: 01-06-2023 10:30:00 - range: - start: 01-06-2023 10:30:00 - end: 01-06-2023 10:40:00 - tags: - - descriptor: - name: Charging Point - list: - - descriptor: - name: Charger type - value: AC - - descriptor: - name: Connector type - value: CCS2 - - descriptor: - name: Power Rating - value: greater than 50kW - - descriptor: - name: Availability - value: Available - display: true - billing: - email: abc@example.com - number: +91-9876522222 - quote: - price: - value: "32" - currency: INR - breakup: - - item: - descriptor: - name: Estimated units consumed - quantity: - selected: - measure: - value: "4" - unit: kWh - price: - value: "32" - currency: INR - payments: - - type: PRE-ORDER - status: PAID - params: - amount: "40" - currency: INR - time: - range: - start: "2023-08-10T10:00:00Z" - end: "2023-08-10T10:30:00Z" - cancellation_terms: - - fulfillment_state: - descriptor: - code: charging-start - cancellation_fee: - percentage: 30% - external_ref: - mimetype: text/html - url: https://chargezone.in/charge/tnc.html - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /on_rating: - post: - tags: - - Beckn Application Platform (BAP) - description: Provide feedback on a service - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - on_rating - required: - - action - message: - type: object - properties: - feedback_form: - description: A feedback form to allow the user to provide additional information on the rating provided - allOf: - - $ref: "#/components/schemas/XInput" - error: - $ref: "#/components/schemas/Error" - required: - - context - - message - examples: - The provider responds with a form URL for rating: - value: - context: - domain: uei:charging - action: on_rating - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - feedback_form: - xinput: - form: - url: https://api.example-bpp.com/pilot/bpp/feedback/portal - required: "false" - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message - /on_support: - post: - tags: - - Beckn Application Platform (BAP) - description: Contact Support - requestBody: - content: - application/json: - schema: - type: object - properties: - context: - allOf: - - $ref: "#/components/schemas/Context" - - properties: - action: - enum: - - on_support - required: - - action - message: - type: object - properties: - support: - $ref: "#/components/schemas/Support" - error: - $ref: "#/components/schemas/Error" - required: - - context - examples: - The provider returns support details: - value: - context: - domain: uei:charging - action: on_support - location: - country: - name: India - code: IND - city: std:080 - version: 1.1.0 - bap_id: example-bap.com - bap_uri: https://api.example-bap.com/pilot/bap/energy/v1 - bpp_id: chargezone-energy-bpp.com - bpp_uri: https://api.example-bpp.com/pilot/bpp/ - transaction_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - message_id: 6743e9e2-4fb5-487c-92b7-13ba8018f176 - timestamp: "2023-07-16T04:41:16Z" - message: - support: - order_id: 6743e9e2-4fb5-487c-92b7 - phone: 1800 1080 - email: customer.care@chargezone.com - url: https://www.chargezone.com/helpdesk - responses: - "200": - description: Acknowledgement of message received after successful validation of schema and signature - content: - application/json: - schema: - type: object - properties: - message: - type: object - properties: - ack: - allOf: - - $ref: "#/components/schemas/Ack" - - properties: - status: - enum: - - ACK - - NACK - required: - - ack - error: - $ref: "#/components/schemas/Error" - required: - - message -components: - securitySchemes: - SubscriberAuth: - type: apiKey - in: header - name: Authorization - description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' - schemas: - Ack: - description: "Describes the acknowledgement sent in response to an API call. If the implementation uses HTTP/S, then Ack must be returned in the same session. Every API call to a BPP must be responded to with an Ack whether the BPP intends to respond with a callback or not. This has one property called `status` that indicates the status of the Acknowledgement." - type: object - properties: - status: - type: string - description: "The status of the acknowledgement. If the request passes the validation criteria of the BPP, then this is set to ACK. If a BPP responds with status = `ACK` to a request, it is required to respond with a callback. If the request fails the validation criteria, then this is set to NACK. Additionally, if a BPP does not intend to respond with a callback even after the request meets the validation criteria, it should set this value to `NACK`." - enum: - - ACK - - NACK - tags: - description: A list of tags containing any additional information sent along with the Acknowledgement. - type: array - items: - $ref: "#/components/schemas/TagGroup" - AddOn: - description: Describes an additional item offered as a value-addition to a product or service. This does not exist independently in a catalog and is always associated with an item. - type: object - properties: - id: - description: Provider-defined ID of the add-on - type: string - descriptor: - $ref: "#/components/schemas/Descriptor" - price: - $ref: "#/components/schemas/Price" - Address: - description: Describes a postal address. - type: string - Agent: - description: "Describes the direct performer, driver or executor that fulfills an order. It is usually a person. But in some rare cases, it could be a non-living entity like a drone, or a bot. Some examples of agents are Doctor in the healthcare sector, a driver in the mobility sector, or a delivery person in the logistics sector. This object can be set at any stage of the order lifecycle. This can be set at the discovery stage when the BPP wants to provide details on the agent fulfilling the order, like in healthcare, where the doctor's name appears during search. This object can also used to search for a particular person that the customer wants fulfilling an order. Sometimes, this object gets instantiated after the order is confirmed, like in the case of on-demand taxis, where the driver is assigned after the user confirms the ride." - properties: - person: - $ref: "#/components/schemas/Person" - contact: - $ref: "#/components/schemas/Contact" - organization: - $ref: "#/components/schemas/Organization" - rating: - $ref: "#/components/schemas/Rating/properties/value" - Authorization: - description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." - type: object - properties: - type: - description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. - type: string - token: - description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." - type: string - valid_from: - description: Timestamp in RFC3339 format from which token is valid - type: string - format: date-time - valid_to: - description: Timestamp in RFC3339 format until which token is valid - type: string - format: date-time - status: - description: Status of the token - type: string - Billing: - description: "Describes the billing details of an entity.
This has properties like name,organization,address,email,phone,time,tax_number, created_at,updated_at" - type: object - properties: - name: - description: Name of the billable entity - type: string - organization: - description: Details of the organization being billed. - allOf: - - $ref: "#/components/schemas/Organization" - address: - description: The address of the billable entity - allOf: - - $ref: "#/components/schemas/Address" - state: - description: The state where the billable entity resides. This is important for state-level tax calculation - allOf: - - $ref: "#/components/schemas/State" - city: - description: The city where the billable entity resides. - allOf: - - $ref: "#/components/schemas/City" - email: - description: Email address where the bill is sent to - type: string - format: email - phone: - description: Phone number of the billable entity - type: string - time: - description: Details regarding the billing period - allOf: - - $ref: "#/components/schemas/Time" - tax_id: - description: ID of the billable entity as recognized by the taxation authority - type: string - Cancellation: - description: Describes a cancellation event - type: object - properties: - time: - description: Date-time when the order was cancelled by the buyer - type: string - format: date-time - cancelled_by: - type: string - enum: - - CONSUMER - - PROVIDER - reason: - description: The reason for cancellation - allOf: - - $ref: "#/components/schemas/Option" - additional_description: - description: Any additional information regarding the nature of cancellation - allOf: - - $ref: "#/components/schemas/Descriptor" - CancellationTerm: - description: Describes the cancellation terms of an item or an order. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. - type: object - properties: - fulfillment_state: - description: The state of fulfillment during which this term is applicable. - allOf: - - $ref: "#/components/schemas/FulfillmentState" - reason_required: - description: Indicates whether a reason is required to cancel the order - type: boolean - cancel_by: - description: Information related to the time of cancellation. - allOf: - - $ref: "#/components/schemas/Time" - cancellation_fee: - $ref: "#/components/schemas/Fee" - xinput: - $ref: "#/components/schemas/XInput" - external_ref: - $ref: "#/components/schemas/MediaFile" - Catalog: - description: "Describes the products or services offered by a BPP. This is typically sent as the response to a search intent from a BAP. The payment terms, offers and terms of fulfillment supported by the BPP can also be included here. The BPP can show hierarchical nature of products/services in its catalog using the parent_category_id in categories. The BPP can also send a ttl (time to live) in the context which is the duration for which a BAP can cache the catalog and use the cached catalog.
This has properties like bbp/descriptor,bbp/categories,bbp/fulfillments,bbp/payments,bbp/offers,bbp/providers and exp
This is used in the following situations.
  • This is typically used in the discovery stage when the BPP sends the details of the products and services it offers as response to a search intent from the BAP.
" - type: object - properties: - descriptor: - $ref: "#/components/schemas/Descriptor" - fulfillments: - description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. - type: array - items: - $ref: "#/components/schemas/Fulfillment" - payments: - description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. - type: array - items: - $ref: "#/components/schemas/Payment" - offers: - description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. - type: array - items: - $ref: "#/components/schemas/Offer" - providers: - type: array - items: - $ref: "#/components/schemas/Provider" - exp: - description: Timestamp after which catalog will expire - type: string - format: date-time - ttl: - description: Duration in seconds after which this catalog will expire - type: string - Category: - description: A label under which a collection of items can be grouped. - type: object - properties: - id: - description: ID of the category - type: string - parent_category_id: - $ref: "#/components/schemas/Category/properties/id" - descriptor: - $ref: "#/components/schemas/Descriptor" - time: - $ref: "#/components/schemas/Time" - ttl: - description: Time to live for an instance of this schema - tags: - type: array - items: - $ref: "#/components/schemas/TagGroup" - Circle: - description: Describes a circular region of a specified radius centered at a specified GPS coordinate. - type: object - properties: - gps: - $ref: "#/components/schemas/Gps" - radius: - -allOf - - $ref: "#/components/schemas/Scalar" - - properties: - type: - type: string - value: - type: string - unit: - type: string - required: - - type - - value - allOf: - - anyOf: - - not: - properties: - type: - const: CONSTANT - required: - - type - - required: - - unit - City: - description: Describes a city - type: object - properties: - name: - description: Name of the city - type: string - code: - description: City code - type: string - Contact: - description: Describes the contact information of an entity - type: object - properties: - phone: - type: string - email: - type: string - jcard: - type: object - description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification - Context: - description: "Every API call in beckn protocol has a context. It provides a high-level overview to the receiver about the nature of the intended transaction. Typically, it is the BAP that sets the transaction context based on the consumer's location and action on their UI. But sometimes, during unsolicited callbacks, the BPP also sets the transaction context but it is usually the same as the context of a previous full-cycle, request-callback interaction between the BAP and the BPP. The context object contains four types of fields.
  1. Demographic information about the transaction using fields like `domain`, `country`, and `region`.
  2. Addressing details like the sending and receiving platform's ID and API URL.
  3. Interoperability information like the protocol version that implemented by the sender and,
  4. Transaction details like the method being called at the receiver's endpoint, the transaction_id that represents an end-to-end user session at the BAP, a message ID to pair requests with callbacks, a timestamp to capture sending times, a ttl to specifiy the validity of the request, and a key to encrypt information if necessary.
This object must be passed in every interaction between a BAP and a BPP. In HTTP/S implementations, it is not necessary to send the context during the synchronous response. However, in asynchronous protocols, the context must be sent during all interactions," - type: object - properties: - domain: - description: Domain code that is relevant to this transaction context - allOf: - - $ref: "#/components/schemas/Domain/properties/code" - location: - description: The location where the transaction is intended to be fulfilled. - allOf: - - $ref: "#/components/schemas/Location" - action: - description: The Beckn protocol method being called by the sender and executed at the receiver. - type: string - version: - type: string - description: Version of transaction protocol being used by the sender. - bap_id: - description: Subscriber ID of the BAP - allOf: - - description: "A globally unique identifier of the platform, Typically it is the fully qualified domain name (FQDN) of the platform." - type: string - bap_uri: - description: Subscriber URL of the BAP for accepting callbacks from BPPs. - allOf: - - description: The callback URL of the Subscriber. This should necessarily contain the same domain name as set in `subscriber_id``. - type: string - format: uri - bpp_id: - description: Subscriber ID of the BPP - allOf: - - $ref: "#/components/schemas/Context/properties/bap_id/allOf/0" - bpp_uri: - description: Subscriber URL of the BPP for accepting calls from BAPs. - allOf: - - $ref: "#/components/schemas/Context/properties/bap_uri/allOf/0" - transaction_id: - description: "This is a unique value which persists across all API calls from `search` through `confirm`. This is done to indicate an active user session across multiple requests. The BPPs can use this value to push personalized recommendations, and dynamic offerings related to an ongoing transaction despite being unaware of the user active on the BAP." - type: string - format: uuid - message_id: - description: "This is a unique value which persists during a request / callback cycle. Since beckn protocol APIs are asynchronous, BAPs need a common value to match an incoming callback from a BPP to an earlier call. This value can also be used to ignore duplicate messages coming from the BPP. It is recommended to generate a fresh message_id for every new interaction. When sending unsolicited callbacks, BPPs must generate a new message_id." - type: string - format: uuid - timestamp: - description: Time of request generation in RFC3339 format - type: string - format: date-time - key: - description: The encryption public key of the sender - type: string - ttl: - description: The duration in ISO8601 format after timestamp for which this message holds valid - type: string - Country: - description: Describes a country - type: object - properties: - name: - type: string - description: Name of the country - code: - type: string - description: Country code as per ISO 3166-1 and ISO 3166-2 format - Credential: - description: Describes a credential of an entity - Person or Organization - type: object - properties: - id: - type: string - type: - type: string - default: VerifiableCredential - url: - description: URL of the credential - type: string - format: uri - Customer: - description: Describes a customer buying/availing a product or a service - type: object - properties: - person: - $ref: "#/components/schemas/Person" - contact: - $ref: "#/components/schemas/Contact" - DecimalValue: - description: Describes a numerical value in decimal form - type: string - pattern: "[+-]?([0-9]*[.])?[0-9]+" - Descriptor: - description: Physical description of something. - type: object - properties: - name: - type: string - code: - type: string - short_desc: - type: string - long_desc: - type: string - additional_desc: - type: object - properties: - url: - type: string - content_type: - type: string - enum: - - text/plain - - text/html - - application/json - media: - type: array - items: - $ref: "#/components/schemas/MediaFile" - images: - type: array - items: - $ref: "#/components/schemas/Image" - Domain: - description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." - type: object - properties: - name: - description: Name of the domain - type: string - code: - description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." - additional_info: - description: A url that contains addtional information about that domain. - allOf: - - $ref: "#/components/schemas/MediaFile" - Duration: - description: Describes duration as per ISO8601 format - type: string - Error: - description: "Describes an error object that is returned by a BAP, BPP or BG as a response or callback to an action by another network participant. This object is sent when any request received by a network participant is unacceptable. This object can be sent either during Ack or with the callback." - type: object - properties: - code: - type: string - description: 'Standard error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-005-ERROR-CODES-DRAFT-01.md of this repo"' - paths: - type: string - description: Path to json schema generating the error. Used only during json schema validation errors + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: BAP declares the customer's intent to buy/avail products or services + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search message: - type: string - description: Human readable message describing the error. Used mainly for logging. Not recommended to be shown to the user. - Fee: - description: A fee applied on a particular entity - type: object - properties: - percentage: - description: Percentage of a value - allOf: - - $ref: "#/components/schemas/DecimalValue" - amount: - description: A fixed value - allOf: - - $ref: "#/components/schemas/Price" - Form: - description: Describes a form - type: object - properties: - url: - description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." - type: string - format: uri - data: - description: The form submission data - type: object - additionalProperties: - type: string - mime_type: - description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. - type: string - enum: - - text/html - - application/xml - submission_id: - type: string - format: uuid - Fulfillment: - description: Describes how a an order will be rendered/fulfilled to the end-customer - type: object - properties: - id: - description: Unique reference ID to the fulfillment of an order - type: string - type: - description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." - type: string - rateable: - description: Whether the fulfillment can be rated or not - type: boolean - rating: - description: The rating value of the fulfullment service. - allOf: - - $ref: "#/components/schemas/Rating/properties/value" - state: - description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. - allOf: - - $ref: "#/components/schemas/FulfillmentState" - tracking: - type: boolean - description: Indicates whether the fulfillment allows tracking - default: false - customer: - description: The person that will ultimately receive the order - allOf: - - $ref: "#/components/schemas/Customer" - agent: - description: The agent that is currently handling the fulfillment of the order - allOf: - - $ref: "#/components/schemas/Agent" - contact: - $ref: "#/components/schemas/Contact" - vehicle: - $ref: "#/components/schemas/Vehicle" - stops: - description: The list of logical stops encountered during the fulfillment of an order. - type: array - items: - $ref: "#/components/schemas/Stop" - path: - description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. - type: string - tags: - type: array - items: - $ref: "#/components/schemas/TagGroup" - FulfillmentState: - description: Describes the state of fulfillment - type: object - properties: - descriptor: - $ref: "#/components/schemas/Descriptor" - updated_at: - type: string - format: date-time - updated_by: - type: string - description: ID of entity which changed the state - Gps: - description: Describes a GPS coordinate - type: string - pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' - Image: - description: Describes an image - type: object - properties: - url: - description: URL to the image. This can be a data url or an remote url - type: string - format: uri - size_type: - description: The size of the image. The network policy can define the default dimensions of each type - type: string - enum: - - xs - - sm - - md - - lg - - xl - - custom - width: - description: Width of the image in pixels - type: string - height: - description: Height of the image in pixels - type: string - Intent: - description: "The intent to buy or avail a product or a service. The BAP can declare the intent of the consumer containing
  • What they want (A product, service, offer)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" - type: object - properties: - descriptor: - description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." - allOf: - - $ref: "#/components/schemas/Descriptor" - provider: - description: The provider from which the customer wants to place to the order from - allOf: - - $ref: "#/components/schemas/Provider" - fulfillment: - description: Details on how the customer wants their order fulfilled - allOf: - - $ref: "#/components/schemas/Fulfillment" - location: - description: Location of the request that needs fulfillment. - allOf: - - $ref: "#/components/schemas/Location" - payment: - description: Details on how the customer wants to pay for the order - allOf: - - $ref: "#/components/schemas/Payment" - category: - description: Details on the item category - allOf: - - $ref: "#/components/schemas/Category" - offer: - description: details on the offer the customer wants to avail - allOf: - - $ref: "#/components/schemas/Offer" - item: - description: Details of the item that the consumer wants to order - allOf: - - $ref: "#/components/schemas/Item" - tags: - type: array - items: - $ref: "#/components/schemas/TagGroup" - ItemQuantity: - description: Describes the count or amount of an item - type: object - properties: - allocated: - description: This represents the exact quantity allocated for purchase of the item. - type: object - properties: - count: - type: integer - minimum: 0 - measure: - $ref: "#/components/schemas/Scalar" - available: - description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this - type: object - properties: - count: - type: integer - minimum: 0 - measure: - $ref: "#/components/schemas/Scalar" - maximum: - description: This represents the maximum quantity allowed for purchase of the item - type: object - properties: - count: - type: integer - minimum: 1 - measure: - $ref: "#/components/schemas/Scalar" - minimum: - description: This represents the minimum quantity allowed for purchase of the item - type: object - properties: - count: - type: integer - minimum: 0 - measure: - $ref: "#/components/schemas/Scalar" - selected: - description: This represents the quantity selected for purchase of the item - type: object - properties: - count: - type: integer - minimum: 0 - measure: - $ref: "#/components/schemas/Scalar" - unitized: - description: This represents the quantity available in a single unit of the item + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: BAP declares the customer's cart (or equivalent) created by selecting objects from the catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: type: object properties: - count: - type: integer - minimum: 1 - maximum: 1 - measure: - $ref: "#/components/schemas/Scalar" - Item: - description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." - type: object - properties: - id: - description: ID of the item. - type: string - parent_item_id: - description: "ID of the item, this item is a variant of" - allOf: - - $ref: "#/components/schemas/Item/properties/id" - parent_item_quantity: - description: The number of units of the parent item this item is a multiple of - allOf: - - $ref: "#/components/schemas/ItemQuantity" - descriptor: - description: Physical description of the item - allOf: - - $ref: "#/components/schemas/Descriptor" - creator: - description: The creator of this item - allOf: - - $ref: "#/components/schemas/Organization" - price: - description: "The price of this item, if it has intrinsic value" - allOf: - - $ref: "#/components/schemas/Price" - quantity: - description: The selling quantity of the item - allOf: - - $ref: "#/components/schemas/ItemQuantity" - category_ids: - description: Categories this item can be listed under - type: array - items: - allOf: - - $ref: "#/components/schemas/Category/properties/id" - fulfillment_ids: - description: Modes through which this item can be fulfilled - type: array - items: - allOf: - - $ref: "#/components/schemas/Fulfillment/properties/id" - location_ids: - description: Provider Locations this item is available in - type: array - items: + ack: allOf: - - $ref: "#/components/schemas/Location/properties/id" - payment_ids: - description: Payment modalities through which this item can be ordered - type: array - items: - allOf: - - $ref: "#/components/schemas/Payment/properties/id" - add_ons: - type: array - items: - $ref: "#/components/schemas/AddOn" - cancellation_terms: - description: Cancellation terms of this item - type: array - items: - $ref: "#/components/schemas/CancellationTerm" - refund_terms: - description: Refund terms of this item - type: array - items: - description: Refund term of an item or an order - type: object - properties: - fulfillment_state: - description: The state of fulfillment during which this term is applicable. - allOf: - - $ref: "#/components/schemas/State" - refund_eligible: - description: Indicates if cancellation will result in a refund - type: boolean - refund_within: - description: Time within which refund will be processed after successful cancellation. - allOf: - - $ref: "#/components/schemas/Time" - refund_amount: - $ref: "#/components/schemas/Price" - replacement_terms: - description: Terms that are applicable be met when this item is replaced - type: array - items: - $ref: "#/components/schemas/ReplacementTerm" - return_terms: - description: Terms that are applicable when this item is returned - type: array - items: - $ref: "#/components/schemas/ReturnTerm" - xinput: - description: Additional input required from the customer to purchase / avail this item - allOf: - - $ref: "#/components/schemas/XInput" - time: - description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. - allOf: - - $ref: "#/components/schemas/Time" - rateable: - description: Whether this item can be rated - type: boolean - rating: - description: The rating of the item - allOf: - - $ref: "#/components/schemas/Rating/properties/value" - matched: - description: Whether this item is an exact match of the request - type: boolean - related: - description: Whether this item is a related item to the exactly matched item - type: boolean - recommended: - description: Whether this item is a recommended item to a response - type: boolean - ttl: - description: Time to live in seconds for an instance of this schema - type: string - tags: - type: array - items: - $ref: "#/components/schemas/TagGroup" - Location: - description: The physical location of something - type: object - properties: - id: - type: string - descriptor: - $ref: "#/components/schemas/Descriptor" - map_url: - description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. - type: string - format: uri - gps: - description: The GPS co-ordinates of this location. - allOf: - - $ref: "#/components/schemas/Gps" - address: - description: The address of this location. - allOf: - - $ref: "#/components/schemas/Address" - city: - description: "The city this location is, or is located within" - allOf: - - $ref: "#/components/schemas/City" - district: - description: "The state this location is, or is located within" - type: string - state: - description: "The state this location is, or is located within" - allOf: - - $ref: "#/components/schemas/State" - country: - description: "The country this location is, or is located within" - allOf: - - $ref: "#/components/schemas/Country" - area_code: - type: string - circle: - $ref: "#/components/schemas/Circle" - polygon: - description: The boundary polygon of this location - type: string - 3dspace: - description: The three dimensional region describing this location - type: string - rating: - description: The rating of this location - allOf: - - $ref: "#/components/schemas/Rating/properties/value" - MediaFile: - description: This object contains a url to a media file. - type: object - properties: - mimetype: - description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" - type: string - url: - description: The URL of the file - type: string - format: uri - signature: - description: The digital signature of the file signed by the sender - type: string - dsa: - description: The signing algorithm used by the sender - type: string - Offer: - description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. - type: object - properties: - id: - type: string - descriptor: - $ref: "#/components/schemas/Descriptor" - location_ids: - type: array - items: - $ref: "#/components/schemas/Location/properties/id" - category_ids: - type: array - items: - $ref: "#/components/schemas/Category/properties/id" - item_ids: - type: array - items: - $ref: "#/components/schemas/Item/properties/id" - time: - $ref: "#/components/schemas/Time" - tags: - type: array - items: - $ref: "#/components/schemas/TagGroup" - Option: - description: Describes a selectable option - type: object - properties: - id: - type: string - descriptor: - $ref: "#/components/schemas/Descriptor" - Order: - description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. - type: object - properties: - id: - type: string - description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. - ref_order_ids: - description: A list of order IDs to link this order to previous orders. - type: array - items: - type: string - description: ID of a previous order - status: - description: Status of the order. Allowed values can be defined by the network policy - type: string - enum: - - ACTIVE - - COMPLETE - - CANCELLED - type: - description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." - type: string - default: DEFAULT - enum: - - DRAFT - - DEFAULT - provider: - description: Details of the provider whose catalog items have been selected. - allOf: - - $ref: "#/components/schemas/Provider" - items: - description: The items purchased / availed in this order - type: array - items: - $ref: "#/components/schemas/Item" - add_ons: - description: The add-ons purchased / availed in this order - type: array - items: - $ref: "#/components/schemas/AddOn" - offers: - description: The offers applied in this order - type: array - items: - $ref: "#/components/schemas/Offer" - billing: - description: The billing details of this order - allOf: - - $ref: "#/components/schemas/Billing" - fulfillments: - description: The fulfillments involved in completing this order - type: array - items: - $ref: "#/components/schemas/Fulfillment" - cancellation: - description: The cancellation details of this order - allOf: - - $ref: "#/components/schemas/Cancellation" - cancellation_terms: - description: Cancellation terms of this item - type: array - items: - $ref: "#/components/schemas/CancellationTerm" - refund_terms: - description: Refund terms of this item - type: array - items: - $ref: "#/components/schemas/Item/properties/refund_terms/items" - replacement_terms: - description: Replacement terms of this item - type: array - items: - $ref: "#/components/schemas/ReplacementTerm" - return_terms: - description: Return terms of this item - type: array - items: - $ref: "#/components/schemas/ReturnTerm" - quote: - description: The mutually agreed upon quotation for this order. - allOf: - - $ref: "#/components/schemas/Quotation" - payments: - description: The terms of settlement for this order - type: array - items: - $ref: "#/components/schemas/Payment" - created_at: - description: The date-time of creation of this order - type: string - format: date-time - updated_at: - description: The date-time of updated of this order - type: string - format: date-time - xinput: - description: Additional input required from the customer to confirm this order - allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + description: Updated order object + allOf: + - $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_search: + post: + tags: + - Beckn Application Platform (BAP) + - Beckn Gateway (BG) + description: BPP sends its catalog in response to a search request. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_select: + post: + tags: + - Beckn Application Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_init: + post: + tags: + - Beckn Application Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_confirm: + post: + tags: + - Beckn Application Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_track: + post: + tags: + - Beckn Application Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_cancel: + post: + tags: + - Beckn Application Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_update: + post: + tags: + - Beckn Application Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_status: + post: + tags: + - Beckn Application Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_rating: + post: + tags: + - Beckn Application Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: - $ref: "#/components/schemas/XInput" - tags: - type: array - items: - $ref: "#/components/schemas/TagGroup" - Organization: - description: An organization. Usually a recognized business entity. - type: object - properties: - descriptor: - $ref: "#/components/schemas/Descriptor" - address: - description: The postal address of the organization - allOf: - - $ref: "#/components/schemas/Address" - state: - description: The state where the organization's address is registered - allOf: - - $ref: "#/components/schemas/State" - city: - description: The city where the the organization's address is registered - allOf: - - $ref: "#/components/schemas/City" - contact: - $ref: "#/components/schemas/Contact" - Payment: - description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." - type: object - properties: - id: - description: ID of the payment term that can be referred at an item or an order level in a catalog - type: string - collected_by: - description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." - url: - type: string - description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." - format: uri - params: - type: object - properties: - transaction_id: - type: string - description: The reference transaction ID associated with a payment activity - amount: - type: string - currency: - type: string - bank_code: - type: string - bank_account_number: - type: string - virtual_payment_address: - type: string - source_bank_code: - type: string - source_bank_account_number: - type: string - source_virtual_payment_address: - type: string - type: - type: string - enum: - - PRE-ORDER - - PRE-FULFILLMENT - - ON-FULFILLMENT - - POST-FULFILLMENT - status: - type: string - enum: - - PAID - - NOT-PAID - time: - $ref: "#/components/schemas/Time" - tags: - type: array - items: - $ref: "#/components/schemas/TagGroup" - Person: - description: Describes a person as any individual - type: object - properties: - id: - type: string - description: Describes the identity of the person - url: - description: Profile url of the person - type: string - format: uri - name: - description: the name of the person - type: string - image: - $ref: "#/components/schemas/Image" - age: - description: Age of the person - allOf: - - $ref: "#/components/schemas/Duration" - dob: - description: Date of birth of the person - type: string - format: date - gender: - type: string - description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" - creds: - type: array - items: - $ref: "#/components/schemas/Credential" - languages: - type: array - items: - description: Describes a language known to the person. - type: object - properties: - code: - type: string - name: - type: string - skills: - type: array - items: - description: Describes a skill of the person. - type: object - properties: - code: - type: string - name: - type: string - tags: - type: array - items: - $ref: "#/components/schemas/TagGroup" - Price: - description: Describes the price of a product or service - type: object - properties: - currency: - type: string - value: - $ref: "#/components/schemas/DecimalValue" - estimated_value: - $ref: "#/components/schemas/DecimalValue" - computed_value: - $ref: "#/components/schemas/DecimalValue" - listed_value: - $ref: "#/components/schemas/DecimalValue" - offered_value: - $ref: "#/components/schemas/DecimalValue" - minimum_value: - $ref: "#/components/schemas/DecimalValue" - maximum_value: - $ref: "#/components/schemas/DecimalValue" - Provider: - description: Describes the catalog of a business. - type: object - properties: - id: - type: string - description: Id of the provider - descriptor: - $ref: "#/components/schemas/Descriptor" - category_id: - type: string - description: Category Id of the provider at the BPP-level catalog - rating: - $ref: "#/components/schemas/Rating/properties/value" - time: - $ref: "#/components/schemas/Time" - categories: - type: array - items: - $ref: "#/components/schemas/Category" - fulfillments: - type: array - items: - $ref: "#/components/schemas/Fulfillment" - payments: - type: array - items: - $ref: "#/components/schemas/Payment" - locations: - type: array - items: - $ref: "#/components/schemas/Location" - offers: - type: array - items: - $ref: "#/components/schemas/Offer" - items: - type: array - items: - $ref: "#/components/schemas/Item" - exp: - type: string - description: Time after which catalog has to be refreshed - format: date-time - rateable: - description: Whether this provider can be rated or not - type: boolean - ttl: - description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." - type: integer - minimum: -1 - tags: - type: array - items: - $ref: "#/components/schemas/TagGroup" - Quotation: - description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" - type: object - properties: - id: - description: ID of the quote. - type: string - format: uuid - price: - description: The total quoted price - allOf: - - $ref: "#/components/schemas/Price" - breakup: - description: the breakup of the total quoted price - type: array - items: - type: object - properties: - item: - $ref: "#/components/schemas/Item" - title: - type: string - price: - $ref: "#/components/schemas/Price" - ttl: - $ref: "#/components/schemas/Duration" - Rating: - description: Describes the rating of an entity - type: object - properties: - rating_category: - description: Category of the entity being rated - type: string - enum: - - Item - - Order - - Fulfillment - - Provider - - Agent - - Support - id: - description: Id of the object being rated - type: string - value: - description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." - type: string - Region: - description: Describes an arbitrary region of space. The network policy should contain a published list of supported regions by the network. - type: object - properties: - dimensions: - description: "The number of dimensions that are used to describe any point inside that region. The most common dimensionality of a region is 2, that represents an area on a map. There are regions on the map that can be approximated to one-dimensional regions like roads, railway lines, or shipping lines. 3 dimensional regions are rarer, but are gaining popularity as flying drones are being adopted for various fulfillment services." - type: string - enum: - - "1" - - "2" - - "3" - type: - description: "The type of region. This is used to specify the granularity of the region represented by this object. Various examples of two-dimensional region types are city, country, state, district, and so on. The network policy should contain a list of all possible region types supported by the network." - type: string - name: - type: string - description: Name of the region as specified on the map where that region exists. - code: - type: string - description: A standard code representing the region. This should be interpreted in the same way by all network participants. - boundary: - type: string - description: "A string representing the boundary of the region. One-dimensional regions are represented by polylines. Two-dimensional regions are represented by polygons, and three-dimensional regions can represented by polyhedra." - map_url: - type: string - description: The url to the map of the region. This can be a globally recognized map or the one specified by the network policy. - ReplacementTerm: - description: The replacement policy of an item or an order - type: object - properties: - fulfillment_state: - description: The state of fulfillment during which this term is applicable. - allOf: - - $ref: "#/components/schemas/State" - replace_within: - description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" - allOf: - - $ref: "#/components/schemas/Time" - external_ref: - $ref: "#/components/schemas/MediaFile" - ReturnTerm: - description: Describes the return policy of an item or an order - type: object - properties: - fulfillment_state: - description: The state of fulfillment during which this term IETF''s applicable. - allOf: - - $ref: "#/components/schemas/State" - return_eligible: - description: Indicates whether the item is eligible for return - type: boolean - return_time: - description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." - allOf: - - $ref: "#/components/schemas/Time" - return_location: - description: The location where the item or order must / will be returned to - allOf: - - $ref: "#/components/schemas/Location" - fulfillment_managed_by: - description: The entity that will perform the return - type: string - enum: - - CONSUMER - - PROVIDER - Scalar: - description: Describes a scalar - type: object - properties: - type: - type: string - enum: - - CONSTANT - - VARIABLE - value: - $ref: "#/components/schemas/DecimalValue" - estimated_value: - $ref: "#/components/schemas/DecimalValue" - computed_value: - $ref: "#/components/schemas/DecimalValue" - range: - type: object - properties: - min: - $ref: "#/components/schemas/DecimalValue" - max: - $ref: "#/components/schemas/DecimalValue" - unit: - type: string - Schedule: - description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" - type: object - properties: - frequency: - $ref: "#/components/schemas/Duration" - holidays: - type: array - items: - type: string - format: date-time - times: - type: array - items: - type: string - format: date-time - State: - description: A bounded geopolitical region of governance inside a country. - type: object - properties: - name: - type: string - description: Name of the state - code: - type: string - description: State code as per country or international standards - Stop: - description: A logical point in space and time during the fulfillment of an order. - type: object - properties: - id: - type: string - parent_stop_id: - type: string - location: - description: Location of the stop - allOf: - - $ref: "#/components/schemas/Location" - type: - description: The type of stop. Allowed values of this property can be defined by the network policy. - type: string - time: - description: Timings applicable at the stop. - allOf: - - $ref: "#/components/schemas/Time" - instructions: - description: Instructions that need to be followed at the stop - allOf: - - $ref: "#/components/schemas/Descriptor" - contact: - description: Contact details of the stop - allOf: - - $ref: "#/components/schemas/Contact" - person: - description: The details of the person present at the stop - allOf: - - $ref: "#/components/schemas/Person" - authorization: - $ref: "#/components/schemas/Authorization" - Support: - description: Details of customer support - type: object - properties: - ref_id: - type: string - callback_phone: - type: string - format: phone - phone: - type: string - format: phone - email: - type: string - format: email - url: - type: string - format: uri - Tag: - description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." - type: object - properties: - descriptor: - description: "Description of the Tag, can be used to store detailed information." - allOf: - - $ref: "#/components/schemas/Descriptor" - value: - description: The value of the tag. This set by the BPP and rendered as-is by the BAP. - type: string - display: - description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." - type: boolean - TagGroup: - description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" - type: object - properties: - display: - description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." - type: boolean - default: true - descriptor: - description: "Description of the TagGroup, can be used to store detailed information." - allOf: - - $ref: "#/components/schemas/Descriptor" - list: - description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." - type: array - items: - $ref: "#/components/schemas/Tag" - Time: - description: "Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations
This has properties like label, time stamp,duration,range, days, schedule" + error: + $ref: "#/components/schemas/Error" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_support: + post: + tags: + - Beckn Application Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: "Describes the acknowledgement sent in response to an API call. If the implementation uses HTTP/S, then Ack must be returned in the same session. Every API call to a BPP must be responded to with an Ack whether the BPP intends to respond with a callback or not. This has one property called `status` that indicates the status of the Acknowledgement." + type: object + properties: + status: + type: string + description: "The status of the acknowledgement. If the request passes the validation criteria of the BPP, then this is set to ACK. If a BPP responds with status = `ACK` to a request, it is required to respond with a callback. If the request fails the validation criteria, then this is set to NACK. Additionally, if a BPP does not intend to respond with a callback even after the request meets the validation criteria, it should set this value to `NACK`." + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: Describes an additional item offered as a value-addition to a product or service. This does not exist independently in a catalog and is always associated with an item. + type: object + properties: + id: + description: Provider-defined ID of the add-on + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes the direct performer, driver or executor that fulfills an order. It is usually a person. But in some rare cases, it could be a non-living entity like a drone, or a bot. Some examples of agents are Doctor in the healthcare sector, a driver in the mobility sector, or a delivery person in the logistics sector. This object can be set at any stage of the order lifecycle. This can be set at the discovery stage when the BPP wants to provide details on the agent fulfilling the order, like in healthcare, where the doctor's name appears during search. This object can also used to search for a particular person that the customer wants fulfilling an order. Sometimes, this object gets instantiated after the order is confirmed, like in the case of on-demand taxis, where the driver is assigned after the user confirms the ride." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: "Describes the billing details of an entity.
This has properties like name,organization,address,email,phone,time,tax_number, created_at,updated_at" + type: object + properties: + name: + description: Name of the billable entity + type: string + organization: + description: Details of the organization being billed. + allOf: + - $ref: "#/components/schemas/Organization" + address: + description: The address of the billable entity + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address where the bill is sent to + type: string + format: email + phone: + description: Phone number of the billable entity + type: string + time: + description: Details regarding the billing period + allOf: + - $ref: "#/components/schemas/Time" + tax_id: + description: ID of the billable entity as recognized by the taxation authority + type: string + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the buyer + type: string + format: date-time + cancelled_by: + type: string + enum: + - CONSUMER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + CancellationTerm: + description: Describes the cancellation terms of an item or an order. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes the products or services offered by a BPP. This is typically sent as the response to a search intent from a BAP. The payment terms, offers and terms of fulfillment supported by the BPP can also be included here. The BPP can show hierarchical nature of products/services in its catalog using the parent_category_id in categories. The BPP can also send a ttl (time to live) in the context which is the duration for which a BAP can cache the catalog and use the cached catalog.
This has properties like bbp/descriptor,bbp/categories,bbp/fulfillments,bbp/payments,bbp/offers,bbp/providers and exp
This is used in the following situations.
  • This is typically used in the discovery stage when the BPP sends the details of the products and services it offers as response to a search intent from the BAP.
" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: A label under which a collection of items can be grouped. + type: object + properties: + id: + description: ID of the category + type: string + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular region of a specified radius centered at a specified GPS coordinate. + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + description: Name of the city + type: string + code: + description: City code + type: string + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: "Every API call in beckn protocol has a context. It provides a high-level overview to the receiver about the nature of the intended transaction. Typically, it is the BAP that sets the transaction context based on the consumer's location and action on their UI. But sometimes, during unsolicited callbacks, the BPP also sets the transaction context but it is usually the same as the context of a previous full-cycle, request-callback interaction between the BAP and the BPP. The context object contains four types of fields.
  1. Demographic information about the transaction using fields like `domain`, `country`, and `region`.
  2. Addressing details like the sending and receiving platform's ID and API URL.
  3. Interoperability information like the protocol version that implemented by the sender and,
  4. Transaction details like the method being called at the receiver's endpoint, the transaction_id that represents an end-to-end user session at the BAP, a message ID to pair requests with callbacks, a timestamp to capture sending times, a ttl to specifiy the validity of the request, and a key to encrypt information if necessary.
This object must be passed in every interaction between a BAP and a BPP. In HTTP/S implementations, it is not necessary to send the context during the synchronous response. However, in asynchronous protocols, the context must be sent during all interactions," + type: object + properties: + domain: + description: Domain code that is relevant to this transaction context + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + description: The Beckn protocol method being called by the sender and executed at the receiver. + type: string + version: + type: string + description: Version of transaction protocol being used by the sender. + bap_id: + description: Subscriber ID of the BAP + allOf: + - description: "A globally unique identifier of the platform, Typically it is the fully qualified domain name (FQDN) of the platform." + type: string + bap_uri: + description: Subscriber URL of the BAP for accepting callbacks from BPPs. + allOf: + - description: The callback URL of the Subscriber. This should necessarily contain the same domain name as set in `subscriber_id``. + type: string + format: uri + bpp_id: + description: Subscriber ID of the BPP + allOf: + - $ref: "#/components/schemas/Context/properties/bap_id/allOf/0" + bpp_uri: + description: Subscriber URL of the BPP for accepting calls from BAPs. + allOf: + - $ref: "#/components/schemas/Context/properties/bap_uri/allOf/0" + transaction_id: + description: "This is a unique value which persists across all API calls from `search` through `confirm`. This is done to indicate an active user session across multiple requests. The BPPs can use this value to push personalized recommendations, and dynamic offerings related to an ongoing transaction despite being unaware of the user active on the BAP." + type: string + format: uuid + message_id: + description: "This is a unique value which persists during a request / callback cycle. Since beckn protocol APIs are asynchronous, BAPs need a common value to match an incoming callback from a BPP to an earlier call. This value can also be used to ignore duplicate messages coming from the BPP. It is recommended to generate a fresh message_id for every new interaction. When sending unsolicited callbacks, BPPs must generate a new message_id." + type: string + format: uuid + timestamp: + description: Time of request generation in RFC3339 format + type: string + format: date-time + key: + description: The encryption public key of the sender + type: string + ttl: + description: The duration in ISO8601 format after timestamp for which this message holds valid + type: string + Country: + description: Describes a country + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + DecimalValue: + description: Describes a numerical value in decimal form + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: "Describes an error object that is returned by a BAP, BPP or BG as a response or callback to an action by another network participant. This object is sent when any request received by a network participant is unacceptable. This object can be sent either during Ack or with the callback." + type: object + properties: + code: + type: string + description: 'Standard error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-005-ERROR-CODES-DRAFT-01.md of this repo"' + paths: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error. Used mainly for logging. Not recommended to be shown to the user. + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to buy or avail a product or a service. The BAP can declare the intent of the consumer containing
  • What they want (A product, service, offer)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order type: object properties: - label: - type: string - timestamp: - type: string - format: date-time - duration: - $ref: "#/components/schemas/Duration" - range: - type: object - properties: - start: - type: string - format: date-time - end: - type: string - format: date-time - days: - type: string - description: comma separated values representing days of the week - schedule: - $ref: "#/components/schemas/Schedule" - Tracking: - description: Contains tracking information that can be used by the BAP to track the fulfillment of an order in real-time. which is useful for knowing the location of time sensitive deliveries. + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. type: object properties: - id: - description: A unique tracking reference number - type: string - url: - description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." - type: string - format: uri - location: - description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." - allOf: - - $ref: "#/components/schemas/Location" - status: - description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." - type: string - enum: - - active - - inactive - Vehicle: - description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. type: object properties: - category: - type: string - capacity: - type: integer - make: - type: string - model: - type: string - size: - type: string - variant: - type: string - color: - type: string - energy_type: - type: string - registration: - type: string - wheels_count: - type: string - cargo_volumne: - type: string - wheelchair_access: - type: string - code: - type: string - emission_standard: - type: string - XInput: - description: "Contains any additional or extended inputs required to confirm an order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, to confirm a flight ticket, the airline requires details of the passengers along with information on baggage, identity, in addition to the class of ticket. Similarly, a logistics company may require details on the nature of shipment in order to confirm the shipping. A recruiting firm may require additional details on the applicant in order to confirm a job application. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of a business. + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: type: object properties: - form: - $ref: "#/components/schemas/Form" - required: - description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. - type: boolean + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + type: string + Region: + description: Describes an arbitrary region of space. The network policy should contain a published list of supported regions by the network. + type: object + properties: + dimensions: + description: "The number of dimensions that are used to describe any point inside that region. The most common dimensionality of a region is 2, that represents an area on a map. There are regions on the map that can be approximated to one-dimensional regions like roads, railway lines, or shipping lines. 3 dimensional regions are rarer, but are gaining popularity as flying drones are being adopted for various fulfillment services." + type: string + enum: + - "1" + - "2" + - "3" + type: + description: "The type of region. This is used to specify the granularity of the region represented by this object. Various examples of two-dimensional region types are city, country, state, district, and so on. The network policy should contain a list of all possible region types supported by the network." + type: string + name: + type: string + description: Name of the region as specified on the map where that region exists. + code: + type: string + description: A standard code representing the region. This should be interpreted in the same way by all network participants. + boundary: + type: string + description: "A string representing the boundary of the region. One-dimensional regions are represented by polylines. Two-dimensional regions are represented by polygons, and three-dimensional regions can represented by polyhedra." + map_url: + type: string + description: The url to the map of the region. This can be a globally recognized map or the one specified by the network policy. + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: "Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations
This has properties like label, time stamp,duration,range, days, schedule" + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Contains tracking information that can be used by the BAP to track the fulfillment of an order in real-time. which is useful for knowing the location of time sensitive deliveries. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required to confirm an order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, to confirm a flight ticket, the airline requires details of the passengers along with information on baggage, identity, in addition to the class of ticket. Similarly, a logistics company may require details on the nature of shipment in order to confirm the shipping. A recruiting firm may require additional details on the applicant in order to confirm a job application. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean From fd035f48a9fe8cb27abba3fce6be2292dce43d17 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu <154209057+vbabuEM@users.noreply.github.com> Date: Wed, 27 Mar 2024 13:39:45 +0530 Subject: [PATCH 019/102] Update README.md --- README.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.md b/README.md index b2677ad..2463460 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,20 @@ ONIX - Open Network In A Box, is a project designed to effortlessly set up and m In the install folder, you find a tool that helps install a Beckn network. This tool serves as a valuable resource for developers and network participants eager to explore BECKN protocols or join open networks supported by the BECKN protocol. By simplifying the installation process, ONIX streamlines the onboarding experience. For more details, refer to [release notes](./install/RELEASE.md) and [start with Beckn](./install/START_BECKN.md) Experience the convenience and efficiency of ONIX as you embark on your journey with BECKN protocols and open networks. + +## Note on mandatory Layer 2 Config (Important) +This note will eventually be moved to a proper place in the documentation. It has been put here to alert people who install it in the meantime. +Beckn-Onix mandates availability of Layer 2 Config for a particular domain before any transactions can be conducted on it. If the layer 2 config is not present, on either the BAP or the BPP, the following error is returned back to the caller. "Config error : Layer 2 config not found." + +Usually the network facilitators will host the Layer 2 config and provide a way to access it. Currently we have a small script (layer2/download_layer_2_config_bap.sh and layer2/download_layer_2_config_bpp.sh) that can download the layer 2 config from a fixed location and insert it into the docker container that runs the Protocol Server Client. + +If you have the Layer 2 config file with you and not hosted, you can use the following procedure to update it manually. In case you do not have layer 2 config file with you, as developer machine workaround, you can copy the core_version.yaml(e.g. core_1.1.0.yaml) and rename it as the layer 2 config for a domain (e.g. for a domain named retail for core version 1.1.0, retail_1.1.0.yaml). This is strictly not recommended for production networks. + +Process to manually update layer 2 config. +``` +docker cp "$FILENAME" "$CONTAINER_NAME":"$CONTAINER_PATH/$FILENAME" + +# example +docker cp retail_1.1.0.yaml bap-client:/usr/src/app/schemas/retail_1.1.0.yaml + +``` From e34d96cc5d9cd3411d2ee4cfd1a813c891e585f1 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu <154209057+vbabuEM@users.noreply.github.com> Date: Wed, 27 Mar 2024 13:40:30 +0530 Subject: [PATCH 020/102] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2463460..5786568 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ In the install folder, you find a tool that helps install a Beckn network. This Experience the convenience and efficiency of ONIX as you embark on your journey with BECKN protocols and open networks. ## Note on mandatory Layer 2 Config (Important) -This note will eventually be moved to a proper place in the documentation. It has been put here to alert people who install it in the meantime. +This note will eventually be moved to a proper place in the documentation. It has been put here to alert people who run Beckn ONIX in the meantime. Beckn-Onix mandates availability of Layer 2 Config for a particular domain before any transactions can be conducted on it. If the layer 2 config is not present, on either the BAP or the BPP, the following error is returned back to the caller. "Config error : Layer 2 config not found." Usually the network facilitators will host the Layer 2 config and provide a way to access it. Currently we have a small script (layer2/download_layer_2_config_bap.sh and layer2/download_layer_2_config_bpp.sh) that can download the layer 2 config from a fixed location and insert it into the docker container that runs the Protocol Server Client. From 725020d9b0c04bdd2ab68f90ad153da3bc042ae8 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu <154209057+vbabuEM@users.noreply.github.com> Date: Wed, 27 Mar 2024 13:42:27 +0530 Subject: [PATCH 021/102] Update README.md --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5786568..932ea71 100644 --- a/README.md +++ b/README.md @@ -20,5 +20,9 @@ docker cp "$FILENAME" "$CONTAINER_NAME":"$CONTAINER_PATH/$FILENAME" # example docker cp retail_1.1.0.yaml bap-client:/usr/src/app/schemas/retail_1.1.0.yaml +docker cp retail_1.1.0.yaml bap-network:/usr/src/app/schemas/retail_1.1.0.yaml + +docker cp retail_1.1.0.yaml bpp-client:/usr/src/app/schemas/retail_1.1.0.yaml +docker cp retail_1.1.0.yaml bpp-netork:/usr/src/app/schemas/retail_1.1.0.yaml ``` From 9dbf54767d78cd3c5086c151e9fd836a1614be3e Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 27 Mar 2024 18:56:05 +0530 Subject: [PATCH 022/102] Install bpp without sandbox --- install/beckn-onix.sh | 94 ++++++++----------------------------------- 1 file changed, 16 insertions(+), 78 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index b6b6ca0..79a063b 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -119,37 +119,6 @@ install_bap_protocol_server(){ echo "Protocol server BAP installation successful" } -# Function to install BPP Protocol Server with BPP Sandbox -install_bpp_protocol_server_with_sandbox(){ - start_support_services - echo "${GREEN}................Installing Sandbox................${NC}" - start_container "sandbox-api" - sleep 5 - echo "Sandbox installation successful" - - echo "${GREEN}................Installing Webhook................${NC}" - start_container "sandbox-webhook" - sleep - echo "Webhook installation successful" - - echo "${GREEN}................Installing Protocol Server for BPP................${NC}" - - if [[ $1 ]];then - registry_url=$1 - bpp_subscriber_id=$2 - bpp_subscriber_key_id=$3 - bpp_subscriber_url=$4 - bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url - else - bash scripts/update_bpp_config.sh - fi - - sleep 10 - start_container "bpp-client" - start_container "bpp-network" - sleep 10 - echo "Protocol server BPP installation successful" -} # Function to install BPP Protocol Server without Sandbox install_bpp_protocol_server(){ @@ -179,15 +148,14 @@ install_bpp_protocol_server(){ # MAIN SCRIPT STARTS HERE #!/bin/bash -# echo "$(ls /home/ravi/onix)" -echo "Welcome to Onix!" +echo "Welcome to Beckn Onix!" if [ -f ./onix_ascii_art.txt ]; then cat ./onix_ascii_art.txt else - echo "[Display ONIX ASCII Art]" + echo "[Display Beckn ONIX ASCII Art]" fi -echo "ONIX is a platform that helps you quickly launch and configure beckn-enabled networks." +echo "Beckn ONIX is a platform that helps you quickly launch and configure beckn-enabled networks." echo -e "\nWhat would you like to do?\n1. Join an existing network\n2. Create new production network\n3. Set up a network on your local machine\n4. Merge multiple networks\n5. Configure Existing Network\n(Press Ctrl+C to exit)" read -p "Enter your choice: " choice @@ -211,6 +179,8 @@ completeSetup() { platform=$1 config_url=$2 # Passing this as an argument, though it could be optional or ignored by some setups + public_address="https://" + echo "Proceeding with the setup for $platform..." if [ -n "$config_url" ]; then echo "Using network configuration from: $config_url" @@ -226,6 +196,7 @@ completeSetup() { else new_registry_url=$registry_url fi + public_address=$registry_url install_package install_registry $new_registry_url ;; @@ -243,6 +214,7 @@ completeSetup() { gateway_url=${gateway_url%/} fi + public_address=$gateway_url install_package install_gateway $new_registry_url $gateway_url ;; @@ -254,6 +226,7 @@ completeSetup() { read -p "Enter BAP Subscriber URL: " bap_subscriber_url read -p "Enter the registry_url(e.g. https://registry.becknprotocol.io/subscribers): " registry_url bap_subscriber_key_id=$bap_subscriber_id-key + public_address=$bap_subscriber_url install_package install_bap_protocol_server $registry_url $bap_subscriber_id $bap_subscriber_key_id $bap_subscriber_url ;; @@ -263,9 +236,12 @@ completeSetup() { read -p "Enter BPP Subscriber ID: " bpp_subscriber_id read -p "Enter BPP Subscriber URL: " bpp_subscriber_url read -p "Enter the registry_url(e.g. https://registry.becknprotocol.io/subscribers): " registry_url + read -p "Enter Webhook URL: " webhook_url + bpp_subscriber_key_id=$bpp_subscriber_id-key + public_address=$bpp_subscriber_url install_package - install_bpp_protocol_server_with_sandbox $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url + install_bpp_protocol_server $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url ;; *) echo "Invalid platform selected." @@ -275,7 +251,7 @@ completeSetup() { echo "[Installation Logs]" echo -e "${boldGreen}Your $platform setup is complete.${reset}" - echo -e "${boldGreen}You can access your $platform at http://${reset}" + echo -e "${boldGreen}You can access your $platform at $public_address ${reset}" # Key generation and subscription logic follows here } @@ -301,44 +277,6 @@ else exit 1 fi -echo "Process complete. Thank you for using Onix!" - - - -# text=" -# The following components will be installed - -# 1. Registry -# 2. Gateway -# 3. Sandbox -# 4. Sandbox Webhook -# 5. Protocol Server for BAP -# 6. Protocol Server for BPP -# " - -# # Main script starts here -# bash scripts/banner.sh -# echo "Welcome to ONIX" -# echo "$text" - -# read -p "${GREEN}Do you want to install all the components on the local system? (Y/n): ${NC}" install_all - -# if [[ $install_all =~ ^[Yy]$ ]]; then -# # Install and bring up everything -# install_package -# install_registry -# install_gateway -# start_support_services -# install_bap_protocol_server -# install_bpp_protocol_server_with_sandbox -# else -# # User selects specific components to install -# echo "Please select the components that you want to install" -# echo "1. Beckn Gateway & Beckn Registry" -# echo "2. BAP Protocol Server" -# echo "3. BPP Protocol Server with BPP Sandbox" -# echo "4. BPP Protocol Server" -# echo "5. Generic Client Layer" -# echo "6. Exit" - -# read -p "Enter your choice (1-6): " user_choice +echo "Process complete. Thank you for using Beckn Onix!" + + From f91a93899c0103267363f6bb517f661d94e7193c Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Sat, 30 Mar 2024 06:38:13 +0530 Subject: [PATCH 023/102] Add user guide and walkthrough demo --- .gitignore | 1 + ...IX Demo Collection.postman_collection.json | 197 +++++++ docs/demo_walkthrough.md | 466 ++++++++++++++++ docs/energy_demo.md | 31 ++ docs/images/sample_deployment.png | Bin 0 -> 51219 bytes docs/sample_nginx_configurations.md | 516 ++++++++++++++++++ docs/user_guide.md | 219 ++++++++ 7 files changed, 1430 insertions(+) create mode 100644 artifacts/ONIX Demo Collection.postman_collection.json create mode 100644 docs/demo_walkthrough.md create mode 100644 docs/energy_demo.md create mode 100644 docs/images/sample_deployment.png create mode 100644 docs/sample_nginx_configurations.md create mode 100644 docs/user_guide.md diff --git a/.gitignore b/.gitignore index c6bba59..b546895 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ # Logs +.DS_Store logs *.log npm-debug.log* diff --git a/artifacts/ONIX Demo Collection.postman_collection.json b/artifacts/ONIX Demo Collection.postman_collection.json new file mode 100644 index 0000000..46c8f30 --- /dev/null +++ b/artifacts/ONIX Demo Collection.postman_collection.json @@ -0,0 +1,197 @@ +{ + "info": { + "_postman_id": "303038a6-0aee-4094-b5c3-45fef219cdef", + "name": "ONIX Demo Collection", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json", + "_exporter_id": "31540449" + }, + "item": [ + { + "name": "UEI", + "item": [ + { + "name": "Search", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"uei:charging\",\n \"location\": {\n \"city\": {\n \"name\": \"Bangalore\",\n \"code\": \"std:080\"\n },\n \"country\": {\n \"name\": \"India\",\n \"code\": \"IND\"\n }\n },\n \"action\": \"search\",\n \"version\": \"1.1.0\",\n \"transaction_id\": \"fc24f1e9-6d01-44bf-888c-d5884ca0f66f\",\n \"message_id\": \"{{$randomUUID}}\",\n \"timestamp\": \"2023-10-09T04:46:28.012Z\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\"\n },\n \"message\": {\n \"intent\": {\n \"location\": {\n \"circle\": {\n \"gps\": \"12.423423,77.325647\",\n \"radius\": {\n \"type\": \"CONSTANT\",\n \"value\": \"5\",\n \"unit\": \"km\"\n }\n }\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/search", + "host": [ + "{{base_url}}" + ], + "path": [ + "search" + ] + } + }, + "response": [] + }, + { + "name": "Select", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"{{uei}}\",\n \"location\": {\n \"city\": {\n \"name\": \"Bangalore\",\n \"code\": \"std:080\"\n },\n \"country\": {\n \"name\": \"India\",\n \"code\": \"IND\"\n }\n },\n \"action\": \"select\",\n \"version\": \"1.1.0\",\n \"transaction_id\": \"fc24f1e9-6d01-44bf-888c-d5884ca0f66f\",\n \"message_id\": \"{{$randomUUID}}\",\n \"timestamp\": \"2023-10-09T04:46:28.012Z\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\"\n },\n \"message\": {\n \"order\": {\n \"provider\": {\n \"id\": \"1\"\n },\n \"items\": [\n {\n \"id\": \"1\"\n }\n ]\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/select", + "host": [ + "{{base_url}}" + ], + "path": [ + "select" + ] + } + }, + "response": [] + }, + { + "name": "Init", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"{{uei}}\",\n \"location\": {\n \"city\": {\n \"name\": \"Bangalore\",\n \"code\": \"std:080\"\n },\n \"country\": {\n \"name\": \"India\",\n \"code\": \"IND\"\n }\n },\n \"action\": \"init\",\n \"version\": \"1.1.0\",\n \"transaction_id\": \"fc24f1e9-6d01-44bf-888c-d5884ca0f66f\",\n \"message_id\": \"{{$randomUUID}}\",\n \"timestamp\": \"2023-10-09T04:46:28.012Z\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\"\n },\n \"message\": {\n \"order\": {\n \"provider\": {\n \"id\": \"1\"\n },\n \"items\": [\n {\n \"id\": \"1\"\n }\n ],\n \"billing\": {\n \"name\": \"Alice Smith\",\n \"address\": \"Apt 303, Maple Towers, Richmond Road, 560001\",\n \"state\": {\n \"name\": \"Jurong East\"\n },\n \"city\": {\n \"name\": \"Jurong East\"\n },\n \"email\": \"alice.smith@example.com\",\n \"phone\": \"9886098860\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/init", + "host": [ + "{{base_url}}" + ], + "path": [ + "init" + ] + } + }, + "response": [] + }, + { + "name": "Confirm", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"{{uei}}\",\n \"location\": {\n \"city\": {\n \"name\": \"Bangalore\",\n \"code\": \"std:080\"\n },\n \"country\": {\n \"name\": \"India\",\n \"code\": \"IND\"\n }\n },\n \"action\": \"confirm\",\n \"version\": \"1.1.0\",\n \"transaction_id\": \"fc24f1e9-6d01-44bf-888c-d5884ca0f66f\",\n \"message_id\": \"{{$randomUUID}}\",\n \"timestamp\": \"2023-10-09T04:46:28.012Z\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\"\n },\n \"message\": {\n \"order\": {\n \"items\": [\n {\n \"id\": \"1\"\n }\n ],\n \"fulfillments\": [\n {\n \"id\": \"1\",\n \"customer\": {\n \"contact\": {\n \"email\": \"fox.judie61234@abc.org\",\n \"phone\": \"+91-9999999999\"\n },\n \"person\": {\n \"name\": \"Judie Fox6\"\n }\n }\n }\n ],\n \"billing\": {\n \"name\": \"Industry buyer\",\n \"address\": \"B005 aspire heights, Jurong East, SGP, 680230\",\n \"state\": {\n \"name\": \"Jurong East\"\n },\n \"city\": {\n \"name\": \"Jurong East\"\n },\n \"email\": \"nobody@nomail.com\",\n \"phone\": \"9886098860\"\n }\n }\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/confirm", + "host": [ + "{{base_url}}" + ], + "path": [ + "confirm" + ] + } + }, + "response": [] + }, + { + "name": "Status", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"context\": {\n \"domain\": \"{{uei}}\",\n \"location\": {\n \"city\": {\n \"name\": \"Bangalore\",\n \"code\": \"std:080\"\n },\n \"country\": {\n \"name\": \"India\",\n \"code\": \"IND\"\n }\n },\n \"action\": \"status\",\n \"version\": \"1.1.0\",\n \"transaction_id\": \"fc24f1e9-6d01-44bf-888c-d5884ca0f66f\",\n \"message_id\": \"{{$randomUUID}}\",\n \"timestamp\": \"2023-10-09T04:46:28.012Z\",\n \"bpp_id\": \"{{bpp_id}}\",\n \"bpp_uri\": \"{{bpp_uri}}\",\n \"bap_id\": \"{{bap_id}}\",\n \"bap_uri\": \"{{bap_uri}}\"\n },\n \"message\": {\n \"order_id\": \"1\"\n }\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "{{base_url}}/status", + "host": [ + "{{base_url}}" + ], + "path": [ + "status" + ] + } + }, + "response": [] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "bpp_id", + "value": "onix-bpp.becknprotocol.io", + "type": "string" + }, + { + "key": "bpp_uri", + "value": "https://onix-bpp.becknprotocol.io", + "type": "string" + }, + { + "key": "bap_id", + "value": "onix-bap.becknprotocol.io", + "type": "string" + }, + { + "key": "bap_uri", + "value": "https://onix-bap.becknprotocol.io", + "type": "string" + }, + { + "key": "core_version", + "value": "1.1.0", + "type": "string" + }, + { + "key": "base_url", + "value": "https://onix-bap-client.becknprotocol.io", + "type": "string" + } + ] +} \ No newline at end of file diff --git a/docs/demo_walkthrough.md b/docs/demo_walkthrough.md new file mode 100644 index 0000000..e6f261e --- /dev/null +++ b/docs/demo_walkthrough.md @@ -0,0 +1,466 @@ +# Steps to setup a new Beckn network and conduct retail and energy transactions on it + +## Introduction + +This document describes setting up of a [Beckn network](https://becknprotocol.io/) with Beckn ONIX and conducting transactions in a couple of domains (retail and energy). The general flow will involve the following steps: + +- [Setup the prerequisites](#overall-prerequisites) +- [Create a new network and install the registry](#create-a-new-network-and-install-the-registry) +- [Install a gateway for the network](#install-a-gateway-for-the-network) +- [Install a Beckn Adaptor for the BAP](#install-a-beckn-adaptor-for-the-bap) +- [Install a Beckn Adaptor for the BPP](#install-a-beckn-adaptor-for-the-bpp) +- [Change the status of the BAP and BPP on the registry as Subscribed](#change-the-status-of-the-bap-and-bpp-on-registry-to-subscribed) +- [Update BAP and BPP with the layer 2 configuration files for the domains we are interested in](#update-bap-and-bpp-with-the-layer-2-configuration-files-for-the-domains-we-are-interested-in) +- [Conduct successful transactions on the network](#conduct-successful-transactions-on-the-network) + +For the sake of illustration, all the urls are shown as subdomains of becknprotocol.io. These will not be available for you to configure on your network. When you are installing on your network, replace them with your own domain name. For example when the instruction below says "https://onix-registry.becknprotocol.io", if you own a domain "example.org", then what you enter will be "https://onix-registry.example.org". Of course you can give a different subdomain than `onix-registry`. However you should be consistent in using the same URL wherever registry url is required. + +Some of the outputs listed below might be different when you run the script for the first time. The output depends on whether the required docker containers are present in the machine or not. + +Note: Due to a [known issue](https://github.com/beckn/beckn-onix/issues/11), on certain machines, when the script is run for the first time, it errors out complaining about permission error in accessing docker daemon. Till this issue is fixed, the work around is to exit the terminal and restart the installation in a new terminal. + +Please refer to the [Beckn Onix User Guide](./user_guide.md) for detailed explanation of the below steps. + +## Sample deployment diagram + +The following diagram shows a conceptual view of a multi-node Bekn network that we will be setting up. The urls shown here are the same as those used in the examples. + +![Typical deployment](./images/sample_deployment.png) + +## Overall prerequisites + +- Setup the following subdomains at the registrar. Refer to [registering or adding domain or subdomain section](./user_guide.md/#appendix-a---registering-or-adding-domain-or-subdomains) + + - https://onix-registry.becknprotocol.io - point to machine with registry + - https://onix-gateway.becknprotocol.io - point to machine with gateway + - https://onix-bap-client.becknprotocol.io - point to machine with BAP + - https://onix-bap.becknprotocol.io - point to machine with BAP + - https://onix-bpp-client.becknprotocol.io - point to machine with BPP + - https://onix-bpp.becknprotocol.io - point to machine with BPP + +- Configure the reverse proxy to have the right ssl certificate installed for all the addresses above. Refer to [configuring ssl certificates on in reverse proxy](./user_guide.md/#ssl-certificates-configured-in-reverse-proxy) for more details +- Configure the reverse proxy with proxy_pass to configure the following routes. Refer to [configuring reverse proxy using proxy_pass](./user_guide.md/#configuring-nginx-reverse-proxy-using-proxy-pass) for details. + + - https://onix-registry.becknprotocol.io to port 3030 on the machine + - https://onix-gateway.becknprotocol.io to port 4030 on the machine + - https://onix-bap-client.becknprotocol.io to port 5001 on the machine + - https://onix-bap.becknprotocol.io to port 5002 on the machine + - https://onix-bpp-client.becknprotocol.io to port 6001 on the machine + - https://onix-bpp.becknprotocol.io to port 6002 on the machine + +- This guide assumes you have a marketplace or a headless store and want to set it up to work with the Beckn network. It is still useful for people who are developing the buyer side software and want to set it up with the network. In such cases a [sandbox](https://github.com/beckn/beckn-sandbox) might be required to mimic a marketplace or a headless shop. + +## Create a new network and install the registry + +- ssh into the virtual server that will hold the registry, clone the repo, change into the install folder and run the beckn-onix.sh script. + +``` +git clone https://github.com/beckn/beckn-onix.git +cd beckn-onix/install +./beckn-onix.sh +``` + +- In the prompt that comes up, choose setting up a new network. + +``` +Beckn ONIX is a platform that helps you quickly launch and configure beckn-enabled networks. + +What would you like to do? +1. Join an existing network +2. Create new production network +3. Set up a network on your local machine +4. Merge multiple networks +5. Configure Existing Network +(Press Ctrl+C to exit) +Enter your choice: 2 + +``` + +- Further choose Registry as the platform you want to install + +``` +Which platform would you like to set up? +1. Registry +2. Gateway +3. BAP +4. BPP +Enter your choice: 1 +``` + +- Skip the option to apply network configuration + +``` +Proceeding with the setup for Registry... +Please provide the network-specific configuration URL. +Paste the URL of the network configuration here (or press Enter to skip): +``` + +- Input the host name where the registry will reside as https://onix-registry.becknprotocol.io + +``` +No network configuration URL provided, proceeding without it. + +Enter publicly accessible registry URL: https://onix-registry.becknprotocol.io +``` + +- The installation will complete to indicate that the registry has been installed. + +``` +................Installing required packages................ +Docker Bash completion is already installed. +docker-compose is already installed. +Package Installation is done +onix-registry.becknprotocol.io +................Installing Registry service................ +WARN[0000] /home/ec2-user/beckn-onix/install/docker-compose-v2.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container registry Started 0.5s +Registry installation successful +[Installation Logs] +Your Registry setup is complete. +You can access your Registry at https://onix-registry.becknprotocol.io +Process complete. Thank you for using Beckn Onix! +``` + +## Install a gateway for the network + +Please refer to the [Setting up a gateway](./user_guide.md/#setting-up-a-gateway) section of the user guide for the prerequisites and additional information. + +- On the virtual server that will hold the gateway, clone the repo + +``` +git clone https://github.com/beckn/beckn-onix.git + +``` + +- Due to a [known issue](https://github.com/beckn/beckn-onix/issues/8) with the new version of gateway, we need to do the following. This will be fixed by the project very soon and this step will not be required then. Open `beckn-onix/install/gateway_data/config/networks/onix.json` in an editor and change its contents to the following + +``` +{ + "core_version" : "1.1.0", + "registry_id": "onix-registry.becknprotocol.io..LREG", + "search_provider_id" : "onix-gateway.becknprotocol.io", + "self_registration_supported": true, + "subscription_needed_post_registration" : true, + "base_url": "https://onix-registry.becknprotocol.io", + "registry_url" : "https://onix-registry.becknprotocol.io/subscribers", + "extension_package": "in.succinct.beckn.boc", + "wild_card" : "" +} +``` + +- Change into the install folder and run the beckn-onix.sh script. + +``` +cd beckn-onix/install +./beckn-onix.sh + +``` + +- In the prompt that comes up, choose joining an existing network. + +``` +Beckn ONIX is a platform that helps you quickly launch and configure beckn-enabled networks. + +What would you like to do? +1. Join an existing network +2. Create new production network +3. Set up a network on your local machine +4. Merge multiple networks +5. Configure Existing Network +(Press Ctrl+C to exit) +Enter your choice: 1 + +``` + +- Choose the component to install as Gateway + +``` +Which platform would you like to set up? +1. Gateway +2. BAP +3. BPP +Enter your choice: 1 +``` + +- Skip the option to apply network configuration + +``` +Proceeding with the setup for Gateway... +Please provide the network-specific configuration URL. +Paste the URL of the network configuration here (or press Enter to skip): +``` + +- Input the URL of the registry we just now installed https://onix-registry.becknprotocol.io + +``` +No network configuration URL provided, proceeding without it. + +Enter your registry URL: https://onix-registry.becknprotocol.io +``` + +- Input the Gateway URL https://onix-gateway.becknprotocol.io + +``` +Enter publicly accessible gateway URL: https://onix-gateway.becknprotocol.io +``` + +- The installation will complete to indicate the Gateway has been installed and registered with the registry + +``` +................Installing required packages................ +Docker Bash completion is already installed. +docker-compose is already installed. +Package Installation is done + % Total % Received % Xferd Average Speed Time Time Time Current + Dload Upload Total Spent Left Speed +100 555 0 533 100 22 3551 146 --:--:-- --:--:-- --:--:-- 3724 +Signing Public Key: LlT+DXNzpEKenZuBfhaRl4vvgRxAI2wm8O7/2vmsb0E= +Encryption Public Key: qhlWmkfy6WgzSSsGFc9dDfu3Sm3ZbbFf1bYiG+2RjFw= +URL https://onix-registry.becknprotocol.io/subscribers +................Installing Gateway service................ +Creating gateway ... done +Registering Gateway in the registry +{ + "SWFHttpResponse" : { + "Message" : "" + ,"Status" : "OK" + } +} +Gateway installation successful +[Installation Logs] +Your Gateway setup is complete. +You can access your Gateway at https://onix-gateway.becknprotocol.io +Process complete. Thank you for using Beckn Onix! +``` + +## Install a Beckn Adaptor for the BAP + +- On the virtual server that will hold the BAP, clone the repo, change into the install folder and run the beckn-onix.sh script. + +``` +git clone https://github.com/beckn/beckn-onix.git +cd beckn-onix/install +./beckn-onix.sh + +``` + +- In the prompt that comes up, choose joining an existing network. + +``` +What would you like to do? +1. Join an existing network +2. Create new production network +3. Set up a network on your local machine +4. Merge multiple networks +5. Configure Existing Network +(Press Ctrl+C to exit) +Enter your choice: 1 +``` + +- Choose the component to install as BAP + +``` +Which platform would you like to set up? +1. Gateway +2. BAP +3. BPP +Enter your choice: 2 +``` + +- Skip the option to apply network configuration + +``` +Proceeding with the setup for BAP... +Please provide the network-specific configuration URL. +Paste the URL of the network configuration here (or press Enter to skip): +``` + +- Input the BAP subscriber id - onix-bap.becknprotocol.io +- Input the BAP URL - https://onix-bap.becknprotocol.io +- Input the subscription endpoint of the registry - https://onix-registry.becknprotocol.io/subscribers + +``` +Enter BAP Subscriber ID: onix-bap.becknprotocol.io +Enter BAP Subscriber URL: https://onix-bap.becknprotocol.io +Enter the registry_url(e.g. https://registry.becknprotocol.io/subscribers)https://onix-registry.becknprotocol.io/subscribers +``` + +- The installation will complete to indicate the BAP Beckn Adaptor has installed. + +``` +................Installing required packages................ +Docker Bash completion is already installed. +docker-compose is already installed. +Package Installation is done +................Installing MongoDB................ +WARN[0000] /home/ubuntu/beckn-onix/install/docker-compose-app.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container mongoDB Started 0.4s +MongoDB installation successful +................Installing RabbitMQ................ +WARN[0000] /home/ubuntu/beckn-onix/install/docker-compose-app.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container rabbitmq Started 0.5s +RabbitMQ installation successful +................Installing Redis................ +WARN[0000] /home/ubuntu/beckn-onix/install/docker-compose-app.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container redis Started 0.6s +Redis installation successful +Generating public/private key pair +Your Private Key: o1t1TvdFaHU1H+2wDTsCEJgMRU9zdVt20SeFRyT0nyOlZujB4B0XZX1bMlchKBUpHQ65/9BCj6aMzS0Rdf+dRw== +Your Public Key: pWboweAdF2V9WzJXISgVKR0Ouf/QQo+mjM0tEXX/nUc= +Configuring BAP protocol server +Registering BAP protocol server on the registry +Network Participant Entry is created. Please login to registry https://onix-registry.becknprotocol.io/subscribers and subscribe you Network Participant. +WARN[0000] /home/ubuntu/beckn-onix/install/docker-compose-v2.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container bap-client Started 0.4s +WARN[0000] /home/ubuntu/beckn-onix/install/docker-compose-v2.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container bap-network Started 0.5s +Protocol server BAP installation successful +[Installation Logs] +Your BAP setup is complete. +You can access your BAP at https://onix-bap.becknprotocol.io +Process complete. Thank you for using Beckn Onix! + +``` + +## Install a Beckn Adaptor for the BPP + +- On the virtual server that will hold the BPP, clone the repo, change into the install folder and run the beckn-onix.sh script. + +``` +git clone https://github.com/beckn/beckn-onix.git +cd beckn-onix/install +./beckn-onix.sh + +``` + +- In the prompt that comes up, choose joining an existing network. + +``` +What would you like to do? +1. Join an existing network +2. Create new production network +3. Set up a network on your local machine +4. Merge multiple networks +5. Configure Existing Network +(Press Ctrl+C to exit) +Enter your choice: 1 + +``` + +- Choose the component to install as BPP + +``` +Which platform would you like to set up? +1. Gateway +2. BAP +3. BPP +Enter your choice: 3 +``` + +- Skip the option to apply network configuration + +``` +Proceeding with the setup for BPP... +Please provide the network-specific configuration URL. +Paste the URL of the network configuration here (or press Enter to skip): +``` + +- Input BPP subscriber id as onix-bpp.becknprotocol.io +- Input the BPP URL as https://onix-bpp.becknprotocol.io +- Input the registry URL to subscribe as https://onix-registry.becknprotocol.io/subscribers +- Input the webhook URL as the endpoint where your seller app or marketplace is. In case you do not have one, you can try 'https://unified-bpp.becknprotocol.io/beckn-bpp-adapter'. However the availability of a seller software for ever at this endpoint is not guaranteed (It currently is present) + +``` +Enter BPP Subscriber ID: onix-bpp.becknprotocol.io +Enter BPP Subscriber URL: https://onix-bpp.becknprotocol.io +Enter the registry_url(e.g. https://registry.becknprotocol.io/subscribers): https://onix-registry.becknprotocol.io/subscribers +Enter Webhook URL: https://unified-bpp.becknprotocol.io/beckn-bpp-adapter +``` + +- The installation will complete to indicate the BPP Beckn Adaptor has installed. + +``` +................Installing required packages................ +Docker Bash completion is already installed. +docker-compose is already installed. +Package Installation is done +................Installing MongoDB................ +WARN[0000] /home/ec2-user/beckn-onix/install/docker-compose-app.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container mongoDB Started 0.4s +MongoDB installation successful +................Installing RabbitMQ................ +WARN[0000] /home/ec2-user/beckn-onix/install/docker-compose-app.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container rabbitmq Started 0.6s +RabbitMQ installation successful +................Installing Redis................ +WARN[0000] /home/ec2-user/beckn-onix/install/docker-compose-app.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container redis Started 0.6s +Redis installation successful +................Installing Protocol Server for BPP................ +Generating public/private key pair +Configuring BAP protocol server +Registering BPP protocol server on the registry +Network Participant Entry is created. Please login to registry https://onix-registry.becknprotocol.io/subscribers and subscribe you Network Participant. +WARN[0000] /home/ec2-user/beckn-onix/install/docker-compose-v2.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container bpp-client Started 0.4s +WARN[0000] /home/ec2-user/beckn-onix/install/docker-compose-v2.yml: `version` is obsolete +[+] Running 1/1 + ✔ Container bpp-network Started 0.5s +Protocol server BPP installation successful +[Installation Logs] +Your BPP setup is complete. +You can access your BPP at https://onix-bpp.becknprotocol.io +Process complete. Thank you for using Beckn Onix! +``` + +## Change the status of the BAP and BPP on registry to Subscribed + +The newly added BAP and BPP should be transitioned to the "SUBSCRIBED" state in the registry. + +- Login to the newly installed registry (e.g. https://onix-registry.becknprotocol.io). The default username and password are root/root +- In the Admin menu, click Network Participant +- Click the pencil icon next to the onix-bap.becknprotocol.io +- Click on the Network Role tab +- Click on the pencil icon in the row of onix-bap.becknprotocol.io +- Change the status to SUBSCRIBED +- Click the Done button. + +- In the Admin menu, click Network Participant +- Click the pencil icon next to the onix-bpp.becknprotocol.io +- Click on the Network Role tab +- Click on the pencil icon in the row of onix-bpp.becknprotocol.io +- Change the status to SUBSCRIBED +- Click the Done button. + +## Update BAP and BPP with the layer 2 configuration files for the domains we are interested in + +The installation so far has installed a core Beckn network with the registry, gateway, BAP and the BPP. We cannot perform tranasctions on it till we have a layer 2 config file installed for the domains we want to transact in. + +- Login to the virtual server with the BAP +- Change into the beckn-onix/layer2 folder +- Run the download_layer_2_config_bap.sh file. +- Specify the path to the layer 2 config file for the domain of interest. For example, for retail, we have https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/retail_1.1.0.yaml and for energy https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/uei_charging_1.1.0.yaml + +- Login to the virtual server with the BPP +- Change into the beckn-onix/layer2 folder +- Run the download_layer_2_config_bpp.sh file. +- Specify the path to the layer 2 config file for the domain of interest. For example, for retail, we have https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/retail_1.1.0.yaml and for energy https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/uei_charging_1.1.0.yaml + +- Now with these layer 2 configs installed, we can conduct retail and energy transactions on the network. + +## Conduct successful transactions on the network + +- Load the collection available at `artifacts\ONIX Demo Collection.postman_collection.json` in this repo. +- Run the UEI >> Search request +- The request should succeed without any errors. +- Additional folders and tests will be addded to this collection. diff --git a/docs/energy_demo.md b/docs/energy_demo.md new file mode 100644 index 0000000..50e9848 --- /dev/null +++ b/docs/energy_demo.md @@ -0,0 +1,31 @@ +# Creating a new Beckn network using ONIX and conducting layer 2 transactions + +## Introduction + +This document describes the process to create a new Beckn network and conduct Energy transactions on it. Please refer to the [User Guide](.//user_guide.md) for details on the pre-requesites and additional details on all the steps. + +The [Demo Walkthrough](./demo_walkthrough.md) document describes how to install a new Beckn network. In general, readying a new network for installation involves the following steps + +1. Installing the core network with the registry, gateway, BAP adaptor and the BPP adaptor. +2. Installing the layer 2 config files for the domains in which we want to transact +3. Conducting successful transactions on the new network. + +The [Demo Walkthrough](./demo_walkthrough.md) illustrates download of retail domain layer 2 configuration. For energy domain all the steps remain the same except that we will have to download the layer 2 config file for energy (e.g. https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/uei_charging_1.1.0.yaml) + +In this document we describe how we can create a energy domain layer 2 config file such as the example above. While these instructions are similar for other domains, the values used in example are more suited for energy domain. + +## Creating a layer 2 config file for energy domain + +We start with either the core specification or a working group recommended layer 2 config for the domain as the base. Some of the changes we do to this base spec include + +### Adding enumerations for fields + +### Marking fields as required + +### Creating tags + +### Adding tags and requirements on those as conditionals + +## Additional steps + +After all the modifications to the layer 2 config are made for the domain, it needs to be hosted in a centralized place, so the network participants can download them as illustrated in the [Demo Walkthrough](./demo_walkthrough.md). Once these are downloaded by the BAP and the BPP, they can conduct transactions in the domain. diff --git a/docs/images/sample_deployment.png b/docs/images/sample_deployment.png new file mode 100644 index 0000000000000000000000000000000000000000..3343f7ad2fe97375b372366b6e84fcec18fcd176 GIT binary patch literal 51219 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 an$L. + server_name onix-bap-client.becknprotocol.io; + + location / { + # This for Host, Client and Forwarded For + #proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # For Web Sockets. + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # For Proxy. + proxy_pass "http://localhost:5001"; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + # Put the server name as website name . + server_name onix-bap-client.becknprotocol.io; + + # Point it to the port in which you want to run the server http://localhost:. + location / { + # This for Host, Client and Forwarded For + #proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # For Web Sockets. + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # For Proxy. + proxy_pass "http://localhost:5001"; + } + + + # This is the path to certificate. /etc/letsencrypt/live//fullchain.pem + ssl_certificate /etc/letsencrypt/live/onix-bap-client.becknprotocol.io/fullchain.pem; + + + # This is the path to certificate. /etc/letsencrypt/live//privkey.pem + ssl_certificate_key /etc/letsencrypt/live/onix-bap-client.becknprotocol.io/privkey.pem; + + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; # about 40000 sessions + ssl_session_tickets off; + + # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam + # ssl_dhparam /path/to/dhparam; + + # intermediate configuration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers on; + + # HSTS (ngx_http_headers_module is required) (63072000 seconds) + add_header Strict-Transport-Security "max-age=63072000" always; + + # OCSP stapling + ssl_stapling on; + ssl_stapling_verify on; + + # verify chain of trust of OCSP response using Root CA and Intermediate certs + # ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; + + # replace with the IP address of your resolver + resolver 8.8.8.8; +} +``` + +The following is a sample Nginx configuration for BAP Network (e.g. 'https://onix-bap.becknprotocol.io') + +``` +server { + listen 80; + listen [::]:80; + # Put the server name as website name . + server_name onix-bap.becknprotocol.io; + + location / { + # This for Host, Client and Forwarded For + #proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # For Web Sockets. + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # For Proxy. + proxy_pass "http://localhost:5002"; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + # Put the server name as website name . + server_name onix-bap.becknprotocol.io; + + # Point it to the port in which you want to run the server http://localhost:. + location / { + # This for Host, Client and Forwarded For + #proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # For Web Sockets. + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # For Proxy. + proxy_pass "http://localhost:5002"; + } + + + # This is the path to certificate. /etc/letsencrypt/live//fullchain.pem + ssl_certificate /etc/letsencrypt/live/onix-bap.becknprotocol.io/fullchain.pem; + + + # This is the path to certificate. /etc/letsencrypt/live//privkey.pem + ssl_certificate_key /etc/letsencrypt/live/onix-bap.becknprotocol.io/privkey.pem; + + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; # about 40000 sessions + ssl_session_tickets off; + + # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam + # ssl_dhparam /path/to/dhparam; + + # intermediate configuration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers on; + + # HSTS (ngx_http_headers_module is required) (63072000 seconds) + add_header Strict-Transport-Security "max-age=63072000" always; + + # OCSP stapling + ssl_stapling on; + ssl_stapling_verify on; + + # verify chain of trust of OCSP response using Root CA and Intermediate certs + # ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; + + # replace with the IP address of your resolver + resolver 8.8.8.8; +} +``` + +## Nginx sample configuration for BPP + +The BPP requires two URLs. One is for the BPP Network 'https://onix-bpp.becknprotocol.io' which faces the Beckn network. The other is for the BPP client 'https://onix-bpp-client.becknprotocol.io' which faces the seller side applciation. + +The following is the sample Nginx configuration for BPP client (e.g. 'https://onix-bpp-client.becknprotocol.io') + +``` +server { + listen 80; + listen [::]:80; + # Put the server name as website name . + server_name onix-bap.becknprotocol.io; + + location / { + # This for Host, Client and Forwarded For + #proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # For Web Sockets. + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # For Proxy. + proxy_pass "http://localhost:5002"; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + # Put the server name as website name . + server_name onix-bap.becknprotocol.io; + + # Point it to the port in which you want to run the server http://localhost:. + location / { + # This for Host, Client and Forwarded For + #proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # For Web Sockets. + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # For Proxy. + proxy_pass "http://localhost:5002"; + } + + + # This is the path to certificate. /etc/letsencrypt/live//fullchain.pem + ssl_certificate /etc/letsencrypt/live/onix-bap.becknprotocol.io/fullchain.pem; + + + # This is the path to certificate. /etc/letsencrypt/live//privkey.pem + ssl_certificate_key /etc/letsencrypt/live/onix-bap.becknprotocol.io/privkey.pem; + + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; # about 40000 sessions + ssl_session_tickets off; + + # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam + # ssl_dhparam /path/to/dhparam; + + # intermediate configuration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers on; + + # HSTS (ngx_http_headers_module is required) (63072000 seconds) + add_header Strict-Transport-Security "max-age=63072000" always; + + # OCSP stapling + ssl_stapling on; + ssl_stapling_verify on; + + # verify chain of trust of OCSP response using Root CA and Intermediate certs + # ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; + + # replace with the IP address of your resolver + resolver 8.8.8.8; +} +``` + +The following is the sample Nginx configuration for BPP Network (e.g. 'https://onix-bpp.becknprotocol.io') + +``` +server { + listen 80; + listen [::]:80; + # Put the server name as website name . + server_name onix-bpp.becknprotocol.io; + + location / { + # This for Host, Client and Forwarded For + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # For Web Sockets. + #proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # For Proxy. + proxy_pass "http://localhost:6002"; + } +} + +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + + # Put the server name as website name . + server_name onix-bpp.becknprotocol.io; + + # Point it to the port in which you want to run the server http://localhost:. + location / { + # This for Host, Client and Forwarded For + proxy_set_header Host $http_host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + + # For Web Sockets. + #proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + # For Proxy. + proxy_pass "http://localhost:6002"; + } + + + # This is the path to certificate. /etc/letsencrypt/live//fullchain.pem + ssl_certificate /etc/letsencrypt/live/onix-bpp.becknprotocol.io/fullchain.pem; + + + # This is the path to certificate. /etc/letsencrypt/live//privkey.pem + ssl_certificate_key /etc/letsencrypt/live/onix-bpp.becknprotocol.io/privkey.pem; + + ssl_session_timeout 1d; + ssl_session_cache shared:MozSSL:10m; # about 40000 sessions + ssl_session_tickets off; + + # curl https://ssl-config.mozilla.org/ffdhe2048.txt > /path/to/dhparam + # ssl_dhparam /path/to/dhparam; + + # intermediate configuration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers on; + + # HSTS (ngx_http_headers_module is required) (63072000 seconds) + add_header Strict-Transport-Security "max-age=63072000" always; + + # OCSP stapling + ssl_stapling on; + ssl_stapling_verify on; + + # verify chain of trust of OCSP response using Root CA and Intermediate certs + # ssl_trusted_certificate /path/to/root_CA_cert_plus_intermediates; + + # replace with the IP address of your resolver + resolver 8.8.8.8; +} +``` diff --git a/docs/user_guide.md b/docs/user_guide.md new file mode 100644 index 0000000..aecb9e1 --- /dev/null +++ b/docs/user_guide.md @@ -0,0 +1,219 @@ +# Beckn ONIX - User Guide + +## Table of Contents + +- [Introduction](#introduction) +- [Running Beckn ONIX on the cloud](#running-beckn-onix-on-the-cloud) + - [Sample deployment diagram](#sample-deployment-diagram) + - [Overall Prerequisites](#overall-pre-requisites) + - [Setting up a new network - Registry](#setting-up-a-new-network---registry) + - [Setting up a Gateway](#setting-up-a-gateway) + - [Setting up a BAP Beckn Adapter](#setting-up-a-bap-beckn-adapter) + - [Setting up a BPP Beckn Adapter](#setting-up-a-bpp-beckn-adapter) + - [Downloading Layer 2 Configuration for a domain](#downloading-layer-2-configuration-for-a-domain) + - [Testing transactions on the network](#testing-transactions-on-the-new-network) +- [Running Beckn ONIX locally](#running-beckn-onix-locally) +- [Appendix A - subdomain/domain name configuration](#appendix-a---registering-or-adding-domain-or-subdomains) +- [Appendix B - Nginx reverse proxy configuration](#appendix-b---nginx-reverse-proxy-configuration) + +## Introduction + +Beckn ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. This effort is also aimed at inviting contributions from the community to create secure, reliable builds for production environments. + +This user guide provides all information necessary to setup a Beckn network and conduct transactions on it. For a better understanding of Beckn and the terminologies associated with the ecosystem, please refer to the [Beckn for Developers site](https://developers.becknprotocol.io/). + +There are two primary setups covered in this document. + +- A typical production setup with the various Beckn components on different nodes - This is explained in the Running Beckn ONIX on the cloud section. +- A developer all in one setup - This is explained in the Running Beckn ONIX locally section. + +## Running Beckn ONIX on the Cloud + +Using Beckn ONIX, we can install a Beckn network on the cloud. This will be similar to a simple production instance of Beckn network. In the sections below, we use Amazon EC2 as an example for VPS provider. The guide can be useful for other cloud environments with simple changes on methods of accessing them etc. In this part of the guide, we explain installation of the four components of Registry, Gateway, BAP and BPP Beckn Adapter on different instances of virtual servers. You can however use the same process with minimal changes to install multiple nodes on the same virtual server (e.g. Registry and Gateway on a single virtual server) + +### Sample deployment diagram + +The following diagram shows a conceptual view of a multi-node Bekn network. The urls shown here are the same as those used in the examples. + +![Typical deployment](./images/sample_deployment.png) + +**Use of docker and reference implementations** +Docker compose and docker are extensively used in the installation and running of the various component software. Similarly the Beckn-ONIX installer, itself being a reference implementation, installs the reference implentation of the Beckn Adapter for the BAP and BPP, reference implementation of the registry and gateway. In order to interact with the internals of these components, we will need to enter the container. Familiarity with Docker will be useful in working with the installation. To list the running containers use `docker ps`. Similarly for example to connect to a container and browse it using shell, use `docker exec -it bap-client sh` + +### Overall Pre-requisites + +- Atleast four virtual servers (EC2 instances) configured on the cloud provider with administrator login (e.g. ssh access) to them. +- Access to domain name management with ability to create domain-name/subdomains for each of the components. +- Each of the various sections below list additional pre-requisites which build on these. + +### Setting up a new network - Registry + +In the Beckn ecosystem, a new network starts with the setting up of the Registry. All network participant register with the Registry with their public key. They also call the lookup endpoint on the Registry to discover and validate other network participants. + +**Prerequisites for installation** + +- A domain or subdomain where the registry will be accessible (e.g https://onix-registry.becknprotocol.io) +- A virtual server with domain/subdomain pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details +- SSL certificate for the server and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) +- Reverse proxy configured to route the traffic at the registry url (e.g. onix-registry.becknprotocol.io) to port 3030. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) + +**Installation Steps** + +- Clone the Beckn ONIX repository (git clone https://github.com/beckn/beckn-onix.git) +- Change into the installation folder `cd beckn-onix/install` +- Run the installation script `./beckn-onix.sh` +- Specify you want to start a new network and install the registry +- Skip the network configuration download option +- Enter the publicly accessible address of the registry (e.g. https://onix-registry.becknprotocol.io) +- The registry installation will continue to completion. + +### Setting up a Gateway + +In the Beckn ecosystem, the role of the Gateway is limited to the discovery phase. When the BAP wants to search for an item, it sends it to the Gateway and the Gateway broadcasts the request to all BPPs registered for the domain. It registers itself with the registry upon installation. + +**Prerequisites** + +- Address of the registry of the network the gateway will join (e.g. https://onix-registry.becknprotocol.io) +- A domain or subdomain where the gateway will be accessible (e.g https://onix-gateway.becknprotocol.io) +- A virtual server with domain/subdomain pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details +- SSL certificate for the server and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) +- Reverse proxy configured to route the traffic at the gateway url (e.g. onix-gateway.becknprotocol.io) to port 4030. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) + +**Installation Steps** + +- Clone the Beckn ONIX repository (git clone https://github.com/beckn/beckn-onix.git) +- Change into the installation folder `cd beckn-onix/install` +- Run the installation script `./beckn-onix.sh` +- Specify you want to join an existing network and install the gateway +- Skip the network configuration download option +- Enter the address of the registry of the network you want to join (e.g. https://onix-registry.becknprotocol.io) +- Enter the publicly accessible address of the gateway (e.g. https://onix-gateway.becknprotocol.io) +- The gateway installation will continue to completion and it will register itself with the registry as a participant with role BG(Beckn Gateway) + +### Setting up a BAP Beckn Adapter + +The BAP (Beckn Application Platform) is the bridge between buyer side applications and the Beckn Network. As part of Beckn-ONIX installation, a reference implementation of the Beckn Adapter for the BAP is installed. This adapter talks to two logical entities. On the one side you have the buyer applications which call the BAP with Beckn requests. The BAP forwards these requests to the Beckn network and other participants call back the BAP with responses. These two endpoints are referred to as client and network endpoints in this document. + +**Prerequisites** + +- Address of the registry's subscription endpoint of the network the BAP will join (e.g. https://onix-registry.becknprotocol.io/subscribers) +- A domain or subdomain where the client endpoint of BAP will be accessible (e.g https://onix-bap-client.becknprotocol.io) +- A domain or subdomain where the network endpoint of BAP will be accessible (e.g. https://onix-bap.becknprtocol.io) +- A virtual server with both the above domains/subdomains pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details +- SSL certificate for the two endpoints and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) +- Reverse proxy configured to route the traffic at the bap client url (e.g. onix-bap-client.becknprotocol.io) to port 5001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bap network url (e.g. onix-bap.becknprotocol.io) to port 5002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) + +**Installation Steps** + +- Clone the Beckn ONIX repository (git clone https://github.com/beckn/beckn-onix.git) +- Change into the installation folder `cd beckn-onix/install` +- Run the installation script `./beckn-onix.sh` +- Specify you want to join an existing network and install the BAP. +- Skip the network configuration download option +- Enter the Subscriber id for the BAP. When setting up a new network, its value can be anything you want. However it is recommended to have it the same as the BAP URL without the https:// part (e.g. onix-bap.becknprotocol.io). In existing networks this might be further validated for uniqueness by the registry. +- Enter the Subscriber URI for the BAP. This is the network endpoint of the BAP Beckn Adapter. (e.g. https://onix-bap.becknprotocol.io) +- Enter the address of the subscription endpoint of the registry of the network you want to join (e.g. https://onix-registry.becknprotocol.io/subscribers). Note the suffix subscribers in the endpoint address. +- The BAP installation will continue to completion and it will register itself with the registry as a network participant. + +### Setting up a BPP Beckn Adapter + +The BPP (Beckn Provider Platform) is the bridge between the seller side applications such as a market place or a headless shop and the Beckn network. As part of Beckn-ONIX installation, a reference implementation of the Beckn Adapter for the BPP is installed. This adapter talks to two entities. On the one side, it talks to the seller side apps. It forwards the requests from the Beckn network to this/these software. It also recieves the responses from the seller side apps. This interface towards the seller side applications is called as BPP-Client (client within the context of BPP)within this document. The BPP adapter also receives requests from the Beckn network and returns back the responses to the requesting participant. This part of the Beckn Adapter is called the BPP Network (or just network when the BPP context is implied.) + +**Prerequisites** + +- Address of the registry's subscription endpoint of the network the BPP will join (e.g. https://onix-registry.becknprotocol.io/subscribers) +- A domain or subdomain where the client endpoint of BPP will be accessible (e.g https://onix-bpp-client.becknprotocol.io) +- A domain or subdomain where the network endpoint of BPP will be accessible (e.g. https://onix-bap.becknprtocol.io) +- A virtual server with both the above domains/subdomains pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details +- SSL certificate for the two endpoints and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) +- Reverse proxy configured to route the traffic at the bap client url (e.g. onix-bap-client.becknprotocol.io) to port 5001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bap network url (e.g. onix-bap.becknprotocol.io) to port 5002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) + +**Installation Steps** + +- Clone the Beckn ONIX repository (git clone https://github.com/beckn/beckn-onix.git) +- Change into the installation folder `cd beckn-onix/install` +- Run the installation script `./beckn-onix.sh` +- Specify you want to join an existing network and install the BPP. +- Skip the network configuration download option +- Enter the Subscriber id for the BPP. When setting up a new network, its value can be anything you want. However it is recommended to have it the same as the BAP URL without the https:// part (e.g. onix-bpp.becknprotocol.io). In existing networks this might be further validated for uniqueness by the registry. +- Enter the Subscriber URL for the BPP (e.g. https://onix-bpp.becknprotocol.io). This is the network endpoint of the BPP Beckn Adapter. +- Enter the webhook URL. This is the endpoint on your custom market place or headless shop which will receive Beckn requests. The endpoint usually contains the address of the market place or shop as a substring. (e.g. https://unified-bpp.becknprotocol.io) +- Enter the address of the subscription endpoint of the registry of the network you want to join (e.g. https://onix-registry.becknprotocol.io/subscribers). Note the suffix subscribers in the endpoint address. +- The BPP installation will continue to completion and it will register itself with the registry as a network participant. + +### Changing subscription status of BAP and BPP at the registry + +While the Beckn ONIX installs network participant software as well as registers them with the Registry, they need to be manually put to the 'Subscribed' status. Its only then that they can transact. In real networks, the network facilitator might require additional documentation or validation before transitioning the BAP/BPP to the Subscribed state. When we are setting up the entire network ourselves, we can also do this task. + +**Steps** + +- Log into your registry at the url you specified (e.g. https://onix-registry.becknprotocol.io). The default username, password is root/root +- Select Network Participants Under Admin menu +- Edit the BAP record. In the Network Role tab, edit the entry and change the state to 'Subscribed' +- Repeat the same for the BPP record. + +### Downloading Layer 2 Configuration for a domain + +With Beckn onix installation of the Beckn network, we have a core network with all required network participants. However we cannot still do any transactions on this network. In order to do transactions, we need the Layer 2 Config file for the domain in which we want to transact. Layer 2 configuration files contain + +- rules and policies agreed upon by entities operating in the domain through working group and other consultations +- rules and policies required by the network facilitator + +Currently the layer-2 config are per domain, though this might change with future evolution of the core specification. The layer 2 config file is usually hosted by the network facilitator. Participants have to get this from the hosted location and install it within the respective containers. This is currently done by a script that needs to be run and provided with address of the layer 2 config file. + +**Steps** + +- Change into the beckn-onix/layer2 folder. +- Start the `download_layer_2_config_bap.sh` +- Specify the path of the layer 2 config file for the required domain. (e.g. https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/retail_1.1.0.yaml). Some sample layer 2 config files are present at `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/retail_1.1.0.yaml` +- This file is downloaded and installed into the container. +- Repeat the same process for the BPP. However run the `download_layer_2_config_bpp.sh` file instead. + +### Testing transactions on the new network + +- We can use postman collection for the specific domain to test end to end communication on the domain. Some sample postman collections for testing are [present here](https://github.com/beckn/beckn-sandbox/tree/main/artefacts) +- When running postman collection from the buyer side, the base url to which the requests are sent should be the client side endpoint of the BAP Beckn Adapter instance. (e.g https://onix-bap-client.becknprotocol.io) + +## Running Beckn ONIX locally + +- In order for people new to Beckn who want to try out Beckn on their own machine, a simple one click installer has been written. Currently it can be installed by running the `start_beckn.sh` script. In the next release, this will be integrated with the main script and this script deprecated. An all in one installation has preconfigured values for variables and so pretty much does not ask for any input. + +## Appendix A - Registering or adding domain or subdomains + +All the components of Beckn network need to be publicly accessible. Using domain names for them is the easiest. There are two options for domain names. One is a separate domain name for each component(e.g. registrybp.io). Second is to use subdomains for the individual componetns (e.g. onix-registry.becknprotocol.io , onix-gateway.becknprotocol.io etc). Which one of these two are used depends on the business requirement. For example if an organization is the network facilitator, they might go for a domain name for the registry instead of subdomain. In the examples given above we have primarily used subdomain approach. + +The process of registering domain names differs by the Domain Registrar. An example is here https://www.cloudflare.com/en-gb/products/registrar/ + +Similarly the process of adding subdomains differs by the Domain Registrar. An example is here https://developers.cloudflare.com/dns/manage-dns-records/how-to/create-subdomain/ + +For example in the prerequesites when it says "Subdomain name added(e.g. onix-gateway.becknprotocol.io) and point to this virtual server", what needs to be done is + +- Decide on a name (here it is onix-gateway) +- Add the name as subdomain at your registrar (here the registrar would be that of becknnprotocol.io) +- Point the record at the registrar to the machine on which you are installing the gateway + +## Appendix B - NGINX reverse proxy configuration + +All components of Beckn network need to be publicly accessible. Also it is required that they run on the https server for additional security. In addition some of the components of the reference implementation have two webservers running on the same node and require to be each publicly accessible through https. In order to achieve all of these requirements, it is recommended to install reverse-proxy on all the machines where the Beckn network components installed. This document uses Nginx as Reverse proxy, but the same can be configured through other programs. + +### SSL certificates configured in reverse proxy + +To enable https communication, SSL certificates need to be obtained and configured in Nginx. Depending on where you get the SSL certificate from, the process will vary. One such process for a provider [letsencrypt is documented here](https://letsencrypt.org/getting-started/) + +Once the SSL certificate is obtained, it needs to be configured. For Nginx, this [configuration is explained here] (https://nginx.org/en/docs/http/configuring_https_servers.html) + +When the prerequisite in this document says: "Nginx is configured with ssl certificate for the registry URL(e.g. https://onix-registry.becknprotocol.io)", it involves the following: + +- Obtain ssl certificate for `https://onix-registry.becknprotocol.io` +- Configure Nginx on the virtual server to create a server at https://onix-registry.becknprotocol.io. +- Configure this server to use the ssl certificate + +### Configuring Nginx reverse proxy using proxy pass + +In the role of reverse proxy, Nginx will forward communication that came on a particular url to a different destination (usually a server running on the same machine at a different port). This facility is used extensively in the reference Beckn components. For example the reference implementation of the BAP Protocol Server installs two servers. One at port 5001 and another at port 5002. We will need to configure two URLs (e.g. https://onix-bap-client.becknprotocol.io and https://onix-bap.becknprotocol.io) for this virtual server and Nginx should forward the first to server running on port 5001 and second to server running on port 5002. + +[This document](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) explains the configuration of reverse proxy using proxy_pass + +You can find sample Nginx configuration for the Registry, Gateway, BAP and BPP [here](./sample_nginx_configuration.md) From 23225d61ac909c0e8a85e8189a9cb8c55347c626 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Sat, 30 Mar 2024 06:40:31 +0530 Subject: [PATCH 024/102] removing wip file --- docs/energy_demo.md | 31 ------------------------------- 1 file changed, 31 deletions(-) delete mode 100644 docs/energy_demo.md diff --git a/docs/energy_demo.md b/docs/energy_demo.md deleted file mode 100644 index 50e9848..0000000 --- a/docs/energy_demo.md +++ /dev/null @@ -1,31 +0,0 @@ -# Creating a new Beckn network using ONIX and conducting layer 2 transactions - -## Introduction - -This document describes the process to create a new Beckn network and conduct Energy transactions on it. Please refer to the [User Guide](.//user_guide.md) for details on the pre-requesites and additional details on all the steps. - -The [Demo Walkthrough](./demo_walkthrough.md) document describes how to install a new Beckn network. In general, readying a new network for installation involves the following steps - -1. Installing the core network with the registry, gateway, BAP adaptor and the BPP adaptor. -2. Installing the layer 2 config files for the domains in which we want to transact -3. Conducting successful transactions on the new network. - -The [Demo Walkthrough](./demo_walkthrough.md) illustrates download of retail domain layer 2 configuration. For energy domain all the steps remain the same except that we will have to download the layer 2 config file for energy (e.g. https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/uei_charging_1.1.0.yaml) - -In this document we describe how we can create a energy domain layer 2 config file such as the example above. While these instructions are similar for other domains, the values used in example are more suited for energy domain. - -## Creating a layer 2 config file for energy domain - -We start with either the core specification or a working group recommended layer 2 config for the domain as the base. Some of the changes we do to this base spec include - -### Adding enumerations for fields - -### Marking fields as required - -### Creating tags - -### Adding tags and requirements on those as conditionals - -## Additional steps - -After all the modifications to the layer 2 config are made for the domain, it needs to be hosted in a centralized place, so the network participants can download them as illustrated in the [Demo Walkthrough](./demo_walkthrough.md). Once these are downloaded by the BAP and the BPP, they can conduct transactions in the domain. From 26aa5f25c18cc315ab9f5eb1e492c93781d2f6bd Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Sat, 30 Mar 2024 06:45:43 +0530 Subject: [PATCH 025/102] Update readme --- README.md | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 932ea71..aec2463 100644 --- a/README.md +++ b/README.md @@ -2,19 +2,27 @@ ONIX - Open Network In A Box, is a project designed to effortlessly set up and maintain Beckn network that is scalable, secure and easy to maintain. -In the install folder, you find a tool that helps install a Beckn network. This tool serves as a valuable resource for developers and network participants eager to explore BECKN protocols or join open networks supported by the BECKN protocol. By simplifying the installation process, ONIX streamlines the onboarding experience. For more details, refer to [release notes](./install/RELEASE.md) and [start with Beckn](./install/START_BECKN.md) +In the install folder, you find a tool that helps install a Beckn network. This tool serves as a valuable resource for developers and network participants eager to explore BECKN protocols or join open networks supported by the BECKN protocol. By simplifying the installation process, ONIX streamlines the onboarding experience. + +Refer to the following documents for more information: + +- [User Guide](./docs/user_guide.md) +- [Step by step walkthrough of a demo](./docs/demo_walkthrough.md) +- [release notes](./install/RELEASE.md) Experience the convenience and efficiency of ONIX as you embark on your journey with BECKN protocols and open networks. ## Note on mandatory Layer 2 Config (Important) + This note will eventually be moved to a proper place in the documentation. It has been put here to alert people who run Beckn ONIX in the meantime. -Beckn-Onix mandates availability of Layer 2 Config for a particular domain before any transactions can be conducted on it. If the layer 2 config is not present, on either the BAP or the BPP, the following error is returned back to the caller. "Config error : Layer 2 config not found." +Beckn-Onix mandates availability of Layer 2 Config for a particular domain before any transactions can be conducted on it. If the layer 2 config is not present, on either the BAP or the BPP, the following error is returned back to the caller. "Config error : Layer 2 config not found." -Usually the network facilitators will host the Layer 2 config and provide a way to access it. Currently we have a small script (layer2/download_layer_2_config_bap.sh and layer2/download_layer_2_config_bpp.sh) that can download the layer 2 config from a fixed location and insert it into the docker container that runs the Protocol Server Client. +Usually the network facilitators will host the Layer 2 config and provide a way to access it. Currently we have a small script (layer2/download_layer_2_config_bap.sh and layer2/download_layer_2_config_bpp.sh) that can download the layer 2 config from a fixed location and insert it into the docker container that runs the Protocol Server Client. If you have the Layer 2 config file with you and not hosted, you can use the following procedure to update it manually. In case you do not have layer 2 config file with you, as developer machine workaround, you can copy the core_version.yaml(e.g. core_1.1.0.yaml) and rename it as the layer 2 config for a domain (e.g. for a domain named retail for core version 1.1.0, retail_1.1.0.yaml). This is strictly not recommended for production networks. Process to manually update layer 2 config. + ``` docker cp "$FILENAME" "$CONTAINER_NAME":"$CONTAINER_PATH/$FILENAME" From 6c0c9868aa9af1a9c6a3d0dcde9ba0ef8bede9eb Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Sat, 30 Mar 2024 12:35:32 +0530 Subject: [PATCH 026/102] Fix typos --- docs/demo_walkthrough.md | 2 +- docs/user_guide.md | 48 ++++++++++++++++++++-------------------- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/docs/demo_walkthrough.md b/docs/demo_walkthrough.md index e6f261e..f26693e 100644 --- a/docs/demo_walkthrough.md +++ b/docs/demo_walkthrough.md @@ -1,4 +1,4 @@ -# Steps to setup a new Beckn network and conduct retail and energy transactions on it +# Steps to setup a new Beckn network and conduct transactions on it ## Introduction diff --git a/docs/user_guide.md b/docs/user_guide.md index aecb9e1..0ca263a 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -33,7 +33,7 @@ Using Beckn ONIX, we can install a Beckn network on the cloud. This will be simi ### Sample deployment diagram -The following diagram shows a conceptual view of a multi-node Bekn network. The urls shown here are the same as those used in the examples. +The following diagram shows a conceptual view of a multi-node Beckn network. The urls shown here are the same as those used in the examples. ![Typical deployment](./images/sample_deployment.png) @@ -53,17 +53,17 @@ In the Beckn ecosystem, a new network starts with the setting up of the Registry **Prerequisites for installation** - A domain or subdomain where the registry will be accessible (e.g https://onix-registry.becknprotocol.io) -- A virtual server with domain/subdomain pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details +- A virtual server with the above mentioned domain/subdomain pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details - SSL certificate for the server and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) -- Reverse proxy configured to route the traffic at the registry url (e.g. onix-registry.becknprotocol.io) to port 3030. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the registry url (e.g. https://onix-registry.becknprotocol.io) to port 3030. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) **Installation Steps** -- Clone the Beckn ONIX repository (git clone https://github.com/beckn/beckn-onix.git) +- Clone the Beckn ONIX repository `git clone https://github.com/beckn/beckn-onix.git` - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to start a new network and install the registry -- Skip the network configuration download option +- Skip the apply network configuration option - Enter the publicly accessible address of the registry (e.g. https://onix-registry.becknprotocol.io) - The registry installation will continue to completion. @@ -75,9 +75,9 @@ In the Beckn ecosystem, the role of the Gateway is limited to the discovery phas - Address of the registry of the network the gateway will join (e.g. https://onix-registry.becknprotocol.io) - A domain or subdomain where the gateway will be accessible (e.g https://onix-gateway.becknprotocol.io) -- A virtual server with domain/subdomain pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details +- A virtual server with the above mentioned domain/subdomain pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details - SSL certificate for the server and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) -- Reverse proxy configured to route the traffic at the gateway url (e.g. onix-gateway.becknprotocol.io) to port 4030. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the gateway url (e.g. https://onix-gateway.becknprotocol.io) to port 4030. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) **Installation Steps** @@ -85,7 +85,7 @@ In the Beckn ecosystem, the role of the Gateway is limited to the discovery phas - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to join an existing network and install the gateway -- Skip the network configuration download option +- Skip the apply network configuration option - Enter the address of the registry of the network you want to join (e.g. https://onix-registry.becknprotocol.io) - Enter the publicly accessible address of the gateway (e.g. https://onix-gateway.becknprotocol.io) - The gateway installation will continue to completion and it will register itself with the registry as a participant with role BG(Beckn Gateway) @@ -99,10 +99,10 @@ The BAP (Beckn Application Platform) is the bridge between buyer side applicatio - Address of the registry's subscription endpoint of the network the BAP will join (e.g. https://onix-registry.becknprotocol.io/subscribers) - A domain or subdomain where the client endpoint of BAP will be accessible (e.g https://onix-bap-client.becknprotocol.io) - A domain or subdomain where the network endpoint of BAP will be accessible (e.g. https://onix-bap.becknprtocol.io) -- A virtual server with both the above domains/subdomains pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details +- A virtual server with both the above mentioned domains/subdomains pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details - SSL certificate for the two endpoints and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) -- Reverse proxy configured to route the traffic at the bap client url (e.g. onix-bap-client.becknprotocol.io) to port 5001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) -- Reverse proxy configured to route the traffic at the bap network url (e.g. onix-bap.becknprotocol.io) to port 5002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bap client url (e.g. https://onix-bap-client.becknprotocol.io) to port 5001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bap network url (e.g. https://onix-bap.becknprotocol.io) to port 5002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) **Installation Steps** @@ -110,7 +110,7 @@ The BAP (Beckn Application Platform) is the bridge between buyer side applicatio - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to join an existing network and install the BAP. -- Skip the network configuration download option +- Skip the apply network configuration option - Enter the Subscriber id for the BAP. When setting up a new network, its value can be anything you want. However it is recommended to have it the same as the BAP URL without the https:// part (e.g. onix-bap.becknprotocol.io). In existing networks this might be further validated for uniqueness by the registry. - Enter the Subscriber URI for the BAP. This is the network endpoint of the BAP Beckn Adapter. (e.g. https://onix-bap.becknprotocol.io) - Enter the address of the subscription endpoint of the registry of the network you want to join (e.g. https://onix-registry.becknprotocol.io/subscribers). Note the suffix subscribers in the endpoint address. @@ -125,10 +125,10 @@ The BPP (Beckn Provider Platform) is the bridge between the seller side applicat - Address of the registry's subscription endpoint of the network the BPP will join (e.g. https://onix-registry.becknprotocol.io/subscribers) - A domain or subdomain where the client endpoint of BPP will be accessible (e.g https://onix-bpp-client.becknprotocol.io) - A domain or subdomain where the network endpoint of BPP will be accessible (e.g. https://onix-bap.becknprtocol.io) -- A virtual server with both the above domains/subdomains pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details +- A virtual server with both the above mentioned domains/subdomains pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details - SSL certificate for the two endpoints and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) -- Reverse proxy configured to route the traffic at the bap client url (e.g. onix-bap-client.becknprotocol.io) to port 5001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) -- Reverse proxy configured to route the traffic at the bap network url (e.g. onix-bap.becknprotocol.io) to port 5002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bap client url (e.g. https://onix-bap-client.becknprotocol.io) to port 5001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bap network url (e.g. https://onix-bap.becknprotocol.io) to port 5002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) **Installation Steps** @@ -136,16 +136,16 @@ The BPP (Beckn Provider Platform) is the bridge between the seller side applicat - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to join an existing network and install the BPP. -- Skip the network configuration download option -- Enter the Subscriber id for the BPP. When setting up a new network, its value can be anything you want. However it is recommended to have it the same as the BAP URL without the https:// part (e.g. onix-bpp.becknprotocol.io). In existing networks this might be further validated for uniqueness by the registry. +- Skip the apply network configuration option +- Enter the Subscriber id for the BPP. When setting up a new network, its value can be anything you want. However it is recommended to have it the same as the BPP URL without the https:// part (e.g. onix-bpp.becknprotocol.io). In existing networks this might be further validated for uniqueness by the registry. - Enter the Subscriber URL for the BPP (e.g. https://onix-bpp.becknprotocol.io). This is the network endpoint of the BPP Beckn Adapter. -- Enter the webhook URL. This is the endpoint on your custom market place or headless shop which will receive Beckn requests. The endpoint usually contains the address of the market place or shop as a substring. (e.g. https://unified-bpp.becknprotocol.io) +- Enter the webhook URL. This is the endpoint on your custom market place or headless shop which will receive Beckn requests. The endpoint usually contains the address of the market place or shop as a substring. (e.g. https://unified-bpp.becknprotocol.io/beckn-bpp-adapter) - Enter the address of the subscription endpoint of the registry of the network you want to join (e.g. https://onix-registry.becknprotocol.io/subscribers). Note the suffix subscribers in the endpoint address. - The BPP installation will continue to completion and it will register itself with the registry as a network participant. ### Changing subscription status of BAP and BPP at the registry -While the Beckn ONIX installs network participant software as well as registers them with the Registry, they need to be manually put to the 'Subscribed' status. Its only then that they can transact. In real networks, the network facilitator might require additional documentation or validation before transitioning the BAP/BPP to the Subscribed state. When we are setting up the entire network ourselves, we can also do this task. +While the Beckn ONIX installs network participant beckn adapter as well as registers them with the Registry, they need to be manually put to the 'Subscribed' status. Its only then that they can transact. In real networks, the network facilitator might require additional documentation or validation before transitioning the BAP/BPP to the Subscribed state. When we are setting up the entire network ourselves, we do this task ourselves. **Steps** @@ -156,18 +156,18 @@ While the Beckn ONIX installs network participant software as well as registers ### Downloading Layer 2 Configuration for a domain -With Beckn onix installation of the Beckn network, we have a core network with all required network participants. However we cannot still do any transactions on this network. In order to do transactions, we need the Layer 2 Config file for the domain in which we want to transact. Layer 2 configuration files contain +With Beckn network setup by ONIX, we have a core network with all required network participants. However we cannot still do any transactions on this network. In order to do transactions, we need the Layer 2 Config file for the domain in which we want to transact. Layer 2 configuration files contain - rules and policies agreed upon by entities operating in the domain through working group and other consultations - rules and policies required by the network facilitator -Currently the layer-2 config are per domain, though this might change with future evolution of the core specification. The layer 2 config file is usually hosted by the network facilitator. Participants have to get this from the hosted location and install it within the respective containers. This is currently done by a script that needs to be run and provided with address of the layer 2 config file. +Currently the layer-2 config are per domain, though this might change with future evolution of the Beckn core specification. The layer 2 config file is usually hosted by the network facilitator. Participants have to get this from the hosted location and install it within the respective containers. This is currently done by a script that needs to be run and provided with address of the layer 2 config file. **Steps** - Change into the beckn-onix/layer2 folder. - Start the `download_layer_2_config_bap.sh` -- Specify the path of the layer 2 config file for the required domain. (e.g. https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/retail_1.1.0.yaml). Some sample layer 2 config files are present at `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/retail_1.1.0.yaml` +- Specify the path of the layer 2 config file for the required domain. (e.g. https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/retail_1.1.0.yaml). Some sample layer 2 config files are present at `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples` - This file is downloaded and installed into the container. - Repeat the same process for the BPP. However run the `download_layer_2_config_bpp.sh` file instead. @@ -178,11 +178,11 @@ Currently the layer-2 config are per domain, though this might change with futur ## Running Beckn ONIX locally -- In order for people new to Beckn who want to try out Beckn on their own machine, a simple one click installer has been written. Currently it can be installed by running the `start_beckn.sh` script. In the next release, this will be integrated with the main script and this script deprecated. An all in one installation has preconfigured values for variables and so pretty much does not ask for any input. +- In order for people new to Beckn who want to try out Beckn on their own machine, a simple one click installer has been written. Currently it can be installed by running the `start_beckn.sh` script present in the installfolder. In the next release, this will be integrated with the main script and the `start_beckn.sh` script deprecated. An all in one installation has preconfigured values for variables and so pretty much does not ask for any input. ## Appendix A - Registering or adding domain or subdomains -All the components of Beckn network need to be publicly accessible. Using domain names for them is the easiest. There are two options for domain names. One is a separate domain name for each component(e.g. registrybp.io). Second is to use subdomains for the individual componetns (e.g. onix-registry.becknprotocol.io , onix-gateway.becknprotocol.io etc). Which one of these two are used depends on the business requirement. For example if an organization is the network facilitator, they might go for a domain name for the registry instead of subdomain. In the examples given above we have primarily used subdomain approach. +All the components of Beckn network need to be publicly accessible. Using domain names for them is the easiest. There are two options for domain names. One is a separate domain name for each component(e.g. registrybp.io). Second is to use subdomains for the individual componetns (e.g. onix-registry.becknprotocol.io , onix-gateway.becknprotocol.io etc). Which one of these two to use depends on the business requirement. For example if an organization is the network facilitator, they might go for a domain name for the registry instead of subdomain. In the examples given above we have primarily used subdomain approach. The process of registering domain names differs by the Domain Registrar. An example is here https://www.cloudflare.com/en-gb/products/registrar/ From 851bd5f7d94c7946092bd703ea947fca33b60fb7 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Sat, 30 Mar 2024 14:37:27 +0530 Subject: [PATCH 027/102] Add additional demo scenario --- docs/demo_healthcare.md | 142 +++++++++++++++++++++++ docs/images/message_validation_in_ba.png | Bin 0 -> 22293 bytes 2 files changed, 142 insertions(+) create mode 100644 docs/demo_healthcare.md create mode 100644 docs/images/message_validation_in_ba.png diff --git a/docs/demo_healthcare.md b/docs/demo_healthcare.md new file mode 100644 index 0000000..a9d5ff5 --- /dev/null +++ b/docs/demo_healthcare.md @@ -0,0 +1,142 @@ +# Creating a Beckn network for healthcare using Beckn ONIX and transacting on it. + +## Introduction + +[Beckn](https://becknprotocol.io/) as a protocol allows creation of decentralised commerce network across many domains. Healthcare is one of them. Beckn ONIX is a project aimed at easing setup and maintanence of Beckn network for different domains. It provides utilities to quickly setup the core Beckn network as well as provides tools to enable domain specific transactions. The latter is achieved through the use of layer 2 configuration files. + +The [Beckn ONIX User Guide](./user_guide.md) provides an overall understanding of setup of the core Beckn network as well as download and ingestion of Layer 2 configuration files. The [step by step demo](./demo_walkthrough.md) walks through one such installation in great detail. The layer 2 configurations illustrated in that demo belong to the retail and energy domain. + +## Healthcare usecases on Beckn network + +A sample of the usecases that can be imagined on Beckn networks include + +- Discovery and request for ambulance service including scenarios such as + - Requesting an immediate ambulance service + - Scheduled pickup by ambulance + - Querying special ambulances for certain category of patients + - Requesting with both start and destination locations +- Blood bank related use cases including + - Finding and transacting for emergency blood + - Identifying and enrolling for donation +- Doctor consultation including + - search by location + - search by speciality +- Diagnostics related transactions including +- Pharmacy related transactions including + - Location aware search + +## Setting up Beckn network for healthcare usecases + +Setting up of a network for healthcare related use cases follows the same steps as illustrated in the [step by step demo](./demo_walkthrough.md) document. The primary differences is the layer 2 configuration file downloaded will be specific to healthcare and suited to conduct healthcare transactions. A sample layer 2 config for healthcare is available in the beckn_onix/layer2/samples folder and its path can be provided when running download_layer_2_config_bap.sh and download_layer_2_config_bpp.sh. If you are joining a network administered by a network facilitator, they might have a different layer 2 config and that should be used instead of the sample. + +The following is a conceptual view of core and layer 2 config from a perspective of validation +![Validation in Beckn Adaptor](./images/message_validation_in_ba.png) + +## Writing Layer 2 configuration file for healthcare domain + +Layer 2 configuration file addresses two primary concerns + +- The rules and policies agreed by participants from the healtcare domain and agreed upon usually through working groups or other mechanisms +- The rules and policies required by the network facilitator. + +At an implementation level, the layer 2 configuration has additional data over core in two primary areas + +- Description, examples and other non-machine enforceable information. These are useful for implementors to get the big picture, perform semantic validation and use example requests as base for their own modifications. +- Rules and policies against which incoming messages can be validated. These are over and above those in the core and cover domain specific scenarios. + +## Sample validations that can be encoded into layer 2 configuration + +1. Limiting values to a fixed set of enumerations. Examples include + +- Limiting fulfillment type to ["walk-in","doorstep service"] for diagnostics +- Limiting fulfillment type to ["IN-STORE_PICKUP","HOME-DELIVERY"] for items in pharmacy +- Limiting fulfillment type to ["EMERGENCY","NORMAL"] for blood bank related queries + +``` +type: object +properties: + type: + type: string + enum: + - EMERGENCY + - NORMAL +required: + - type +``` + +2. Limiting values using minimum and maximum + +- Setting minimum and maximum of count field of unitized object to indicate a single unit item in medicine packages + +``` +unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: '#/components/schemas/Scalar' +``` + +3. Marking an optional field in the core as required in the layer 2 config + +- Mandating feedback form be filled after consultation during rating +- Mandating cancellation reason for appointment cancellation +- Mandating credentials of doctor be present in search + +``` +type: object +properties: + cancellation_reason: + type: string +required: + - cancellation_reason +``` + +4. Mandating custom tags to be present in the tag list + +- Requiring the symptoms field be filled before the doctor's appointment is confirmed +- Requiring the qualifications of doctor to be returned ih search results in either skills or verifiable creds + +``` +type: object +properties: + creds: + type: object + skills: + type: object +oneOf: +- required: + - skills +- required: + - creds +``` + +5. Conditional requirement based on value of a different field + +- If item is medical equipment, additinoal description should be present + +``` +type: object +properties: + code: + type: string + additional_desc: + type: string +anyOf: +- not: + properties: + code: + const: "medical-equipment" + required: + - code +- required: + - additional_desc +``` + +## Conclusion + +Multitide DHP related use cases can be implemented on the Beckn networks. The process Beckn ONIX follows to create core Beckn network and allowing participants to download layer 2 configuration is identical across domains. Layer 2 configuration captures both domain policies and rules as well as those enforced by the network facilitators. Layer 2 configuration are both prescriptive as well as mandatory. The mandatory rules and policies can be written on top of the core spec within the layer 2 config and can be enforced by incorporating a validator in the workflow. diff --git a/docs/images/message_validation_in_ba.png b/docs/images/message_validation_in_ba.png new file mode 100644 index 0000000000000000000000000000000000000000..610722256e659dfdd96381d9bb812df5fcc63726 GIT binary patch literal 22293 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 literal 0 HcmV?d00001 From 94b362c0c6f5012105b06247a56c4066a6293c64 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Sun, 31 Mar 2024 07:38:07 +0530 Subject: [PATCH 028/102] Add demo scenarios --- docs/demo_scenarios.md | 45 + {docs => layer2/docs}/demo_healthcare.md | 0 layer2/samples/dhp_1.1.0.yaml | 2164 ++++++++++++++++++++++ layer2/samples/mobility_1.1.0.yaml | 2164 ++++++++++++++++++++++ 4 files changed, 4373 insertions(+) create mode 100644 docs/demo_scenarios.md rename {docs => layer2/docs}/demo_healthcare.md (100%) create mode 100644 layer2/samples/dhp_1.1.0.yaml create mode 100644 layer2/samples/mobility_1.1.0.yaml diff --git a/docs/demo_scenarios.md b/docs/demo_scenarios.md new file mode 100644 index 0000000..7bd5646 --- /dev/null +++ b/docs/demo_scenarios.md @@ -0,0 +1,45 @@ +## Introduction + +The [demo walkthrough](../docs/demo_walkthrough.md) and the accompanying video shows a story where we have the following steps + +1. We install a core Beckn network using Beckn ONIX +2. We try to conduct a retail transaction, but it fails due to layer 2 config not being present +3. We install the layer 2 config for retail from and successfully complete a retail transaction +4. We try to perform a query to find charging station nearby (energy transaction), but it fails due to the layer 2 for energy being absent +5. We install the layer 2 config for energy +6. Now the energy transaction completes. + +In this document we list a few other demo stories where we can show a similar flow but with different domains. The steps are identical, but the story changes to involve different domains. + +## Healthcare + Mobility + +Alice wants to book a wellness center appointment and then book a cab to reach the clinic. + +1. We install a core Beckn network using Beckn ONIX +2. Alice tries to conduct a healthcare booking, but it fails due to layer 2 config not being present +3. We install the layer 2 config for healthcare and successfully complete a healthcare appointment booking +4. She tries to book a cab to reach the clinic, but it fails due to the layer 2 for mobility not being present +5. We install the layer 2 config for mobility +6. Now Alice can book a cab and reach the clinic. + +## Mobility + Retail + +Bob wants to book a cab back home. He wants to buy groceries so he can pick it up on the way + +1. We install a core Beckn network using Beckn ONIX +2. Bob tries to book a cab, but it fails due to layer 2 config not being present +3. We install the layer 2 config for mobility and successfully complete the booking +4. He now wants to buy groceries from a shop on the way, but it fails due to the layer 2 for retail not being present +5. We install the layer 2 config for retail +6. Now Bob can complete the retail order and pick it up on the way home + +## Healthcare + Energy + Retail + +Cindy wants to schedule a wellness clinic visit, find charging stations near the clinic to get her bike charged while she is attending her appointment + +1. We install a core Beckn network using Beckn ONIX +2. Cindy tries to book a wellness clinic appointment. It fails due to healthcare layer 2 being missing +3. We install the layer 2 config for healthcare and Cindy can successfully book the appointment +4. Now she wants to find charging stations near the clinic, but it fails as energy layer 2 config is absent. +5. We install the layer 2 config for energy +6. Now Cindy can find charging stations near the clinic where she can drop the bike and have it charged while finishing her appointment diff --git a/docs/demo_healthcare.md b/layer2/docs/demo_healthcare.md similarity index 100% rename from docs/demo_healthcare.md rename to layer2/docs/demo_healthcare.md diff --git a/layer2/samples/dhp_1.1.0.yaml b/layer2/samples/dhp_1.1.0.yaml new file mode 100644 index 0000000..469286d --- /dev/null +++ b/layer2/samples/dhp_1.1.0.yaml @@ -0,0 +1,2164 @@ +openapi: 3.0.0 +info: + title: Beckn Protocol Core + description: DHP layer 2 config from core yaml + version: 1.1.0 +security: + - SubscriberAuth: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: BAP declares the customer's intent to buy/avail products or services + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: BAP declares the customer's cart (or equivalent) created by selecting objects from the catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + description: Updated order object + allOf: + - $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_search: + post: + tags: + - Beckn Application Platform (BAP) + - Beckn Gateway (BG) + description: BPP sends its catalog in response to a search request. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_select: + post: + tags: + - Beckn Application Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_init: + post: + tags: + - Beckn Application Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_confirm: + post: + tags: + - Beckn Application Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_track: + post: + tags: + - Beckn Application Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_cancel: + post: + tags: + - Beckn Application Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_update: + post: + tags: + - Beckn Application Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_status: + post: + tags: + - Beckn Application Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_rating: + post: + tags: + - Beckn Application Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_support: + post: + tags: + - Beckn Application Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: "Describes the acknowledgement sent in response to an API call. If the implementation uses HTTP/S, then Ack must be returned in the same session. Every API call to a BPP must be responded to with an Ack whether the BPP intends to respond with a callback or not. This has one property called `status` that indicates the status of the Acknowledgement." + type: object + properties: + status: + type: string + description: "The status of the acknowledgement. If the request passes the validation criteria of the BPP, then this is set to ACK. If a BPP responds with status = `ACK` to a request, it is required to respond with a callback. If the request fails the validation criteria, then this is set to NACK. Additionally, if a BPP does not intend to respond with a callback even after the request meets the validation criteria, it should set this value to `NACK`." + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: Describes an additional item offered as a value-addition to a product or service. This does not exist independently in a catalog and is always associated with an item. + type: object + properties: + id: + description: Provider-defined ID of the add-on + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes the direct performer, driver or executor that fulfills an order. It is usually a person. But in some rare cases, it could be a non-living entity like a drone, or a bot. Some examples of agents are Doctor in the healthcare sector, a driver in the mobility sector, or a delivery person in the logistics sector. This object can be set at any stage of the order lifecycle. This can be set at the discovery stage when the BPP wants to provide details on the agent fulfilling the order, like in healthcare, where the doctor's name appears during search. This object can also used to search for a particular person that the customer wants fulfilling an order. Sometimes, this object gets instantiated after the order is confirmed, like in the case of on-demand taxis, where the driver is assigned after the user confirms the ride." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: "Describes the billing details of an entity.
This has properties like name,organization,address,email,phone,time,tax_number, created_at,updated_at" + type: object + properties: + name: + description: Name of the billable entity + type: string + organization: + description: Details of the organization being billed. + allOf: + - $ref: "#/components/schemas/Organization" + address: + description: The address of the billable entity + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address where the bill is sent to + type: string + format: email + phone: + description: Phone number of the billable entity + type: string + time: + description: Details regarding the billing period + allOf: + - $ref: "#/components/schemas/Time" + tax_id: + description: ID of the billable entity as recognized by the taxation authority + type: string + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the buyer + type: string + format: date-time + cancelled_by: + type: string + enum: + - CONSUMER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + CancellationTerm: + description: Describes the cancellation terms of an item or an order. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes the products or services offered by a BPP. This is typically sent as the response to a search intent from a BAP. The payment terms, offers and terms of fulfillment supported by the BPP can also be included here. The BPP can show hierarchical nature of products/services in its catalog using the parent_category_id in categories. The BPP can also send a ttl (time to live) in the context which is the duration for which a BAP can cache the catalog and use the cached catalog.
This has properties like bbp/descriptor,bbp/categories,bbp/fulfillments,bbp/payments,bbp/offers,bbp/providers and exp
This is used in the following situations.
  • This is typically used in the discovery stage when the BPP sends the details of the products and services it offers as response to a search intent from the BAP.
" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: A label under which a collection of items can be grouped. + type: object + properties: + id: + description: ID of the category + type: string + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular region of a specified radius centered at a specified GPS coordinate. + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + description: Name of the city + type: string + code: + description: City code + type: string + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: "Every API call in beckn protocol has a context. It provides a high-level overview to the receiver about the nature of the intended transaction. Typically, it is the BAP that sets the transaction context based on the consumer's location and action on their UI. But sometimes, during unsolicited callbacks, the BPP also sets the transaction context but it is usually the same as the context of a previous full-cycle, request-callback interaction between the BAP and the BPP. The context object contains four types of fields.
  1. Demographic information about the transaction using fields like `domain`, `country`, and `region`.
  2. Addressing details like the sending and receiving platform's ID and API URL.
  3. Interoperability information like the protocol version that implemented by the sender and,
  4. Transaction details like the method being called at the receiver's endpoint, the transaction_id that represents an end-to-end user session at the BAP, a message ID to pair requests with callbacks, a timestamp to capture sending times, a ttl to specifiy the validity of the request, and a key to encrypt information if necessary.
This object must be passed in every interaction between a BAP and a BPP. In HTTP/S implementations, it is not necessary to send the context during the synchronous response. However, in asynchronous protocols, the context must be sent during all interactions," + type: object + properties: + domain: + description: Domain code that is relevant to this transaction context + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + description: The Beckn protocol method being called by the sender and executed at the receiver. + type: string + version: + type: string + description: Version of transaction protocol being used by the sender. + bap_id: + description: Subscriber ID of the BAP + allOf: + - description: "A globally unique identifier of the platform, Typically it is the fully qualified domain name (FQDN) of the platform." + type: string + bap_uri: + description: Subscriber URL of the BAP for accepting callbacks from BPPs. + allOf: + - description: The callback URL of the Subscriber. This should necessarily contain the same domain name as set in `subscriber_id``. + type: string + format: uri + bpp_id: + description: Subscriber ID of the BPP + allOf: + - $ref: "#/components/schemas/Context/properties/bap_id/allOf/0" + bpp_uri: + description: Subscriber URL of the BPP for accepting calls from BAPs. + allOf: + - $ref: "#/components/schemas/Context/properties/bap_uri/allOf/0" + transaction_id: + description: "This is a unique value which persists across all API calls from `search` through `confirm`. This is done to indicate an active user session across multiple requests. The BPPs can use this value to push personalized recommendations, and dynamic offerings related to an ongoing transaction despite being unaware of the user active on the BAP." + type: string + format: uuid + message_id: + description: "This is a unique value which persists during a request / callback cycle. Since beckn protocol APIs are asynchronous, BAPs need a common value to match an incoming callback from a BPP to an earlier call. This value can also be used to ignore duplicate messages coming from the BPP. It is recommended to generate a fresh message_id for every new interaction. When sending unsolicited callbacks, BPPs must generate a new message_id." + type: string + format: uuid + timestamp: + description: Time of request generation in RFC3339 format + type: string + format: date-time + key: + description: The encryption public key of the sender + type: string + ttl: + description: The duration in ISO8601 format after timestamp for which this message holds valid + type: string + Country: + description: Describes a country + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + DecimalValue: + description: Describes a numerical value in decimal form + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: "Describes an error object that is returned by a BAP, BPP or BG as a response or callback to an action by another network participant. This object is sent when any request received by a network participant is unacceptable. This object can be sent either during Ack or with the callback." + type: object + properties: + code: + type: string + description: 'Standard error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-005-ERROR-CODES-DRAFT-01.md of this repo"' + paths: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error. Used mainly for logging. Not recommended to be shown to the user. + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to buy or avail a product or a service. The BAP can declare the intent of the consumer containing
  • What they want (A product, service, offer)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of a business. + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + type: string + Region: + description: Describes an arbitrary region of space. The network policy should contain a published list of supported regions by the network. + type: object + properties: + dimensions: + description: "The number of dimensions that are used to describe any point inside that region. The most common dimensionality of a region is 2, that represents an area on a map. There are regions on the map that can be approximated to one-dimensional regions like roads, railway lines, or shipping lines. 3 dimensional regions are rarer, but are gaining popularity as flying drones are being adopted for various fulfillment services." + type: string + enum: + - "1" + - "2" + - "3" + type: + description: "The type of region. This is used to specify the granularity of the region represented by this object. Various examples of two-dimensional region types are city, country, state, district, and so on. The network policy should contain a list of all possible region types supported by the network." + type: string + name: + type: string + description: Name of the region as specified on the map where that region exists. + code: + type: string + description: A standard code representing the region. This should be interpreted in the same way by all network participants. + boundary: + type: string + description: "A string representing the boundary of the region. One-dimensional regions are represented by polylines. Two-dimensional regions are represented by polygons, and three-dimensional regions can represented by polyhedra." + map_url: + type: string + description: The url to the map of the region. This can be a globally recognized map or the one specified by the network policy. + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: "Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations
This has properties like label, time stamp,duration,range, days, schedule" + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Contains tracking information that can be used by the BAP to track the fulfillment of an order in real-time. which is useful for knowing the location of time sensitive deliveries. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required to confirm an order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, to confirm a flight ticket, the airline requires details of the passengers along with information on baggage, identity, in addition to the class of ticket. Similarly, a logistics company may require details on the nature of shipment in order to confirm the shipping. A recruiting firm may require additional details on the applicant in order to confirm a job application. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean diff --git a/layer2/samples/mobility_1.1.0.yaml b/layer2/samples/mobility_1.1.0.yaml new file mode 100644 index 0000000..b3ae63c --- /dev/null +++ b/layer2/samples/mobility_1.1.0.yaml @@ -0,0 +1,2164 @@ +openapi: 3.0.0 +info: + title: Beckn Protocol Core + description: retail layer 2 config from core yaml + version: 1.1.0 +security: + - SubscriberAuth: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: BAP declares the customer's intent to buy/avail products or services + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: BAP declares the customer's cart (or equivalent) created by selecting objects from the catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + description: Updated order object + allOf: + - $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_search: + post: + tags: + - Beckn Application Platform (BAP) + - Beckn Gateway (BG) + description: BPP sends its catalog in response to a search request. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_select: + post: + tags: + - Beckn Application Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_init: + post: + tags: + - Beckn Application Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_confirm: + post: + tags: + - Beckn Application Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_track: + post: + tags: + - Beckn Application Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_cancel: + post: + tags: + - Beckn Application Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_update: + post: + tags: + - Beckn Application Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_status: + post: + tags: + - Beckn Application Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_rating: + post: + tags: + - Beckn Application Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_support: + post: + tags: + - Beckn Application Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: "Describes the acknowledgement sent in response to an API call. If the implementation uses HTTP/S, then Ack must be returned in the same session. Every API call to a BPP must be responded to with an Ack whether the BPP intends to respond with a callback or not. This has one property called `status` that indicates the status of the Acknowledgement." + type: object + properties: + status: + type: string + description: "The status of the acknowledgement. If the request passes the validation criteria of the BPP, then this is set to ACK. If a BPP responds with status = `ACK` to a request, it is required to respond with a callback. If the request fails the validation criteria, then this is set to NACK. Additionally, if a BPP does not intend to respond with a callback even after the request meets the validation criteria, it should set this value to `NACK`." + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: Describes an additional item offered as a value-addition to a product or service. This does not exist independently in a catalog and is always associated with an item. + type: object + properties: + id: + description: Provider-defined ID of the add-on + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes the direct performer, driver or executor that fulfills an order. It is usually a person. But in some rare cases, it could be a non-living entity like a drone, or a bot. Some examples of agents are Doctor in the healthcare sector, a driver in the mobility sector, or a delivery person in the logistics sector. This object can be set at any stage of the order lifecycle. This can be set at the discovery stage when the BPP wants to provide details on the agent fulfilling the order, like in healthcare, where the doctor's name appears during search. This object can also used to search for a particular person that the customer wants fulfilling an order. Sometimes, this object gets instantiated after the order is confirmed, like in the case of on-demand taxis, where the driver is assigned after the user confirms the ride." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: "Describes the billing details of an entity.
This has properties like name,organization,address,email,phone,time,tax_number, created_at,updated_at" + type: object + properties: + name: + description: Name of the billable entity + type: string + organization: + description: Details of the organization being billed. + allOf: + - $ref: "#/components/schemas/Organization" + address: + description: The address of the billable entity + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address where the bill is sent to + type: string + format: email + phone: + description: Phone number of the billable entity + type: string + time: + description: Details regarding the billing period + allOf: + - $ref: "#/components/schemas/Time" + tax_id: + description: ID of the billable entity as recognized by the taxation authority + type: string + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the buyer + type: string + format: date-time + cancelled_by: + type: string + enum: + - CONSUMER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + CancellationTerm: + description: Describes the cancellation terms of an item or an order. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes the products or services offered by a BPP. This is typically sent as the response to a search intent from a BAP. The payment terms, offers and terms of fulfillment supported by the BPP can also be included here. The BPP can show hierarchical nature of products/services in its catalog using the parent_category_id in categories. The BPP can also send a ttl (time to live) in the context which is the duration for which a BAP can cache the catalog and use the cached catalog.
This has properties like bbp/descriptor,bbp/categories,bbp/fulfillments,bbp/payments,bbp/offers,bbp/providers and exp
This is used in the following situations.
  • This is typically used in the discovery stage when the BPP sends the details of the products and services it offers as response to a search intent from the BAP.
" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: A label under which a collection of items can be grouped. + type: object + properties: + id: + description: ID of the category + type: string + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular region of a specified radius centered at a specified GPS coordinate. + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + description: Name of the city + type: string + code: + description: City code + type: string + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: "Every API call in beckn protocol has a context. It provides a high-level overview to the receiver about the nature of the intended transaction. Typically, it is the BAP that sets the transaction context based on the consumer's location and action on their UI. But sometimes, during unsolicited callbacks, the BPP also sets the transaction context but it is usually the same as the context of a previous full-cycle, request-callback interaction between the BAP and the BPP. The context object contains four types of fields.
  1. Demographic information about the transaction using fields like `domain`, `country`, and `region`.
  2. Addressing details like the sending and receiving platform's ID and API URL.
  3. Interoperability information like the protocol version that implemented by the sender and,
  4. Transaction details like the method being called at the receiver's endpoint, the transaction_id that represents an end-to-end user session at the BAP, a message ID to pair requests with callbacks, a timestamp to capture sending times, a ttl to specifiy the validity of the request, and a key to encrypt information if necessary.
This object must be passed in every interaction between a BAP and a BPP. In HTTP/S implementations, it is not necessary to send the context during the synchronous response. However, in asynchronous protocols, the context must be sent during all interactions," + type: object + properties: + domain: + description: Domain code that is relevant to this transaction context + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + description: The Beckn protocol method being called by the sender and executed at the receiver. + type: string + version: + type: string + description: Version of transaction protocol being used by the sender. + bap_id: + description: Subscriber ID of the BAP + allOf: + - description: "A globally unique identifier of the platform, Typically it is the fully qualified domain name (FQDN) of the platform." + type: string + bap_uri: + description: Subscriber URL of the BAP for accepting callbacks from BPPs. + allOf: + - description: The callback URL of the Subscriber. This should necessarily contain the same domain name as set in `subscriber_id``. + type: string + format: uri + bpp_id: + description: Subscriber ID of the BPP + allOf: + - $ref: "#/components/schemas/Context/properties/bap_id/allOf/0" + bpp_uri: + description: Subscriber URL of the BPP for accepting calls from BAPs. + allOf: + - $ref: "#/components/schemas/Context/properties/bap_uri/allOf/0" + transaction_id: + description: "This is a unique value which persists across all API calls from `search` through `confirm`. This is done to indicate an active user session across multiple requests. The BPPs can use this value to push personalized recommendations, and dynamic offerings related to an ongoing transaction despite being unaware of the user active on the BAP." + type: string + format: uuid + message_id: + description: "This is a unique value which persists during a request / callback cycle. Since beckn protocol APIs are asynchronous, BAPs need a common value to match an incoming callback from a BPP to an earlier call. This value can also be used to ignore duplicate messages coming from the BPP. It is recommended to generate a fresh message_id for every new interaction. When sending unsolicited callbacks, BPPs must generate a new message_id." + type: string + format: uuid + timestamp: + description: Time of request generation in RFC3339 format + type: string + format: date-time + key: + description: The encryption public key of the sender + type: string + ttl: + description: The duration in ISO8601 format after timestamp for which this message holds valid + type: string + Country: + description: Describes a country + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + DecimalValue: + description: Describes a numerical value in decimal form + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: "Describes an error object that is returned by a BAP, BPP or BG as a response or callback to an action by another network participant. This object is sent when any request received by a network participant is unacceptable. This object can be sent either during Ack or with the callback." + type: object + properties: + code: + type: string + description: 'Standard error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-005-ERROR-CODES-DRAFT-01.md of this repo"' + paths: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error. Used mainly for logging. Not recommended to be shown to the user. + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to buy or avail a product or a service. The BAP can declare the intent of the consumer containing
  • What they want (A product, service, offer)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of a business. + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + type: string + Region: + description: Describes an arbitrary region of space. The network policy should contain a published list of supported regions by the network. + type: object + properties: + dimensions: + description: "The number of dimensions that are used to describe any point inside that region. The most common dimensionality of a region is 2, that represents an area on a map. There are regions on the map that can be approximated to one-dimensional regions like roads, railway lines, or shipping lines. 3 dimensional regions are rarer, but are gaining popularity as flying drones are being adopted for various fulfillment services." + type: string + enum: + - "1" + - "2" + - "3" + type: + description: "The type of region. This is used to specify the granularity of the region represented by this object. Various examples of two-dimensional region types are city, country, state, district, and so on. The network policy should contain a list of all possible region types supported by the network." + type: string + name: + type: string + description: Name of the region as specified on the map where that region exists. + code: + type: string + description: A standard code representing the region. This should be interpreted in the same way by all network participants. + boundary: + type: string + description: "A string representing the boundary of the region. One-dimensional regions are represented by polylines. Two-dimensional regions are represented by polygons, and three-dimensional regions can represented by polyhedra." + map_url: + type: string + description: The url to the map of the region. This can be a globally recognized map or the one specified by the network policy. + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: "Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations
This has properties like label, time stamp,duration,range, days, schedule" + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Contains tracking information that can be used by the BAP to track the fulfillment of an order in real-time. which is useful for knowing the location of time sensitive deliveries. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required to confirm an order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, to confirm a flight ticket, the airline requires details of the passengers along with information on baggage, identity, in addition to the class of ticket. Similarly, a logistics company may require details on the nature of shipment in order to confirm the shipping. A recruiting firm may require additional details on the applicant in order to confirm a job application. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean From 7c6f30f8ab44ca1dbef610fa88ca0ff3c648cf4b Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Sun, 31 Mar 2024 07:48:00 +0530 Subject: [PATCH 029/102] Fix paths in demo scenarios --- docs/demo_scenarios.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/demo_scenarios.md b/docs/demo_scenarios.md index 7bd5646..f963b21 100644 --- a/docs/demo_scenarios.md +++ b/docs/demo_scenarios.md @@ -17,9 +17,9 @@ Alice wants to book a wellness center appointment and then book a cab to reach t 1. We install a core Beckn network using Beckn ONIX 2. Alice tries to conduct a healthcare booking, but it fails due to layer 2 config not being present -3. We install the layer 2 config for healthcare and successfully complete a healthcare appointment booking +3. We install the layer 2 config for healthcare `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/dhp_1.1.0.yaml` and successfully complete a healthcare appointment booking 4. She tries to book a cab to reach the clinic, but it fails due to the layer 2 for mobility not being present -5. We install the layer 2 config for mobility +5. We install the layer 2 config for mobility `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/mobility_1.1.0.yaml` 6. Now Alice can book a cab and reach the clinic. ## Mobility + Retail @@ -28,18 +28,18 @@ Bob wants to book a cab back home. He wants to buy groceries so he can pick it u 1. We install a core Beckn network using Beckn ONIX 2. Bob tries to book a cab, but it fails due to layer 2 config not being present -3. We install the layer 2 config for mobility and successfully complete the booking +3. We install the layer 2 config for mobility `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/mobility_1.1.0.yaml` and successfully complete the booking 4. He now wants to buy groceries from a shop on the way, but it fails due to the layer 2 for retail not being present -5. We install the layer 2 config for retail +5. We install the layer 2 config for retail `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/retail_1.1.0.yaml` 6. Now Bob can complete the retail order and pick it up on the way home -## Healthcare + Energy + Retail +## Healthcare + Energy Cindy wants to schedule a wellness clinic visit, find charging stations near the clinic to get her bike charged while she is attending her appointment 1. We install a core Beckn network using Beckn ONIX 2. Cindy tries to book a wellness clinic appointment. It fails due to healthcare layer 2 being missing -3. We install the layer 2 config for healthcare and Cindy can successfully book the appointment +3. We install the layer 2 config for healthcare `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/dhp_1.1.0.yaml` and Cindy can successfully book the appointment 4. Now she wants to find charging stations near the clinic, but it fails as energy layer 2 config is absent. -5. We install the layer 2 config for energy +5. We install the layer 2 config for energy `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/uei_charging_1.1.0.yaml` 6. Now Cindy can find charging stations near the clinic where she can drop the bike and have it charged while finishing her appointment From 2f22e01a32787ebbed4717653408a1d5ce2790fa Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Mon, 1 Apr 2024 21:28:19 +0530 Subject: [PATCH 030/102] Fixed code to update networks onix.json file --- .../config/networks/onix.json-sample | 11 +++ install/scripts/update_gateway_details.sh | 70 +++++++++++++------ 2 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 install/gateway_data/config/networks/onix.json-sample diff --git a/install/gateway_data/config/networks/onix.json-sample b/install/gateway_data/config/networks/onix.json-sample new file mode 100644 index 0000000..f89e7f9 --- /dev/null +++ b/install/gateway_data/config/networks/onix.json-sample @@ -0,0 +1,11 @@ +{ + "core_version" : "1.1.0", + "registry_id": "REGISTRY_ID..LREG", + "search_provider_id" : "GATEWAY_ID", + "self_registration_supported": true, + "subscription_needed_post_registration" : true, + "base_url": "REGISTRY_URL", + "registry_url" : "REGISTRY_URL/subscribers", + "extension_package": "in.succinct.beckn.boc", + "wild_card" : "" +} \ No newline at end of file diff --git a/install/scripts/update_gateway_details.sh b/install/scripts/update_gateway_details.sh index 49ba577..f6436e3 100755 --- a/install/scripts/update_gateway_details.sh +++ b/install/scripts/update_gateway_details.sh @@ -2,10 +2,20 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" source $SCRIPT_DIR/get_container_details.sh -gateway_url=gateway +gateway_id=gateway gateway_port=4030 protocol=http reg_url=http://$1:3030/subscribers/lookup +registry_id=registry +registry_url=http://registry:3030 + +update_network_json(){ + cp $SCRIPT_DIR/../gateway_data/config/networks/onix.json-sample $SCRIPT_DIR/../gateway_data/config/networks/onix.json + networks_config_file="$SCRIPT_DIR/../gateway_data/config/networks/onix.json" + tmp_file=$(mktemp "tempfile.XXXXXXXXXX") + sed " s|GATEWAY_ID|$gateway_id|g; s|REGISTRY_ID|$registry_id|g; s|REGISTRY_URL|$registry_url|g" "$networks_config_file" > "$tmp_file" + mv "$tmp_file" "$networks_config_file" +} get_details_registry() { # Make the curl request and store the output in a variable @@ -36,42 +46,62 @@ update_gateway_config() { config_file="$SCRIPT_DIR/../gateway_data/config/swf.properties" tmp_file=$(mktemp "tempfile.XXXXXXXXXX") - sed " s|SUBSCRIBER_ID|$gateway_url|g; s|SIGNING_PUBLIC_KEY|$signing_public_key|g; s|ENCRYPTION_PUBLIC_KEY|$encr_public_key|g; s|GATEWAY_URL|$gateway_url|g; s|GATEWAY_PORT|$gateway_port|g; s|PROTOCOL|$protocol|g; s|REGISTRY_URL|$subscriber_url|g" "$config_file" > "$tmp_file" + #sed " s|SUBSCRIBER_ID|$gateway_id|g; s|SIGNING_PUBLIC_KEY|$signing_public_key|g; s|ENCRYPTION_PUBLIC_KEY|$encr_public_key|g; s|GATEWAY_URL|$gateway_id|g; s|GATEWAY_PORT|$gateway_port|g; s|PROTOCOL|$protocol|g; s|REGISTRY_URL|$subscriber_url|g" "$config_file" > "$tmp_file" + sed " s|SUBSCRIBER_ID|$gateway_id|g; s|GATEWAY_URL|$gateway_id|g; s|GATEWAY_PORT|$gateway_port|g; s|PROTOCOL|$protocol|g; s|REGISTRY_URL|$subscriber_url|g" "$config_file" > "$tmp_file" mv "$tmp_file" "$config_file" + update_network_json } -if [[ $1 == https://* ]]; then - reg_url=$1/subscribers/lookup - get_details_registry $reg_url -else - service_name=$1 - if [[ $(uname -s) == 'Darwin' ]]; then - ip=localhost - elif [[ $(systemd-detect-virt) == 'wsl' ]]; then - ip=$(hostname -I | awk '{print $1}') - else - ip=$(get_container_ip $service_name) +# if [[ $1 == https://* ]]; then +# reg_url=$1/subscribers/lookup +# get_details_registry $reg_url +# else +# service_name=$1 +# if [[ $(uname -s) == 'Darwin' ]]; then +# ip=localhost +# elif [[ $(systemd-detect-virt) == 'wsl' ]]; then +# ip=$(hostname -I | awk '{print $1}') +# else +# ip=$(get_container_ip $service_name) +# fi +# reg_url=http://$ip:3030/subscribers/lookup +# get_details_registry $reg_url +# fi + +echo "Registry: $1 && Gateway: $2" + +if [[ $1 ]]; then + registry_url=$1 + if [[ $1 == https://* ]]; then + if [[ $(uname -s) == 'Darwin' ]]; then + registry_id=$(echo "$1" | sed -E 's/https:\/\///') + else + registry_id=$(echo "$1" | sed 's/https:\/\///') + fi + elif [[ $1 == http://* ]]; then + if [[ $(uname -s) == 'Darwin' ]]; then + registry_id=$(echo "$1" | sed -E 's/http:\/\///') + else + registry_id=$(echo "$1" | sed 's/http:\/\///') + fi fi - reg_url=http://$ip:3030/subscribers/lookup - get_details_registry $reg_url fi - if [[ $2 ]]; then if [[ $2 == https://* ]]; then if [[ $(uname -s) == 'Darwin' ]]; then - gateway_url=$(echo "$2" | sed -E 's/https:\/\///') + gateway_id=$(echo "$2" | sed -E 's/https:\/\///') else - gateway_url=$(echo "$2" | sed 's/https:\/\///') + gateway_id=$(echo "$2" | sed 's/https:\/\///') fi gateway_port=443 protocol=https update_gateway_config elif [[ $2 == http://* ]]; then if [[ $(uname -s) == 'Darwin' ]]; then - gateway_url=$(echo "$2" | sed -E 's/http:\/\///') + gateway_id=$(echo "$2" | sed -E 's/http:\/\///') else - gateway_url=$(echo "$2" | sed 's/http:\/\///') + gateway_id=$(echo "$2" | sed 's/http:\/\///') fi gateway_port=80 protocol=http From 42c0a65eb86b06e78fef95351807b5355e9a1a02 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Tue, 2 Apr 2024 11:17:51 +0530 Subject: [PATCH 031/102] Use standard nomenclature for Beckn-ONIX --- README.md | 12 ++--- docs/demo_scenarios.md | 8 +-- docs/demo_walkthrough.md | 10 ++-- docs/user_guide.md | 28 +++++----- install/RELEASE.md | 30 +++++------ install/START_BECKN.md | 88 ++++++++++++++++---------------- install/beckn-onix.sh | 6 +-- install/release/RELEASE_0.1.0.md | 21 +++++--- install/start_beckn.sh | 2 +- install/start_beckn_v2.sh | 6 +-- layer2/docs/demo_healthcare.md | 8 +-- 11 files changed, 113 insertions(+), 106 deletions(-) diff --git a/README.md b/README.md index aec2463..c34f89a 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# ONIX +# Beckn-ONIX -ONIX - Open Network In A Box, is a project designed to effortlessly set up and maintain Beckn network that is scalable, secure and easy to maintain. +Beckn-ONIX - Open Network In A Box, is a project designed to effortlessly set up and maintain Beckn network that is scalable, secure and easy to maintain. -In the install folder, you find a tool that helps install a Beckn network. This tool serves as a valuable resource for developers and network participants eager to explore BECKN protocols or join open networks supported by the BECKN protocol. By simplifying the installation process, ONIX streamlines the onboarding experience. +In the install folder, you find a tool that helps install a Beckn network. This tool serves as a valuable resource for developers and network participants eager to explore Beckn protocols or join open networks supported by the Beckn protocol. By simplifying the installation process, Beckn-ONIX streamlines the onboarding experience. Refer to the following documents for more information: @@ -10,12 +10,12 @@ Refer to the following documents for more information: - [Step by step walkthrough of a demo](./docs/demo_walkthrough.md) - [release notes](./install/RELEASE.md) -Experience the convenience and efficiency of ONIX as you embark on your journey with BECKN protocols and open networks. +Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. ## Note on mandatory Layer 2 Config (Important) -This note will eventually be moved to a proper place in the documentation. It has been put here to alert people who run Beckn ONIX in the meantime. -Beckn-Onix mandates availability of Layer 2 Config for a particular domain before any transactions can be conducted on it. If the layer 2 config is not present, on either the BAP or the BPP, the following error is returned back to the caller. "Config error : Layer 2 config not found." +This note will eventually be moved to a proper place in the documentation. It has been put here to alert people who run Beckn-ONIX in the meantime. +Beckn-ONIX mandates availability of Layer 2 Config for a particular domain before any transactions can be conducted on it. If the layer 2 config is not present, on either the BAP or the BPP, the following error is returned back to the caller. "Config error : Layer 2 config not found." Usually the network facilitators will host the Layer 2 config and provide a way to access it. Currently we have a small script (layer2/download_layer_2_config_bap.sh and layer2/download_layer_2_config_bpp.sh) that can download the layer 2 config from a fixed location and insert it into the docker container that runs the Protocol Server Client. diff --git a/docs/demo_scenarios.md b/docs/demo_scenarios.md index f963b21..c12203b 100644 --- a/docs/demo_scenarios.md +++ b/docs/demo_scenarios.md @@ -2,7 +2,7 @@ The [demo walkthrough](../docs/demo_walkthrough.md) and the accompanying video shows a story where we have the following steps -1. We install a core Beckn network using Beckn ONIX +1. We install a core Beckn network using Beckn-ONIX 2. We try to conduct a retail transaction, but it fails due to layer 2 config not being present 3. We install the layer 2 config for retail from and successfully complete a retail transaction 4. We try to perform a query to find charging station nearby (energy transaction), but it fails due to the layer 2 for energy being absent @@ -15,7 +15,7 @@ In this document we list a few other demo stories where we can show a similar fl Alice wants to book a wellness center appointment and then book a cab to reach the clinic. -1. We install a core Beckn network using Beckn ONIX +1. We install a core Beckn network using Beckn-ONIX 2. Alice tries to conduct a healthcare booking, but it fails due to layer 2 config not being present 3. We install the layer 2 config for healthcare `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/dhp_1.1.0.yaml` and successfully complete a healthcare appointment booking 4. She tries to book a cab to reach the clinic, but it fails due to the layer 2 for mobility not being present @@ -26,7 +26,7 @@ Alice wants to book a wellness center appointment and then book a cab to reach t Bob wants to book a cab back home. He wants to buy groceries so he can pick it up on the way -1. We install a core Beckn network using Beckn ONIX +1. We install a core Beckn network using Beckn-ONIX 2. Bob tries to book a cab, but it fails due to layer 2 config not being present 3. We install the layer 2 config for mobility `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/mobility_1.1.0.yaml` and successfully complete the booking 4. He now wants to buy groceries from a shop on the way, but it fails due to the layer 2 for retail not being present @@ -37,7 +37,7 @@ Bob wants to book a cab back home. He wants to buy groceries so he can pick it u Cindy wants to schedule a wellness clinic visit, find charging stations near the clinic to get her bike charged while she is attending her appointment -1. We install a core Beckn network using Beckn ONIX +1. We install a core Beckn network using Beckn-ONIX 2. Cindy tries to book a wellness clinic appointment. It fails due to healthcare layer 2 being missing 3. We install the layer 2 config for healthcare `https://raw.githubusercontent.com/beckn/beckn-onix/main/layer2/samples/dhp_1.1.0.yaml` and Cindy can successfully book the appointment 4. Now she wants to find charging stations near the clinic, but it fails as energy layer 2 config is absent. diff --git a/docs/demo_walkthrough.md b/docs/demo_walkthrough.md index f26693e..ab9a5b8 100644 --- a/docs/demo_walkthrough.md +++ b/docs/demo_walkthrough.md @@ -19,7 +19,7 @@ Some of the outputs listed below might be different when you run the script for Note: Due to a [known issue](https://github.com/beckn/beckn-onix/issues/11), on certain machines, when the script is run for the first time, it errors out complaining about permission error in accessing docker daemon. Till this issue is fixed, the work around is to exit the terminal and restart the installation in a new terminal. -Please refer to the [Beckn Onix User Guide](./user_guide.md) for detailed explanation of the below steps. +Please refer to the [Beckn-ONIX User Guide](./user_guide.md) for detailed explanation of the below steps. ## Sample deployment diagram @@ -119,7 +119,7 @@ Registry installation successful [Installation Logs] Your Registry setup is complete. You can access your Registry at https://onix-registry.becknprotocol.io -Process complete. Thank you for using Beckn Onix! +Process complete. Thank you for using Beckn-ONIX! ``` ## Install a gateway for the network @@ -231,7 +231,7 @@ Gateway installation successful [Installation Logs] Your Gateway setup is complete. You can access your Gateway at https://onix-gateway.becknprotocol.io -Process complete. Thank you for using Beckn Onix! +Process complete. Thank you for using Beckn-ONIX! ``` ## Install a Beckn Adaptor for the BAP @@ -324,7 +324,7 @@ Protocol server BAP installation successful [Installation Logs] Your BAP setup is complete. You can access your BAP at https://onix-bap.becknprotocol.io -Process complete. Thank you for using Beckn Onix! +Process complete. Thank you for using Beckn-ONIX! ``` @@ -420,7 +420,7 @@ Protocol server BPP installation successful [Installation Logs] Your BPP setup is complete. You can access your BPP at https://onix-bpp.becknprotocol.io -Process complete. Thank you for using Beckn Onix! +Process complete. Thank you for using Beckn-ONIX! ``` ## Change the status of the BAP and BPP on registry to Subscribed diff --git a/docs/user_guide.md b/docs/user_guide.md index 0ca263a..f5ef584 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -1,9 +1,9 @@ -# Beckn ONIX - User Guide +# Beckn-ONIX - User Guide ## Table of Contents - [Introduction](#introduction) -- [Running Beckn ONIX on the cloud](#running-beckn-onix-on-the-cloud) +- [Running Beckn-ONIX on the cloud](#running-beckn-onix-on-the-cloud) - [Sample deployment diagram](#sample-deployment-diagram) - [Overall Prerequisites](#overall-pre-requisites) - [Setting up a new network - Registry](#setting-up-a-new-network---registry) @@ -12,7 +12,7 @@ - [Setting up a BPP Beckn Adapter](#setting-up-a-bpp-beckn-adapter) - [Downloading Layer 2 Configuration for a domain](#downloading-layer-2-configuration-for-a-domain) - [Testing transactions on the network](#testing-transactions-on-the-new-network) -- [Running Beckn ONIX locally](#running-beckn-onix-locally) +- [Running Beckn-ONIX locally](#running-beckn-onix-locally) - [Appendix A - subdomain/domain name configuration](#appendix-a---registering-or-adding-domain-or-subdomains) - [Appendix B - Nginx reverse proxy configuration](#appendix-b---nginx-reverse-proxy-configuration) @@ -24,12 +24,12 @@ This user guide provides all information necessary to setup a Beckn network and There are two primary setups covered in this document. -- A typical production setup with the various Beckn components on different nodes - This is explained in the Running Beckn ONIX on the cloud section. -- A developer all in one setup - This is explained in the Running Beckn ONIX locally section. +- A typical production setup with the various Beckn components on different nodes - This is explained in the Running Beckn-ONIX on the cloud section. +- A developer all in one setup - This is explained in the Running Beckn-ONIX locally section. -## Running Beckn ONIX on the Cloud +## Running Beckn-ONIX on the Cloud -Using Beckn ONIX, we can install a Beckn network on the cloud. This will be similar to a simple production instance of Beckn network. In the sections below, we use Amazon EC2 as an example for VPS provider. The guide can be useful for other cloud environments with simple changes on methods of accessing them etc. In this part of the guide, we explain installation of the four components of Registry, Gateway, BAP and BPP Beckn Adapter on different instances of virtual servers. You can however use the same process with minimal changes to install multiple nodes on the same virtual server (e.g. Registry and Gateway on a single virtual server) +Using Beckn-ONIX, we can install a Beckn network on the cloud. This will be similar to a simple production instance of Beckn network. In the sections below, we use Amazon EC2 as an example for VPS provider. The guide can be useful for other cloud environments with simple changes on methods of accessing them etc. In this part of the guide, we explain installation of the four components of Registry, Gateway, BAP and BPP Beckn Adapter on different instances of virtual servers. You can however use the same process with minimal changes to install multiple nodes on the same virtual server (e.g. Registry and Gateway on a single virtual server) ### Sample deployment diagram @@ -59,7 +59,7 @@ In the Beckn ecosystem, a new network starts with the setting up of the Registry **Installation Steps** -- Clone the Beckn ONIX repository `git clone https://github.com/beckn/beckn-onix.git` +- Clone the Beckn-ONIX repository `git clone https://github.com/beckn/beckn-onix.git` - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to start a new network and install the registry @@ -81,7 +81,7 @@ In the Beckn ecosystem, the role of the Gateway is limited to the discovery phas **Installation Steps** -- Clone the Beckn ONIX repository (git clone https://github.com/beckn/beckn-onix.git) +- Clone the Beckn-ONIX repository (git clone https://github.com/beckn/beckn-onix.git) - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to join an existing network and install the gateway @@ -106,7 +106,7 @@ The BAP (Beckn Application Platform) is the bridge between buyer side applicatio **Installation Steps** -- Clone the Beckn ONIX repository (git clone https://github.com/beckn/beckn-onix.git) +- Clone the Beckn-ONIX repository (git clone https://github.com/beckn/beckn-onix.git) - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to join an existing network and install the BAP. @@ -132,7 +132,7 @@ The BPP (Beckn Provider Platform) is the bridge between the seller side applicat **Installation Steps** -- Clone the Beckn ONIX repository (git clone https://github.com/beckn/beckn-onix.git) +- Clone the Beckn-ONIX repository (git clone https://github.com/beckn/beckn-onix.git) - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to join an existing network and install the BPP. @@ -145,7 +145,7 @@ The BPP (Beckn Provider Platform) is the bridge between the seller side applicat ### Changing subscription status of BAP and BPP at the registry -While the Beckn ONIX installs network participant beckn adapter as well as registers them with the Registry, they need to be manually put to the 'Subscribed' status. Its only then that they can transact. In real networks, the network facilitator might require additional documentation or validation before transitioning the BAP/BPP to the Subscribed state. When we are setting up the entire network ourselves, we do this task ourselves. +While the Beckn-ONIX installs network participant beckn adapter as well as registers them with the Registry, they need to be manually put to the 'Subscribed' status. Its only then that they can transact. In real networks, the network facilitator might require additional documentation or validation before transitioning the BAP/BPP to the Subscribed state. When we are setting up the entire network ourselves, we do this task ourselves. **Steps** @@ -156,7 +156,7 @@ While the Beckn ONIX installs network participant beckn adapter as well as regis ### Downloading Layer 2 Configuration for a domain -With Beckn network setup by ONIX, we have a core network with all required network participants. However we cannot still do any transactions on this network. In order to do transactions, we need the Layer 2 Config file for the domain in which we want to transact. Layer 2 configuration files contain +With Beckn network setup by Beckn-ONIX, we have a core network with all required network participants. However we cannot still do any transactions on this network. In order to do transactions, we need the Layer 2 Config file for the domain in which we want to transact. Layer 2 configuration files contain - rules and policies agreed upon by entities operating in the domain through working group and other consultations - rules and policies required by the network facilitator @@ -176,7 +176,7 @@ Currently the layer-2 config are per domain, though this might change with futur - We can use postman collection for the specific domain to test end to end communication on the domain. Some sample postman collections for testing are [present here](https://github.com/beckn/beckn-sandbox/tree/main/artefacts) - When running postman collection from the buyer side, the base url to which the requests are sent should be the client side endpoint of the BAP Beckn Adapter instance. (e.g https://onix-bap-client.becknprotocol.io) -## Running Beckn ONIX locally +## Running Beckn-ONIX locally - In order for people new to Beckn who want to try out Beckn on their own machine, a simple one click installer has been written. Currently it can be installed by running the `start_beckn.sh` script present in the installfolder. In the next release, this will be integrated with the main script and the `start_beckn.sh` script deprecated. An all in one installation has preconfigured values for variables and so pretty much does not ask for any input. diff --git a/install/RELEASE.md b/install/RELEASE.md index 7fb2bd6..d98a18f 100644 --- a/install/RELEASE.md +++ b/install/RELEASE.md @@ -2,9 +2,9 @@ ### Objective -ONIX - Open Network In A Box. This install utility is designed to effortlessly set up all BECKN components on a machine using a one-click installer. This tool serves as a valuable resource for developers and network participants eager to explore BECKN protocols or join open networks supported by the BECKN protocol. By simplifying the installation process, ONIX streamlines the onboarding experience. +Beckn-ONIX - Open Network In A Box. This install utility is designed to effortlessly set up all Beckn components on a machine using a one-click installer. This tool serves as a valuable resource for developers and network participants eager to explore Beckn protocols or join open networks supported by the Beckn protocol. By simplifying the installation process, Beckn-ONIX streamlines the onboarding experience. -Experience the convenience and efficiency of ONIX as you embark on your journey with BECKN protocols and open networks. +Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. | Version | Release Date | | ------------------------------------------------------------------------------------------ | ------------ | @@ -14,9 +14,9 @@ Experience the convenience and efficiency of ONIX as you embark on your journey ### New Features -- This release focuses on enabling the installation of individual components with user-provided configurations. -- It extends support to the Windows operating system, specifically Windows 10. -- Additionally, it now supports the Mac operating system. +- This release focuses on enabling the installation of individual components with user-provided configurations. +- It extends support to the Windows operating system, specifically Windows 10. +- Additionally, it now supports the Mac operating system. This release is specifically designed to facilitate the deployment of individual components, offering users the flexibility to customize configurations. Furthermore, it ensures seamless compatibility with both Windows and Mac operating systems. @@ -24,28 +24,28 @@ For a comprehensive summary of the features, refer [here](https://github.com/bec ### Enhancements -- Support for Windows operating system. -- Support for Mac operating system. -- Can be used to install specific components with custom configuration. +- Support for Windows operating system. +- Support for Mac operating system. +- Can be used to install specific components with custom configuration. ### Bug Fixes -- None +- None ### Known Issues -- None +- None ### Limitations -- The current installer is tested only for Linux (Ubuntu) / Windows (windows 10) / Mac, it might support other flavors also. -- The current version supports only vertical scaling, horizontal scaling (ECS / EKS) is planned for an upcoming release -- When installing individual components, registration with the registry has to be done manually, this is explicitly done to avoid confusion and to prevent the network from incorrect or wrong registrations. +- The current installer is tested only for Linux (Ubuntu) / Windows (windows 10) / Mac, it might support other flavors also. +- The current version supports only vertical scaling, horizontal scaling (ECS / EKS) is planned for an upcoming release +- When installing individual components, registration with the registry has to be done manually, this is explicitly done to avoid confusion and to prevent the network from incorrect or wrong registrations. ### Upcoming Version -- Support for horizontal scaling using Elastic Kubernetes Cluster. +- Support for horizontal scaling using Elastic Kubernetes Cluster. ### Release Date -- 2024-03-01 +- 2024-03-01 diff --git a/install/START_BECKN.md b/install/START_BECKN.md index b7e3b13..6853806 100644 --- a/install/START_BECKN.md +++ b/install/START_BECKN.md @@ -1,4 +1,4 @@ -# ONIX Setup Script +# Beckn-ONIX Setup Script ## Overview @@ -8,84 +8,84 @@ This shell script, `start_beckn_v2.sh`, automates the setup of Beckn components, 1. **Clone the Repository:** - ```bash - git clone -b main https://github.com/beckn/onix.git - ``` + ```bash + git clone -b main https://github.com/beckn/onix.git + ``` 2. **Navigate to the Script Directory:** - ```bash - cd onix/install - ``` + ```bash + cd onix/install + ``` 3. **Run the Setup Script:** - ```bash - ./start_beckn_v2.sh - ``` + ```bash + ./start_beckn_v2.sh + ``` - The script will guide you through the installation. + The script will guide you through the installation. ## Installation Sequence - Design 1. **Install Required Packages:** It will install Docker, Docker-Compose, and jq packages which are required for this setup. - ```bash - ./package_manager.sh - ``` + ```bash + ./package_manager.sh + ``` 2. **Install Registry Service:** - ```bash - ./start_container registry - ``` + ```bash + ./start_container registry + ``` 3. **Install Gateway Service:** - ```bash - ./update_gateway_details.sh registry - ./start_container gateway - ./register_gateway.sh - ``` + ```bash + ./update_gateway_details.sh registry + ./start_container gateway + ./register_gateway.sh + ``` 4. **Start Supporting Services:** - - MongoDB - - RabbitMQ - - Redis + - MongoDB + - RabbitMQ + - Redis - ```bash - ./start_support_services - ``` + ```bash + ./start_support_services + ``` 5. **Install Protocol Server for BAP:** - ```bash - ./update_bap_config.sh - ./start_container "bap-client" - ./start_container "bap-network" - ``` + ```bash + ./update_bap_config.sh + ./start_container "bap-client" + ./start_container "bap-network" + ``` 6. **Install Sandbox:** - ```bash - ./start_container "sandbox-api" - ``` + ```bash + ./start_container "sandbox-api" + ``` 7. **Install Webhook:** - ```bash - ./start_container "sandbox-webhook" - ``` + ```bash + ./start_container "sandbox-webhook" + ``` 8. **Install Protocol Server for BPP:** - ```bash - ./update_bpp_config.sh - ./start_container "bpp-client" - ./start_container "bpp-network" - ``` + ```bash + ./update_bpp_config.sh + ./start_container "bpp-client" + ./start_container "bpp-network" + ``` ## Post-Installation Details diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 79a063b..6481761 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -148,11 +148,11 @@ install_bpp_protocol_server(){ # MAIN SCRIPT STARTS HERE #!/bin/bash -echo "Welcome to Beckn Onix!" +echo "Welcome to Beckn-ONIX!" if [ -f ./onix_ascii_art.txt ]; then cat ./onix_ascii_art.txt else - echo "[Display Beckn ONIX ASCII Art]" + echo "[Display Beckn-ONIX ASCII Art]" fi echo "Beckn ONIX is a platform that helps you quickly launch and configure beckn-enabled networks." @@ -277,6 +277,6 @@ else exit 1 fi -echo "Process complete. Thank you for using Beckn Onix!" +echo "Process complete. Thank you for using Beckn-ONIX!" diff --git a/install/release/RELEASE_0.1.0.md b/install/release/RELEASE_0.1.0.md index e8fc5bd..25e004c 100644 --- a/install/release/RELEASE_0.1.0.md +++ b/install/release/RELEASE_0.1.0.md @@ -1,18 +1,20 @@ # Release Notes -## ONIX Version 0.1.0 (2024-02-16) +## Beckn-ONIX Version 0.1.0 (2024-02-16) ### Objective -ONIX - Open Network In A Box, is a utility designed to effortlessly set up all BECKN components on a machine using a one-click installer. This tool serves as a valuable resource for developers and network participants eager to explore BECKN protocols or join open networks supported by the BECKN protocol. By simplifying the installation process, ONIX streamlines the onboarding experience. -The current version installs all components automatically without requiring user input, facilitating a seamless setup process. However, we are committed to further enhancing ONIX's functionality. In the upcoming release, we will introduce the capability to selectively install specific components and accommodate user-provided configurations. +Beckn-ONIX - Open Network In A Box, is a utility designed to effortlessly set up all Beckn components on a machine using a one-click installer. This tool serves as a valuable resource for developers and network participants eager to explore Beckn protocols or join open networks supported by the Beckn protocol. By simplifying the installation process, Beckn-ONIX streamlines the onboarding experience. + +The current version installs all components automatically without requiring user input, facilitating a seamless setup process. However, we are committed to further enhancing Beckn-ONIX's functionality. In the upcoming release, we will introduce the capability to selectively install specific components and accommodate user-provided configurations. For a comprehensive summary of the features, refer [here](https://github.com/beckn/beckn-utilities/milestone/2?closed=1) -Experience the convenience and efficiency of ONIX as you embark on your journey with BECKN protocols and open networks. +Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. ### New Features -- Implemented installation support for the following BECKN components: + +- Implemented installation support for the following Beckn components: - Protocol Server BAP - Protocol Server BPP - Webhook BPP @@ -20,26 +22,31 @@ Experience the convenience and efficiency of ONIX as you embark on your journey - Registry - Gateway - Infrastructure required for the above services - + This release is specifically tailored for deployment on Linux machines, encompassing all aforementioned components with default configurations. ### Enhancements + - None ### Bug Fixes + - None ### Known Issues + - None ### Limitations + - The current installer is tested only for Linux (Ubuntu), it might support other flavors also. - The current version installs all the components with the default configurations. - ### Upcoming Version + - Installation of individual components with user-provided configuration. - Support for Windows and Mac OS will be added. ### Release Date + - 2024-02-16 diff --git a/install/start_beckn.sh b/install/start_beckn.sh index 57c74b4..213f960 100755 --- a/install/start_beckn.sh +++ b/install/start_beckn.sh @@ -25,7 +25,7 @@ start_support_services(){ } # Main script starts here text=" -Welcome to ONIX! +Welcome to Beckn-ONIX! The following components will be installed 1. MongoDB, RabbitMQ and Redis diff --git a/install/start_beckn_v2.sh b/install/start_beckn_v2.sh index 069d949..d91c377 100755 --- a/install/start_beckn_v2.sh +++ b/install/start_beckn_v2.sh @@ -187,7 +187,7 @@ The following components will be installed # Main script starts here bash scripts/banner.sh -echo "Welcome to ONIX" +echo "Welcome to Beckn-ONIX" echo "$text" read -p "${GREEN}Do you want to install all the components on the local system? (Y/n): ${NC}" install_all @@ -306,11 +306,11 @@ else ;; 7) - echo "Exiting ONIX" + echo "Exiting Beckn-ONIX" exit 0 ;; *) - echo "Invalid choice. Exiting ONIX." + echo "Invalid choice. Exiting Beckn-ONIX." exit 1 ;; esac diff --git a/layer2/docs/demo_healthcare.md b/layer2/docs/demo_healthcare.md index a9d5ff5..2abe50b 100644 --- a/layer2/docs/demo_healthcare.md +++ b/layer2/docs/demo_healthcare.md @@ -1,10 +1,10 @@ -# Creating a Beckn network for healthcare using Beckn ONIX and transacting on it. +# Creating a Beckn network for healthcare using Beckn-ONIX and transacting on it. ## Introduction -[Beckn](https://becknprotocol.io/) as a protocol allows creation of decentralised commerce network across many domains. Healthcare is one of them. Beckn ONIX is a project aimed at easing setup and maintanence of Beckn network for different domains. It provides utilities to quickly setup the core Beckn network as well as provides tools to enable domain specific transactions. The latter is achieved through the use of layer 2 configuration files. +[Beckn](https://becknprotocol.io/) as a protocol allows creation of decentralised commerce network across many domains. Healthcare is one of them. Beckn-ONIX is a project aimed at easing setup and maintanence of Beckn network for different domains. It provides utilities to quickly setup the core Beckn network as well as provides tools to enable domain specific transactions. The latter is achieved through the use of layer 2 configuration files. -The [Beckn ONIX User Guide](./user_guide.md) provides an overall understanding of setup of the core Beckn network as well as download and ingestion of Layer 2 configuration files. The [step by step demo](./demo_walkthrough.md) walks through one such installation in great detail. The layer 2 configurations illustrated in that demo belong to the retail and energy domain. +The [Beckn-ONIX User Guide](./user_guide.md) provides an overall understanding of setup of the core Beckn network as well as download and ingestion of Layer 2 configuration files. The [step by step demo](./demo_walkthrough.md) walks through one such installation in great detail. The layer 2 configurations illustrated in that demo belong to the retail and energy domain. ## Healthcare usecases on Beckn network @@ -139,4 +139,4 @@ anyOf: ## Conclusion -Multitide DHP related use cases can be implemented on the Beckn networks. The process Beckn ONIX follows to create core Beckn network and allowing participants to download layer 2 configuration is identical across domains. Layer 2 configuration captures both domain policies and rules as well as those enforced by the network facilitators. Layer 2 configuration are both prescriptive as well as mandatory. The mandatory rules and policies can be written on top of the core spec within the layer 2 config and can be enforced by incorporating a validator in the workflow. +Multitide DHP related use cases can be implemented on the Beckn networks. The process Beckn-ONIX follows to create core Beckn network and allowing participants to download layer 2 configuration is identical across domains. Layer 2 configuration captures both domain policies and rules as well as those enforced by the network facilitators. Layer 2 configuration are both prescriptive as well as mandatory. The mandatory rules and policies can be written on top of the core spec within the layer 2 config and can be enforced by incorporating a validator in the workflow. From aefe509160fd5fce64985af473db53be9f8feecb Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Tue, 2 Apr 2024 13:16:27 +0530 Subject: [PATCH 032/102] Add FAQ --- README.md | 31 +++++--------------------- docs/contribution.md | 19 ++++++++++++++++ docs/faq.md | 28 +++++++++++++++++++++++ docs/notes/mandatory_layer_2_config.md | 22 ++++++++++++++++++ 4 files changed, 75 insertions(+), 25 deletions(-) create mode 100644 docs/contribution.md create mode 100644 docs/faq.md create mode 100644 docs/notes/mandatory_layer_2_config.md diff --git a/README.md b/README.md index c34f89a..f835321 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,17 @@ # Beckn-ONIX -Beckn-ONIX - Open Network In A Box, is a project designed to effortlessly set up and maintain Beckn network that is scalable, secure and easy to maintain. +Beckn ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. This effort is also aimed at inviting contributions from the community to create secure, reliable builds for production environments. -In the install folder, you find a tool that helps install a Beckn network. This tool serves as a valuable resource for developers and network participants eager to explore Beckn protocols or join open networks supported by the Beckn protocol. By simplifying the installation process, Beckn-ONIX streamlines the onboarding experience. +Within the install folder you will find a `beckn-onix.sh` file which is an installer that helps create a multi-node Beckn network using reference implementations Refer to the following documents for more information: - [User Guide](./docs/user_guide.md) -- [Step by step walkthrough of a demo](./docs/demo_walkthrough.md) +- [Step by step walkthrough of a demo installation](./docs/demo_walkthrough.md) +- [Frequently asked questions (FAQ)](./docs/faq.md) - [release notes](./install/RELEASE.md) Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. -## Note on mandatory Layer 2 Config (Important) - -This note will eventually be moved to a proper place in the documentation. It has been put here to alert people who run Beckn-ONIX in the meantime. -Beckn-ONIX mandates availability of Layer 2 Config for a particular domain before any transactions can be conducted on it. If the layer 2 config is not present, on either the BAP or the BPP, the following error is returned back to the caller. "Config error : Layer 2 config not found." - -Usually the network facilitators will host the Layer 2 config and provide a way to access it. Currently we have a small script (layer2/download_layer_2_config_bap.sh and layer2/download_layer_2_config_bpp.sh) that can download the layer 2 config from a fixed location and insert it into the docker container that runs the Protocol Server Client. - -If you have the Layer 2 config file with you and not hosted, you can use the following procedure to update it manually. In case you do not have layer 2 config file with you, as developer machine workaround, you can copy the core_version.yaml(e.g. core_1.1.0.yaml) and rename it as the layer 2 config for a domain (e.g. for a domain named retail for core version 1.1.0, retail_1.1.0.yaml). This is strictly not recommended for production networks. - -Process to manually update layer 2 config. - -``` -docker cp "$FILENAME" "$CONTAINER_NAME":"$CONTAINER_PATH/$FILENAME" - -# example -docker cp retail_1.1.0.yaml bap-client:/usr/src/app/schemas/retail_1.1.0.yaml -docker cp retail_1.1.0.yaml bap-network:/usr/src/app/schemas/retail_1.1.0.yaml - -docker cp retail_1.1.0.yaml bpp-client:/usr/src/app/schemas/retail_1.1.0.yaml -docker cp retail_1.1.0.yaml bpp-netork:/usr/src/app/schemas/retail_1.1.0.yaml - -``` +**Note on mandatory Layer 2 Config (Important)** +Please refer to this [note on mandatory layer 2 configuration](./docs/notes/mandatory_layer_2_config.md). diff --git a/docs/contribution.md b/docs/contribution.md new file mode 100644 index 0000000..2c60789 --- /dev/null +++ b/docs/contribution.md @@ -0,0 +1,19 @@ +## Contribution + +We welcome contribution from the community both for Beckn-ONIX project as well as initiatives to add such tools in different production environment. Use the following process to contribute to this project + +### Process to raise issues + +- Check in the [issues](https://github.com/beckn/beckn-onix/issues) section to see if a similar issue or enhancement has been already raised +- If there is an issue already present, use the comment facility in the issue to add your input +- If there is no issue and you feel it needs to be raised, use the New Issue button. A template will be present. Use it to fill the various parts. +- Track the issue you raised and communicate using comments + +### Process to fix issues + +- Once an issue has been raised and validated, any interested contributor can assign it to himself and work on it. +- Use the comment section of the issue to develop any concensus or for clarification +- Use the [forking and raising pull request](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-a-project) guide here for the process of making your change and asking for it to be incorporated in the project +- Use the mentions (@ symbol followed by username e.g. @jjohn) to draw attention to the maintainers of the project. Usually the person committing the last few commits on the main branch is a good candidate to approach +- Once the maintainer has agreed with the changes, he will merge the changes into the right branch based on the branching strategy of the project. +- The issue will be closed after validation. diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000..a57be16 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,28 @@ +## Beckn-ONIX FAQ + +**Q: What is Beckn-ONIX?** +**A:** Beckn ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. + +**Q: Is Beckn-ONIX a protocol? Is Beckn-ONIX a new version of Beckn?** +**A:** No Beckn-ONIX is not a protocol. Beckn-ONIX is not a new version of Beckn. Beckn-ONIX project just helps setup and maintain a Beckn network. This initiative is independent of the evolution of Beckn + +**Q: What components are installed when we setup a Beckn network with Beckn-ONIX?** +**A:** When you setup a new Beckn network using Beckn-ONIX, the reference implementations of [Beckn Registry](https://github.com/beckn/beckn-registry-app), [Beckn Gateway](https://github.com/beckn/beckn-gateway-app), [BAP Beckn Adapter](https://github.com/beckn/protocol-server) and [BPP Beckn Adapter](https://github.com/beckn/protocol-server) + +**Q: Do I need anything more than Beckn-ONIX to do transactions?** +**A:** Yes. Beckn-ONIX only installs the core network components. Refer to the [Sample deployment diagram](./user_guide.md/#sample-deployment-diagram) for a simple illustration of the various components. As you see in that diagram, apart from the core network components, you would need a buyer side application and a seller side application to perform transactions. Typically you will be implementing one or both of these. If you are only implementing one side of it, you can use sample applications or postman as the other application. + +**Q: Do I have to use Beckn-ONIX to install these reference components?** +**A:** No. If you are comfortable you can install the reference implementations of [Beckn Registry](https://github.com/beckn/beckn-registry-app), [Beckn Gateway](https://github.com/beckn/beckn-gateway-app), [BAP Beckn Adapter](https://github.com/beckn/protocol-server) and [BPP Beckn Adapter](https://github.com/beckn/protocol-server) directly from the repositories. Beckn-ONIX makes the tasks easier through guided installation. + +**Q: Do I have to use these reference components to get onto Beckn network? Can I write them myself** +**A:** Sure. As the name suggests, these are just reference components and their objective is to get you started easily. You can however write your own implementation of the Beckn protocol using the tech stack you like. + +**Q: The user guide mentions Nginx for reverse proxy. Can I use any other program as reverse proxy** +**A:** Yes. You can use other programs. The user guide uses Nginx primarily as an example. The instructions to configure the reverse proxy might change. In particular, for the flow we have you might need to identify how to install SSL certificates and how to proxy a request to a port based on the requested URL. + +**Q: Is Beckn-ONIX the best way to setup and manage Beckn network?** +**A:** No. Beckn-ONIX is just one effort to kick start the process of creating tools to aid easy creation and operation of Beckn networks. We want the community to create even better tools for different production environments. + +**Q: How do I contribute to this project?** +**A:** We welcome contributions both to this project as well as initiatives in other production environment. Refer to the [contribution guide](./contribution.md) for more details on the process. diff --git a/docs/notes/mandatory_layer_2_config.md b/docs/notes/mandatory_layer_2_config.md new file mode 100644 index 0000000..db39310 --- /dev/null +++ b/docs/notes/mandatory_layer_2_config.md @@ -0,0 +1,22 @@ +## Note on mandatory Layer 2 Config (Important) + +This note will eventually be moved to a proper place in the documentation. It has been put here to alert people who run Beckn-ONIX in the meantime. +Beckn-ONIX mandates availability of Layer 2 Config for a particular domain before any transactions can be conducted on it. If the layer 2 config is not present, on either the BAP or the BPP, the following error is returned back to the caller. "Config error : Layer 2 config not found." + +Usually the network facilitators will host the Layer 2 config and provide a way to access it. Currently we have a small script (layer2/download_layer_2_config_bap.sh and layer2/download_layer_2_config_bpp.sh) that can download the layer 2 config from a fixed location and insert it into the docker container that runs the Protocol Server Client. + +If you have the Layer 2 config file with you and not hosted, you can use the following procedure to update it manually. In case you do not have layer 2 config file with you, as developer machine workaround, you can copy the core_version.yaml(e.g. core_1.1.0.yaml) and rename it as the layer 2 config for a domain (e.g. for a domain named retail for core version 1.1.0, retail_1.1.0.yaml). This is strictly not recommended for production networks. + +Process to manually update layer 2 config. + +``` +docker cp "$FILENAME" "$CONTAINER_NAME":"$CONTAINER_PATH/$FILENAME" + +# example +docker cp retail_1.1.0.yaml bap-client:/usr/src/app/schemas/retail_1.1.0.yaml +docker cp retail_1.1.0.yaml bap-network:/usr/src/app/schemas/retail_1.1.0.yaml + +docker cp retail_1.1.0.yaml bpp-client:/usr/src/app/schemas/retail_1.1.0.yaml +docker cp retail_1.1.0.yaml bpp-netork:/usr/src/app/schemas/retail_1.1.0.yaml + +``` From 41a69be9a6b81e501faa562172f06b7a9f762d5a Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Tue, 2 Apr 2024 13:23:04 +0530 Subject: [PATCH 033/102] Add FAQ --- README.md | 2 +- docs/demo_walkthrough.md | 6 +++--- docs/faq.md | 2 +- docs/user_guide.md | 2 +- install/beckn-onix.sh | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index f835321..f23a544 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Beckn-ONIX -Beckn ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. This effort is also aimed at inviting contributions from the community to create secure, reliable builds for production environments. +Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. This effort is also aimed at inviting contributions from the community to create secure, reliable builds for production environments. Within the install folder you will find a `beckn-onix.sh` file which is an installer that helps create a multi-node Beckn network using reference implementations diff --git a/docs/demo_walkthrough.md b/docs/demo_walkthrough.md index ab9a5b8..2a61f96 100644 --- a/docs/demo_walkthrough.md +++ b/docs/demo_walkthrough.md @@ -2,7 +2,7 @@ ## Introduction -This document describes setting up of a [Beckn network](https://becknprotocol.io/) with Beckn ONIX and conducting transactions in a couple of domains (retail and energy). The general flow will involve the following steps: +This document describes setting up of a [Beckn network](https://becknprotocol.io/) with Beckn-ONIX and conducting transactions in a couple of domains (retail and energy). The general flow will involve the following steps: - [Setup the prerequisites](#overall-prerequisites) - [Create a new network and install the registry](#create-a-new-network-and-install-the-registry) @@ -63,7 +63,7 @@ cd beckn-onix/install - In the prompt that comes up, choose setting up a new network. ``` -Beckn ONIX is a platform that helps you quickly launch and configure beckn-enabled networks. +Beckn-ONIX is a platform that helps you quickly launch and configure beckn-enabled networks. What would you like to do? 1. Join an existing network @@ -160,7 +160,7 @@ cd beckn-onix/install - In the prompt that comes up, choose joining an existing network. ``` -Beckn ONIX is a platform that helps you quickly launch and configure beckn-enabled networks. +Beckn-ONIX is a platform that helps you quickly launch and configure beckn-enabled networks. What would you like to do? 1. Join an existing network diff --git a/docs/faq.md b/docs/faq.md index a57be16..05fc248 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -1,7 +1,7 @@ ## Beckn-ONIX FAQ **Q: What is Beckn-ONIX?** -**A:** Beckn ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. +**A:** Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. **Q: Is Beckn-ONIX a protocol? Is Beckn-ONIX a new version of Beckn?** **A:** No Beckn-ONIX is not a protocol. Beckn-ONIX is not a new version of Beckn. Beckn-ONIX project just helps setup and maintain a Beckn network. This initiative is independent of the evolution of Beckn diff --git a/docs/user_guide.md b/docs/user_guide.md index f5ef584..377e30d 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -18,7 +18,7 @@ ## Introduction -Beckn ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. This effort is also aimed at inviting contributions from the community to create secure, reliable builds for production environments. +Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. This effort is also aimed at inviting contributions from the community to create secure, reliable builds for production environments. This user guide provides all information necessary to setup a Beckn network and conduct transactions on it. For a better understanding of Beckn and the terminologies associated with the ecosystem, please refer to the [Beckn for Developers site](https://developers.becknprotocol.io/). diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 6481761..a933702 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -155,7 +155,7 @@ else echo "[Display Beckn-ONIX ASCII Art]" fi -echo "Beckn ONIX is a platform that helps you quickly launch and configure beckn-enabled networks." +echo "Beckn-ONIX is a platform that helps you quickly launch and configure beckn-enabled networks." echo -e "\nWhat would you like to do?\n1. Join an existing network\n2. Create new production network\n3. Set up a network on your local machine\n4. Merge multiple networks\n5. Configure Existing Network\n(Press Ctrl+C to exit)" read -p "Enter your choice: " choice From fd46662423239f141ee5b57ea46f6c6889518dd0 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Tue, 2 Apr 2024 22:12:36 +0530 Subject: [PATCH 034/102] Fixed volume mount issue --- install/.gitignore | 4 ++-- install/beckn-onix.sh | 14 +++++++++----- install/docker-compose-v2.yml | 19 ++++++++++++++----- .../gateway_data/config/networks/onix.json | 8 ++++---- .../config/networks/onix.json-sample | 2 +- .../gateway_data/config/swf.properties-sample | 2 +- install/scripts/update_gateway_details.sh | 12 +++++++++--- 7 files changed, 40 insertions(+), 21 deletions(-) diff --git a/install/.gitignore b/install/.gitignore index 38d6f13..7decf9c 100644 --- a/install/.gitignore +++ b/install/.gitignore @@ -7,5 +7,5 @@ protocol-server-data/bap-network.yml protocol-server-data/bpp-client.yml protocol-server-data/bpp-network.yml ENV/.env-generic-client-layer -registry.lock* -gateway.lock* +registry.*db +gateway.*db diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index a933702..f838975 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -47,6 +47,10 @@ update_registry_details() { tmp_file=$(mktemp "tempfile.XXXXXXXXXX") sed "s|REGISTRY_URL|$registry_url|g; s|REGISTRY_PORT|$registry_port|g; s|PROTOCOL|$protocol|g" "$config_file" > "$tmp_file" mv "$tmp_file" "$config_file" + docker volume create registry_data_volume + docker run --rm -v $SCRIPT_DIR/../registry_data/config:/source -v registry_data_volume:/target busybox cp /source/{envvars,logger.properties,swf.properties} /target/ + docker volume create registry_database_volume + docker run --rm -v $SCRIPT_DIR/../registry_data/database:/source -v registry_database_volume:/target busybox cp /source/db.txt /target/db.txt } # Function to start the MongoDB, Redis, and RabbitMQ Services @@ -77,11 +81,11 @@ install_gateway() { echo "Registering Gateway in the registry" sleep 10 - if [[ $1 && $2 ]]; then - bash scripts/register_gateway.sh $2 - else - bash scripts/register_gateway.sh - fi + # if [[ $1 && $2 ]]; then + # bash scripts/register_gateway.sh $2 + # else + # bash scripts/register_gateway.sh + # fi echo " " echo "Gateway installation successful" } diff --git a/install/docker-compose-v2.yml b/install/docker-compose-v2.yml index 79981a8..fde4301 100644 --- a/install/docker-compose-v2.yml +++ b/install/docker-compose-v2.yml @@ -11,8 +11,8 @@ services: - 3030:3030 restart: unless-stopped volumes: - - ./registry_data/config/swf.properties:/registry/overrideProperties/config/swf.properties - - ./registry_data/database:/registry/database + - registry_data_volume:/registry/overrideProperties/config + - registry_data_volume:/registry/database gateway: image: fidedocker/gateway @@ -24,9 +24,8 @@ services: - 4030:4030 restart: unless-stopped volumes: - - ./gateway_data/config/swf.properties:/gateway/overrideProperties/config/swf.properties - - ./gateway_data/config/networks:/gateway/overrideProperties/config/networks #Update varibales post demo - - ./gateway_data/database:/gateway/database + - gateway_data_volume:/gateway/overrideProperties/config + - gateway_database_volume:/gateway/database bap-client: image: fidedocker/protocol-server @@ -109,3 +108,13 @@ networks: beckn_network: driver: bridge +volumes: + registry_data_volume: + name: registry_data_volume + registry_database_volume: + name: registry_database_volume + gateway_data_volume: + name: gateway_data_volume + gateway_database_volume: + name: gateway_database_volume + diff --git a/install/gateway_data/config/networks/onix.json b/install/gateway_data/config/networks/onix.json index dfc401b..2bb446a 100644 --- a/install/gateway_data/config/networks/onix.json +++ b/install/gateway_data/config/networks/onix.json @@ -1,11 +1,11 @@ { "core_version" : "1.1.0", - "registry_id": "registry-energy.becknprotocol.io..LREG", - "search_provider_id" : "gateway-energy.becknprotocol.io", + "registry_id": "registry-dev.becknprotocol.io..LREG", + "search_provider_id" : "gateway-dev.becknprotocol.io", "self_registration_supported": true, "subscription_needed_post_registration" : true, - "base_url": "https://registry-energy.becknprotocol.io", - "registry_url" : "https://registry-energy.becknprotocol.io/subscribers", + "base_url": "https://registry-dev.becknprotocol.io", + "registry_url" : "https://registry-dev.becknprotocol.io/subscribers", "extension_package": "in.succinct.beckn.boc", "wild_card" : "" } \ No newline at end of file diff --git a/install/gateway_data/config/networks/onix.json-sample b/install/gateway_data/config/networks/onix.json-sample index f89e7f9..8990d63 100644 --- a/install/gateway_data/config/networks/onix.json-sample +++ b/install/gateway_data/config/networks/onix.json-sample @@ -8,4 +8,4 @@ "registry_url" : "REGISTRY_URL/subscribers", "extension_package": "in.succinct.beckn.boc", "wild_card" : "" -} \ No newline at end of file +} diff --git a/install/gateway_data/config/swf.properties-sample b/install/gateway_data/config/swf.properties-sample index 0c4c6e2..20b8a50 100644 --- a/install/gateway_data/config/swf.properties-sample +++ b/install/gateway_data/config/swf.properties-sample @@ -40,4 +40,4 @@ in.succinct.beckn.gateway.public_key_id=SUBSCRIBER_ID.k1 in.succinct.onet.country.iso.3=IND in.succinct.onet.country.iso.2=IN -in.succinct.onet.name=onix \ No newline at end of file +in.succinct.onet.name=onix diff --git a/install/scripts/update_gateway_details.sh b/install/scripts/update_gateway_details.sh index f6436e3..9cdd8c3 100755 --- a/install/scripts/update_gateway_details.sh +++ b/install/scripts/update_gateway_details.sh @@ -15,6 +15,7 @@ update_network_json(){ tmp_file=$(mktemp "tempfile.XXXXXXXXXX") sed " s|GATEWAY_ID|$gateway_id|g; s|REGISTRY_ID|$registry_id|g; s|REGISTRY_URL|$registry_url|g" "$networks_config_file" > "$tmp_file" mv "$tmp_file" "$networks_config_file" + docker run --rm -v $SCRIPT_DIR/../gateway_data/config:/source -v gateway_data_volume:/target busybox cp -r /source/networks /target/ } get_details_registry() { @@ -38,9 +39,9 @@ get_details_registry() { update_gateway_config() { # Print the extracted keys - echo "Signing Public Key: $signing_public_key" - echo "Encryption Public Key: $encr_public_key" - echo "URL $subscriber_url" + # echo "Signing Public Key: $signing_public_key" + # echo "Encryption Public Key: $encr_public_key" + # echo "URL $subscriber_url" cp $SCRIPT_DIR/../gateway_data/config/swf.properties-sample $SCRIPT_DIR/../gateway_data/config/swf.properties config_file="$SCRIPT_DIR/../gateway_data/config/swf.properties" @@ -49,7 +50,12 @@ update_gateway_config() { #sed " s|SUBSCRIBER_ID|$gateway_id|g; s|SIGNING_PUBLIC_KEY|$signing_public_key|g; s|ENCRYPTION_PUBLIC_KEY|$encr_public_key|g; s|GATEWAY_URL|$gateway_id|g; s|GATEWAY_PORT|$gateway_port|g; s|PROTOCOL|$protocol|g; s|REGISTRY_URL|$subscriber_url|g" "$config_file" > "$tmp_file" sed " s|SUBSCRIBER_ID|$gateway_id|g; s|GATEWAY_URL|$gateway_id|g; s|GATEWAY_PORT|$gateway_port|g; s|PROTOCOL|$protocol|g; s|REGISTRY_URL|$subscriber_url|g" "$config_file" > "$tmp_file" mv "$tmp_file" "$config_file" + docker volume create gateway_data_volume + docker volume create gateway_database_volume + docker run --rm -v $SCRIPT_DIR/../gateway_data/config:/source -v gateway_data_volume:/target busybox cp /source/{envvars,logger.properties,swf.properties} /target/ + docker run --rm -v $SCRIPT_DIR/../registry_data/database:/source -v gateway_database_volume:/target busybox cp /source/db.txt /target/db.txt update_network_json + } # if [[ $1 == https://* ]]; then From ffeb0209fa2498ab64550a0ca6d708c22e9e3093 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Tue, 2 Apr 2024 22:50:46 +0530 Subject: [PATCH 035/102] Fixed volume mount issue --- install/.gitignore | 3 +++ install/beckn-onix.sh | 2 +- install/gateway_data/config/swf.properties-sample | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/install/.gitignore b/install/.gitignore index 7decf9c..6a5de0f 100644 --- a/install/.gitignore +++ b/install/.gitignore @@ -1,7 +1,10 @@ docker_data gateway_data/config/swf.properties +gateway_data/config/networks/onix.json registry_data/config/swf.properties .vscode +gateway_data/config/networks/onix.json +gateway_data/database/standalone.mv.db protocol-server-data/bap-client.yml protocol-server-data/bap-network.yml protocol-server-data/bpp-client.yml diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index f838975..e95574e 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -51,7 +51,7 @@ update_registry_details() { docker run --rm -v $SCRIPT_DIR/../registry_data/config:/source -v registry_data_volume:/target busybox cp /source/{envvars,logger.properties,swf.properties} /target/ docker volume create registry_database_volume docker run --rm -v $SCRIPT_DIR/../registry_data/database:/source -v registry_database_volume:/target busybox cp /source/db.txt /target/db.txt - + docker rmi busybox } # Function to start the MongoDB, Redis, and RabbitMQ Services start_support_services(){ diff --git a/install/gateway_data/config/swf.properties-sample b/install/gateway_data/config/swf.properties-sample index 20b8a50..64c1c08 100644 --- a/install/gateway_data/config/swf.properties-sample +++ b/install/gateway_data/config/swf.properties-sample @@ -1,6 +1,6 @@ swf.load.complete.config.tables.if.count.less.than=500 swf.user.password.encrypted=false -swf.plugins.background.core.workers.numThreads=2 +swf.plugins.background.core.workers.numThreads=1 swf.application.authentication.required=false swf.encryption.support=false From 92e2cc9189fca3c6e06a9d8a99eda54a31722681 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 3 Apr 2024 09:56:24 +0530 Subject: [PATCH 036/102] Fixes #35 #36 --- docs/faq.md | 9 +++++++++ docs/user_guide.md | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/docs/faq.md b/docs/faq.md index 05fc248..c341395 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -1,28 +1,37 @@ ## Beckn-ONIX FAQ **Q: What is Beckn-ONIX?** + **A:** Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. **Q: Is Beckn-ONIX a protocol? Is Beckn-ONIX a new version of Beckn?** + **A:** No Beckn-ONIX is not a protocol. Beckn-ONIX is not a new version of Beckn. Beckn-ONIX project just helps setup and maintain a Beckn network. This initiative is independent of the evolution of Beckn **Q: What components are installed when we setup a Beckn network with Beckn-ONIX?** + **A:** When you setup a new Beckn network using Beckn-ONIX, the reference implementations of [Beckn Registry](https://github.com/beckn/beckn-registry-app), [Beckn Gateway](https://github.com/beckn/beckn-gateway-app), [BAP Beckn Adapter](https://github.com/beckn/protocol-server) and [BPP Beckn Adapter](https://github.com/beckn/protocol-server) **Q: Do I need anything more than Beckn-ONIX to do transactions?** + **A:** Yes. Beckn-ONIX only installs the core network components. Refer to the [Sample deployment diagram](./user_guide.md/#sample-deployment-diagram) for a simple illustration of the various components. As you see in that diagram, apart from the core network components, you would need a buyer side application and a seller side application to perform transactions. Typically you will be implementing one or both of these. If you are only implementing one side of it, you can use sample applications or postman as the other application. **Q: Do I have to use Beckn-ONIX to install these reference components?** + **A:** No. If you are comfortable you can install the reference implementations of [Beckn Registry](https://github.com/beckn/beckn-registry-app), [Beckn Gateway](https://github.com/beckn/beckn-gateway-app), [BAP Beckn Adapter](https://github.com/beckn/protocol-server) and [BPP Beckn Adapter](https://github.com/beckn/protocol-server) directly from the repositories. Beckn-ONIX makes the tasks easier through guided installation. **Q: Do I have to use these reference components to get onto Beckn network? Can I write them myself** + **A:** Sure. As the name suggests, these are just reference components and their objective is to get you started easily. You can however write your own implementation of the Beckn protocol using the tech stack you like. **Q: The user guide mentions Nginx for reverse proxy. Can I use any other program as reverse proxy** + **A:** Yes. You can use other programs. The user guide uses Nginx primarily as an example. The instructions to configure the reverse proxy might change. In particular, for the flow we have you might need to identify how to install SSL certificates and how to proxy a request to a port based on the requested URL. **Q: Is Beckn-ONIX the best way to setup and manage Beckn network?** + **A:** No. Beckn-ONIX is just one effort to kick start the process of creating tools to aid easy creation and operation of Beckn networks. We want the community to create even better tools for different production environments. **Q: How do I contribute to this project?** + **A:** We welcome contributions both to this project as well as initiatives in other production environment. Refer to the [contribution guide](./contribution.md) for more details on the process. diff --git a/docs/user_guide.md b/docs/user_guide.md index 377e30d..94d3c63 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -216,4 +216,4 @@ In the role of reverse proxy, Nginx will forward communication that came on a pa [This document](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) explains the configuration of reverse proxy using proxy_pass -You can find sample Nginx configuration for the Registry, Gateway, BAP and BPP [here](./sample_nginx_configuration.md) +You can find sample Nginx configuration for the Registry, Gateway, BAP and BPP [here](./sample_nginx_configurations.md) From 5beaa5eeabbf0f5ff460ccaa70e0321ddd896214 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Mon, 15 Apr 2024 21:34:00 +0530 Subject: [PATCH 037/102] Add sample layer2 files --- layer2/samples/dhp_0.7.3_1.1.0.yaml | 2164 +++++++++++++ layer2/samples/dhp_1.1.0.yaml | 8 +- layer2/samples/dsep_1.1.0.yaml | 3063 +++++++++++++++++++ layer2/samples/dsep_courses_1.1.0.yaml | 3063 +++++++++++++++++++ layer2/samples/dsep_jobs_1.1.0.yaml | 3063 +++++++++++++++++++ layer2/samples/dsep_scholarships_1.1.0.yaml | 3063 +++++++++++++++++++ layer2/samples/retail_1.1.0.yaml | 6 +- 7 files changed, 14423 insertions(+), 7 deletions(-) create mode 100644 layer2/samples/dhp_0.7.3_1.1.0.yaml create mode 100644 layer2/samples/dsep_1.1.0.yaml create mode 100644 layer2/samples/dsep_courses_1.1.0.yaml create mode 100644 layer2/samples/dsep_jobs_1.1.0.yaml create mode 100644 layer2/samples/dsep_scholarships_1.1.0.yaml diff --git a/layer2/samples/dhp_0.7.3_1.1.0.yaml b/layer2/samples/dhp_0.7.3_1.1.0.yaml new file mode 100644 index 0000000..8ce8b4f --- /dev/null +++ b/layer2/samples/dhp_0.7.3_1.1.0.yaml @@ -0,0 +1,2164 @@ +openapi: 3.0.0 +info: + title: DHP Core API + description: DHP Core API specification. This is an adaptation of Beckn core version 1.1.0 + version: 0.7.3 +security: + - SubscriberAuth: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: BAP declares the customer's intent to buy/avail healthcare services/products. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: BAP declares the customer's cart (or equivalent) created by selecting objects from the catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + description: Updated order object + allOf: + - $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_search: + post: + tags: + - Beckn Application Platform (BAP) + - Beckn Gateway (BG) + description: BPP sends its catalog in response to a search request. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_select: + post: + tags: + - Beckn Application Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_init: + post: + tags: + - Beckn Application Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_confirm: + post: + tags: + - Beckn Application Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_track: + post: + tags: + - Beckn Application Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_cancel: + post: + tags: + - Beckn Application Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_update: + post: + tags: + - Beckn Application Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_status: + post: + tags: + - Beckn Application Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_rating: + post: + tags: + - Beckn Application Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_support: + post: + tags: + - Beckn Application Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: "Describes the acknowledgement sent in response to an API call. If the implementation uses HTTP/S, then Ack must be returned in the same session. Every API call to a BPP must be responded to with an Ack whether the BPP intends to respond with a callback or not. This has one property called `status` that indicates the status of the Acknowledgement." + type: object + properties: + status: + type: string + description: "The status of the acknowledgement. If the request passes the validation criteria of the BPP, then this is set to ACK. If a BPP responds with status = `ACK` to a request, it is required to respond with a callback. If the request fails the validation criteria, then this is set to NACK. Additionally, if a BPP does not intend to respond with a callback even after the request meets the validation criteria, it should set this value to `NACK`." + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: Describes an additional item offered as a value-addition to a product or service. This does not exist independently in a catalog and is always associated with an item. + type: object + properties: + id: + description: Provider-defined ID of the add-on + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes the direct performer, driver or executor that fulfills an order. It is usually a person. But in some rare cases, it could be a non-living entity like a drone, or a bot. Some examples of agents are Doctor in the healthcare sector, a driver in the mobility sector, or a delivery person in the logistics sector. This object can be set at any stage of the order lifecycle. This can be set at the discovery stage when the BPP wants to provide details on the agent fulfilling the order, like in healthcare, where the doctor's name appears during search. This object can also used to search for a particular person that the customer wants fulfilling an order. Sometimes, this object gets instantiated after the order is confirmed, like in the case of on-demand taxis, where the driver is assigned after the user confirms the ride." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: "Describes the billing details of an entity.
This has properties like name,organization,address,email,phone,time,tax_number, created_at,updated_at" + type: object + properties: + name: + description: Name of the billable entity + type: string + organization: + description: Details of the organization being billed. + allOf: + - $ref: "#/components/schemas/Organization" + address: + description: The address of the billable entity + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address where the bill is sent to + type: string + format: email + phone: + description: Phone number of the billable entity + type: string + time: + description: Details regarding the billing period + allOf: + - $ref: "#/components/schemas/Time" + tax_id: + description: ID of the billable entity as recognized by the taxation authority + type: string + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the buyer + type: string + format: date-time + cancelled_by: + type: string + enum: + - CONSUMER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + CancellationTerm: + description: Describes the cancellation terms of an item or an order. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes the products or services offered by a BPP. This is typically sent as the response to a search intent from a BAP. The payment terms, offers and terms of fulfillment supported by the BPP can also be included here. The BPP can show hierarchical nature of products/services in its catalog using the parent_category_id in categories. The BPP can also send a ttl (time to live) in the context which is the duration for which a BAP can cache the catalog and use the cached catalog.
This has properties like bbp/descriptor,bbp/categories,bbp/fulfillments,bbp/payments,bbp/offers,bbp/providers and exp
This is used in the following situations.
  • This is typically used in the discovery stage when the BPP sends the details of the products and services it offers as response to a search intent from the BAP.
" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: A label under which a collection of items can be grouped. + type: object + properties: + id: + description: ID of the category + type: string + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular region of a specified radius centered at a specified GPS coordinate. + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + description: Name of the city + type: string + code: + description: City code + type: string + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: "Every API call in beckn protocol has a context. It provides a high-level overview to the receiver about the nature of the intended transaction. Typically, it is the BAP that sets the transaction context based on the consumer's location and action on their UI. But sometimes, during unsolicited callbacks, the BPP also sets the transaction context but it is usually the same as the context of a previous full-cycle, request-callback interaction between the BAP and the BPP. The context object contains four types of fields.
  1. Demographic information about the transaction using fields like `domain`, `country`, and `region`.
  2. Addressing details like the sending and receiving platform's ID and API URL.
  3. Interoperability information like the protocol version that implemented by the sender and,
  4. Transaction details like the method being called at the receiver's endpoint, the transaction_id that represents an end-to-end user session at the BAP, a message ID to pair requests with callbacks, a timestamp to capture sending times, a ttl to specifiy the validity of the request, and a key to encrypt information if necessary.
This object must be passed in every interaction between a BAP and a BPP. In HTTP/S implementations, it is not necessary to send the context during the synchronous response. However, in asynchronous protocols, the context must be sent during all interactions," + type: object + properties: + domain: + description: Domain code that is relevant to this transaction context + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + description: The Beckn protocol method being called by the sender and executed at the receiver. + type: string + version: + type: string + description: Version of transaction protocol being used by the sender. + bap_id: + description: Subscriber ID of the BAP + allOf: + - description: "A globally unique identifier of the platform, Typically it is the fully qualified domain name (FQDN) of the platform." + type: string + bap_uri: + description: Subscriber URL of the BAP for accepting callbacks from BPPs. + allOf: + - description: The callback URL of the Subscriber. This should necessarily contain the same domain name as set in `subscriber_id``. + type: string + format: uri + bpp_id: + description: Subscriber ID of the BPP + allOf: + - $ref: "#/components/schemas/Context/properties/bap_id/allOf/0" + bpp_uri: + description: Subscriber URL of the BPP for accepting calls from BAPs. + allOf: + - $ref: "#/components/schemas/Context/properties/bap_uri/allOf/0" + transaction_id: + description: "This is a unique value which persists across all API calls from `search` through `confirm`. This is done to indicate an active user session across multiple requests. The BPPs can use this value to push personalized recommendations, and dynamic offerings related to an ongoing transaction despite being unaware of the user active on the BAP." + type: string + format: uuid + message_id: + description: "This is a unique value which persists during a request / callback cycle. Since beckn protocol APIs are asynchronous, BAPs need a common value to match an incoming callback from a BPP to an earlier call. This value can also be used to ignore duplicate messages coming from the BPP. It is recommended to generate a fresh message_id for every new interaction. When sending unsolicited callbacks, BPPs must generate a new message_id." + type: string + format: uuid + timestamp: + description: Time of request generation in RFC3339 format + type: string + format: date-time + key: + description: The encryption public key of the sender + type: string + ttl: + description: The duration in ISO8601 format after timestamp for which this message holds valid + type: string + Country: + description: Describes a country + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + DecimalValue: + description: Describes a numerical value in decimal form + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: "Describes an error object that is returned by a BAP, BPP or BG as a response or callback to an action by another network participant. This object is sent when any request received by a network participant is unacceptable. This object can be sent either during Ack or with the callback." + type: object + properties: + code: + type: string + description: 'Standard error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-005-ERROR-CODES-DRAFT-01.md of this repo"' + paths: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error. Used mainly for logging. Not recommended to be shown to the user. + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to buy or avail a product or a service. The BAP can declare the intent of the consumer containing
  • What they want (A product, service, offer)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of a business. + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + type: string + Region: + description: Describes an arbitrary region of space. The network policy should contain a published list of supported regions by the network. + type: object + properties: + dimensions: + description: "The number of dimensions that are used to describe any point inside that region. The most common dimensionality of a region is 2, that represents an area on a map. There are regions on the map that can be approximated to one-dimensional regions like roads, railway lines, or shipping lines. 3 dimensional regions are rarer, but are gaining popularity as flying drones are being adopted for various fulfillment services." + type: string + enum: + - "1" + - "2" + - "3" + type: + description: "The type of region. This is used to specify the granularity of the region represented by this object. Various examples of two-dimensional region types are city, country, state, district, and so on. The network policy should contain a list of all possible region types supported by the network." + type: string + name: + type: string + description: Name of the region as specified on the map where that region exists. + code: + type: string + description: A standard code representing the region. This should be interpreted in the same way by all network participants. + boundary: + type: string + description: "A string representing the boundary of the region. One-dimensional regions are represented by polylines. Two-dimensional regions are represented by polygons, and three-dimensional regions can represented by polyhedra." + map_url: + type: string + description: The url to the map of the region. This can be a globally recognized map or the one specified by the network policy. + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: "Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations
This has properties like label, time stamp,duration,range, days, schedule" + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Contains tracking information that can be used by the BAP to track the fulfillment of an order in real-time. which is useful for knowing the location of time sensitive deliveries. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required to confirm an order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, to confirm a flight ticket, the airline requires details of the passengers along with information on baggage, identity, in addition to the class of ticket. Similarly, a logistics company may require details on the nature of shipment in order to confirm the shipping. A recruiting firm may require additional details on the applicant in order to confirm a job application. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean diff --git a/layer2/samples/dhp_1.1.0.yaml b/layer2/samples/dhp_1.1.0.yaml index 469286d..8ce8b4f 100644 --- a/layer2/samples/dhp_1.1.0.yaml +++ b/layer2/samples/dhp_1.1.0.yaml @@ -1,8 +1,8 @@ openapi: 3.0.0 info: - title: Beckn Protocol Core - description: DHP layer 2 config from core yaml - version: 1.1.0 + title: DHP Core API + description: DHP Core API specification. This is an adaptation of Beckn core version 1.1.0 + version: 0.7.3 security: - SubscriberAuth: [] paths: @@ -11,7 +11,7 @@ paths: tags: - Beckn Provider Platform (BPP) - Beckn Gateway (BG) - description: BAP declares the customer's intent to buy/avail products or services + description: BAP declares the customer's intent to buy/avail healthcare services/products. requestBody: content: application/json: diff --git a/layer2/samples/dsep_1.1.0.yaml b/layer2/samples/dsep_1.1.0.yaml new file mode 100644 index 0000000..bfac183 --- /dev/null +++ b/layer2/samples/dsep_1.1.0.yaml @@ -0,0 +1,3063 @@ +openapi: 3.0.0 +info: + title: Decentralized Skilling and Education Protocol Specification + description: Adaptation of beckn protocol for the domain of skilling and education + version: 0.7.0 + +security: + - SubscriberAuth: [] + - GatewaySubscriberAuthNew: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: This allows a BAP to discover for catalogs offering
a) Jobs and Internships
b) Trainings and Courses
c) Mentors and Coaches and,
d) Scholarships and Grants + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + examples: + Search for 'web design' jobs by category code in the region of Delhi: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + category: + descriptor: + name: Web design jobs + code: nic2008:62012 + Search for jobs by skills like carpentry and painting: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + fulfillment: + customer: + person: + skills: + - name: Painting + - name: Carpentry + tags: + - descriptor: + name: Competence + list: + - descriptor: + name: Experience + value: 12Y + + Search for jobs along with expected salary: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + fulfillment: + customer: + person: + skills: + - name: Java Programming + tags: + - descriptor: + name: Competence + list: + - descriptor: + name: Experience + value: 12Y + tags: + - descriptor: + name: Expectations + list: + - descriptor: + name: expected_payment + value: 250000INR/Month + + Search for jobs offered by a specific provider: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + provider: + descriptor: + name: Infosys + Search for online courses matching a specific topic: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + item: + descriptor: + name: AI basics + tags: + - descriptor: + name: course_labels + list: + - descriptor: + name: label_1 + value: AI + - descriptor: + name: label_2 + value: ML + - descriptor: + name: label_3 + value: beginners + - descriptor: + name: label_4 + value: Artifical Intelligence + - descriptor: + name: label_5 + value: machine learning + - descriptor: + name: label_6 + value: neural networks + fulfillment: + type: FULL-TIME + Search for BTech courses offered by an engineering instituition like IIT Delhi: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + provider: + descriptor: + name: IIT Delhi + tags: + - descriptor: + name: course_labels + list: + - descriptor: + name: label_1 + value: AI + - descriptor: + name: label_2 + value: ML + - descriptor: + name: label_3 + value: beginners + - descriptor: + name: label_4 + value: Artifical Intelligence + - descriptor: + name: label_5 + value: machine learning + - descriptor: + name: label_6 + value: neural networks + category: + descriptor: + name: B.Tech + code: BTECH + fulfillment: + type: FULL-TIME + Searching for a mentor by name: + value: + context: + domain: mentorship-and-coaching + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + fulfillment: + agent: + name: Dr Rajiv Manocha + Search for scholarships: + value: + context: + domain: mentorship + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + category: + id: "4" + descriptor: + name: Engineering and Technology + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: API for Selecting items from the catalog. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + description: Contact support + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /on_search: + post: + tags: + - Beckn App Platform (BAP) + - Beckn Gateway (BG) + description: Send catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + Publish a catalog of software jobs by a software agency: + value: + context: + domain: jobs:nic2008:62XXX + location: + city: + code: "*" + country: + code: IND + action: on_search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + bpp_id: https://naukri.com/ + bpp_uri: https://api.naukri.com/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + catalog: + descriptor: + name: Naukri Recruitment Platform + providers: + - descriptor: + name: Infosys + categories: + - id: "1" + name: Frontend Jobs + - id: "2" + name: Backend Jobs + items: + - descriptor: + name: Senior Software Developer + code: SSFD + fulfillment_ids: + - "1" + category_ids: + - "1" + matched: true + - descriptor: + name: Software Consultant - On site + code: SWCO + fulfillment_ids: + - "1" + category_ids: + - "1" + matched: "false" + - descriptor: + name: Software Consultant - Remote + code: SWCR + fulfillment_ids: + - "2" + category_ids: + - "2" + matched: "false" + fulfillments: + - id: "1" + descriptor: + name: Full-time + stops: + - location: + city: + code: BLR + - id: "2" + descriptor: + name: On-site + stops: + - location: + city: + code: BLR + type: start + time: + timestamp: "2022-08-10" + - location: + city: BLR + type: end + time: + timestamp: "2022-08-10" + - id: "3" + descriptor: + name: Remote + stops: + - time: + timestamp: "2022-08-10" + type: start + - time: + timestamp: "2022-08-10" + type: end + Publish a catalog of online courses: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: on_search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + catalog: + descriptor: + name: XAcademy + providers: + - descriptor: + name: XAcademy + categories: + - id: "1" + name: Software + - id: "2" + name: Management + items: + - id: "1" + descriptor: + name: Basics of AI + price: + value: "6000" + fulfillment_ids: + - "1" + category_ids: + - "1" + - id: "2" + descriptor: + name: AI for Data Analysis + price: + value: "7000" + fulfillment_ids: + - "1" + category_ids: + - "1" + fulfillments: + - id: "1" + type: ONLINE + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - context + /on_select: + post: + tags: + - Beckn App Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_init: + post: + tags: + - Beckn App Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_confirm: + post: + tags: + - Beckn App Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_track: + post: + tags: + - Beckn App Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_cancel: + post: + tags: + - Beckn App Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_update: + post: + tags: + - Beckn App Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_status: + post: + tags: + - Beckn App Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_rating: + post: + tags: + - Beckn App Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_support: + post: + tags: + - Beckn App Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_cancellation_reasons: + post: + tags: + - BPP Meta APIs + description: Get cancellation reasons from the BPP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /cancellation_reasons: + post: + tags: + - BAP Meta APIs + description: Get cancellation reasons from the BPP + requestBody: + description: List of cancellation reasons + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + message: + type: object + properties: + cancellation_reasons: + type: array + items: + $ref: "#/components/schemas/Option" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_return_reasons: + post: + tags: + - BPP Meta APIs + description: Get return reasons from the BPP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /return_reasons: + post: + tags: + - BAP Meta APIs + description: Get return reasons from the BPP + requestBody: + description: List of return reasons + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + return_reasons: + type: array + items: + $ref: "#/components/schemas/Option" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_rating_categories: + post: + tags: + - BPP Meta APIs + description: Get a list of categories that can be rated by the BAP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /rating_categories: + post: + tags: + - BAP Meta APIs + description: Get a list of categories that can be rated by the BAP + requestBody: + description: Array of categories which can be rated + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + rating_categories: + type: array + items: + $ref: "#/components/schemas/Rating/properties/rating_category" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + GatewaySubscriberAuth: + type: apiKey + in: header + name: Proxy-Authorization + description: 'Signature of message body + BAP/BPP''s Authorization header using BG''s signing public key. Format:

Proxy-Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"

Note:This header will be deprecated soon and will no longer be supported in future releases. New implementors are requested to use the X-Gateway-Authorization header. Existing implementations are requested to migrate their header to the new header. The deprecation date will be set after discussion as per the standard specification governance process.

' + GatewaySubscriberAuthNew: + type: apiKey + in: header + name: X-Gateway-Authorization + description: 'Signature of message body + BAP/BPP''s Authorization header using BG''s signing public key. Format:

X-Gateway-Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: This describes an acknowledgement of receipt of a message. Upon receiving a message, the receiver must first authenticate the sender by verifying its digital signature. Upon successful verification of the signature, the receiver must validate the schema of the message. After performing both the operations, the receiver should send an Ack object in response. + type: object + properties: + status: + type: string + description: "Describe the status of the ACK response. If the message passes the acknowledgement criteria, then the receiver shouls set this value equal to ACK else it should be set to NACK" + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: This is typically an optional product or service that can be offered in addition to a product or a service of type Item. Objects of type AddOn should not exist without an associated Item. If a BAP receives an Item with an add-on, it must show it to the user as a selectable object. If any AddOn object is found without an associated Item object, then the validator must throw an error 'NO-PARENT=ITEM' with message 'No parent found' + type: object + properties: + id: + type: string + description: ID of the add-on as present in the source catalog + optional: + type: boolean + default: false + description: This value indicates if the add-on is optional or required to be selected by the user along with an Item. If this value is set to true, then the BAP must ensure that the add-on is mandatorily selected by the user while creating the Order object with the Item. + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes a person who fulfills this order." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: Describes the billing details of an order. This must be provided by BAP user before confirmation of the order. + type: object + properties: + name: + description: Name of the person under who's name the bill will be generated. + type: string + organization: + description: Name of the organization under who's name the bill will be generated. + allOf: + - $ref: "#/components/schemas/Organization" + address: + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address of the person / organization being billed. The BPP must send the bill to this email address. The format of the bill may be defined in the network policy. + type: string + format: email + phone: + description: Phone number of the person / organization being billed. The BPP must send the bill to this phone number as per the format specified in the network policy. In case the bill is a downloadable file, it is recommended the bill should be sent to the phone number as a downloadable link. + type: string + time: + $ref: "#/components/schemas/Time" + tax_id: + description: This is the identity of a Tax-paying person or an organization. This number can be provided to the BPP to avail tax benefits, if applicable. The format of this string should be specified in the network policy + type: string + created_at: + description: Date and time at which this bill was generated by the BPP. + type: string + format: date-time + + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the seeker + type: string + format: date-time + cancelled_by: + type: string + enum: + - SEEKER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + + CancellationTerm: + description: Describes the cancellation terms of an order, i.e, scholarship application, course etc. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes a skilling and education catalog" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: Describes a category + type: object + properties: + id: + type: string + description: Unique id of the category + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular area on the map + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + type: string + description: Name of the city + code: + type: string + description: City code + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: Describes a beckn message context + type: object + properties: + domain: + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + type: string + description: Defines the Beckn API call type. + version: + type: string + description: Version of Beckn core API specification being used + bap_id: + type: string + description: Unique id of the BAP. By default it is the fully qualified domain name of the BAP + bap_uri: + type: string + format: uri + description: URI of the BAP for accepting callbacks. Must have the same domain name as the bap_id + bpp_id: + type: string + description: Unique id of the BPP. By default it is the fully qualified domain name of the BPP + bpp_uri: + type: string + format: uri + description: URI of the BPP. Must have the same domain name as the bap_id + transaction_id: + type: string + format: uuid + description: This is a unique value which persists across all API calls from search through confirm + message_id: + type: string + format: uuid + description: This is a unique value which persists during a request / callback cycle + timestamp: + type: string + format: date-time + description: Time of request generation in RFC3339 format + key: + type: string + description: The encryption public key of the sender + ttl: + type: string + description: The duration in ISO8601 format after timestamp for which this message holds valid + Country: + description: Describes a country. + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + DecimalValue: + description: Describes a decimal value + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: Describes an error object + type: object + properties: + type: + type: string + enum: + - CONTEXT-ERROR + - CORE-ERROR + - DOMAIN-ERROR + - POLICY-ERROR + - JSON-SCHEMA-ERROR + code: + type: string + description: "Beckn specific error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-RFC-005-ERROR-CODES-DRAFT-01.md of this repo" + path: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error + required: + - type + - code + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to get a Learning and Career Development Resources. The BAP can declare the intent of the consumer containing
  • What they want (scholarship, job, course etc)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of an entity, entitiy can be a scholarship facilitator, course provider etc + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Describes a tracking object. it can be used to track the status of a service, i.e, a scholarship application, a course etc. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required for the order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, A scholarship application may require additional details on the applicant as a proof of eligibility. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean diff --git a/layer2/samples/dsep_courses_1.1.0.yaml b/layer2/samples/dsep_courses_1.1.0.yaml new file mode 100644 index 0000000..bfac183 --- /dev/null +++ b/layer2/samples/dsep_courses_1.1.0.yaml @@ -0,0 +1,3063 @@ +openapi: 3.0.0 +info: + title: Decentralized Skilling and Education Protocol Specification + description: Adaptation of beckn protocol for the domain of skilling and education + version: 0.7.0 + +security: + - SubscriberAuth: [] + - GatewaySubscriberAuthNew: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: This allows a BAP to discover for catalogs offering
a) Jobs and Internships
b) Trainings and Courses
c) Mentors and Coaches and,
d) Scholarships and Grants + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + examples: + Search for 'web design' jobs by category code in the region of Delhi: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + category: + descriptor: + name: Web design jobs + code: nic2008:62012 + Search for jobs by skills like carpentry and painting: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + fulfillment: + customer: + person: + skills: + - name: Painting + - name: Carpentry + tags: + - descriptor: + name: Competence + list: + - descriptor: + name: Experience + value: 12Y + + Search for jobs along with expected salary: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + fulfillment: + customer: + person: + skills: + - name: Java Programming + tags: + - descriptor: + name: Competence + list: + - descriptor: + name: Experience + value: 12Y + tags: + - descriptor: + name: Expectations + list: + - descriptor: + name: expected_payment + value: 250000INR/Month + + Search for jobs offered by a specific provider: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + provider: + descriptor: + name: Infosys + Search for online courses matching a specific topic: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + item: + descriptor: + name: AI basics + tags: + - descriptor: + name: course_labels + list: + - descriptor: + name: label_1 + value: AI + - descriptor: + name: label_2 + value: ML + - descriptor: + name: label_3 + value: beginners + - descriptor: + name: label_4 + value: Artifical Intelligence + - descriptor: + name: label_5 + value: machine learning + - descriptor: + name: label_6 + value: neural networks + fulfillment: + type: FULL-TIME + Search for BTech courses offered by an engineering instituition like IIT Delhi: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + provider: + descriptor: + name: IIT Delhi + tags: + - descriptor: + name: course_labels + list: + - descriptor: + name: label_1 + value: AI + - descriptor: + name: label_2 + value: ML + - descriptor: + name: label_3 + value: beginners + - descriptor: + name: label_4 + value: Artifical Intelligence + - descriptor: + name: label_5 + value: machine learning + - descriptor: + name: label_6 + value: neural networks + category: + descriptor: + name: B.Tech + code: BTECH + fulfillment: + type: FULL-TIME + Searching for a mentor by name: + value: + context: + domain: mentorship-and-coaching + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + fulfillment: + agent: + name: Dr Rajiv Manocha + Search for scholarships: + value: + context: + domain: mentorship + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + category: + id: "4" + descriptor: + name: Engineering and Technology + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: API for Selecting items from the catalog. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + description: Contact support + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /on_search: + post: + tags: + - Beckn App Platform (BAP) + - Beckn Gateway (BG) + description: Send catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + Publish a catalog of software jobs by a software agency: + value: + context: + domain: jobs:nic2008:62XXX + location: + city: + code: "*" + country: + code: IND + action: on_search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + bpp_id: https://naukri.com/ + bpp_uri: https://api.naukri.com/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + catalog: + descriptor: + name: Naukri Recruitment Platform + providers: + - descriptor: + name: Infosys + categories: + - id: "1" + name: Frontend Jobs + - id: "2" + name: Backend Jobs + items: + - descriptor: + name: Senior Software Developer + code: SSFD + fulfillment_ids: + - "1" + category_ids: + - "1" + matched: true + - descriptor: + name: Software Consultant - On site + code: SWCO + fulfillment_ids: + - "1" + category_ids: + - "1" + matched: "false" + - descriptor: + name: Software Consultant - Remote + code: SWCR + fulfillment_ids: + - "2" + category_ids: + - "2" + matched: "false" + fulfillments: + - id: "1" + descriptor: + name: Full-time + stops: + - location: + city: + code: BLR + - id: "2" + descriptor: + name: On-site + stops: + - location: + city: + code: BLR + type: start + time: + timestamp: "2022-08-10" + - location: + city: BLR + type: end + time: + timestamp: "2022-08-10" + - id: "3" + descriptor: + name: Remote + stops: + - time: + timestamp: "2022-08-10" + type: start + - time: + timestamp: "2022-08-10" + type: end + Publish a catalog of online courses: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: on_search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + catalog: + descriptor: + name: XAcademy + providers: + - descriptor: + name: XAcademy + categories: + - id: "1" + name: Software + - id: "2" + name: Management + items: + - id: "1" + descriptor: + name: Basics of AI + price: + value: "6000" + fulfillment_ids: + - "1" + category_ids: + - "1" + - id: "2" + descriptor: + name: AI for Data Analysis + price: + value: "7000" + fulfillment_ids: + - "1" + category_ids: + - "1" + fulfillments: + - id: "1" + type: ONLINE + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - context + /on_select: + post: + tags: + - Beckn App Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_init: + post: + tags: + - Beckn App Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_confirm: + post: + tags: + - Beckn App Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_track: + post: + tags: + - Beckn App Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_cancel: + post: + tags: + - Beckn App Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_update: + post: + tags: + - Beckn App Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_status: + post: + tags: + - Beckn App Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_rating: + post: + tags: + - Beckn App Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_support: + post: + tags: + - Beckn App Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_cancellation_reasons: + post: + tags: + - BPP Meta APIs + description: Get cancellation reasons from the BPP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /cancellation_reasons: + post: + tags: + - BAP Meta APIs + description: Get cancellation reasons from the BPP + requestBody: + description: List of cancellation reasons + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + message: + type: object + properties: + cancellation_reasons: + type: array + items: + $ref: "#/components/schemas/Option" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_return_reasons: + post: + tags: + - BPP Meta APIs + description: Get return reasons from the BPP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /return_reasons: + post: + tags: + - BAP Meta APIs + description: Get return reasons from the BPP + requestBody: + description: List of return reasons + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + return_reasons: + type: array + items: + $ref: "#/components/schemas/Option" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_rating_categories: + post: + tags: + - BPP Meta APIs + description: Get a list of categories that can be rated by the BAP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /rating_categories: + post: + tags: + - BAP Meta APIs + description: Get a list of categories that can be rated by the BAP + requestBody: + description: Array of categories which can be rated + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + rating_categories: + type: array + items: + $ref: "#/components/schemas/Rating/properties/rating_category" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + GatewaySubscriberAuth: + type: apiKey + in: header + name: Proxy-Authorization + description: 'Signature of message body + BAP/BPP''s Authorization header using BG''s signing public key. Format:

Proxy-Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"

Note:This header will be deprecated soon and will no longer be supported in future releases. New implementors are requested to use the X-Gateway-Authorization header. Existing implementations are requested to migrate their header to the new header. The deprecation date will be set after discussion as per the standard specification governance process.

' + GatewaySubscriberAuthNew: + type: apiKey + in: header + name: X-Gateway-Authorization + description: 'Signature of message body + BAP/BPP''s Authorization header using BG''s signing public key. Format:

X-Gateway-Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: This describes an acknowledgement of receipt of a message. Upon receiving a message, the receiver must first authenticate the sender by verifying its digital signature. Upon successful verification of the signature, the receiver must validate the schema of the message. After performing both the operations, the receiver should send an Ack object in response. + type: object + properties: + status: + type: string + description: "Describe the status of the ACK response. If the message passes the acknowledgement criteria, then the receiver shouls set this value equal to ACK else it should be set to NACK" + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: This is typically an optional product or service that can be offered in addition to a product or a service of type Item. Objects of type AddOn should not exist without an associated Item. If a BAP receives an Item with an add-on, it must show it to the user as a selectable object. If any AddOn object is found without an associated Item object, then the validator must throw an error 'NO-PARENT=ITEM' with message 'No parent found' + type: object + properties: + id: + type: string + description: ID of the add-on as present in the source catalog + optional: + type: boolean + default: false + description: This value indicates if the add-on is optional or required to be selected by the user along with an Item. If this value is set to true, then the BAP must ensure that the add-on is mandatorily selected by the user while creating the Order object with the Item. + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes a person who fulfills this order." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: Describes the billing details of an order. This must be provided by BAP user before confirmation of the order. + type: object + properties: + name: + description: Name of the person under who's name the bill will be generated. + type: string + organization: + description: Name of the organization under who's name the bill will be generated. + allOf: + - $ref: "#/components/schemas/Organization" + address: + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address of the person / organization being billed. The BPP must send the bill to this email address. The format of the bill may be defined in the network policy. + type: string + format: email + phone: + description: Phone number of the person / organization being billed. The BPP must send the bill to this phone number as per the format specified in the network policy. In case the bill is a downloadable file, it is recommended the bill should be sent to the phone number as a downloadable link. + type: string + time: + $ref: "#/components/schemas/Time" + tax_id: + description: This is the identity of a Tax-paying person or an organization. This number can be provided to the BPP to avail tax benefits, if applicable. The format of this string should be specified in the network policy + type: string + created_at: + description: Date and time at which this bill was generated by the BPP. + type: string + format: date-time + + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the seeker + type: string + format: date-time + cancelled_by: + type: string + enum: + - SEEKER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + + CancellationTerm: + description: Describes the cancellation terms of an order, i.e, scholarship application, course etc. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes a skilling and education catalog" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: Describes a category + type: object + properties: + id: + type: string + description: Unique id of the category + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular area on the map + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + type: string + description: Name of the city + code: + type: string + description: City code + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: Describes a beckn message context + type: object + properties: + domain: + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + type: string + description: Defines the Beckn API call type. + version: + type: string + description: Version of Beckn core API specification being used + bap_id: + type: string + description: Unique id of the BAP. By default it is the fully qualified domain name of the BAP + bap_uri: + type: string + format: uri + description: URI of the BAP for accepting callbacks. Must have the same domain name as the bap_id + bpp_id: + type: string + description: Unique id of the BPP. By default it is the fully qualified domain name of the BPP + bpp_uri: + type: string + format: uri + description: URI of the BPP. Must have the same domain name as the bap_id + transaction_id: + type: string + format: uuid + description: This is a unique value which persists across all API calls from search through confirm + message_id: + type: string + format: uuid + description: This is a unique value which persists during a request / callback cycle + timestamp: + type: string + format: date-time + description: Time of request generation in RFC3339 format + key: + type: string + description: The encryption public key of the sender + ttl: + type: string + description: The duration in ISO8601 format after timestamp for which this message holds valid + Country: + description: Describes a country. + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + DecimalValue: + description: Describes a decimal value + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: Describes an error object + type: object + properties: + type: + type: string + enum: + - CONTEXT-ERROR + - CORE-ERROR + - DOMAIN-ERROR + - POLICY-ERROR + - JSON-SCHEMA-ERROR + code: + type: string + description: "Beckn specific error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-RFC-005-ERROR-CODES-DRAFT-01.md of this repo" + path: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error + required: + - type + - code + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to get a Learning and Career Development Resources. The BAP can declare the intent of the consumer containing
  • What they want (scholarship, job, course etc)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of an entity, entitiy can be a scholarship facilitator, course provider etc + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Describes a tracking object. it can be used to track the status of a service, i.e, a scholarship application, a course etc. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required for the order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, A scholarship application may require additional details on the applicant as a proof of eligibility. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean diff --git a/layer2/samples/dsep_jobs_1.1.0.yaml b/layer2/samples/dsep_jobs_1.1.0.yaml new file mode 100644 index 0000000..bfac183 --- /dev/null +++ b/layer2/samples/dsep_jobs_1.1.0.yaml @@ -0,0 +1,3063 @@ +openapi: 3.0.0 +info: + title: Decentralized Skilling and Education Protocol Specification + description: Adaptation of beckn protocol for the domain of skilling and education + version: 0.7.0 + +security: + - SubscriberAuth: [] + - GatewaySubscriberAuthNew: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: This allows a BAP to discover for catalogs offering
a) Jobs and Internships
b) Trainings and Courses
c) Mentors and Coaches and,
d) Scholarships and Grants + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + examples: + Search for 'web design' jobs by category code in the region of Delhi: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + category: + descriptor: + name: Web design jobs + code: nic2008:62012 + Search for jobs by skills like carpentry and painting: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + fulfillment: + customer: + person: + skills: + - name: Painting + - name: Carpentry + tags: + - descriptor: + name: Competence + list: + - descriptor: + name: Experience + value: 12Y + + Search for jobs along with expected salary: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + fulfillment: + customer: + person: + skills: + - name: Java Programming + tags: + - descriptor: + name: Competence + list: + - descriptor: + name: Experience + value: 12Y + tags: + - descriptor: + name: Expectations + list: + - descriptor: + name: expected_payment + value: 250000INR/Month + + Search for jobs offered by a specific provider: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + provider: + descriptor: + name: Infosys + Search for online courses matching a specific topic: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + item: + descriptor: + name: AI basics + tags: + - descriptor: + name: course_labels + list: + - descriptor: + name: label_1 + value: AI + - descriptor: + name: label_2 + value: ML + - descriptor: + name: label_3 + value: beginners + - descriptor: + name: label_4 + value: Artifical Intelligence + - descriptor: + name: label_5 + value: machine learning + - descriptor: + name: label_6 + value: neural networks + fulfillment: + type: FULL-TIME + Search for BTech courses offered by an engineering instituition like IIT Delhi: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + provider: + descriptor: + name: IIT Delhi + tags: + - descriptor: + name: course_labels + list: + - descriptor: + name: label_1 + value: AI + - descriptor: + name: label_2 + value: ML + - descriptor: + name: label_3 + value: beginners + - descriptor: + name: label_4 + value: Artifical Intelligence + - descriptor: + name: label_5 + value: machine learning + - descriptor: + name: label_6 + value: neural networks + category: + descriptor: + name: B.Tech + code: BTECH + fulfillment: + type: FULL-TIME + Searching for a mentor by name: + value: + context: + domain: mentorship-and-coaching + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + fulfillment: + agent: + name: Dr Rajiv Manocha + Search for scholarships: + value: + context: + domain: mentorship + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + category: + id: "4" + descriptor: + name: Engineering and Technology + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: API for Selecting items from the catalog. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + description: Contact support + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /on_search: + post: + tags: + - Beckn App Platform (BAP) + - Beckn Gateway (BG) + description: Send catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + Publish a catalog of software jobs by a software agency: + value: + context: + domain: jobs:nic2008:62XXX + location: + city: + code: "*" + country: + code: IND + action: on_search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + bpp_id: https://naukri.com/ + bpp_uri: https://api.naukri.com/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + catalog: + descriptor: + name: Naukri Recruitment Platform + providers: + - descriptor: + name: Infosys + categories: + - id: "1" + name: Frontend Jobs + - id: "2" + name: Backend Jobs + items: + - descriptor: + name: Senior Software Developer + code: SSFD + fulfillment_ids: + - "1" + category_ids: + - "1" + matched: true + - descriptor: + name: Software Consultant - On site + code: SWCO + fulfillment_ids: + - "1" + category_ids: + - "1" + matched: "false" + - descriptor: + name: Software Consultant - Remote + code: SWCR + fulfillment_ids: + - "2" + category_ids: + - "2" + matched: "false" + fulfillments: + - id: "1" + descriptor: + name: Full-time + stops: + - location: + city: + code: BLR + - id: "2" + descriptor: + name: On-site + stops: + - location: + city: + code: BLR + type: start + time: + timestamp: "2022-08-10" + - location: + city: BLR + type: end + time: + timestamp: "2022-08-10" + - id: "3" + descriptor: + name: Remote + stops: + - time: + timestamp: "2022-08-10" + type: start + - time: + timestamp: "2022-08-10" + type: end + Publish a catalog of online courses: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: on_search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + catalog: + descriptor: + name: XAcademy + providers: + - descriptor: + name: XAcademy + categories: + - id: "1" + name: Software + - id: "2" + name: Management + items: + - id: "1" + descriptor: + name: Basics of AI + price: + value: "6000" + fulfillment_ids: + - "1" + category_ids: + - "1" + - id: "2" + descriptor: + name: AI for Data Analysis + price: + value: "7000" + fulfillment_ids: + - "1" + category_ids: + - "1" + fulfillments: + - id: "1" + type: ONLINE + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - context + /on_select: + post: + tags: + - Beckn App Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_init: + post: + tags: + - Beckn App Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_confirm: + post: + tags: + - Beckn App Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_track: + post: + tags: + - Beckn App Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_cancel: + post: + tags: + - Beckn App Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_update: + post: + tags: + - Beckn App Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_status: + post: + tags: + - Beckn App Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_rating: + post: + tags: + - Beckn App Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_support: + post: + tags: + - Beckn App Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_cancellation_reasons: + post: + tags: + - BPP Meta APIs + description: Get cancellation reasons from the BPP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /cancellation_reasons: + post: + tags: + - BAP Meta APIs + description: Get cancellation reasons from the BPP + requestBody: + description: List of cancellation reasons + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + message: + type: object + properties: + cancellation_reasons: + type: array + items: + $ref: "#/components/schemas/Option" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_return_reasons: + post: + tags: + - BPP Meta APIs + description: Get return reasons from the BPP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /return_reasons: + post: + tags: + - BAP Meta APIs + description: Get return reasons from the BPP + requestBody: + description: List of return reasons + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + return_reasons: + type: array + items: + $ref: "#/components/schemas/Option" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_rating_categories: + post: + tags: + - BPP Meta APIs + description: Get a list of categories that can be rated by the BAP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /rating_categories: + post: + tags: + - BAP Meta APIs + description: Get a list of categories that can be rated by the BAP + requestBody: + description: Array of categories which can be rated + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + rating_categories: + type: array + items: + $ref: "#/components/schemas/Rating/properties/rating_category" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + GatewaySubscriberAuth: + type: apiKey + in: header + name: Proxy-Authorization + description: 'Signature of message body + BAP/BPP''s Authorization header using BG''s signing public key. Format:

Proxy-Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"

Note:This header will be deprecated soon and will no longer be supported in future releases. New implementors are requested to use the X-Gateway-Authorization header. Existing implementations are requested to migrate their header to the new header. The deprecation date will be set after discussion as per the standard specification governance process.

' + GatewaySubscriberAuthNew: + type: apiKey + in: header + name: X-Gateway-Authorization + description: 'Signature of message body + BAP/BPP''s Authorization header using BG''s signing public key. Format:

X-Gateway-Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: This describes an acknowledgement of receipt of a message. Upon receiving a message, the receiver must first authenticate the sender by verifying its digital signature. Upon successful verification of the signature, the receiver must validate the schema of the message. After performing both the operations, the receiver should send an Ack object in response. + type: object + properties: + status: + type: string + description: "Describe the status of the ACK response. If the message passes the acknowledgement criteria, then the receiver shouls set this value equal to ACK else it should be set to NACK" + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: This is typically an optional product or service that can be offered in addition to a product or a service of type Item. Objects of type AddOn should not exist without an associated Item. If a BAP receives an Item with an add-on, it must show it to the user as a selectable object. If any AddOn object is found without an associated Item object, then the validator must throw an error 'NO-PARENT=ITEM' with message 'No parent found' + type: object + properties: + id: + type: string + description: ID of the add-on as present in the source catalog + optional: + type: boolean + default: false + description: This value indicates if the add-on is optional or required to be selected by the user along with an Item. If this value is set to true, then the BAP must ensure that the add-on is mandatorily selected by the user while creating the Order object with the Item. + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes a person who fulfills this order." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: Describes the billing details of an order. This must be provided by BAP user before confirmation of the order. + type: object + properties: + name: + description: Name of the person under who's name the bill will be generated. + type: string + organization: + description: Name of the organization under who's name the bill will be generated. + allOf: + - $ref: "#/components/schemas/Organization" + address: + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address of the person / organization being billed. The BPP must send the bill to this email address. The format of the bill may be defined in the network policy. + type: string + format: email + phone: + description: Phone number of the person / organization being billed. The BPP must send the bill to this phone number as per the format specified in the network policy. In case the bill is a downloadable file, it is recommended the bill should be sent to the phone number as a downloadable link. + type: string + time: + $ref: "#/components/schemas/Time" + tax_id: + description: This is the identity of a Tax-paying person or an organization. This number can be provided to the BPP to avail tax benefits, if applicable. The format of this string should be specified in the network policy + type: string + created_at: + description: Date and time at which this bill was generated by the BPP. + type: string + format: date-time + + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the seeker + type: string + format: date-time + cancelled_by: + type: string + enum: + - SEEKER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + + CancellationTerm: + description: Describes the cancellation terms of an order, i.e, scholarship application, course etc. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes a skilling and education catalog" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: Describes a category + type: object + properties: + id: + type: string + description: Unique id of the category + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular area on the map + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + type: string + description: Name of the city + code: + type: string + description: City code + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: Describes a beckn message context + type: object + properties: + domain: + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + type: string + description: Defines the Beckn API call type. + version: + type: string + description: Version of Beckn core API specification being used + bap_id: + type: string + description: Unique id of the BAP. By default it is the fully qualified domain name of the BAP + bap_uri: + type: string + format: uri + description: URI of the BAP for accepting callbacks. Must have the same domain name as the bap_id + bpp_id: + type: string + description: Unique id of the BPP. By default it is the fully qualified domain name of the BPP + bpp_uri: + type: string + format: uri + description: URI of the BPP. Must have the same domain name as the bap_id + transaction_id: + type: string + format: uuid + description: This is a unique value which persists across all API calls from search through confirm + message_id: + type: string + format: uuid + description: This is a unique value which persists during a request / callback cycle + timestamp: + type: string + format: date-time + description: Time of request generation in RFC3339 format + key: + type: string + description: The encryption public key of the sender + ttl: + type: string + description: The duration in ISO8601 format after timestamp for which this message holds valid + Country: + description: Describes a country. + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + DecimalValue: + description: Describes a decimal value + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: Describes an error object + type: object + properties: + type: + type: string + enum: + - CONTEXT-ERROR + - CORE-ERROR + - DOMAIN-ERROR + - POLICY-ERROR + - JSON-SCHEMA-ERROR + code: + type: string + description: "Beckn specific error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-RFC-005-ERROR-CODES-DRAFT-01.md of this repo" + path: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error + required: + - type + - code + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to get a Learning and Career Development Resources. The BAP can declare the intent of the consumer containing
  • What they want (scholarship, job, course etc)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of an entity, entitiy can be a scholarship facilitator, course provider etc + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Describes a tracking object. it can be used to track the status of a service, i.e, a scholarship application, a course etc. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required for the order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, A scholarship application may require additional details on the applicant as a proof of eligibility. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean diff --git a/layer2/samples/dsep_scholarships_1.1.0.yaml b/layer2/samples/dsep_scholarships_1.1.0.yaml new file mode 100644 index 0000000..bfac183 --- /dev/null +++ b/layer2/samples/dsep_scholarships_1.1.0.yaml @@ -0,0 +1,3063 @@ +openapi: 3.0.0 +info: + title: Decentralized Skilling and Education Protocol Specification + description: Adaptation of beckn protocol for the domain of skilling and education + version: 0.7.0 + +security: + - SubscriberAuth: [] + - GatewaySubscriberAuthNew: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: This allows a BAP to discover for catalogs offering
a) Jobs and Internships
b) Trainings and Courses
c) Mentors and Coaches and,
d) Scholarships and Grants + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + examples: + Search for 'web design' jobs by category code in the region of Delhi: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + category: + descriptor: + name: Web design jobs + code: nic2008:62012 + Search for jobs by skills like carpentry and painting: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + fulfillment: + customer: + person: + skills: + - name: Painting + - name: Carpentry + tags: + - descriptor: + name: Competence + list: + - descriptor: + name: Experience + value: 12Y + + Search for jobs along with expected salary: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + fulfillment: + customer: + person: + skills: + - name: Java Programming + tags: + - descriptor: + name: Competence + list: + - descriptor: + name: Experience + value: 12Y + tags: + - descriptor: + name: Expectations + list: + - descriptor: + name: expected_payment + value: 250000INR/Month + + Search for jobs offered by a specific provider: + value: + context: + domain: jobs + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + intent: + provider: + descriptor: + name: Infosys + Search for online courses matching a specific topic: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + item: + descriptor: + name: AI basics + tags: + - descriptor: + name: course_labels + list: + - descriptor: + name: label_1 + value: AI + - descriptor: + name: label_2 + value: ML + - descriptor: + name: label_3 + value: beginners + - descriptor: + name: label_4 + value: Artifical Intelligence + - descriptor: + name: label_5 + value: machine learning + - descriptor: + name: label_6 + value: neural networks + fulfillment: + type: FULL-TIME + Search for BTech courses offered by an engineering instituition like IIT Delhi: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + provider: + descriptor: + name: IIT Delhi + tags: + - descriptor: + name: course_labels + list: + - descriptor: + name: label_1 + value: AI + - descriptor: + name: label_2 + value: ML + - descriptor: + name: label_3 + value: beginners + - descriptor: + name: label_4 + value: Artifical Intelligence + - descriptor: + name: label_5 + value: machine learning + - descriptor: + name: label_6 + value: neural networks + category: + descriptor: + name: B.Tech + code: BTECH + fulfillment: + type: FULL-TIME + Searching for a mentor by name: + value: + context: + domain: mentorship-and-coaching + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + fulfillment: + agent: + name: Dr Rajiv Manocha + Search for scholarships: + value: + context: + domain: mentorship + location: + city: + code: std:011 + country: + code: IND + action: search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/v0/ + bpp_id: https://mymentor.com/ + bpp_uri: https://api.mymentor.com/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + ttl: P10S + message: + intent: + category: + id: "4" + descriptor: + name: Engineering and Technology + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: API for Selecting items from the catalog. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + description: Contact support + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /on_search: + post: + tags: + - Beckn App Platform (BAP) + - Beckn Gateway (BG) + description: Send catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + examples: + Publish a catalog of software jobs by a software agency: + value: + context: + domain: jobs:nic2008:62XXX + location: + city: + code: "*" + country: + code: IND + action: on_search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + bpp_id: https://naukri.com/ + bpp_uri: https://api.naukri.com/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + catalog: + descriptor: + name: Naukri Recruitment Platform + providers: + - descriptor: + name: Infosys + categories: + - id: "1" + name: Frontend Jobs + - id: "2" + name: Backend Jobs + items: + - descriptor: + name: Senior Software Developer + code: SSFD + fulfillment_ids: + - "1" + category_ids: + - "1" + matched: true + - descriptor: + name: Software Consultant - On site + code: SWCO + fulfillment_ids: + - "1" + category_ids: + - "1" + matched: "false" + - descriptor: + name: Software Consultant - Remote + code: SWCR + fulfillment_ids: + - "2" + category_ids: + - "2" + matched: "false" + fulfillments: + - id: "1" + descriptor: + name: Full-time + stops: + - location: + city: + code: BLR + - id: "2" + descriptor: + name: On-site + stops: + - location: + city: + code: BLR + type: start + time: + timestamp: "2022-08-10" + - location: + city: BLR + type: end + time: + timestamp: "2022-08-10" + - id: "3" + descriptor: + name: Remote + stops: + - time: + timestamp: "2022-08-10" + type: start + - time: + timestamp: "2022-08-10" + type: end + Publish a catalog of online courses: + value: + context: + domain: trainings-and-courses + location: + city: + code: std:011 + country: + code: IND + action: on_search + version: 1.1.0 + bap_id: https://exampleapp.io/ + bap_uri: https://api.exampleapp.io/uhi/v0/ + message_id: 5ac3dd78-829e-4c7d-9139-a15adbb582cc + timestamp: "2021-03-23T10:00:40.065Z" + message: + catalog: + descriptor: + name: XAcademy + providers: + - descriptor: + name: XAcademy + categories: + - id: "1" + name: Software + - id: "2" + name: Management + items: + - id: "1" + descriptor: + name: Basics of AI + price: + value: "6000" + fulfillment_ids: + - "1" + category_ids: + - "1" + - id: "2" + descriptor: + name: AI for Data Analysis + price: + value: "7000" + fulfillment_ids: + - "1" + category_ids: + - "1" + fulfillments: + - id: "1" + type: ONLINE + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - context + /on_select: + post: + tags: + - Beckn App Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_init: + post: + tags: + - Beckn App Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_confirm: + post: + tags: + - Beckn App Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_track: + post: + tags: + - Beckn App Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_cancel: + post: + tags: + - Beckn App Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_update: + post: + tags: + - Beckn App Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_status: + post: + tags: + - Beckn App Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_rating: + post: + tags: + - Beckn App Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /on_support: + post: + tags: + - Beckn App Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_cancellation_reasons: + post: + tags: + - BPP Meta APIs + description: Get cancellation reasons from the BPP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /cancellation_reasons: + post: + tags: + - BAP Meta APIs + description: Get cancellation reasons from the BPP + requestBody: + description: List of cancellation reasons + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + message: + type: object + properties: + cancellation_reasons: + type: array + items: + $ref: "#/components/schemas/Option" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_return_reasons: + post: + tags: + - BPP Meta APIs + description: Get return reasons from the BPP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /return_reasons: + post: + tags: + - BAP Meta APIs + description: Get return reasons from the BPP + requestBody: + description: List of return reasons + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + return_reasons: + type: array + items: + $ref: "#/components/schemas/Option" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /get_rating_categories: + post: + tags: + - BPP Meta APIs + description: Get a list of categories that can be rated by the BAP + requestBody: + description: Context header is sent as the request + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + + /rating_categories: + post: + tags: + - BAP Meta APIs + description: Get a list of categories that can be rated by the BAP + requestBody: + description: Array of categories which can be rated + content: + application/json: + schema: + type: object + properties: + context: + $ref: "#/components/schemas/Context" + rating_categories: + type: array + items: + $ref: "#/components/schemas/Rating/properties/rating_category" + responses: + "200": + description: Acknowledgement of message received + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + $ref: "#/components/schemas/Ack" + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + GatewaySubscriberAuth: + type: apiKey + in: header + name: Proxy-Authorization + description: 'Signature of message body + BAP/BPP''s Authorization header using BG''s signing public key. Format:

Proxy-Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"

Note:This header will be deprecated soon and will no longer be supported in future releases. New implementors are requested to use the X-Gateway-Authorization header. Existing implementations are requested to migrate their header to the new header. The deprecation date will be set after discussion as per the standard specification governance process.

' + GatewaySubscriberAuthNew: + type: apiKey + in: header + name: X-Gateway-Authorization + description: 'Signature of message body + BAP/BPP''s Authorization header using BG''s signing public key. Format:

X-Gateway-Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: This describes an acknowledgement of receipt of a message. Upon receiving a message, the receiver must first authenticate the sender by verifying its digital signature. Upon successful verification of the signature, the receiver must validate the schema of the message. After performing both the operations, the receiver should send an Ack object in response. + type: object + properties: + status: + type: string + description: "Describe the status of the ACK response. If the message passes the acknowledgement criteria, then the receiver shouls set this value equal to ACK else it should be set to NACK" + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: This is typically an optional product or service that can be offered in addition to a product or a service of type Item. Objects of type AddOn should not exist without an associated Item. If a BAP receives an Item with an add-on, it must show it to the user as a selectable object. If any AddOn object is found without an associated Item object, then the validator must throw an error 'NO-PARENT=ITEM' with message 'No parent found' + type: object + properties: + id: + type: string + description: ID of the add-on as present in the source catalog + optional: + type: boolean + default: false + description: This value indicates if the add-on is optional or required to be selected by the user along with an Item. If this value is set to true, then the BAP must ensure that the add-on is mandatorily selected by the user while creating the Order object with the Item. + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes a person who fulfills this order." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: Describes the billing details of an order. This must be provided by BAP user before confirmation of the order. + type: object + properties: + name: + description: Name of the person under who's name the bill will be generated. + type: string + organization: + description: Name of the organization under who's name the bill will be generated. + allOf: + - $ref: "#/components/schemas/Organization" + address: + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address of the person / organization being billed. The BPP must send the bill to this email address. The format of the bill may be defined in the network policy. + type: string + format: email + phone: + description: Phone number of the person / organization being billed. The BPP must send the bill to this phone number as per the format specified in the network policy. In case the bill is a downloadable file, it is recommended the bill should be sent to the phone number as a downloadable link. + type: string + time: + $ref: "#/components/schemas/Time" + tax_id: + description: This is the identity of a Tax-paying person or an organization. This number can be provided to the BPP to avail tax benefits, if applicable. The format of this string should be specified in the network policy + type: string + created_at: + description: Date and time at which this bill was generated by the BPP. + type: string + format: date-time + + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the seeker + type: string + format: date-time + cancelled_by: + type: string + enum: + - SEEKER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + + CancellationTerm: + description: Describes the cancellation terms of an order, i.e, scholarship application, course etc. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes a skilling and education catalog" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: Describes a category + type: object + properties: + id: + type: string + description: Unique id of the category + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular area on the map + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + type: string + description: Name of the city + code: + type: string + description: City code + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: Describes a beckn message context + type: object + properties: + domain: + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + type: string + description: Defines the Beckn API call type. + version: + type: string + description: Version of Beckn core API specification being used + bap_id: + type: string + description: Unique id of the BAP. By default it is the fully qualified domain name of the BAP + bap_uri: + type: string + format: uri + description: URI of the BAP for accepting callbacks. Must have the same domain name as the bap_id + bpp_id: + type: string + description: Unique id of the BPP. By default it is the fully qualified domain name of the BPP + bpp_uri: + type: string + format: uri + description: URI of the BPP. Must have the same domain name as the bap_id + transaction_id: + type: string + format: uuid + description: This is a unique value which persists across all API calls from search through confirm + message_id: + type: string + format: uuid + description: This is a unique value which persists during a request / callback cycle + timestamp: + type: string + format: date-time + description: Time of request generation in RFC3339 format + key: + type: string + description: The encryption public key of the sender + ttl: + type: string + description: The duration in ISO8601 format after timestamp for which this message holds valid + Country: + description: Describes a country. + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + DecimalValue: + description: Describes a decimal value + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: Describes an error object + type: object + properties: + type: + type: string + enum: + - CONTEXT-ERROR + - CORE-ERROR + - DOMAIN-ERROR + - POLICY-ERROR + - JSON-SCHEMA-ERROR + code: + type: string + description: "Beckn specific error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-RFC-005-ERROR-CODES-DRAFT-01.md of this repo" + path: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error + required: + - type + - code + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to get a Learning and Career Development Resources. The BAP can declare the intent of the consumer containing
  • What they want (scholarship, job, course etc)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of an entity, entitiy can be a scholarship facilitator, course provider etc + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Describes a tracking object. it can be used to track the status of a service, i.e, a scholarship application, a course etc. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required for the order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, A scholarship application may require additional details on the applicant as a proof of eligibility. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean diff --git a/layer2/samples/retail_1.1.0.yaml b/layer2/samples/retail_1.1.0.yaml index b3ae63c..e57689e 100644 --- a/layer2/samples/retail_1.1.0.yaml +++ b/layer2/samples/retail_1.1.0.yaml @@ -1,7 +1,7 @@ openapi: 3.0.0 info: - title: Beckn Protocol Core - description: retail layer 2 config from core yaml + title: Beckn for Local Retail + description: Adaptation of beckn protocol for the local retail domain version: 1.1.0 security: - SubscriberAuth: [] @@ -11,7 +11,7 @@ paths: tags: - Beckn Provider Platform (BPP) - Beckn Gateway (BG) - description: BAP declares the customer's intent to buy/avail products or services + description: BAP declares the customer's intent to buy products from retail providers requestBody: content: application/json: From 0892185a5d76ad8c90649b3de3467cdd8ba2a7cb Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 17 Apr 2024 08:02:53 +0530 Subject: [PATCH 038/102] wip --- install/beckn-onix.sh | 23 +---------------------- install/docker-compose-v2.yml | 9 ++++++--- 2 files changed, 7 insertions(+), 25 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index e95574e..afdfd84 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -166,34 +166,17 @@ read -p "Enter your choice: " choice boldGreen="\e[1m\e[92m" reset="\e[0m" -# Function to request network configuration URL -requestNetworkConfig() { - echo "Please provide the network-specific configuration URL." - read -p "Paste the URL of the network configuration here (or press Enter to skip): " config_url - if [ -n "$config_url" ]; then - echo "Network configuration URL provided: $config_url" - else - echo "No network configuration URL provided, proceeding without it." - fi - echo "" -} - # Function to handle the setup process for each platform completeSetup() { platform=$1 - config_url=$2 # Passing this as an argument, though it could be optional or ignored by some setups public_address="https://" echo "Proceeding with the setup for $platform..." - if [ -n "$config_url" ]; then - echo "Using network configuration from: $config_url" - fi # Insert the specific commands for each platform, including requesting network config if necessary case $platform in "Registry") - requestNetworkConfig read -p "Enter publicly accessible registry URL: " registry_url if [[ $registry_url =~ /$ ]]; then new_registry_url=${registry_url%/} @@ -205,7 +188,6 @@ completeSetup() { install_registry $new_registry_url ;; "Gateway"|"Beckn Gateway") - requestNetworkConfig read -p "Enter your registry URL: " registry_url read -p "Enter publicly accessible gateway URL: " gateway_url @@ -223,7 +205,6 @@ completeSetup() { install_gateway $new_registry_url $gateway_url ;; "BAP") - requestNetworkConfig echo "${GREEN}................Installing Protocol Server for BAP................${NC}" read -p "Enter BAP Subscriber ID: " bap_subscriber_id @@ -235,7 +216,6 @@ completeSetup() { install_bap_protocol_server $registry_url $bap_subscriber_id $bap_subscriber_key_id $bap_subscriber_url ;; "BPP") - requestNetworkConfig echo "${GREEN}................Installing Protocol Server for BAP................${NC}" read -p "Enter BPP Subscriber ID: " bpp_subscriber_id read -p "Enter BPP Subscriber URL: " bpp_subscriber_url @@ -274,8 +254,7 @@ read -p "Enter your choice: " platform_choice selected_platform="${platforms[$((platform_choice-1))]}" if [[ -n $selected_platform ]]; then - # Note: Passing an empty string for config_url since it's optionally handled within `completeSetup` - completeSetup "$selected_platform" "" + completeSetup "$selected_platform" else echo "Invalid option. Please restart the script and select a valid option." exit 1 diff --git a/install/docker-compose-v2.yml b/install/docker-compose-v2.yml index fde4301..92164df 100644 --- a/install/docker-compose-v2.yml +++ b/install/docker-compose-v2.yml @@ -1,4 +1,4 @@ -version: '3' +version: "3" services: registry: @@ -12,7 +12,7 @@ services: restart: unless-stopped volumes: - registry_data_volume:/registry/overrideProperties/config - - registry_data_volume:/registry/database + - registry_database_volume:/registry/database gateway: image: fidedocker/gateway @@ -111,10 +111,13 @@ networks: volumes: registry_data_volume: name: registry_data_volume + external: true registry_database_volume: name: registry_database_volume + external: true gateway_data_volume: name: gateway_data_volume + external: true gateway_database_volume: name: gateway_database_volume - + external: true From 0e4193bc908760de844ce375e390a655947aad42 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 17 Apr 2024 09:51:16 +0530 Subject: [PATCH 039/102] Separate yml file to limit unnecessary volumes --- install/beckn-onix.sh | 19 ++++++++------- install/docker-compose-bap.yml | 27 ++++++++++++++++++++++ install/docker-compose-bpp.yml | 28 +++++++++++++++++++++++ install/docker-compose-gateway.yml | 27 ++++++++++++++++++++++ install/docker-compose-registry.yml | 27 ++++++++++++++++++++++ install/scripts/update_gateway_details.sh | 2 +- 6 files changed, 121 insertions(+), 9 deletions(-) create mode 100644 install/docker-compose-bap.yml create mode 100644 install/docker-compose-bpp.yml create mode 100644 install/docker-compose-gateway.yml create mode 100644 install/docker-compose-registry.yml diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index afdfd84..2611e77 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -12,7 +12,7 @@ install_package(){ start_container(){ #ignore orphaned containers warning export COMPOSE_IGNORE_ORPHANS=1 - docker-compose -f docker-compose-v2.yml up -d $1 + docker-compose -f $1 up -d $2 } update_registry_details() { @@ -50,7 +50,10 @@ update_registry_details() { docker volume create registry_data_volume docker run --rm -v $SCRIPT_DIR/../registry_data/config:/source -v registry_data_volume:/target busybox cp /source/{envvars,logger.properties,swf.properties} /target/ docker volume create registry_database_volume - docker run --rm -v $SCRIPT_DIR/../registry_data/database:/source -v registry_database_volume:/target busybox cp /source/db.txt /target/db.txt + if [ -e $SCRIPT_DIR/../registry_data/database/db.txt ] + then + docker run --rm -v $SCRIPT_DIR/../registry_data/database:/source -v registry_database_volume:/target busybox cp /source/db.txt /target/db.txt + fi docker rmi busybox } # Function to start the MongoDB, Redis, and RabbitMQ Services @@ -77,7 +80,7 @@ install_gateway() { bash scripts/update_gateway_details.sh registry fi echo "${GREEN}................Installing Gateway service................${NC}" - start_container gateway + start_container "docker-compose-gateway.yml" gateway echo "Registering Gateway in the registry" sleep 10 @@ -99,7 +102,7 @@ install_registry(){ fi echo "${GREEN}................Installing Registry service................${NC}" - start_container registry + start_container "docker-compose-registry.yml" registry sleep 10 echo "Registry installation successful" } @@ -117,8 +120,8 @@ install_bap_protocol_server(){ bash scripts/update_bap_config.sh fi sleep 10 - start_container "bap-client" - start_container "bap-network" + start_container "docker-compose-bap.yml" "bap-client" + start_container "docker-compose-bap.yml" "bap-network" sleep 10 echo "Protocol server BAP installation successful" } @@ -141,8 +144,8 @@ install_bpp_protocol_server(){ fi sleep 10 - start_container "bpp-client" - start_container "bpp-network" + start_container "docker-compose-bpp.yml" "bpp-client" + start_container "docker-compose-bpp.yml" "bpp-network" sleep 10 echo "Protocol server BPP installation successful" } diff --git a/install/docker-compose-bap.yml b/install/docker-compose-bap.yml new file mode 100644 index 0000000..6aced59 --- /dev/null +++ b/install/docker-compose-bap.yml @@ -0,0 +1,27 @@ +version: "3" + +services: + bap-client: + image: fidedocker/protocol-server + container_name: bap-client + networks: + - beckn_network + ports: + - 5001:5001 + restart: unless-stopped + volumes: + - ./protocol-server-data/bap-client.yml:/usr/src/app/config/default.yml + + bap-network: + image: fidedocker/protocol-server + container_name: bap-network + networks: + - beckn_network + ports: + - 5002:5002 + restart: unless-stopped + volumes: + - ./protocol-server-data/bap-network.yml:/usr/src/app/config/default.yml +networks: + beckn_network: + driver: bridge diff --git a/install/docker-compose-bpp.yml b/install/docker-compose-bpp.yml new file mode 100644 index 0000000..5e50b81 --- /dev/null +++ b/install/docker-compose-bpp.yml @@ -0,0 +1,28 @@ +version: "3" + +services: + bpp-client: + image: fidedocker/protocol-server + container_name: bpp-client + networks: + - beckn_network + ports: + - 6001:6001 + restart: unless-stopped + volumes: + - ./protocol-server-data/bpp-client.yml:/usr/src/app/config/default.yml + + bpp-network: + image: fidedocker/protocol-server + container_name: bpp-network + networks: + - beckn_network + ports: + - 6002:6002 + restart: unless-stopped + volumes: + - ./protocol-server-data/bpp-network.yml:/usr/src/app/config/default.yml + +networks: + beckn_network: + driver: bridge diff --git a/install/docker-compose-gateway.yml b/install/docker-compose-gateway.yml new file mode 100644 index 0000000..67113c5 --- /dev/null +++ b/install/docker-compose-gateway.yml @@ -0,0 +1,27 @@ +version: "3" + +services: + gateway: + image: fidedocker/gateway + container_name: gateway + networks: + - beckn_network + ports: + - 4000:4000 + - 4030:4030 + restart: unless-stopped + volumes: + - gateway_data_volume:/gateway/overrideProperties/config + - gateway_database_volume:/gateway/database + +networks: + beckn_network: + driver: bridge + +volumes: + gateway_data_volume: + name: gateway_data_volume + external: true + gateway_database_volume: + name: gateway_database_volume + external: true diff --git a/install/docker-compose-registry.yml b/install/docker-compose-registry.yml new file mode 100644 index 0000000..dad20af --- /dev/null +++ b/install/docker-compose-registry.yml @@ -0,0 +1,27 @@ +version: "3" + +services: + registry: + image: fidedocker/registry + container_name: registry + networks: + - beckn_network + ports: + - 3000:3000 + - 3030:3030 + restart: unless-stopped + volumes: + - registry_data_volume:/registry/overrideProperties/config + - registry_database_volume:/registry/database + +networks: + beckn_network: + driver: bridge + +volumes: + registry_data_volume: + name: registry_data_volume + external: true + registry_database_volume: + name: registry_database_volume + external: true diff --git a/install/scripts/update_gateway_details.sh b/install/scripts/update_gateway_details.sh index 9cdd8c3..c26b472 100755 --- a/install/scripts/update_gateway_details.sh +++ b/install/scripts/update_gateway_details.sh @@ -53,7 +53,7 @@ update_gateway_config() { docker volume create gateway_data_volume docker volume create gateway_database_volume docker run --rm -v $SCRIPT_DIR/../gateway_data/config:/source -v gateway_data_volume:/target busybox cp /source/{envvars,logger.properties,swf.properties} /target/ - docker run --rm -v $SCRIPT_DIR/../registry_data/database:/source -v gateway_database_volume:/target busybox cp /source/db.txt /target/db.txt + docker run --rm -v $SCRIPT_DIR/../gateway_data/database:/source -v gateway_database_volume:/target busybox cp /source/db.txt /target/db.txt update_network_json } From 86fc70bfe1bfb58d5d729bd22e53285e83394143 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 17 Apr 2024 10:23:32 +0530 Subject: [PATCH 040/102] Check for existence of db.txt before copying --- install/scripts/update_gateway_details.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/install/scripts/update_gateway_details.sh b/install/scripts/update_gateway_details.sh index c26b472..392fa22 100755 --- a/install/scripts/update_gateway_details.sh +++ b/install/scripts/update_gateway_details.sh @@ -53,7 +53,10 @@ update_gateway_config() { docker volume create gateway_data_volume docker volume create gateway_database_volume docker run --rm -v $SCRIPT_DIR/../gateway_data/config:/source -v gateway_data_volume:/target busybox cp /source/{envvars,logger.properties,swf.properties} /target/ - docker run --rm -v $SCRIPT_DIR/../gateway_data/database:/source -v gateway_database_volume:/target busybox cp /source/db.txt /target/db.txt + if [ -e $SCRIPT_DIR/../gateway_data/database/db.txt ] + then + docker run --rm -v $SCRIPT_DIR/../gateway_data/database:/source -v gateway_database_volume:/target busybox cp /source/db.txt /target/db.txt + fi update_network_json } From 2b70ebe0cbafb104588d0ca6fdc8e3b56c33ac1b Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 17 Apr 2024 12:09:44 +0530 Subject: [PATCH 041/102] Remove unwanted db.txt copy --- install/beckn-onix.sh | 6 +----- install/scripts/update_gateway_details.sh | 4 ---- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 2611e77..6f61127 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -48,12 +48,8 @@ update_registry_details() { sed "s|REGISTRY_URL|$registry_url|g; s|REGISTRY_PORT|$registry_port|g; s|PROTOCOL|$protocol|g" "$config_file" > "$tmp_file" mv "$tmp_file" "$config_file" docker volume create registry_data_volume - docker run --rm -v $SCRIPT_DIR/../registry_data/config:/source -v registry_data_volume:/target busybox cp /source/{envvars,logger.properties,swf.properties} /target/ docker volume create registry_database_volume - if [ -e $SCRIPT_DIR/../registry_data/database/db.txt ] - then - docker run --rm -v $SCRIPT_DIR/../registry_data/database:/source -v registry_database_volume:/target busybox cp /source/db.txt /target/db.txt - fi + docker run --rm -v $SCRIPT_DIR/../registry_data/config:/source -v registry_data_volume:/target busybox cp /source/{envvars,logger.properties,swf.properties} /target/ docker rmi busybox } # Function to start the MongoDB, Redis, and RabbitMQ Services diff --git a/install/scripts/update_gateway_details.sh b/install/scripts/update_gateway_details.sh index 392fa22..2eec117 100755 --- a/install/scripts/update_gateway_details.sh +++ b/install/scripts/update_gateway_details.sh @@ -53,10 +53,6 @@ update_gateway_config() { docker volume create gateway_data_volume docker volume create gateway_database_volume docker run --rm -v $SCRIPT_DIR/../gateway_data/config:/source -v gateway_data_volume:/target busybox cp /source/{envvars,logger.properties,swf.properties} /target/ - if [ -e $SCRIPT_DIR/../gateway_data/database/db.txt ] - then - docker run --rm -v $SCRIPT_DIR/../gateway_data/database:/source -v gateway_database_volume:/target busybox cp /source/db.txt /target/db.txt - fi update_network_json } From 025f7997b7a17aeadd6c81c79440c76dca53990d Mon Sep 17 00:00:00 2001 From: Venkatesh Babu <154209057+vbabuEM@users.noreply.github.com> Date: Wed, 17 Apr 2024 14:47:10 +0530 Subject: [PATCH 042/102] Use docker volumes for support services and bap/bpp (#54) * Add volumes for bap * Add volumes for bpp * Fix typo * Remove version due to obsolete warning --- install/beckn-onix.sh | 16 ++++++++++++++++ install/docker-compose-app.yml | 15 ++++++++++----- install/docker-compose-bap.yml | 28 ++++++++++++++++++++++++---- install/docker-compose-bpp.yml | 27 +++++++++++++++++++++++---- install/docker-compose-gateway.yml | 3 +-- install/docker-compose-registry.yml | 3 +-- install/docker-compose-v2.yml | 3 +-- install/docker-compose.yml | 4 +--- install/scripts/update_bpp_config.sh | 2 +- 9 files changed, 78 insertions(+), 23 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 6f61127..5d63036 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -116,6 +116,14 @@ install_bap_protocol_server(){ bash scripts/update_bap_config.sh fi sleep 10 + docker volume create bap_client_config_volume + docker volume create bap_network_config_volume + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bap_client_config_volume:/target busybox cp /source/bap-client.yml /target/default.yml + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bap_client_config_volume:/target busybox cp /source/bap-client.yaml-sample /target + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bap_network_config_volume:/target busybox cp /source/bap-network.yml /target/default.yml + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bap_network_config_volume:/target busybox cp /source/bap-network.yaml-sample /target + docker rmi busybox + start_container "docker-compose-bap.yml" "bap-client" start_container "docker-compose-bap.yml" "bap-network" sleep 10 @@ -140,6 +148,14 @@ install_bpp_protocol_server(){ fi sleep 10 + docker volume create bpp_client_config_volume + docker volume create bpp_network_config_volume + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bpp_client_config_volume:/target busybox cp /source/bpp-client.yml /target/default.yml + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bpp_client_config_volume:/target busybox cp /source/bpp-client.yaml-sample /target + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bpp_network_config_volume:/target busybox cp /source/bpp-network.yml /target/default.yml + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bpp_network_config_volume:/target busybox cp /source/bpp-network.yaml-sample /target + docker rmi busybox + start_container "docker-compose-bpp.yml" "bpp-client" start_container "docker-compose-bpp.yml" "bpp-network" sleep 10 diff --git a/install/docker-compose-app.yml b/install/docker-compose-app.yml index b31bac4..ce15d6b 100644 --- a/install/docker-compose-app.yml +++ b/install/docker-compose-app.yml @@ -1,12 +1,10 @@ -version: "3" - services: mongo_db: image: mongo restart: unless-stopped container_name: mongoDB volumes: - - ./docker_data/mongo_DB:/data/db + - beckn_mongo_db:/data/db networks: - beckn_network ports: @@ -25,7 +23,7 @@ services: ports: - "6379:6379" volumes: - - ./docker_data/redis_DB:/data + - beckn_redis:/data queue_service: image: rabbitmq:3.9.11-management-alpine @@ -43,4 +41,11 @@ services: networks: beckn_network: - driver: bridge \ No newline at end of file + name: beckn_network + driver: bridge + +volumes: + beckn_mongo_db: + name: beckn_mongo_db + beckn_redis: + name: beckn_redis diff --git a/install/docker-compose-bap.yml b/install/docker-compose-bap.yml index 6aced59..5c9e83b 100644 --- a/install/docker-compose-bap.yml +++ b/install/docker-compose-bap.yml @@ -1,5 +1,3 @@ -version: "3" - services: bap-client: image: fidedocker/protocol-server @@ -10,7 +8,9 @@ services: - 5001:5001 restart: unless-stopped volumes: - - ./protocol-server-data/bap-client.yml:/usr/src/app/config/default.yml + - bap_client_config_volume:/usr/src/app/config + - bap_client_schemas_volume:/usr/src/app/schemas + - bap_client_logs_volume:/usr/src/app/logs bap-network: image: fidedocker/protocol-server @@ -21,7 +21,27 @@ services: - 5002:5002 restart: unless-stopped volumes: - - ./protocol-server-data/bap-network.yml:/usr/src/app/config/default.yml + - bap_network_config_volume:/usr/src/app/config + - bap_network_schemas_volume:/usr/src/app/schemas + - bap_network_logs_volume:/usr/src/app/logs + networks: beckn_network: + name: beckn_network driver: bridge + +volumes: + bap_client_config_volume: + name: bap_client_config_volume + external: true + bap_client_schemas_volume: + name: bap_client_schemas_volume + bap_client_logs_volume: + name: bap_client_logs_volume + bap_network_config_volume: + name: bap_network_config_volume + external: true + bap_network_schemas_volume: + name: bap_network_schemas_volume + bap_network_logs_volume: + name: bap_network_logs_volume diff --git a/install/docker-compose-bpp.yml b/install/docker-compose-bpp.yml index 5e50b81..2747275 100644 --- a/install/docker-compose-bpp.yml +++ b/install/docker-compose-bpp.yml @@ -1,5 +1,3 @@ -version: "3" - services: bpp-client: image: fidedocker/protocol-server @@ -10,7 +8,9 @@ services: - 6001:6001 restart: unless-stopped volumes: - - ./protocol-server-data/bpp-client.yml:/usr/src/app/config/default.yml + - bpp_client_config_volume:/usr/src/app/config + - bpp_client_schemas_volume:/usr/src/app/schemas + - bpp_client_logs_volume:/usr/src/app/logs bpp-network: image: fidedocker/protocol-server @@ -21,8 +21,27 @@ services: - 6002:6002 restart: unless-stopped volumes: - - ./protocol-server-data/bpp-network.yml:/usr/src/app/config/default.yml + - bpp_network_config_volume:/usr/src/app/config + - bpp_network_schemas_volume:/usr/src/app/schemas + - bpp_network_logs_volume:/usr/src/app/logs networks: beckn_network: + name: beckn_network driver: bridge + +volumes: + bpp_client_config_volume: + name: bpp_client_config_volume + external: true + bpp_client_schemas_volume: + name: bpp_client_schemas_volume + bpp_client_logs_volume: + name: bpp_client_logs_volume + bpp_network_config_volume: + name: bpp_network_config_volume + external: true + bpp_network_schemas_volume: + name: bpp_network_schemas_volume + bpp_network_logs_volume: + name: bpp_network_logs_volume diff --git a/install/docker-compose-gateway.yml b/install/docker-compose-gateway.yml index 67113c5..96322dc 100644 --- a/install/docker-compose-gateway.yml +++ b/install/docker-compose-gateway.yml @@ -1,5 +1,3 @@ -version: "3" - services: gateway: image: fidedocker/gateway @@ -16,6 +14,7 @@ services: networks: beckn_network: + name: beckn_network driver: bridge volumes: diff --git a/install/docker-compose-registry.yml b/install/docker-compose-registry.yml index dad20af..a07d43f 100644 --- a/install/docker-compose-registry.yml +++ b/install/docker-compose-registry.yml @@ -1,5 +1,3 @@ -version: "3" - services: registry: image: fidedocker/registry @@ -16,6 +14,7 @@ services: networks: beckn_network: + name: beckn_network driver: bridge volumes: diff --git a/install/docker-compose-v2.yml b/install/docker-compose-v2.yml index 92164df..b73857b 100644 --- a/install/docker-compose-v2.yml +++ b/install/docker-compose-v2.yml @@ -1,5 +1,3 @@ -version: "3" - services: registry: image: fidedocker/registry @@ -106,6 +104,7 @@ services: networks: beckn_network: + name: beckn_network driver: bridge volumes: diff --git a/install/docker-compose.yml b/install/docker-compose.yml index eb44d7f..a7cea70 100644 --- a/install/docker-compose.yml +++ b/install/docker-compose.yml @@ -1,5 +1,3 @@ -version: '3' - services: registry: image: fidedocker/registry @@ -114,5 +112,5 @@ services: networks: beckn_network: + name: beckn_network driver: bridge - diff --git a/install/scripts/update_bpp_config.sh b/install/scripts/update_bpp_config.sh index 88106a6..fbd450d 100755 --- a/install/scripts/update_bpp_config.sh +++ b/install/scripts/update_bpp_config.sh @@ -117,7 +117,7 @@ else ) - echo "Configuring BAP protocol server" + echo "Configuring BPP protocol server" # Apply replacements in both files for file in "$clientFile" "$networkFile"; do for key in "${!replacements[@]}"; do From 15b6d86494457ab1519da42130b06f6fbbdb5149 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 17 Apr 2024 16:25:37 +0530 Subject: [PATCH 043/102] Add two more volumes --- install/docker-compose-app.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/install/docker-compose-app.yml b/install/docker-compose-app.yml index ce15d6b..c986658 100644 --- a/install/docker-compose-app.yml +++ b/install/docker-compose-app.yml @@ -5,6 +5,7 @@ services: container_name: mongoDB volumes: - beckn_mongo_db:/data/db + - beckn_mongo_config:/data/configdb networks: - beckn_network ports: @@ -34,6 +35,8 @@ services: ports: - "5672:5672" - "15672:15672" + volumes: + - beckn_rabbitmq:/var/lib/rabbitmq environment: AMQP_URL: "amqp://queue_service?connection_attempts=3&retry_delay=5" RABBITMQ_DEFAULT_USER: beckn @@ -47,5 +50,9 @@ networks: volumes: beckn_mongo_db: name: beckn_mongo_db + beckn_mongo_config: + name: beckn_mongo_config beckn_redis: name: beckn_redis + beckn_rabbitmq: + name: beckn_rabbitmq From d3729eab077aff9941a9a4dec99bb8e706124f86 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Fri, 19 Apr 2024 07:31:59 +0530 Subject: [PATCH 044/102] Removed gateway workaround from documentation as its not required anymore --- docs/demo_walkthrough.md | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/docs/demo_walkthrough.md b/docs/demo_walkthrough.md index 2a61f96..caeabf8 100644 --- a/docs/demo_walkthrough.md +++ b/docs/demo_walkthrough.md @@ -133,22 +133,6 @@ git clone https://github.com/beckn/beckn-onix.git ``` -- Due to a [known issue](https://github.com/beckn/beckn-onix/issues/8) with the new version of gateway, we need to do the following. This will be fixed by the project very soon and this step will not be required then. Open `beckn-onix/install/gateway_data/config/networks/onix.json` in an editor and change its contents to the following - -``` -{ - "core_version" : "1.1.0", - "registry_id": "onix-registry.becknprotocol.io..LREG", - "search_provider_id" : "onix-gateway.becknprotocol.io", - "self_registration_supported": true, - "subscription_needed_post_registration" : true, - "base_url": "https://onix-registry.becknprotocol.io", - "registry_url" : "https://onix-registry.becknprotocol.io/subscribers", - "extension_package": "in.succinct.beckn.boc", - "wild_card" : "" -} -``` - - Change into the install folder and run the beckn-onix.sh script. ``` From b979ddc574471194e367ad8466a23976806db2c2 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Fri, 19 Apr 2024 07:37:25 +0530 Subject: [PATCH 045/102] Fix user guide language --- README.md | 2 +- docs/demo_scenarios.md | 2 +- ...mo_walkthrough.md => setup_walkthrough.md} | 36 ------------------- docs/user_guide.md | 4 --- layer2/docs/demo_healthcare.md | 4 +-- 5 files changed, 4 insertions(+), 44 deletions(-) rename docs/{demo_walkthrough.md => setup_walkthrough.md} (94%) diff --git a/README.md b/README.md index f23a544..4cb4838 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ Within the install folder you will find a `beckn-onix.sh` file which is an insta Refer to the following documents for more information: - [User Guide](./docs/user_guide.md) -- [Step by step walkthrough of a demo installation](./docs/demo_walkthrough.md) +- [Step by step walkthrough of a setup](./docs/setup_walkthrough.md) - [Frequently asked questions (FAQ)](./docs/faq.md) - [release notes](./install/RELEASE.md) diff --git a/docs/demo_scenarios.md b/docs/demo_scenarios.md index c12203b..8dc6a61 100644 --- a/docs/demo_scenarios.md +++ b/docs/demo_scenarios.md @@ -1,6 +1,6 @@ ## Introduction -The [demo walkthrough](../docs/demo_walkthrough.md) and the accompanying video shows a story where we have the following steps +The [setup walkthrough](../docs/setup_walkthrough.md) and the accompanying video shows a story where we have the following steps 1. We install a core Beckn network using Beckn-ONIX 2. We try to conduct a retail transaction, but it fails due to layer 2 config not being present diff --git a/docs/demo_walkthrough.md b/docs/setup_walkthrough.md similarity index 94% rename from docs/demo_walkthrough.md rename to docs/setup_walkthrough.md index caeabf8..26f209c 100644 --- a/docs/demo_walkthrough.md +++ b/docs/setup_walkthrough.md @@ -87,19 +87,9 @@ Which platform would you like to set up? Enter your choice: 1 ``` -- Skip the option to apply network configuration - -``` -Proceeding with the setup for Registry... -Please provide the network-specific configuration URL. -Paste the URL of the network configuration here (or press Enter to skip): -``` - - Input the host name where the registry will reside as https://onix-registry.becknprotocol.io ``` -No network configuration URL provided, proceeding without it. - Enter publicly accessible registry URL: https://onix-registry.becknprotocol.io ``` @@ -167,19 +157,9 @@ Which platform would you like to set up? Enter your choice: 1 ``` -- Skip the option to apply network configuration - -``` -Proceeding with the setup for Gateway... -Please provide the network-specific configuration URL. -Paste the URL of the network configuration here (or press Enter to skip): -``` - - Input the URL of the registry we just now installed https://onix-registry.becknprotocol.io ``` -No network configuration URL provided, proceeding without it. - Enter your registry URL: https://onix-registry.becknprotocol.io ``` @@ -252,14 +232,6 @@ Which platform would you like to set up? Enter your choice: 2 ``` -- Skip the option to apply network configuration - -``` -Proceeding with the setup for BAP... -Please provide the network-specific configuration URL. -Paste the URL of the network configuration here (or press Enter to skip): -``` - - Input the BAP subscriber id - onix-bap.becknprotocol.io - Input the BAP URL - https://onix-bap.becknprotocol.io - Input the subscription endpoint of the registry - https://onix-registry.becknprotocol.io/subscribers @@ -347,14 +319,6 @@ Which platform would you like to set up? Enter your choice: 3 ``` -- Skip the option to apply network configuration - -``` -Proceeding with the setup for BPP... -Please provide the network-specific configuration URL. -Paste the URL of the network configuration here (or press Enter to skip): -``` - - Input BPP subscriber id as onix-bpp.becknprotocol.io - Input the BPP URL as https://onix-bpp.becknprotocol.io - Input the registry URL to subscribe as https://onix-registry.becknprotocol.io/subscribers diff --git a/docs/user_guide.md b/docs/user_guide.md index 94d3c63..7135c27 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -63,7 +63,6 @@ In the Beckn ecosystem, a new network starts with the setting up of the Registry - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to start a new network and install the registry -- Skip the apply network configuration option - Enter the publicly accessible address of the registry (e.g. https://onix-registry.becknprotocol.io) - The registry installation will continue to completion. @@ -85,7 +84,6 @@ In the Beckn ecosystem, the role of the Gateway is limited to the discovery phas - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to join an existing network and install the gateway -- Skip the apply network configuration option - Enter the address of the registry of the network you want to join (e.g. https://onix-registry.becknprotocol.io) - Enter the publicly accessible address of the gateway (e.g. https://onix-gateway.becknprotocol.io) - The gateway installation will continue to completion and it will register itself with the registry as a participant with role BG(Beckn Gateway) @@ -110,7 +108,6 @@ The BAP (Beckn Application Platform) is the bridge between buyer side applicatio - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to join an existing network and install the BAP. -- Skip the apply network configuration option - Enter the Subscriber id for the BAP. When setting up a new network, its value can be anything you want. However it is recommended to have it the same as the BAP URL without the https:// part (e.g. onix-bap.becknprotocol.io). In existing networks this might be further validated for uniqueness by the registry. - Enter the Subscriber URI for the BAP. This is the network endpoint of the BAP Beckn Adapter. (e.g. https://onix-bap.becknprotocol.io) - Enter the address of the subscription endpoint of the registry of the network you want to join (e.g. https://onix-registry.becknprotocol.io/subscribers). Note the suffix subscribers in the endpoint address. @@ -136,7 +133,6 @@ The BPP (Beckn Provider Platform) is the bridge between the seller side applicat - Change into the installation folder `cd beckn-onix/install` - Run the installation script `./beckn-onix.sh` - Specify you want to join an existing network and install the BPP. -- Skip the apply network configuration option - Enter the Subscriber id for the BPP. When setting up a new network, its value can be anything you want. However it is recommended to have it the same as the BPP URL without the https:// part (e.g. onix-bpp.becknprotocol.io). In existing networks this might be further validated for uniqueness by the registry. - Enter the Subscriber URL for the BPP (e.g. https://onix-bpp.becknprotocol.io). This is the network endpoint of the BPP Beckn Adapter. - Enter the webhook URL. This is the endpoint on your custom market place or headless shop which will receive Beckn requests. The endpoint usually contains the address of the market place or shop as a substring. (e.g. https://unified-bpp.becknprotocol.io/beckn-bpp-adapter) diff --git a/layer2/docs/demo_healthcare.md b/layer2/docs/demo_healthcare.md index 2abe50b..4076a17 100644 --- a/layer2/docs/demo_healthcare.md +++ b/layer2/docs/demo_healthcare.md @@ -4,7 +4,7 @@ [Beckn](https://becknprotocol.io/) as a protocol allows creation of decentralised commerce network across many domains. Healthcare is one of them. Beckn-ONIX is a project aimed at easing setup and maintanence of Beckn network for different domains. It provides utilities to quickly setup the core Beckn network as well as provides tools to enable domain specific transactions. The latter is achieved through the use of layer 2 configuration files. -The [Beckn-ONIX User Guide](./user_guide.md) provides an overall understanding of setup of the core Beckn network as well as download and ingestion of Layer 2 configuration files. The [step by step demo](./demo_walkthrough.md) walks through one such installation in great detail. The layer 2 configurations illustrated in that demo belong to the retail and energy domain. +The [Beckn-ONIX User Guide](./user_guide.md) provides an overall understanding of setup of the core Beckn network as well as download and ingestion of Layer 2 configuration files. The [step by step setup](./setup_walkthrough.md) walks through one such installation in great detail. The layer 2 configurations illustrated in that demo belong to the retail and energy domain. ## Healthcare usecases on Beckn network @@ -27,7 +27,7 @@ A sample of the usecases that can be imagined on Beckn networks include ## Setting up Beckn network for healthcare usecases -Setting up of a network for healthcare related use cases follows the same steps as illustrated in the [step by step demo](./demo_walkthrough.md) document. The primary differences is the layer 2 configuration file downloaded will be specific to healthcare and suited to conduct healthcare transactions. A sample layer 2 config for healthcare is available in the beckn_onix/layer2/samples folder and its path can be provided when running download_layer_2_config_bap.sh and download_layer_2_config_bpp.sh. If you are joining a network administered by a network facilitator, they might have a different layer 2 config and that should be used instead of the sample. +Setting up of a network for healthcare related use cases follows the same steps as illustrated in the [step by step setup](./setup_walkthrough.md) document. The primary differences is the layer 2 configuration file downloaded will be specific to healthcare and suited to conduct healthcare transactions. A sample layer 2 config for healthcare is available in the beckn_onix/layer2/samples folder and its path can be provided when running download_layer_2_config_bap.sh and download_layer_2_config_bpp.sh. If you are joining a network administered by a network facilitator, they might have a different layer 2 config and that should be used instead of the sample. The following is a conceptual view of core and layer 2 config from a perspective of validation ![Validation in Beckn Adaptor](./images/message_validation_in_ba.png) From 437676faf537140e3986c27d6fce36c03ab40041 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Mon, 29 Apr 2024 18:20:57 +0530 Subject: [PATCH 046/102] Changed from docker-compose to docker compose --- install/beckn-onix.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 5d63036..685852f 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -12,7 +12,7 @@ install_package(){ start_container(){ #ignore orphaned containers warning export COMPOSE_IGNORE_ORPHANS=1 - docker-compose -f $1 up -d $2 + docker compose -f $1 up -d $2 } update_registry_details() { From a90f189bb8d2d3652dea28f5b3300c570402933c Mon Sep 17 00:00:00 2001 From: Bhanu Prakash Reddy <126443511+em-tpt-bbandi@users.noreply.github.com> Date: Tue, 30 Apr 2024 10:50:56 +0530 Subject: [PATCH 047/102] Update beckn-onix.sh --- install/beckn-onix.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 685852f..0fb5812 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -57,15 +57,15 @@ start_support_services(){ #ignore orphaned containers warning export COMPOSE_IGNORE_ORPHANS=1 echo "${GREEN}................Installing MongoDB................${NC}" - docker-compose -f docker-compose-app.yml up -d mongo_db + docker compose -f docker-compose-app.yml up -d mongo_db echo "MongoDB installation successful" echo "${GREEN}................Installing RabbitMQ................${NC}" - docker-compose -f docker-compose-app.yml up -d queue_service + docker compose -f docker-compose-app.yml up -d queue_service echo "RabbitMQ installation successful" echo "${GREEN}................Installing Redis................${NC}" - docker-compose -f docker-compose-app.yml up -d redis_db + docker compose -f docker-compose-app.yml up -d redis_db echo "Redis installation successful" } From bae214bf30a7abc5c2f48118be18cb02d39febfe Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Thu, 2 May 2024 16:11:34 +0530 Subject: [PATCH 048/102] Fixes #62 Add BAP and BPP to documentation --- docs/images/request_flow.png | Bin 0 -> 42163 bytes docs/sample_nginx_configurations.md | 22 +++++----- docs/user_guide.md | 65 ++++++++++++++++++++++++++-- 3 files changed, 73 insertions(+), 14 deletions(-) create mode 100644 docs/images/request_flow.png diff --git a/docs/images/request_flow.png b/docs/images/request_flow.png new file mode 100644 index 0000000000000000000000000000000000000000..08f4e7f247e110f03dd416cd5f847e37fe9647f8 GIT binary patch literal 42163 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

ON7GB|@^0+wZYoRey}Ni8FP@GjyeE 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 literal 0 HcmV?d00001 diff --git a/docs/sample_nginx_configurations.md b/docs/sample_nginx_configurations.md index e69301b..66fc99f 100644 --- a/docs/sample_nginx_configurations.md +++ b/docs/sample_nginx_configurations.md @@ -356,21 +356,21 @@ server { listen 80; listen [::]:80; # Put the server name as website name . - server_name onix-bap.becknprotocol.io; + server_name onix-bpp-client.becknprotocol.io; location / { # This for Host, Client and Forwarded For - #proxy_set_header Host $http_host; + proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # For Web Sockets. - proxy_http_version 1.1; + #proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # For Proxy. - proxy_pass "http://localhost:5002"; + proxy_pass "http://localhost:6001"; } } @@ -379,33 +379,33 @@ server { listen [::]:443 ssl http2; # Put the server name as website name . - server_name onix-bap.becknprotocol.io; + server_name onix-bpp-client.becknprotocol.io; # Point it to the port in which you want to run the server http://localhost:. location / { # This for Host, Client and Forwarded For - #proxy_set_header Host $http_host; + proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; # For Web Sockets. - proxy_http_version 1.1; + #proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; # For Proxy. - proxy_pass "http://localhost:5002"; + proxy_pass "http://localhost:6001"; } # This is the path to certificate. /etc/letsencrypt/live//fullchain.pem - ssl_certificate /etc/letsencrypt/live/onix-bap.becknprotocol.io/fullchain.pem; + ssl_certificate /etc/letsencrypt/live/onix-bpp-client.becknprotocol.io/fullchain.pem; # This is the path to certificate. /etc/letsencrypt/live//privkey.pem - ssl_certificate_key /etc/letsencrypt/live/onix-bap.becknprotocol.io/privkey.pem; + ssl_certificate_key /etc/letsencrypt/live/onix-bpp-client.becknprotocol.io/privkey.pem; - ssl_session_timeout 1d; + ssl_session_timeout 1d; ssl_session_cache shared:MozSSL:10m; # about 40000 sessions ssl_session_tickets off; diff --git a/docs/user_guide.md b/docs/user_guide.md index 7135c27..227bb05 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -12,6 +12,8 @@ - [Setting up a BPP Beckn Adapter](#setting-up-a-bpp-beckn-adapter) - [Downloading Layer 2 Configuration for a domain](#downloading-layer-2-configuration-for-a-domain) - [Testing transactions on the network](#testing-transactions-on-the-new-network) + - [Connecting BAP Beckn Adapter to BAP Software](#connecting-bap-beckn-adapter-to-bapbuyer-side-software) + - [Connecting BPP Beckn Adapter to BPP Software](#connecting-bpp-beckn-adapter-to-bppseller-side-software) - [Running Beckn-ONIX locally](#running-beckn-onix-locally) - [Appendix A - subdomain/domain name configuration](#appendix-a---registering-or-adding-domain-or-subdomains) - [Appendix B - Nginx reverse proxy configuration](#appendix-b---nginx-reverse-proxy-configuration) @@ -121,11 +123,11 @@ The BPP (Beckn Provider Platform) is the bridge between the seller side applicat - Address of the registry's subscription endpoint of the network the BPP will join (e.g. https://onix-registry.becknprotocol.io/subscribers) - A domain or subdomain where the client endpoint of BPP will be accessible (e.g https://onix-bpp-client.becknprotocol.io) -- A domain or subdomain where the network endpoint of BPP will be accessible (e.g. https://onix-bap.becknprtocol.io) +- A domain or subdomain where the network endpoint of BPP will be accessible (e.g. https://onix-bpp.becknprtocol.io) - A virtual server with both the above mentioned domains/subdomains pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details - SSL certificate for the two endpoints and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) -- Reverse proxy configured to route the traffic at the bap client url (e.g. https://onix-bap-client.becknprotocol.io) to port 5001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) -- Reverse proxy configured to route the traffic at the bap network url (e.g. https://onix-bap.becknprotocol.io) to port 5002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bap client url (e.g. https://onix-bpp-client.becknprotocol.io) to port 6001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bap network url (e.g. https://onix-bpp.becknprotocol.io) to port 6002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) **Installation Steps** @@ -172,6 +174,63 @@ Currently the layer-2 config are per domain, though this might change with futur - We can use postman collection for the specific domain to test end to end communication on the domain. Some sample postman collections for testing are [present here](https://github.com/beckn/beckn-sandbox/tree/main/artefacts) - When running postman collection from the buyer side, the base url to which the requests are sent should be the client side endpoint of the BAP Beckn Adapter instance. (e.g https://onix-bap-client.becknprotocol.io) +### Connecting BAP Beckn Adapter to BAP(buyer side) software + +Currently Beckn ONIX only installs the reference BAP Adapter on the BAP machine. It does not install any reference buyer side software. However in real-world, buyer side BAP software will interact with this BAP Adapter to perform Beckn transactions. This section provides guidance on how to integrate the two. The following diagram shows the message flow from BAP all the way through to the BPP and back. + +![Request and response flow with BAP and BPP illustrated](./images/request_flow.png) + +The BAP software will typically be a Backend server that provides buying side functionality to users. It takes care of functionalities such as user authentication, profile management, Order flow, Order history and other functionalities common in a commerce application. Many of these functionalities are outside of Beckn scope. The Order flow is primarily where the software will use the BAP Beckn Adapter to communicate to the Beckn network. Typically the order flow within Beckn has four stages (Discovery, Order, Fulfillment and Post Fulfillment). Please refer to this [document](https://developers.becknprotocol.io/docs/introduction/beckn-protocol-specification/) for details on how the individual Beckn requests (currently ten) map to these. + +Taking an example of a user searching for an item, the user will typically enter his search request (say Arabica Coffee Powder) into the UI which will be conveyed to the BAP Backend server. The BAP backend server will call the BAP-Client endpoint with a Search request. This endpoint in the running example will be https://onix-bap-client.becknprotocol.io/search This endpoint as mentioned in the [Setting up a BAP Beckn Adapter](#setting-up-a-bap-beckn-adapter) should be configured to point to the BAP Beckn Adapter Client softare running at a port (default 5001) through Nginx configuration. The format of the message to be sent is explained in the [core specification](https://github.com/beckn/protocol-specifications/blob/master/api/transaction/build/transaction.yaml). An example is below + +``` +{ + "context": { + "domain": "retail", + "location": { + "country": { + "code": "IND" + }, + "city": { + "code": "std:080" + } + }, + "action": "search", + "version": "1.1.0", + "bap_id": "onix-bap.becknprotocol.io", + "bap_uri": "https://onix-bap.becknprotocol.io", + "transaction_id": "{{$randomUUID}}", + "message_id": "{{$randomUUID}}", + "timestamp": "{{$timestamp}}" + }, + "message": { + "intent": { + "item": { + "descriptor": { + "name": "Arabica Coffee Powder" + } + } + } + } +} +``` + +The reference implentation of the BAP Beckn Adapter will forward this to the Beckn network and return back with matching search results from different providers for the retail domain in the network. By default this happens in a synchronous manner, though it can be configured in the BAP Beckn Adapter Client Configuration (Refer to the "Protocol Server BAP Client Setup section" of this [document](https://github.com/beckn/protocol-server/blob/master/setup.md#protocol-server-bap-client-setup)) Refer to the [core protocol specification](https://github.com/beckn/protocol-specifications/blob/master/api/transaction/build/transaction.yaml) for the various other request and response formats for the rest of the order flow requests. + +### Connecting BPP Beckn Adapter to BPP(Seller side) software + +Currently Beckn-ONIX only installs the BPP Beckn Adapter reference implementation on the BPP machine. It does not install a reference implemenation of a market-place or BPP. Typically in real-world there is a backend server that provides seller functionality that talks to the BPP Beckn Adapter. This section describes how the interaction between BPP Beckn Adapter and such a server should occur. Refer to the image in the previous [section](#connecting-bap-beckn-adapter-to-bapbuyer-side-software) for an illustration of BAP and BPP integration along with message flow. + +The BPP software or market-place typically provides functionalities such as Login for shop owners, ability to manage inventory, list products, add product details, take an order, mark fulfillment of orders and aggregate post fulfillment feedback etc. While many of these functionalities are outside of the Beckn protocol, the BPP software will interact with the BPP Beckn Adapter for the order flow. The order flow typically involves Discovery, Order, Fulfillment and Post fulfillment phases and is explained in the context of Beckn [here](https://developers.becknprotocol.io/docs/introduction/beckn-protocol-specification/). The [core protocol specification](https://github.com/beckn/protocol-specifications/blob/master/api/transaction/build/transaction.yaml) explains the format of the various (currently ten) messages that need to flow between the BAP and BPP during the transaction. + +The communication between the BPP Beckn Adapter and the BPP software is asynchronous by default. [This document](https://github.com/beckn/protocol-specifications/blob/master/docs/BECKN-003-Beckn-Protocol-Communication-Draft-01.md) explains how the communication happens. In order to connect any BPP software with the BPP Beckn Adapter, we need to do two things. + +1. Configure the webhook address on the BPP Beckn Adapter to a endpoint in the BPP software. This endpoint will receive all the Beckn messages. The BPP software should identify the message through the action attribute in the context field of the request. Refer to the [Protocol Server BPP Client Setup](https://github.com/beckn/protocol-server/blob/master/setup.md#protocol-server-bpp-client-setup) section - webhook configuration for details. +2. Once the BPP software is ready with a response (say the item results for the search query), it has to call the BPP Beckn Adapter Client endpoint. In the example, that would be https://onix-bpp-client.becknprotocol.io. + +Refer to the [core specification](https://github.com/beckn/protocol-specifications/blob/master/api/transaction/build/transaction.yaml) for details on the format of other responses (on_search, on_select, on_init etc) to complete the order flow. + ## Running Beckn-ONIX locally - In order for people new to Beckn who want to try out Beckn on their own machine, a simple one click installer has been written. Currently it can be installed by running the `start_beckn.sh` script present in the installfolder. In the next release, this will be integrated with the main script and the `start_beckn.sh` script deprecated. An all in one installation has preconfigured values for variables and so pretty much does not ask for any input. From 721e171f41a18d38978c62dfdbdb6ad8fe38369c Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Thu, 2 May 2024 21:01:55 +0530 Subject: [PATCH 049/102] GUI for onix --- onix-gui/.eslintrc.json | 3 + onix-gui/.gitignore | 36 + onix-gui/README.md | 52 + onix-gui/app/Infy_Pending.pdf | Bin 0 -> 101618 bytes onix-gui/app/api/check-layer2/route.js | 66 + onix-gui/app/api/clonning-repo/route.js | 36 + onix-gui/app/api/install-bap/route.js | 116 + onix-gui/app/api/install-bpp/route.js | 128 + onix-gui/app/api/install-gateway/route.js | 92 + onix-gui/app/api/install-layer2/route.js | 38 + onix-gui/app/api/install-registry/route.js | 156 + onix-gui/app/favicon.ico | Bin 0 -> 25931 bytes onix-gui/app/globals.css | 19 + onix-gui/app/install/configure/page.js | 58 + onix-gui/app/install/create/page.js | 67 + onix-gui/app/install/join/page.js | 68 + onix-gui/app/install/local/page.js | 60 + onix-gui/app/install/merge/page.js | 58 + onix-gui/app/install/page.js | 54 + onix-gui/app/layout.js | 22 + onix-gui/app/page.js | 55 + onix-gui/app/page.module.css | 182 + onix-gui/app/setup/bap/page.js | 132 + onix-gui/app/setup/bpp/page.js | 146 + onix-gui/app/setup/gateway/page.js | 126 + onix-gui/app/setup/registry/page.js | 96 + onix-gui/app/template.csv | 1 + onix-gui/app/yaml-gen/install-yaml/page.js | 105 + onix-gui/app/yaml-gen/page.js | 183 + .../components/Buttons/Buttons.module.css | 24 + onix-gui/components/Buttons/PrimaryButton.js | 16 + .../components/Buttons/SecondaryButton.jsx | 8 + onix-gui/components/InputField/InputField.jsx | 19 + .../InputField/InputField.module.css | 23 + onix-gui/components/Slider/Slider.jsx | 20 + onix-gui/components/Slider/Slider.module.css | 67 + onix-gui/jsconfig.json | 7 + onix-gui/next.config.mjs | 4 + onix-gui/package-lock.json | 4247 +++++++++++++++++ onix-gui/package.json | 22 + onix-gui/public/arrow.png | Bin 0 -> 261 bytes onix-gui/scripts/start.sh | 49 + 42 files changed, 6661 insertions(+) create mode 100644 onix-gui/.eslintrc.json create mode 100644 onix-gui/.gitignore create mode 100644 onix-gui/README.md create mode 100644 onix-gui/app/Infy_Pending.pdf create mode 100644 onix-gui/app/api/check-layer2/route.js create mode 100644 onix-gui/app/api/clonning-repo/route.js create mode 100644 onix-gui/app/api/install-bap/route.js create mode 100644 onix-gui/app/api/install-bpp/route.js create mode 100644 onix-gui/app/api/install-gateway/route.js create mode 100644 onix-gui/app/api/install-layer2/route.js create mode 100644 onix-gui/app/api/install-registry/route.js create mode 100644 onix-gui/app/favicon.ico create mode 100644 onix-gui/app/globals.css create mode 100644 onix-gui/app/install/configure/page.js create mode 100644 onix-gui/app/install/create/page.js create mode 100644 onix-gui/app/install/join/page.js create mode 100644 onix-gui/app/install/local/page.js create mode 100644 onix-gui/app/install/merge/page.js create mode 100644 onix-gui/app/install/page.js create mode 100644 onix-gui/app/layout.js create mode 100644 onix-gui/app/page.js create mode 100644 onix-gui/app/page.module.css create mode 100644 onix-gui/app/setup/bap/page.js create mode 100644 onix-gui/app/setup/bpp/page.js create mode 100644 onix-gui/app/setup/gateway/page.js create mode 100644 onix-gui/app/setup/registry/page.js create mode 100644 onix-gui/app/template.csv create mode 100644 onix-gui/app/yaml-gen/install-yaml/page.js create mode 100644 onix-gui/app/yaml-gen/page.js create mode 100644 onix-gui/components/Buttons/Buttons.module.css create mode 100644 onix-gui/components/Buttons/PrimaryButton.js create mode 100644 onix-gui/components/Buttons/SecondaryButton.jsx create mode 100644 onix-gui/components/InputField/InputField.jsx create mode 100644 onix-gui/components/InputField/InputField.module.css create mode 100644 onix-gui/components/Slider/Slider.jsx create mode 100644 onix-gui/components/Slider/Slider.module.css create mode 100644 onix-gui/jsconfig.json create mode 100644 onix-gui/next.config.mjs create mode 100644 onix-gui/package-lock.json create mode 100644 onix-gui/package.json create mode 100644 onix-gui/public/arrow.png create mode 100755 onix-gui/scripts/start.sh diff --git a/onix-gui/.eslintrc.json b/onix-gui/.eslintrc.json new file mode 100644 index 0000000..bffb357 --- /dev/null +++ b/onix-gui/.eslintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "next/core-web-vitals" +} diff --git a/onix-gui/.gitignore b/onix-gui/.gitignore new file mode 100644 index 0000000..fd3dbb5 --- /dev/null +++ b/onix-gui/.gitignore @@ -0,0 +1,36 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js +.yarn/install-state.gz + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env*.local + +# vercel +.vercel + +# typescript +*.tsbuildinfo +next-env.d.ts diff --git a/onix-gui/README.md b/onix-gui/README.md new file mode 100644 index 0000000..5453b9b --- /dev/null +++ b/onix-gui/README.md @@ -0,0 +1,52 @@ +# beckn-onix-gui + +The GUI for the beckn-onix cli tool. + +## Pre-requisites + +1. 4 server/instances +2. 4 sub-domains mapped to each instance + +## User Guide + +### Step 1: Clone the beckn-onix-gui repo + +``` +git clone https://github.com/Mishalabdullah/beckn-onix-gui.git +``` + +### Step 2: Change directory to the nextjs project + +``` +cd onix-gui +``` + +### Step 3: Run nextjs on port 3005 + +For running the installation script just run this command. The sudo privilages are required when installing packages and configuring the nginx reverse proxy + +``` +sudo ./start.sh +``` + +Note: Port 3000 is being used by onix, so we're using port 3005 instead. + +### Step 4: Configure a reverse proxy using NGINX + +Map port 3005 to a domain or use your machine IP:3005 to access the GUI from your browser. + +### Step 5: Secure with certbot + +Use certbot to obtain an SSL certificate and secure your GUI. + +## Contributing + +Contributions are welcome! If you'd like to contribute to the beckn-onix-gui project, please fork the repo and submit a pull request. + +## License + +The beckn-onix-gui project is licensed under the MIT License. See the LICENSE file for more information. + +## Contact + +If you have any questions or issues with the beckn-onix-gui project, please don't hesitate to reach out. diff --git a/onix-gui/app/Infy_Pending.pdf b/onix-gui/app/Infy_Pending.pdf new file mode 100644 index 0000000000000000000000000000000000000000..30a4d43cb28dc10ae96ca3ae1803b15560e79c52 GIT binary patch literal 101618 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�cl zuuQj&lMi01bXL!W>zyc*pM0wkF<7Z|)(ktcusT!+ogy~}!jaeLK+Y#qzJ0B#+_k?Ea)SivNrIHOss3a`jeLxhqF$5T#Qsral)tx zNwXO&({70<8pB9&^=%_M6iu5(t#u!vmXxZo(IM8SNttTABw*W_sG5s??(oG(m2Va= zBCML$MUr2`yyV&2CdE&yhgo}^fliELi$aPUDG69j45gFp zuubMSCTwz1SaVzHfM%>$OfcZw00a3t`2Kkp=8m!B?#cS224~a>bUCZ{Z%_lgEn&GZ z?>(Y5DYqYrkAviEAk&qZ5N-YJ`!DrS>XV-7&S=wvaluc!6z}Iy<$>G|HQnI3qn#A} zBlTE3!)d+*^a0C*a2`um^#V*gGJtG^)x?9wqd^}J;cj@VeGU$|)TCJ(>j&<2oJRhT zyaDq4n{zuxVG#5mM$-%h2 zv1@Ll0q&T@l%JbF$!^hYizyZf7T80sqWX~Y*y;Pb_+U~8TCS!4FgV6@F(+k9q{iDP zvi|J)Nq)=X8QU#RG0%A?^IT9bqCxa3mK~nA{zK}9`2_aFYRKES#y9Tnt>LO~{q!7- z5%q9i$>t4dPp!L2_L{akGLL;vmKX)l@Pk6i$b|k0%8#CWHIaLQ>lUsNwC)zyGpRcc zZqt7p<6D}oRlZtW&^&o|OpO+aPF&tg za9;%IjV4pnn+{z~ie1u*WM6Wt6gNWU&87t-PsYj)kU?F)Yjw*r7qj9bu;NIs?FtuSe@Ng*$L+|6Ql2erpo$wx_s35+>~#X#4e zQqOda0jUxgn4|MdKRwo{$Q$YiO4=6Wk1-9oEQy=;;WPa`clW+tjg|}gV7i4P{pjHh zGVkrrPmDSVgF^F~->V$6e%He!FAb*HpBuy(rrZJbN0A+tcAL+Go1uj4Lm88-K}NL; z(1)WLZ`Z@j;lpx%p|g1m`Tl`lK@cBlM3)a-r5fT|4}2aa})R_L%x0(gg7h z%OAw0c>BRF2aMTB<`Y`sjse+s0eOtB@+2D&>UXfK+T3JhL8pPkV%_%jYa(B?*${J4 z)NcA$SnUtmw-!d-Evgw}X$L4DxZ3Y%>(cu|6{Db_al@RLFj$9Y{&b++2Zw)k;hMccRfysR$ANdYV8|xdgt5W{ zxtZwIWMuHh*h=O_n4R1KK`TdEG3kpi*MYVla;=Z8zI=hA9os&s;%JLYDxEhkp<0LC z5Y;bfI@#zM!|>)7^tlH0^NWda1cJ|#^};t9`aEQw=P7iC<%jmb$O)dgbMGAT-@uN2 z(atZu^4Q49A*LOB@dYxm!T;lj9|Q~d#Z!+Zm1hdO%IT4HZI=G^s5u7~sW6_Z+=+T14ajG?w(ZdU;5c-*jlhWSX^WA#KVI&-BY>w~M5#?r;3}Me5d?&oO4Q*Fgvp=UU{rrguR|zR13nAT@ zl%L~MOSSCgW{Z2i)pP9rkO8EnxjZz?pGq+KrmC3e4vKkZp!cq?N52`*J+=-wWcl*k zX%T`!Ap*q#m@5oong{nvhi>5V2WGAZ&^yP#J6uM3ODiSjHd4QzbC)@Sb{L1|3RQ@tgh^dW(xNl4d?8eA-Ls4 zEYqwrW6bi;;(s_0B3FgWFp)1EFkw5IJ(vLG|H5h_@`p*Hnv;MOYe3Ib9B2CFbZJkd zmL+xs+&LG=xt%VsNl0@X80;7tUMa0~p%;m%go`RC ztmk2$LM<#j9V|+&C!H`1GB_@oT7(@xeX*3H+?JVcCt)qav-*aP6QViOPTxxeyBZ}j z?CZXXlHL;D#!_I}SVx3{exI24Pn0u~xatHaCb_86XsnnU#>*y4WAbgD zI@cfzRFea<=6r|96{3xCPMVDmdF~d2Hk)I#(6Z%{MtG6oWgW6_o5}z`9=%rT5Mpc! zR#N(52y+>URP1Q5nkN!l-;1;^f0wbUpZe^wREWzGS^RlI_~%(7M+q%ivwaU%*+|xk zBzHetk+6m>^;P_P=E(>83=Xd_fNsedYNQYH^0_wV{UfKH|*Ps}IGO$AFuUwVPJ z^<@$n`2`3);yb%j5r(;K-$RNQd(lN5xdsmpO-+%hVGlq=2MxK$`FL9EJ~Z?nir$TV z*X0@W@T{$F$Pg++oy?DCdXwbVY{ofh(TkzTzd&WQEagY#4vY)~87Uf8JyF4DvyS=e zRuUyDiQM#-hi6Nf4b|2=miiTJjQzd_*F06AvQ?m)09R5Sl8@(L*BU5`^K1-cfmm+% zCVad3(zdZojArH=!&*=m6->V~5+@L-E0v1NPc*%r5lIP-!m@5Uf0=`hVW8QA$2w7) znpdWBbjxhE9-IX7MizCemv`7#3<(lOZ-tf+CJ~!>rJjCG#EyejElG#1Z5XTM#c!K3 zFjau?B6(7~pa<^Gbw%^@& z#ArM(HaX~CaQ1VM-Q@-TYL$(W@2o1l8<<_}vI?q)uljrU_kJ^l}+Rjim)8)YJ zI$1jJ0(t`B6htc1UAEiea}`A-?H_s&s_Po;cck;C+bLDF(SLOIRhFaDGj!tHrTS65 zPB%)f8F)_L;@U7gyC-a)QZ{0s!5oGXJ=`j=FfRjta1Ct#&?nB(yh9jUj?D_ms%8&c zNyr1bKJaViSOh?@q@g1#%J%F4igWAl>9~sZn)V@JxrQo{;iDo`oAKZ#D2YgsZ_uH( zwJ}}n{pMxqc1%>r%hT?QOGH=5L?6O1X6I^RE8KiR9BC7t(&>l}+}Cqd1ArVz0 zvr%QT6zU?_WR*t@>J)kmE6U5|J`t`Iva5Eew|3~Za%c}4Hs6n z$+t@zQdZ`b+NyW8*&VXKI`)1Ne@q;$@h1}=<56k4_wMtses6TI{WFo3jQDXKwVTkC z>z_4!vGZUua>2f}{aO~Z8CTK>t6=}W3ll{nsn|5%|x_}ZBFUHBveWA4m)#zTQ z`4f*Zs{5^pa*#`mD1imlS2XWyWW)^gNZHYGl9WCXSORg)d=2(&C~nayZ)}p(%SO^^ zUx?(rrJ+*DBcS4T;-SY3cx@PiQ7R52SY#7VrkN}nw2N`A7_=VD)lZ7Kg`YNdf&wo% zfJ1^v^ED4Q5+!Z|9~`$&r4rYXDieD<|H8lW&^%-H;GScPKGK;Mr3ybK%cO*($&M`V z&1q-Ewn`1(f5AOZZ+lhtwC|;9KdJ1);pFD=j+e~V4Fk_zYPTuwwY%;L1FrH4i`D1$ z#l7eE?k!_e^rgsvAs;N@e12@oHh!?th9!`&kqAI#2pAV5KcJss8sre?V6%$UDyK3) zLEGpXJ%ScEQ8$|er38pR!Pb<=`wb^FV|qQS|en&nio7(GV^#B^P!q|h`+*qR&TFnyi0inxotHj@lB{gL*Tz;=dL_-k2xm#@bV8}LEnZOk1#=PvT1$LrX)gQ|ZDHkRgXkaN9J z+h%Fz4(NJWcs%Dr)9!@7KOQ`a~Tr(v1ciNBerdmGHdZBpAUAn6^A&;vy z)I>6LH_D`o!oNPU#zX+zi&xB)$1kc!d!a z3JDQF&Mgg3QX^s{Uqqmgo5c~>R3q0%G+N5v41I+GBqL*@0o9F!X}~rrAHCAIQoxlf zTdt~dsj3B5RarSTPGi?xk&TZB`!dX2-eA*ERk{T&e4o@6In=Yph%K6`J@dYNP=B`D ztj}fnIAjyDli0!GHa%FcYRe_4(iT2;XV~G4jr~Ad@43iM$r_ie>lRV7=X|d(qP)Q^O_Zr{aRv%)$&8H zkPrzOvV#!zv1MGb2&JaM|CIRqw76xHUA$$d;ApONhig&vv6!ZJS%^k?2O;#YK-_d^ zCkOv1PWGd8kIZ^SedF7SrwMigy6c~+ic3O;sb>L{z>y;nlBIZCjd zfWfDhKEl4|zu~r+6D#+jSJLsfU^5PF3*EU$)vXe1?NceZA`1QJ;*#$Lw zKI*#c94Q|^Z!g~1;R}tpP(5@AWNPNsm4&=uz{0cs;uaDx3nc4{d8zIjD(E*>m7JkV z2V;Iy?Hi8?(_@{pw=wLD{gLWF_1xJ&a@TGqLSKuS8Wom&_``!310%$_fgykF#3_o6 zm|B-%n`Ylf-20HL9gmq%O%OYCA7Kq9kt8x>H7H+wH4NY9iRne$aQa;nvq>JPWrtc8 zx1RGu+7=xBZ1kyyH>X|M+FsjHZs_uz4mozhW839)_oG_;upCLK_mN;@(haaS*Rt*& z0%-#+{Mz}xh`zW8Uv=CON<*i)I@dWq4O*JRuWvkb*?(MGI(6A^v*W1i(fTw`?Y<0S)itrAxrYL2O998Y zJ^DjJj_i`Y8#Gdx;%-qJ%K+QxQ?xVCC{4~_S;6ES{0KmsNWjo*hx!`4w& z_$FVGk&;OgX}FOJa|bDma(Mzgy^0h$s)PzDM~lNwCWI9^;RA5Na+5J)i{7-D4#*~% z9Gjw<>zSS);y9JZ1UstdHS%1yq|nZiQ3Tz2_+k;~*c{t|s^opXuzf+}<`W%2M~fiy z#==tny))$LTlI7qq3W{|F|(Mabv%xQ@+f;373$W3ph4E1`sqd|!a1Z?>RN|hOH=K3 z#sjhOeDwoLquH_;Wi-H&qvZG8(T0*YIr?mGvo6&rAO2|_h9)KA%0aQ8ZxOVnd`|#E zz`7y>M%U>`b5$Mundcy+6`06Y&MY`8FjM)Ai7Hz9L^)u`E%}l>EYRRB@YHtSBnOe}y+!Fi9>3a;#vQ zi(|08SY)Yuf@!c66~=vFIPwMaTn4qv(Ty!o5Hn&W#fG<|JLQc7CJ(!uv5X;IIP43%Vla7I| zal(vB;u&30HNYZ?aUwmnOq*OwmK~TC+%np7%e8+b78JBmy<+%PR8+)t*$9h#Vtn$H zc9S-dJbALwi1~onvc<|Kn+rDw@pMgQb^n&BTRd{I$K;Q1r4coU?eE<6W}s1I>9X|n za5t9yrqr}X+Jlh^3FAQU*&IG#KWPiw)gMm8c8ay|9+>)4q!hM9wGS)1TGIyL9nqJe3!TMNqn$&t}I;Mk4b6k0dnz6+a5N?=c#C^drhi8u(9qPdyD6mj_Gir z73a#lF17h}tDL_MT(<1;IMmf#r55yJs$zcGSi-SAon4rY z_|BZX_nd=R(=F#(%^#Ndj*RKI=HcD9e^l1#lbjAJX`}_8x4t-XCKgG2ui-7%T+4+e zGYrbkRf^MXH$6!9;?&JCt~!fp$7TxK7UOSR=1e^tb!D@SUB#)PhnGuz_b5VLFT~Xj zuFh)6b9-cvH|ejQgGr+%Kk+IfZry6;xOrLEp5B`^|rU+roE=+M}nJFb2Kk0+0>pJ`t!| zs?5%xX~{d!KH^@Qx{^>>fE-g?I-x_2Mm+O9O210hyXe?LC&%zE;SY;&yA?UAH#M!7Y-$za$5 zGj%AeC^|)&u*F0X_4H@;f38^z;DSR9C%myd>KOY*kx=n}A4>9`G_*~)r+{fp)&IsX z$F0FX5n%CsPru)s>aM+H{vg$lWW*^yw#;|i;XR;rGPewl#z{DlAU2RdZugv7U93%Y z8Balt##!L$;p%(kLnu|OG_9F}D$*h{# z5u7yM`8MyzItZs3vfm8O+Uavoh)b=Hdtd(Kr|T8Q2}~QdejO{H?;ig=%@$s6(dn44 zTqGyG_A6$)B?RX4*cX^FJ!9<7dDa>DXKTR_Y@NM`+=p zT1k=7%XNOwV&H}S?e+Ozw1T8!;X$Vh;3jtLGG8~2$8`afL56_&vHg5Z`zY5{NVNLI z{%7p6b==3k{Bx*emN}2#J{{3!-xI5=*}di6ZzzYjhYE>5COs9G-`5WjpMkt^rU}KPtqOhp3)IH~gn;(C9pm;8 zG7udz(HJPKg$@fhk}^oGD3cuf?Nm5skmbNpG>Ifhsx)~PeIxpJlpLm0$|AOTtR6WJ z86>%)K_X;nbN{ew$E4~kQv_HNEn~?vfF;CHn0Df;7I8AU*t*y-1sS>eOjPUe5qWCn zTz$4B?{dqUd%+X&lxVBHsk~QeesL-ilp-o9HohkxIr6QT;2t$I<0$8$yR|{%)_XA+J_iJ$+ zup<)9fP$$>XAuE+i85L>U&M1}Bb?Vm$kHxXzof-)-v9kw8;c7~mGO@T!R{sY?K)b(G4Nlk+;Bd^Vuvkeq+N<>be|b@tt}o9B<|TRQXf(=Pt#`#<^Y3TdSAXZy6KB-aoH=C7ednF~ z?8;U8`$@ylirCEF{UKg`$6zR^Tw{ST6ui2||Iw>!D0p>^|ASW-^|wUBC~Tnrpor2- zSFVrdUS+x85GAxqAOiCDk-Q)My|h`^^KxFve^l^qyjjrpy9(O9FSm1MXOuVIG|<(7 zLyrdj_V#y}KF`?=d%I*efNT(`K4OBdU#r=6EM||5WY4Oov#&_(>I+Jid+z!C->mQM zK>L|Jg>aEE`s!~=+FHd{`46(_>CHcn7$J_4r-;YO=h^O(-m@81p!Qz+K#xIj?X_UK z222Ro9#^a@NeeqD+P{OMTK=ijw%iViwnsfA>S^}S4$pE=r$_L7rB$}E#iBo;D(wGE z`s!&ate&RA+%fg9o+dHxvB<5SrvBB_)b3_GsXeP_&J#FYYtK7%`;BGYEK4!F%wWg9 z-MG}C05#{fD$E!oHTJxHtb22H$F5!M*t)3iix;2i`+WJ z_(%OqPN6fYwSOKc*$?_xJ-NVdXfe4gmfz;j`%WQ~l;qzLpasShDD2Kzwfx(2q@?gP z1(^Ykw6udgPt`4X6G)0I5h_)^_O$le)ApJg$nE-u4-2MCsw7elLxhB>N*$(ls8`8X zDc7r8)Saq1sy3@sq-L4s)|dMgqMCI--}v$R%U*c2Nl~J*fMX99VrQVO4 zKvovZWHFWXha^Mln`P1|UoT^tkhF!Sht!`;$#wKLN-4{+N2O+o4wE{h>!mHyPDzq_ z>6Pov9qV$gn-$wpeX`)wP#2?>74Yxyjc;JinfyCw>=m?}YsR(5{n7(A6vBV?C=S9R z*~R>cb#--lXU!0-J!Cb8W0LJr}^-urH%qDBm=gYMT87)?5&OyeAR%}SR2**e0X4g;|W0NGor`c?Zf?|Me@;MxK zJIDdAH=s>W$V`Z0kIe)(hBQcI=Ef*{v&!%9C0BRnHV^Fq|McAf-|pQ3|8C#$lNV2V zr+>##a5}QhLjIlN!Yh^22f85lj!-PuShYtULDKL@fg4Cr%xx&<_5qW^Ve+Bw&P{;? zmX#0mSL!n%@8q=ZDOj(jr8FMGrUp)vbK0Tby)H-`xLfvxy4Nc~%%*_>N zZmu{T7&&W5oUk`F3AwfJ8;`wF5~wo~?+4G%h=(fPdARSa2l}2YHF{lre?VP6{)a#K zdx`M+?m*u^{(bcZ;n$x}5!ZNPtG^fq*!JgVlKBP9izn2@@O+V<1z9a zv0a{To@broIE^e8&ydeFpKe|3I9I$#X4{7I9p^i*5W9?BrXPsC^8JoS#Xra|i?7J9 zT3>R!E50YcXMM*p6t~nLr0uF5?Q{>LW|>h`n4hj^On%OqRdBmBpUG}ud+_(tR>o-t zpcY(WDAm27OkPnea?`UNXQrYM_6u+V+G9?e)nXx5PJcOSB?TizTWGE>#t9c@YFkofeC#f?VY$Zk%aRHLX(AV<+DqHC=DoViHWfr1!p) z^D9Yj+GN;})|$0vH9^BlX;T#ZF89_LTS-#Kf6V4zyYFrPj`khx$mmnBeXlvVM%rt- z0lS;}dYg^Sum<^&fl+RTJ<_Hx4>^BQ|D4cw?q=q*_16=&Yxf1~9qd)iV7)UJiP()B zgY|N8u%3PSpeMwh18hl0LiJAE;R_fnR*$#A>F{{R$_jFVh@6@Efh!$&PDj02EsBjL zP!wx0n;1tKr#iiu=k#J8<0x`_&(eX@wvDX#^2Q{1zeQ$GYG~d+%-jWJ&pKC_wF<56 zQ{N?~+413xr1XW|yJ>1?-*u7LaChJJbQk??-<9W%Z$5#n-aUQSXVhFVvN_yG*tfLv z_LoXKboDK@&vp&4&pscp zliXvg*$NN53!4}9f7ra--y$oc1#t|H+q>%>UN&dnO{YV5x6y|U9>C^d@^cZCR zKla`PzKZH>7(ZvWduQe@bN3}T$t1Zq3EYr`EQEwWZXkgKLV_WLMIwYGkU&U67FMlT z72K+5)w;D}YpL2+5h5a1rIp&+YPGd?v9C+tqP108-j-6U6kM*NwY{Zuu>NBjZCbn?ykn1y+5+IVZNzDP>Iid5_pa zl>pP}MUYf`^P^ESXkR?t2|%E|Wc|Ma!J>mckRqX^mH%doXyJ|l`(?+^V5)`@GZ|Co zmq@4L;Xe$Fw;m4=zt+kN60I(54q;g!?k=fU1_NP&Vu_QB3LM7-)jF72V?X{7XDq3m zdl?S>``DArW_EFW{^ges?Zc0qJ3RJ9VjD~W>-Hd_O}tdo(USD}#5|Lv0f$dm|804KrP{)kWQKx|$0N1lA zy7n+gl;SOIbghKQWM-6Oe+FS!Z#@wxXEJFgMJfM-?m!Y<4hTB3z*DK>^D0Xe*4?!OdGyUJmm|=-{(Ty9F&X7*i33G z=ZRKvYQP$tI>kD5YPofWr!1vnYW>tUYunU~)}End)>-?A|FQ!ncV)>ArM-G;eB2Iai)n z&(-C%npZ~Gn|q>LEqg65TK-}EN7PYPV#AzL5H9f*Ww`xoru0u?ri2P?RkmAf_uIy8 z{Qb7aY=5?~wxE0l)63~xZCX}IVfpcLW`8*@_dzjFlFWT(V=aI$ z;?FEF>sTo;%$NdgD8?ME1>xs}R|FT z33OITu+bR>x(rvCK67H>WE4h)=Jkt46&N7oLEEW>FN4lBMc;jw_%BXIt4_h~N$P5! zczKKFQ!S_dRKoHoPb2Gv(3X@Z5gUzKEVd~}*=b}VDwHF!MHFUbzt0zPA7u*;^+Gor z>uIa#mKH}bkAZ=$~fsb-i3LKJiS2L*Ivi-=)5jKAs*>`2u@^yO6K4$M^>O5`I1Z zM(W?Vj}?pJv2nnDQbM4rNS=^QCY!A$CLR1q=51o*RV=gBAAVKFiX4;I%DZJw+t(q} zF)RD^l|^Tb`M1-?(#A8RWDo%G4jlwCbwv|Wl7~U?=tStyi10|OqZm1jiDk}eOe}NS zN(AbSEKV5etVZ*(Kr0(znBy4l!~5|;d>V7i5G= zLfx2BH&N(E$*`hHy`;+6PnW~fZDTl)wxDd1i;fWPptk0m#+?M>ADcWN2*txcx-Cl+ zP*!FR>-G`aB-2ls z0-pAb(ZR>pJ+>tl|I0Jq*~FAAyLIcgzCN<`Tl}%HzunSw%a4ZQe~$m+%lOXcmfiUB zk6(S^WsrhP#@}a8f!qi(?V9}djh{9&Ldn=>DjI;@02BitU6kxYE3sW^$9BR#m!JW} zBF-6-P5uxkW1GihCb%|HT$?O(#eqU_ZK9+8<)6Pmr&E*@ZAIiiakVWFEjT?i&o$4t z)V0*N*0t7mFLN(@kM%+2!Jx%#4M-cA9(E%?Vi~aRwjQuNAs&&Quvom7J(k}wtSxhm zz2APNowZ{S1F`Hvx*B;cRBIpFkKRG2!3?(BWi(O85LCTdN+NT6g3Rr$_OQ)N`IE8*$j8M0z{(AY2mtW#+_3IFK)3=pj0?9+CqIYB}=IX|UXFe03k^~$Ei zo}8rJX~1=nqr^#OViFTEgn-$~$5a3O=o|6B5B}l$Z~t5RV}UDIUH8a?*KE8QU+a7F z6`YEtZ(-)D#~w)8)cgEvzxdwgfm6;0%6(hghswApr@UNZIBUdOVy&_ArS8(ua;8OU zb}tQWU^@9OvBSMKbUgj%{Ohha1Mj-tb^qD-LEv4=5xwc@(I8=?i-Lrwn(~>jHQ!so zlv)=twbuFW`p|Nz)w;p@uJC*B$M}p*!5-EoD|X>qI(<`R8 zP2(nxP+yaYHKoxZOceuDnl`j4MN;L=6r>axNGn;A#3zaMOlL2~qREU?Tc8g7vht)p zu|fV%FiNt%FXeHTFi9|ASYRnOB*_}5ludSxQ&tr_%jv8~Mkx{TAmcS^Ba4UK6TFh0 z*>&Q|*GD$~{OYxL791W^zcsS;>ksYP{=lBE-1N!U?#Jv6msB&hkLNSamwxo!7v6a3 z1d+{)KsKiVuk--Lc`3#D(ox6*R%RRDCN7h^*iC%D*d?1iMEj$t1|Zf>=o07ZKy#?wxjEP#+AeJOoMq1X739TstIxN@OQxJyZ^*t+ z*{?8)!li^H6FSB`LdL2g#g4~lS1Z7C?r;GgBik@ff5tY<#6l!r%nB+gosF_;OTh#J zX!{AMS4GU3T5`~et-*A%zCMy&LVlklYG*o5_dabX#7A1a#R+*Zv0>9}$Y~{PiiM|^ z81!P0na-wS(N?llI6*=oN;n#;v}ujpB6BQ7kw&{#N`Siu%~GZhXg{dEEzywe12j+|9p+ zeE2eLJ(^p@_CP_PFc1q21n#xmXMNae4q9`q2Ls0gT!6a9g6SoxW-Dv4ha~J_qHY(* z3P`%&josret+SqNb;Y=e4a^2Z@aa2kWiTZ;#4@*Gx=8f!^qD1ev1l}uUa}A2K#Z`U zK+Fm(NcWTEQXfesVM-`Z_muoaUo7O-7YqH7>Q!{9IZ>;~a-t`xHTE@s;5+yj%0Oqa zgba5|qR)wA1#EK4C{9IBwP~IeFv(AqJG6~_Zp9&pCcz9=jUqZzkVCMi;3$qxz3M6) z1r{=x@&uB+E;0>0ZM2saBs*R21A>fpXmOFYLO83mxU{54y$JCM0F=cJu?z}g0-p}|`)}M16KCj?8$~-=r8*-VbrlY8+ zkm@;EBUXbRGdxNQ(IVullg!i}}|2 zcKf(I=tX8(9+g5qDusLrDdeM4$mgZch<}_)A(BcU_nH*)X*&r30D<{&5|8>=FVoWM z8@A&J%1k#1GTk7^be$l5t?A+C?6270wvXGnbbFP(33NPzt=M%*mEUToY{ecVWM|JL zwX%mujqFr1*{Ni*2cmhy8ALcm8z(r+7Ja>nk}RL7fTA4dY$dRmlZ4BhB)^sVTGcI} z4Z$GwvIx0CJk{g@! zI#-n)yb)Kvc^Aev-L?DN#*bdv{!Mo3Pme$M((^AoPx#4RgxL4#`id8|U7lVT-yR>? z74%MwTJ{mHl&xitSveZz@dZkJW{1V$W_gV4A>QPcCCemz#*#!;7DKm*<+NHNVyt*Z z$+(D*i`Yw*8E=ek{?DbMn-Gsk+$auu3;;Fm#2`s0Qok$dI+6N)M6yPL8jIxM0D6D+ z2;Di-NSB59N@kQC^q%%I1K$1KgWhp3=Vjam5xEUQaU1mIj%bVD6{y~6a`>qVgXSH? z(FL=*-}mE~k8(54*h`wU1pZ^qFhmSxUko)z8$An__>*<)Em315>6Yl3$y8+=-JuzU z#63*;m`$*mA~wO2f~{uYV2HSLuR_2AaWv(KEFp>IfpZm(_VVQ98_h^GwmQ<4P98^= zgOZEjaqJ!a-0`iCE*c%#wB!qwU=IG}wzdcF8(YIXuy@zeo39vq8o1VVKoFH=_bD8 zyT$wUsCUG1QA!uV;4^UyD+=t>Sd&r<0Jemu9)A$^FA}r zn>dc)co)J}nPJ@)&cVy3q&~@_eIg5{ki)(YbReG(nUqdq3~I_z?CS4H){!evxWkcD0* zkQ;kOV0SR?*^kJsUDm1XXtE{d z0mTcg)1reUVb3PidBFg9T}p>q1|;3P$n(_auB9TE2M4gi1Y^g zJHd27z*$1JDPk@cW{OqTChJOWrLe-ZQoMrO!QU;uApDH`g>X{%gX!sFfg;|b^Xq$&680H*V)y45-DUB>6i93qzF_Gu!v`D6z+<8>$pHZ~! zGyA}hn%E_5kg;sh4@{FIC^38zWX~kdx?v(1gRWhLnt)T2jp5U&IHL54w9WFAQxG>P zh#%?)LeyP_0v79UGZw5*rc6qhx(ZE}=x#Ynmgt^|o=QyWgW2sXCsSLTv9*}&F*X6E znk!iv>XUZXMIufYuVER{ZzUVH+P09%FS;&Y%u6j7&8exCWKZy+RI)Yr=Z94K^LU1~ z0)Hjlv9|^3Q~$#F@k1GOTh}2k`FZP*LN^q{552R{pT}im#~<-Rk)oV$a@g$lLTPSy zB@M{lheLky@`sP7XvuNgN^J^ZVp%cW-es47YjcP*gGl8BO_XYjri?wubOPT591uV9 zhxkVP+*|PnuH=uM`wl)B-#XUGr02lPLnemCp4yyCN!qhB#lWUPR;f+>xQ4Pj(B|B zSXrzKGt|gU7G^}6ktrknj0bx6DcN-xNm}RW-FEdTJ?=r%a)oTL$FkUdy4vYB@ z%A|c-6R;x*PEEpaC<#tUf`dtLYSMX*p(HpZ2@WQ~mZU|q)+E@L1lyBfSCYA=B*D%k z*pURgk`(l0W!;$sJCb0lzW>i`Yy>1LGh&NnYe|GV$(w8z_U+2%NjL)oQiT)H- zWZA5=kl-N}mI(`4!GI#Y8o~P_`y)&Qgsd&H&w(8r^;`O>&yvoVQop5}kcflueIFqc z2SdG=RK_~!T&cs@x;Ej%Jc`>6`^}%)yrfSKSzG;)eJMDFmXwkxDTS7lLbk;_NJ%MF zg-@Zr^Ay5WsZo()A!Vi*^Rp>X)DgrKXBmZL8SFVrXV31|tO$M;VKS}2q$9$lS<0kS zKgFb}5`nzB<#5jMft-oCsR^NxzfI%Y;mA?E{qXrpg*L%N?a-uYr?%vy0LlFrU8S{U zP&+E3itu}doGzDi;*rhbc4fOQjuh;)dJF@@@Q_76;}2|HMG69|#DeSrMdV1YY!X=^ z4ZuUaf@atjk$qFfIP}nM7d{eb1_^bhB%3A=6dl;O^-JlW`_We(Ih?h6&cN-XD>@sl zs^GHkXk4>y#j(eZjO8$2?p;%H$Ae>EVh(NJzT}=;$9`>CukXRQ_Tu-bm&L`if{S@b zIja1Q{k`ind)6gzL_f#`y4|7RyOdY`@A$|4oN9L4++HVGuUPO}C9BP1n`FY;l19EQ zVZw%5ZDBvPSpC#`m8sn-Q@d48*sU_;N&6{S-o}uRKqz6&stQoq;yXw@0J?j-5qGXm#5-TX# z4#Ad!?UGX`J90$U7NR_)#6+v)1>$0PCnYJ~@RcOUNuQrjqNTlG9eH!@14|TXbn2$M zp>J^6UwW)|U~$nEV?)fIzRlIQy)^b65K=Yc?{hgoEmjo3JWnF0%H8dV~lE z>LO5pK5&|(fMtPDXKoc%nl}hNW^;*B;jHkM`fHU%&PCo@|7w1<*sQcU+q}*G&HQGu zQ`zj??Ctb#!yZxKt(USbe2a9crI+pEyQE%=3i~(e^5$`TNPZiNwToj^2MSb=<^PVailzsNd!LH@wn>zvY>BpkdfGObzKlKMWJ-uGvs%h871#0WM2@I= zlurXXKuLUlAFfw`da*x8yhOdK4Bkx`NWT3 z|M8E034HZhgqRnAY8==^X=YY|3o9JX;!3!A+){2mH_Qp5!z`LbtIHu;5o^XW?QSHA zx%VPrjTS!HaZuaxR7J> zq|$a~kQ`M>uuL{!P!9)EUfgS=C&07~;UBx$Y7F4Yr9Q!$u{#E1evyTG~3%N9EZzU$M653#Zcrwc9 zFvv|B5;;k5b`l&(g2PF0RuY_<1ZO0{YC=u8yp_vzXI6*{#hP$yW>@Cr;?3eU;RCL3 z=6#Q~ioT%VSGXwe7d}3PS;jC*5tjU`&8x-L(rS6NWwmvqd84>d+9+?dY_yJMkLK9P z=GE|&8R1pZO1U$;Gj}*^IJ`UjMd?1vZMk2{yQA0!&)avsb*oc;Z5Z?2)PXBt43 z0fY@8S97%JX$X*I0AT}2CF|v#Y2~ZTIT4G*1=Va1C+DXI$>dUIAdfCY2vh}{0&4<~ z1zrgV_CR`|Kk#;dOAp)xodLV z7{>XlQ+rdH)R4!-X-g)lGxR;f;rU+7MQD)=<;&?o91I6yE`Lc8dA*2EKl-(haFc+S zkaIvKZw6HIR)G3o0(2soJgpWr-pE`!u@&)ft0_Dc@_Qmw{_0dbl@v{~nQEM-FjYHq zPawb_DJG{rZFKtK)~P{SmyDdLC2Nb07co^uyNj42G9e#EeogEIwqqNfHMjm4PJ=oT_xo@6wfA`5=tx9Zdux)PJv*<_zK`AM9Y>eIBjSkAPxEZ&`$ z?NFSGOJRjftD1tuTvH0>r$LbBhT9BVRtn0@vRcejq!gT+BT7P)OF`*MD$)D2Q&MR_ z&5fzitFF2VCGm6Ot8SZ!z?%7iFiw@Tvs3dq%DMC9KrrY@r4rs_N;*E(Q9Su5L$bs( zC!Z-TnNjwso#1eh!%FBxTh$@^^}8bZQQ*ISTs z&2wLB?RnvfSALCWhc*p%)y&TFM~dpNYFw}*H$7UnYlFXeb#qx(DAgr}i>ohRz3Tqu z-vVwG9{&q7mA@PLa3A$SsFQ4ddD5oY3D}eb3rVm<&f?52q2J#K1F$=Q5w=(*%p$KM zM(q;l1*~jWGEpYBUO+(W2Zm*WfVSXqlet!`U27UJ?KbT*aR?N|{icJaMD{6t zg6!m(O1k!EtdfXpM{%+8V$$IsDUY*WdKwTblaq9dVq!0rtX79j5~=W(1VRGEMMVX= zsu%HT%Yev)zN5@RCh_SGXhsP(RIcmIyXKn1Pdwp@=B7PxzcQ!mt4zmD*wh>U!cAje zT$~pqa^`A~Gw+bEf8i&!Inp3m8sqVmFsjQ-j)FNI3pm{+Q5O!IU0w@zd1VmO4!}Pu z_D-@Zy-7NnH_5K_M*Kcv00yab>7#a~&q*iK6U)kdR7U#}7NyUvPpj)Qp+4%g@DYpB zN>D!T!^eHt*BGSx z6Ai^dOehZeB&|fJX6c?AIvq=`Ns&&3ij9Fut~`CV^V4RdrbN)Sv6Y(gK-o-?Q*2hd zmF!q0=dXk5$XQa5)$GuwN2X4_O4~jLx*QO{gE}Nw*(*>os4^DKYAeBVvgxddZ{lE6 zw(9cNFZ)`PB9F?BzDq8-dDiHCqjj5`N{5)+#twgB`hrWA-f|sN{>d9a1wk@X4pbm9 z9iQ6glC)hNU3j}X<4rhgQIghRo>*&3&KyWyN9*IwNHPmpNNhz9(_`KWqRBhb>4x+t zOL>ek9pw^{+Ez!o=yirl%p_nyR2_z2tp7^HizlXKl%QM)s3tFFMoN$u0=Ro4_PN~r z5~M<4w@g8~VzyL{N~JoqKx)OU%u4eLaXnto^q70Z?Pwd`#_TX}7q>}!@m^*Rd%fv8 z^9|yc(Ou%L(zno8rDxESrpKih(f6e{(CgBN=y%d5=!}#H&5``bE9IhWsZ44@F-hcO zPHzbhWL%=pDTrhrzCe^+Lhg2Y7y_d5j^KhGl0}`9fE60c@VrGPn+M*E0&d{{%h8vk zs35Unzf3Zj%@I*@i=u>BhKXn!nR!VZFi9edFkfK7mP~Uj7Sq0Ngj1e~@w<73 z2Ph`0OblnrfBYFC=TpJJSld`z(0}S=o3^;DJTZ6TD4%@(A=$2_Z(Nx8OWrU~_Q=z| zPTnI=_x-wxF@7}O`|Qa`xnK%b#4ln01XLMhzE5>vyFanY zA+dJYa2OeYoimP3a2iekV(A<6ss><5q)#{jJ~cl}SjMxH9p@TDNv7mf$!%w4HWaWs z1zB*#oOV@?SyVgK*zAFVXz00UOarU@+JUfJ~)*X(W z?wy`%tv5Jsa^B>+-hG$!ko+CxX~!}5AEn>B|7IOi{^1@Er8!-Gn=P^F-s_S>DV)8= zevO^A2NI3Y%p7N8SACh?Zc!XgCs0?w?Q%t&k{fR97Q4d|ktI-oB^TK+B?}}26jDM= zLFl;<6FSONJz)oo#N0=jmY7`Sj5(P#&gYzr^C+Hs#EvsjZHh!5QJlq8OQEI7!Y;9l z)6Kkd4;R=0Lrm3Zih4N+R6yYv`S=hJB{`haubeppY9P}%vC&lquTu5Q^-C3){(MuDYLBH2At#xPq{-s zSZgKW?Brly+;-jyFLQI8U+4*rF&Lh zWu4EF&CBu4-+MEfnI8S!XuP*NTzGkFNqob@N^Ur1lRcHo9lLwvs>`=Bn?CvBV{=z7 zB@+Av2zJ6KVbL!7JsF0u7M?84RVYvW8lBw&1DQ;%o*YdaOK#PU!Z|&0P_tnn$EZPp zQmM!5Yn;XtbO{HF%X{?DJVL|7;7yv7dSR3N%RPcm@Har6rcn=ojRD=Q60?=) z$K0>~Mp+ChASagBE&M3{m55=AMPdM_Z{tln=pTEPWe0)FOKJgAHn4j^^yA$Q0_%S?x;vMt9 z@QxY%{g^rF9pztmM?rr+rfBadXgylRUCK2g6S9-<)T10!fXYx6S^&n-acVN zx)S{`*3sR&q@`u`itU%rtQ;85&0E_UZm6@EYhoNS!xd7)m3iTCUM0ICR8k1~l|R(D zaO>dUy7lwtes1TCqP~qzZ*wanRLp6GEAz5dX~9)HH?CT>aVNVzQ?gCX&(F?Wj|$#; zxxC=zS6`-wfE5%duYx#olmn=|Ou*#-G#xI`ewCkS>Ca32sq}yWcUER;NpVq*{_E0z zefqEQ+;rYO{!gBte;+w7f1^D1=Y=IDg}0O7@5R%Lr-um?FDrt-Zx>IWUd%L;a4bk7 zn5z?M#~v*#DJr6g@ej$f_-YdVog}`UK-AUX1gH3&lDAu zj@1ElM`0mo-+H3B34r&>YrifjEXfCeP!e681Y_QgdNi$_0c9uOY$>q`Vu-UN0b5zY z8bL7>E16k>Vjh2q9f*f%LgQo(57>c2Au0u(YsSDq7muA-b6FcvP_-{UfIdtX-*I-E zU>xGj(-k*4WC2bY(JygD@!UJ>Ycgk~FZN2K70)+zy6(0$W^LqF({HR#{7omThBuDC z$#3RgLq$NjyJCxPti?NPaZe5Iis9B6USENiPr(~<@v>aJAPv`~;)MY`MZqXf^>SEU zfEO&V)vMVV8MCu(8ESEw*E=^QEt{R2#)%@(HZWN7b*b`#Q$H!f1*eJ&PSM5{7oRv) zG`+Ab`7a|2RAn2Rl}T*nISd%fWhLZWBR0mAGl!*H&m3-d8jEeL$;NuzK8YO@WjGrR|H|Wm$_xn*IHc3|7p) z`IooFf7E?vf79IA%)eOzfq-l;Z&+1WepyYVr0cfJ^wW0x0fTA41MZJ)-jj_xBiI!2 zMVO75xHW)H0o>}x3;a0SvDLB1!QNoSyDYfJj5nHaDT{MhJcGfvq~Xt{;Z13HbsDZu z!)XY4vXQE&jH*sa_macC>{7bKNGMGOB&TGh+1ZpdUevzcrQ^4)?Nkv#@2R4KVv5uA zPz-;VU^qLQF7u_{2&c!Bk;W3~hck#@!p89Z>X!SSAADf!v9>jjesuS(@9kgq$up*f zyB_Y||5om~tJo3OFP`pvU|T)@>9!{?k8OMrXFc^GwtaVF&-daVd~3n(7xvD7_DQ_( zgR`@?KSAj207Cp~z)lFwjAd*U_lV53W*8zkg?^_1rP*cG>JZYrtc^hypqLY&;}ip} zXf2^F$Z+VCKxW^HJ;eq&aQ76f+1LL0hdXkPA2Fw|-MO!E`wwqj!YE~M`E}CZS>qDdTq>)LTyUW##qg@)A6?HI5%%*9Nfse>tw2i%a zLV5GV^g>sLhafPc6e=)_x#{G|vEldLJPH&|QVUXW!;#BM+K_dSeUAau?(>Wtj^ynVD&I zY0ON2ou6rS;1#xR8?(aPZDvwZJQ3`6YhG;}jfAyDq-$hO_6TaoshGSWR*<0?lm){- zKqKwV;sOQuaDqNFpeKo*t8rbB=EbGOm~^s1lF;ew+YfQmZ|m;*`nKxok*{|>)5(p- z=T>Z3oR?j{dH#Zp3$hB9^z2=-B>}$Mr$GO(R_Ahp<`Evj4%HBIyt-rgg zm`IxI21Ipai3j3IyxHf=AZd^ zp0MX7ef`Bpw2xQBrfVHbt!zm&F-VdkKeSQCTIq98!YSkeaUcgY6- zf;J#6+F_&v75@q7PttYM3p29xZY##@M{mZ}(NX-&FXQD*%GkR=*dzFC+(M}B`tiRo z5;@NbO^pRavnvvFVB}C8?>J67IEM?F`H*Ol5um?_v}()PPl|{hMUMzA^XX^@fjygd zPswuTdi}ZcLTkDTOrv;O&de+a&+a#yr?+lfz>!6M$OcHP;-|rw$&4woWRCD0BQsHf zHw(0%PrOV9%gZOmUZyReo<}mjm4&Z5^xf|sdiGiNo*S__{?UzOCNSR2zRN{W6g9-A z?a9O&?K|zvN;`HsQDn-L&@?$LN$C;LO~G88nkL9nIOO(8)(~$e5~mo%O%)lKhD0|g zDnh>1Ng74AlmHPWXp4Bj65NA*w`lXDyIODWuR7>@t-5DnE;r}yjXgKDWR6;=Enn2I zsV03iuY9q~`Z%cV7W6`dacU*euyrKJ6F(YHIt+=XX%JjCq%b37_Cm;DA?Ah^g zV-Ez-e*^g%H_^?wE!-9uCm!@@>@vH}CAmE;=i+7xcL|IDK!g|Eyim{MnLIY}nCD&V zT{y?J+{L&UvnZLcgd@o0h8)mN371Rt5|blgQ3?PnWZ00|1-s6_xn5C;kfivY&9mpGIZ+X?=}2@I-*gYvpI8jIVMz2x)34ksoH{WHjieY3!d zX7kw`kP#-9+w$@iab@^<{QOTE2W)P|B5=HHb=msx{P;0$%h)imuhQt$U?@7RG&}wq z@(uF4p#4#3zZ+$sd~|875alc36h54*reKt-?G=bw2g*uO9yscLfkY7;TR&Sd@v& z(s5Y;FSO!1GhS)J3r%<#iwf84CE?9Qw zE4w=H9c=U;S@6!P>sNz*d3Dp(UsG}aikrJ;EW7XD_TKQzFD@=zv1?Jr>lK^7+%f!( z-jW-y1WG17c|G)`87R3TmO0acYXm%x!CY9et9Hh2_jw}7teP3K6g5kpD1x4&bvLT4 z)z+1vlFh9d8D$gQa~FOT#CAsf_wo1Rv14a8-hNrMsPm4FQ{0yLALA$Ezl*>1mE!LE zd;9LXY>NI}BQ6VSBBRBz9J5*GxR{Km%NWTD&=4!j*eZw-gjEozrl=@lKFSa>lA<_4 zMyCuKBB(3|)B@Mb$e8%-Czo|@gzW>NzISW~^HXli{`img#~;*7XP<}CMbN&0agigD zIho-jWY&u@F;R{aaMTRtJuVPdo>W*d5!uB5K#KsPWS<|qg-IRz-7z-G{xtrB{c$to zt5MTYpr#Cm_!f|SZi zGfFeKqwmN6xcBY-E1K{9?LK^G>qFJ?zjxiezIbN$ookNW6F9>4RUiYF^atsE zsyxwrigEL?V-(+0#{b0p4j?DWjag<2*cnk2w-`1%;iV_cqD%)Nh=nRmizal8sdUUP zE%WMvkojHV>Z_MN{MaMx!xc4I;xW9j`_@%co_oyo?~&NDLgr(m-Ph7~?~GNLKv$Po zs2VUnH$uSrBo_ENLXue&BNFSDSg^Y#l_F{Uz>YQtpiJ0w(?vQxZ?p z>70yr9!-fkw9+H-3ppW4c zJI|R|PlRE7f+<2~7a5UtlO;h@LHc2{F8zv6Py#QaIt@9%7XFlkirAL8^(XE%RSUyK z1}FAG#?I}Vs8W{ao@R4z?!#YotnO(l6gz- z=N8(}eX+7-X_;98y?JHj3O4zrLu#I8Db0D9v9y9)R? z;V!QOcX6Q{v^G|?CmZik@eLt-y%$$F7dn|m7F=P$bIo{$8JC%G4TDP=%!g4x38(=! z5SWq`PPb#bJ0!_zAz<>+3o!W!sYI+|Lz4t<;)2mqmSm4G_gwk2FD+eq=WAD9^ZFf2 zTJC!7iWN7tmojA?H?%DK!us;kjxTUmFT3|w*IfOpds68IDx1j)<8_U`5xz5Avbll)zgfMa`pi8-IDHeMK*;E^2vqxpw zDg_cEYLYmhEpTNR6$f_XqH8}iL3Lu=xB5zoHXRs_zklr5xf^cCsq3!(h}$v^blFAM zbXLS$nT2he$`?i*dYxW`I{CmbS`nM(_L5b2VTHN|!(0GD9d;No7(~ z^D^^%Y-k2ifigorLj}?tj@mjR0FsQBwsIoGbw%)eKUsD{6Y}XQA`oLv8F7_q3P?^q zn^2qBD)IW=GuO<|3C-WR=Cb`GbLVb5(7F4&SJ!ZdxS6ZA&W&|1%uQ*!WoZ3vtD}_z z_jh!DWBYuLP4DRSOqmtQD9R1H+=Y!JD;8e9vS?=4&8?QIwmE6R!g*72Dhj9gJe5ry zvulQy7UZwk-K?K|$^M>N2dOd9gd@P;xu`&76+>hdv2=bi_A*r&vdAY6*x$!@9gSbf zKFj{}Tmk#j{UncDp_dvVk94#uHe+S5C&(=KZ16BQN*K%q%{#Q0$0Izxmcv^)45pxl z;|xU~4QUEt=Khe0;<@;OBN^l!2WaCo>yOig9@i*l%-MKf|E>d@W(L@&cvqxq_1q0R z<~W|lZ)YVPUZ7-eo78;G_nsxAmlUv)(TvyXh`3&zG;sI?t*oLS2;ZUyaE zw$g8#FkFOX+$_VgjMa{?6~nN_ZiJVRfrGEcco5@Gj4@;9$agSdoG_ZQ02a+`>Mo^5 z&4fdTO2g#a@^a$PA$#(Q!D`UBJhwJJ{e}4K7jdcCBAI!{?6%_?Zp$aP0ONeYlbMm> z&Z@~~D+tEZ5E5oV-6MELY&1u~ip^?KEVhW%;;aD#jNOWuGiY0zP-ZCkF1NVy{ldQ)TQ2;TKpKz=2>EG&>7NXyXy)LiipI z=W;j{U~7eRWVAPY^DW;O@cQCAhl1zPW$;>Gf&K8O0SH zg4xXbqh6Yk1a+g1S&F`V>T9eeQ^A}jvh|k>SH-3XSv7M;a_eEu4|=qy4fHlC^lIwW zHaFEXzxF4y_J#hP<*`eDPL^=TRT7Ql@FMKF-El{4*^~TE|CVfJEiK+SGD{IX@Vq4J zS_qfkzWKQO`aDY1AUl}%S6e}es%g9Y04pHqch@U*Ol)q$xbIX=jb;|FwUd{Dz^o6E zYrXB5GgEoDdQEH~%gUKYZt@6CchX386z9A;wUYPv+CI^i?WY@h_w4P%sH1mB{UkDL z?53kE(Qsp)^KYIiS0ceJ+CuhN*UWH7YTLMB)ZRS=M-vi-hiH5>;R<4%G|hRJ4q3hr z^c${~XJWYpw|U|G!*f5qyJk9e^YmSbEB}PtkOqtQLky@o7r));vcFRIBM|Ghcc#}o z9;l+Hl1h?J0E}xdW10Y|n@+OnO?)(iUU-o%xP%lR5@LNCNQ;tfT+)skmmcJ>NEop) z1O|=M1>d(p9>vGY|IL6z{t1un*$fD$8Xq+(v`8Z5VGl1}xn&1knUrE0RioSPO_$wz z|8*S*U!XWjF*M}%Add{0v1Cj8lw9wM^BW8K&ah{yNYmqMHEz)61hdv2qNtv(+}kP2 z2Z(Exhza?Kyxb!DNRjefs*6h;%g@*IF5#(|uf9vd0>AF#g2wa7Jh)*Vp?;rTl>5D4 zZ%qmpt)>r;LRUh2chH7x=hJ#P)T8(Y0U9php9#F&&isG2bet(05111&Xv1vjfjwN` z^QEYuY{XuuFMh7vh0}>>@)e{yTY+DCRsA&&IU0;Z+yZ|0ul5^6i^BeHoSGl4|6{}Y z@|%#Qc%O~1d|Gut_Eo7u{APE^CV72*(sROVH}Cq(?M$zm#*5yY#SP5Zee@PP)|@@K zdPx!ZDG>^Th*+E2^vAA_obLHtJre_uVH~R^|5FVCE$jK(tZx%H{GZD1?`FN6=KoK9 zHUMU0Gn$3;e1C1|{`0>pLJnAA$|J2Ypcq&dzn4C^?q5rS0g+z2{*K8LZ>K~~Uyk|e zbg=6^_91(gR~>7EqssE{n%zH~(dP-<6aif#re+4O+g%e|W?lo54=*>gH^JN&r8(vN ziK{ze7FiaeunZXb>VN;=`@ndKO9B?I62~UAddX0$@S2##g3-fl{tf)sh&TAziiQz` zdmATXvC%4!U{D#Yq0B*FR_LSf9~~NcVS-;KrTe-_U*7X{SVKF$7%B}dU$&AgK#^n= zp>!xiI2Ov29O1Y0bwxDQvY*t9A_&I1;xe=q7Bh=!NiAfp4;LE~A~2IeJ~>ug@}PBS zfBzV6AS-de*Wo!7c>oF!8B*1)nQ zkxh3<#gM5sDW%btowuPBW1>g!4^%acGH$woQ*#O;t@_cjA$|OR4%DLR!Wrb!b%b@kZ`6_@l*YeYLWH+mR z@02~l1p!dQb?l9d3#yeI7E=FyR%-xxv4#h*h{X>Q6dsm6=cZ0H(~p?MwTs2+>V~1s zdy^EiI!bR>p$8L}1}`DQBImLAq^u8rZ&UxGcaD6d%%PM+bz5?wW4)U4;gSu-Hz_^Gm9}NfGW)?Z4s{PBD7bLnu_rHJW?z`6Zsbf9QLo4 z-*Uo^CHLXKCUw*DJK1FYTCvWPhTzKdinn~3BlqY36F7Dt9yAjiPN}5R94(g1MWOV! z7xkBHkvL`H)a4_Ftp3Kw+f?U%ci9MwSeYs;`xt@IdC7a^uI_ zhne!Wr)C#h>7sl~Q6Jm}{R#>RjqdfbAfS%Z-hpOkS)n@v`R-Q^!?5r1FJ zXBwt~JFSHIw``7O`-UJqJqNl03+y(1htD8sL=h(1w(T4e4`T^>1`q%ir@#-~u6&r1 zgZx1`o^KNS;%ALbF*M}Ai)S{Hgm-#u4=JzbYZS|_xv`&Z)#=o!{Hfv9dZQ@Ad2m*i zPxv*TaE|GzHBK$f&1c@+B~s`|F=o=>cl{!8*P$4vusl^C{+1Q#QWDvRbMfx$N|u!#OI zU#s%l`z$hrkzhyfqedv1OI)i)O2RieC%#mtrK^?~B3xksrIOlek&li-CuQ0d0KCE{ zZ!(xt@RxD|N!5eujOW2Ejten}?cXHVyh`K~ z$1MPZ77ED37#maC6(3K(_D;k&lhaH)p8lC9JJUYMu;}3thk~ImT7=}EKM%+2si9iN zr7>G7!}PbDf?vY|F{9J4kzl?u_<5uk?9jJj!5rE0KK)HPat!^-h_f8&%3ERK>wwKX_O z+ktA@j7&af|2;h(rib=<--M#3TqAcbu+s!qqj)J^^TqssN83Kj(M^)VXs^htxtKp zx!+BqTmP2IU2N8QTX`kZXs+fVbJE7Ab!~T$2WvFe73x!UIfiHxKRn!FUyvMW zgYU4hZn4|3A8sEGYM1-^9KB{EARwByE~hFdcP9h8e#f>IpL(*hjS2xw@4L1n0O9G6zShA4C`!D3!BB-y7~Y`CiPAir$-lSADYl#dR~^glV@nO zwN(JKNgKI&v(InRKCZLfI|T{%=6YPX3%9bxCz`OauZqObI;x!&iM8^CTOZ$dTKO`H zI}S%#4Ml@p%~f`vs#=xvjb31FOG~ZJ`LfmW46r!icLDr@l(B-{s(XOOg=X;GS8Re0 z46U_8KhN{cayO9$t6xtg$wU>th2PtHtwtp8+)MKVJTykXN>*>AtpI=1Xsa3pThget zb}}U6%bQMreQ7V~$8=nLzS9)-$=TQ%09I0BxQaJmyc2|2N?df*uV(}n~KDzv{#<-1lYeF==0xIl-GSkRC zAMM(fyL0|}H9AH8jrU%ZgWtcCGjCx=@(d_S0|BSYG>`*|mS)~ug8E+1^HZBvfyHQF zFme{L<)wvq#Nf&{*5z}Q7Q6v>SgL=RF$()B{5=cmSa_D?z;TaH;3|)T~P90+4uM&KWoX>=%NZICj+iHi5SSZb#{^Gf_=MjX41^3 zk|peOBm(c>CS*vP@VxncC(qI(*;3*Z+vh*Yil#q|hO!-LeK$L|K&ER>q%P0*#Q!<- zcBh|&)`pFFH#A0bJHNim-TcYF%#7?-ye~A{H058}N{xz-@AU?Oap?@_Aa-kT=T{LQ zlUaAcXm#2SvHYzs=kcR`;!>5y>-6sl|HU$>-Z;rbht;_+q5&(ZyPPpe|KZxtX$n#_ zCf#-8@_di{Ql`!@H;7>Ws7dT@Kla~kTS7Uyz8=}7W|@G!x9Xy@^C@H(s96?S7{j~kvdHG)3VY|L&mF!DN+17*d>fm4PLdY*EY0#< zS`6`h2h{;8(RGMd7ym4KEViU(9Q4^ARND~^@(QWMGun5gKSe|ZkeAV_*^3rh% zQgeyV(di?AcwH|Y+;RA*O&aTdnK#{DYu0wjY0wu0>Jl#tuIyL0v1RbBa+=i$@YmkO zX7Vkq%9sZI>y5DCzl%p->bf+y#z!giCy7pSP)SurTWYCkFjM9+G2Ikvz;dkxuLv%6 z)J^GtS3CGp#K5u@%O@!(hZ)a)lcY7d%M6n_nS31e;d@Thn}44FJWXpVpYLtF$9b6v z_m(#FJGC-b^aT0lN@_Bt&vPAK5BWKa)=dYBfb#WDj#bs+V_j{UEhk-=ZN^%2ReqSu zcd<81IVU5_=#IxGYDp@*Y89)ler6o;Kdx&)yS*9D6$%S+eroX?)9$&*_0FzJz1_XR z4lV`8+ol6))Zc==@V{xyp}O(StN!i#W6VMP!_h}OQ3}s`JpkfWwvqlH>`5a`mBR- z`ok+=TEgtM&EkIvZ1870c^&IB*yxF$XbL2Jfe?_t|*W$KERK3;MY%ou@Cns6)8X1(k(}2IS z<4O=Kq{>mue0yuo)DWe*H4sNQK7D=KG?L`~+-Mi7n{|>ybSqF1rNnu`S0`TxBMs@v$McZ;>K7w*RPVum+5EeQI>!fJGeKp0Ia{< z0$7(qq6vmr9-u(cEJjG5+dX3jbmYBZO-p;QaW#?K8$@)MtcC zeM_=mo8eBlbZ5Bt2!Z+T;=cs5DCO2}eHK@7okYI+BmAX1bR5nC=Wr?3J)!Zo&IFb} zNrVnKzv2H15h#RzbfZn91rl`7=x=exqD-bZ%hx%ldchaa5+j<@h9Lfp+#iLLU=AVv zdoj)g_tp=!4z)6%#KViecv?M-Wg`~jHE3VO=Wnd^LZIgmV8Xlma&q zIr~vsPNGg?!@U(BaKXWrJ(0LG28;;9>am>QnpTS12>%|eOv0I4|MYa(Z3)8WZU>(S zhn>R*AX%Md-#ZU)c%6AsS4^0Hbf0=d`_-@kL%Br0$EKNPc?pr4vN#I~&*DXkZ5(7F zw<0tL;g+IIs7I}rpZ&<1Bs>y5!20;C-nHn#F_<8Zb)++Tjui#i0(IguCoDQ7Nqp%MK-K&={p`;LFz+kuu*ik~8^DK@49P89{GA zJ(=9Y-TPvsI8qbEK$;`t6H^+JoWG>Qv$EA${Yuq7_gQsFnY4YbF*9Oy z?h=UrGUJfEpGqsWA)7K`MMuLd@M#P$c~~98B;+V|oOcpxZ`o^b5kG+!`vktCRI5ImsCP!h?p7M7eQbfhMe>v>keTC8k$RetB3N;a2`Uvv$pF6N{X~V zavX=hoxKoZHQ>DcfM`SW{M#JYkp|Jm@IQnzoJ_1tG~E=XDtLKKfuqu{ui@(QT190J z)bi*@$}hCKamt!3IsZ+}sp?|2|7O>Xwhd7L!W_wEeHmX>2GHWNU}q1c>>%ob7&dow z$nel3X`pB@PU0T^BlwYCV#qx%7nPSm6?1XWn+G|o!;oup3}RVmBf0;>l%gYjb7*^< z;&1S9-|yU~PKWU7&DL%26>`2^=Qpg^1?^(;)XXub19-m8&sCTkC$!ScX6Y62>n{b|^|4}h6GVL(54ikBB~ z0dZV6Ca%vE&?GA+bkb?_tXHm`UvV^P>)X)E+&%!<^mKRncOi8vbjFzJm>mFF4dR{Z zoobyLPMJZiyZPskJ;(v&5haMzSHmZ>r*?}U(gvxA^g&90416jNEyDrQ{TK+c2}2d! zSzi-_7RrP%#K*fre>`6uR165RGOo`vZI=$p@rXEAy2B1ZLQH3z+9?aR!8h)sX46CY zThl{=!(r&Qg4hq7E|mSH>aEFIAn8+iGI_pbu;{iNnTqcBrS_^@?|6v~F)>^1n@c(` zoOT__j}CuYD~;asMqbu%7P$moKUECO-L7W6sqcTK3&2DPR$iK4y5NOg=`U&szKShU zEqQid4XK5s9M5vU+Eff25FGnv2mb^~Qt||~h$j}7^o}ZKy%8)Hx;?Y0!3fR+prIfQ zd#7jNirvZENIHrJmEgf)XC2X*Tf6Kx?Zw>%tFyicSlITh+ADsaam?#5^&*wqbBkJt zQEbzxYRCX6GwYn$Vb__Hg+bhUuqS6WYkU;99S7+-Y#pr8A^7^cLbBA4Qlmjis6t`Z zTksXWLUQ&No7OipsarHZ@_AvsLo==@RjDb9xgv%~BzcNZuf%vMiqNWljk-N1->N~# zzO2A;#j8fxRp%wAUwB4m+T$&G_IA1(W}kDM>nm2@aXicaN*4jEs}5P2x>)}gA-U~5 za{IBuZR5bJ;;l(cIn+HTzyhS#5gwUJvj(SWNY&@8#bv+bn0qusM@;xy~$pcb&XKtSDAoPq28Qle;9 zf3|D;=I!(+kxl1O4aTfD?x6+}>*or2SfX$X%&rnN%MBjQW{`oSA`mV-oBmI=lUFQZXm9@Tesa%qh6pfz+=+-dG|IJ zm#F~KQ7W!x_f{cvK8GAdL{1gA+$tlBj&+2#Np~rR->Pqo);CIgFI0$D zomqdR`Y|nOL490Lgw0R6e<9LWRMvigH^x_tp%u(hZZ=E4@xWe^ufcI1w6X}XLp~3| zVpdGUZ$yyb4oft!rWTlJAj#!@gG=DP|KjhGvfkuek#O&9t_atM|ijZZf1*LM{L8faR(6wH2Xs-C(O%)RlyK^oe%I((>beddoC z@Tmg9w%K796~UX0hd1|B9@F6Sgko+`6F2BsD}d^xhvFvZ;(P~-5Bq{V=vp;!l>8Jh z#qC!K^veNY<>%RE3jg!Xee4b(-)n6IZ@3u$b!~|}nQklI>9ugXHw@BK@oL&py#r>S znDH+6Sm!(p^|a)!K5gr99JG&;AB5cV1>twx8|Nkt?i`s{I$fmAqH4JIBW{a|Gnx|N z7ZBnDqflpKQ4L1Ih)2R|tp{VR2UV;FRjdd3xj_fqpmc6f8#m~V8>Ge!;@}3IbA!yd zL4DjHL~hVeZV(+e=->3vMRZo9IOCQ8<5>dgi}he}mb&>U{)%SkhY(ufLG=*sj#~(e`doB^>{*lVsiQ5gSn9LD=T0JiB(hU&p zPPY>T#67LL*Rd#itc$u@ch+z(L3$5gSH`P+pSrx<%DXaEekZVp14}BlaMYuxv<8<6 zGQO`ea!L~eD^EFG5j(hhd$k6jmbp7OZ+KyUm}W5iRxWC>9-bMw znsv^CHXCisrVs%Rw6qDP%rU3wUx4J*RVO|w_pG#>t@ktxD%CCLO9J`}KE9)oh3^U( zIr_|Vit#)jE3Hw^2dUS9NBn#<_uk>h@3yn^8jK;8E3>qmApn{gLW_2EZ1FZuQ!*f7 zJ>-YzO&7O9xlf{}Z-Sj?ttc-5QfLt9vu*G%HT>pZf1@45VK1;}!d=3mvYWzu?uTbm z=huXjjYnu!+3&p{-D7bm4WEzpd_jW0$xi(&oygx>jx9)o9>7_bAFDkcw-@6c5}BX4 z_ShhU7o@K%+86xCRu>9`m7Cyth)j1y3%ksue61)4Kti(cm9={|ME~KS`!ctQExmfQ zy7G7m|7Pc(35Nq$Tq)7zCyr*(PG)rnV%S^QcKFtAcwuF2CQHk}=aaJd3);&{?Za2v z8?(%{CJLf)&?G=tR7}TC{qCHJ6K%9m$c(j6B!3pp825SB&K6cUO4(qe8_N!ue&Ab>45&1`8(Yj68wy~Yvb7`WRJNf)6 z?P&+>;jy!A7ozyj%8Pj1{E_WuTKnewl<#NZYYRY(L7mrAhOB|^F$ za$}})b6T)IBGwRvBpIqaaoIPiYTgy35!5x>P=2|KA2whJ8R z?8cWl9Pb#+=1<#g)&8%9w{4iTCUk=IaR-^PEvVjg9HsgkNblo>CLqf1!Hik@WxqhU!phA25PP98J z#}$#Q8=k-3T1_*9>Qz(I@uxEVSN;E4qWCc283R+_C9YXA!+AsO8$V&-=#=KaXSZRoSbtMaaEx4>@8pG^ zAnacA!@z!<<*T+N{AEKXk5Y z{J7z_#Tbh~is1S8CJC|GEwR)qM@vX@srtTbZb$=GcMXx}R^Va4`sE5ES?P1$p3&0C zA+3I7ORbh2v;yPK#^rlglc$_KOm#~lU{ZA34x%;y4$gVf&z>dh&*J^`pj+bb{Jn|L8=KR-Wz)T6@rw}Q&Y_K_g6a8ovqEy+|!nuc}@_Z0$5Ht1a6TrJ#_2J zkB<$^E#%tHBxojj>B*AzzZH|!=~fBeiHBpUbVQsK~4C?%Xgh;K3m(phKqZN zF3#Fvt@AgtSmYt=SBsgE44Jp3?muY58}yb{o> zjrGOtiG4dOf2vG5Wa@6KXLFA0shH0pmBe+r#ZSrqir_`UJFX-NXyw-U=i3y_VE?}h>IR!zaH@AHiOdr**Ou){mPRGYv<4*ERIzLzX zdCitK{1-&cwCrLYOdbG*2kOg!lI0-aOB?`V{P4%_m=rc&cW02I4nmp6vo0jdWpke* zyQ*&yS{Vs!aq?=#cw@*LpRo#AJyErLOFTLr=n-0ia`mrJ{POcGyu0AGsE6eVzryex zUct$X#6V=pbJ%x`25#-ZWz)xS_xY|@D8Dec zcIFVK-5&}Q90-Lh$U$O<%uHc=!PQ;7FgL-W{OJ(qAY9m_4`^$>)R%2%1gf$0N$6il z$;^~T4*CO31iUH#)_{C%a7eW>lNkGoytZh;mQ%o*C+%RDe7NUhcauH24(r%F5Vo6! zt%+>wI?XgKd8vjpb-NeZ7VB)-tOXwyYJ25OLSbydOmQLTg`a}W`+jO|$tCV>`QTYlWpr;xK- z=4NJR;teX8mf4i66%EQB!2lfO8 z1FlruL4|@Z_rGnS_*lUV(Hft?*F77_eDAZ@MdGvB`Krci&ju*1<$FSk=ene#!?Vx+ zSjdmjIzn)_b-yWKYd)Ys<@_O@t5>vdS5TlJs9>GE_pC7JFgy5|1;Q4iV;II7Sd!nV zY{~{C7K|brQ7a)U?={<^gW&%h!Qoa7RDr6p<2A(W#_UFuHksDpI*o`lsq}J5XqH*& z>5i0tPorlrQqti`t4%jOAU!ZHPxb86212Ec>U)8`#m@TetZr-<%suIV^bl4mRw_2d zbQm*CPa;`{b%BwBN4-7SrCg_GfdStpMKyyan{m-5!kMY%K=0Zyn@#lHrQ_4w(ks2g z+%u8;P0+7pD%B!&`+%c4654&nGC*^4P~V){t41`oY2)S>c}91U7Ia|NTnMc=NUVhc^LnF9V{#-L5+U!)3Yk@3sxrfByRJUgtXoC(*1{h`==mb1qs&J18dLT zJl4u_?K@=0rsq22iWzOYTEY`@AK)|Z9r%Q6Dg2~iS^lKfvF$mh+t{r1&B&}4q7A6M zJLx$=K7qfpI8i*oy|ccndam9mir_D1$ys90k#(vS=GVKiH=nNj*jhxipxvs=VKzC( z)8>4x%%SMiU{-(NxN1+)>eP1HdfGO#foV*9u5iv+pX=L_Q5mFm3fwNao9i#$uGj|N ztw83U?E#KKZ9T1T8`~S=8&c=y=Mv|e#>w{-E@k&-E@}7gfTZ_9E^+r!0{Q{EWRLtrUY4tI*|kYjlnQk&{iJtnd}BW>P(V{a?CyYdF1XO}_UFYsnc-x9UIk1^H{>&X*J zH>(kQB<|tDH_y{2tNP}!ujwz!MV;~gd|aMbrVT$6FepnoH>X<|3vM7h{x*~^hqQim zN1w@dkOrnolhkyrOmtG zLEWRU_!Res+xRp#q7wKFHeycg`-SA0a(HXTiv9lKtuAgU5#&3((MOZnV==^X@+Hdb zDdea)l(0=#djIxfmEDrNsmVW5@M6p5GZ?RpvfyZ7EMW5*ndVy+i4x0kTa9U$&+Ae5 zuJl_q+LH0QK$`z~xEsHB%7@$&Q^1GqR?@TmP4EgcCs8mqFelY-Pd_Kq0>97R)t9(q z9@;BUFh_n)<67zW>@%MWW-Xt{eA>gxY3hiP;ByLy7Iiq>QFul$qJCb$=+EEZY3}HZ zwY{b&p_)FF*vsWBy&!mX(0?EVEKc>SU=*!yYitei=I!lrTo55T6ky{#ESL^N@*y5b zaYr3O`}QPq9)1pg&3So94sIl8hcIDuT42zSlh9I9vwxQ&z@sFHK}N-=B#=cVj);jw zA)~|_LZOO?b;DHY$B;sYr)JxW+kSX*I$Cca;xSWfD4XI$FkeAmsG(B@8XKSch~RAKme zM~sb_-~V{OpL_V3|b}6KbY; zX>0BBa+y&nkRe+$+Ox{wbcBAe0>CnZd@{gXn7CA$Hd~p4BT4Vv92Fg=hIK^((lNOr zuuRiYWz5r7y0@pi;sd1{sM1VbCo>j({DQyqWAD>oLsFJ9Nd|4OoKOa91#U)ptR3ns zPnddEhSF6_n{!M^xo>%v`eTOd^SyCEO2Z0}NDzPJAO?(b0mLm2^P?EP2@6<_;Th~d z9Y&7}u|lHxi@7H+^PAI(kp>jM#~?G5JIpRK?7C+oGm^Bv>OKLe9`6<^odtcOyvc(^GrmMCGvu%Nu-QFJqI3<^XlC$hsGX z@wyjAw7co&gb|POP`zgm(Cpy#Hvgw+G{6kYso^7|?*~S6c=BE>A$#h-cT&G*7C5%Uf+&x14V27I z!a~iD89v-9QPC7xJfpslF!YRvV&E)r>mQC6Vc;$B)7S#CX?0L8v~5^H6s6$R{|XEy zRI`<;G8tM>E=Xi=4hXN&21OMX%&(RG7(iwTQ^n0Bdg$K*)(bQfo7ysa70hMVR^@$Z zW}^I%FPpHFuGFcmEs8*9QbWPNe!C$czaYY2AR%DEA?zT2AV>Moo7s4g8|D$`{{VlC z5!XXSBKU#i0q!#phvb3!vn%sw2+h~6&tJDX_CE{9&7GTEn}oT>0q8;jyGT2P<8G5~ z_}$zm@oBrsyWC9|J-_<3e)V6#zbGKS^kbiqA)WZEl+_WGCCd9t`e_+!(;XQ`sTIya;vp2z7)AiH{gT zGO>$$DB_#;E+}^-8invF5{UHqXc$3ABqD@IPjp3Kz9Mjo)au`u9&w?-Iz(H9*@ z;fqgVrIv|9Yiy*JGykiRgs;(u)3aE5c6ddx8&Fz%rfu{|5D0C&lOJ69Pj{j(tdYy{ zXRGvkj!X*|f?e!?Er|{djtw!RZIbqFRtT2$I;y2~;U=6Qvs$PoCH`QEi8roY*R*G( zy>-vdijjRgust_?Gr0B@3)J$^w#$)nj(GkMgYgn{|01ss{qeXe=L=<0rxB@os0lA= zVOvb+xHj$Rbj7s*xOn%m_;>qu-p3+zEV~dsbQiiy(jawN_zti`ZdC7je2QkO(VlUHs9|Hg{f@#EOvS+*c=ItS)ZxjdM`-=@l zmYZ|y^F-G4tAS{X3f+04ix=g#`vf*>SsQIzT}&cFv3(DN|f>TK0Nv=V+fA2~9mj&ytE@e%5gTgPW)c-Bb1b*$?{>r@v)>mMWV z)|b}hE<{}oo<)h2Y%GyPp~OXjA)tt!8D>@Weh1w^-v;iI{IpI$%|}NIFs={W2w5H0 zN1x*F;>)34%_0c86$w__qc#7QqfZEYxD!}cgoae2#Z`8&vhR{??nMsFUzv=pi%+}We`3+{yd9FLN#}tR@S)U%lvGK zx6GWW%ph=v!Wd8zi1tw7E}4RihdCedU(8amw=tz6(?6x6Y68ykOH~&Ed(IJ?nkAwi zM2q4Tr1eCt$|lGgMK16zmA9%rt$iEtJ~6(Aq80p|b-;E<#fq^WY|wV-}l$J3w7>k-nsh`75l zguwr0R4*41((~5SWLJ&ro4y;fbkHQ*RFoN#K=f~wx9h$Oi>I2+Oi@*2W`6@rr0Uw! zouOoQ?90>TgU0)DtGdV+a$l72-hiA))wx@KjCXw1zv#oZgIFjR;eOHzoKT)oPAq*J zg5Va7y=p;lRn-K}C?^R}dq$l+RB=swG?tpTbz0RS$1@a=Pg?Ct`xD-oJ)TMny|`8x|I^QDUFoB29q)^0`5}rM0JvDP{du1> z)mr$iLY5xifp=R`+H0FBi=P!>{xD{V5Z!ib38w) zTVbz9L=^B@{xG+)N8sJsc^V*S#$drt(Fo*Y5oSSf(fJ88OW=1KS>b9YQ;{) z$i{X{&}MxNP+DUlyyti1?vxMYj4%=?(soV9@^*J2GzpT>+)}KnwpL}wb1ZD!-ksK@ zeo=(EBUlvsNX&tWq}5VvK#t`M>vR>b@-y3%~b(s%2F* zlE0s(_ctoJthEhJ*rby0%9^;wI2EfSZ~2Ye%`1Ht1VsQxt-&Xv%%;119p8Z-hP$hQ zz%HJ6j%ev}XK@njHD4k!e?eDVh}S3`wj5hHBe9V$4YLiQip%XvFnBU^}`XQ%HQRiV;%81au(@O7=Kae zhVuogOS^^$;IlCH^IqO)P)^Gf*g7Uo=U-4gN zL>H1jyML+-f)EsFSe8@-rEnEik4psgWvg$v@$GSgc#{QwuVVA1?`xN2dE8<;(c;l!Ywkkkf{12jH!E?_tCig z{TP8xeR^S$W`lm|N z!++?h0JusakiQ4=B=m`NUikL@Xba6^+`7Y3#QYt&`i zPkyhdB=krq<$w)2TtTS8UYK6Wqddw@(AZN|Vkh(R*4-xULgpUakm`eusi6)ud8GPS zrCkXq`$M!3{!IkN!c^N^-u^45$bM$DfpLiH6*9k=RBzw5LZH4-t&>SASz<9f0WZ7Q6CFemyid8_}Ek7;s;>u#GI7 zfU)79B4)7_DnwTFL}DX8QjawNH`6uUwmn+k;!(Ketitd{t{r|3@R&7>cgpK?)}~l%!=N~TLdLE!Wjh-c=|`5a5Gf0fnI293xe4FSo5gyPkL|OsNnZ5> zqu&YL$zKqwmM6!aY}N!a-^$tqJ&?h4SnL0aLo)wSgWtL7q7q#m1tBGp=jt&H8~wk@ zJv?15a6;nwC!9dPqi)2;0Y-1i9_%30E$~Y2=L&LI&?d?urlO|)r`45b9EawQvkec< z&IZ{6CsgH{o!LW-Y=bT=9sT-ojFVP@L&kCQn)^3&mwdpMJ0-&rj>Z@hYOwT-EEJBN zCUk3sr$Zd0b`vcicf#7SFp_&4ejTmr0}&5$#%{I?buU&|`kpKHRvX9_;kgT`bT*I^ zqR&(5*YuHSf$%zTYdTCUVgceK7OH=9BsnUKKM=$Jmt_p>Gb0V%##Mw?1&KRE3;`v6 zKoQHtqjEYr#7A2iK#70(EWTBN#E&LF3tohUS4nYg%xpjO&%-G5J-}g2{Z^PumTaf7XlWT(odluAP^qQ}g;V zmU>d%3mS`@x^M3RsU<`kb0A8jUB*#AMUv>OJfJkdM|4^?x!SkWER!rn2HYiCqX?~@ zD=eK?H|BFBf%C8X^A#_vBR+q#j{6R|0Gn$!t9>B(;%U-uS8nj=a_B5PjQuMZ_#vdA z>y@?j7SaBDnvXfxSU1UNJ5R#A>ElQCbC=tl2b>$$Vc{tAb9go$XVH8o8^8F+TFfx@ zYnmsz49TF6cT|5!(bp4~DH2A>XMZun(8YgQJ33^|Si=vSZ(Ir~h=p=1D~7xwypBUT z$r4p6^3N-iI3mxw1W&#y20@Tk?tTQ5-kQL7{trJ3ApXl$dC)A5v{C-RiFce3=?0%&HgFgtRn%tMmV3Y#oA? z1OEI27OD4_=vIo#{tan*b>8~p-{Zf*h9CcIJO{;XPm}b}k6HZ8i<|euhayg)=SW}s z9_o6zo8z-|Sjf!4^FTj|yR#|7a8}wK3SuS~Bta7W+hariNr zf7e1ei;jSw8$=aJAtM`n3EaiS|5>e=%m?%iP9RKWGKE_AkOmLcl5HYQj{+Mb!;j)6 zzrr-JpXAFY!j9Guo&u)_~ctPCt2m3DQ&%c6wlw~^55%%B7Wzzhyq_@?{$ea zFenF-apwp~u|IvLOj$Tlk5O_6B z6~Xo4kG5&H&ZZ)S$boh$b`zoh$;n1V;1c4-GrkI4GvTQ5IIw<6F0Tk?-59)!W&jpy zjb_WWL?7bmr6ee5a58oYe&G(11v;eBJz&)E`_#Teu)am;l(|tRl;L_#DtTB>;ugxr zq^OHVH{7dB-nHDnT;r0NtTkSK>Gk`?KR^Arz5eWAJI~$`Vu@^!2=E zd~w~VH2!(2Y@qH91nL2ofo;H5@kIYW{LBAIR^p%TkD)__%}gd!GnlH+5;>T{tf<^V z6k4M#s9+(q^H0e)QC}AH9cty8*~SU+XjYMdh_u@-UYl|iU>gnLb&6@tNeo(2ib?Wo zF#i0`gtpq7cF94-Y%7m)#kwQSeiP2MVLL8vjR}e+dze^;EF%T~D?XADs!yEoJO;Q`avw@)lv_4GCn-*s!m=W^>%L+|JF!ld#X{wViFL;*a zz9y*h^?U{TBJhT&>6*TCb+U2=juU)>^;GrZQx~ScGC}mt$<5)cMWtpCCBZi{ zgnBc&xS^wbV_#tSrNt-Q@IAMT!iuYS#ABq!URi2f*E5|{`9GfbKy;kGa$5BSM!8J2 zZcVz4a(=U{;XZ4Zx@(fjzHe7-#(yrJm0NTVsjUW-)Z3ORD`O&lnyw5E_}ja5fRt9l zl`%6_G1#)2vVCFJCN7+j)idT6a<0P}sN2LSrkor801tDQ+eLR0<;cSS( z7$H4JCfz=Ua7Gzvw`BSX982cdTeBQdiY`awM3d(SPsn=~HGg?sO3=6BGmVA7b#tsF zvoASpJrg^vluE}HfdONF^yS)JX5RvMO4dDr&1(9r0sArsIQ4=0F&5F?D`UnGWSVrB z3H48kwdK0^tjK9d2cPfe5XzPH*;J}V^^3OTbz5xcIm(T>GzC)lbY}Ex957P?6a71g zd@5ehR*O=uEmYa!^`33M5V6Yc^OQ#^Sd%*>5kEJoe=5PCQwz^i1j&~fRov=7N3YmP z72aTs{SN?rK!U#-U>5zZrOr7`Fxnp^|VYu4two0sKiwwi8avI zaEVH9!RNGjI6dy=Q?7C(+>ZDF=A`FUdMR_I8fS^#%qfQ+;FPCjgku!({^02x)6(4$ z;`*>Gw?osPPis^bm%fi>+lyQlwSf`kVWSny+jOw(6N+OL?^YclEA7{9<9YXQt+!9* zd~gydvKD;*`)u-FO2_n{G#~k_}Ah;i9ZqlX?)lzXeAw_-lq;$ z?^lP=dYa{G=emN{(l=b2U0YmRU4M6Nqc!zy*E_CVuHCM8U3*;bx%Ro^v;jnAg8_creDMYH{VcGNyUH%gA|@w*e{ zn|syBUOuv)A879BoA&hvu{VWuJ0T zIiehwLfWO1-{O=3nX2@X?MTyJcBHF|%p!xVsx$i2XgwQ?D_2F(t{p9_wBxF&RWEBFA! zSqGVWU>)kb&asDi+yw9`yb{F?p}s2Rr$u5nw}RS;=U?^;^bC)YP-ZZf9U)^Blq1k& zLoNhIi3)0{>_X|oiI11Jqi-d+1E~%|?hknhcweOI0VLJ{AeLyXAWz#8Ulj}{_KU~{gZ@G55>RtbI?RCHG;U`qS&rA^=m%m-j{|it?G>fQ$ zXdV&&QobJg%p_!w{} zQUwu*t>E~l#xq!cD)k3`rbls%v<2Xcm?MrjQH@a=BP>dlWe}Yc-PUn*+7Z?XIPc7~ zz9gjeW$Vjy{OTDuNZ8^A#}$fD+(U8S5*cwL;>L(}am8^Z;@Y?;#gCNf zN~u_^lq+wF-zsk_d&Ec9k=E}KVpLjxNjO$({gYy`uD5Ph+F18lKTtf@qc)3@U~6Z) zLdmjEx7R9H*jL*BqztmJwy#zO+t=COQ0}+?-CLMDla=y9H~mBBg65eQq|_k zHdCdo&9iN0O0~_8+f>NJHa~5%NG7*=txcW0y3OV`+vRO--fnYL-qq%lwm$it_%`uv z@D3%P&Q{)0QA8&(?|7n#Cb4b`(R4FC(+rc!&G>VO=zQm0Kvdlrzo|}3 ziIx);5UoTWTxTPVQLgZ=C0dVo(!0sjZ95C16TWv(6zwNEg#M7;qeLefiJ-^S9VIyq zbu;S6VeOP;-1o6Bcj`s@XnmYML7${g)l2o6`fPo!Ua2qC7wa{8Ey=6s?mE(J(6Id}0`Z2u$np&^b+t%yWk9qyxkiNy6NpUE?H;2;JcsqDIliZDS^Y$P<$=iX- zs`2)sn0+YbVsC%%Aa9{}xOb#?48<&lro=nhJ58VJE%VOuR(R)8{uSOT?;_$$D2HX< z72Y-8I`2mBR__kd*L(MQ4^o_E-Xq@QKH;+yclvbJ_yWFEUprrWUq@dTU!JcgX$pu} zcvtxPQmQK70N-HWP~QkjHOe>EH{LhVH^n!d^nEGj3}3l#j&DAtT|jbQl4tm;eM^1I zeJg!yed~Rjyn~2u^A6&E^X>HQ@$J`ZeTRHU_3geB3DTS6JCqQoZ}-ki(6|**{9u9) zGVz2UG}O9;bkb*2yH4T>xe1+o(-XQTbocJicO~Q}^d{adFS!iIz`3ELBPCG1T&Krs&|97|~McJN#MZM}p1ZtejimEZ5%?++Oo zf2Kdj-@)IRcsG9!e=p*F{Qdod{DqunGd|ouQr}K|3^>ch{u2Fw_nFInCjb;*v?zbW9Ofo z*gmmiVwc1`Uv*;7#Dau%`ohG%G#92~?$jm@NF1CvG%+u61l=8#IF|ZkV8ZCc)Wq?L z6DjSK#Oc0vi8B(*{gb^%^dgqMZK-tue}%7|e|SQJzMbM{Q@L|kPMn{(faL1Lr8Gtd z6PMGN?n!7!6bZSBD-+jJZJeqhSAOmqU z3R4r02DE@L5ac`q=>f7UL-y%`T(U7r8|W118tCp{WXkz0>!pF-`ociJz`($ez_37( zw*%Wl;)IcdA1KW9>e>lrzdn5;DvK*KVc`mgm6sSxX z9atEkRv6sFbh? z(?}igl_zb~*98S(Q9;n|tkv!ZE$@;dQzRYKhnxkWYzWrUvMXtyNAl%A3T(})?XMr>dm3v8^V?xJVEW!foY}5GEs0@ zjGxJIiK$8TWH}p>HCme%`YV!sUU#yV9Ml&krzdCA=xC3n?lCwEWIr(T+y zoSV2!Uzgn58%pk%Jdjqy3CWDcv}z;|(TkFYK~ogyL@`Gvk4v7AJc(jz$y1X{lV>K+ zPM*t1m0X#;FnO_lAi0LdqBu~QT+1s|pdZz|f?};oUYEQfd9J=CP?IQJaK2>XtAp=nVBp*7TX7UX)LDs1Kpm z%us(q3`Rno>lvI98Wbud8>kNr4~-0s2^EJ*LX$(&LS>;@p$hNt(7aGpXi;cMXjy25 zek`;mR2SM9+8Wvsst@f89Sj`_9rvzC5#G8Kdx|qfPYEQHrliumrvBvhn&$P~ly)R9 z;rX7@K6pZ}P3f4@B_&T^m(nv(%l4B};4e(+8(`cRl2VXZkTM`;uuo4JN;5H#G9qPE z%Gi|gq2iQ@p~)#zQl^JyrOZevCwnk4B)MP8oJ7GZLdyKag5U{1>3OwHX`iw{A4j<0 z^DpsRS!TQPFQNRa{UO7ClImDC*2myrf3Jkzfy2Q={tgj2p;K@~QU%*ypfY7CqXEm_ zgCy5cKFi4tQ&U!^to6HD_HImB=@WsODeEKlnN-mvd#x$eDVq|HCU;NSMthslN&WpL zDLYg4r0fq&N;#BrH06YMS#m$UGI40Cq_uZ$YMegWTgPLUs`1#R`gnF2tqAV)ZY6z? zXD;`iIXh^kr>3W7dpi&=`4ZBTw*-nPW>so#YNyn$-ul!|`UKiR)unc)-0}&3suNRF zd+U=@3J4*Ov(2aW10P6nhNKQlElTZ9d^F;ZP8~;lg1N!1*xUXY4%m5 z&ZPWjr_N2S^!8#~B1A=5%u@-OX+PC2b#ZV?gnN(c6H;po?z8(VQfofY1?-cZuy)WeL=Y?;9+smD?qlHB^-)P~@cR7Jwak4Y&7T%Z%As8!BgTqAQBs+2Mp|ZC4%K9FT8FgG`j)hAX*7~Nr_y?* z^$G4z>zvl#H<5TB>d8{?vb0dzAnH%*jij>FaVa|~hxuuRz6GhhlV>KC(JE6<8X7PE zLFQ@0y;Xstw2_R%X(Q7*Qyj7-9$BjAx}+Rm9+f`E*p;P@ODi_(Q<640Z5q{(cBg4& zWC^8deORBgF?C4Vth9=Rfl0>+CEVV^BpP>GCF@dprp-&M(ks&zr7cNYmbM~oP4djN zX~}cb>e4nQ_18zIZB5%jygqH8zAo(`&6m=&Bi^)>GpJ|cUHQd z(w_F-y%P7+zPc`Ht3D}6n+R{)^i*2uCZ)II9e8?sKd*Y@s4bJy1@Gt6J3{UPIWJ)t z%e-Qy_e>b5Pf8oZ`oy6=on+qs*Q6KFIIc<8StdQ?!~#Bpr1$0BzP~W(c=`a^+t;U! z39Hf{j5(P(WoB<{aDE3Sxy_1)K=e{G>y*-X>Pxp;&(`& z=xv*lM>D80xRTovT*`9#6v*w!Vkrl**woz_5+z5KVf@HUW|-=0-Z?G$xdo`&y%nnD_Tv) z%;4ID?HRKn_k%n)VPNu1+SPQmoY6q3YRMW2k&>qIDbl}>5!*LC)0#FdP;2tGneI$~W+*c=Gbgh{ zLQQ7pz=6zenLRRlW%kMJZ=8`c2l@7A7V=3mb2y(OGe>5Q$tu$Ixz#6( zd@}cC9`sgZ9?3kOCAi!yJIdY18m%x8l26K6 z?f8sL9PQ$hJLQb?HRBSeB|BfkD@ay*UO}=tvL>qw&%vzJtUT|cte!@0IDPNSD#+@a zH6Uwn*3h&H^XUYh7-WsmM`w-F7t=ncHfwCw_^gS>vk2qVpEV_Gde)4r@~k;o^NnW? zM!y+P6^!$H)`G0+tfj_?7|#dHCm48M!Ku`5*HvEhEr+x9prm!vq|0|w_r$YWC_)+jDg%bXq z8D}){@0jxM@Ra%^@b~e&^eJ%8(`Dwo95P~>d?a`maFi1M3;5IEcupVghi9rEKrZFy zx|}wAG>j*%HheB&T@Ahg{O90<5q~D0l&^vYW$~MY;RAU0+Xo)`d}9aaY-sqcd*W-r z$MGAFb{~Ic%UsUow#Y|Vw)TPM5oiuVQ;(Q_Xr{Al^C8Z3XkI~_#n9BU#yS!4)4^{- zoHudzO}rtQ$+GeocqZmr@4=Gg2kD<@tQLxNsE<56G2K3p`Pk~-HG`O1& z{okO^M|)=&J%iS@LH&ccoBb)jm!8jh@d54@8Zzu^H{|h%lMQ(X;*>z%jkb*7d~C;2 z;s})94f0N-w#=>Z;9a4)g>zFX5ht0svLEsf3>mfcqLfv(kMM>qYmOk!zYwPZrM!dO z-a#GqLB9(*Hz4MRxND5XEPkh*EUE`Ajo+Ak6D@j$KdmC08P6KT`2=y&Stjf1fw5!F zd>gEkxxAe}(UNhWZs#7xCyGVJ*g>{Jz6CK4LUSeRPzy~rSZO=R9WnYlS+>SQlfy9` zhW%d;%NftIy%MDlK|Z6@-y3rZeO1FbI1LNlH3D!Im-VvQ0o<$Ty1f0A|_F|#?Q zIF34`L-Qtc>S3Jeuthvlr_v4&-?|%Bn&CyHMvuV|>wy|00J9#QCpb z0~m`Njrv2Lj#NEt|0cc&qwt0?6Zx)HBIXMIMAZ5!avOwktV3UYfV3e)Z`1^7{|fyL z(40Wsu0qXUL>sR{8#m$;=Diq;v6!u^(V`{LG$8Fuh&jqYTK>L?2pd>u%sbY|NvKaU zG&7LHc9gF2EUeJAyHdbe2wdK!nrO#M9Am7g4%p!#3@8H~kIoQ^)aNO+( zo{uOaYTH_Pa~y?mE?4|mZ6DV$1Kg}&O&vc->lu7;c*ei6udCC2Vs+>`ui zvb5mtKIrEnew?{#%mm7nu*JfzZZ~%kJy1Gk0rwT5L=W@;^A!d@<1YHg@*DKY924Qg zJlD`~H{z~?zmsBLZ`dSq%Q03)yJ1n#K<mUQ=Z17R=!?eE) z8EdiqO7upaF<;Po2QWGcdc%h~^$P4E6)hcuHcmjf{a{PQ#{4qZO4jJOyAXBANB#?0 zPdg31d$*Cl%|Kd4jNz!~5RTvWQPiy#ZO1;=UW8VUMd_VUAJ~#&MLrKB=X!9v&9KHE zKx`l0qu`p{Vbt@}VxW34&mfG#D)iMx%*X8*qiho=xo*P@J2z$rzBOq9-)QtO@U|1m z9SFPXYm72-UT^Hjpi$AQ*JB4*Z|E^Ae+v06e9P$#=2A8Hw=9P+_m88ES0Uzq4UW=_ zk=xsdA7YIFjw$!S_68u;Z78KbdanoM0`y@4>=3K7<-546VXSu`w{Ih#-o~C8Wqpd8 ze1K9889P|ywi2=meK}^wTUcig85-EhPcc%3xO*M;Y>QFzqsES%-@}zUO6i9B%r^T3 zdw6~~&DP6U9}T?1-DQ{~&!EmP!a~q9)=yw*FT#FCnRnY^pTlp+UJnajh?okj;zh_o z^wj~w+Kv9ix*0O|U8vjb(BBUEZrH=^K-Wp&-M|-shrnlnFG2jjqV3gK*}EgpjktRQ z_$|g-26-6xJ4lre{Ss&%!Ads@?+$%{Z>Rp&V7b4Cd4Wxx_{2O=wi5mXi(4fvQApS1I zKY;i}#z_$RZ{hoxU6866E!_@oF}PvjeAhP5SksL@0sl5~XfW0_@U_Sv$UrN838%su zdIYQOzgV`cgk}cn_HDFosC5t3t=P)nxEyMn@=$Ie>>RUzPJCP+ppeB_DS!r+QuJ^s zdT*F<7pI0<#(9D5&Gs$qpZ&1yZ2lgrbsfI3-VvHd5VIJTxgTkr;Qj6V?)lp`LKx*I z$aySA=O!D!A^s?TGe+Koefu*u%FPmQ1eKQK<3;BSGyVVt8I+7rh! z6DgqSfINpF&kl&Wj9X;MLyNGQ%bywZou3F@u(HV6#)%u_?!>pz`U!qR z)5>qq#eE}=-@y#ZT-jB2legga+Y98K@}9=uXMa!*li!j>@_X_J_zm{QNF;t8Yqr_N}V&6`j5%Yc`-b@U8`AyS?xADGd8}pf24OSt> z2Ao-qCrRe6(<*sbng&F&COZ%q1v+=wnf^(Qvc#0r58qXvk{|Ou`k8zGS zPf<=|oizK8znNDd_&s37@eBTq$!6~hen*TJoy8dOnCK=R7f*?vcwg`iv6!wq#UJSE zE8e8*F0r4ke)c!07r*Jqa$F($JFawGDeiGx?YLSDbX?=;AntW^baWK=Il4Hyh{29- zj&9<9N1h{33~}7%C=d@g?sp6k4>}4Rh2kMRi(5~lYV_w$v4?U$B#w#`id5nhP4Ou~ z{??|Ft8`MjD&3WQ{-zH31Nl2V#&>&^3Cbj8s#2=VRAwu4l}cryvY2!elp3X0S*5H~ zHYi(^?aD5E&uCcGHNm_N^KS*yHKFlpFfM78ZKWIECGsmpGE?R#6J!UHI+MlqkiBFd z*`Gp#WT6}`NAj~o`62INY|F@o%dCrNj^y(5PwT%}w*C?N$C%sh=O?Jv29}ix%q@L! z_kW^E3 zq(h#<+&am^-^9KdsdAayK1BYTm|LNdk1(hCkSe6&R0tJ?BkuXQvbY!GuZ!;#e|`MF zXl`8j<-SX6vxqR>nSBuN%symaX@Y}NQwt2FxPxiz+ zu-ots>_6}h>|1yTb~oOE{ea(rwFLPcSW6DS18cd8-+{Gs8 zIz`tlnogBAmbk6_4aKeKaKrb(gIacnbE}QBE)TpP^50$XPl1P zvWUuz^i8Df=rQCxB5hovE^F40lTDxQN8&f8<9jRAHI026$(#K;vkok8RJX$4q1HF{ zd&G~F&0!wTh##pt_ZQcT+ptePcvAXE+amrE^|&T9yXMsNX7!9}%Sm-DiRp)kABw6Q zw!FF zM{BQj)VgSST2HM&>#GeoWxurK*PZ75y3@?>bjqnR`!~|hp_uXdEWfTPtPM8XeJbDV zm)O46h8q3!d4A)#m$cwVw`lG0C;vwF~{swAXdO zb=Y+*dYy7LxUKHCZnxX-4mHawvd$8@Gu=7v4(`s7ySaN{&5e*5-`&gI2Y!F|Aa|jA zxO=2~4BCGRau>Txm?C!Pp6s3mzsx-=dM$NVxaYa6+>4^u9`_PA)*|-`cM1BD$2WRy z?`+tCdyTt}+lw}CbZ>RbcWnK#y$c@(q$MPn)EeU#t0 z?#EzKGyhceogCAjG37O`m9gt;tiLD<@1p(4m{^UPmEcGl0t@NyAYTSoM@{8n6-h-NeRYi98~5p+-cKJ0J;h-^k_U7-`Vhn!rWbKpd{(vniFgTr zA3A)0xSr&P_*AR>((WS7Jz=^V?!#{f*#_dt8p7@3L%t7xE)4+i$|t-4M$X zvI5zPZyQSi`BBI>A^t+dzlUYV^N`oFtRR1Z{3YTjh+`WV$G=+fI&=F?%;S)=6*)Wb zd8MVyD4p+G-(?>8t}{wEKB@nKQ4_u^??L|Uk!lg-fh=2)N|}UmcO%sy=uuAv^|a!> z2ssjQ{sMWA(H7Kj2kJ8#ca7)gKSQgL%3`FtANp6J-+@$bg4+;BLhpebhxk1Ze;)J` zp#K_bG7kD~kQ*RBiJIUOaLZK4c$dR618EOKejIt?nY_IXG*;w*yApRT@o4Wei1`Wh zpCX42h@Xf!zeb!lA^#KdVV2u2#CT!s+F(qr7}L1nkUK$s67nrbI|peuptfbm|8W8NFCotDkVir8g4W%Q)?Eb|c4A3G z9Q>w>ydE;FR2o)_&pMU1knx6z@-X6*B2F*JLm_vBoCDbhc>wyyu%dKmz6<#V^ccoe z`7z|1A^#L(@q5(jEyze~fd$6FHmo-E*l&@~KalqONc(%}S3w-c1{(8If{zL%zd<;zpaXKQ-Y@{-tQx6jSdkIS1eL{-(X3ydt7ZXHh@k8;X=pw4= zx=H+vu5RKDu}R!4w$Sx8=g&ZVR1|}C|0Gd;uc#JzY^=}c?QAuIoO<175z6_)nQtwGyp z!S9NUW|T8E%ojuRbC#79#CJmfG;`adkozD`SMZtO1CiTG$Ro{smf~6TQhwJC@=Wln zkmq;tH1#Ev(g4j%_*IfHbBh!5Zj`thF())VeYH&CyYk!C>q&Ot8M4>*py2l>gZ$|~ za<~b61bBfVBkg?rBHIT1hKFGTgNrL?B(`3_W8sY z*sJYJNxz(=mG-sv^+cQO+w42-d+hs3cgTL!e!?LgaSqMla|CHG!93fMYd`AfC|8LbBD9oh$HZw?Qh23fJLm4$<=AUq z@90h?=7P91gAOXcK5pvA4>Z<=-0UJXXcOW;A9~c@K;mf2@Q4S1@CNnNDA~2E4ngxM^XnZXQObg7U7QPJqSSmAgyxWsW zN^oE8z`VeMz~aC%nTsNr69|l;Z?BLhusX0dupzM7F7!2s8su$fU0@rz8(&^7M9m^! zGZ^Iiz)muI0{a4MrS1gEf+q4|#7jfJIn?yCd#MhqO zs(iXW*vj5S`YX*=rFZrY|BhhWV25C5%G(nNo9*u&>?TXwV21xdFe8{1>=W!49N=py z%R`cHw!JE_fxa}D%I5Vl?1w)y(&vJbHaKDU?DYAva0gU$oK4|{YKsTLS!8x6xOq(8~981JaCL#n=@ zZQ)OCB_aG-4>#LYdZ91U9leve2;Ev01JpvKG%8z4-&!FleRnBZW=j#1l8%tnSfgSC zsesWVL*TogLc(1LR}sRs3zGB%f~R(>ih1;eR!C}ghCDNso?vF{ScS+qq&Syy&cItC z$QgpqgC*iexSTzRf9Q$55OF?E#*FAMsc$RrETlUFj+U#vS7{FXT#0zzAgMh~X`?zf z19r4ZjiGSwV0Y9V*e`XIk_WhI-L6oYse5}fkfxbP9f`C>igd@f7ONP5v_*)eAxNnt z*#825mc!3lkYtt0JFp{+Mge@AfOhi=oIH>Ung=`!U+jxC&4ZsE%G=GxcKB1MTG*iN zb-weVAdXbB<)50S%mid?DX0#-4NgwN~H^6YaxVI2|L z&DWa&-Iif=5KEh-8}ql2MeN-BO-px0X%QNt; z0>p4C?3s{!KT=^MkQqQGBP?5ibVKS72ki%%2HF`<7r^Cg>IcfRQwAWGqz_0P>uuzt z5zw@=A&DwQQT|YmD1`~?krQQ{>MvOa{r@%Rhw7csX2wI?F!zUt_81q1wuN@W?9oQr z_mL@6_pV7Mpl~;dOp10_rrnlRcu(8iIvUeB-c3?|MeSycy`DA!%~N8YMNC8e+${GC zG6u>`TzIy{$hs$ie~Dy@l`YmJRnH)-P1HBt=H+3J%2lSG%lL_tw}PqoeT1PbCcgK? zq>qk2ycf{l43vjCit99l3_6VRijBu;d?v-Xk8t^{RZJSkJd38G)Md|9(ER9?<+B(p`^x0BgLW-pojA(ZPLQKv$+Qc_)l*(aGF`}Yui#g`a^v+R(@WcPRN6#M z#Gn3}=aCsgX1EIf;fyy*nTXzbV>O=;imOY#$z-O6;>u}nhUT+%Jk|=u)$I{I@CsFU z5ym1ii}ZU-?&k=C`n?@=R6Y)ODi2?{YfQPT z-GzHp&=Vcs;mlB+&PL-XsXVOVZ1r6By44IHNy+{y?5|=*4fc4K)Otfw^HWLfOC%Mb zCZ3uDfzOfD_pqcK?gbDBZhU9J<(I&(2c0Xaq5S^@cD!r859Cewxe@luU|0A}uv?(X zK-$7S6z}GPmf?#b(7JfK2QF`b-48cFj3DqIfj0s2FVN2<4M2WB!s7G+eE?6V!sqdL z>wNf@iKiX#bU6H+1$-UoXdqvJxJybyPe&ho^VLz7$`q1A8Y>$ZTwZZ!JMz1&%nk z5dUH~?1&{_D%?B`f35;v1RsD~&0(Jodj{w>AkYx2siZ8#h7sM#cQL_gRX!KMY3Fof zrjy}huv49(&M=lj>GL2v-T9;QM^?xAv-1!;11AF1#fbnH1kVee&n^r$4K`)XgFAye z*~Ovdq1Rc9&>NvQSW7qAO<|X~sctH}>}UU8TgLb(GGm!M9fR@7WTujtL1s3YLVaIE zW)V}TYRda!ZB}VF>V(a5vnj?+K=3TkJ|G15I&rb($9yG8OtZ|$#hKxm0a0o z=(`+pHAKHVo8B#?Ybq~_xfUIM=eL^J^9_5u#qGwXc7dzBCtFp!u^ny)wz4h0$t3w! zUn?oOoFi1WMa^u)?kM_n7n}#J&wH_7234oK%ormTkN|) zhk;%J`XF+voPV;I%abNOoY}#g?#>NVy2vv-ES%X9z?mJcGuXM0r8*;>k(6&nIio4x zjCKCP>INGJf6eLzcLcv=4MN4CV%E?-%{`5s=brAK&Keyzf6tdg`eZ^COf79vHBTo~ zpG>0|)09jLGOe{q*QTB39b^2GZo4pfwv93&?RUh;XFY$?oR1kd@z;_{NY!|viyyrD z&~O&nlaS$*c7`)tBKr{H^d!AAq10PT%>Tbeuxpt5Bbv?nvNZe!J&Vm{ z&$6@GBD&6H#cVBW$TrjU8@7e6mTW6sm$1+2YQ?^w>r(b5U9DLuUB6}f*bl4?`;o4; z>>yp2bHN2`C$}_XS8$tJEA6?%{p@!<$b;-k?sAuP^q>)7UlqbbdPP!hgko#eUDv;AgO|{7il(yOy8D&tl#9+5BvF9Y2Sk!@Bcx`MKP zUt<0E%lu__Cx3;%!us=9`K#+Ej+27iMM;BWFb***L%{uayQZ}Yd= zK>iMYhvoBk`MYcoe~-V%2J>}%9lMvWr{2&IzJYIG_wkSTM{Fqnn19Uvz(3)iuwndD z{wcfPz0$ps4R;^%{Op0~`Rtf+LgsQgBiQaN|AKofJUOF5x~Rj-Pm*mH^NidkPpagH zY$@~LQx*J(bn$gcW^PY3OPE&%MtDf7qShXrVV3PCJaryn~n*kjdycZLV4re zbV?|3x^{=Y1-m+d%!1xmKB;hZP9SqdH`gSPxuTmc31qJ5=JyF?7UV)nt=x1?7|$t4 z4MC<3TwR+mrt89`+*c?CuDZqh<$aLQ)pZqItxxExdj(e;61uv+g7oyt3uE4#ZbVaiu_myXT-B&zIa{~2mQep zgNuSM1s4Zj4lW745?l(O8n7^#2COk_MlG5)RDX4%aHscfQsSuWH4f9}cgg0k@# zHP|7?i4N62Bukg?Fvl>&uyd}OjVRslnQ%E76mwTu5!UiJKtj}(GU*EwWbaHoEFPo& z?Bn8b<_|6lE@y$@zTiIQ(lei!E?$;rVT+Y4UA!$mXXo1Y+V?Wd3u9MMn3l5k;a%Zx zsCMyiZnuar@}5^P5;tOu#JW=ddAyh;rqI`BiMbSG3&j$#T&xsp#5%E2Y!TbVF5-K| zeo`3Q2pP4ER3qJ}Z!|KR8ZC_05gvWs&gf`#F}fQ)jb28M(cj23h8V+*Q4xQPvBm^r zvN6?|VazrPjUr=_vD7FwRv9J6dSjEZ)!1R|HcE{HlAF{=mG7ILS=&rA>zWPB#%43K zrP;=8Z+0@fnmxoUGtpyTr=P7YYsI>n4`^c=0vl=oMz56=TziT`667)7vWL& z5&sUus~d0TJad7$*j#3=FjrG})<)thf-5=94He@n8czx0CoW#986T1KiO3uKJ@~WP z+-B}H_e8_L&n&Y{D_|vADOMe;p4HH5Vl}r~S#8a1tAo`!l1^4PE5pjN`b2Q6pEbZ5 zYz?zUT4Sv7)}+J6iz%XWa?4(da$$%h^DfB98Fz5vB6do{0|{U7LMk{-g$dNn_q ze+&9+JjE<~HB*)U6$obKGt8Z5=iuGfLDS*J4}3Hz<_I5p6h2^{JO2|X-eMDBKLz#) zpcdRGt8xPfW;8R*r9FhT0&4a#2f`5ELu=tbzQz9zdIg@&!&CTN_BTlnekADu6%Ux5 zO|1^;<_A#B_ve`3&F=w)By2eB%RmuV>|;>OVP}89yMKoLEzp*r*8sl>Uw;x`{|9{N zi>IG~A~p_T9=gcJQ~1oE0fPDR0&&G3f*rHPxstyW2ZZbzl*CpVZK=JJX%b( zcrkV#on5~FsC>rL$hExI(UR6Nol^9)eDwV%AXzH6aJRfkMlD{_l>&N zsIRHi0!zo$tw#N=Pd+r#;{pT8E_I$t739?5VPmYWb|3p((obXJpew~ek2rTnFKevd zRZCEE93?2Jq*Jlqe_KCoK)f;aCR3`6(_>9H*&=U3S9VmAc*yuO4JFkHZ&^ zhvt+VSIsFou9{PFoHeK9IBQPHao3!Z1oi*1`uujn`oE@ptyurpl)o|tdg_urKk8>d zJQZ!dom49saxhdH#X^!H^*~rY7i^%0Gq>{ag}9QemP_g_A*M*&b;|Es_*1aaC=+ z>iVf#AAO^(kNg^M6I54{Nc*H;w0-i+$s+So-3ob0<+UTr5j|=kM;zIABYK@t1A2Yr zA#O-vu2(76B6a+cg&`|im*&?{8>714kJN^}qP5}AEx}L4WyvobmnFY=T$UVBTuzAA z;wMktG%?yjI2mM)r1K=SAx{>mW$o8Drtker*M9wCdgs5KERCtP-i)sPWODQ<>Mtja z%)dQqB>x^wO`1_7x$wxo9LY;PYa}ln`L}!NeqdS+me)^LTLRTr%tl`^Gpc<*uMFwT zM{m}ryjUN*c&7g%Qb-NViWyV*W!gc#VnzjiZV4je1`%!eC1f~0sZjEZr$WgIkP6k4 zL5*-sNsl5ag@{JWKWyp8<4-QO4f4uH>twBJ(tYW&>` zejogvbw=Cb8g`o8Ll}l>UeVZ^o0=PBM9lNp_pA!nn)@wg*;dG^MJCnUXr){AtwvT;GA*puRy(Vs zxyI^3Z*8}_TRp8_+GUQ_-^#OwkZm}bQPx;%LWTDxTT`tWWM9>Oi^wdcyJBmV zRbs8THqo0~tsUg&Zt`=t_H(jTN`97F2W(+G@qXH#UE3DCM~v+d1Rp}oyoWbY)iha^k0_gP)+ zGOLTv^aXrLR()TJuMU}dBxhcgcNOC$=FZnJ5-+|czUJ|Fc4J>FUt2OA>^8p6QWjq~ zUxqJB%Hr!ICG+*O_xJ|*2IJYV#LsF*LwqBBV|?R%W9-qsNxmt*>AqRMxn$=17W$UN z>qNZEBhZOBEvPcxt4iq_Nn77?-%8&a-#Xt$-xjN#Z@X`oZ!eks4zuezwiB`rI3cH& zlWO&H(w+KNEvLS(A8BlVYn9W;X=-h9S|CJmTHv&H8j;IJBrwA(sAk=$IZ>D!qxPXxyM*!pD0UcS*cp^#){vfWGX)fTi|TnY zYAUmRYR*aehfIS-3d>FlhrrP^c&1u2@e++V}nMG=Tf|~Wj!$2^TLG48UxuG*#ty!sW{BzCPu15ifgAX&_ps~=s^*e4#8b?sFjj&pNjd?? ztPFwq+-et3wMQmHS{Q1c4|ba5YL`&V0MR?Seh$1fsM^C7ZuDN5YWG&`uF4>f-p>_t zKlGmPND;M@rP`;Ht9eao_K2EW0=u~r6nj9j>9DuMTWYRX3($_BY6s1i;4@|`9ZDmg zWK0$zCdsbmu&F(61!lEz%ssP{=Vo}YYy`s)jAN_ zqeOa=85C_n9@z{lgW7ik{DXAcv@KJ!I2apz#6Ah>llEsY1f8Rj{fUIm|E@7 z=@D5t^>Y^wr9~cG98g zR>S@tE;Q?pOK8>~r_iXiHMLQjM8b0~tEs=#k<^#}NM&sxqJK&6{fWP%$Nr{_eHpHH zx?CG_#5s}s`!coODHFZxu`xacNdk&>@g((iUBtbIxDO-llPK=*Wyy&9ril9sA#1bn zSK+VNMM#I{M=6h50h5JOlE$4763O`uGN#9z5YnjhN;%=uEA<3QFSRuHoUK&s zqBJq;W6h<((aI(Nq~uT@NF&PGq!UOo8~ZKP!6nmW@(CoHfOg1ImFt$_(4+G2=lF*# zSFxs}{+m-aHmq{B-MIhiv~5gRI>{#YOkItUk@5e<;g#i* zY`MzaUYh9nfJ3Vs13J?7ZFS1YMyx4oLvH0BCoT0j+2N&7@qfIeks2=dDJ>v-`Mku# zNptiwL5@c}HjTI~hY^Q9as*>VXy*cb-K^8}a=~kfyb~N9t?(Em&@#PX$ z{r+MT-5P7C=bR3$k#GEC4 zNto}d8_RNhP5#F%z*tBYo5*Tv#OZjKa*bkS7ypy|XOUcuPs+dRQ<&PTYtl&~yTH5v zIUCNvzBQ45$3Mraw*Td_pI`Fw(R8J);v~}5lRKZO*(7p)?6J%yk?*|Cj%-edY>(B% zoRI2&J2JClH2WoHb{t6@rAH;@C$OBcvn*trdgKWlqvdk`5_2VvBu>j`Jd9<(#Egd{ ziPgxT{0Z!roVRc!vD+|4W_}V#96yIZ*5~6+f>@4~_?Mgsa3t{@`#*mY`z8P9S66De zlCCjoQrX_{^uFEM@jG|>^Mi8l?jt_6Lay383ez?2tlgfxfAmycd6sS-PR*Tx``NsZ zup+*QF9qJ87xPtwl<@U@6W_{r@ZG$WAK;6G5RULfZILGGiUy*wXeL^UHln@gB)WRKJ-k3#KHwv8g zpjOkWRk;FdIt5ma8sEc?HL~gi1HD2ND~>mkIWUem8u`9miU^~1Z+L$!|l5LN)I+)c48&!Osw z9+8a4M@VyIiJn4sr5le#bV)q!Pk1&1#k5>q-XDf*lY$i%)iM299vi}jQ(IHT#srGj zA&B)nvd^aHg)lNEd!eVx%EMcRHP&S)F%F_cD#LyT2N6GI$VUf}L(35MgE*JtAo6$_ z%7KGeBX$sRST>g>I`40Iv=*-FbPLX!ve**R4<)*kZ!sys8} zu+L=J`yAHr1Xw6~9+onZQ?cX@wYl`96W!+%J``pI`j1GdvbE*uqEi8@-Vb8mg|emP zDW$Zu3?+OS^s@}5<-rXxDc+66o^Obq2*^BuxOw;|;zLjgqRv)J!HgEpdPUzqTxrLt zy>;X(xYc(OOZiAOrL6e&2)sS@$KnM2pV>U=HifD%0$RZ_G<4=o2>1d0>G4x;r~hJ9tq2E^1Xs;+4oQ@+)W zsb6}c^pSr5k=5MVK6RGTGc0m)YbM57vyba{b7bFV6O!6H|iD062i}9ufc=i$V<=+y}M3;WbAY3bLrB$l&HhhxTL%jEJ^0kL!Td7 zEe(AA-n{{DS^IlY4HtWYWr+C>{BW>+Wpw{~)+YfvCK0-?xSA-*S@zX&K`3lL4y-K0 zk6$K|?8he)p+9_BO|{6QO&DRufJ5rG1kU%GoFpS~|U&D8=7_(FxLf zQNsA^dV*@fFN?^Sc{@=Y9QfTa>6`2)%k!^>AEur?vNj|2rbQB!3FSuK^9n|2-j#3X zyZBzdUoc^dkf*)3^AK%p(qlI#8Oc#R*4d^UThLu#SXDsl!^m}FdV}Zjf~nxno-wiU^F(G87+-A zbhR|v8=Z`|wZ;Zxv$4(CY3wofsn|2h zOw$Y~#7r_%%sOU0v!U4}LE7Pqk(xz~y9u28$<>}_XjSObGu8Q$7(3%Quao~uQawh7 zaVw6IEPa}!+FuTRF!mKFPQBzfwNve)#?`pkR#3GY8wZZv`53;a&NJ0#v*J`%eLki- zr4;9@>hZM)Bs~N?_N-F18ymkEzTq5CeJZHhu?@1RkvM@6akanP<*;9hw-8>ni=a>^ z!$R8FlSwO|BC2*ZG_XIOz}cf5YPxF)^Xq*WkBqyscI~S zs~zfY0HScUzamBh1x`2>YG*~Y&zl-!#m;g9XMmcZ23nQ^BSC7^#y~2Fr(j2{3XBKw zO?V5tYZy2`)VKgt?LBxUT&hvgklqamJyeV#9_d;?#^%CQJV&!6<{ZtXWG_Ge5~pbL zG+tMpkV%xT$T^z8aK)UX*^Hi)5LJGaNPpl<)DQYjA=^YqOS*5v+w)GmD}AX4@5(bt zgOx9hBl$<|IcSV8*J(AnY^bw!)j086O|=uBN^cXRbjGLUX=%>WX;w3*o}SoOWK6GqjfVMuC%sBq zGbg=9Ql&|B4;eWsF+)5pW{H1_XT?164%MpfiTA~Z@GgX{F1=9~C+W-c^qY}gjvuxp zTl;9(G4{u~2i{xKAUW|W#(tX5e|L_k{{=XwX;7WJw^0{5J@H<$L4??~+WB|Af(ai1-UTy)VNMD+}Gn=&#&AHIK=8 zj`^?$U@wL}6ZU&ycVS-vdlu|{VE15u5ccz7e*^ZLVP6P)7ubhL`=RqdUzP~32YeXZ z)PlVT_D-gmVvU2+d(c4 z$TEx->iU{4)ajd0o;m7@DFdk{mQ?$-1OC95s2`1~6l{t5xi;!(kMi6m&>d7)x0H1? z&t`G|oAuf5_;;oMyrNa9cav6sw$v&4YFB5qdvnY#&1yGh^~YN8ij2`Wz5lb?aa#Rp zR;TJ?CtC_l?=hSN$_qt!UM`Ocb$FCFFk^py?D=ol-iSZn(G)<~`SKaHu5#!QdoWAbNul^Qc05>BsJn_>sP zW3Ekw+DrZIa*g5G(_E zHuOGvHl+E2G`|Pwe&0y@Ga5Uufa0GiN6XPr{TcK()DG)h^+C}`i`pq%?Tr2b?D(%?V3v-dcB5DGThMzEL-DTayQ{wJhoI=m80i0)_rnf(jDG<^ zyVAg)lwTm_92Mu(4nLNZlfFd#NRV=A^rap|%X_8Klru1@V4R7V8U*{Bpcr}JKLW?N zfq~Hs)z?&`F=`yZxUW3rgc@%_Pv5|tCpFJWryp{R0Y43BjPW>dHD5~2&BFMDp>~+> z6_ZZrgP8a?W}OTB<-cs2MN_PqyrOB=EWt>E?17a~x>ZWE_>lxc+SB_guVvDgkYdr? zRz8w2wOotEdogJSEmkwvbX+frNwcLfak@Sx&Bn*%r~Ha(rt+5g=kk;@(_t?yPbZ;9 zHZW&RkNcocXyVKd^E=RLTRSRiqh_HcR~Y5n3VSc0D06Wh{NEE>b^R`%<1$QFrRGOf}O_ zoqD0>K%y09poHY=yalvN^k@-su$srHPZ3e)lc@7XFtbsON$L5D7$GuohJ%_nXrOe} zZIO#WQ5ULFLj!FWHMV6!hYU3qh`-oo{g|8@X_=~-4ppUle9N@*70nNNW~Q1InN_3T zYOHzPXibNinK=CbO}UpTV-BXwhEjhM=%>3ZU-{F7s; z#j&}H+TCe#Y%7|tHlby{L$||a`B`3?wwE;|Zyz`2MZU!N5h+2l$>na|m*?_)K9rB( zqxm>Kkr(i3d?ue0%~zP?B2=3rJ0{-MSwgCfg4Va1J*?&ptCM|%()GWTr<2M{DrXw_ z7q3pzQRCjaq*OUsjlZgYBC3s|N>Ka}dTA9k@N2xAdssMKpa;t~0iY1-j3}PP z&ZjcuV(NGNj@`(zL)`eZi zdb7SPkKN0Lu?N}cs5^rtQJdjbqM~#6j&)h{?%l4IC(tTC1WTrPYCz>+C-!^Ro%LaN zuz_p{yPu6@e})@5@1zzxgPqGRWtX$7Nn5UGx3PXKpWVlXvp>o?Rd8jpQ&>8+4qBsK zcP+IMa@d`05F5%KV58VWY;5ml1A7~7Ks$nV1I+}@>3wVed}9FUV9;TpBSFXX?tRw) zV?5{-&{?4KL6?B81YIksX@Yv7seSt2al2U$v=L}C&{m-BKs)uxz56b+D`*eUOwer5 zzBzZ~-fHH8=7SCe9RWHzC-2tY<~Y#FpwmI;fEL}6dq=*x1avv*O3*c+>+TqMcYkvu z=oZlJpu0f#l4!S@`z5s;&=k=6pw0T{4!X-~3)%s+GiW!^jQ)4`?r&v*_5tk&IskMq z=&-wP>vM-S5_Amcc+g3pQ^=b*8^<`+61&YXe-dR14%3F4xpVuyMbnaW(~Zn_W-*O zXfEgw(2=0y1`cd`p*MWBm7mx309t|HpZE&*K+x(ReE=nkS6*}FkY zK@Ujk6QE8$h27_Yrhuk{HUMohDEE%uz80XZLEC|L1eGIB29-69*#$>n}uAhY!#(Y`FA0eV;4~wc`=oBzoAm=5-LqDrE=i6R4!gd<=f>{B3wb`=kMa) zOk@*O;-*xC%aJch>r_cYRZxS<#5DG+Bd~Fl%ZI1IDyT)JY%MAuYeV{@z2ofMDk(-M znVQR>PD)g3V^sW}1?pBwe^mvQ>v`)}gL8IHmGrbKX;PIGBNZ&Y3TjXdbRKJT1U7x@ z-C=2Zm9%b^^vo)#pcX)bYVfMQaT8m}R!|##JKIOC>F&G_wV6jzOL-w*!PoQce4lVc zs%R)$ijE>ftP{J9fRSc2GFlm(jGjh6W2iCKm}1N^78xsz4aN>*zZo#o%tmG_vy<7= z>}L)&$C?YR&DL(4*-3U?yQ$sQ?rQh42iPO*3HEe*o^O_Kfv?z^(RZROl`{d^{MP@PGwJf<##Rpjap4L@1yw?%~vRXiqO1GjNkOF zQ}W?=`Tfue&xhb%P^nl;`!G!N8I_)_)O=68pS5dMxKEA0KW%*c{pma7@9T7mxu^K3 z(?33b&X^nj{EQV9o^OqRp57eKL)h!036<$>sQuc7+H+adqRYjaAqqwM2*uA#)4Y}D zyA`k7So6(_pQYWMRi=2ozKWlnt@#$k>#wO8Z|7*A&*=;~W1n=@yh19SGcjIc&Y2f; zFWt|r@O(vu`;9+wzdQcEL8}V)+vD%g%c*dm{WISe$KN-q6Mx@0y~6#-3ioT`HKxhx z3is=9Z&FQ|qIXE4SZ=aG@n6@`T&LErbK&|7Y8iB--b4oVefm=GX9)Ff#;^&jfK8_! z-#jYWmQvZahDx{1RKD$|5{^+Bm&8+fUF}b2&GmPh_EY>qotH11s`*~Un@!Suzv35Z z&AVuV;>~T%n`k~w^HRkx&eVLY<_i^Xk)iog#edU6^SPSq@3qw7Z#hfxOImBbR`FJO zieIX=`_g&wsnEJ(e5|)_U*W!Mh5P&p_tRqT$^SN8;-9yfTH$_f{QWhB@%LSN#NYqE zLb>w$UGZh*?@Mu?nxI4(PW{#KY%-h1X0bxHfGuIgY&BcQHnDANmy-7P%N6gMu6d#2 z*S6JM$6_~~irsQGU$6Lex<ZR{gv_ecebu@zbt0epV~dV1AOYtuHn!5T9KPtX1@HRK<&q& zaz3j0C=*UQryDb!3@3w~>I`*;u@vV4=RtP5^GD~8td8?%=OK26Gr^h4>N;OLd)NiR z^MdEI3xiFAO`!RjJM+LcqiVC_vG2UA0NPn@DY3rpMX*2S-g-h;7c$AZY|%)xAL8Q zFTJ^x+R$sL6}=fN2ugXGu!Sd5M7n4onqZAYd(l~R7n!1u=qK{TP%%=B6%$z=1jzeykoyGE$AYMnj`1y?MYejgV2>sAJTp zR(dmPr?;b)dN(7(=wN7J@(P zdl7t|ZxQil$o3NWGrq;(g}#@;pY<&PpXYmp3F1rXu8>^63jU058F-=ZHSlMB%faXQ zUMJUuzGAw2mR!F9{)}%0c%ko2@MnE1!RPtjBG=FQR?*!&a{V^=GrrZ}g}!&dpY^Q) zpXYm*T+j2BK>oSD_jLHy>hQgu`O7aBb1y`c#K&s}9#^I$YayxIRa?w(D?xp~JO9hwDonuAMquUm;w(bhy6O z;o7ak^^FeK9v!Z45w5*DT;J)`E7jrqUWad=4&M(*z5P0rKk85((4jl1LszE5bx4KF zVJch>SK)Gm3YTNZa5<(5mt(1LIkpOy<5S^s92G9dFT>>oRJfd=3YQa7;c{FRF2_^h za>6oPPLc|jldQt!)KcMcPEp}Cn~Fp*vfLuD%Xk10Ak&b+{VpaGj^a)kufye1xm9 z4%Y=bTupSieyzjRREO(AgsYhj*F`#9&2_jg*5PWQ!}S}4tECRtB|2QKbhs|nsn=SE z@3%<3HadKl>F~AH;k#UgkIDX_+y$W_Ye#m2HxX&#Y^otTP>a4N)#bU=o*&7^k*iTu zDi^RBY%aB5ma>&>Ew$>lvpw`=3){&`sbUH6+B}^%q;k47@4&l;-lKZr3g=pLVrZ?l zJsNr+wr+&2)3!%LACT>LaJOFD9u0j6n{>B9+a3-5C+gqEsDB?t{o54v@8hU{o1^}H z67_FO)W0vucBOL#VLP?$(a=}0{f@9*+V*JZ)981%M!)-6^t;=l-~BxL-R;ruei8ld zj_7y4j(&G{^t<0gzq=>$UD@ghEk%tjTWfWwwI%neXo){F9jTVipw^aLw=Pf0_(skq zur9GKrL+^2dU9?}XUvlC#^iqEJ()b4Tdp(jMRjasE&NdUZBYw#7^U(U>`gufdyb7a zYGGyajZ9dV7+1o6leD{8L|YkG0m;DAPO$gH)0?AD_riy7+#3kF6mGtQKYQFvxXh4l zr2pimr+g~?S5L)0>5nLt-xA+SAH?@q_uUY!6^6FTl~`~2gPfCL1dI?1*rV+~Ggr24 z?9R!PuoFTv?1WIens1b^>XbW!$kT@8*hk7yyj@*Mt>9C^8Nr#}`fx|c+p?PS#=aLX zbt|0FQyr-f=ZA?Ca#~|%XzEe=B4nvz|Jfcb4#`r*P;ZewyJ&lgo#HFyCP^gmBm-{D z;H;#|ao6#%U*^HTGj#%5^O!h0ocq`nyWIOQW}l46n^ztFOG!CL=>B#UI^zrb3`6E) z!#>llYoEmgU(P-@b{J<;JMny@3AGGc7$c2Q#-EHa##m|({?(XdJZ3yWt-=}9F8rtQ zFXI{GS>xZv^TvzD%f_q5>&8lBweha8&iK&y$oRzgjQrYZd`0cUJyyf;A?vr+W!B}^ z6;^wzgLReF$?9TtvwB!Ptt>0sy4||dy4xCP-D~~98g7lSMp~n+(bgDitToOWZ%wc! zT9d5FR)ICenrcn6rdugSMU@fv>=5^&jhF>r-pH zwbR;d?X~tZ33Uy14`qZhL%l+MLjAqX-d1nBx6|9@?eX?{rQUw8EG)ui*bY14K-de{ z3a5k{h8u^QhMR|5hFgdK5&l>B+3<7W7s4-vUkSe!ek1%=`0emJNp~dWCJji+Pa2Xm zG--U&#N?dhe#yDXdCB?7Lz0Ij%hA%0skMKmaW19c1;&NO#m0liA1MX@Y&>K@g=3;*Ty$iL#wgX+G=C9wb~&CJ61@+9IKy|Yvoyk zt)WMlf(znO@Ez-2>pklOor0fRUs_*V-&)@%NWs(XGY*r2&Ftosg01W}c3Zn0Qm~Jm z7yNhdx#05^QZPMKFPef)L(M}ik%H|*9YdWfq~OQir{3q@m)=+2H{Q42cis=)!7vXS zVJqwl`@?QHIecpP-0=C~UxzOW|0aBCcvg5$xG+3Fydb^i_ z8&4YlXZ+pxhw+^8g7K2^3esv7^}yCrAM8KW3;WdgobuXE>pbII>pbgx<1bcctE<)B z%CIu6UREEguhrigVC7pwtYOv+YnC;~DzxTP+`nj@Z!NKwS;f{$YqhbK_&RHY^^x_7 z^_jK9+GXvrO0E4?nJsMF4%n{oxz*V|)u?Cx%I}9j44EM(6bdDU zYKKxobwYJR^+QcU7lnQkx-@iI=!(#lp{ql`4|NOm2=xqQg|b6Ap!Y#tB!fnF;3_lb8cli16i{Y2UuZCX_znOGrQeM*FqzOrr zlKUq2PacpwIC*ID@MO7z$rI3frS%Vyu9s{2Pic5WzpK*en$g%ZNi(HhMszZfK2}c? zztTEbE!`unlR8(fZ*sM^}L&}wA8Y`to| zZoO%}ZM;YPed|N5ZC_YlS>IUSSwC0@ZEjn(KdNnKk+$6lZ95CvmP6Y1LPBk87HSb{ z6>1Y|7wQn|6zWnz+dlC=^Sda(?C{+1 zyl_!?VR&(PX?S^fMN+?{dy)nv{Wa;)>%myVDkU7%i2&Mp&#`L@~AH`lntlez-Ts> zdIEBnIhXWtvvrWlC{Cr6Mdg&=4uoV;%cKd~Ph5YvkY#O&iZmHLco{-`{w zkYkrHITKLM0hJ@ba&%XY5YK07|IGzt78>6%K`o>2iH@5yMMsD_v76(yjw@UYY&IZ z2S7)FJ_tGz^pBvUK>s9Z=vzs{UxMzGRFAL9eWB!RQo(FiE4YeT)Ha}4G7XjTFp_uCH6$vY*nHWHX~u>hA>KCfm2vj{PWka`cOnBVY8E zsV^yR?7--=N%|po`kbs=*3`;YeOaRx^&cJMO5cvTw9+VrK_u2cKmPf3AF?n?Iqu7Uy8-EA=C+MeI!g>_`dU`Gr!xq;mqacq+uDP z=N-`QDZd-QvUJ@4KBn9__HU~ef*Nv+k3B9A?^>Q*`Iw#@k>(Vmb>ORDFVV%ko?dUMd9wZL<*=_wyT0+3c&~VUyrtf& z-fc1Okl)^waen;tJF;z5+a2xx+53w(&U@G!>pkf`;yvy?;Z5|0-b8Pb z_n4>JB8@2(-y%(ao2_P_uzlR)NxT-H%jfa=d=cNv4+&3PD4H>OPS^$RDECk9Q1=h+ zF!z3Uxch)R!hO&k>Hg81+cEJh{xyI!V(!V>Y z48Du<|BErw?jU&$ZfTk8@_PJnE&20&0e^wyU%}V%t-b*DPCK%v+(GVOcZhqhd!IXq zox>WibKSw1RjX#8H(|e)Ph)3?yZ4pP4)^Z#`g;St`@KJUeZAYgJLtZj*PrzvEYHjL z29ZQ0mv=vVhrLTB_wB6E8|gjh{gK*zkC6L*>{+&m-pZ%92hkh!jB3s;RGxg!zF=Qc zIsXIuksaiYmrK{(-rd~x?xSm{HJ#=v!ird&UL6 zGWlvbqXMbcm2y`%b{(bO^;Cl2K;_1bR6^ZEDS0!M+`ZXtRFC$JOVzunRJn(GWdqqD zDtYc@L)d-PKl=lf{r6KJ>jCy4n@(Sz%buYY=ZjSKzQIs{HVQWbbK4qU#-MEA8 zWZ$#>RCAWGLtKz%n4}v%?&kp>q zWYVH1_>+7p{~Mpi|Bp}SPw~I=r};nlKl#7-GyGZpZ~h!Dhp*u!q<`!92mC|+AHIoi=37V`G1tg#jZy>ik=!ovxqi=ldGFrp z_EYzVN^yUuo3HNWKczVLv*Vv*H_piWf=cgSdzW~vyi2{--fz7&-eq1}?{cr5cZJv9 z`<>UpyVC3EUFCK1uJ$^6*LYpL-+NuXYrSsXbzXPxdas9fgO}l*?=|)=@S1qP_L_PZ zdd<9xyyo7;UJLIxUQ6#r{F&=1{!AZxNIXRONRT$v^8%jhdET$QI$pY0&pX?z@15fX zy^t67lDuTEmUoI*+dI`u@lNwny)<%nhIgh{*E`EQ&uip0@XqxbdeqxxCU3$olDmV7 zQEx`pmD?z8SZcfR{?_c^!7UEn_NzThr&Uvyt` z7rBewCGN}aQuh`2Rd<>DPxtTcEO(|S$p5F^Z#>(b?Y`#z!!2=lyKlHF+*R)DZn688 zyT*Oj-Ry30KXtdd+uR-Qm+n{YF85paJ9oePqi1@S`;oicebZg(zU{7d-*Mk_-*?x# z>)a3A_3nr62KPViCii3a6ZbRsb9cM@g}c-J+AVdzclWtJxCh*W9`}5n=N6J;)Z|1devK&}f!b6o8TxvhRQr>T7QH_Bs& z&tdWTYbE8a)jD5Q$W`tbt?O0k>apenrR$Bwjiixd#2Dy$M|Kuzb#jcBEA0)Cw#ytK z^*vtOPlvwOiPd=dmyMs#FQ5$k4ga3(KZvl*$J}8L9;J>KYTbU3^mrMxcMj?M%h2Ju zr0@SCjsG|4ywv#TN#hrj&Mzfhf2D$cZ`2yD^n2AWpy9HG^&n|@eN}7gwJ_0IyUI0P zvcBnq8s~PZbEqyxEmA0Jo6gT&OrRDZlhb;moh_N96wuI_cOWHIAtIA_-s zpOZGuO^6%f3wom3zU^7$yo2kAo|fpWo5SrTfD@JE%5~*a3;Z8Wi~99b=fuRmn}&Dm zR(MxFCmKDQp=wvzOr4}E=d{at@R@Meoz={q_(y(r++0X?D>L+Y0CIk_981nRq2$WK zsdaMZcTSDUb@ZpmmdmG3H|T|tQ8|0N?+GVi`S}%TS~jJXf?6U^Mg2U3{9MNxi1lI% zYbv&q|CieNc0RidUulc4T#m1_!&f>*{g?VI^>_y3`s9k53w=$>sdAg#X)haRZPc`! zkgC|oQc1# zWNyR^oTiytN#?^zn@4te5?Qa~8LM$}Moyrv9sOcW=%gGw`VRj0Mcxslp*63W(<^GPrp@A#aps$n4wF?ny%|=G6iIAmFwC1FnJb!>Typ4smVirc1`~IzW!4>A>&_; zh1QADqiIJ`%e~0T+X<1A(B=BT`jzzaSbdjg(H~FWv(WA;fDYDlY8;z%krvMJYJ=5; zeDZ8cDVx-|{>Mq1k4;L8biEEvUzBB`EE982NI6ZUbT+%AvNg`95-jRK1`Ih3# z6_1sKq;H{D7^rjhCQ=DB4KpO<%!tKo8C$_tv$bpk+swAHooo-=$I7_L13ZbRaJk;E zA#cK)^H#hq@4!3rZajl$@jh7fH<%COBl#FUo=@Ua_;fyt&lL~jB$M$(NnWB-W+8j> zM5#AVlzQ|;saH>wdiF#glYIa&Sv*ekaY_~0BYHx{f$SHFCn=2>o4Ly@HOnm9@~jjq-D+Spv07MdtPWNe ztA~|kNxeD>=`eF7@evf>am2@(6U@oPCz(^s>BOg*GtD`~XHzT`5ua}^G?x%xY%Vib z5HB`YnI**6P~2=JzQNpVZX>?c++pq}zRTQe?kB#FV$5WQB`nACh=;6NRx0rntBzHV zcwLIe#>5+0O|2Hhn_I1{w#3_5?X6D4J5ua+C*IA`#;yG4-i`uEy0E+Wr z#D`iVtkJ|rS!1mU#K&8ctSQ6`tZCLv;xnw-Rw41Z)_iLr@degmi%LRksa0&PBEHgE zW33~;*4kigCceqqYV9Dt-P&dCCBDbnXO$5@U<=z}hHcv+yB6^zJH@U;Jk73aHy~c$ zZe&w$+ioIfmJ)Aix3Sw3Z)bP3yAbbece68y_pmeVY~sD_9J@d9e)a%+F!6kQs6B%C zaC?+JmiQQZygiBdM7zMAMtrJ0!=6oimOa;=Pkf%ez+Oyzk-gL|CcfNWX|Ex^+FomK zAimz-WN#(D#oli3BEHk!WA7tgY9H{)m7>gN`{XLmfG^1>S7_GurTOHl%5-0SpIjB$ z(AUH#S2Q;Bwe-o=h^>9?d>x5*@OAceBi_~5!~bUhj<@fKi>f2xxRegP~t;; z!+oQOkMxc4jVC_NH_=x>e6nw+7uRL65_%N3FV?#-recx^dg?+^l|zT@9X3``NZ>_A=M z7~-Ryan3~I6P(G;RN_;d>CPSLT8CXHLSDDS>dcEzRD?a))Qan zY;?8|-|TF2b`sy=>~>0t?{)V38Syf|=?^f&@Ay4`ZQ`~3ss420b^P`G4T(4KH}*Fp z-qhd1Px;^9%HP&c`QP8(-^ow;-`~aGooYJ6pFwpR<$tQd`ucNaJ?o4^ZTki2c3I~V zG9JiyAb$n&S0H}{G6Bd0AQON*0^|`Oj{unnWFnA>KpqA1D3C{iOad|q$Rr?-0eK9_ zV?ZVYnG9qykjH^M4&-ql1waab6aaYw$P+-G0P-Y|CxJW(WIB-PK&AtE3dmDHo&quh z$P6GefczcE-+}xc$V?zJfy@N*G?1r(JPl+PkXb-x0r>}ze*pOhkl8?H1DOrvpFsWz zEV`4^CX0htSAE|9rEo&oXaxj=G(+zsSzAa?^90Av7=0YL5nau1MufaC$m1Cj@1AdrDT1_H?kk`E*w2(-ly zZ2{dbdy#|;1~M23^v4hV0o^XoL#KY6Um~E}gD7c(C}}~r2T{@nQPP5L52B{j`dvFPmB|w${c?HNTKwbf|6v$E_OM&bKvKPo+Af-S`fs_K- z2V@@*Nw>>BvNKLn@dfC1d1@CSyMXKh@->jJfqV^QH;~;xb_4ka$TvW~0kQ|k9w2*w zd<*1TAd<@6v*gOG7OWL(!`iV9tP|_Py0IRtC(B~lEQhJ{rXOc4_+9Wj7DT^Jj?&1! zw%of;?rbLaT$D5Fgmp=7Ko4f?S(8P=24r$70*!{AWZ%EMJ$=A zzn=1cq98Mb=n$N{Emxayn9*e9nI>``#5j5~9;3_BOxB~|a{O^BJ(-5pXyq%?42(@t zJAup+)Q|ZJnIMFpsT3Q)#BiJGSXwM_wPm;%%)1ys));%~&Mk0YiL-vT+L zc0I{BW;)iwIF1l6$~SPr05G&7{)U#rG_)4}h8DuKxDgupZ^cC2B;(C4eTqf?vdEc} zJ@LO%{q^s`YU*#g5OXPB)E6e;oXnI`$f5e%Ay#OSC0N~dAz@whWuME zPD>&#bD6NTs`Ml1a|C=oc-mYI1f-DkgK=k zztGs0)g1Nj3!_92V`S(t_|^ouuRYmvbX}LBTlkNW{Et&z;D>Ahdgj;jl%unh(dw>x zwz2$|9Tqdh-}M=;|F63>ghP)Vp%^3bA~ILpr}t;kWqz`E;iJN6Rzqmo3kxpIn|zzeqYW|D)xZ`OB7P z>rXDv)?Xx@IX^j_Ilo9c@BQR--up$;nf@PbpXtAB`)vNnP4%tTL;ueF zEHV}%=1=ZEx#H10Fmsy#5sAmJUZFnLBP4uzRt6EkGYfwFYVd?skNY(^BH;g_Z!0KV zgmz$mwLn&Ut=*sh%bkBGKmK?Jf5NnxX8&K(;{bhI4I^l3jj8`$YW^y(@sUC0FD#+M zFE8O_9+v;|d076-=V8S!pNG>W413NQWRTUD6$r-x^_#!$`16-5TDrnb^1|{te97IJ!30mF6{M@hN{g^nw1?u0`K>t zQ@RIMNL*O!aW1lm>&v5uY04V;n}w&Mw2QAow7&Lu^o#}a1y%>T1)c=f-g89azsHX_ zhhUFrk7|!#k79q>(%rF)8F23kT@Y0e_Z(v%ynw8Nj7WE{Juo$p?lDJdv1#Dt$Bm+A zOLor)>R(gSxR7~aj|*L`C19sN$8ZXh+U`a|mwX??K}UFb8V~@`=r|a^9+>NtD;x2N z6Wb=D^KBmg=+GI@S)6M+43%Pz*x)vt&yki zYP$rM#O$p|J%0a_5c|3(pgDpmcH;C7(e1)gB#FyF&3@4)C0z304qx;SI|eExIO>(2#WvGh;q zov_VPQh`UNo;ju%BE38`;+>1SIYcII0W+TC7_yzu8n7K-*3+IhTJO&wq0cA1+rpda z$%tUzf5=X8?u*kJ5f~Ymf*^LU_MSJQH-bYav~w6??dihEJ9C#s5r+pMe!ToaNfEC5 zeIY%34!5?c2ww^4u4V(UpChU$6}p48M4}5R7lfs)kvwgKsV0Tl@MJkF#61d*>z6?7&c=mIA8)_N1J%(eT zKpV$CNg^&+1Ic8BA$=7{hr8r z5=hG2*9+{X=9QuNE)`G9N}$n!SuXhqU!Via6eRh4s7Sh-fR0iKnkqR+E!1t9jlKl-TFQf@}c<&86%T2;Xjf(#&hNcw^qkw z)NlHaMZ|Tm_vsh#7q}K!TPFe?xt9E%28+$kA&kxxMgiUXddU zuwJj~>~q^pocB1?#kzdAH7xdJMaB(j!(c_`WMh!hC9`Pfp|P-TlS}69ruD-1?<=Z9D`sycEq zZi;H6OMF#W1iN@-`&@cAa>=-T*$|&|^?4&gB85%dc1`fERUkmoL)F>~>&=(EsQiLb zTw%vk>_V2ppu%Tknm@Gi$+_|_cp1swUuw`TO9?p#5TbnN{+`3}82DrQ_IQU=gH*pK z?CfkZI=T-yN3`_c^k#V%3Lo}rZiA`f5|yHc@kY%Tm4N%uuChtU2OGZ?p9kSH1d+E7 zLfVxO5rpS*3aWeP;_o*d%FSH&UDlJ=*6tJ!YrDPbtHoWF6+a<*SvcZmz0N%z6*QQTP;6JPzwhj7>yqPTFHhaa2SN zUXpmo-G{uIH7ajv*j018Fy9G*BBQ)asDN7LeZ0cjRv6;Spr$c}d8)Y;wA4rfiC@4{V~EqSjH|!*v|rrwB3n$6MP*>U8W7 ztxMt%#)B|FUbQt5_GWnuocIc&B}D#?SnXNU%wKWNia$r8k)d@ZwoS~;sGw1rh-ll_ z%g+BLKcBhqJ16!2qc38_exg4QD&L8_I_ABM#5U>t-1#|!o; z5MebasQy%S$Fuj3o{UfpDYBREnCup>^y!I}mw3qBKJ?mo zkFL`)8!BL;8FmUG9p`FNt1hc{x;ET$n2=AYskxf7(JLG?PT0zS{+69l zt1^D4?RhU-i8orEI%8gE{kXkb$MRNJ$uGhN+I8~8afVz@ntm@8XK!1Im+K>BB$#qZ z#mGufv5edfmWh1AxVBkjktXf#t+3fH?ry&Bd{@N% zjO=L+qEYUfLX866`ywUyAKI-Pa_%7_j{WS{Q^Ez6MR|-t%g+y#pwkO7#^i5Q>m@RXCLe#r)7t>mm zPoI9&(O+TbmhEz0IM8aA4*4Jx7rH4PKNp6^QM~XNr|)UzFmkDIOY&KB*ZK9{qb3qa ztl#Hf3r&?QpKIbJ%pMov^3FC<-Lw)f zb!eVm9ov5OnVmQ(w{&y*(J8O}$gd11_F9|5=6Ee#NvPa_^InpS5^36ZIUP0YkJ$=+ zQoKCee0eNcygz%SVse;2F~u=#|B$ltFokdx6qtdwU3K(L}1h^CGiMnAA;=Eqx4jZqmGbig$RjeIS6q2~J9j|)- zB&iBCU~qqe%C5<(ZCCQCMdp0nFg*p$d+K+8p@o222_Jt~x>)5rt@iY#)@tX?5^?1g zMYuF38_Ego@~G%%ABEWmafAhw_Xp@!n;Vp$hHp&ywu|vRa*xe-0hPv5rK$0yfM-;yTH3i#L_3o_lgx_fz z<1%Xz-k8^xhl$SHhy8vDA>O$5{Gykl2m7v_1n~+^5?o|3~wzA zAjkGWqndkfr^AfxPP_l2U+2Ev?_gj3@X(d z%2u3i=6>`tQ`zS)M$nz6j~bbgW;u`j(8h7|HB=&LvD%}W;~_Nti*jYt@@XN1H?sqM*ctG=%w3>d+@DBpTOUKW^21f4Q0#E>gtF zrS?6Eb5fr@>fqtGek1o4vnHH|1?SIhZ!pDv1R!Y=XIGuS2unyk&78)Z|N94E2ZMF);_WEjaGvz{1PJ!N+lB0tMc;Ec{T{yx9uJl4TS?~vDc^v9)Iy#@@{Ls-L~E+!b=*m1>@ZShFa zhq@^OGF+if2EK8t9cc0IT%L`PUZ=lal}GKp)>+e%aQxXBm!!kAb?sM8}{C<(Zc5k z@#}cKJX|kfLp`jChhgeUM3l(vJ9<9sK1P{pwOrKOSJiBdWSlEBvMs;=Jy78k=aT9-jaauzQntF}3cKqduZI zw1GEtc;gyavpTZQQMoBi$j8yi`08xHC75ruazf6?i)P#)T4O7b>UqydX4Z3WaRx?q z5GyCWd&<+}T7iWZcVy_wH?<8ndNYk?(|#D;64gdo&_k%+i*Y5KVPCL{Bm z4U_N`i1a26_4iAe$DRFegmJXKC-RaNwkkYvUY8IzGi|@M6?y*Cy)|*Cb=q)zUrsnG zy8SioXNVFd?P}3y&d)@O#{4?pmVcv;LUeS;P@r#gJan7}d_Jx@n`@)l=zb9m;>**| zifdIg8h<2CJ8UywnyCEVphA_5GGMo+ynwZ5i7?Ob$?2@pRG8$Wsh#pII{}OeQI7*3 zS+EJ0VmW8nY!$Vm*Qb|qIfxbPeLKo&>nTt83$AFrb%1ZTOgnQ?$Bh`G zYSqlrrt>Zqgzof5gyEBRnz>34OzWLtp;KTiHKtZSJUux47J*ipmzK4{ zu2opb=SnhCQB}{d`?Rg5P0Q~M7MN*dY!(n@j{hTh{D5Sl#c$nP&k*Q8mZejU;Y zCde9DZUM`d+`GF&bqZf-2};8q5_uiYku+oPXMNBzeREqBDz4kusn0&H+k*RaTa8|X z3@5QZVzfV1$o3tXDj3ptlb&=Ld;ai+JP$_`6E__$4pdSaH(-Dc1sMn93Gi?jT!wwt z>oKmro|*5Yib;)mVq(MJyL8$j7NH#1WC-CbLs?Kv=^|?DZsLm2n#bryb4b72cSc?Gj{f>zi>E!vZWGGUX5dY;z)3rRf~pb{BnL#^!FV0n%|z zs!R(`9e;sx9cle*op8rGwK`1k1gzTPyywbBtfLTC={867<>+JjMlxiFQDC{D(8IivI^`JANlSSJ2i1XA+5r<#g zQ+iM(Ix95&CAxVkGc5FV zA|5if$De-EJUcsA-1<7()C9(SNUW%*JBqexCfzFFk;HlM z{hxcyfcM&Javx-F<8xGM;5A=3J}0HW|GpvsrA$5)>}i9@j1Jy`i*0~ zlg~R(Ecq1t$5Y!-DKijb``(F(2}~qjs#_r^&1LdHg_vSJDH-sGqs?!t7B3E#TOB{k zs!OpruY$FpLij8b$7dXg_va1iSRSVB_Juz6#gfl9E8J=IBhXT~c|tXKy;jBkOkp|x zr%k=_4;y`ajzVJFBpM<%oQFYgo^&NYxY_)MVyAL$*!Fn%mtpzQ>0}J~{lo^4?jfE* zjpfIvTGrXQE_StJkr^cmLQv;JRkGho9u}*)+Ra*A<|2aJ(s^6Y?Hf*tNO29HsnQ<` zTBT8Y;>OWPy(=|zd)@BF<`Mj;zW){G&kdW|gc8I|)F_F>l0{u@BA)^an#AnUXkJ~p zNmhapQPCE#)x?RaS&pKop1#Aw4kHrJ>RIj8pVR4XNoc5{KIwcPuHETuPYc5fS7VxT z(GFh|dk_C2Lz4RNb@thS!J4__@uhN6&kPiOC+Cb!}N1-zQ7LYoBnS*a0XW zGcsptwg`J#gDOJQ?KQY(10q=&m2OrqjAQ1%17AO2Hz<`7(_Uzs;=+?+9)#~}Jrp8& zS{xy(oNB%28<|-BD!b$8IDgZwIyONgsf>4AEapmEwpf#)KQt{FqtI$af*=3(z^BH> zZG?n4(U@LgevXu|EG6K?^pi^nT9;-anU*w06Y^!VYy*=9uDxHAq!>70P_Ju6zjwsP zH=&uFXVIfMjZpZ@d&#&PU971fGv*(+(u0i4p`ZGC?HygIGqbST|f zDx6%S*esYS;qVi^7NudT&exYqIiG84qF3G|E;F}p( zf<77e--gDQ-Bj;#PKk6O znz1vUkIj_*fo4OKJ1er}Ez(*5eK4k_g9XIZ#nSX8?31IJEhaZNhzkV!AS#N5@?kRQ(PPq*0iRhoPvz9sS}7(!2+nT zarMIFgtZMr;$q|E>Ighp5`ZfS!{rJR;^G6eOr7K{ZLD9of&{qv|HAAFV&~xodLV0W zY7GGa#V{jMQjVS=et6@sysVAAB@amO?*bLmmzMwS0R>l6dmD2}2Wxvv03@dd&_8XE z09-@U%L$PFZ*+J4&~P(zy{r4l@fWxaeH z&$$3o=A(q;wCMZy!Lg$nMg3XDMC!;7n`F3j#msaDZkx5E3P-5?g~Y?mD{s!{TLON! zaJr336q?>t|JK(TGyh#++j4W0v++%CCSrM*AOrdHj2uzd@A>f9P(b>sE2H^lFJZay zrNq^8K(p`Vj^fElZGi9ZT9d8c0TLG+kw+o(H>Wu_y`Ph))Sq7GlTsgSIRcFgNet4*c=`?~L{N83!-JGw1ED)d{QLZZA>_OA<`B5=`D)M-^$O^Gm#Lpje3_ zwYr-24S=32&$FlwUPV^&cu0QnUlj0**t;CPy||bGEdQQKXc=U1Xk6nSWFWWWb4Fh* zPqcaPqoc#-De%yya(SUd&s1V{qe9_A3e6+gv2XY_LJzPS-__!98Yd@OCGqV)Xg^%H zjc>N2qSnlnQwi3%USYN-i7^{6`(e&!^yP~136;v(FI?>yTs8IpBQ59r8KTbHi|Mb8 zxi~?|B%cW=XGa>|baoBkTo)KG#4Ze6m4=PjEib=KIC56@+`?Lpi`x3p#g`_2Q#xnq zG;m*e{(|9V@ZOOkV24C%tXqrBost z$W^0w*Dbjc*SyI?<(U)_&1vLPz6jU^GdBcQukqr@f(40H(p}!*GmqnA42`X0U*_6T z4$%F`x;cs7G&0jPe=-9ZNI8DGhG)G0$vT!vaDkO{20Q9E>w1fxp?!4{;yImXD@cxV zY1PnPMAYnPdf%Zzcl6VbPFrhUoNpN!{iC%FEt})^P#y6YZ#?BM$|U(7OFuZhdN@(LML;@;<_7Cz~f91D21npFL&C0Ahixmnuo%X@5o1Ki~ln|mkd z2h>~|^E!D}G%AqjywoI_cYLu%2BF0m#RrVLFMh6bnJD|`cz9G6PdMuNKD&Gyb|JhJ zyC5cuc8Jfp9(Hl_olQF6tm`r}qn51x*dbrI>SWnX&`xu#qd@)egGRNyP<}%yr>(&R zDGpj=>cD(XsMMI>e0pKBpcc^QLK0@}v80<0`9mNQ%@U)Cl+b?w0sfDK_StETa!#h+~MmJVggaJ@r5w?V1$wZ6iOpc5h0E za%nK~VZ?(qZDF>}%^z<&Y}kNFlqoOt;MukJM1DjmiX)8W7Gi|Cyp<~v&(I7)^!S#Muu!38B^WtP? z?sPPr{BT1h=npS)$Ae7VsFe7kF)Q1&NcHU$;NKVMGa}K&Jdls&}2L} za7))#D0D3->`j}7+7Zp_$KM^rF0NK_<3n;oG4r|=>T!OglmkmdEL!wV&mMYW7OH3K zYUTb^*m2OD!bo)H{K}2P;xlYP`m^h+*V<^69Si!t!agcTnrKI#PXYHz_;do>oj>KcS|Ph%fKm`RoTkeW}p(= zD&3UoVb>@()@&s>d*lH5j4^1>BWBPr7yVmt_exHaVw$}~S5rBagm4J)O}!Jau4d#kzvJb^R193Mv; z>`L&opE%H0+^>jUZxbN0rn+C2UV|@ocZoC3894nU>`KN1?6c&t%j>eOe<@;1reZRx z3Q4Q=e#iH3E=l<^++f8OP|R!(?Rjtaf!sJuc0>A$595Q^f^n+pF0!9KggjF>?whw5 zc$nh2tNgZWvW8;LEMf~8(#6|ZvmgsVlYYZ_hF4xsKCm19L(#3ph0Cv&e_^VPE%vH*l^N(WdY%dpOVZR3ts^jrvl4codBVRBbcyQf!CVM5iicPOx{7HNbjoi_B z)`}wcAR+XN2j*@hRjS**XjaX3u7Di}IRJ&=>jS|3My|pcDVn1)5n{Bh z-CG7Gu?jn|6uLioH|EeQv@zEKu$hZ>R_(<64(8niFw z;9L#2(4?I!-j3$2&%XHV--nK(+-PJJ?~z7?oC9Go?usPbLOyV*ji zq~=jvnG)-d=IQyBLD$M}Mx?8z273IvZc?g(1j$`~3nf!3rPeU0*7JkZ?a8|#CDLYn z`uZIvP4r()&AVPnM&17Q4l*@}lISZ}UTCas?dCN6USm4&$>hBde-UB^GTwub9sr>t z-fVI&WHbj4N>MvgpypNG-k><)x|(Ve%EdXCzJXwdw)8{5t9ME=`_XoEepT+}DAZQv zMqIrCH(TIU?bMIh*h0w%KJ^+G{HDcR~bb5WIS;@nT$FP;I`uj$N+A zx~il?5%<=*tx7p5Uk)=+7-Qvp86W6DvRh>|A3lSaRzs^o4xGn!fH+UvVZ5P67MPrB ztWP8@LUI;mJtNdkH@WcIBtEA*4V4XqJjmGW!}QLZ z;i9Xq%<8xeysXa}NtfroMWZKoglnZ(p4xkM84R;IpJEQ3{zAP|0iv^wNg2f^Ja?Z z>NZFn*L^?su*LEf{gESjYiCKH@sIde9ACnwusqUpOyj``*IBY9|Afy%^}qHZ!Ck*= zW8W@)E!#PLw*=K_1Au$Rm=R}GGkdc|pUj;*nk@`Y`}8*&fSk*2v#A*f7qd}1#DtmH z0|nUu7qCChex(06^TEVI5vQF|jHq-{Ot#25`3rxaBM9as*2KT$q;s*wHJRK_s8_7 z>D-$pF!XAl+@8qc@DLRx5)V`j#!D>=1`Z9Xg1k3zt=b4s_SdO~Z^*rxGy6-Y8RIk= zoLM47S3fYT7xPqJ#WCkRtJk@ggE&Yv6|0z7($^zUqA{DuN#Q7GGNDB=BPW4vhk#^5 z)iH(Jtx@VXOiVc=r;TxQ=3SWg(JnMe*JOq6;Vc^>Ge^D&YarWtKx3C~i)GX{Fr5Wc z=Umu4g+hf+?Rq=eLpK;XEmW)@1*p}NTE+|Gdal;kjBt(n2!tp=M_qv(TRp~1IXSZQ z(mXvOGfqSHGAeQWeEC?pR_XHWlhM%3yKCs^ARrddu$px}#y&&mB(`CJx0gtyXDgjD z|5A0YX)VFy*|DQ-bQ1Q72&MZ^9y;DL%P#t}oT8M`#uOCJHPc3K*2qH)%JHZwUnb&- zdf$biF_B)o-0|HivtLE*M^W0y9OHgHQTOI~GZ^nwQ9xDw&epFJ)fXxf%St<*|jrV>T3&k^( zj!w{zIs7!(eWMy&J7ZmB4n$yimGgjm!@4f&kdDPHQVfT(l~RL>!)HSbVyfwvukLpe zj?XHU(@yEu)7R?>a(Mc7^+ZT?P}ETnj=F%Nhi4LDMT%qvyy zDjZnHFof|HbcUyxd=I~2)#=2dSF+pb04s|sD7c|aZL!W=!MR4pl zEO^hBqXHMWUp3x`de)~;de{{d9*UKpxvL$G%*=gHdyz2wa$Tf@qoW`IIDUr7m%9rI zp)S(hoRhw|P41QL5o{f^EGF1<&G0JSFWxJ|wwN(u0~X-Wi(_&9wm!EEFNbnEaOa}c z*+FPZF?3dL7ftB?27lk^kRX_&LAfKG(;Wrca$4)2FG%gh!yf zW|jD-Mi|rKf-j}hUHFNZ$E|LK-!&V(1-@lW;B;%#b1HR?;~YVpV6SNLc=K6X*hzNt z=5>)Akui(cgNvJvj+4lEy|26@{U2{~WPd{f2~Lnm`GBM3#glhhw=GtAWeF3BeMKSy zoy@cbYhOciE^U2{pg226OY`d}NB}nS^QXX3a^f<%wwot*(ZsN0!F)fpTC$p zFN`F8pZ63rbe56@X+ZmRGuOi$aml(%?qU0ON-f=}Up94(T2-hLdf%?*)z`OFlX4C6 zu`$~B&l(4l9gO)nh^FOz2}N7CqJi<{ZwWP<;Gee?jF#zGm-axmnbMV5TGUyScbyRy z_@b%wXxbsd{w)+b`T+<^Gho$7{YACAaocesr8S--(fhNWT-t*{)98yyd9~rE--b%S z$#8FGbZZ-#bK>N}8z(Z=ke23>v#9$bg5_An3zZk18LX`NG7Mo(>Q3lbzgzC9m zP_pkmw%nvFSvd}42l3ACmJTDn9UWO=ojzD>E3nFl!@m4G*^Vv`?m{Tv!4r|PE zN_=vL=BH=bcwSHiVLPc$p>MTelsza=1x^5V<- zDN`zL(^?(uE{FH=_CWtEbMyBKTjB<1guUXiCwm05Z`}LrNoNW3aDi2%mZo#_RQd~J z(X(~zz)+iBtv-huJR|kR8k$5PRDVzg!bv6B!oEI%idASwG`C9OC{_*b9NC!Y5Jlz2lzgh7mbqSKRzj z-)Y_iB(lNX<9w~l>vGX7LCrDL;IAbIE9cSnd$kgB#9oof#Kab(IeyPE>I?4yl>qW$ z*a^s9)$sv3YtQm!w<84O@TFrU}sHV8BGp(0? zFamcx^|E!v0*qtD3{dCA^R2BnLu##R7zdYUPfoQ=lAhGsz5KB{o|d-=bWq@{4YgTY z-$~r>u66#)lIBdJlP3CS332{siVq;d;mx5|6Eu*kzv)qo&R8MvLL4cuAmRV_MZ zys#$kQ@Vya(31p+t*uwhSS{|MSh}h}E={~+d#2{Tl=twuI)C2Mi5lZSm^)C|*G-Er z2U=6z)9HLE=I3gy1tl-3cu)J~c%i6SVaHu7pwMXP2aQ*+O@cb^G+#)#tj1Ns>uEl(`t9mpRu~L>E+G9 zxl1OvR%GzG8CHI5EnD^fz_ogRY_ocg7-ib(64*H*vzugj0 zL!6HzL`I8+3Cs-z{}R})^Ov3wtJ%VMg;wW}bZ5Yc3nNPYT;Oz^kTcz(3{miuL9~pT zA;!3?FH2A!aRimlKgRIYd5SMup$-D7EjY&}GlC?4qb?lcC^{j(-g2j0I>ezt*kd7l z8w(X>393lhS(CqhLowl~JNT-0==bOSd;bk!_M2bfpvOyR>Z%2U0o7~Nr3;)7tsXhZ zZEbX-G(i=OI~?YB>c47O9R3H~SzUL^-t;oROj~2MOsPMT^EK+zg+}$@h3ABnF^{KW zNL81OXgSjv#4Fa2J!MH`Kib2qX%#sG<>=H--x{#}E~PEKC1|qjLD;VnbyAsvH*P>_ zgBB$pxLvd99JYK@+RE5T8|4zhco@iS5r*7UB#$q8hz^FiXQGJ_XHWkqop<4=V!eJK zbN;bmOAz6C>4(RuN-NJWKFro^vB}&Gpnm_4{~4gxBCY+>Ae|z7s`01i|J%E!IE20F zBW=_r9K4gjyv0TQ-rT#Po7+FffHf{RUfI8@WHhReI@0k~v?te1XGfW!sMQ zr(Yn!#8-gp+`*-l_;&;I!nsY{OTXST18%>gM}{))@l+5!^+74{1KM|TybwcP$(#an z3aIYq6fSIJj6`Q?kxJ)>aq@gDg8zzX;P-aj;mEy_OusrkBACi(JRuEo41b06{+er4 zKM>Q@#edpeIBEGes8hkz-57)k#|7f_cChhw4D`-h;_16F4>6*@7!oy*zL}aQKF_ZE zc@KrMo&&w&3F4d<9XbaoVGyiKAuc$+6R4r)C<%>_R$7m$KeN%P9t9N^iqdWka;Sza z)Ia`-`LpUB=3UPR6noPLT*3!VFw9SXd1aF*iADV&OvpT2h$-Ci<=GFXNkmP5M#u5` zOB*dp?r)0@1zMhnZVysJOx6%NmgA)!b&VT)M^pgahjNstAA+l~xk9r-2&II{r>^TV zPI1Ghd6#6ZT2kbyXM6y6iUQ)@_Jcbw!PBo{3j{QnWQLKO&K%#7^NYkY8=WXahK?$R zndY~=6Eh+*C9~#NMsvT0bktHpS>|tulm%NsjOCjuI*mYJUyhEIF0g!}RGG+Z)k3t3 zj}EPS`XXgCjs|G5CXe+=o0ilsXJ_0*cSCw)A!bZUp^R=uzt>n#TC0{>J|%$t7Gkoj zdy2$=pc!l?4J?>)3Eit*(UNSoLxmTo?_(^co#R?%tQKQL1;jTlM!i^_;y^v6 zD^SwPUV7>yduY_93d}pnVXfH&Wjr=3Pao*^EApBPDuBN)u#GB} ziW7;-N;QUOIucUj!#p#HbjjqJlL4s3sJNqs`S;v%}c)S5wj! zW~b2$-GqdcJ(NpCYp2oBda+>IP&rS!+ECR*FKGs=IrKEp)38Q1<9A60LoRh6>RK(|X8w(&fEUO+1ifu<}KxoMLVxsvdPz zrK3VpdLJd3>P5Qp-4|Qjv<5jTk)2wwg65T61^xM}dTa|bj*x|JJ$%X@%LO7UvS?@$ zYA|iqV^6x#K-EOF#|&!-=#ic+`|_0cGPs_qGRSVA$nhF`(mfqw4F41h<#ugLQdOXY zep-gg)V0wOIJ6P;kWfOMjxd&oEX=Nw1eg0)zMq3LxP+A$WJ6J`b3tBo!u^clv+tqh z25kgc#FWt4Lk!v?i%rXJ)JXKgeR+#G)dy#EM9b;HV6;e4!m|}3S^A!i{OpCd;+Rn~ z^anC#Z=SzT{Iu{E2Q#Vz`}ZpXF&^$rM#0L)Zdw8{anq&!G5A z>x)FPrrjM(;S0+f;r%kEbr#RVUlI9zlSh_g1N@UCOt60H{>Wo zj_M#ie|3Pu!`%!lclXdKp_~iQ4$@Y-1C+K^T)usI-yqcoCLp3^tl-)_uULlWR>pA7 zXedy-Y@?k8<=n?u#;Z~{J`dmzNV1s4-wtS!7}(+dPgD4gIdtuV|7eHk$i&C~_Pq`ET+qi8`K-CWEqAs}v8<1o^eqbtB1f^nbV^d&V@Ys-H?ykjE$ zMK=1wE8^zj;rj=#2uABtaIgWWWoj;t<{Fl+AS)XO3zt7Ffy@9_m;oZoe)#{L(- zj2+PVTjH*h02V-l8x96WnSwZ(np?V`MBU}W>)4e zOaZbQAPok@xwv>>T3lS*@HZYAc#a!h_XPgNd-ulsr;rbx1kb@0cqHLDxB`z9JO@|ck%s5s3V$H+!WDSnka*z=JV0Lo@VsyZFuV`E@IHXy zaCzYhU^rY}xB?gsmk+K0h6Ch-i-6$(`QRd8I6yvlkHBz%d~gLY93UTD0SpJo2Uh^Y z0rJ5Wz;J+ka0M_NAm1Msz)kc2feSay{|7GIG(Q{*FWfZ$pW%R;=7%fr!cFtT75+Gj zAFlAnS^RK?KhENZEBtX5{~s)HXYv0T4!E=U|A2=(i~kRJI9z_X!XMZ1!xjFxP5`d( z$5{gK9{q8az@Gtt0~CPw=#R4m{tO2kpunHufP)YK3W4DM6UDGFht0!CK=3!_r+X zFNlv9UIv)uyF&mN0@7VApae(HCkO(P5P*kI2$o=0_yOo}^!zaBce?z7ARxi8@B>1C zD9jSjJPZWz#tln%Wk44JY_M7Y2;7qbydWUmmGOZDU~quiyTk+Z1Ly#d?mhu-1loYv z1G*@5S0=~>f+e8mg50nK(-j05vhX$pfnoqTtc(wqV521nWPpwWRs;oL2{x93fb-z! z1%*IBg4GJ~z!L0}(O*1O7!em91ne-6!1%g%t^r8Be+$8=wlE<;;xD~_(p#k+-GI#t z;Q1=rSirW%yG;wW@%_D7LH@a0{jmn45W_Yy$Y1*&TwK}|VEZ~+|5E`*UH)r(lXP=^ z0q~ERlqFTPK+3A}k}AxwE!fi3)yC052DVEw$q4gs@$hni!N5Wf=HupN<>F%mb1?#P z%8nNQFA-pSv~UCV8K4Cla~DU5qm`>LNDW|6yMi;Iz*^?;w1;>y|Dyw*E|yl9Tp(^f98B281%H9~`S`$mAS-woHy4+X z5a2l23*_*385rpMKg$3qZXV#2@n2=I3^1GjT?SbHuQH$wK_J@xT_(i+FFBY1Fhl+= z2L|TFf0Y4Pcz{^^?=nFlULY3#T_*Hzdw?z%FfaZ~jvLsQf%W1)Wv(u!05{y_jv9Z* uXXpNl!|vz^#2XM4z|ly<#v7nw|2gWIy13r?8nDCz=EtO`f1)aj`F{X3bEq}| literal 0 HcmV?d00001 diff --git a/onix-gui/app/api/check-layer2/route.js b/onix-gui/app/api/check-layer2/route.js new file mode 100644 index 0000000..1fb27cf --- /dev/null +++ b/onix-gui/app/api/check-layer2/route.js @@ -0,0 +1,66 @@ +import { exec } from "child_process"; +import { NextResponse } from "next/server"; + +export async function POST(req) { + const request = await req.json(); + const containerName = request.checked ? "bpp-network" : "bap-network"; + const fileToCheck = request.fileName; + + const executeShellCommand = (command) => { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + console.error("Error:", error); + reject(error); + return; + } + if (stderr) { + console.error("Error:", stderr); + reject(new Error(stderr)); + return; + } + const output = stdout; + console.log("Output:", output); + resolve(output); + }); + }); + }; + + try { + const containerExists = await executeShellCommand( + `docker ps -a --filter "name=${containerName}" --format "{{.Names}}"` + ); + if (!containerExists.trim()) { + return new NextResponse(`Error: ${containerName} server not present`, { + status: 500, + }); + } + + const result = await executeShellCommand( + `docker exec ${containerName} /bin/sh -c "[ -f '/usr/src/app/schemas/${fileToCheck}' ] && echo 'File found' || echo 'File not found'"` + ); + if (result.trim() === "File found") { + return NextResponse.json( + { message: true }, + { + status: 200, + } + ); + } else { + return NextResponse.json( + { message: false }, + { + status: 200, + } + ); + } + } catch (error) { + console.error(`exec error: ${error}`); + return NextResponse.json( + { message: `Error executing shell command: ${error}` }, + { + status: 500, + } + ); + } +} diff --git a/onix-gui/app/api/clonning-repo/route.js b/onix-gui/app/api/clonning-repo/route.js new file mode 100644 index 0000000..e8c0225 --- /dev/null +++ b/onix-gui/app/api/clonning-repo/route.js @@ -0,0 +1,36 @@ +import { spawn } from "child_process"; +import { NextResponse } from "next/server"; +import os from "os"; +import path from "path"; +// This function is used to clone the github repository of beckn-onix +export async function GET(req) { + console.log("Cloning GitHub repository..."); + const repoUrl = "https://github.com/beckn/beckn-onix"; + const destination = path.join(os.homedir(), "beckn-onix"); + const gitProcess = spawn("git", ["clone", repoUrl, destination]); + + gitProcess.stdout.on("data", (data) => { + console.log(`stdout: ${data}`); + }); + + gitProcess.stderr.on("data", (data) => { + console.error(`stderr: ${data}`); + }); + + return new Promise((resolve, reject) => { + gitProcess.on("close", (code) => {const destination = "~/beckn-onix"; + if (code === 0) { + console.log("Repository cloned successfully"); + resolve( + NextResponse.json( + { success: true, data: "Repo Cloned Successfully" }, + { status: 200 } + ) + ); + } else { + console.error(`git process exited with code ${code}`); + resolve(NextResponse.json({ success: false }, { status: 500 })); + } + }); + }); +} diff --git a/onix-gui/app/api/install-bap/route.js b/onix-gui/app/api/install-bap/route.js new file mode 100644 index 0000000..2c5fb04 --- /dev/null +++ b/onix-gui/app/api/install-bap/route.js @@ -0,0 +1,116 @@ +import { exec } from "child_process"; +import { NextResponse } from "next/server"; +import { promises as fs } from "fs"; +import { join } from "path"; +import os from "os"; + +const pathDir = join(os.homedir(), "beckn-onix"); + +const executeCommand = (command) => { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + console.error("Error:", error); + reject(error); + return; + } + const output = stdout + stderr; + console.log("Output:", output); + resolve(output); + }); + }); +}; + +async function directoryExists(path) { + try { + await fs.access(path); + return true; + } catch (error) { + return false; + } +} +export async function startSupportServices() { + try { + process.env.COMPOSE_IGNORE_ORPHANS = "1"; + + const result1 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d mongo_db` + ); + console.log("Result 1:", result1); + + const result2 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d queue_service` + ); + console.log("Result 2:", result2); + + const result3 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d redis_db` + ); + console.log("Result 3:", result3); + await executeCommand("docker volume create registry_data_volume"); + await executeCommand("docker volume create registry_database_volume"); + await executeCommand("docker volume create gateway_data_volume"); + await executeCommand("docker volume create gateway_database_volume"); + return NextResponse.json({ result1, result2, result3 }); + } catch (error) { + console.error("An error occurred:", error); + return NextResponse.json({ error: "An error occurred" }, { status: 500 }); + } +} + +export async function POST(req) { + const becknOnixDirExists = await directoryExists(pathDir); + + if (!becknOnixDirExists) { + console.log(`Directory "${pathDir}" does not exist. Cloning repository...`); + try { + const response = await fetch(`${req.nextUrl.origin}/api/clonning-repo`); + if (!response.ok) { + console.error( + `Failed to clone repository: ${response.status} ${response.statusText}` + ); + return NextResponse.json( + { + error: `Failed to clone repository: ${response.status} ${response.statusText}`, + }, + { status: 500 } + ); + } + console.log("Repository cloned successfully."); + } catch (error) { + console.error("An error occurred while cloning the repository:", error); + return NextResponse.json( + { error: "An error occurred while cloning the repository" }, + { status: 500 } + ); + } + } + + try { + await startSupportServices(); + const data = await req.json(); + + const registryUrl = data.registryUrl; + const bppSubscriberId = data.subscriberId; + const bppSubscriberUrl = data.subscriberUrl; + const networkconfigurl = data.networkconfigurl; + + let updateBppConfigCommand = `bash ${pathDir}/install/scripts/update_bap_config.sh ${registryUrl} ${bppSubscriberId} ${bppSubscriberUrl} ${networkconfigurl}`; + const result1 = await executeCommand(updateBppConfigCommand); + console.log("Result 1:", result1); + const result3 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-v2.yml up -d "bap-client"` + ); + console.log("Result 3:", result3); + + const result4 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-v2.yml up -d "bap-network"` + ); + console.log("Result 4:", result4); + + return NextResponse.json({ result1, result3, result4 }); + } catch (error) { + console.error("An error occurred:", error); + return NextResponse.json({ error: "An error occurred" }, { status: 500 }); + } +} diff --git a/onix-gui/app/api/install-bpp/route.js b/onix-gui/app/api/install-bpp/route.js new file mode 100644 index 0000000..2ac5ca0 --- /dev/null +++ b/onix-gui/app/api/install-bpp/route.js @@ -0,0 +1,128 @@ +import { exec } from "child_process"; +import { NextResponse } from "next/server"; +import { promises as fs } from "fs"; +import { join } from "path"; +import os from "os"; + +const pathDir = join(os.homedir(), "beckn-onix"); +async function directoryExists(path) { + try { + await fs.access(path); + return true; + } catch (error) { + return false; + } +} + +const executeCommand = (command) => { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + console.error("Error:", error); + reject(error); + return; + } + const output = stdout + stderr; + console.log("Output:", output); + resolve(output); + }); + }); +}; + +export async function startSupportServices() { + try { + process.env.COMPOSE_IGNORE_ORPHANS = "1"; + + const result1 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d mongo_db` + ); + console.log("Result 1:", result1); + + const result2 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d queue_service` + ); + console.log("Result 2:", result2); + + const result3 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d redis_db` + ); + console.log("Result 3:", result3); + await executeCommand("docker volume create registry_data_volume"); + await executeCommand("docker volume create registry_database_volume"); + await executeCommand("docker volume create gateway_data_volume"); + await executeCommand("docker volume create gateway_database_volume"); + return NextResponse.json({ result1, result2, result3 }); + } catch (error) { + console.error("An error occurred:", error); + return NextResponse.json({ error: "An error occurred" }, { status: 500 }); + } +} + +export async function POST(req, res) { + const becknOnixDirExists = await directoryExists(pathDir); + console.log("Installing Beckn Onix...", becknOnixDirExists); + + if (!becknOnixDirExists) { + console.log(`Directory beckn-onix does not exist. Cloning repository...`); + try { + const response = await fetch(`${req.nextUrl.origin}/api/clonning-repo`); + if (!response.ok) { + console.error( + `Failed to clone repository: ${response.status} ${response.statusText}` + ); + return NextResponse.json( + { + error: `Failed to clone repository: ${response.status} ${response.statusText}`, + }, + { status: 500 } + ); + } + console.log("Repository cloned successfully."); + } catch (error) { + console.error("An error occurred while cloning the repository:", error); + return NextResponse.json( + { error: "An error occurred while cloning the repository" }, + { status: 500 } + ); + } + } + + try { + await startSupportServices(); + const data = req.json(); + const registryUrl = data.registryUrl; + const bppSubscriberId = data.subscriberId; + const bppSubscriberUrl = data.subscriberUrl; + const webhookUrl = data.webhookUrl; + // const webhookUrl = "https://unified-bpp.becknprotocol.io/beckn-bpp-adapter"; + + // let updateBppConfigCommand = "bash scripts/update_bpp_config.sh"; + // if (registryUrl) { + // updateBppConfigCommand += ``; + // } + let updateBppConfigCommand = `bash ${pathDir}/install/scripts/update_bpp_config.sh ${registryUrl} ${bppSubscriberId} ${bppSubscriberUrl} ${webhookUrl}`; + const result1 = await executeCommand(updateBppConfigCommand); + console.log("Result 1:", result1); + + const result2 = await executeCommand("sleep 10"); + console.log("Result 2:", result2); + + const result3 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-v2.yml up -d bpp-client` + ); + console.log("Result 3:", result3); + + const result4 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-v2.yml up -d bpp-network` + ); + console.log("Result 4:", result4); + + const result5 = await executeCommand("sleep 10"); + console.log("Result 5:", result5); + + return NextResponse.json({ result1, result2, result3, result4, result5 }); + } catch (error) { + console.error("An error occurred:", error); + return NextResponse.json({ error: "An error occurred" }, { status: 500 }); + } +} diff --git a/onix-gui/app/api/install-gateway/route.js b/onix-gui/app/api/install-gateway/route.js new file mode 100644 index 0000000..3545f6e --- /dev/null +++ b/onix-gui/app/api/install-gateway/route.js @@ -0,0 +1,92 @@ +import { exec } from "child_process"; +import { NextResponse } from "next/server"; +import { promises as fs } from "fs"; +import { join } from "path"; +import os from "os"; + +async function directoryExists(path) { + try { + await fs.access(path); + return true; + } catch (error) { + return false; + } +} + +export async function POST(req, res) { + const pathDir = join(os.homedir(), "beckn-onix"); + const becknOnixDirExists = await directoryExists(pathDir); + console.log("Installing Beckn Onix...", becknOnixDirExists); + + if (!becknOnixDirExists) { + console.log(`Directory beckn-onix does not exist. Cloning repository...`); + try { + const response = await fetch(`${req.nextUrl.origin}/api/clonning-repo`); + if (!response.ok) { + console.error( + `Failed to clone repository: ${response.status} ${response.statusText}` + ); + return NextResponse.json( + { + error: `Failed to clone repository: ${response.status} ${response.statusText}`, + }, + { status: 500 } + ); + } + console.log("Repository cloned successfully."); + } catch (error) { + console.error("An error occurred while cloning the repository:", error); + return NextResponse.json( + { error: "An error occurred while cloning the repository" }, + { status: 500 } + ); + } + } + + const data = await req.json(); + const executeCommand = (command) => { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + console.error("Error:", error); + reject(error); + return; + } + const output = stdout + stderr; + console.log("Output:", output); + resolve(output); + }); + }); + }; + + try { + const result1 = await executeCommand( + `bash ${pathDir}/install/scripts/package_manager.sh` + ); + console.log("Result 1:", result1); + await executeCommand("docker volume create registry_data_volume"); + await executeCommand("docker volume create registry_database_volume"); + const result2 = await executeCommand( + ` bash ${pathDir}/install/scripts/update_gateway_details.sh ${data.registryUrl} ${data.gatewayUrl}` + ); + console.log("Result 2:", result2); + + const result3 = await executeCommand( + `docker-compose -f ${pathDir}/install/docker-compose-v2.yml up -d gateway` + ); + console.log("Result 3:", result3); + + const result4 = await executeCommand(`sleep 2`); + console.log("Result 4:", result4); + + const result5 = await executeCommand( + `bash ${pathDir}/install/scripts/register_gateway.sh ${data.gatewayUrl}` + ); + console.log("Result 5:", result5); + + return NextResponse.json({ result1, result2, result3, result4, result5 }); + } catch (error) { + console.error("An error occurred:", error); + return NextResponse.json({ error: "An error occurred" }, { status: 500 }); + } +} diff --git a/onix-gui/app/api/install-layer2/route.js b/onix-gui/app/api/install-layer2/route.js new file mode 100644 index 0000000..c795226 --- /dev/null +++ b/onix-gui/app/api/install-layer2/route.js @@ -0,0 +1,38 @@ +import { exec } from "child_process"; +import { NextResponse } from "next/server"; + +export async function POST(req) { + const request = await req.json(); + const fileURL = request.yamlUrl; + const containerName = request.container; + + const executeShellCommand = (command) => { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + console.error("Error:", error); + reject(error); + return; + } + if (stderr) { + console.error("Error:", stderr); + reject(new Error(stderr)); + return; + } + const output = stdout; + console.log("Output:", output); + resolve(output); + }); + }); + }; + + try { + await executeShellCommand( + `docker exec ${containerName} wget -P /usr/src/app/schemas/ ${fileURL}` + ); + return NextResponse.json({ status: 200 }); + } catch (error) { + console.error(`exec error: ${error}`); + return NextResponse.json({ status: 500 }); + } +} diff --git a/onix-gui/app/api/install-registry/route.js b/onix-gui/app/api/install-registry/route.js new file mode 100644 index 0000000..70c4102 --- /dev/null +++ b/onix-gui/app/api/install-registry/route.js @@ -0,0 +1,156 @@ +import { exec } from "child_process"; +import { NextResponse } from "next/server"; +import { promises as fs } from "fs"; +import { tmpdir } from "os"; +import { join } from "path"; +import os from "os"; + +async function directoryExists(path) { + try { + await fs.access(path); + return true; + } catch (error) { + return false; + } +} + +export async function POST(req, res) { + const pathDir = join(os.homedir(), "beckn-onix"); + const becknOnixDirExists = await directoryExists(pathDir); + console.log("Installing Beckn Onix...", becknOnixDirExists); + + if (!becknOnixDirExists) { + console.log(`Directory beckn-onix does not exist. Cloning repository...`); + try { + const response = await fetch(`${req.nextUrl.origin}/api/clonning-repo`); + if (!response.ok) { + console.error( + `Failed to clone repository: ${response.status} ${response.statusText}` + ); + return NextResponse.json( + { + error: `Failed to clone repository: ${response.status} ${response.statusText}`, + }, + { status: 500 } + ); + } + console.log("Repository cloned successfully."); + } catch (error) { + console.error("An error occurred while cloning the repository:", error); + return NextResponse.json( + { error: "An error occurred while cloning the repository" }, + { status: 500 } + ); + } + } + + const data = await req.json(); + const executeCommand = (command) => { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + console.error("Error:", error); + reject(error); + return; + } + const output = stdout + stderr; + console.log("Output:", output); + resolve(output); + }); + }); + }; + const updateRegistryDetails = async (url) => { + let registryUrl = ""; + let registryPort = ""; + let protocol = ""; + + if (url) { + if (url.startsWith("https://")) { + registryUrl = url.replace("https://", ""); + registryPort = "443"; + protocol = "https"; + } else if (url.startsWith("http://")) { + registryUrl = url.replace("http://", ""); + registryPort = "80"; + protocol = "http"; + } + } else { + registryUrl = "registry"; + registryPort = "3030"; + protocol = "http"; + } + + console.log("Registry URL:", registryUrl); + + const configFile = join( + pathDir, + "install", + "registry_data", + "config", + "swf.properties" + ); + const sampleFile = join( + pathDir, + "install", + "registry_data", + "config", + "swf.properties-sample" + ); + + try { + await fs.copyFile(sampleFile, configFile); + const tempDir = join(os.homedir(), "beckn-onix", "tmp"); + await fs.mkdir(tempDir, { recursive: true }); // Create the temporary directory if it doesn't exist + + const tempFile = join(tempDir, "tempfile.XXXXXXXXXX"); + const configData = await fs.readFile(configFile, "utf8"); + const updatedConfigData = configData + .replace(/REGISTRY_URL/g, registryUrl) + .replace(/REGISTRY_PORT/g, registryPort) + .replace(/PROTOCOL/g, protocol); + + await fs.writeFile(tempFile, updatedConfigData); + await fs.rename(tempFile, configFile); + await executeCommand("docker volume create registry_data_volume"); + await executeCommand("docker volume create registry_database_volume"); + await executeCommand("docker volume create gateway_data_volume"); + await executeCommand("docker volume create gateway_database_volume"); + await executeCommand( + `docker run --rm -v ${join( + pathDir, + "install", + "registry_data", + "config" + )}:/source -v registry_data_volume:/target busybox sh -c "cp /source/envvars /target/ && cp /source/logger.properties /target/ && cp /source/swf.properties /target/"` + ); + + // Start the registry container + await executeCommand( + `docker-compose -f ${join( + pathDir, + "install", + "docker-compose-v2.yml" + )} up -d registry` + ); + + // Wait for 10 seconds + await new Promise((resolve) => setTimeout(resolve, 10000)); + + console.log("Registry installation successful"); + } catch (error) { + console.error("Error updating registry details:", error); + throw error; + } + }; + + try { + const url = data.registryUrl; + await updateRegistryDetails(url); + return NextResponse.json({ + message: "Registry details updated successfully", + }); + } catch (error) { + console.error("An error occurred:", error); + return NextResponse.json({ error: "An error occurred" }, { status: 500 }); + } +} diff --git a/onix-gui/app/favicon.ico b/onix-gui/app/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..718d6fea4835ec2d246af9800eddb7ffb276240c GIT binary patch literal 25931 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 LrJugUA?W`A8`#=m literal 0 HcmV?d00001 diff --git a/onix-gui/app/globals.css b/onix-gui/app/globals.css new file mode 100644 index 0000000..d0e8c4c --- /dev/null +++ b/onix-gui/app/globals.css @@ -0,0 +1,19 @@ +* { + padding: 0; + margin: 0; +} + +body{ + min-width: 100vw; + min-height: 100vh; + background-color: #000000; + color: white; + font-family: "Ubuntu Mono", monospace; + + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + +} diff --git a/onix-gui/app/install/configure/page.js b/onix-gui/app/install/configure/page.js new file mode 100644 index 0000000..4da2300 --- /dev/null +++ b/onix-gui/app/install/configure/page.js @@ -0,0 +1,58 @@ +"use client"; + +import Link from "next/link"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import Image from "next/image"; +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + return ( + <> +

+
+ +

Configure Existing Network

+
+ +
+ arrow +

Gateway

+
+ + +
+ arrow +

BAP Adapter

+
+ + +
+ arrow +

BPP Adapter

+
+ +
+
+
+ + ); +} diff --git a/onix-gui/app/install/create/page.js b/onix-gui/app/install/create/page.js new file mode 100644 index 0000000..0cf9db7 --- /dev/null +++ b/onix-gui/app/install/create/page.js @@ -0,0 +1,67 @@ +"use client"; + +import Link from "next/link"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import Image from "next/image"; +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + return ( + <> +
+
+ +

Create a Production Network

+
+ +
+ arrow +

Gateway

+
+ + +
+ arrow +

BAP Adapter

+
+ + +
+ arrow +

BPP Adapter

+
+ + +
+ arrow +

Registry

+
+ +
+
+
+ + ); +} diff --git a/onix-gui/app/install/join/page.js b/onix-gui/app/install/join/page.js new file mode 100644 index 0000000..619e14b --- /dev/null +++ b/onix-gui/app/install/join/page.js @@ -0,0 +1,68 @@ +"use client"; + +import Link from "next/link"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import Image from "next/image"; +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + return ( + <> +
+
+ +

Join an existing network

+ +
+ +
+ arrow +

Gateway

+
+ + +
+ arrow +

BAP Adapter

+
+ + +
+ arrow +

BPP Adapter

+
+ +
+
+
+ + ); +} diff --git a/onix-gui/app/install/local/page.js b/onix-gui/app/install/local/page.js new file mode 100644 index 0000000..7dbd607 --- /dev/null +++ b/onix-gui/app/install/local/page.js @@ -0,0 +1,60 @@ +"use client"; + +import Link from "next/link"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import Image from "next/image"; +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + return ( + <> +
+
+ +

+ Set up a network on your local machine +

+
+ +
+ arrow +

Gateway

+
+ + +
+ arrow +

BAP Adapter

+
+ + +
+ arrow +

BPP Adapter

+
+ +
+
+
+ + ); +} diff --git a/onix-gui/app/install/merge/page.js b/onix-gui/app/install/merge/page.js new file mode 100644 index 0000000..7391660 --- /dev/null +++ b/onix-gui/app/install/merge/page.js @@ -0,0 +1,58 @@ +"use client"; + +import Link from "next/link"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import Image from "next/image"; +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + return ( + <> +
+
+ +

Merge multiple networks

+
+ +
+ arrow +

Gateway

+
+ + +
+ arrow +

BAP

+
+ + +
+ arrow +

BPP

+
+ +
+
+
+ + ); +} diff --git a/onix-gui/app/install/page.js b/onix-gui/app/install/page.js new file mode 100644 index 0000000..a196231 --- /dev/null +++ b/onix-gui/app/install/page.js @@ -0,0 +1,54 @@ +"use client"; + +import Link from "next/link"; +import styles from "../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import Image from "next/image"; +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + return ( + <> +
+
+ +

ONIX

+

+ Open Network In A Box, is a project designed to effortlessly set up + and maintain Beckn network that is scalable, secure and easy to + maintain. +

+
+ +
+ arrow +

Join an existing network

+
+ + +
+ arrow +

Create new production network

+
+ +
+
+
+ + ); +} diff --git a/onix-gui/app/layout.js b/onix-gui/app/layout.js new file mode 100644 index 0000000..e461a93 --- /dev/null +++ b/onix-gui/app/layout.js @@ -0,0 +1,22 @@ +import { Inter } from "next/font/google"; +import "./globals.css"; +import { ToastContainer, toast } from "react-toastify"; +import "react-toastify/dist/ReactToastify.css"; +import { Bounce } from "react-toastify"; +const inter = Inter({ subsets: ["latin"] }); + +export const metadata = { + title: "ONIX GUI", + description: "Generated by create next app", +}; + +export default function RootLayout({ children }) { + return ( + + + {children} + + + + ); +} diff --git a/onix-gui/app/page.js b/onix-gui/app/page.js new file mode 100644 index 0000000..600fc62 --- /dev/null +++ b/onix-gui/app/page.js @@ -0,0 +1,55 @@ +import Link from "next/link"; +import styles from "./page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import Image from "next/image"; +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + return ( + <> +
+
+

ONIX

+

+ Open Network In A Box, is a project designed to effortlessly set up + and maintain Beckn network that is scalable, secure and easy to + maintain. +

+
+ +
+ arrow +

Installation Wizard

+
+ + {/* +
+ arrow +

Network Monitor

+
+ */} + +
+ arrow +

Layer 2 Tester

+
+ +
+
+
+ + ); +} diff --git a/onix-gui/app/page.module.css b/onix-gui/app/page.module.css new file mode 100644 index 0000000..1947e56 --- /dev/null +++ b/onix-gui/app/page.module.css @@ -0,0 +1,182 @@ +.mainHeading { + font-size: 5rem; + margin-bottom: 1rem; + text-align: center; +} + +.mainText { + font-size: 1.5rem; + max-width: 55rem; + text-align: center; + margin: auto; + margin-bottom: 1rem; +} + +.boxesContainer { + margin-top: 2rem; + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + + flex-wrap: wrap; +} + +.secondBoxesContainer { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + flex-wrap: wrap; +} + +.box { + position: relative; + + width: 15rem; + height: 15rem; + border: 1px solid rgb(61, 61, 61); + + display: flex; + flex-direction: column; + justify-content: flex-end; + align-self: center; + text-align: center; + + font-size: 1.25rem; + padding: 1rem; +} + +.box p { + max-width: 12rem; + margin: 0 auto; +} + +.box img { + width: 2rem; + position: absolute; + + top: 1rem; + right: 1rem; +} + +.smallbox { + position: relative; + + width: 12rem; + height: 12rem; + border: 1px solid rgb(61, 61, 61); + + display: flex; + flex-direction: column; + justify-content: flex-end; + align-self: center; + text-align: center; + + font-size: 1.25rem; + padding: 1rem; +} + +.smallbox p { + max-width: 12rem; + margin: 0 auto; +} + +.smallbox img { + width: 2rem; + position: absolute; + + top: 1rem; + right: 1rem; +} + + +.formContainer { + padding: 1rem; + border: 1px solid rgb(61, 61, 61); + border-radius: 30px; +} + +.buttonsContainer { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + column-gap: 0.5rem; + margin-top: 1rem; + margin-bottom: 1rem; +} + +.currentRoute { + margin-bottom: 6rem; + font-family: "Ubuntu Mono", monospace; + font-size: 1.25rem; + font-weight: 600; + + text-align: center; +} + +.backButton { + position: absolute; + top: 1rem; + left: 1rem; + font-size: 1.25rem; + padding: 0.5rem; + border: 1px solid rgb(61, 61, 61); + background-color: transparent; + color: white; + cursor: pointer; +} + +.dashboard { + margin-bottom: 2rem; +} + +.dashboardHeading { + font-size: 2rem; + margin-bottom: 1rem; + text-align: center; +} + +.dashboardTable { + width: 100%; + border-collapse: collapse; + font-size: 1.25rem; + font-family: "Ubuntu Mono", monospace; + border: 1px solid rgb(61, 61, 61); +} + +.dashboardTable th, +.dashboardTable td { + padding: 1rem; + text-align: left; + border-bottom: 1px solid rgb(61, 61, 61); +} + +.dashboardTable th { + font-weight: 600; +} + +@media screen and (max-width: 600px) { + .dashboardTable { + font-size: 1rem; + } + + .dashboardTable th, + .dashboardTable td { + padding: 0.5rem; + } +} + +.counts { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + margin-top: 1rem; + margin-bottom: 2rem; +} + +.count { + max-width: 10rem; +} \ No newline at end of file diff --git a/onix-gui/app/setup/bap/page.js b/onix-gui/app/setup/bap/page.js new file mode 100644 index 0000000..2613e6e --- /dev/null +++ b/onix-gui/app/setup/bap/page.js @@ -0,0 +1,132 @@ +"use client"; + +import InputField from "@/components/InputField/InputField"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import SecondaryButton from "@/components/Buttons/SecondaryButton"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import { useState, useCallback } from "react"; +import { toast } from "react-toastify"; + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + const [subscriberUrl, setSubscriberUrl] = useState(""); + const [subscriberId, setSubscriberId] = useState(""); + const [registryUrl, setRegistryUrl] = useState(""); + const [buttonDisable, setButtonDisable] = useState(false); + const [networkconfigurl, setNetworkconfigurl] = useState(""); + + const handleSubscriberUrlChange = (event) => { + setSubscriberUrl(event.target.value); + }; + + const handleSubscriberIdChange = (event) => { + setSubscriberId(event.target.value); + }; + + const handleRegistryUrlChange = (event) => { + setRegistryUrl(event.target.value); + }; + + const handleNetworkconfigurlChange = (event) => { + setNetworkconfigurl(event.target.value); + }; + const installBap = useCallback(async () => { + const toastId = toast.loading("Installing BAP..."); + setButtonDisable(true); + try { + const response = await fetch("/api/install-bap", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + subscriberUrl, + subscriberId, + registryUrl, + networkconfigurl, + }), + }); + + if (response.ok) { + console.log("BPP installed successfully"); + toast.update(toastId, { + render: "BPP installed successfully 👌", + type: "success", + isLoading: false, + autoClose: 5000, + }); + } else { + console.error("Failed to install BAP"); + toast.update(toastId, { + render: "Failed to install BAP 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + } catch (error) { + console.error("An error occurred:", error); + toast.update(toastId, { + render: "Bap installation done", + type: "success", + isLoading: false, + autoClose: 5000, + }); + } + setButtonDisable(false); + }, [subscriberUrl, subscriberId, registryUrl, networkconfigurl]); + + return ( + <> +
+
+ +

BAP

+
+ + + + + + +
+ {/* */} + +
+
+
+
+ + ); +} diff --git a/onix-gui/app/setup/bpp/page.js b/onix-gui/app/setup/bpp/page.js new file mode 100644 index 0000000..3d37d00 --- /dev/null +++ b/onix-gui/app/setup/bpp/page.js @@ -0,0 +1,146 @@ +"use client"; + +import InputField from "@/components/InputField/InputField"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import SecondaryButton from "@/components/Buttons/SecondaryButton"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import { useState, useCallback } from "react"; +import { toast } from "react-toastify"; + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + const [subscriberUrl, setSubscriberUrl] = useState(""); + const [subscriberId, setSubscriberId] = useState(""); + const [registryUrl, setRegistryUrl] = useState(""); + const [networkconfigurl, setNetworkconfigurl] = useState(""); + const [webhookUrl, setWebhookUrl] = useState(""); + const [buttonDisable, setButtonDisable] = useState(false); + const handleSubscriberUrlChange = (event) => { + setSubscriberUrl(event.target.value); + }; + + const handleSubscriberIdChange = (event) => { + setSubscriberId(event.target.value); + }; + + const handleRegistryUrlChange = (event) => { + setRegistryUrl(event.target.value); + }; + const handleNetworkconfigurlChange = (event) => { + setNetworkconfigurl(event.target.value); + }; + const handleWebhookUrlChange = (event) => { + setWebhookUrl(event.target.value); + }; + + const installBpp = useCallback(async () => { + const toastId = toast.loading("Installing BPP..."); + setButtonDisable(true); + try { + const response = await toast.promise( + fetch("/api/install-bpp", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + subscriberUrl: subscriberUrl, + subscriberId: subscriberId, + registryUrl: registryUrl, + networkconfigurl: networkconfigurl, + webhookUrl: webhookUrl, + }), + }), + { + success: "BPP installed successfully 👌", + error: "Failed to install BPP 🤯", + } + ); + + if (response.ok) { + console.log("BPP installed successfully"); + toast.update(toastId, { + render: "BPP installed successfully 👌", + type: "success", + isLoading: false, + autoClose: 5000, + }); + } else { + console.error("Failed to install BPP"); + toast.update(toastId, { + render: "Failed to install BPP 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + } catch (error) { + console.error("An error occurred:", error); + toast.update(toastId, { + render: "An error occurred while installing BPP 😥", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + setButtonDisable(false); + }, [subscriberUrl, subscriberId, registryUrl, networkconfigurl, webhookUrl]); + return ( + <> +
+
+ +

BPP

+
+ + + + + + + +
+ {/* */} + +
+
+
+
+ + ); +} diff --git a/onix-gui/app/setup/gateway/page.js b/onix-gui/app/setup/gateway/page.js new file mode 100644 index 0000000..41be273 --- /dev/null +++ b/onix-gui/app/setup/gateway/page.js @@ -0,0 +1,126 @@ +"use client"; + +import InputField from "@/components/InputField/InputField"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import { useState, useCallback } from "react"; +import SecondaryButton from "@/components/Buttons/SecondaryButton"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import { usePathname } from "next/navigation"; +import { toast } from "react-toastify"; + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + let pathname = usePathname(); + const [gatewayUrl, setGatewayUrl] = useState(""); + const [registryUrl, setRegistryUrl] = useState(""); + const [networkconfigurl, setNetworkconfigurl] = useState(""); + + const handleGatewayUrlChange = (event) => { + setGatewayUrl(event.target.value); + }; + const handleRegistryUrlChange = (event) => { + setRegistryUrl(event.target.value); + }; + const handleNetworkconfigurlChange = (event) => { + setNetworkconfigurl(event.target.value); + }; + + const installGateway = useCallback(async () => { + const toastId = toast.loading("Installing gateway..."); + + try { + const response = await toast.promise( + fetch("/api/install-gateway", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + gatewayUrl: gatewayUrl, + registryUrl: registryUrl, + networkconfigurl: networkconfigurl, + }), + }), + { + success: "gateway installed successfully 👌", + error: "Failed to install BAP 🤯", + } + ); + + if (response.ok) { + console.log("Gateway installed successfully"); + toast.update(toastId, { + render: "Gateway installed successfully 👌", + type: "success", + isLoading: false, + autoClose: 5000, + }); + } else { + console.error("Failed to install gateway"); + toast.update(toastId, { + render: "Failed to install gateway 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + } catch (error) { + console.error("An error occurred:", error); + toast.update(toastId, { + render: "An error occurred while installing the gateway 😥", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + }, [gatewayUrl, registryUrl, networkconfigurl]); + return ( + <> +
+
+ +

Gateway

+
+ {/* To do todo + 1. Create a check function so that the url formats are correct + 2. Send response when installing and also erros that happen when an envet happens to the user + 3. a gear dialog where the user's can specify to where the beckn repo to be cloned. + */} + + + + + +
+ {/* */} + +
+
+
+
+ + ); +} diff --git a/onix-gui/app/setup/registry/page.js b/onix-gui/app/setup/registry/page.js new file mode 100644 index 0000000..6fce954 --- /dev/null +++ b/onix-gui/app/setup/registry/page.js @@ -0,0 +1,96 @@ +"use client"; +import SecondaryButton from "@/components/Buttons/SecondaryButton"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import InputField from "@/components/InputField/InputField"; +import { useState, useCallback } from "react"; +import { toast } from "react-toastify"; + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + const [registryUrl, setRegistryUrl] = useState(""); + + const handleRegistryUrlChange = (event) => { + setRegistryUrl(event.target.value); + }; + + const installRegistry = useCallback(async () => { + const toastId = toast.loading("Installing registry..."); + + try { + const response = await toast.promise( + fetch("/api/install-registry", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ registryUrl: registryUrl }), + }), + { + success: "registry installed successfully 👌", + error: "Failed to install registry 🤯", + } + ); + console.log("console.log of response", response); + + if (response.ok) { + console.log("Repository cloned successfully"); + toast.update(toastId, { + render: "Registry installed successfully 👌", + type: "success", + isLoading: false, + autoClose: 5000, + }); + } else { + console.error("Failed to clone repository"); + toast.update(toastId, { + render: "Failed to install registry 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + } catch (error) { + console.error("An error occurred:", error); + toast.update(toastId, { + render: "An error occurred while installing the registry 😥", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + }, [registryUrl]); + + return ( + <> +
+
+ +

Registry

+
+ +
+ {/* */} + +
+
+
+
+ + ); +} diff --git a/onix-gui/app/template.csv b/onix-gui/app/template.csv new file mode 100644 index 0000000..d9ea810 --- /dev/null +++ b/onix-gui/app/template.csv @@ -0,0 +1 @@ +name,email,phone_number,district,category,organization,customfile,checkbox_field,date_field,datetime_field,time_field,number_field,rating_field diff --git a/onix-gui/app/yaml-gen/install-yaml/page.js b/onix-gui/app/yaml-gen/install-yaml/page.js new file mode 100644 index 0000000..22ad80c --- /dev/null +++ b/onix-gui/app/yaml-gen/install-yaml/page.js @@ -0,0 +1,105 @@ +"use client"; +import SecondaryButton from "@/components/Buttons/SecondaryButton"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import Slider from "@/components/Slider/Slider"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import InputField from "@/components/InputField/InputField"; +import { useState, useCallback } from "react"; +import { toast } from "react-toastify"; + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function InstallYaml() { + const [yamlUrl, setYamlUrl] = useState(""); + const [checked, setChecked] = useState(false); + + const container = checked ? "bpp-network" : "bap-network"; + + const handleRegistryUrlChange = (event) => { + setYamlUrl(event.target.value); + }; + + const installYaml = useCallback(async () => { + const toastId = toast.loading("Installing Layer 2 Config file..."); + + try { + const response = await fetch("/api/install-layer2", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ container, yamlUrl }), + }); + + if (response.ok) { + const data = await response.json(); + console.log(data); + const FileFound = data.message; + if (FileFound == false) { + setShowDownloadLayer2Button(true); + toast.update(toastId, { + render: "No Layer 2 Config Present 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } else { + toast.update(toastId, { + render: "Yaml File Present 👌", + type: "success", + isLoading: false, + autoClose: 5000, + }); + } + } else { + console.error("Failed to check yaml"); + toast.update(toastId, { + render: "Container Not Found 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + } catch (error) { + console.error("An error occurred:", error); + } + }); + + return ( + <> +
+
+ +

Install Yaml

+
+ + +
+ {/* */} + +
+
+
+
+ + ); +} diff --git a/onix-gui/app/yaml-gen/page.js b/onix-gui/app/yaml-gen/page.js new file mode 100644 index 0000000..b80f556 --- /dev/null +++ b/onix-gui/app/yaml-gen/page.js @@ -0,0 +1,183 @@ +"use client"; +import { useState } from "react"; +import { Ubuntu_Mono } from "next/font/google"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import InputField from "@/components/InputField/InputField"; +import Slider from "@/components/Slider/Slider"; +import styles from "../page.module.css"; +import { toast } from "react-toastify"; + +import Link from "next/link"; + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function CheckYaml() { + const [domainName, setDomainName] = useState(""); + const [versionNumber, setversionNumber] = useState(""); + const [checked, setChecked] = useState(false); + const [showDownloadLayer2Button, setShowDownloadLayer2Button] = + useState(false); + const [propertyLink, setPropertyLink] = useState(""); + + const handleYamlChange = (event) => { + setPropertyLink(event.target.value); + }; + const handledomainNameChange = (event) => { + setDomainName(event.target.value); + }; + const handleVersionChange = (event) => { + setversionNumber(event.target.value); + }; + const nameGenerator = async () => { + const parts = domainName.split(":"); + const domainNameWithoutVersion = parts[0]; + const domainVersion = parts[1] || ""; + const filename = `${domainNameWithoutVersion}_${domainVersion}_${versionNumber}.yaml`; + return filename; + }; + const handleDownload = async () => { + const userInput = prompt("Enter the URL of the Layer 2 Config file"); + try { + const response = await fetch("/api/install-layer2", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ checked, userInput }), + }); + + if (response.ok) { + const data = await response.json(); + console.log(data); + const FileFound = data.message; + if (FileFound == false) { + setShowDownloadLayer2Button(true); + toast.update(toastId, { + render: "No Layer 2 Config Present 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } else { + toast.update(toastId, { + render: "Yaml File Present 👌", + type: "success", + isLoading: false, + autoClose: 5000, + }); + } + } else { + console.error("Failed to check yaml"); + toast.update(toastId, { + render: "Container Not Found 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + } catch (error) { + console.error("An error occurred:", error); + } + }; + + const handleOnclick = async () => { + const fileName = await nameGenerator(); + const toastId = toast.loading("Checking for layer2 yaml file"); + try { + const response = await fetch("/api/check-layer2", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ checked, fileName }), + }); + + if (response.ok) { + const data = await response.json(); + const FileFound = data.message; + if (FileFound == false) { + setShowDownloadLayer2Button(true); + toast.update(toastId, { + render: "No Layer 2 Config Present 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } else { + toast.update(toastId, { + render: "Yaml File Present 👌", + type: "success", + isLoading: false, + autoClose: 5000, + }); + } + } else { + console.error("Failed to check yaml"); + toast.update(toastId, { + render: "Container Not Found 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + } catch (error) { + console.error("An error occurred:", error); + } + }; + return ( + <> +
+ + +
+

+ Yaml File Checker +

+ +
+ + + + + +
+ +
+ {showDownloadLayer2Button && ( + + )} +
+
+
+ + ); +} diff --git a/onix-gui/components/Buttons/Buttons.module.css b/onix-gui/components/Buttons/Buttons.module.css new file mode 100644 index 0000000..64f7a6a --- /dev/null +++ b/onix-gui/components/Buttons/Buttons.module.css @@ -0,0 +1,24 @@ +.primaryButton { + background-color: #abd4fa; + color: #000000; + padding: 0.5rem 1rem; + border-radius: 10px; + border: none; + font-size: 1rem; + cursor: pointer; + + padding: 0.75rem 2rem; +} + +.secondaryButton { + background-color: #000000; + color: #abd4fa; + padding: 0.5rem 1rem; + border-radius: 10px; + border: none; + font-size: 1rem; + cursor: pointer; + + border: 1px solid #abd4fa; + padding: 0.75rem 2.25rem; +} diff --git a/onix-gui/components/Buttons/PrimaryButton.js b/onix-gui/components/Buttons/PrimaryButton.js new file mode 100644 index 0000000..57a18c5 --- /dev/null +++ b/onix-gui/components/Buttons/PrimaryButton.js @@ -0,0 +1,16 @@ +import React from "react"; +import styles from "./Buttons.module.css"; + +const PrimaryButton = ({ label = "continue", onClick, disabled = false }) => { + return ( + + ); +}; + +export default PrimaryButton; diff --git a/onix-gui/components/Buttons/SecondaryButton.jsx b/onix-gui/components/Buttons/SecondaryButton.jsx new file mode 100644 index 0000000..97a3564 --- /dev/null +++ b/onix-gui/components/Buttons/SecondaryButton.jsx @@ -0,0 +1,8 @@ +import React from "react"; +import styles from "./Buttons.module.css"; + +const SecondaryButton = () => { + return ; +}; + +export default SecondaryButton; diff --git a/onix-gui/components/InputField/InputField.jsx b/onix-gui/components/InputField/InputField.jsx new file mode 100644 index 0000000..aac6551 --- /dev/null +++ b/onix-gui/components/InputField/InputField.jsx @@ -0,0 +1,19 @@ +import React from "react"; +import styles from "./InputField.module.css"; + +const InputField = ({ label, value, onChange, placeholder = "Input Text" }) => { + return ( +
+ + +
+ ); +}; + +export default InputField; diff --git a/onix-gui/components/InputField/InputField.module.css b/onix-gui/components/InputField/InputField.module.css new file mode 100644 index 0000000..e3c2efc --- /dev/null +++ b/onix-gui/components/InputField/InputField.module.css @@ -0,0 +1,23 @@ +.inputContainer { + display: flex; + flex-direction: column; + margin: 1.5rem 1rem; +} + +.inputLabel { + font-size: 1rem; + font-weight: bold; + margin-bottom: 0.5rem; +} + +.inputField { + padding: 1rem; + font-family: "Ubuntu Mono", sans-serif; + color: white; + font-size: 1rem; + border-radius: 15px; + border: 1px solid rgb(61, 61, 61); + background: #000000; + + min-width:15rem +} diff --git a/onix-gui/components/Slider/Slider.jsx b/onix-gui/components/Slider/Slider.jsx new file mode 100644 index 0000000..5c03937 --- /dev/null +++ b/onix-gui/components/Slider/Slider.jsx @@ -0,0 +1,20 @@ +import React from "react"; +import styles from "./Slider.module.css"; + +const Slider = ({ label, checked, toggleChecked }) => { + return ( +
+ + +
+ ); +}; + +export default Slider; diff --git a/onix-gui/components/Slider/Slider.module.css b/onix-gui/components/Slider/Slider.module.css new file mode 100644 index 0000000..749e1c3 --- /dev/null +++ b/onix-gui/components/Slider/Slider.module.css @@ -0,0 +1,67 @@ +.switch { + transform: scale(0.75); + position: relative; + display: inline-block; + width: 60px; + height: 34px; +} + +.inputContainer { + display: flex; + + align-items: center; + justify-content: space-around; +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: white; + -webkit-transition: .4s; + transition: .4s; +} + +.slider:before { + position: absolute; + content: ""; + height: 26px; + width: 26px; + left: 4px; + bottom: 4px; + background-color: black; + -webkit-transition: .4s; + transition: .4s; +} + +input:checked+.slider { + background-color: #9dc5e6; +} + +input:focus+.slider { + box-shadow: 0 0 1px white; +} + +input:checked+.slider:before { + -webkit-transform: translateX(26px); + -ms-transform: translateX(26px); + transform: translateX(26px); +} + +/* Rounded sliders */ +.slider.round { + border-radius: 34px; +} + +.slider.round:before { + border-radius: 50%; +} \ No newline at end of file diff --git a/onix-gui/jsconfig.json b/onix-gui/jsconfig.json new file mode 100644 index 0000000..2a2e4b3 --- /dev/null +++ b/onix-gui/jsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "paths": { + "@/*": ["./*"] + } + } +} diff --git a/onix-gui/next.config.mjs b/onix-gui/next.config.mjs new file mode 100644 index 0000000..4678774 --- /dev/null +++ b/onix-gui/next.config.mjs @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {}; + +export default nextConfig; diff --git a/onix-gui/package-lock.json b/onix-gui/package-lock.json new file mode 100644 index 0000000..6714052 --- /dev/null +++ b/onix-gui/package-lock.json @@ -0,0 +1,4247 @@ +{ + "name": "onix-gui", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "onix-gui", + "version": "0.1.0", + "dependencies": { + "child_process": "^1.0.2", + "next": "14.1.4", + "react": "^18", + "react-dom": "^18", + "react-toastify": "^10.0.5" + }, + "devDependencies": { + "eslint": "^8", + "eslint-config-next": "14.1.4" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.1.tgz", + "integrity": "sha512-+BIznRzyqBf+2wCTxcKE3wDjfGeCoVE61KSHGpkzqrLi8qxqFwBeUFyId2cxkTmm55fzDGnm0+yCxaxygrLUnQ==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@next/env": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.1.4.tgz", + "integrity": "sha512-e7X7bbn3Z6DWnDi75UWn+REgAbLEqxI8Tq2pkFOFAMpWAWApz/YCUhtWMWn410h8Q2fYiYL7Yg5OlxMOCfFjJQ==" + }, + "node_modules/@next/eslint-plugin-next": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.1.4.tgz", + "integrity": "sha512-n4zYNLSyCo0Ln5b7qxqQeQ34OZKXwgbdcx6kmkQbywr+0k6M3Vinft0T72R6CDAcDrne2IAgSud4uWCzFgc5HA==", + "dev": true, + "dependencies": { + "glob": "10.3.10" + } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.1.4.tgz", + "integrity": "sha512-ubmUkbmW65nIAOmoxT1IROZdmmJMmdYvXIe8211send9ZYJu+SqxSnJM4TrPj9wmL6g9Atvj0S/2cFmMSS99jg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.1.4.tgz", + "integrity": "sha512-b0Xo1ELj3u7IkZWAKcJPJEhBop117U78l70nfoQGo4xUSvv0PJSTaV4U9xQBLvZlnjsYkc8RwQN1HoH/oQmLlQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.1.4.tgz", + "integrity": "sha512-457G0hcLrdYA/u1O2XkRMsDKId5VKe3uKPvrKVOyuARa6nXrdhJOOYU9hkKKyQTMru1B8qEP78IAhf/1XnVqKA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.1.4.tgz", + "integrity": "sha512-l/kMG+z6MB+fKA9KdtyprkTQ1ihlJcBh66cf0HvqGP+rXBbOXX0dpJatjZbHeunvEHoBBS69GYQG5ry78JMy3g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.1.4.tgz", + "integrity": "sha512-BapIFZ3ZRnvQ1uWbmqEGJuPT9cgLwvKtxhK/L2t4QYO7l+/DxXuIGjvp1x8rvfa/x1FFSsipERZK70pewbtJtw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.1.4.tgz", + "integrity": "sha512-mqVxTwk4XuBl49qn2A5UmzFImoL1iLm0KQQwtdRJRKl21ylQwwGCxJtIYo2rbfkZHoSKlh/YgztY0qH3wG1xIg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.1.4.tgz", + "integrity": "sha512-xzxF4ErcumXjO2Pvg/wVGrtr9QQJLk3IyQX1ddAC/fi6/5jZCZ9xpuL9Tzc4KPWMFq8GGWFVDMshZOdHGdkvag==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-ia32-msvc": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.1.4.tgz", + "integrity": "sha512-WZiz8OdbkpRw6/IU/lredZWKKZopUMhcI2F+XiMAcPja0uZYdMTZQRoQ0WZcvinn9xZAidimE7tN9W5v9Yyfyw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.1.4.tgz", + "integrity": "sha512-4Rto21sPfw555sZ/XNLqfxDUNeLhNYGO2dlPqsnuCg8N8a2a9u1ltqBOPQ4vj1Gf7eJC0W2hHG2eYUHuiXgY2w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rushstack/eslint-patch": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.9.0.tgz", + "integrity": "sha512-AAWymnpvHbGty1BmgbdfbqQDboXs6xN6h2yAacO4yKVyyUUBnpYkp+P9jjPrV9zrAGw7JVVriRtGOHPInnfjZQ==", + "dev": true + }, + "node_modules/@swc/helpers": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.2.tgz", + "integrity": "sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==", + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "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/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", + "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.findlast": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", + "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", + "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.toreversed": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz", + "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + } + }, + "node_modules/array.prototype.tosorted": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz", + "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.1.0", + "es-shim-unscopables": "^1.0.2" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axe-core": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz", + "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", + "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==", + "dev": true, + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001600", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", + "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/child_process": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/child_process/-/child_process-1.0.2.tgz", + "integrity": "sha512-Wmza/JzL0SiWz7kl6MhIKT5ceIlnFPJX+lwUGj7Clhy5MMldsSoJR0+uvRzOS5Kv45Mq7t1PoE8TsOA9bzvb6g==" + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==" + }, + "node_modules/clsx": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.0.tgz", + "integrity": "sha512-m3iNNWpd9rl3jvvcBnu70ylMdrXt8Vlq4HYadnU5fwcOtvkSQWPmj7amUcDT2qYI7risszBjI5AUIUox9D16pg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, + "node_modules/data-view-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", + "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", + "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", + "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/enhanced-resolve": { + "version": "5.16.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", + "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-abstract": { + "version": "1.23.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.2.tgz", + "integrity": "sha512-60s3Xv2T2p1ICykc7c+DNDPLDMm9t4QxCOUU0K9JxiLjM3C1zB9YVdN7tjxrFd4+AkZ8CdX1ovUga4P2+1e+/w==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "arraybuffer.prototype.slice": "^1.0.3", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "data-view-buffer": "^1.0.1", + "data-view-byte-length": "^1.0.1", + "data-view-byte-offset": "^1.0.0", + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "es-set-tostringtag": "^2.0.3", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.4", + "get-symbol-description": "^1.0.2", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "hasown": "^2.0.2", + "internal-slot": "^1.0.7", + "is-array-buffer": "^3.0.4", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.1", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.3", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.13", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.5", + "regexp.prototype.flags": "^1.5.2", + "safe-array-concat": "^1.1.2", + "safe-regex-test": "^1.0.3", + "string.prototype.trim": "^1.2.9", + "string.prototype.trimend": "^1.0.8", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.2", + "typed-array-byte-length": "^1.0.1", + "typed-array-byte-offset": "^1.0.2", + "typed-array-length": "^1.0.5", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.15" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-iterator-helpers": { + "version": "1.0.18", + "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz", + "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-errors": "^1.3.0", + "es-set-tostringtag": "^2.0.3", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.0.3", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "iterator.prototype": "^1.1.2", + "safe-array-concat": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", + "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", + "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.4", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "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/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-next": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.1.4.tgz", + "integrity": "sha512-cihIahbhYAWwXJwZkAaRPpUi5t9aOi/HdfWXOjZeUOqNWXHD8X22kd1KG58Dc3MVaRx3HoR/oMGk2ltcrqDn8g==", + "dev": true, + "dependencies": { + "@next/eslint-plugin-next": "14.1.4", + "@rushstack/eslint-patch": "^1.3.3", + "@typescript-eslint/parser": "^5.4.2 || ^6.0.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-import-resolver-typescript": "^3.5.2", + "eslint-plugin-import": "^2.28.1", + "eslint-plugin-jsx-a11y": "^6.7.1", + "eslint-plugin-react": "^7.33.2", + "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705" + }, + "peerDependencies": { + "eslint": "^7.23.0 || ^8.0.0", + "typescript": ">=3.3.1" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-import-resolver-typescript": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz", + "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "enhanced-resolve": "^5.12.0", + "eslint-module-utils": "^2.7.4", + "fast-glob": "^3.3.1", + "get-tsconfig": "^4.5.0", + "is-core-module": "^2.11.0", + "is-glob": "^4.0.3" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts" + }, + "peerDependencies": { + "eslint": "*", + "eslint-plugin-import": "*" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", + "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz", + "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.23.2", + "aria-query": "^5.3.0", + "array-includes": "^3.1.7", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "=4.7.0", + "axobject-query": "^3.2.1", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.15", + "hasown": "^2.0.0", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react": { + "version": "7.34.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", + "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlast": "^1.2.4", + "array.prototype.flatmap": "^1.3.2", + "array.prototype.toreversed": "^1.1.2", + "array.prototype.tosorted": "^1.1.3", + "doctrine": "^2.1.0", + "es-iterator-helpers": "^1.0.17", + "estraverse": "^5.3.0", + "jsx-ast-utils": "^2.4.1 || ^3.0.0", + "minimatch": "^3.1.2", + "object.entries": "^1.1.7", + "object.fromentries": "^2.0.7", + "object.hasown": "^1.1.3", + "object.values": "^1.1.7", + "prop-types": "^15.8.1", + "resolve": "^2.0.0-next.5", + "semver": "^6.3.1", + "string.prototype.matchall": "^4.0.10" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8" + } + }, + "node_modules/eslint-plugin-react-hooks": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz", + "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" + } + }, + "node_modules/eslint-plugin-react/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-react/node_modules/resolve": { + "version": "2.0.0-next.5", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz", + "integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/eslint-plugin-react/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dev": true, + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "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", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-async-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz", + "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-data-view": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", + "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "dev": true, + "dependencies": { + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finalizationregistry": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz", + "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz", + "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", + "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "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.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz", + "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/iterator.prototype": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz", + "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "get-intrinsic": "^1.2.1", + "has-symbols": "^1.0.3", + "reflect.getprototypeof": "^1.0.4", + "set-function-name": "^2.0.1" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsx-ast-utils": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", + "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.6", + "array.prototype.flat": "^1.3.1", + "object.assign": "^4.1.4", + "object.values": "^1.1.6" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/language-subtag-registry": { + "version": "0.3.22", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz", + "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/next": { + "version": "14.1.4", + "resolved": "https://registry.npmjs.org/next/-/next-14.1.4.tgz", + "integrity": "sha512-1WTaXeSrUwlz/XcnhGTY7+8eiaFvdet5z9u3V2jb+Ek1vFo0VhHKSAIJvDWfQpttWjnyw14kBeq28TPq7bTeEQ==", + "dependencies": { + "@next/env": "14.1.4", + "@swc/helpers": "0.5.2", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "graceful-fs": "^4.2.11", + "postcss": "8.4.31", + "styled-jsx": "5.1.1" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": ">=18.17.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "14.1.4", + "@next/swc-darwin-x64": "14.1.4", + "@next/swc-linux-arm64-gnu": "14.1.4", + "@next/swc-linux-arm64-musl": "14.1.4", + "@next/swc-linux-x64-gnu": "14.1.4", + "@next/swc-linux-x64-musl": "14.1.4", + "@next/swc-win32-arm64-msvc": "14.1.4", + "@next/swc-win32-ia32-msvc": "14.1.4", + "@next/swc-win32-x64-msvc": "14.1.4" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.entries": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz", + "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", + "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", + "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.hasown": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz", + "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==", + "dev": true, + "dependencies": { + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.values": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", + "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-scurry": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", + "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", + "dev": true, + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "dev": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "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" + } + ] + }, + "node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", + "integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.0" + }, + "peerDependencies": { + "react": "^18.2.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "dev": true + }, + "node_modules/react-toastify": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-10.0.5.tgz", + "integrity": "sha512-mNKt2jBXJg4O7pSdbNUfDdTsK9FIdikfsIE/yUCxbAEXl4HMyJaivrVFcn3Elvt5xvCQYhUZm+hqTIu1UXM3Pw==", + "dependencies": { + "clsx": "^2.1.0" + }, + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" + } + }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz", + "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.1", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "globalthis": "^1.0.3", + "which-builtin-type": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", + "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "set-function-name": "^2.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "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" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", + "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "get-intrinsic": "^1.2.4", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scheduler": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz", + "integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/source-map-js": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz", + "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/string.prototype.matchall": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", + "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-symbols": "^1.0.3", + "internal-slot": "^1.0.7", + "regexp.prototype.flags": "^1.5.2", + "set-function-name": "^2.0.2", + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", + "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", + "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/styled-jsx": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz", + "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==", + "dependencies": { + "client-only": "0.0.1" + }, + "engines": { + "node": ">= 12.0.0" + }, + "peerDependencies": { + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", + "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", + "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", + "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", + "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-proto": "^1.0.3", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typescript": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "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-builtin-type": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz", + "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==", + "dev": true, + "dependencies": { + "function.prototype.name": "^1.1.5", + "has-tostringtag": "^1.0.0", + "is-async-function": "^2.0.0", + "is-date-object": "^1.0.5", + "is-finalizationregistry": "^1.0.2", + "is-generator-function": "^1.0.10", + "is-regex": "^1.1.4", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", + "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "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-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/onix-gui/package.json b/onix-gui/package.json new file mode 100644 index 0000000..38899c1 --- /dev/null +++ b/onix-gui/package.json @@ -0,0 +1,22 @@ +{ + "name": "onix-gui", + "version": "0.1.0", + "private": true, + "scripts": { + "dev": "next dev", + "build": "next build", + "start": "next start", + "lint": "next lint" + }, + "dependencies": { + "child_process": "^1.0.2", + "next": "14.1.4", + "react": "^18", + "react-dom": "^18", + "react-toastify": "^10.0.5" + }, + "devDependencies": { + "eslint": "^8", + "eslint-config-next": "14.1.4" + } +} diff --git a/onix-gui/public/arrow.png b/onix-gui/public/arrow.png new file mode 100644 index 0000000000000000000000000000000000000000..7151c6858502a3d1f64538a7b62aecb4c1ca5980 GIT binary patch literal 261 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoM!3HGxw}u@9Qk(@Ik;M!Q+`=Ht$S`Y;1W=H% zILO_JVcj{Imp~3nx}&cn1H;CC?mvmFK>jRG7srqa#;xaX^EN2(v_70=!JxdOQ`@3R z`2~v=m-3E@ixpJtCbVT&{}6V1(Ae)M@^sGazuSbiO_oTK-Itp7N?7O8)}N^vA^)z2 zX9+nSW#D#~C}?kA$ie>4T4oZ{0uR0hMOB8TD-5QWm{v>(bLjcPptMB%g`0|lxDx9u zLEZ~38I4*^3|$;tCzL!CntXU#4tKK@Wl6kW;8+{Ew{yazv)Uy /dev/null 2>&1 & + +# Wait for the Next.js app to start +echo "Waiting for Next.js app to start on port $PORT..." +until nc -z localhost "$PORT"; do + sleep 1 + echo "Loding ..." +done + +# Install the tunnel service if not installed + + + +echo "Exposing local port $PORT using $TUNNEL_SERVICE..." +lt --port "$PORT" > /tmp/lt.log 2>&1 & + +# Wait for the tunnel service to start +echo "Waiting for tunnel service to start..." +sleep 5 + +# Get the tunnel URL from the log file +TUNNEL_URL=$(grep -o 'https://[^[:blank:]]*' /tmp/lt.log) +#Get the tunnel password +echo "Getting Tunnel Password" +TUNNEL_PASSWORD=$(curl https://loca.lt/mytunnelpassword)&& + +# Print the tunnel URL and password +echo "---------------------------------------" +echo "Next.js app is running locally on port $PORT" +echo "Tunnel Service URL: $TUNNEL_URL" +echo "Tunnel Password: $TUNNEL_PASSWORD" +echo "---------------------------------------" From 10cba84a0353aaf4c42dd83f896a64383f123d18 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Thu, 2 May 2024 21:44:17 +0530 Subject: [PATCH 050/102] added the GUI --- onix-gui/app/api/install-layer2/route.js | 38 ---- onix-gui/app/yaml-gen/page.js | 183 ------------------ onix-gui/{ => onix}/.eslintrc.json | 0 onix-gui/{ => onix}/.gitignore | 0 onix-gui/{ => onix}/README.md | 21 +- onix-gui/{ => onix}/app/Infy_Pending.pdf | Bin .../{ => onix}/app/api/check-layer2/route.js | 36 ++-- .../{ => onix}/app/api/clonning-repo/route.js | 0 .../app/api/get-network-participant/route.js | 27 +++ .../{ => onix}/app/api/install-bap/route.js | 7 +- .../{ => onix}/app/api/install-bpp/route.js | 5 +- .../app/api/install-gateway/route.js | 5 +- .../app/api/install-registry/route.js | 14 -- onix-gui/{ => onix}/app/favicon.ico | Bin onix-gui/{ => onix}/app/globals.css | 0 .../{ => onix}/app/install/configure/page.js | 8 +- .../{ => onix}/app/install/create/page.js | 10 +- onix-gui/{ => onix}/app/install/join/page.js | 8 +- onix-gui/{ => onix}/app/install/local/page.js | 8 +- onix-gui/{ => onix}/app/install/merge/page.js | 15 +- onix-gui/{ => onix}/app/install/page.js | 35 +++- onix-gui/{ => onix}/app/layout.js | 0 onix-gui/onix/app/monitor/dashboard/page.js | 95 +++++++++ onix-gui/onix/app/monitor/page.js | 74 +++++++ onix-gui/{ => onix}/app/page.js | 14 +- onix-gui/{ => onix}/app/page.module.css | 0 onix-gui/{ => onix}/app/setup/bap/page.js | 2 +- onix-gui/{ => onix}/app/setup/bpp/page.js | 2 +- onix-gui/{ => onix}/app/setup/gateway/page.js | 2 +- .../{ => onix}/app/setup/registry/page.js | 2 +- onix-gui/{ => onix}/app/template.csv | 0 .../app/yaml-gen/check-yaml}/page.js | 70 +++---- onix-gui/onix/app/yaml-gen/option/bap/page.js | 64 ++++++ onix-gui/onix/app/yaml-gen/option/bpp/page.js | 64 ++++++ onix-gui/onix/app/yaml-gen/option/page.js | 43 ++++ onix-gui/onix/app/yaml-gen/page.js | 122 ++++++++++++ .../components/Buttons/Buttons.module.css | 0 .../components/Buttons/PrimaryButton.js | 0 .../components/Buttons/SecondaryButton.jsx | 0 .../components/InputField/InputField.jsx | 4 +- .../InputField/InputField.module.css | 0 .../{ => onix}/components/Slider/Slider.jsx | 0 .../components/Slider/Slider.module.css | 0 onix-gui/{ => onix}/jsconfig.json | 0 onix-gui/{ => onix}/next.config.mjs | 0 onix-gui/{ => onix}/package-lock.json | 0 onix-gui/{ => onix}/package.json | 0 onix-gui/{ => onix}/public/arrow.png | Bin onix-gui/{scripts => }/start.sh | 3 +- 49 files changed, 617 insertions(+), 364 deletions(-) delete mode 100644 onix-gui/app/api/install-layer2/route.js delete mode 100644 onix-gui/app/yaml-gen/page.js rename onix-gui/{ => onix}/.eslintrc.json (100%) rename onix-gui/{ => onix}/.gitignore (100%) rename onix-gui/{ => onix}/README.md (68%) rename onix-gui/{ => onix}/app/Infy_Pending.pdf (100%) rename onix-gui/{ => onix}/app/api/check-layer2/route.js (60%) rename onix-gui/{ => onix}/app/api/clonning-repo/route.js (100%) create mode 100644 onix-gui/onix/app/api/get-network-participant/route.js rename onix-gui/{ => onix}/app/api/install-bap/route.js (92%) rename onix-gui/{ => onix}/app/api/install-bpp/route.js (93%) rename onix-gui/{ => onix}/app/api/install-gateway/route.js (93%) rename onix-gui/{ => onix}/app/api/install-registry/route.js (85%) rename onix-gui/{ => onix}/app/favicon.ico (100%) rename onix-gui/{ => onix}/app/globals.css (100%) rename onix-gui/{ => onix}/app/install/configure/page.js (85%) rename onix-gui/{ => onix}/app/install/create/page.js (84%) rename onix-gui/{ => onix}/app/install/join/page.js (86%) rename onix-gui/{ => onix}/app/install/local/page.js (85%) rename onix-gui/{ => onix}/app/install/merge/page.js (76%) rename onix-gui/{ => onix}/app/install/page.js (56%) rename onix-gui/{ => onix}/app/layout.js (100%) create mode 100644 onix-gui/onix/app/monitor/dashboard/page.js create mode 100644 onix-gui/onix/app/monitor/page.js rename onix-gui/{ => onix}/app/page.js (81%) rename onix-gui/{ => onix}/app/page.module.css (100%) rename onix-gui/{ => onix}/app/setup/bap/page.js (98%) rename onix-gui/{ => onix}/app/setup/bpp/page.js (98%) rename onix-gui/{ => onix}/app/setup/gateway/page.js (98%) rename onix-gui/{ => onix}/app/setup/registry/page.js (97%) rename onix-gui/{ => onix}/app/template.csv (100%) rename onix-gui/{app/yaml-gen/install-yaml => onix/app/yaml-gen/check-yaml}/page.js (59%) create mode 100644 onix-gui/onix/app/yaml-gen/option/bap/page.js create mode 100644 onix-gui/onix/app/yaml-gen/option/bpp/page.js create mode 100644 onix-gui/onix/app/yaml-gen/option/page.js create mode 100644 onix-gui/onix/app/yaml-gen/page.js rename onix-gui/{ => onix}/components/Buttons/Buttons.module.css (100%) rename onix-gui/{ => onix}/components/Buttons/PrimaryButton.js (100%) rename onix-gui/{ => onix}/components/Buttons/SecondaryButton.jsx (100%) rename onix-gui/{ => onix}/components/InputField/InputField.jsx (76%) rename onix-gui/{ => onix}/components/InputField/InputField.module.css (100%) rename onix-gui/{ => onix}/components/Slider/Slider.jsx (100%) rename onix-gui/{ => onix}/components/Slider/Slider.module.css (100%) rename onix-gui/{ => onix}/jsconfig.json (100%) rename onix-gui/{ => onix}/next.config.mjs (100%) rename onix-gui/{ => onix}/package-lock.json (100%) rename onix-gui/{ => onix}/package.json (100%) rename onix-gui/{ => onix}/public/arrow.png (100%) rename onix-gui/{scripts => }/start.sh (95%) diff --git a/onix-gui/app/api/install-layer2/route.js b/onix-gui/app/api/install-layer2/route.js deleted file mode 100644 index c795226..0000000 --- a/onix-gui/app/api/install-layer2/route.js +++ /dev/null @@ -1,38 +0,0 @@ -import { exec } from "child_process"; -import { NextResponse } from "next/server"; - -export async function POST(req) { - const request = await req.json(); - const fileURL = request.yamlUrl; - const containerName = request.container; - - const executeShellCommand = (command) => { - return new Promise((resolve, reject) => { - exec(command, (error, stdout, stderr) => { - if (error) { - console.error("Error:", error); - reject(error); - return; - } - if (stderr) { - console.error("Error:", stderr); - reject(new Error(stderr)); - return; - } - const output = stdout; - console.log("Output:", output); - resolve(output); - }); - }); - }; - - try { - await executeShellCommand( - `docker exec ${containerName} wget -P /usr/src/app/schemas/ ${fileURL}` - ); - return NextResponse.json({ status: 200 }); - } catch (error) { - console.error(`exec error: ${error}`); - return NextResponse.json({ status: 500 }); - } -} diff --git a/onix-gui/app/yaml-gen/page.js b/onix-gui/app/yaml-gen/page.js deleted file mode 100644 index b80f556..0000000 --- a/onix-gui/app/yaml-gen/page.js +++ /dev/null @@ -1,183 +0,0 @@ -"use client"; -import { useState } from "react"; -import { Ubuntu_Mono } from "next/font/google"; -import PrimaryButton from "@/components/Buttons/PrimaryButton"; -import InputField from "@/components/InputField/InputField"; -import Slider from "@/components/Slider/Slider"; -import styles from "../page.module.css"; -import { toast } from "react-toastify"; - -import Link from "next/link"; - -const ubuntuMono = Ubuntu_Mono({ - weight: "400", - style: "normal", - subsets: ["latin"], -}); - -export default function CheckYaml() { - const [domainName, setDomainName] = useState(""); - const [versionNumber, setversionNumber] = useState(""); - const [checked, setChecked] = useState(false); - const [showDownloadLayer2Button, setShowDownloadLayer2Button] = - useState(false); - const [propertyLink, setPropertyLink] = useState(""); - - const handleYamlChange = (event) => { - setPropertyLink(event.target.value); - }; - const handledomainNameChange = (event) => { - setDomainName(event.target.value); - }; - const handleVersionChange = (event) => { - setversionNumber(event.target.value); - }; - const nameGenerator = async () => { - const parts = domainName.split(":"); - const domainNameWithoutVersion = parts[0]; - const domainVersion = parts[1] || ""; - const filename = `${domainNameWithoutVersion}_${domainVersion}_${versionNumber}.yaml`; - return filename; - }; - const handleDownload = async () => { - const userInput = prompt("Enter the URL of the Layer 2 Config file"); - try { - const response = await fetch("/api/install-layer2", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ checked, userInput }), - }); - - if (response.ok) { - const data = await response.json(); - console.log(data); - const FileFound = data.message; - if (FileFound == false) { - setShowDownloadLayer2Button(true); - toast.update(toastId, { - render: "No Layer 2 Config Present 🤯", - type: "error", - isLoading: false, - autoClose: 5000, - }); - } else { - toast.update(toastId, { - render: "Yaml File Present 👌", - type: "success", - isLoading: false, - autoClose: 5000, - }); - } - } else { - console.error("Failed to check yaml"); - toast.update(toastId, { - render: "Container Not Found 🤯", - type: "error", - isLoading: false, - autoClose: 5000, - }); - } - } catch (error) { - console.error("An error occurred:", error); - } - }; - - const handleOnclick = async () => { - const fileName = await nameGenerator(); - const toastId = toast.loading("Checking for layer2 yaml file"); - try { - const response = await fetch("/api/check-layer2", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ checked, fileName }), - }); - - if (response.ok) { - const data = await response.json(); - const FileFound = data.message; - if (FileFound == false) { - setShowDownloadLayer2Button(true); - toast.update(toastId, { - render: "No Layer 2 Config Present 🤯", - type: "error", - isLoading: false, - autoClose: 5000, - }); - } else { - toast.update(toastId, { - render: "Yaml File Present 👌", - type: "success", - isLoading: false, - autoClose: 5000, - }); - } - } else { - console.error("Failed to check yaml"); - toast.update(toastId, { - render: "Container Not Found 🤯", - type: "error", - isLoading: false, - autoClose: 5000, - }); - } - } catch (error) { - console.error("An error occurred:", error); - } - }; - return ( - <> -
- - -
-

- Yaml File Checker -

- -
- - - - - -
- -
- {showDownloadLayer2Button && ( - - )} -
-
-
- - ); -} diff --git a/onix-gui/.eslintrc.json b/onix-gui/onix/.eslintrc.json similarity index 100% rename from onix-gui/.eslintrc.json rename to onix-gui/onix/.eslintrc.json diff --git a/onix-gui/.gitignore b/onix-gui/onix/.gitignore similarity index 100% rename from onix-gui/.gitignore rename to onix-gui/onix/.gitignore diff --git a/onix-gui/README.md b/onix-gui/onix/README.md similarity index 68% rename from onix-gui/README.md rename to onix-gui/onix/README.md index 5453b9b..a18038f 100644 --- a/onix-gui/README.md +++ b/onix-gui/onix/README.md @@ -6,28 +6,23 @@ The GUI for the beckn-onix cli tool. 1. 4 server/instances 2. 4 sub-domains mapped to each instance +3. Local Tunnel + `npm i -g localtunnel` ## User Guide -### Step 1: Clone the beckn-onix-gui repo +### Step 1: Run the `start.sh` script ``` -git clone https://github.com/Mishalabdullah/beckn-onix-gui.git +cd .. && ./start.sh ``` -### Step 2: Change directory to the nextjs project +### Step 2: Accessing the GUI. -``` -cd onix-gui -``` - -### Step 3: Run nextjs on port 3005 +You will be getting a URL and password as on output of the script. Open the url in the browser and then +paste the password. -For running the installation script just run this command. The sudo privilages are required when installing packages and configuring the nginx reverse proxy - -``` -sudo ./start.sh -``` +### Step 3: Install and setup your network Note: Port 3000 is being used by onix, so we're using port 3005 instead. diff --git a/onix-gui/app/Infy_Pending.pdf b/onix-gui/onix/app/Infy_Pending.pdf similarity index 100% rename from onix-gui/app/Infy_Pending.pdf rename to onix-gui/onix/app/Infy_Pending.pdf diff --git a/onix-gui/app/api/check-layer2/route.js b/onix-gui/onix/app/api/check-layer2/route.js similarity index 60% rename from onix-gui/app/api/check-layer2/route.js rename to onix-gui/onix/app/api/check-layer2/route.js index 1fb27cf..9ffccdf 100644 --- a/onix-gui/app/api/check-layer2/route.js +++ b/onix-gui/onix/app/api/check-layer2/route.js @@ -2,9 +2,8 @@ import { exec } from "child_process"; import { NextResponse } from "next/server"; export async function POST(req) { - const request = await req.json(); - const containerName = request.checked ? "bpp-network" : "bap-network"; - const fileToCheck = request.fileName; + const checked = await req.json(); + const containerName = checked.checked ? "bpp-network" : "bap-network"; const executeShellCommand = (command) => { return new Promise((resolve, reject) => { @@ -14,11 +13,13 @@ export async function POST(req) { reject(error); return; } + if (stderr) { console.error("Error:", stderr); reject(new Error(stderr)); return; } + const output = stdout; console.log("Output:", output); resolve(output); @@ -30,6 +31,7 @@ export async function POST(req) { const containerExists = await executeShellCommand( `docker ps -a --filter "name=${containerName}" --format "{{.Names}}"` ); + if (!containerExists.trim()) { return new NextResponse(`Error: ${containerName} server not present`, { status: 500, @@ -37,30 +39,14 @@ export async function POST(req) { } const result = await executeShellCommand( - `docker exec ${containerName} /bin/sh -c "[ -f '/usr/src/app/schemas/${fileToCheck}' ] && echo 'File found' || echo 'File not found'"` + `docker exec ${containerName} ls /usr/src/app/schemas/ | grep -v "core" | grep ".yaml" | wc -l` ); - if (result.trim() === "File found") { - return NextResponse.json( - { message: true }, - { - status: 200, - } - ); - } else { - return NextResponse.json( - { message: false }, - { - status: 200, - } - ); - } + + return new NextResponse(result); } catch (error) { console.error(`exec error: ${error}`); - return NextResponse.json( - { message: `Error executing shell command: ${error}` }, - { - status: 500, - } - ); + return new NextResponse(`Error executing shell command: ${error}`, { + status: 500, + }); } } diff --git a/onix-gui/app/api/clonning-repo/route.js b/onix-gui/onix/app/api/clonning-repo/route.js similarity index 100% rename from onix-gui/app/api/clonning-repo/route.js rename to onix-gui/onix/app/api/clonning-repo/route.js diff --git a/onix-gui/onix/app/api/get-network-participant/route.js b/onix-gui/onix/app/api/get-network-participant/route.js new file mode 100644 index 0000000..45f68f5 --- /dev/null +++ b/onix-gui/onix/app/api/get-network-participant/route.js @@ -0,0 +1,27 @@ +import { NextResponse } from "next/server"; + +export async function POST(req, res) { + const request = await req.json(); + const registryUrl = request.registryUrl; + const body = { type: "BPP" }; + + try { + const response = await fetch(registryUrl, { + method: "POST", + headers: { + Accept: "application/json", + "Content-Type": "application/json", + }, + body: JSON.stringify(body), + }); + + const data = await response.json(); + return NextResponse.json(data, { status: 200 }); + } catch (error) { + console.error(error); + return NextResponse.json( + { error: "Error making request to registry" }, + { status: 500 } + ); + } +} diff --git a/onix-gui/app/api/install-bap/route.js b/onix-gui/onix/app/api/install-bap/route.js similarity index 92% rename from onix-gui/app/api/install-bap/route.js rename to onix-gui/onix/app/api/install-bap/route.js index 2c5fb04..9236941 100644 --- a/onix-gui/app/api/install-bap/route.js +++ b/onix-gui/onix/app/api/install-bap/route.js @@ -47,10 +47,7 @@ export async function startSupportServices() { `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d redis_db` ); console.log("Result 3:", result3); - await executeCommand("docker volume create registry_data_volume"); - await executeCommand("docker volume create registry_database_volume"); - await executeCommand("docker volume create gateway_data_volume"); - await executeCommand("docker volume create gateway_database_volume"); + return NextResponse.json({ result1, result2, result3 }); } catch (error) { console.error("An error occurred:", error); @@ -94,10 +91,10 @@ export async function POST(req) { const bppSubscriberId = data.subscriberId; const bppSubscriberUrl = data.subscriberUrl; const networkconfigurl = data.networkconfigurl; - let updateBppConfigCommand = `bash ${pathDir}/install/scripts/update_bap_config.sh ${registryUrl} ${bppSubscriberId} ${bppSubscriberUrl} ${networkconfigurl}`; const result1 = await executeCommand(updateBppConfigCommand); console.log("Result 1:", result1); + const result3 = await executeCommand( `docker-compose -f ${pathDir}/install/docker-compose-v2.yml up -d "bap-client"` ); diff --git a/onix-gui/app/api/install-bpp/route.js b/onix-gui/onix/app/api/install-bpp/route.js similarity index 93% rename from onix-gui/app/api/install-bpp/route.js rename to onix-gui/onix/app/api/install-bpp/route.js index 2ac5ca0..9943be4 100644 --- a/onix-gui/app/api/install-bpp/route.js +++ b/onix-gui/onix/app/api/install-bpp/route.js @@ -47,10 +47,7 @@ export async function startSupportServices() { `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d redis_db` ); console.log("Result 3:", result3); - await executeCommand("docker volume create registry_data_volume"); - await executeCommand("docker volume create registry_database_volume"); - await executeCommand("docker volume create gateway_data_volume"); - await executeCommand("docker volume create gateway_database_volume"); + return NextResponse.json({ result1, result2, result3 }); } catch (error) { console.error("An error occurred:", error); diff --git a/onix-gui/app/api/install-gateway/route.js b/onix-gui/onix/app/api/install-gateway/route.js similarity index 93% rename from onix-gui/app/api/install-gateway/route.js rename to onix-gui/onix/app/api/install-gateway/route.js index 3545f6e..46b150b 100644 --- a/onix-gui/app/api/install-gateway/route.js +++ b/onix-gui/onix/app/api/install-gateway/route.js @@ -64,8 +64,7 @@ export async function POST(req, res) { `bash ${pathDir}/install/scripts/package_manager.sh` ); console.log("Result 1:", result1); - await executeCommand("docker volume create registry_data_volume"); - await executeCommand("docker volume create registry_database_volume"); + const result2 = await executeCommand( ` bash ${pathDir}/install/scripts/update_gateway_details.sh ${data.registryUrl} ${data.gatewayUrl}` ); @@ -76,7 +75,7 @@ export async function POST(req, res) { ); console.log("Result 3:", result3); - const result4 = await executeCommand(`sleep 2`); + const result4 = await executeCommand(`sleep 10`); console.log("Result 4:", result4); const result5 = await executeCommand( diff --git a/onix-gui/app/api/install-registry/route.js b/onix-gui/onix/app/api/install-registry/route.js similarity index 85% rename from onix-gui/app/api/install-registry/route.js rename to onix-gui/onix/app/api/install-registry/route.js index 70c4102..fbffb7b 100644 --- a/onix-gui/app/api/install-registry/route.js +++ b/onix-gui/onix/app/api/install-registry/route.js @@ -111,20 +111,6 @@ export async function POST(req, res) { await fs.writeFile(tempFile, updatedConfigData); await fs.rename(tempFile, configFile); - await executeCommand("docker volume create registry_data_volume"); - await executeCommand("docker volume create registry_database_volume"); - await executeCommand("docker volume create gateway_data_volume"); - await executeCommand("docker volume create gateway_database_volume"); - await executeCommand( - `docker run --rm -v ${join( - pathDir, - "install", - "registry_data", - "config" - )}:/source -v registry_data_volume:/target busybox sh -c "cp /source/envvars /target/ && cp /source/logger.properties /target/ && cp /source/swf.properties /target/"` - ); - - // Start the registry container await executeCommand( `docker-compose -f ${join( pathDir, diff --git a/onix-gui/app/favicon.ico b/onix-gui/onix/app/favicon.ico similarity index 100% rename from onix-gui/app/favicon.ico rename to onix-gui/onix/app/favicon.ico diff --git a/onix-gui/app/globals.css b/onix-gui/onix/app/globals.css similarity index 100% rename from onix-gui/app/globals.css rename to onix-gui/onix/app/globals.css diff --git a/onix-gui/app/install/configure/page.js b/onix-gui/onix/app/install/configure/page.js similarity index 85% rename from onix-gui/app/install/configure/page.js rename to onix-gui/onix/app/install/configure/page.js index 4da2300..f0749f9 100644 --- a/onix-gui/app/install/configure/page.js +++ b/onix-gui/onix/app/install/configure/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; -import Image from "next/image"; + const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -28,7 +28,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

Gateway

@@ -37,7 +37,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

BAP Adapter

@@ -46,7 +46,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

BPP Adapter

diff --git a/onix-gui/app/install/create/page.js b/onix-gui/onix/app/install/create/page.js similarity index 84% rename from onix-gui/app/install/create/page.js rename to onix-gui/onix/app/install/create/page.js index 0cf9db7..14e38e6 100644 --- a/onix-gui/app/install/create/page.js +++ b/onix-gui/onix/app/install/create/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; -import Image from "next/image"; + const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -28,7 +28,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

Gateway

@@ -37,7 +37,7 @@ export default function Home() { className={styles.box} style={{ textDecoration: "underline", color: "white" }} > - arrow +

BAP Adapter

@@ -46,7 +46,7 @@ export default function Home() { className={styles.box} style={{ textDecoration: "underline", color: "white" }} > - arrow +

BPP Adapter

@@ -55,7 +55,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

Registry

diff --git a/onix-gui/app/install/join/page.js b/onix-gui/onix/app/install/join/page.js similarity index 86% rename from onix-gui/app/install/join/page.js rename to onix-gui/onix/app/install/join/page.js index 619e14b..5223af5 100644 --- a/onix-gui/app/install/join/page.js +++ b/onix-gui/onix/app/install/join/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; -import Image from "next/image"; + const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -32,7 +32,7 @@ export default function Home() { }} >
- arrow +

Gateway

@@ -44,7 +44,7 @@ export default function Home() { }} >
- arrow +

BAP Adapter

@@ -56,7 +56,7 @@ export default function Home() { }} >
- arrow +

BPP Adapter

diff --git a/onix-gui/app/install/local/page.js b/onix-gui/onix/app/install/local/page.js similarity index 85% rename from onix-gui/app/install/local/page.js rename to onix-gui/onix/app/install/local/page.js index 7dbd607..a698588 100644 --- a/onix-gui/app/install/local/page.js +++ b/onix-gui/onix/app/install/local/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; -import Image from "next/image"; + const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -30,7 +30,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

Gateway

@@ -39,7 +39,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

BAP Adapter

@@ -48,7 +48,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

BPP Adapter

diff --git a/onix-gui/app/install/merge/page.js b/onix-gui/onix/app/install/merge/page.js similarity index 76% rename from onix-gui/app/install/merge/page.js rename to onix-gui/onix/app/install/merge/page.js index 7391660..7e256d9 100644 --- a/onix-gui/app/install/merge/page.js +++ b/onix-gui/onix/app/install/merge/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; -import Image from "next/image"; + const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -15,12 +15,7 @@ export default function Home() { <>
- +

Merge multiple networks

- arrow +

Gateway

@@ -37,7 +32,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

BAP

@@ -46,7 +41,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

BPP

diff --git a/onix-gui/app/install/page.js b/onix-gui/onix/app/install/page.js similarity index 56% rename from onix-gui/app/install/page.js rename to onix-gui/onix/app/install/page.js index a196231..e104190 100644 --- a/onix-gui/app/install/page.js +++ b/onix-gui/onix/app/install/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; -import Image from "next/image"; + const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -33,7 +33,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

Join an existing network

@@ -42,10 +42,39 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

Create new production network

+ +
+ +

+ Set up a network on your local machine +

+
+ + {/* +
+ +

Merge multiple networks

+
+ + +
+ +

Configure Existing Network

+
+ */}
diff --git a/onix-gui/app/layout.js b/onix-gui/onix/app/layout.js similarity index 100% rename from onix-gui/app/layout.js rename to onix-gui/onix/app/layout.js diff --git a/onix-gui/onix/app/monitor/dashboard/page.js b/onix-gui/onix/app/monitor/dashboard/page.js new file mode 100644 index 0000000..072b95d --- /dev/null +++ b/onix-gui/onix/app/monitor/dashboard/page.js @@ -0,0 +1,95 @@ +import styles from "../../page.module.css"; + +const page = () => { + const data = [ + { + ip: "192.168.1.1", + status: "Live", + cpu: "2%", + memory: "18.8 MB", + uptime: "10 days", + }, + { + ip: "10.0.0.1", + status: "404", + cpu: "0%", + memory: "0 MB", + uptime: "5 days", + }, + { + ip: "172.16.0.1", + status: "Live", + cpu: "6%", + memory: "56.4 MB", + uptime: "15 days", + }, + { + ip: "192.0.2.1", + status: "Live", + cpu: "69%", + memory: "648.6 MB", + uptime: "20 days", + }, + { + ip: "198.51.100.1", + status: "404", + cpu: "0%", + memory: "0 MB", + uptime: "3 days", + }, + { + ip: "203.0.113.1", + status: "Live", + cpu: ".4%", + memory: "3.7 MB", + uptime: "8 days", + }, + ]; + return ( +
+
+

+ Uptime Network Participants: 10 +

+

+ Uptime Network Participants: 10 +

+
+

Dashboard

+ + + + + + + + + + + + {data.map((item, index) => ( + + + + + + + + ))} + +
S/NIP / Domain NameStatusCPUMemory
{index + 1}{item.ip}{item.status}{item.cpu}{item.memory}
+
+ ); +}; + +export default page; diff --git a/onix-gui/onix/app/monitor/page.js b/onix-gui/onix/app/monitor/page.js new file mode 100644 index 0000000..5e042e2 --- /dev/null +++ b/onix-gui/onix/app/monitor/page.js @@ -0,0 +1,74 @@ +"use client"; +import { useState } from "react"; +import InputField from "@/components/InputField/InputField"; +import styles from "../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import SecondaryButton from "@/components/Buttons/SecondaryButton"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import { useRouter } from "next/navigation"; +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function Home() { + const [registryUrl, setRegistryUrl] = useState(""); + const router = useRouter(); + const handleRegistryUrlChange = (event) => { + setRegistryUrl(event.target.value); + }; + const handleContinue = async () => { + try { + const response = await fetch("/api/get-network-participant", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ registryUrl }), + }); + + if (response.ok) { + const networkParticipantsData = await response.json(); + router.push("/monitor/dashboard"); + // redirecting to the dashboard page + } else { + console.log("error fetching participant data"); + } + } catch (error) { + console.error("Error:", error); + } + }; + + return ( + <> +
+
+ + {/*

ONIX{pathname}

*/} +

Network Registry

+
+ + {/* */} + {/* */} + {/* */} + +
+ {/* */} + +
+
+
+
+ + ); +} diff --git a/onix-gui/app/page.js b/onix-gui/onix/app/page.js similarity index 81% rename from onix-gui/app/page.js rename to onix-gui/onix/app/page.js index 600fc62..33f3594 100644 --- a/onix-gui/app/page.js +++ b/onix-gui/onix/app/page.js @@ -1,7 +1,7 @@ import Link from "next/link"; import styles from "./page.module.css"; import { Ubuntu_Mono } from "next/font/google"; -import Image from "next/image"; + const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -25,25 +25,25 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- arrow +

Installation Wizard

- {/*
- arrow +

Network Monitor

- */} +
- arrow +

Layer 2 Tester

diff --git a/onix-gui/app/page.module.css b/onix-gui/onix/app/page.module.css similarity index 100% rename from onix-gui/app/page.module.css rename to onix-gui/onix/app/page.module.css diff --git a/onix-gui/app/setup/bap/page.js b/onix-gui/onix/app/setup/bap/page.js similarity index 98% rename from onix-gui/app/setup/bap/page.js rename to onix-gui/onix/app/setup/bap/page.js index 2613e6e..ff4b4f8 100644 --- a/onix-gui/app/setup/bap/page.js +++ b/onix-gui/onix/app/setup/bap/page.js @@ -117,7 +117,7 @@ export default function Home() { />
- {/* */} +
- {/* */} +
- {/* */} +
diff --git a/onix-gui/app/setup/registry/page.js b/onix-gui/onix/app/setup/registry/page.js similarity index 97% rename from onix-gui/app/setup/registry/page.js rename to onix-gui/onix/app/setup/registry/page.js index 6fce954..8bc57c2 100644 --- a/onix-gui/app/setup/registry/page.js +++ b/onix-gui/onix/app/setup/registry/page.js @@ -85,7 +85,7 @@ export default function Home() { onChange={handleRegistryUrlChange} />
- {/* */} +
diff --git a/onix-gui/app/template.csv b/onix-gui/onix/app/template.csv similarity index 100% rename from onix-gui/app/template.csv rename to onix-gui/onix/app/template.csv diff --git a/onix-gui/app/yaml-gen/install-yaml/page.js b/onix-gui/onix/app/yaml-gen/check-yaml/page.js similarity index 59% rename from onix-gui/app/yaml-gen/install-yaml/page.js rename to onix-gui/onix/app/yaml-gen/check-yaml/page.js index 22ad80c..4ebbcf6 100644 --- a/onix-gui/app/yaml-gen/install-yaml/page.js +++ b/onix-gui/onix/app/yaml-gen/check-yaml/page.js @@ -1,12 +1,12 @@ "use client"; -import SecondaryButton from "@/components/Buttons/SecondaryButton"; -import styles from "../../page.module.css"; +import { useState } from "react"; import { Ubuntu_Mono } from "next/font/google"; -import Slider from "@/components/Slider/Slider"; import PrimaryButton from "@/components/Buttons/PrimaryButton"; import InputField from "@/components/InputField/InputField"; -import { useState, useCallback } from "react"; +import Slider from "@/components/Slider/Slider"; +import styles from "../../page.module.css"; import { toast } from "react-toastify"; +import Link from "next/link"; const ubuntuMono = Ubuntu_Mono({ weight: "400", @@ -14,34 +14,30 @@ const ubuntuMono = Ubuntu_Mono({ subsets: ["latin"], }); -export default function InstallYaml() { - const [yamlUrl, setYamlUrl] = useState(""); +export default function CheckYaml() { const [checked, setChecked] = useState(false); + const [propertyLink, setPropertyLink] = useState(""); - const container = checked ? "bpp-network" : "bap-network"; - - const handleRegistryUrlChange = (event) => { - setYamlUrl(event.target.value); + const handleYamlChange = (event) => { + setPropertyLink(event.target.value); }; - const installYaml = useCallback(async () => { - const toastId = toast.loading("Installing Layer 2 Config file..."); - + const handleOnclick = async () => { + const toastId = toast.loading("Checking for layer2 yaml file"); try { - const response = await fetch("/api/install-layer2", { + const response = await fetch("/api/check-layer2", { method: "POST", headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ container, yamlUrl }), + body: JSON.stringify({ checked }), }); if (response.ok) { const data = await response.json(); - console.log(data); - const FileFound = data.message; - if (FileFound == false) { - setShowDownloadLayer2Button(true); + const yamlFile = data; + console.log("YAML", yamlFile); + if (yamlFile == 0) { toast.update(toastId, { render: "No Layer 2 Config Present 🤯", type: "error", @@ -68,19 +64,22 @@ export default function InstallYaml() { } catch (error) { console.error("An error occurred:", error); } - }); - + }; return ( <>
+ +
- -

Install Yaml

+

+ Yaml File Checker +

+
+ {/* */} +
- {/* */} - +
diff --git a/onix-gui/onix/app/yaml-gen/option/bap/page.js b/onix-gui/onix/app/yaml-gen/option/bap/page.js new file mode 100644 index 0000000..974a6a9 --- /dev/null +++ b/onix-gui/onix/app/yaml-gen/option/bap/page.js @@ -0,0 +1,64 @@ +"use client"; + +import InputField from "@/components/InputField/InputField"; +import styles from "../../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import SecondaryButton from "@/components/Buttons/SecondaryButton"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import { usePathname } from "next/navigation"; +import { useState, useCallback } from "react"; +import Slider from "@/components/Slider/Slider" + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + + +export default function Bap() { + + const [checked, setChecked] = useState(false); + const [propertyName, setPropertyName] = useState(""); + const [propertyLink, setPropertyLink] = useState(""); + const [propertyOption, setPropertyOption] = useState(""); + + return ( + <> +
+
+

BAP

+
+ + + + + + + +
+ + +
+
+
+
+ + ) +} \ No newline at end of file diff --git a/onix-gui/onix/app/yaml-gen/option/bpp/page.js b/onix-gui/onix/app/yaml-gen/option/bpp/page.js new file mode 100644 index 0000000..c4ff616 --- /dev/null +++ b/onix-gui/onix/app/yaml-gen/option/bpp/page.js @@ -0,0 +1,64 @@ +"use client"; + +import InputField from "@/components/InputField/InputField"; +import styles from "../../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import SecondaryButton from "@/components/Buttons/SecondaryButton"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import { usePathname } from "next/navigation"; +import { useState, useCallback } from "react"; +import Slider from "@/components/Slider/Slider" + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + + +export default function Bpp() { + + const [checked, setChecked] = useState(false); + const [propertyName, setPropertyName] = useState(""); + const [propertyLink, setPropertyLink] = useState(""); + const [propertyOption, setPropertyOption] = useState(""); + + return ( + <> +
+
+

BPP

+
+ + + + + + + +
+ + +
+
+
+
+ + ) +} \ No newline at end of file diff --git a/onix-gui/onix/app/yaml-gen/option/page.js b/onix-gui/onix/app/yaml-gen/option/page.js new file mode 100644 index 0000000..b8a9b35 --- /dev/null +++ b/onix-gui/onix/app/yaml-gen/option/page.js @@ -0,0 +1,43 @@ +import Link from "next/link"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + + +export default function Option() { + return ( + <> +
+
+

Yaml File Generator

+
+ +
+ +

BAP

+
+ + +
+ +

BPP

+
+ +
+ +
+
+ + ) +} \ No newline at end of file diff --git a/onix-gui/onix/app/yaml-gen/page.js b/onix-gui/onix/app/yaml-gen/page.js new file mode 100644 index 0000000..1fcf514 --- /dev/null +++ b/onix-gui/onix/app/yaml-gen/page.js @@ -0,0 +1,122 @@ +import Link from "next/link"; +import styles from "../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import btnstyles from "@/components/Buttons/Buttons.module.css"; +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function YamlGen() { + return ( + <> +
+
+

+ Yaml File Generator +

+
+ +
+ +

Search

+
+ + +
+ +

Select

+
+ + +
+ +

Init

+
+ + +
+ +

Confirm

+
+ + +
+ +

Status

+
+ +
+
+ +
+ +

Track

+
+ + +
+ +

Cancel

+
+ + +
+ +

Update

+
+ + +
+ +

Rating

+
+ + +
+ +

Support

+
+ +
+
+ +
+ + ); +} diff --git a/onix-gui/components/Buttons/Buttons.module.css b/onix-gui/onix/components/Buttons/Buttons.module.css similarity index 100% rename from onix-gui/components/Buttons/Buttons.module.css rename to onix-gui/onix/components/Buttons/Buttons.module.css diff --git a/onix-gui/components/Buttons/PrimaryButton.js b/onix-gui/onix/components/Buttons/PrimaryButton.js similarity index 100% rename from onix-gui/components/Buttons/PrimaryButton.js rename to onix-gui/onix/components/Buttons/PrimaryButton.js diff --git a/onix-gui/components/Buttons/SecondaryButton.jsx b/onix-gui/onix/components/Buttons/SecondaryButton.jsx similarity index 100% rename from onix-gui/components/Buttons/SecondaryButton.jsx rename to onix-gui/onix/components/Buttons/SecondaryButton.jsx diff --git a/onix-gui/components/InputField/InputField.jsx b/onix-gui/onix/components/InputField/InputField.jsx similarity index 76% rename from onix-gui/components/InputField/InputField.jsx rename to onix-gui/onix/components/InputField/InputField.jsx index aac6551..e20ce98 100644 --- a/onix-gui/components/InputField/InputField.jsx +++ b/onix-gui/onix/components/InputField/InputField.jsx @@ -1,12 +1,12 @@ import React from "react"; import styles from "./InputField.module.css"; -const InputField = ({ label, value, onChange, placeholder = "Input Text" }) => { +const InputField = ({ label, value, onChange }) => { return (
Date: Thu, 2 May 2024 21:53:36 +0530 Subject: [PATCH 051/102] contributors --- onix-gui/onix/README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/onix-gui/onix/README.md b/onix-gui/onix/README.md index a18038f..b701976 100644 --- a/onix-gui/onix/README.md +++ b/onix-gui/onix/README.md @@ -42,6 +42,15 @@ Contributions are welcome! If you'd like to contribute to the beckn-onix-gui pro The beckn-onix-gui project is licensed under the MIT License. See the LICENSE file for more information. + ## Contact If you have any questions or issues with the beckn-onix-gui project, please don't hesitate to reach out. + +### Made with ❤️ + +built by the [Mulearn Team](https://mulearn.org/) +1. [Mishal Abdullah](https://github.com/Mishalabdullah/) +2. [Aswin Asok](https://github.com/AswinAsok) +3. [Viraj Prabhu ](https://github.com/viraka) +4. [Adasrsh](https://adarshmohanks.framer.website/) From 7af6a1e85b0b9e8750e6eae30a5bfd2f8f725779 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Fri, 3 May 2024 11:10:14 +0530 Subject: [PATCH 052/102] copied new version --- onix-gui/{onix => GUI}/README.md | 30 ++--- onix-gui/{onix => GUI}/app/Infy_Pending.pdf | Bin .../app/api/check-layer2/route.js | 36 ++++-- .../app/api/clonning-repo/route.js | 0 .../app/api/install-bap/route.js | 7 +- .../app/api/install-bpp/route.js | 5 +- .../app/api/install-gateway/route.js | 5 +- onix-gui/GUI/app/api/install-layer2/route.js | 38 ++++++ .../app/api/install-registry/route.js | 14 ++ onix-gui/{onix => GUI}/app/favicon.ico | Bin onix-gui/{onix => GUI}/app/globals.css | 0 .../app/install/configure/page.js | 8 +- .../{onix => GUI}/app/install/create/page.js | 10 +- .../{onix => GUI}/app/install/join/page.js | 8 +- .../{onix => GUI}/app/install/local/page.js | 8 +- .../{onix => GUI}/app/install/merge/page.js | 15 ++- onix-gui/{onix => GUI}/app/install/page.js | 35 +---- onix-gui/{onix => GUI}/app/layout.js | 0 onix-gui/{onix => GUI}/app/page.js | 14 +- onix-gui/{onix => GUI}/app/page.module.css | 0 onix-gui/{onix => GUI}/app/setup/bap/page.js | 2 +- onix-gui/{onix => GUI}/app/setup/bpp/page.js | 2 +- .../{onix => GUI}/app/setup/gateway/page.js | 2 +- .../{onix => GUI}/app/setup/registry/page.js | 2 +- onix-gui/{onix => GUI}/app/template.csv | 0 .../GUI/app/yaml-gen/install-yaml/page.js | 105 +++++++++++++++ .../check-yaml => GUI/app/yaml-gen}/page.js | 59 +++++++-- .../components/Buttons/Buttons.module.css | 0 .../components/Buttons/PrimaryButton.js | 0 .../components/Buttons/SecondaryButton.jsx | 0 .../components/InputField/InputField.jsx | 4 +- .../InputField/InputField.module.css | 0 .../components/Slider/Slider.jsx | 0 .../components/Slider/Slider.module.css | 0 onix-gui/{onix => GUI}/jsconfig.json | 0 onix-gui/{onix => GUI}/package-lock.json | 0 onix-gui/{onix => GUI}/package.json | 0 onix-gui/{onix => GUI}/public/arrow.png | Bin onix-gui/onix/.eslintrc.json | 3 - onix-gui/onix/.gitignore | 36 ------ .../app/api/get-network-participant/route.js | 27 ---- onix-gui/onix/app/monitor/dashboard/page.js | 95 -------------- onix-gui/onix/app/monitor/page.js | 74 ----------- onix-gui/onix/app/yaml-gen/option/bap/page.js | 64 --------- onix-gui/onix/app/yaml-gen/option/bpp/page.js | 64 --------- onix-gui/onix/app/yaml-gen/option/page.js | 43 ------ onix-gui/onix/app/yaml-gen/page.js | 122 ------------------ onix-gui/onix/next.config.mjs | 4 - onix-gui/start.sh | 3 +- 49 files changed, 300 insertions(+), 644 deletions(-) rename onix-gui/{onix => GUI}/README.md (60%) rename onix-gui/{onix => GUI}/app/Infy_Pending.pdf (100%) rename onix-gui/{onix => GUI}/app/api/check-layer2/route.js (60%) rename onix-gui/{onix => GUI}/app/api/clonning-repo/route.js (100%) rename onix-gui/{onix => GUI}/app/api/install-bap/route.js (92%) rename onix-gui/{onix => GUI}/app/api/install-bpp/route.js (93%) rename onix-gui/{onix => GUI}/app/api/install-gateway/route.js (93%) create mode 100644 onix-gui/GUI/app/api/install-layer2/route.js rename onix-gui/{onix => GUI}/app/api/install-registry/route.js (85%) rename onix-gui/{onix => GUI}/app/favicon.ico (100%) rename onix-gui/{onix => GUI}/app/globals.css (100%) rename onix-gui/{onix => GUI}/app/install/configure/page.js (85%) rename onix-gui/{onix => GUI}/app/install/create/page.js (84%) rename onix-gui/{onix => GUI}/app/install/join/page.js (86%) rename onix-gui/{onix => GUI}/app/install/local/page.js (85%) rename onix-gui/{onix => GUI}/app/install/merge/page.js (76%) rename onix-gui/{onix => GUI}/app/install/page.js (56%) rename onix-gui/{onix => GUI}/app/layout.js (100%) rename onix-gui/{onix => GUI}/app/page.js (81%) rename onix-gui/{onix => GUI}/app/page.module.css (100%) rename onix-gui/{onix => GUI}/app/setup/bap/page.js (98%) rename onix-gui/{onix => GUI}/app/setup/bpp/page.js (98%) rename onix-gui/{onix => GUI}/app/setup/gateway/page.js (98%) rename onix-gui/{onix => GUI}/app/setup/registry/page.js (97%) rename onix-gui/{onix => GUI}/app/template.csv (100%) create mode 100644 onix-gui/GUI/app/yaml-gen/install-yaml/page.js rename onix-gui/{onix/app/yaml-gen/check-yaml => GUI/app/yaml-gen}/page.js (59%) rename onix-gui/{onix => GUI}/components/Buttons/Buttons.module.css (100%) rename onix-gui/{onix => GUI}/components/Buttons/PrimaryButton.js (100%) rename onix-gui/{onix => GUI}/components/Buttons/SecondaryButton.jsx (100%) rename onix-gui/{onix => GUI}/components/InputField/InputField.jsx (76%) rename onix-gui/{onix => GUI}/components/InputField/InputField.module.css (100%) rename onix-gui/{onix => GUI}/components/Slider/Slider.jsx (100%) rename onix-gui/{onix => GUI}/components/Slider/Slider.module.css (100%) rename onix-gui/{onix => GUI}/jsconfig.json (100%) rename onix-gui/{onix => GUI}/package-lock.json (100%) rename onix-gui/{onix => GUI}/package.json (100%) rename onix-gui/{onix => GUI}/public/arrow.png (100%) delete mode 100644 onix-gui/onix/.eslintrc.json delete mode 100644 onix-gui/onix/.gitignore delete mode 100644 onix-gui/onix/app/api/get-network-participant/route.js delete mode 100644 onix-gui/onix/app/monitor/dashboard/page.js delete mode 100644 onix-gui/onix/app/monitor/page.js delete mode 100644 onix-gui/onix/app/yaml-gen/option/bap/page.js delete mode 100644 onix-gui/onix/app/yaml-gen/option/bpp/page.js delete mode 100644 onix-gui/onix/app/yaml-gen/option/page.js delete mode 100644 onix-gui/onix/app/yaml-gen/page.js delete mode 100644 onix-gui/onix/next.config.mjs diff --git a/onix-gui/onix/README.md b/onix-gui/GUI/README.md similarity index 60% rename from onix-gui/onix/README.md rename to onix-gui/GUI/README.md index b701976..5453b9b 100644 --- a/onix-gui/onix/README.md +++ b/onix-gui/GUI/README.md @@ -6,23 +6,28 @@ The GUI for the beckn-onix cli tool. 1. 4 server/instances 2. 4 sub-domains mapped to each instance -3. Local Tunnel - `npm i -g localtunnel` ## User Guide -### Step 1: Run the `start.sh` script +### Step 1: Clone the beckn-onix-gui repo ``` -cd .. && ./start.sh +git clone https://github.com/Mishalabdullah/beckn-onix-gui.git ``` -### Step 2: Accessing the GUI. +### Step 2: Change directory to the nextjs project -You will be getting a URL and password as on output of the script. Open the url in the browser and then -paste the password. +``` +cd onix-gui +``` + +### Step 3: Run nextjs on port 3005 -### Step 3: Install and setup your network +For running the installation script just run this command. The sudo privilages are required when installing packages and configuring the nginx reverse proxy + +``` +sudo ./start.sh +``` Note: Port 3000 is being used by onix, so we're using port 3005 instead. @@ -42,15 +47,6 @@ Contributions are welcome! If you'd like to contribute to the beckn-onix-gui pro The beckn-onix-gui project is licensed under the MIT License. See the LICENSE file for more information. - ## Contact If you have any questions or issues with the beckn-onix-gui project, please don't hesitate to reach out. - -### Made with ❤️ - -built by the [Mulearn Team](https://mulearn.org/) -1. [Mishal Abdullah](https://github.com/Mishalabdullah/) -2. [Aswin Asok](https://github.com/AswinAsok) -3. [Viraj Prabhu ](https://github.com/viraka) -4. [Adasrsh](https://adarshmohanks.framer.website/) diff --git a/onix-gui/onix/app/Infy_Pending.pdf b/onix-gui/GUI/app/Infy_Pending.pdf similarity index 100% rename from onix-gui/onix/app/Infy_Pending.pdf rename to onix-gui/GUI/app/Infy_Pending.pdf diff --git a/onix-gui/onix/app/api/check-layer2/route.js b/onix-gui/GUI/app/api/check-layer2/route.js similarity index 60% rename from onix-gui/onix/app/api/check-layer2/route.js rename to onix-gui/GUI/app/api/check-layer2/route.js index 9ffccdf..1fb27cf 100644 --- a/onix-gui/onix/app/api/check-layer2/route.js +++ b/onix-gui/GUI/app/api/check-layer2/route.js @@ -2,8 +2,9 @@ import { exec } from "child_process"; import { NextResponse } from "next/server"; export async function POST(req) { - const checked = await req.json(); - const containerName = checked.checked ? "bpp-network" : "bap-network"; + const request = await req.json(); + const containerName = request.checked ? "bpp-network" : "bap-network"; + const fileToCheck = request.fileName; const executeShellCommand = (command) => { return new Promise((resolve, reject) => { @@ -13,13 +14,11 @@ export async function POST(req) { reject(error); return; } - if (stderr) { console.error("Error:", stderr); reject(new Error(stderr)); return; } - const output = stdout; console.log("Output:", output); resolve(output); @@ -31,7 +30,6 @@ export async function POST(req) { const containerExists = await executeShellCommand( `docker ps -a --filter "name=${containerName}" --format "{{.Names}}"` ); - if (!containerExists.trim()) { return new NextResponse(`Error: ${containerName} server not present`, { status: 500, @@ -39,14 +37,30 @@ export async function POST(req) { } const result = await executeShellCommand( - `docker exec ${containerName} ls /usr/src/app/schemas/ | grep -v "core" | grep ".yaml" | wc -l` + `docker exec ${containerName} /bin/sh -c "[ -f '/usr/src/app/schemas/${fileToCheck}' ] && echo 'File found' || echo 'File not found'"` ); - - return new NextResponse(result); + if (result.trim() === "File found") { + return NextResponse.json( + { message: true }, + { + status: 200, + } + ); + } else { + return NextResponse.json( + { message: false }, + { + status: 200, + } + ); + } } catch (error) { console.error(`exec error: ${error}`); - return new NextResponse(`Error executing shell command: ${error}`, { - status: 500, - }); + return NextResponse.json( + { message: `Error executing shell command: ${error}` }, + { + status: 500, + } + ); } } diff --git a/onix-gui/onix/app/api/clonning-repo/route.js b/onix-gui/GUI/app/api/clonning-repo/route.js similarity index 100% rename from onix-gui/onix/app/api/clonning-repo/route.js rename to onix-gui/GUI/app/api/clonning-repo/route.js diff --git a/onix-gui/onix/app/api/install-bap/route.js b/onix-gui/GUI/app/api/install-bap/route.js similarity index 92% rename from onix-gui/onix/app/api/install-bap/route.js rename to onix-gui/GUI/app/api/install-bap/route.js index 9236941..2c5fb04 100644 --- a/onix-gui/onix/app/api/install-bap/route.js +++ b/onix-gui/GUI/app/api/install-bap/route.js @@ -47,7 +47,10 @@ export async function startSupportServices() { `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d redis_db` ); console.log("Result 3:", result3); - + await executeCommand("docker volume create registry_data_volume"); + await executeCommand("docker volume create registry_database_volume"); + await executeCommand("docker volume create gateway_data_volume"); + await executeCommand("docker volume create gateway_database_volume"); return NextResponse.json({ result1, result2, result3 }); } catch (error) { console.error("An error occurred:", error); @@ -91,10 +94,10 @@ export async function POST(req) { const bppSubscriberId = data.subscriberId; const bppSubscriberUrl = data.subscriberUrl; const networkconfigurl = data.networkconfigurl; + let updateBppConfigCommand = `bash ${pathDir}/install/scripts/update_bap_config.sh ${registryUrl} ${bppSubscriberId} ${bppSubscriberUrl} ${networkconfigurl}`; const result1 = await executeCommand(updateBppConfigCommand); console.log("Result 1:", result1); - const result3 = await executeCommand( `docker-compose -f ${pathDir}/install/docker-compose-v2.yml up -d "bap-client"` ); diff --git a/onix-gui/onix/app/api/install-bpp/route.js b/onix-gui/GUI/app/api/install-bpp/route.js similarity index 93% rename from onix-gui/onix/app/api/install-bpp/route.js rename to onix-gui/GUI/app/api/install-bpp/route.js index 9943be4..2ac5ca0 100644 --- a/onix-gui/onix/app/api/install-bpp/route.js +++ b/onix-gui/GUI/app/api/install-bpp/route.js @@ -47,7 +47,10 @@ export async function startSupportServices() { `docker-compose -f ${pathDir}/install/docker-compose-app.yml up -d redis_db` ); console.log("Result 3:", result3); - + await executeCommand("docker volume create registry_data_volume"); + await executeCommand("docker volume create registry_database_volume"); + await executeCommand("docker volume create gateway_data_volume"); + await executeCommand("docker volume create gateway_database_volume"); return NextResponse.json({ result1, result2, result3 }); } catch (error) { console.error("An error occurred:", error); diff --git a/onix-gui/onix/app/api/install-gateway/route.js b/onix-gui/GUI/app/api/install-gateway/route.js similarity index 93% rename from onix-gui/onix/app/api/install-gateway/route.js rename to onix-gui/GUI/app/api/install-gateway/route.js index 46b150b..3545f6e 100644 --- a/onix-gui/onix/app/api/install-gateway/route.js +++ b/onix-gui/GUI/app/api/install-gateway/route.js @@ -64,7 +64,8 @@ export async function POST(req, res) { `bash ${pathDir}/install/scripts/package_manager.sh` ); console.log("Result 1:", result1); - + await executeCommand("docker volume create registry_data_volume"); + await executeCommand("docker volume create registry_database_volume"); const result2 = await executeCommand( ` bash ${pathDir}/install/scripts/update_gateway_details.sh ${data.registryUrl} ${data.gatewayUrl}` ); @@ -75,7 +76,7 @@ export async function POST(req, res) { ); console.log("Result 3:", result3); - const result4 = await executeCommand(`sleep 10`); + const result4 = await executeCommand(`sleep 2`); console.log("Result 4:", result4); const result5 = await executeCommand( diff --git a/onix-gui/GUI/app/api/install-layer2/route.js b/onix-gui/GUI/app/api/install-layer2/route.js new file mode 100644 index 0000000..c795226 --- /dev/null +++ b/onix-gui/GUI/app/api/install-layer2/route.js @@ -0,0 +1,38 @@ +import { exec } from "child_process"; +import { NextResponse } from "next/server"; + +export async function POST(req) { + const request = await req.json(); + const fileURL = request.yamlUrl; + const containerName = request.container; + + const executeShellCommand = (command) => { + return new Promise((resolve, reject) => { + exec(command, (error, stdout, stderr) => { + if (error) { + console.error("Error:", error); + reject(error); + return; + } + if (stderr) { + console.error("Error:", stderr); + reject(new Error(stderr)); + return; + } + const output = stdout; + console.log("Output:", output); + resolve(output); + }); + }); + }; + + try { + await executeShellCommand( + `docker exec ${containerName} wget -P /usr/src/app/schemas/ ${fileURL}` + ); + return NextResponse.json({ status: 200 }); + } catch (error) { + console.error(`exec error: ${error}`); + return NextResponse.json({ status: 500 }); + } +} diff --git a/onix-gui/onix/app/api/install-registry/route.js b/onix-gui/GUI/app/api/install-registry/route.js similarity index 85% rename from onix-gui/onix/app/api/install-registry/route.js rename to onix-gui/GUI/app/api/install-registry/route.js index fbffb7b..70c4102 100644 --- a/onix-gui/onix/app/api/install-registry/route.js +++ b/onix-gui/GUI/app/api/install-registry/route.js @@ -111,6 +111,20 @@ export async function POST(req, res) { await fs.writeFile(tempFile, updatedConfigData); await fs.rename(tempFile, configFile); + await executeCommand("docker volume create registry_data_volume"); + await executeCommand("docker volume create registry_database_volume"); + await executeCommand("docker volume create gateway_data_volume"); + await executeCommand("docker volume create gateway_database_volume"); + await executeCommand( + `docker run --rm -v ${join( + pathDir, + "install", + "registry_data", + "config" + )}:/source -v registry_data_volume:/target busybox sh -c "cp /source/envvars /target/ && cp /source/logger.properties /target/ && cp /source/swf.properties /target/"` + ); + + // Start the registry container await executeCommand( `docker-compose -f ${join( pathDir, diff --git a/onix-gui/onix/app/favicon.ico b/onix-gui/GUI/app/favicon.ico similarity index 100% rename from onix-gui/onix/app/favicon.ico rename to onix-gui/GUI/app/favicon.ico diff --git a/onix-gui/onix/app/globals.css b/onix-gui/GUI/app/globals.css similarity index 100% rename from onix-gui/onix/app/globals.css rename to onix-gui/GUI/app/globals.css diff --git a/onix-gui/onix/app/install/configure/page.js b/onix-gui/GUI/app/install/configure/page.js similarity index 85% rename from onix-gui/onix/app/install/configure/page.js rename to onix-gui/GUI/app/install/configure/page.js index f0749f9..4da2300 100644 --- a/onix-gui/onix/app/install/configure/page.js +++ b/onix-gui/GUI/app/install/configure/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; - +import Image from "next/image"; const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -28,7 +28,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

Gateway

@@ -37,7 +37,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

BAP Adapter

@@ -46,7 +46,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

BPP Adapter

diff --git a/onix-gui/onix/app/install/create/page.js b/onix-gui/GUI/app/install/create/page.js similarity index 84% rename from onix-gui/onix/app/install/create/page.js rename to onix-gui/GUI/app/install/create/page.js index 14e38e6..0cf9db7 100644 --- a/onix-gui/onix/app/install/create/page.js +++ b/onix-gui/GUI/app/install/create/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; - +import Image from "next/image"; const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -28,7 +28,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

Gateway

@@ -37,7 +37,7 @@ export default function Home() { className={styles.box} style={{ textDecoration: "underline", color: "white" }} > - + arrow

BAP Adapter

@@ -46,7 +46,7 @@ export default function Home() { className={styles.box} style={{ textDecoration: "underline", color: "white" }} > - + arrow

BPP Adapter

@@ -55,7 +55,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

Registry

diff --git a/onix-gui/onix/app/install/join/page.js b/onix-gui/GUI/app/install/join/page.js similarity index 86% rename from onix-gui/onix/app/install/join/page.js rename to onix-gui/GUI/app/install/join/page.js index 5223af5..619e14b 100644 --- a/onix-gui/onix/app/install/join/page.js +++ b/onix-gui/GUI/app/install/join/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; - +import Image from "next/image"; const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -32,7 +32,7 @@ export default function Home() { }} >
- + arrow

Gateway

@@ -44,7 +44,7 @@ export default function Home() { }} >
- + arrow

BAP Adapter

@@ -56,7 +56,7 @@ export default function Home() { }} >
- + arrow

BPP Adapter

diff --git a/onix-gui/onix/app/install/local/page.js b/onix-gui/GUI/app/install/local/page.js similarity index 85% rename from onix-gui/onix/app/install/local/page.js rename to onix-gui/GUI/app/install/local/page.js index a698588..7dbd607 100644 --- a/onix-gui/onix/app/install/local/page.js +++ b/onix-gui/GUI/app/install/local/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; - +import Image from "next/image"; const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -30,7 +30,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

Gateway

@@ -39,7 +39,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

BAP Adapter

@@ -48,7 +48,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

BPP Adapter

diff --git a/onix-gui/onix/app/install/merge/page.js b/onix-gui/GUI/app/install/merge/page.js similarity index 76% rename from onix-gui/onix/app/install/merge/page.js rename to onix-gui/GUI/app/install/merge/page.js index 7e256d9..7391660 100644 --- a/onix-gui/onix/app/install/merge/page.js +++ b/onix-gui/GUI/app/install/merge/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; - +import Image from "next/image"; const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -15,7 +15,12 @@ export default function Home() { <>
- +

Merge multiple networks

- + arrow

Gateway

@@ -32,7 +37,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

BAP

@@ -41,7 +46,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

BPP

diff --git a/onix-gui/onix/app/install/page.js b/onix-gui/GUI/app/install/page.js similarity index 56% rename from onix-gui/onix/app/install/page.js rename to onix-gui/GUI/app/install/page.js index e104190..a196231 100644 --- a/onix-gui/onix/app/install/page.js +++ b/onix-gui/GUI/app/install/page.js @@ -3,7 +3,7 @@ import Link from "next/link"; import styles from "../page.module.css"; import { Ubuntu_Mono } from "next/font/google"; - +import Image from "next/image"; const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -33,7 +33,7 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

Join an existing network

@@ -42,39 +42,10 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

Create new production network

- -
- -

- Set up a network on your local machine -

-
- - {/* -
- -

Merge multiple networks

-
- - -
- -

Configure Existing Network

-
- */}
diff --git a/onix-gui/onix/app/layout.js b/onix-gui/GUI/app/layout.js similarity index 100% rename from onix-gui/onix/app/layout.js rename to onix-gui/GUI/app/layout.js diff --git a/onix-gui/onix/app/page.js b/onix-gui/GUI/app/page.js similarity index 81% rename from onix-gui/onix/app/page.js rename to onix-gui/GUI/app/page.js index 33f3594..600fc62 100644 --- a/onix-gui/onix/app/page.js +++ b/onix-gui/GUI/app/page.js @@ -1,7 +1,7 @@ import Link from "next/link"; import styles from "./page.module.css"; import { Ubuntu_Mono } from "next/font/google"; - +import Image from "next/image"; const ubuntuMono = Ubuntu_Mono({ weight: "400", style: "normal", @@ -25,25 +25,25 @@ export default function Home() { style={{ textDecoration: "underline", color: "white" }} >
- + arrow

Installation Wizard

-
- + arrow

Network Monitor

- + */}
- + arrow

Layer 2 Tester

diff --git a/onix-gui/onix/app/page.module.css b/onix-gui/GUI/app/page.module.css similarity index 100% rename from onix-gui/onix/app/page.module.css rename to onix-gui/GUI/app/page.module.css diff --git a/onix-gui/onix/app/setup/bap/page.js b/onix-gui/GUI/app/setup/bap/page.js similarity index 98% rename from onix-gui/onix/app/setup/bap/page.js rename to onix-gui/GUI/app/setup/bap/page.js index ff4b4f8..2613e6e 100644 --- a/onix-gui/onix/app/setup/bap/page.js +++ b/onix-gui/GUI/app/setup/bap/page.js @@ -117,7 +117,7 @@ export default function Home() { />
- + {/* */}
- + {/* */}
- + {/* */}
diff --git a/onix-gui/onix/app/setup/registry/page.js b/onix-gui/GUI/app/setup/registry/page.js similarity index 97% rename from onix-gui/onix/app/setup/registry/page.js rename to onix-gui/GUI/app/setup/registry/page.js index 8bc57c2..6fce954 100644 --- a/onix-gui/onix/app/setup/registry/page.js +++ b/onix-gui/GUI/app/setup/registry/page.js @@ -85,7 +85,7 @@ export default function Home() { onChange={handleRegistryUrlChange} />
- + {/* */}
diff --git a/onix-gui/onix/app/template.csv b/onix-gui/GUI/app/template.csv similarity index 100% rename from onix-gui/onix/app/template.csv rename to onix-gui/GUI/app/template.csv diff --git a/onix-gui/GUI/app/yaml-gen/install-yaml/page.js b/onix-gui/GUI/app/yaml-gen/install-yaml/page.js new file mode 100644 index 0000000..22ad80c --- /dev/null +++ b/onix-gui/GUI/app/yaml-gen/install-yaml/page.js @@ -0,0 +1,105 @@ +"use client"; +import SecondaryButton from "@/components/Buttons/SecondaryButton"; +import styles from "../../page.module.css"; +import { Ubuntu_Mono } from "next/font/google"; +import Slider from "@/components/Slider/Slider"; +import PrimaryButton from "@/components/Buttons/PrimaryButton"; +import InputField from "@/components/InputField/InputField"; +import { useState, useCallback } from "react"; +import { toast } from "react-toastify"; + +const ubuntuMono = Ubuntu_Mono({ + weight: "400", + style: "normal", + subsets: ["latin"], +}); + +export default function InstallYaml() { + const [yamlUrl, setYamlUrl] = useState(""); + const [checked, setChecked] = useState(false); + + const container = checked ? "bpp-network" : "bap-network"; + + const handleRegistryUrlChange = (event) => { + setYamlUrl(event.target.value); + }; + + const installYaml = useCallback(async () => { + const toastId = toast.loading("Installing Layer 2 Config file..."); + + try { + const response = await fetch("/api/install-layer2", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ container, yamlUrl }), + }); + + if (response.ok) { + const data = await response.json(); + console.log(data); + const FileFound = data.message; + if (FileFound == false) { + setShowDownloadLayer2Button(true); + toast.update(toastId, { + render: "No Layer 2 Config Present 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } else { + toast.update(toastId, { + render: "Yaml File Present 👌", + type: "success", + isLoading: false, + autoClose: 5000, + }); + } + } else { + console.error("Failed to check yaml"); + toast.update(toastId, { + render: "Container Not Found 🤯", + type: "error", + isLoading: false, + autoClose: 5000, + }); + } + } catch (error) { + console.error("An error occurred:", error); + } + }); + + return ( + <> +
+
+ +

Install Yaml

+
+ + +
+ {/* */} + +
+
+
+
+ + ); +} diff --git a/onix-gui/onix/app/yaml-gen/check-yaml/page.js b/onix-gui/GUI/app/yaml-gen/page.js similarity index 59% rename from onix-gui/onix/app/yaml-gen/check-yaml/page.js rename to onix-gui/GUI/app/yaml-gen/page.js index 4ebbcf6..937fa35 100644 --- a/onix-gui/onix/app/yaml-gen/check-yaml/page.js +++ b/onix-gui/GUI/app/yaml-gen/page.js @@ -4,8 +4,9 @@ import { Ubuntu_Mono } from "next/font/google"; import PrimaryButton from "@/components/Buttons/PrimaryButton"; import InputField from "@/components/InputField/InputField"; import Slider from "@/components/Slider/Slider"; -import styles from "../../page.module.css"; +import styles from "../page.module.css"; import { toast } from "react-toastify"; + import Link from "next/link"; const ubuntuMono = Ubuntu_Mono({ @@ -15,14 +16,37 @@ const ubuntuMono = Ubuntu_Mono({ }); export default function CheckYaml() { + const [domainName, setDomainName] = useState(""); + const [versionNumber, setversionNumber] = useState(""); const [checked, setChecked] = useState(false); + const [showDownloadLayer2Button, setShowDownloadLayer2Button] = + useState(false); const [propertyLink, setPropertyLink] = useState(""); const handleYamlChange = (event) => { setPropertyLink(event.target.value); }; + const handledomainNameChange = (event) => { + setDomainName(event.target.value); + }; + const handleVersionChange = (event) => { + setversionNumber(event.target.value); + }; + const nameGenerator = async () => { + const parts = domainName.split(":"); + const domainNameWithoutVersion = parts[0]; + let filename; + if (parts[1] === undefined || parts[1] === "") { + filename = `${domainNameWithoutVersion}_${versionNumber}.yaml`; + } else { + filename = `${domainNameWithoutVersion}_${parts[1]}_${versionNumber}.yaml`; + } + console.log(filename); + return filename; + }; const handleOnclick = async () => { + const fileName = await nameGenerator(); const toastId = toast.loading("Checking for layer2 yaml file"); try { const response = await fetch("/api/check-layer2", { @@ -30,14 +54,14 @@ export default function CheckYaml() { headers: { "Content-Type": "application/json", }, - body: JSON.stringify({ checked }), + body: JSON.stringify({ checked, fileName }), }); if (response.ok) { const data = await response.json(); - const yamlFile = data; - console.log("YAML", yamlFile); - if (yamlFile == 0) { + const FileFound = data.message; + if (FileFound == false) { + setShowDownloadLayer2Button(true); toast.update(toastId, { render: "No Layer 2 Config Present 🤯", type: "error", @@ -89,16 +113,29 @@ export default function CheckYaml() { + + - {/* */}
- +
+ {showDownloadLayer2Button && ( + + )}
diff --git a/onix-gui/onix/components/Buttons/Buttons.module.css b/onix-gui/GUI/components/Buttons/Buttons.module.css similarity index 100% rename from onix-gui/onix/components/Buttons/Buttons.module.css rename to onix-gui/GUI/components/Buttons/Buttons.module.css diff --git a/onix-gui/onix/components/Buttons/PrimaryButton.js b/onix-gui/GUI/components/Buttons/PrimaryButton.js similarity index 100% rename from onix-gui/onix/components/Buttons/PrimaryButton.js rename to onix-gui/GUI/components/Buttons/PrimaryButton.js diff --git a/onix-gui/onix/components/Buttons/SecondaryButton.jsx b/onix-gui/GUI/components/Buttons/SecondaryButton.jsx similarity index 100% rename from onix-gui/onix/components/Buttons/SecondaryButton.jsx rename to onix-gui/GUI/components/Buttons/SecondaryButton.jsx diff --git a/onix-gui/onix/components/InputField/InputField.jsx b/onix-gui/GUI/components/InputField/InputField.jsx similarity index 76% rename from onix-gui/onix/components/InputField/InputField.jsx rename to onix-gui/GUI/components/InputField/InputField.jsx index e20ce98..aac6551 100644 --- a/onix-gui/onix/components/InputField/InputField.jsx +++ b/onix-gui/GUI/components/InputField/InputField.jsx @@ -1,12 +1,12 @@ import React from "react"; import styles from "./InputField.module.css"; -const InputField = ({ label, value, onChange }) => { +const InputField = ({ label, value, onChange, placeholder = "Input Text" }) => { return (
{ - const data = [ - { - ip: "192.168.1.1", - status: "Live", - cpu: "2%", - memory: "18.8 MB", - uptime: "10 days", - }, - { - ip: "10.0.0.1", - status: "404", - cpu: "0%", - memory: "0 MB", - uptime: "5 days", - }, - { - ip: "172.16.0.1", - status: "Live", - cpu: "6%", - memory: "56.4 MB", - uptime: "15 days", - }, - { - ip: "192.0.2.1", - status: "Live", - cpu: "69%", - memory: "648.6 MB", - uptime: "20 days", - }, - { - ip: "198.51.100.1", - status: "404", - cpu: "0%", - memory: "0 MB", - uptime: "3 days", - }, - { - ip: "203.0.113.1", - status: "Live", - cpu: ".4%", - memory: "3.7 MB", - uptime: "8 days", - }, - ]; - return ( -
-
-

- Uptime Network Participants: 10 -

-

- Uptime Network Participants: 10 -

-
-

Dashboard

- - - - - - - - - - - - {data.map((item, index) => ( - - - - - - - - ))} - -
S/NIP / Domain NameStatusCPUMemory
{index + 1}{item.ip}{item.status}{item.cpu}{item.memory}
-
- ); -}; - -export default page; diff --git a/onix-gui/onix/app/monitor/page.js b/onix-gui/onix/app/monitor/page.js deleted file mode 100644 index 5e042e2..0000000 --- a/onix-gui/onix/app/monitor/page.js +++ /dev/null @@ -1,74 +0,0 @@ -"use client"; -import { useState } from "react"; -import InputField from "@/components/InputField/InputField"; -import styles from "../page.module.css"; -import { Ubuntu_Mono } from "next/font/google"; -import SecondaryButton from "@/components/Buttons/SecondaryButton"; -import PrimaryButton from "@/components/Buttons/PrimaryButton"; -import { useRouter } from "next/navigation"; -const ubuntuMono = Ubuntu_Mono({ - weight: "400", - style: "normal", - subsets: ["latin"], -}); - -export default function Home() { - const [registryUrl, setRegistryUrl] = useState(""); - const router = useRouter(); - const handleRegistryUrlChange = (event) => { - setRegistryUrl(event.target.value); - }; - const handleContinue = async () => { - try { - const response = await fetch("/api/get-network-participant", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ registryUrl }), - }); - - if (response.ok) { - const networkParticipantsData = await response.json(); - router.push("/monitor/dashboard"); - // redirecting to the dashboard page - } else { - console.log("error fetching participant data"); - } - } catch (error) { - console.error("Error:", error); - } - }; - - return ( - <> -
-
- - {/*

ONIX{pathname}

*/} -

Network Registry

-
- - {/* */} - {/* */} - {/* */} - -
- {/* */} - -
-
-
-
- - ); -} diff --git a/onix-gui/onix/app/yaml-gen/option/bap/page.js b/onix-gui/onix/app/yaml-gen/option/bap/page.js deleted file mode 100644 index 974a6a9..0000000 --- a/onix-gui/onix/app/yaml-gen/option/bap/page.js +++ /dev/null @@ -1,64 +0,0 @@ -"use client"; - -import InputField from "@/components/InputField/InputField"; -import styles from "../../../page.module.css"; -import { Ubuntu_Mono } from "next/font/google"; -import SecondaryButton from "@/components/Buttons/SecondaryButton"; -import PrimaryButton from "@/components/Buttons/PrimaryButton"; -import { usePathname } from "next/navigation"; -import { useState, useCallback } from "react"; -import Slider from "@/components/Slider/Slider" - -const ubuntuMono = Ubuntu_Mono({ - weight: "400", - style: "normal", - subsets: ["latin"], -}); - - -export default function Bap() { - - const [checked, setChecked] = useState(false); - const [propertyName, setPropertyName] = useState(""); - const [propertyLink, setPropertyLink] = useState(""); - const [propertyOption, setPropertyOption] = useState(""); - - return ( - <> -
-
-

BAP

-
- - - - - - - -
- - -
-
-
-
- - ) -} \ No newline at end of file diff --git a/onix-gui/onix/app/yaml-gen/option/bpp/page.js b/onix-gui/onix/app/yaml-gen/option/bpp/page.js deleted file mode 100644 index c4ff616..0000000 --- a/onix-gui/onix/app/yaml-gen/option/bpp/page.js +++ /dev/null @@ -1,64 +0,0 @@ -"use client"; - -import InputField from "@/components/InputField/InputField"; -import styles from "../../../page.module.css"; -import { Ubuntu_Mono } from "next/font/google"; -import SecondaryButton from "@/components/Buttons/SecondaryButton"; -import PrimaryButton from "@/components/Buttons/PrimaryButton"; -import { usePathname } from "next/navigation"; -import { useState, useCallback } from "react"; -import Slider from "@/components/Slider/Slider" - -const ubuntuMono = Ubuntu_Mono({ - weight: "400", - style: "normal", - subsets: ["latin"], -}); - - -export default function Bpp() { - - const [checked, setChecked] = useState(false); - const [propertyName, setPropertyName] = useState(""); - const [propertyLink, setPropertyLink] = useState(""); - const [propertyOption, setPropertyOption] = useState(""); - - return ( - <> -
-
-

BPP

-
- - - - - - - -
- - -
-
-
-
- - ) -} \ No newline at end of file diff --git a/onix-gui/onix/app/yaml-gen/option/page.js b/onix-gui/onix/app/yaml-gen/option/page.js deleted file mode 100644 index b8a9b35..0000000 --- a/onix-gui/onix/app/yaml-gen/option/page.js +++ /dev/null @@ -1,43 +0,0 @@ -import Link from "next/link"; -import styles from "../../page.module.css"; -import { Ubuntu_Mono } from "next/font/google"; - -const ubuntuMono = Ubuntu_Mono({ - weight: "400", - style: "normal", - subsets: ["latin"], -}); - - -export default function Option() { - return ( - <> -
-
-

Yaml File Generator

-
- -
- -

BAP

-
- - -
- -

BPP

-
- -
- -
-
- - ) -} \ No newline at end of file diff --git a/onix-gui/onix/app/yaml-gen/page.js b/onix-gui/onix/app/yaml-gen/page.js deleted file mode 100644 index 1fcf514..0000000 --- a/onix-gui/onix/app/yaml-gen/page.js +++ /dev/null @@ -1,122 +0,0 @@ -import Link from "next/link"; -import styles from "../page.module.css"; -import { Ubuntu_Mono } from "next/font/google"; -import btnstyles from "@/components/Buttons/Buttons.module.css"; -const ubuntuMono = Ubuntu_Mono({ - weight: "400", - style: "normal", - subsets: ["latin"], -}); - -export default function YamlGen() { - return ( - <> -
-
-

- Yaml File Generator -

-
- -
- -

Search

-
- - -
- -

Select

-
- - -
- -

Init

-
- - -
- -

Confirm

-
- - -
- -

Status

-
- -
-
- -
- -

Track

-
- - -
- -

Cancel

-
- - -
- -

Update

-
- - -
- -

Rating

-
- - -
- -

Support

-
- -
-
- -
- - ); -} diff --git a/onix-gui/onix/next.config.mjs b/onix-gui/onix/next.config.mjs deleted file mode 100644 index 4678774..0000000 --- a/onix-gui/onix/next.config.mjs +++ /dev/null @@ -1,4 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = {}; - -export default nextConfig; diff --git a/onix-gui/start.sh b/onix-gui/start.sh index ac2ecd3..4bc740b 100755 --- a/onix-gui/start.sh +++ b/onix-gui/start.sh @@ -1,7 +1,7 @@ #!/bin/bash # Set script variables -PROJECT_DIR="onix" +PROJECT_DIR="GUI" PORT=3005 TUNNEL_SERVICE="lt" @@ -14,6 +14,7 @@ echo "installing Dependencies" echo "Building and starting Next.js app..." npx next build && echo "Builing Web App = True" +sleep 3 npx next start -p "$PORT" > /dev/null 2>&1 & # Wait for the Next.js app to start From 1c2b9a4b8516757d7b9a5c2f8c47a76299ec67ed Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Fri, 3 May 2024 11:12:47 +0530 Subject: [PATCH 053/102] updated docs --- onix-gui/GUI/README.md | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/onix-gui/GUI/README.md b/onix-gui/GUI/README.md index 5453b9b..26cf942 100644 --- a/onix-gui/GUI/README.md +++ b/onix-gui/GUI/README.md @@ -6,28 +6,23 @@ The GUI for the beckn-onix cli tool. 1. 4 server/instances 2. 4 sub-domains mapped to each instance +3. Local Tunnel + `npm i -g localtunnel` ## User Guide -### Step 1: Clone the beckn-onix-gui repo +### Step 1: Run the `start.sh` script ``` -git clone https://github.com/Mishalabdullah/beckn-onix-gui.git +cd .. && ./start.sh ``` -### Step 2: Change directory to the nextjs project +### Step 2: Accessing the GUI. -``` -cd onix-gui -``` - -### Step 3: Run nextjs on port 3005 +You will be getting a URL and password as on output of the script. Open the url in the browser and then +paste the password. -For running the installation script just run this command. The sudo privilages are required when installing packages and configuring the nginx reverse proxy - -``` -sudo ./start.sh -``` +### Step 3: Install and setup your network Note: Port 3000 is being used by onix, so we're using port 3005 instead. @@ -47,6 +42,16 @@ Contributions are welcome! If you'd like to contribute to the beckn-onix-gui pro The beckn-onix-gui project is licensed under the MIT License. See the LICENSE file for more information. + ## Contact If you have any questions or issues with the beckn-onix-gui project, please don't hesitate to reach out. + +### Made with ❤️ + +built by the [Mulearn Team](https://mulearn.org/) +1. [Mishal Abdullah](https://github.com/Mishalabdullah/) +2. [Aswin Asok](https://github.com/AswinAsok) +3. [Viraj Prabhu ](https://github.com/viraka) +4. [Adasrsh](https://adarshmohanks.framer.website/) + From 735f2a3c1ffc5869ef545f0b7a0a3eadee3bd73e Mon Sep 17 00:00:00 2001 From: MishalAbdullah <85678545+Mishalabdullah@users.noreply.github.com> Date: Fri, 3 May 2024 16:05:24 +0530 Subject: [PATCH 054/102] v.04 --- onix-gui/start.sh | 52 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/onix-gui/start.sh b/onix-gui/start.sh index 4bc740b..b30f10d 100755 --- a/onix-gui/start.sh +++ b/onix-gui/start.sh @@ -1,5 +1,40 @@ #!/bin/bash +# Installing dependencies + +sudo apt-get update +sudo apt-get install ca-certificates curl + +sudo install -m 0755 -d /etc/apt/keyrings +sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc +sudo chmod a+r /etc/apt/keyrings/docker.asc + +# Add the repository to Apt sources: +echo \ +"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \ +$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \ +sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + +sudo apt-get update +sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin + +sudo curl -L https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m) -o /usr/local/bin/docker-compose +sudo chmod +x /usr/local/bin/docker-compose + +echo "installing node" +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash && +source ~/.bashrc && +export NVM_DIR="$HOME/.nvm" +[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm +[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion +nvm install Iron && +npm i -g localtunnel && + +# Add user to the docker group and apply permissions +sudo groupadd docker +sudo usermod -aG docker $USER +newgrp docker + # Set script variables PROJECT_DIR="GUI" PORT=3005 @@ -7,27 +42,21 @@ TUNNEL_SERVICE="lt" # Change to the project directory cd "$PROJECT_DIR" || exit + npm i && + # Build and start the Next.js app echo "installing Dependencies" - echo "Building and starting Next.js app..." npx next build && echo "Builing Web App = True" sleep 3 -npx next start -p "$PORT" > /dev/null 2>&1 & +npx next start -p "$PORT" & # Wait for the Next.js app to start -echo "Waiting for Next.js app to start on port $PORT..." -until nc -z localhost "$PORT"; do - sleep 1 - echo "Loding ..." -done # Install the tunnel service if not installed - - - +sleep 3 echo "Exposing local port $PORT using $TUNNEL_SERVICE..." lt --port "$PORT" > /tmp/lt.log 2>&1 & @@ -37,9 +66,10 @@ sleep 5 # Get the tunnel URL from the log file TUNNEL_URL=$(grep -o 'https://[^[:blank:]]*' /tmp/lt.log) + #Get the tunnel password echo "Getting Tunnel Password" -TUNNEL_PASSWORD=$(curl https://loca.lt/mytunnelpassword)&& +TUNNEL_PASSWORD=$(curl https://loca.lt/mytunnelpassword) && # Print the tunnel URL and password echo "---------------------------------------" From a94aab399eda1a731c426903d93ae544feaffbf7 Mon Sep 17 00:00:00 2001 From: MishalAbdullah <85678545+Mishalabdullah@users.noreply.github.com> Date: Fri, 3 May 2024 16:11:29 +0530 Subject: [PATCH 055/102] v0.5 --- onix-gui/start.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/onix-gui/start.sh b/onix-gui/start.sh index b30f10d..aff7e00 100755 --- a/onix-gui/start.sh +++ b/onix-gui/start.sh @@ -31,9 +31,9 @@ nvm install Iron && npm i -g localtunnel && # Add user to the docker group and apply permissions -sudo groupadd docker -sudo usermod -aG docker $USER -newgrp docker +sudo groupadd docker & +sudo usermod -aG docker $USER & +newgrp docker & # Set script variables PROJECT_DIR="GUI" From 927ae616b5feffe44ac3de84a90a9dfb321ee165 Mon Sep 17 00:00:00 2001 From: MishalAbdullah <85678545+Mishalabdullah@users.noreply.github.com> Date: Fri, 3 May 2024 16:42:36 +0530 Subject: [PATCH 056/102] Update start.sh --- onix-gui/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onix-gui/start.sh b/onix-gui/start.sh index aff7e00..fa3073d 100755 --- a/onix-gui/start.sh +++ b/onix-gui/start.sh @@ -42,7 +42,7 @@ TUNNEL_SERVICE="lt" # Change to the project directory cd "$PROJECT_DIR" || exit - +nvm use 20 && npm i && # Build and start the Next.js app From 0a41c020708eb3e0a3287211692282b4bba6e04b Mon Sep 17 00:00:00 2001 From: MishalAbdullah <85678545+Mishalabdullah@users.noreply.github.com> Date: Fri, 3 May 2024 16:56:04 +0530 Subject: [PATCH 057/102] v 2 --- onix-gui/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/onix-gui/start.sh b/onix-gui/start.sh index fa3073d..8ffc509 100755 --- a/onix-gui/start.sh +++ b/onix-gui/start.sh @@ -27,7 +27,7 @@ source ~/.bashrc && export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh" # This loads nvm [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion" # This loads nvm bash_completion -nvm install Iron && +nvm install 20 && npm i -g localtunnel && # Add user to the docker group and apply permissions From de28cfcbcfb80d8a084cf6b80cf02984b72cb110 Mon Sep 17 00:00:00 2001 From: MishalAbdullah <85678545+Mishalabdullah@users.noreply.github.com> Date: Fri, 3 May 2024 17:07:07 +0530 Subject: [PATCH 058/102] Create REAME.md --- onix-gui/REAME.md | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 onix-gui/REAME.md diff --git a/onix-gui/REAME.md b/onix-gui/REAME.md new file mode 100644 index 0000000..339f6dc --- /dev/null +++ b/onix-gui/REAME.md @@ -0,0 +1,77 @@ +# Beckn-Onix Installation Wizard + + + +The below provides an overview of the installation wizard and layer 2 tester & downloader features of Beckn-Onix. Follow the steps outlined below to successfully utilize these features. + + + +### Home Page + +- Visit the home page of the Beckn-Onix installation wizard. + + + +![Home Page](https://github.com/beckn/beckn-onix/assets/85678545/e8674a29-b6e2-4fb2-a5ad-c76166bf1174) + + + +### Installation Wizard + +- Navigate to the installation wizard section. + +- Fill in the required details as prompted. + + + +![Installation Wizard](https://github.com/beckn/beckn-onix/assets/85678545/e9cec587-299f-4793-9045-c7c01551ad51) + + + +### Continue Installation + +- Click on the "Continue" button to proceed with the installation. + +- Repeat the same process for all components. + + + +## Layer 2 + + + +![Layer 2](https://github.com/beckn/beckn-onix/assets/85678545/32978858-5303-43b2-b0b5-517ee98ec6c3) + + + +### Setup Configuration File + +- Select whether you want to set up the layer 2 config file in BAP or BPP. + +- Fill in the Domain and version number of the layer 2 config file. + + + +### Check File Presence + +- If the file is present, a success toast will be displayed. + +- If the file is not present, a link for downloading the layer 2 file to the protocol server will be provided. + + + +![Check File Presence](https://github.com/beckn/beckn-onix/assets/85678545/31aaf210-9fef-4c33-b651-7231cd900f0a) + + + +### Download File + +- Click on the download link to be redirected to another page for downloading. + +- Paste the YAML file URL and click "Continue". + +- If successful, a success toast will be displayed. If unsuccessful, an error toast will be shown. + + + +![Download File](https://github.com/beckn/beckn-onix/assets/85678545/0dd9d456-66ca-4e2a-abc1-ba8dd98719c1) From baf46b7746ae39d791256e5e6d1771a441b0588b Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Sun, 5 May 2024 14:18:14 +0530 Subject: [PATCH 059/102] updated unique key value --- onix-gui/GUI/app/api/install-bap/route.js | 10 ++++++---- onix-gui/GUI/app/api/install-bpp/route.js | 13 +++++-------- onix-gui/GUI/next.config.mjs | 4 ++++ 3 files changed, 15 insertions(+), 12 deletions(-) create mode 100644 onix-gui/GUI/next.config.mjs diff --git a/onix-gui/GUI/app/api/install-bap/route.js b/onix-gui/GUI/app/api/install-bap/route.js index 2c5fb04..3bad4fb 100644 --- a/onix-gui/GUI/app/api/install-bap/route.js +++ b/onix-gui/GUI/app/api/install-bap/route.js @@ -91,12 +91,14 @@ export async function POST(req) { const data = await req.json(); const registryUrl = data.registryUrl; - const bppSubscriberId = data.subscriberId; - const bppSubscriberUrl = data.subscriberUrl; + const bapSubscriberId = data.subscriberId; + const bapSubscriberUrl = data.subscriberUrl; const networkconfigurl = data.networkconfigurl; + // generating unqiuekey for bap subscriberId + const uniqueKeyId = bapSubscriberId + "-key"; - let updateBppConfigCommand = `bash ${pathDir}/install/scripts/update_bap_config.sh ${registryUrl} ${bppSubscriberId} ${bppSubscriberUrl} ${networkconfigurl}`; - const result1 = await executeCommand(updateBppConfigCommand); + let updateBapConfigCommand = `bash ${pathDir}/install/scripts/update_bap_config.sh ${registryUrl} ${bapSubscriberId} ${uniqueKeyId} ${bapSubscriberUrl} ${networkconfigurl}`; + const result1 = await executeCommand(updateBapConfigCommand); console.log("Result 1:", result1); const result3 = await executeCommand( `docker-compose -f ${pathDir}/install/docker-compose-v2.yml up -d "bap-client"` diff --git a/onix-gui/GUI/app/api/install-bpp/route.js b/onix-gui/GUI/app/api/install-bpp/route.js index 2ac5ca0..49c2e80 100644 --- a/onix-gui/GUI/app/api/install-bpp/route.js +++ b/onix-gui/GUI/app/api/install-bpp/route.js @@ -89,18 +89,15 @@ export async function POST(req, res) { try { await startSupportServices(); - const data = req.json(); + const data = await req.json(); const registryUrl = data.registryUrl; const bppSubscriberId = data.subscriberId; const bppSubscriberUrl = data.subscriberUrl; const webhookUrl = data.webhookUrl; - // const webhookUrl = "https://unified-bpp.becknprotocol.io/beckn-bpp-adapter"; - - // let updateBppConfigCommand = "bash scripts/update_bpp_config.sh"; - // if (registryUrl) { - // updateBppConfigCommand += ``; - // } - let updateBppConfigCommand = `bash ${pathDir}/install/scripts/update_bpp_config.sh ${registryUrl} ${bppSubscriberId} ${bppSubscriberUrl} ${webhookUrl}`; + // generating unqiuekey for bpp subscriberId + const uniqueKeyId = bppSubscriberId + "-key"; + let updateBppConfigCommand = `bash ${pathDir}/install/scripts/update_bpp_config.sh ${registryUrl} ${bppSubscriberId} ${uniqueKeyId} ${bppSubscriberUrl} ${webhookUrl}`; + console.log("Update BPP Config Command:", updateBppConfigCommand); const result1 = await executeCommand(updateBppConfigCommand); console.log("Result 1:", result1); diff --git a/onix-gui/GUI/next.config.mjs b/onix-gui/GUI/next.config.mjs new file mode 100644 index 0000000..4678774 --- /dev/null +++ b/onix-gui/GUI/next.config.mjs @@ -0,0 +1,4 @@ +/** @type {import('next').NextConfig} */ +const nextConfig = {}; + +export default nextConfig; From 1c681e88f68a74817793481e7b2a9dc3508a7979 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Sun, 5 May 2024 14:23:40 +0530 Subject: [PATCH 060/102] removing the -t flag not required --- install/scripts/generate_keys.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/install/scripts/generate_keys.sh b/install/scripts/generate_keys.sh index f887fcf..fef5952 100755 --- a/install/scripts/generate_keys.sh +++ b/install/scripts/generate_keys.sh @@ -5,7 +5,7 @@ source $SCRIPT_DIR/variables.sh # Run the script that generates keys and capture the output get_keys() { docker pull fidedocker/protocol-server > /dev/null 2>&1 - docker run --name temp -itd fidedocker/protocol-server > /dev/null 2>&1 + docker run --name temp -i fidedocker/protocol-server > /dev/null 2>&1 output=$(docker exec -it temp node /usr/src/app/scripts/generate-keys 2>&1) docker stop temp > /dev/null 2>&1 docker rm temp > /dev/null 2>&1 @@ -24,4 +24,4 @@ else fi } -#get_keys \ No newline at end of file +#get_keys From 766c741a650c82dae66d1d097eea65c93b0e64f5 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Sun, 5 May 2024 15:45:20 +0530 Subject: [PATCH 061/102] cleaning & udpated generate keys.sh --- install/scripts/generate_keys.sh | 4 ++-- onix-gui/GUI/app/api/install-bpp/route.js | 1 - onix-gui/GUI/app/yaml-gen/install-yaml/page.js | 2 +- onix-gui/GUI/app/yaml-gen/page.js | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/install/scripts/generate_keys.sh b/install/scripts/generate_keys.sh index fef5952..4f00306 100755 --- a/install/scripts/generate_keys.sh +++ b/install/scripts/generate_keys.sh @@ -5,8 +5,8 @@ source $SCRIPT_DIR/variables.sh # Run the script that generates keys and capture the output get_keys() { docker pull fidedocker/protocol-server > /dev/null 2>&1 - docker run --name temp -i fidedocker/protocol-server > /dev/null 2>&1 - output=$(docker exec -it temp node /usr/src/app/scripts/generate-keys 2>&1) + docker run --name temp -itd fidedocker/protocol-server > /dev/null 2>&1 + output=$(docker exec -i temp node /usr/src/app/scripts/generate-keys 2>&1) docker stop temp > /dev/null 2>&1 docker rm temp > /dev/null 2>&1 # Check if the script executed successfully diff --git a/onix-gui/GUI/app/api/install-bpp/route.js b/onix-gui/GUI/app/api/install-bpp/route.js index 49c2e80..533aa62 100644 --- a/onix-gui/GUI/app/api/install-bpp/route.js +++ b/onix-gui/GUI/app/api/install-bpp/route.js @@ -97,7 +97,6 @@ export async function POST(req, res) { // generating unqiuekey for bpp subscriberId const uniqueKeyId = bppSubscriberId + "-key"; let updateBppConfigCommand = `bash ${pathDir}/install/scripts/update_bpp_config.sh ${registryUrl} ${bppSubscriberId} ${uniqueKeyId} ${bppSubscriberUrl} ${webhookUrl}`; - console.log("Update BPP Config Command:", updateBppConfigCommand); const result1 = await executeCommand(updateBppConfigCommand); console.log("Result 1:", result1); diff --git a/onix-gui/GUI/app/yaml-gen/install-yaml/page.js b/onix-gui/GUI/app/yaml-gen/install-yaml/page.js index 22ad80c..fa97491 100644 --- a/onix-gui/GUI/app/yaml-gen/install-yaml/page.js +++ b/onix-gui/GUI/app/yaml-gen/install-yaml/page.js @@ -50,7 +50,7 @@ export default function InstallYaml() { }); } else { toast.update(toastId, { - render: "Yaml File Present 👌", + render: "Yaml File Downloaded 👌", type: "success", isLoading: false, autoClose: 5000, diff --git a/onix-gui/GUI/app/yaml-gen/page.js b/onix-gui/GUI/app/yaml-gen/page.js index 937fa35..6015abe 100644 --- a/onix-gui/GUI/app/yaml-gen/page.js +++ b/onix-gui/GUI/app/yaml-gen/page.js @@ -125,7 +125,7 @@ export default function CheckYaml() { label={"Version Number"} value={versionNumber} onChange={handleVersionChange} - placeholder="1.0.0" + placeholder="1.1.0" />
From d6c5ebe7a5d69e7643a6c7837f362827f5783ba3 Mon Sep 17 00:00:00 2001 From: MishalAbdullah <85678545+Mishalabdullah@users.noreply.github.com> Date: Sun, 5 May 2024 19:39:56 +0530 Subject: [PATCH 062/102] Added GUI to main readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4cb4838..7bf1c54 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ Refer to the following documents for more information: - [Step by step walkthrough of a setup](./docs/setup_walkthrough.md) - [Frequently asked questions (FAQ)](./docs/faq.md) - [release notes](./install/RELEASE.md) +- [GUI Installation Guide](./onix-gui/GUI/README.md) Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. From 4fab727b9544291bcbdafb5aa7afa1f413ee3db2 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Sun, 5 May 2024 23:11:53 +0530 Subject: [PATCH 063/102] updated yaml script --- onix-gui/GUI/app/api/install-layer2/route.js | 16 ++++++++++++++-- onix-gui/GUI/app/yaml-gen/install-yaml/page.js | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/onix-gui/GUI/app/api/install-layer2/route.js b/onix-gui/GUI/app/api/install-layer2/route.js index c795226..bf7d47a 100644 --- a/onix-gui/GUI/app/api/install-layer2/route.js +++ b/onix-gui/GUI/app/api/install-layer2/route.js @@ -28,11 +28,23 @@ export async function POST(req) { try { await executeShellCommand( - `docker exec ${containerName} wget -P /usr/src/app/schemas/ ${fileURL}` + `docker exec ${ + containerName + "-client" + } wget -P /usr/src/app/schemas/ ${fileURL}` + ); + } catch (error) { + console.error(`exec error: ${error}`); + } + + try { + await executeShellCommand( + `docker exec ${ + containerName + "-network" + } wget -P /usr/src/app/schemas/ ${fileURL}` ); return NextResponse.json({ status: 200 }); } catch (error) { console.error(`exec error: ${error}`); return NextResponse.json({ status: 500 }); } -} +} \ No newline at end of file diff --git a/onix-gui/GUI/app/yaml-gen/install-yaml/page.js b/onix-gui/GUI/app/yaml-gen/install-yaml/page.js index fa97491..b6b1129 100644 --- a/onix-gui/GUI/app/yaml-gen/install-yaml/page.js +++ b/onix-gui/GUI/app/yaml-gen/install-yaml/page.js @@ -18,7 +18,7 @@ export default function InstallYaml() { const [yamlUrl, setYamlUrl] = useState(""); const [checked, setChecked] = useState(false); - const container = checked ? "bpp-network" : "bap-network"; + const container = checked ? "bpp" : "bap"; const handleRegistryUrlChange = (event) => { setYamlUrl(event.target.value); From cf4df44e354ab54272ed30a1438e448a69a20090 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Sun, 5 May 2024 23:12:36 +0530 Subject: [PATCH 064/102] spell check --- onix-gui/README.md | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 onix-gui/README.md diff --git a/onix-gui/README.md b/onix-gui/README.md new file mode 100644 index 0000000..339f6dc --- /dev/null +++ b/onix-gui/README.md @@ -0,0 +1,77 @@ +# Beckn-Onix Installation Wizard + + + +The below provides an overview of the installation wizard and layer 2 tester & downloader features of Beckn-Onix. Follow the steps outlined below to successfully utilize these features. + + + +### Home Page + +- Visit the home page of the Beckn-Onix installation wizard. + + + +![Home Page](https://github.com/beckn/beckn-onix/assets/85678545/e8674a29-b6e2-4fb2-a5ad-c76166bf1174) + + + +### Installation Wizard + +- Navigate to the installation wizard section. + +- Fill in the required details as prompted. + + + +![Installation Wizard](https://github.com/beckn/beckn-onix/assets/85678545/e9cec587-299f-4793-9045-c7c01551ad51) + + + +### Continue Installation + +- Click on the "Continue" button to proceed with the installation. + +- Repeat the same process for all components. + + + +## Layer 2 + + + +![Layer 2](https://github.com/beckn/beckn-onix/assets/85678545/32978858-5303-43b2-b0b5-517ee98ec6c3) + + + +### Setup Configuration File + +- Select whether you want to set up the layer 2 config file in BAP or BPP. + +- Fill in the Domain and version number of the layer 2 config file. + + + +### Check File Presence + +- If the file is present, a success toast will be displayed. + +- If the file is not present, a link for downloading the layer 2 file to the protocol server will be provided. + + + +![Check File Presence](https://github.com/beckn/beckn-onix/assets/85678545/31aaf210-9fef-4c33-b651-7231cd900f0a) + + + +### Download File + +- Click on the download link to be redirected to another page for downloading. + +- Paste the YAML file URL and click "Continue". + +- If successful, a success toast will be displayed. If unsuccessful, an error toast will be shown. + + + +![Download File](https://github.com/beckn/beckn-onix/assets/85678545/0dd9d456-66ca-4e2a-abc1-ba8dd98719c1) From 9fc09d26ab9c00964d21d62e08b2fa0185021b83 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Sun, 5 May 2024 23:13:09 +0530 Subject: [PATCH 065/102] renamming --- onix-gui/REAME.md | 77 ----------------------------------------------- 1 file changed, 77 deletions(-) delete mode 100644 onix-gui/REAME.md diff --git a/onix-gui/REAME.md b/onix-gui/REAME.md deleted file mode 100644 index 339f6dc..0000000 --- a/onix-gui/REAME.md +++ /dev/null @@ -1,77 +0,0 @@ -# Beckn-Onix Installation Wizard - - - -The below provides an overview of the installation wizard and layer 2 tester & downloader features of Beckn-Onix. Follow the steps outlined below to successfully utilize these features. - - - -### Home Page - -- Visit the home page of the Beckn-Onix installation wizard. - - - -![Home Page](https://github.com/beckn/beckn-onix/assets/85678545/e8674a29-b6e2-4fb2-a5ad-c76166bf1174) - - - -### Installation Wizard - -- Navigate to the installation wizard section. - -- Fill in the required details as prompted. - - - -![Installation Wizard](https://github.com/beckn/beckn-onix/assets/85678545/e9cec587-299f-4793-9045-c7c01551ad51) - - - -### Continue Installation - -- Click on the "Continue" button to proceed with the installation. - -- Repeat the same process for all components. - - - -## Layer 2 - - - -![Layer 2](https://github.com/beckn/beckn-onix/assets/85678545/32978858-5303-43b2-b0b5-517ee98ec6c3) - - - -### Setup Configuration File - -- Select whether you want to set up the layer 2 config file in BAP or BPP. - -- Fill in the Domain and version number of the layer 2 config file. - - - -### Check File Presence - -- If the file is present, a success toast will be displayed. - -- If the file is not present, a link for downloading the layer 2 file to the protocol server will be provided. - - - -![Check File Presence](https://github.com/beckn/beckn-onix/assets/85678545/31aaf210-9fef-4c33-b651-7231cd900f0a) - - - -### Download File - -- Click on the download link to be redirected to another page for downloading. - -- Paste the YAML file URL and click "Continue". - -- If successful, a success toast will be displayed. If unsuccessful, an error toast will be shown. - - - -![Download File](https://github.com/beckn/beckn-onix/assets/85678545/0dd9d456-66ca-4e2a-abc1-ba8dd98719c1) From b550ab884218712f627edecb187d338f1992e605 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Mon, 6 May 2024 08:28:11 +0530 Subject: [PATCH 066/102] Fixes #68 Integrate GUI installer into Beckn-ONIX --- README.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 7bf1c54..8819ac2 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,19 @@ Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. This effort is also aimed at inviting contributions from the community to create secure, reliable builds for production environments. -Within the install folder you will find a `beckn-onix.sh` file which is an installer that helps create a multi-node Beckn network using reference implementations +## GUI Installer -Refer to the following documents for more information: +There is a community contributed browser based GUI installer to install multi-node reference implementation Beckn network. Refer to the [Installation Guide](./onix-gui/GUI/README.md) and [wizard guide](./onix-gui/README.md) for details. -- [User Guide](./docs/user_guide.md) -- [Step by step walkthrough of a setup](./docs/setup_walkthrough.md) -- [Frequently asked questions (FAQ)](./docs/faq.md) -- [release notes](./install/RELEASE.md) -- [GUI Installation Guide](./onix-gui/GUI/README.md) +## CLI Installer -Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. +For those familiar with CLI, there is a command line installer to install multi-node reference implementation Beckn network. Refer to the [User Guide](./docs/user_guide.md) and [Setup Walkthrough](./docs/setup_walkthrough.md) for details. + +## Additional documents + +- [Frequently asked questions (FAQ)](./docs/faq.md) **Note on mandatory Layer 2 Config (Important)** Please refer to this [note on mandatory layer 2 configuration](./docs/notes/mandatory_layer_2_config.md). + +Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. From f5f510bfea0a5cb89022e3c0fd1fba57374ba9a5 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Mon, 6 May 2024 08:29:47 +0530 Subject: [PATCH 067/102] Fixes #68 Integrate GUI installer into Beckn-ONIX --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8819ac2..8bf757e 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,7 @@ For those familiar with CLI, there is a command line installer to install multi- ## Additional documents - [Frequently asked questions (FAQ)](./docs/faq.md) - -**Note on mandatory Layer 2 Config (Important)** -Please refer to this [note on mandatory layer 2 configuration](./docs/notes/mandatory_layer_2_config.md). +- **Note on mandatory Layer 2 Config (Important)** + Please refer to this [note on mandatory layer 2 configuration](./docs/notes/mandatory_layer_2_config.md). Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. From bef5f70550d8acc8dfa89c9848c228e27440150a Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Mon, 6 May 2024 12:59:14 +0530 Subject: [PATCH 068/102] Fixes #68 Update release notes --- README.md | 8 +- docs/notes/mandatory_layer_2_config.md | 4 +- docs/release_notes.md | 165 +++++++++++++++++++++++++ install/RELEASE.md | 51 -------- install/release/RELEASE_0.1.0.md | 52 -------- 5 files changed, 172 insertions(+), 108 deletions(-) create mode 100644 docs/release_notes.md delete mode 100644 install/RELEASE.md delete mode 100644 install/release/RELEASE_0.1.0.md diff --git a/README.md b/README.md index 8bf757e..47d7a0c 100644 --- a/README.md +++ b/README.md @@ -8,12 +8,12 @@ There is a community contributed browser based GUI installer to install multi-no ## CLI Installer -For those familiar with CLI, there is a command line installer to install multi-node reference implementation Beckn network. Refer to the [User Guide](./docs/user_guide.md) and [Setup Walkthrough](./docs/setup_walkthrough.md) for details. +For those comfortable with CLI, there is a command line installer to install multi-node reference implementation Beckn network. Refer to the [User Guide](./docs/user_guide.md) and [Setup Walkthrough](./docs/setup_walkthrough.md) for details. -## Additional documents +## Other documents +- [Release Notes](./docs/release_notes.md) - [Frequently asked questions (FAQ)](./docs/faq.md) -- **Note on mandatory Layer 2 Config (Important)** - Please refer to this [note on mandatory layer 2 configuration](./docs/notes/mandatory_layer_2_config.md). +- **[Note on mandatory layer 2 configuration(Important)](./docs/notes/mandatory_layer_2_config.md).** Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. diff --git a/docs/notes/mandatory_layer_2_config.md b/docs/notes/mandatory_layer_2_config.md index db39310..e283eb7 100644 --- a/docs/notes/mandatory_layer_2_config.md +++ b/docs/notes/mandatory_layer_2_config.md @@ -5,7 +5,9 @@ Beckn-ONIX mandates availability of Layer 2 Config for a particular domain befor Usually the network facilitators will host the Layer 2 config and provide a way to access it. Currently we have a small script (layer2/download_layer_2_config_bap.sh and layer2/download_layer_2_config_bpp.sh) that can download the layer 2 config from a fixed location and insert it into the docker container that runs the Protocol Server Client. -If you have the Layer 2 config file with you and not hosted, you can use the following procedure to update it manually. In case you do not have layer 2 config file with you, as developer machine workaround, you can copy the core_version.yaml(e.g. core_1.1.0.yaml) and rename it as the layer 2 config for a domain (e.g. for a domain named retail for core version 1.1.0, retail_1.1.0.yaml). This is strictly not recommended for production networks. +- In case you do not have layer 2 config file with you, some sample files are hosted in this repo in this [folder](../../layer2/samples/) +- In case you do not have layer 2 config file with you, and the samples folder does not have the domain that you need, as developer machine workaround, you can copy the core_version.yaml(e.g. core_1.1.0.yaml) and rename it as the layer 2 config for a domain (e.g. for a domain named retail for core version 1.1.0, retail_1.1.0.yaml). This is strictly not recommended for production networks. +- If you have the Layer 2 config file with you and not hosted, you can use the following procedure to update it manually. Process to manually update layer 2 config. diff --git a/docs/release_notes.md b/docs/release_notes.md new file mode 100644 index 0000000..d3f3a65 --- /dev/null +++ b/docs/release_notes.md @@ -0,0 +1,165 @@ +# Release Notes + +## Introduction + +Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. + +Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. + +| Version | Release Date | +| -------------------------------------------- | ------------ | +| [v0.4.0](#beckn-onix-version-040-2024-05-06) | 2024-05-06 | +| [v0.3.0](#beckn-onix-version-030-2024-03-20) | 2024-03-20 | +| [v0.2.0](#beckn-onix-version-020-2024-03-01) | 2024-03-01 | +| [v0.1.0](#beckn-onix-version-010-2024-02-16) | 2024-02-16 | + +## Beckn-ONIX Version 0.4.0 (2024-05-06) + +- This release adds a new browser based GUI for installing Beckn network components + +### New Features + +- A new Browser based GUI installation wizard + +### Enhancements + +- Docker volumes used for data and config. Makes migration to new version of components easy +- New User Guide and Setup Walkthrough documents added to CLI installation + +### Bug fixes + +- BPP Beckn Adapter installation does not automatically install additional software (sandbox) +- Required Gateway configuration files are automatically filled (There was an error due to which this had to be manually done) + +### Limitations + +- GUI based installer only works on Ubuntu Linux +- There is a small error due to which the installation in progress toast for BAP and BPP does not stop, though the installation itself has succeeded +- The GUI installer needs Node, NPM and LocalTunnel to be installed before starting. + +## Beckn-ONIX Version 0.3.0 (2024-03-20) + +- This release supports streamlined multi-node installation. +- Support added to mandata layer 2 configuration files for the domain +- The CLI has been modified to lead the user through the journey of bringing up a Beckn Network. +- Based on whether the user is setting up a new network or joining an existing one, workflow prompt is changed + +### New Features + +- Multi node installation +- New CLI interface to lead user through installation +- Layer 2 Config file is mandated before transactions can happen +- Ability to download layer 2 config file from web and install in BAP/BPP Beckn Adapter + +### Bug Fixes + +- None + +### Known Issues + +- Sometimes installation fails on machines without docker due to user not getting new group membership. Running installation again fixes the issue. +- Mount binds are used instead of docker volumes. Due to this data has to be migrated before deleting the installation folder. +- BPP installs Sandbox even when not requested. + +### Limitations + +- The beckn-onix.sh installer used for multi node. For single node installation the start_beckn.sh file has to be used. + +### Upcoming Version + +- A community driven + +### Release Date + +- 2024-03-01 + +## Beckn-ONIX Version 0.2.0 (2024-03-01) + +### New Features + +- This release focuses on enabling the installation of individual components with user-provided configurations. +- It extends support to the Windows operating system, specifically Windows 10. +- Additionally, it now supports the Mac operating system. + +This release is specifically designed to facilitate the deployment of individual components, offering users the flexibility to customize configurations. Furthermore, it ensures seamless compatibility with both Windows and Mac operating systems. + +For a comprehensive summary of the features, refer [here](https://github.com/beckn/beckn-utilities/milestone/1?closed=1) + +### Enhancements + +- Support for Windows operating system. +- Support for Mac operating system. +- Can be used to install specific components with custom configuration. + +### Bug Fixes + +- None + +### Known Issues + +- None + +### Limitations + +- The current installer is tested only for Linux (Ubuntu) / Windows (windows 10) / Mac, it might support other flavors also. +- The current version supports only vertical scaling, horizontal scaling (ECS / EKS) is planned for an upcoming release +- When installing individual components, registration with the registry has to be done manually, this is explicitly done to avoid confusion and to prevent the network from incorrect or wrong registrations. + +### Upcoming Version + +- Support for horizontal scaling using Elastic Kubernetes Cluster. + +### Release Date + +- 2024-03-01 + +## Beckn-ONIX Version 0.1.0 (2024-02-16) + +### Objective + +Beckn-ONIX - Open Network In A Box, is a utility designed to effortlessly set up all Beckn components on a machine using a one-click installer. This tool serves as a valuable resource for developers and network participants eager to explore Beckn protocols or join open networks supported by the Beckn protocol. By simplifying the installation process, Beckn-ONIX streamlines the onboarding experience. + +The current version installs all components automatically without requiring user input, facilitating a seamless setup process. However, we are committed to further enhancing Beckn-ONIX's functionality. In the upcoming release, we will introduce the capability to selectively install specific components and accommodate user-provided configurations. + +For a comprehensive summary of the features, refer [here](https://github.com/beckn/beckn-utilities/milestone/2?closed=1) + +Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. + +### New Features + +- Implemented installation support for the following Beckn components: + - Protocol Server BAP + - Protocol Server BPP + - Webhook BPP + - Sandbox + - Registry + - Gateway + - Infrastructure required for the above services + +This release is specifically tailored for deployment on Linux machines, encompassing all aforementioned components with default configurations. + +### Enhancements + +- None + +### Bug Fixes + +- None + +### Known Issues + +- None + +### Limitations + +- The current installer is tested only for Linux (Ubuntu), it might support other flavors also. +- The current version installs all the components with the default configurations. + +### Upcoming Version + +- Installation of individual components with user-provided configuration. +- Support for Windows and Mac OS will be added. + +### Release Date + +- 2024-02-16 diff --git a/install/RELEASE.md b/install/RELEASE.md deleted file mode 100644 index d98a18f..0000000 --- a/install/RELEASE.md +++ /dev/null @@ -1,51 +0,0 @@ -# Release Notes - -### Objective - -Beckn-ONIX - Open Network In A Box. This install utility is designed to effortlessly set up all Beckn components on a machine using a one-click installer. This tool serves as a valuable resource for developers and network participants eager to explore Beckn protocols or join open networks supported by the Beckn protocol. By simplifying the installation process, Beckn-ONIX streamlines the onboarding experience. - -Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. - -| Version | Release Date | -| ------------------------------------------------------------------------------------------ | ------------ | -| [v0.1.0](https://github.com/beckn/beckn-utilities/blob/main/onix/release/RELEASE_0.1.0.md) | 2024-02-16 | - -## ONIX Version 0.2.0 (2024-03-01) - -### New Features - -- This release focuses on enabling the installation of individual components with user-provided configurations. -- It extends support to the Windows operating system, specifically Windows 10. -- Additionally, it now supports the Mac operating system. - -This release is specifically designed to facilitate the deployment of individual components, offering users the flexibility to customize configurations. Furthermore, it ensures seamless compatibility with both Windows and Mac operating systems. - -For a comprehensive summary of the features, refer [here](https://github.com/beckn/beckn-utilities/milestone/1?closed=1) - -### Enhancements - -- Support for Windows operating system. -- Support for Mac operating system. -- Can be used to install specific components with custom configuration. - -### Bug Fixes - -- None - -### Known Issues - -- None - -### Limitations - -- The current installer is tested only for Linux (Ubuntu) / Windows (windows 10) / Mac, it might support other flavors also. -- The current version supports only vertical scaling, horizontal scaling (ECS / EKS) is planned for an upcoming release -- When installing individual components, registration with the registry has to be done manually, this is explicitly done to avoid confusion and to prevent the network from incorrect or wrong registrations. - -### Upcoming Version - -- Support for horizontal scaling using Elastic Kubernetes Cluster. - -### Release Date - -- 2024-03-01 diff --git a/install/release/RELEASE_0.1.0.md b/install/release/RELEASE_0.1.0.md deleted file mode 100644 index 25e004c..0000000 --- a/install/release/RELEASE_0.1.0.md +++ /dev/null @@ -1,52 +0,0 @@ -# Release Notes - -## Beckn-ONIX Version 0.1.0 (2024-02-16) - -### Objective - -Beckn-ONIX - Open Network In A Box, is a utility designed to effortlessly set up all Beckn components on a machine using a one-click installer. This tool serves as a valuable resource for developers and network participants eager to explore Beckn protocols or join open networks supported by the Beckn protocol. By simplifying the installation process, Beckn-ONIX streamlines the onboarding experience. - -The current version installs all components automatically without requiring user input, facilitating a seamless setup process. However, we are committed to further enhancing Beckn-ONIX's functionality. In the upcoming release, we will introduce the capability to selectively install specific components and accommodate user-provided configurations. - -For a comprehensive summary of the features, refer [here](https://github.com/beckn/beckn-utilities/milestone/2?closed=1) - -Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. - -### New Features - -- Implemented installation support for the following Beckn components: - - Protocol Server BAP - - Protocol Server BPP - - Webhook BPP - - Sandbox - - Registry - - Gateway - - Infrastructure required for the above services - -This release is specifically tailored for deployment on Linux machines, encompassing all aforementioned components with default configurations. - -### Enhancements - -- None - -### Bug Fixes - -- None - -### Known Issues - -- None - -### Limitations - -- The current installer is tested only for Linux (Ubuntu), it might support other flavors also. -- The current version installs all the components with the default configurations. - -### Upcoming Version - -- Installation of individual components with user-provided configuration. -- Support for Windows and Mac OS will be added. - -### Release Date - -- 2024-02-16 From f6649cbf3fb17b9cc485106744765f3413ba6a6a Mon Sep 17 00:00:00 2001 From: Venkatesh Babu <154209057+vbabuEM@users.noreply.github.com> Date: Mon, 6 May 2024 13:01:39 +0530 Subject: [PATCH 069/102] Update release_notes.md --- docs/release_notes.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/release_notes.md b/docs/release_notes.md index d3f3a65..79b1426 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -37,6 +37,9 @@ Experience the convenience and efficiency of Beckn-ONIX as you embark on your jo - There is a small error due to which the installation in progress toast for BAP and BPP does not stop, though the installation itself has succeeded - The GUI installer needs Node, NPM and LocalTunnel to be installed before starting. +### Release date +2024-05-06 + ## Beckn-ONIX Version 0.3.0 (2024-03-20) - This release supports streamlined multi-node installation. @@ -67,7 +70,7 @@ Experience the convenience and efficiency of Beckn-ONIX as you embark on your jo ### Upcoming Version -- A community driven +- A community driven GUI installer is in works ### Release Date From d73b219c3ca62f40756ccdd732a9bafc20cbb70c Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Tue, 7 May 2024 15:05:08 +0530 Subject: [PATCH 070/102] Added docker compose files for Webhook, Sandbox and GCL. Also, updated the shell script with variables name for each docker file --- install/beckn-onix.sh | 12 +- install/docker-compose-bpp-with-sandbox.yml | 70 +++++++++++ install/docker-compose-gcl.yml | 122 ++++++++++++++++++++ install/scripts/variables.sh | 7 ++ install/start_beckn.sh | 6 +- install/start_beckn_v2.sh | 36 +++--- 6 files changed, 227 insertions(+), 26 deletions(-) create mode 100644 install/docker-compose-bpp-with-sandbox.yml create mode 100644 install/docker-compose-gcl.yml diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 0fb5812..e70ea42 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -76,7 +76,7 @@ install_gateway() { bash scripts/update_gateway_details.sh registry fi echo "${GREEN}................Installing Gateway service................${NC}" - start_container "docker-compose-gateway.yml" gateway + start_container $gateway_docker_compose_file gateway echo "Registering Gateway in the registry" sleep 10 @@ -98,7 +98,7 @@ install_registry(){ fi echo "${GREEN}................Installing Registry service................${NC}" - start_container "docker-compose-registry.yml" registry + start_container $registry_docker_compose_file registry sleep 10 echo "Registry installation successful" } @@ -124,8 +124,8 @@ install_bap_protocol_server(){ docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bap_network_config_volume:/target busybox cp /source/bap-network.yaml-sample /target docker rmi busybox - start_container "docker-compose-bap.yml" "bap-client" - start_container "docker-compose-bap.yml" "bap-network" + start_container $bap_docker_compose_file "bap-client" + start_container $bap_docker_compose_file "bap-network" sleep 10 echo "Protocol server BAP installation successful" } @@ -156,8 +156,8 @@ install_bpp_protocol_server(){ docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bpp_network_config_volume:/target busybox cp /source/bpp-network.yaml-sample /target docker rmi busybox - start_container "docker-compose-bpp.yml" "bpp-client" - start_container "docker-compose-bpp.yml" "bpp-network" + start_container $bpp_docker_compose_file "bpp-client" + start_container $bpp_docker_compose_file "bpp-network" sleep 10 echo "Protocol server BPP installation successful" } diff --git a/install/docker-compose-bpp-with-sandbox.yml b/install/docker-compose-bpp-with-sandbox.yml new file mode 100644 index 0000000..43ffea5 --- /dev/null +++ b/install/docker-compose-bpp-with-sandbox.yml @@ -0,0 +1,70 @@ +services: + bpp-client: + image: fidedocker/protocol-server + container_name: bpp-client + networks: + - beckn_network + ports: + - 6001:6001 + restart: unless-stopped + volumes: + - bpp_client_config_volume:/usr/src/app/config + - bpp_client_schemas_volume:/usr/src/app/schemas + - bpp_client_logs_volume:/usr/src/app/logs + + bpp-network: + image: fidedocker/protocol-server + container_name: bpp-network + networks: + - beckn_network + ports: + - 6002:6002 + restart: unless-stopped + volumes: + - bpp_network_config_volume:/usr/src/app/config + - bpp_network_schemas_volume:/usr/src/app/schemas + - bpp_network_logs_volume:/usr/src/app/logs + + + sandbox-api: + image: fidedocker/sandbox-api + container_name: sandbox-api + networks: + - beckn_network + ports: + - 4010:4000 + restart: unless-stopped + + sandbox-webhook: + image: fidedocker/sandbox-webhook-api + depends_on: + - sandbox-api + container_name: sandbox-webhook + networks: + - beckn_network + ports: + - 3005:3005 + restart: unless-stopped + volumes: + - ./ENV/.env-webhook:/usr/src/app/.env + +networks: + beckn_network: + name: beckn_network + driver: bridge + +volumes: + bpp_client_config_volume: + name: bpp_client_config_volume + external: true + bpp_client_schemas_volume: + name: bpp_client_schemas_volume + bpp_client_logs_volume: + name: bpp_client_logs_volume + bpp_network_config_volume: + name: bpp_network_config_volume + external: true + bpp_network_schemas_volume: + name: bpp_network_schemas_volume + bpp_network_logs_volume: + name: bpp_network_logs_volume diff --git a/install/docker-compose-gcl.yml b/install/docker-compose-gcl.yml new file mode 100644 index 0000000..b73857b --- /dev/null +++ b/install/docker-compose-gcl.yml @@ -0,0 +1,122 @@ +services: + registry: + image: fidedocker/registry + container_name: registry + networks: + - beckn_network + ports: + - 3000:3000 + - 3030:3030 + restart: unless-stopped + volumes: + - registry_data_volume:/registry/overrideProperties/config + - registry_database_volume:/registry/database + + gateway: + image: fidedocker/gateway + container_name: gateway + networks: + - beckn_network + ports: + - 4000:4000 + - 4030:4030 + restart: unless-stopped + volumes: + - gateway_data_volume:/gateway/overrideProperties/config + - gateway_database_volume:/gateway/database + + bap-client: + image: fidedocker/protocol-server + container_name: bap-client + networks: + - beckn_network + ports: + - 5001:5001 + restart: unless-stopped + volumes: + - ./protocol-server-data/bap-client.yml:/usr/src/app/config/default.yml + + bap-network: + image: fidedocker/protocol-server + container_name: bap-network + networks: + - beckn_network + ports: + - 5002:5002 + restart: unless-stopped + volumes: + - ./protocol-server-data/bap-network.yml:/usr/src/app/config/default.yml + + sandbox-api: + image: fidedocker/sandbox-api + container_name: sandbox-api + networks: + - beckn_network + ports: + - 4010:4000 + restart: unless-stopped + + sandbox-webhook: + image: fidedocker/sandbox-webhook-api + depends_on: + - sandbox-api + container_name: sandbox-webhook + networks: + - beckn_network + ports: + - 3005:3005 + restart: unless-stopped + volumes: + - ./ENV/.env-webhook:/usr/src/app/.env + + bpp-client: + image: fidedocker/protocol-server + container_name: bpp-client + networks: + - beckn_network + ports: + - 6001:6001 + restart: unless-stopped + volumes: + - ./protocol-server-data/bpp-client.yml:/usr/src/app/config/default.yml + + bpp-network: + image: fidedocker/protocol-server + container_name: bpp-network + networks: + - beckn_network + ports: + - 6002:6002 + restart: unless-stopped + volumes: + - ./protocol-server-data/bpp-network.yml:/usr/src/app/config/default.yml + + generic-client-layer: + image: fidedocker/generic-client-layer + container_name: generic-client-layer + networks: + - beckn_network + ports: + - 3015:3000 + restart: unless-stopped + volumes: + - ./ENV/.env-generic-client-layer:/app/.env + +networks: + beckn_network: + name: beckn_network + driver: bridge + +volumes: + registry_data_volume: + name: registry_data_volume + external: true + registry_database_volume: + name: registry_database_volume + external: true + gateway_data_volume: + name: gateway_data_volume + external: true + gateway_database_volume: + name: gateway_database_volume + external: true diff --git a/install/scripts/variables.sh b/install/scripts/variables.sh index 94e1f64..a753efe 100755 --- a/install/scripts/variables.sh +++ b/install/scripts/variables.sh @@ -51,3 +51,10 @@ bpp_subscriber_id="bpp-network" bpp_subscriber_key_id="bpp-network-key" bpp_subscriber_url="http://bpp-network:6002" webhook_url="http://sandbox-webhook:3005" + +bpp_docker_compose_file=docker-compose-bpp.yml +bpp_docker_compose_file_sandbox=docker-compose-bpp-with-sandbox.yml +bap_docker_compose_file=docker-compose-bap.yml +registry_docker_compose_file=docker-compose-registry.yml +gateway_docker_compose_file=docker-compose-gateway.yml +gcl_docker_compose_file=docker-compose-gcl.yml \ No newline at end of file diff --git a/install/start_beckn.sh b/install/start_beckn.sh index 213f960..af9b676 100755 --- a/install/start_beckn.sh +++ b/install/start_beckn.sh @@ -12,15 +12,15 @@ start_container(){ #below function will start the MongoDB, Redis and RabbitMQ Services. start_support_services(){ echo "${GREEN}................Installing MongoDB................${NC}" - docker-compose -f docker-compose-app.yml up -d mongo_db + docker compose -f docker-compose-app.yml up -d mongo_db echo "MongoDB installation successful" echo "${GREEN}................Installing RabbitMQ................${NC}" - docker-compose -f docker-compose-app.yml up -d queue_service + docker compose -f docker-compose-app.yml up -d queue_service echo "RabbitMQ installation successful" echo "${GREEN}................Installing Redis................${NC}" - docker-compose -f docker-compose-app.yml up -d redis_db + docker compose -f docker-compose-app.yml up -d redis_db echo "Redis installation successful" } # Main script starts here diff --git a/install/start_beckn_v2.sh b/install/start_beckn_v2.sh index d91c377..3404cb4 100755 --- a/install/start_beckn_v2.sh +++ b/install/start_beckn_v2.sh @@ -12,7 +12,7 @@ install_package(){ start_container(){ #ignore orphaned containers warning export COMPOSE_IGNORE_ORPHANS=1 - docker-compose -f docker-compose-v2.yml up -d $1 + docker compose -f $1 up -d $2 } update_registry_details() { @@ -54,15 +54,15 @@ start_support_services(){ #ignore orphaned containers warning export COMPOSE_IGNORE_ORPHANS=1 echo "${GREEN}................Installing MongoDB................${NC}" - docker-compose -f docker-compose-app.yml up -d mongo_db + docker compose -f docker-compose-app.yml up -d mongo_db echo "MongoDB installation successful" echo "${GREEN}................Installing RabbitMQ................${NC}" - docker-compose -f docker-compose-app.yml up -d queue_service + docker compose -f docker-compose-app.yml up -d queue_service echo "RabbitMQ installation successful" echo "${GREEN}................Installing Redis................${NC}" - docker-compose -f docker-compose-app.yml up -d redis_db + docker compose -f docker-compose-app.yml up -d redis_db echo "Redis installation successful" } @@ -73,7 +73,7 @@ install_gateway() { bash scripts/update_gateway_details.sh registry fi echo "${GREEN}................Installing Gateway service................${NC}" - start_container gateway + start_container $gateway_docker_compose_file gateway echo "Registering Gateway in the registry" sleep 10 @@ -95,7 +95,7 @@ install_registry(){ fi echo "${GREEN}................Installing Registry service................${NC}" - start_container registry + start_container $registry_docker_compose_file registry sleep 10 echo "Registry installation successful" } @@ -113,8 +113,8 @@ install_bap_protocol_server(){ bash scripts/update_bap_config.sh fi sleep 10 - start_container "bap-client" - start_container "bap-network" + start_container $bap_docker_compose_file "bap-client" + start_container $bap_docker_compose_file "bap-network" sleep 10 echo "Protocol server BAP installation successful" } @@ -123,12 +123,12 @@ install_bap_protocol_server(){ install_bpp_protocol_server_with_sandbox(){ start_support_services echo "${GREEN}................Installing Sandbox................${NC}" - start_container "sandbox-api" + start_container $bpp_docker_compose_file_sandbox "sandbox-api" sleep 5 echo "Sandbox installation successful" echo "${GREEN}................Installing Webhook................${NC}" - start_container "sandbox-webhook" + start_container $bpp_docker_compose_file_sandbox "sandbox-webhook" sleep echo "Webhook installation successful" @@ -139,14 +139,15 @@ install_bpp_protocol_server_with_sandbox(){ bpp_subscriber_id=$2 bpp_subscriber_key_id=$3 bpp_subscriber_url=$4 - bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url + webhook_url=$5 + bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url else bash scripts/update_bpp_config.sh fi sleep 10 - start_container "bpp-client" - start_container "bpp-network" + start_container $bpp_docker_compose_file_sandbox "bpp-client" + start_container $bpp_docker_compose_file_sandbox "bpp-network" sleep 10 echo "Protocol server BPP installation successful" } @@ -168,8 +169,8 @@ install_bpp_protocol_server(){ fi sleep 10 - start_container "bpp-client" - start_container "bpp-network" + start_container $bpp_docker_compose_file "bpp-client" + start_container $bpp_docker_compose_file "bpp-network" sleep 10 echo "Protocol server BPP installation successful" } @@ -276,12 +277,13 @@ else 4) read -p "Enter BPP Subscriber ID: " bpp_subscriber_id read -p "Enter BPP Subscriber URL: " bpp_subscriber_url + read -p "Enter Webhook URL: " webhook_url # Ask the user if they want to change the registry_url read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url registry_url=${custom_registry_url:-$beckn_registry_url} bpp_subscriber_key_id=$bpp_subscriber_id-key install_package - install_bpp_protocol_server_with_sandbox $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url + install_bpp_protocol_server_with_sandbox $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url ;; 5) read -p "Enter BPP Subscriber ID: " bpp_subscriber_id @@ -302,7 +304,7 @@ else read -p "Enter BAP Subscriber URL: " bap_subscriber_url read -p "Enter BAP Client URL: " bap_client_url bash scripts/generic-client-layer.sh $bap_subscriber_id $bap_subscriber_url $bap_client_url - start_container "generic-client-layer" + start_container $gcl_docker_compose_file "generic-client-layer" ;; 7) From cfa78b4192213afb8737b463301c439a318323a1 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Tue, 7 May 2024 15:10:24 +0530 Subject: [PATCH 071/102] Added sleep value for webhook --- install/start_beckn_v2.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install/start_beckn_v2.sh b/install/start_beckn_v2.sh index 3404cb4..acf1f44 100755 --- a/install/start_beckn_v2.sh +++ b/install/start_beckn_v2.sh @@ -129,7 +129,7 @@ install_bpp_protocol_server_with_sandbox(){ echo "${GREEN}................Installing Webhook................${NC}" start_container $bpp_docker_compose_file_sandbox "sandbox-webhook" - sleep + sleep 5 echo "Webhook installation successful" echo "${GREEN}................Installing Protocol Server for BPP................${NC}" From ba59c5f0891b64877b8bd8f52705e58ffd42b3dd Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Fri, 10 May 2024 15:36:12 +0530 Subject: [PATCH 072/102] All in one install --- install/ENV/.env-sandbox | 2 + install/START_BECKN.md | 8 +- install/beckn-onix.sh | 100 ++++++++++++++------ install/docker-compose-bpp-with-sandbox.yml | 14 +-- install/docker-compose-gcl.yml | 13 +-- install/docker-compose-v2.yml | 13 +-- install/docker-compose.yml | 15 +-- install/scripts/variables.sh | 2 +- install/start_beckn.sh | 5 - install/start_beckn_v2.sh | 5 - 10 files changed, 81 insertions(+), 96 deletions(-) create mode 100644 install/ENV/.env-sandbox diff --git a/install/ENV/.env-sandbox b/install/ENV/.env-sandbox new file mode 100644 index 0000000..d71b848 --- /dev/null +++ b/install/ENV/.env-sandbox @@ -0,0 +1,2 @@ +BPPCLIENTURL=http://bpp-client:6001 +BASE_URL=http://sandbox-api:3000 diff --git a/install/START_BECKN.md b/install/START_BECKN.md index 6853806..827b4bd 100644 --- a/install/START_BECKN.md +++ b/install/START_BECKN.md @@ -73,13 +73,7 @@ This shell script, `start_beckn_v2.sh`, automates the setup of Beckn components, ./start_container "sandbox-api" ``` -7. **Install Webhook:** - - ```bash - ./start_container "sandbox-webhook" - ``` - -8. **Install Protocol Server for BPP:** +7. **Install Protocol Server for BPP:** ```bash ./update_bpp_config.sh diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index e70ea42..984becc 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -162,24 +162,44 @@ install_bpp_protocol_server(){ echo "Protocol server BPP installation successful" } +# Function to install BPP Protocol Server with Sandbox +install_bpp_protocol_server_with_sandbox(){ + start_support_services + docker volume create bpp_client_config_volume + docker volume create bpp_network_config_volume + + echo "${GREEN}................Installing Sandbox................${NC}" + start_container $bpp_docker_compose_file_sandbox "sandbox-api" + sleep 5 + echo "Sandbox installation successful" -# MAIN SCRIPT STARTS HERE -#!/bin/bash + echo "${GREEN}................Installing Protocol Server for BPP................${NC}" + + if [[ $1 ]];then + registry_url=$1 + bpp_subscriber_id=$2 + bpp_subscriber_key_id=$3 + bpp_subscriber_url=$4 + webhook_url=$5 + bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url + else + bash scripts/update_bpp_config.sh + fi -echo "Welcome to Beckn-ONIX!" -if [ -f ./onix_ascii_art.txt ]; then - cat ./onix_ascii_art.txt -else - echo "[Display Beckn-ONIX ASCII Art]" -fi + sleep 10 + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bpp_client_config_volume:/target busybox cp /source/bpp-client.yml /target/default.yml + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bpp_client_config_volume:/target busybox cp /source/bpp-client.yaml-sample /target + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bpp_network_config_volume:/target busybox cp /source/bpp-network.yml /target/default.yml + docker run --rm -v $SCRIPT_DIR/../protocol-server-data:/source -v bpp_network_config_volume:/target busybox cp /source/bpp-network.yaml-sample /target + docker rmi busybox -echo "Beckn-ONIX is a platform that helps you quickly launch and configure beckn-enabled networks." -echo -e "\nWhat would you like to do?\n1. Join an existing network\n2. Create new production network\n3. Set up a network on your local machine\n4. Merge multiple networks\n5. Configure Existing Network\n(Press Ctrl+C to exit)" -read -p "Enter your choice: " choice + start_container $bpp_docker_compose_file "bpp-client" + start_container $bpp_docker_compose_file "bpp-network" + sleep 10 + echo "Protocol server BPP installation successful" +} -boldGreen="\e[1m\e[92m" -reset="\e[0m" # Function to handle the setup process for each platform completeSetup() { @@ -254,25 +274,51 @@ completeSetup() { # Key generation and subscription logic follows here } -# Determine the platforms available based on the initial choice -platforms=("Gateway" "BAP" "BPP") -[ "$choice" -eq 2 ] && platforms=("Registry" "${platforms[@]}") # Add Registry for new network setups -echo "Great choice! Get ready." -echo -e "\nWhich platform would you like to set up?" -for i in "${!platforms[@]}"; do - echo "$((i+1)). ${platforms[$i]}" -done +# MAIN SCRIPT STARTS HERE -read -p "Enter your choice: " platform_choice +echo "Welcome to Beckn-ONIX!" +if [ -f ./onix_ascii_art.txt ]; then + cat ./onix_ascii_art.txt +else + echo "[Display Beckn-ONIX ASCII Art]" +fi -selected_platform="${platforms[$((platform_choice-1))]}" +echo "Beckn-ONIX is a platform that helps you quickly launch and configure beckn-enabled networks." +echo -e "\nWhat would you like to do?\n1. Join an existing network\n2. Create new production network\n3. Set up a network on your local machine\n4. Merge multiple networks\n5. Configure Existing Network\n(Press Ctrl+C to exit)" +read -p "Enter your choice: " choice + +boldGreen="\e[1m\e[92m" +reset="\e[0m" -if [[ -n $selected_platform ]]; then - completeSetup "$selected_platform" +if [[ $choice -eq 3 ]]; then + echo "Installing all components on the local machine" + install_package + install_registry + install_gateway + install_bap_protocol_server + install_bpp_protocol_server_with_sandbox else - echo "Invalid option. Please restart the script and select a valid option." - exit 1 + # Determine the platforms available based on the initial choice + platforms=("Gateway" "BAP" "BPP") + [ "$choice" -eq 2 ] && platforms=("Registry" "${platforms[@]}") # Add Registry for new network setups + + echo "Great choice! Get ready." + echo -e "\nWhich platform would you like to set up?" + for i in "${!platforms[@]}"; do + echo "$((i+1)). ${platforms[$i]}" + done + + read -p "Enter your choice: " platform_choice + + selected_platform="${platforms[$((platform_choice-1))]}" + + if [[ -n $selected_platform ]]; then + completeSetup "$selected_platform" + else + echo "Invalid option. Please restart the script and select a valid option." + exit 1 + fi fi echo "Process complete. Thank you for using Beckn-ONIX!" diff --git a/install/docker-compose-bpp-with-sandbox.yml b/install/docker-compose-bpp-with-sandbox.yml index 43ffea5..3b8dcc8 100644 --- a/install/docker-compose-bpp-with-sandbox.yml +++ b/install/docker-compose-bpp-with-sandbox.yml @@ -25,7 +25,6 @@ services: - bpp_network_schemas_volume:/usr/src/app/schemas - bpp_network_logs_volume:/usr/src/app/logs - sandbox-api: image: fidedocker/sandbox-api container_name: sandbox-api @@ -34,19 +33,8 @@ services: ports: - 4010:4000 restart: unless-stopped - - sandbox-webhook: - image: fidedocker/sandbox-webhook-api - depends_on: - - sandbox-api - container_name: sandbox-webhook - networks: - - beckn_network - ports: - - 3005:3005 - restart: unless-stopped volumes: - - ./ENV/.env-webhook:/usr/src/app/.env + - ./ENV/.env-sandbox:/usr/src/app/.env networks: beckn_network: diff --git a/install/docker-compose-gcl.yml b/install/docker-compose-gcl.yml index b73857b..67ba486 100644 --- a/install/docker-compose-gcl.yml +++ b/install/docker-compose-gcl.yml @@ -55,19 +55,8 @@ services: ports: - 4010:4000 restart: unless-stopped - - sandbox-webhook: - image: fidedocker/sandbox-webhook-api - depends_on: - - sandbox-api - container_name: sandbox-webhook - networks: - - beckn_network - ports: - - 3005:3005 - restart: unless-stopped volumes: - - ./ENV/.env-webhook:/usr/src/app/.env + - ./ENV/.env-sandbox:/usr/src/app/.env bpp-client: image: fidedocker/protocol-server diff --git a/install/docker-compose-v2.yml b/install/docker-compose-v2.yml index b73857b..67ba486 100644 --- a/install/docker-compose-v2.yml +++ b/install/docker-compose-v2.yml @@ -55,19 +55,8 @@ services: ports: - 4010:4000 restart: unless-stopped - - sandbox-webhook: - image: fidedocker/sandbox-webhook-api - depends_on: - - sandbox-api - container_name: sandbox-webhook - networks: - - beckn_network - ports: - - 3005:3005 - restart: unless-stopped volumes: - - ./ENV/.env-webhook:/usr/src/app/.env + - ./ENV/.env-sandbox:/usr/src/app/.env bpp-client: image: fidedocker/protocol-server diff --git a/install/docker-compose.yml b/install/docker-compose.yml index a7cea70..deeec38 100644 --- a/install/docker-compose.yml +++ b/install/docker-compose.yml @@ -66,21 +66,8 @@ services: ports: - 4010:4000 restart: unless-stopped - - sandbox-webhook: - image: fidedocker/sandbox-webhook-api - depends_on: - - registry - - gateway - - sandbox-api - container_name: sandbox-webhook - networks: - - beckn_network - ports: - - 3005:3005 - restart: unless-stopped volumes: - - ./ENV/.env-webhook:/usr/src/app/.env + - ./ENV/.env-sandbox:/usr/src/app/.env bpp-client: image: fidedocker/protocol-server diff --git a/install/scripts/variables.sh b/install/scripts/variables.sh index a753efe..fcda32f 100755 --- a/install/scripts/variables.sh +++ b/install/scripts/variables.sh @@ -50,7 +50,7 @@ bpp_network_port=6002 bpp_subscriber_id="bpp-network" bpp_subscriber_key_id="bpp-network-key" bpp_subscriber_url="http://bpp-network:6002" -webhook_url="http://sandbox-webhook:3005" +webhook_url="http://sandbox-api:3000" bpp_docker_compose_file=docker-compose-bpp.yml bpp_docker_compose_file_sandbox=docker-compose-bpp-with-sandbox.yml diff --git a/install/start_beckn.sh b/install/start_beckn.sh index af9b676..51df301 100755 --- a/install/start_beckn.sh +++ b/install/start_beckn.sh @@ -75,11 +75,6 @@ start_container "sandbox-api" sleep 5 echo "Sandbox installation successful" -echo "${GREEN}................Installing Webhook................${NC}" -start_container "sandbox-webhook" -sleep -echo "Webhook installation successful" - echo "${GREEN}................Installing Protocol Server for BPP................${NC}" bash scripts/update_bpp_config.sh sleep 10 diff --git a/install/start_beckn_v2.sh b/install/start_beckn_v2.sh index acf1f44..43864e9 100755 --- a/install/start_beckn_v2.sh +++ b/install/start_beckn_v2.sh @@ -127,11 +127,6 @@ install_bpp_protocol_server_with_sandbox(){ sleep 5 echo "Sandbox installation successful" - echo "${GREEN}................Installing Webhook................${NC}" - start_container $bpp_docker_compose_file_sandbox "sandbox-webhook" - sleep 5 - echo "Webhook installation successful" - echo "${GREEN}................Installing Protocol Server for BPP................${NC}" if [[ $1 ]];then From 93edf895b4d8664111a934e619683757cc744fa4 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Fri, 10 May 2024 15:36:43 +0530 Subject: [PATCH 073/102] all in one install --- docs/release_notes.md | 3 ++- docs/user_guide.md | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/release_notes.md b/docs/release_notes.md index 79b1426..cfa3b35 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -38,6 +38,7 @@ Experience the convenience and efficiency of Beckn-ONIX as you embark on your jo - The GUI installer needs Node, NPM and LocalTunnel to be installed before starting. ### Release date + 2024-05-06 ## Beckn-ONIX Version 0.3.0 (2024-03-20) @@ -66,7 +67,7 @@ Experience the convenience and efficiency of Beckn-ONIX as you embark on your jo ### Limitations -- The beckn-onix.sh installer used for multi node. For single node installation the start_beckn.sh file has to be used. +- The beckn-onix.sh installer used for multi node. For single node installation the start_beckn.sh file has to be used. (This is not true anymore. The beckn-onix.sh has an option to install all components on a single machine) ### Upcoming Version diff --git a/docs/user_guide.md b/docs/user_guide.md index 227bb05..4657e2c 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -233,7 +233,7 @@ Refer to the [core specification](https://github.com/beckn/protocol-specificatio ## Running Beckn-ONIX locally -- In order for people new to Beckn who want to try out Beckn on their own machine, a simple one click installer has been written. Currently it can be installed by running the `start_beckn.sh` script present in the installfolder. In the next release, this will be integrated with the main script and the `start_beckn.sh` script deprecated. An all in one installation has preconfigured values for variables and so pretty much does not ask for any input. +- In order for people new to Beckn who want to try out Beckn on their own machine, choose the option to "Set up a network on your local machine" in the main screen. The all in one installation has preconfigured values for variables and so pretty much does not ask for any input. ## Appendix A - Registering or adding domain or subdomains From bfc42ca2f4ae081b38990872f90d8c35d0ce9ef2 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Fri, 10 May 2024 17:28:08 +0530 Subject: [PATCH 074/102] Registry id and url for all in one install --- install/beckn-onix.sh | 2 +- install/scripts/update_gateway_details.sh | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 984becc..429385a 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -73,7 +73,7 @@ install_gateway() { if [[ $1 && $2 ]]; then bash scripts/update_gateway_details.sh $1 $2 else - bash scripts/update_gateway_details.sh registry + bash scripts/update_gateway_details.sh http://registry:3030 fi echo "${GREEN}................Installing Gateway service................${NC}" start_container $gateway_docker_compose_file gateway diff --git a/install/scripts/update_gateway_details.sh b/install/scripts/update_gateway_details.sh index 2eec117..5bcb187 100755 --- a/install/scripts/update_gateway_details.sh +++ b/install/scripts/update_gateway_details.sh @@ -90,6 +90,9 @@ if [[ $1 ]]; then registry_id=$(echo "$1" | sed 's/http:\/\///') fi fi + if [[ $registry_id = "registry:3030" ]]; then + registry_id="registry" + fi fi if [[ $2 ]]; then From 593abead1259690be23a0563eb0b9fa1bb787bb9 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Fri, 10 May 2024 19:06:56 +0530 Subject: [PATCH 075/102] Add docker permisssion instruction to user guide --- docs/user_guide.md | 7 + layer2/samples/retail_1.1.0_1.1.0.yaml | 2164 ++++++++++++++++++++++++ 2 files changed, 2171 insertions(+) create mode 100644 layer2/samples/retail_1.1.0_1.1.0.yaml diff --git a/docs/user_guide.md b/docs/user_guide.md index 4657e2c..5045b7a 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -46,6 +46,13 @@ Docker compose and docker are extensively used in the installation and running o - Atleast four virtual servers (EC2 instances) configured on the cloud provider with administrator login (e.g. ssh access) to them. - Access to domain name management with ability to create domain-name/subdomains for each of the components. +- Run the following two commands on all machines where the script is being run for the first time. Login to a new shell for the command to take effect and continue with the installation. Not doing so will result in docker permisssion error + +``` +sudo groupadd docker +sudo usermod -aG docker $USER +``` + - Each of the various sections below list additional pre-requisites which build on these. ### Setting up a new network - Registry diff --git a/layer2/samples/retail_1.1.0_1.1.0.yaml b/layer2/samples/retail_1.1.0_1.1.0.yaml new file mode 100644 index 0000000..e57689e --- /dev/null +++ b/layer2/samples/retail_1.1.0_1.1.0.yaml @@ -0,0 +1,2164 @@ +openapi: 3.0.0 +info: + title: Beckn for Local Retail + description: Adaptation of beckn protocol for the local retail domain + version: 1.1.0 +security: + - SubscriberAuth: [] +paths: + /search: + post: + tags: + - Beckn Provider Platform (BPP) + - Beckn Gateway (BG) + description: BAP declares the customer's intent to buy products from retail providers + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - search + message: + type: object + properties: + intent: + $ref: "#/components/schemas/Intent" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /select: + post: + tags: + - Beckn Provider Platform (BPP) + description: BAP declares the customer's cart (or equivalent) created by selecting objects from the catalog + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /init: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + description: Acknowledgement of message received after successful validation of schema and signature + content: + application/json: + schema: + type: object + properties: + message: + type: object + properties: + ack: + allOf: + - $ref: "#/components/schemas/Ack" + - properties: + status: + enum: + - ACK + - NACK + required: + - ack + error: + $ref: "#/components/schemas/Error" + required: + - message + /confirm: + post: + tags: + - Beckn Provider Platform (BPP) + description: Initialize an order by providing billing and/or shipping details + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /status: + post: + tags: + - Beckn Provider Platform (BPP) + description: Fetch the latest order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - status + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /track: + post: + tags: + - Beckn Provider Platform (BPP) + description: Track an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - track + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + callback_url: + type: string + format: uri + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /cancel: + post: + tags: + - Beckn Provider Platform (BPP) + description: Cancel an order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - cancel + required: + - action + message: + type: object + properties: + order_id: + $ref: "#/components/schemas/Order/properties/id" + cancellation_reason_id: + $ref: "#/components/schemas/Option/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + required: + - order_id + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /update: + post: + tags: + - Beckn Provider Platform (BPP) + description: Remove object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - update + required: + - action + message: + type: object + properties: + update_target: + description: 'Comma separated values of order objects being updated. For example: ```"update_target":"item,billing,fulfillment"```' + type: string + order: + description: Updated order object + allOf: + - $ref: "#/components/schemas/Order" + required: + - update_target + - order + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /rating: + post: + tags: + - Beckn Provider Platform (BPP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - rating + required: + - action + message: + type: object + properties: + ratings: + type: array + items: + $ref: "#/components/schemas/Rating" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /support: + post: + tags: + - Beckn Provider Platform (BPP) + description: Contact support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_search: + post: + tags: + - Beckn Application Platform (BAP) + - Beckn Gateway (BG) + description: BPP sends its catalog in response to a search request. + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_search + required: + - action + message: + type: object + properties: + catalog: + $ref: "#/components/schemas/Catalog" + required: + - catalog + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_select: + post: + tags: + - Beckn Application Platform (BAP) + description: Send draft order object with quoted price for selected items + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_select + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_init: + post: + tags: + - Beckn Application Platform (BAP) + description: Send order object with payment details updated + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_init + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_confirm: + post: + tags: + - Beckn Application Platform (BAP) + description: Send active order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_confirm + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_track: + post: + tags: + - Beckn Application Platform (BAP) + description: Send tracking details of an active order + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_track + required: + - action + message: + type: object + properties: + tracking: + $ref: "#/components/schemas/Tracking" + required: + - tracking + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_cancel: + post: + tags: + - Beckn Application Platform (BAP) + description: Send cancellation request_id with reasons list in case of cancellation request. Else send cancelled order object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_cancel + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_update: + post: + tags: + - Beckn Application Platform (BAP) + description: Returns updated service with updated runtime object + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_update + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_status: + post: + tags: + - Beckn Application Platform (BAP) + description: Fetch the status of a Service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_status + required: + - action + message: + type: object + properties: + order: + $ref: "#/components/schemas/Order" + required: + - order + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_rating: + post: + tags: + - Beckn Application Platform (BAP) + description: Provide feedback on a service + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_rating + required: + - action + message: + type: object + properties: + feedback_form: + description: A feedback form to allow the user to provide additional information on the rating provided + allOf: + - $ref: "#/components/schemas/XInput" + error: + $ref: "#/components/schemas/Error" + required: + - context + - message + responses: + default: + $ref: "#/paths/~1init/post/responses/default" + /on_support: + post: + tags: + - Beckn Application Platform (BAP) + description: Contact Support + requestBody: + content: + application/json: + schema: + type: object + properties: + context: + allOf: + - $ref: "#/components/schemas/Context" + - properties: + action: + enum: + - on_support + required: + - action + message: + type: object + properties: + support: + $ref: "#/components/schemas/Support" + error: + $ref: "#/components/schemas/Error" + required: + - context + responses: + default: + $ref: "#/paths/~1init/post/responses/default" +components: + securitySchemes: + SubscriberAuth: + type: apiKey + in: header + name: Authorization + description: 'Signature of message body using BAP or BPP subscriber''s signing public key.

Format:

Authorization : Signature keyId="{subscriber_id}|{unique_key_id}|{algorithm}",algorithm="ed25519",created="1606970629",expires="1607030629",headers="(created) (expires) digest",signature="Base64(signing string)"' + schemas: + Ack: + description: "Describes the acknowledgement sent in response to an API call. If the implementation uses HTTP/S, then Ack must be returned in the same session. Every API call to a BPP must be responded to with an Ack whether the BPP intends to respond with a callback or not. This has one property called `status` that indicates the status of the Acknowledgement." + type: object + properties: + status: + type: string + description: "The status of the acknowledgement. If the request passes the validation criteria of the BPP, then this is set to ACK. If a BPP responds with status = `ACK` to a request, it is required to respond with a callback. If the request fails the validation criteria, then this is set to NACK. Additionally, if a BPP does not intend to respond with a callback even after the request meets the validation criteria, it should set this value to `NACK`." + enum: + - ACK + - NACK + tags: + description: A list of tags containing any additional information sent along with the Acknowledgement. + type: array + items: + $ref: "#/components/schemas/TagGroup" + AddOn: + description: Describes an additional item offered as a value-addition to a product or service. This does not exist independently in a catalog and is always associated with an item. + type: object + properties: + id: + description: Provider-defined ID of the add-on + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + price: + $ref: "#/components/schemas/Price" + Address: + description: Describes a postal address. + type: string + Agent: + description: "Describes the direct performer, driver or executor that fulfills an order. It is usually a person. But in some rare cases, it could be a non-living entity like a drone, or a bot. Some examples of agents are Doctor in the healthcare sector, a driver in the mobility sector, or a delivery person in the logistics sector. This object can be set at any stage of the order lifecycle. This can be set at the discovery stage when the BPP wants to provide details on the agent fulfilling the order, like in healthcare, where the doctor's name appears during search. This object can also used to search for a particular person that the customer wants fulfilling an order. Sometimes, this object gets instantiated after the order is confirmed, like in the case of on-demand taxis, where the driver is assigned after the user confirms the ride." + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + organization: + $ref: "#/components/schemas/Organization" + rating: + $ref: "#/components/schemas/Rating/properties/value" + Authorization: + description: "Describes an authorization mechanism used to start or end the fulfillment of an order. For example, in the mobility sector, the driver may require a one-time password to initiate the ride. In the healthcare sector, a patient may need to provide a password to open a video conference link during a teleconsultation." + type: object + properties: + type: + description: Type of authorization mechanism used. The allowed values for this field can be published as part of the network policy. + type: string + token: + description: "Token used for authorization. This is typically generated at the BPP. The BAP can send this value to the user via any channel that it uses to authenticate the user like SMS, Email, Push notification, or in-app rendering." + type: string + valid_from: + description: Timestamp in RFC3339 format from which token is valid + type: string + format: date-time + valid_to: + description: Timestamp in RFC3339 format until which token is valid + type: string + format: date-time + status: + description: Status of the token + type: string + Billing: + description: "Describes the billing details of an entity.
This has properties like name,organization,address,email,phone,time,tax_number, created_at,updated_at" + type: object + properties: + name: + description: Name of the billable entity + type: string + organization: + description: Details of the organization being billed. + allOf: + - $ref: "#/components/schemas/Organization" + address: + description: The address of the billable entity + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the billable entity resides. This is important for state-level tax calculation + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the billable entity resides. + allOf: + - $ref: "#/components/schemas/City" + email: + description: Email address where the bill is sent to + type: string + format: email + phone: + description: Phone number of the billable entity + type: string + time: + description: Details regarding the billing period + allOf: + - $ref: "#/components/schemas/Time" + tax_id: + description: ID of the billable entity as recognized by the taxation authority + type: string + Cancellation: + description: Describes a cancellation event + type: object + properties: + time: + description: Date-time when the order was cancelled by the buyer + type: string + format: date-time + cancelled_by: + type: string + enum: + - CONSUMER + - PROVIDER + reason: + description: The reason for cancellation + allOf: + - $ref: "#/components/schemas/Option" + additional_description: + description: Any additional information regarding the nature of cancellation + allOf: + - $ref: "#/components/schemas/Descriptor" + CancellationTerm: + description: Describes the cancellation terms of an item or an order. This can be referenced at an item or order level. Item-level cancellation terms can override the terms at the order level. + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + reason_required: + description: Indicates whether a reason is required to cancel the order + type: boolean + cancel_by: + description: Information related to the time of cancellation. + allOf: + - $ref: "#/components/schemas/Time" + cancellation_fee: + $ref: "#/components/schemas/Fee" + xinput: + $ref: "#/components/schemas/XInput" + external_ref: + $ref: "#/components/schemas/MediaFile" + Catalog: + description: "Describes the products or services offered by a BPP. This is typically sent as the response to a search intent from a BAP. The payment terms, offers and terms of fulfillment supported by the BPP can also be included here. The BPP can show hierarchical nature of products/services in its catalog using the parent_category_id in categories. The BPP can also send a ttl (time to live) in the context which is the duration for which a BAP can cache the catalog and use the cached catalog.
This has properties like bbp/descriptor,bbp/categories,bbp/fulfillments,bbp/payments,bbp/offers,bbp/providers and exp
This is used in the following situations.
  • This is typically used in the discovery stage when the BPP sends the details of the products and services it offers as response to a search intent from the BAP.
" + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + fulfillments: + description: Fulfillment modes offered at the BPP level. This is used when a BPP itself offers fulfillments on behalf of the providers it has onboarded. + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + description: Payment terms offered by the BPP for all transactions. This can be overriden at the provider level. + type: array + items: + $ref: "#/components/schemas/Payment" + offers: + description: Offers at the BPP-level. This is common across all providers onboarded by the BPP. + type: array + items: + $ref: "#/components/schemas/Offer" + providers: + type: array + items: + $ref: "#/components/schemas/Provider" + exp: + description: Timestamp after which catalog will expire + type: string + format: date-time + ttl: + description: Duration in seconds after which this catalog will expire + type: string + Category: + description: A label under which a collection of items can be grouped. + type: object + properties: + id: + description: ID of the category + type: string + parent_category_id: + $ref: "#/components/schemas/Category/properties/id" + descriptor: + $ref: "#/components/schemas/Descriptor" + time: + $ref: "#/components/schemas/Time" + ttl: + description: Time to live for an instance of this schema + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Circle: + description: Describes a circular region of a specified radius centered at a specified GPS coordinate. + type: object + properties: + gps: + $ref: "#/components/schemas/Gps" + radius: + $ref: "#/components/schemas/Scalar" + City: + description: Describes a city + type: object + properties: + name: + description: Name of the city + type: string + code: + description: City code + type: string + Contact: + description: Describes the contact information of an entity + type: object + properties: + phone: + type: string + email: + type: string + jcard: + type: object + description: A Jcard object as per draft-ietf-jcardcal-jcard-03 specification + Context: + description: "Every API call in beckn protocol has a context. It provides a high-level overview to the receiver about the nature of the intended transaction. Typically, it is the BAP that sets the transaction context based on the consumer's location and action on their UI. But sometimes, during unsolicited callbacks, the BPP also sets the transaction context but it is usually the same as the context of a previous full-cycle, request-callback interaction between the BAP and the BPP. The context object contains four types of fields.
  1. Demographic information about the transaction using fields like `domain`, `country`, and `region`.
  2. Addressing details like the sending and receiving platform's ID and API URL.
  3. Interoperability information like the protocol version that implemented by the sender and,
  4. Transaction details like the method being called at the receiver's endpoint, the transaction_id that represents an end-to-end user session at the BAP, a message ID to pair requests with callbacks, a timestamp to capture sending times, a ttl to specifiy the validity of the request, and a key to encrypt information if necessary.
This object must be passed in every interaction between a BAP and a BPP. In HTTP/S implementations, it is not necessary to send the context during the synchronous response. However, in asynchronous protocols, the context must be sent during all interactions," + type: object + properties: + domain: + description: Domain code that is relevant to this transaction context + allOf: + - $ref: "#/components/schemas/Domain/properties/code" + location: + description: The location where the transaction is intended to be fulfilled. + allOf: + - $ref: "#/components/schemas/Location" + action: + description: The Beckn protocol method being called by the sender and executed at the receiver. + type: string + version: + type: string + description: Version of transaction protocol being used by the sender. + bap_id: + description: Subscriber ID of the BAP + allOf: + - description: "A globally unique identifier of the platform, Typically it is the fully qualified domain name (FQDN) of the platform." + type: string + bap_uri: + description: Subscriber URL of the BAP for accepting callbacks from BPPs. + allOf: + - description: The callback URL of the Subscriber. This should necessarily contain the same domain name as set in `subscriber_id``. + type: string + format: uri + bpp_id: + description: Subscriber ID of the BPP + allOf: + - $ref: "#/components/schemas/Context/properties/bap_id/allOf/0" + bpp_uri: + description: Subscriber URL of the BPP for accepting calls from BAPs. + allOf: + - $ref: "#/components/schemas/Context/properties/bap_uri/allOf/0" + transaction_id: + description: "This is a unique value which persists across all API calls from `search` through `confirm`. This is done to indicate an active user session across multiple requests. The BPPs can use this value to push personalized recommendations, and dynamic offerings related to an ongoing transaction despite being unaware of the user active on the BAP." + type: string + format: uuid + message_id: + description: "This is a unique value which persists during a request / callback cycle. Since beckn protocol APIs are asynchronous, BAPs need a common value to match an incoming callback from a BPP to an earlier call. This value can also be used to ignore duplicate messages coming from the BPP. It is recommended to generate a fresh message_id for every new interaction. When sending unsolicited callbacks, BPPs must generate a new message_id." + type: string + format: uuid + timestamp: + description: Time of request generation in RFC3339 format + type: string + format: date-time + key: + description: The encryption public key of the sender + type: string + ttl: + description: The duration in ISO8601 format after timestamp for which this message holds valid + type: string + Country: + description: Describes a country + type: object + properties: + name: + type: string + description: Name of the country + code: + type: string + description: Country code as per ISO 3166-1 and ISO 3166-2 format + Credential: + description: Describes a credential of an entity - Person or Organization + type: object + properties: + id: + type: string + type: + type: string + default: VerifiableCredential + url: + description: URL of the credential + type: string + format: uri + Customer: + description: Describes a customer buying/availing a product or a service + type: object + properties: + person: + $ref: "#/components/schemas/Person" + contact: + $ref: "#/components/schemas/Contact" + DecimalValue: + description: Describes a numerical value in decimal form + type: string + pattern: "[+-]?([0-9]*[.])?[0-9]+" + Descriptor: + description: Physical description of something. + type: object + properties: + name: + type: string + code: + type: string + short_desc: + type: string + long_desc: + type: string + additional_desc: + type: object + properties: + url: + type: string + content_type: + type: string + enum: + - text/plain + - text/html + - application/json + media: + type: array + items: + $ref: "#/components/schemas/MediaFile" + images: + type: array + items: + $ref: "#/components/schemas/Image" + Domain: + description: "Described the industry sector or sub-sector. The network policy should contain codes for all the industry sectors supported by the network. Domains can be created in varying levels of granularity. The granularity of a domain can be decided by the participants of the network. Too broad domains will result in irrelevant search broadcast calls to BPPs that don't have services supporting the domain. Too narrow domains will result in a large number of registry entries for each BPP. It is recommended that network facilitators actively collaborate with various working groups and network participants to carefully choose domain codes keeping in mind relevance, performance, and opportunity cost. It is recommended that networks choose broad domains like mobility, logistics, healthcare etc, and progressively granularize them as and when the number of network participants for each domain grows large." + type: object + properties: + name: + description: Name of the domain + type: string + code: + description: "Standard code representing the domain. The standard is usually published as part of the network policy. Furthermore, the network facilitator should also provide a mechanism to provide the supported domains of a network." + additional_info: + description: A url that contains addtional information about that domain. + allOf: + - $ref: "#/components/schemas/MediaFile" + Duration: + description: Describes duration as per ISO8601 format + type: string + Error: + description: "Describes an error object that is returned by a BAP, BPP or BG as a response or callback to an action by another network participant. This object is sent when any request received by a network participant is unacceptable. This object can be sent either during Ack or with the callback." + type: object + properties: + code: + type: string + description: 'Standard error code. For full list of error codes, refer to docs/protocol-drafts/BECKN-005-ERROR-CODES-DRAFT-01.md of this repo"' + paths: + type: string + description: Path to json schema generating the error. Used only during json schema validation errors + message: + type: string + description: Human readable message describing the error. Used mainly for logging. Not recommended to be shown to the user. + Fee: + description: A fee applied on a particular entity + type: object + properties: + percentage: + description: Percentage of a value + allOf: + - $ref: "#/components/schemas/DecimalValue" + amount: + description: A fixed value + allOf: + - $ref: "#/components/schemas/Price" + Form: + description: Describes a form + type: object + properties: + url: + description: "The URL from where the form can be fetched. The content fetched from the url must be processed as per the mime_type specified in this object. Once fetched, the rendering platform can choosed to render the form as-is as an embeddable element; or process it further to blend with the theme of the application. In case the interface is non-visual, the the render can process the form data and reproduce it as per the standard specified in the form." + type: string + format: uri + data: + description: The form submission data + type: object + additionalProperties: + type: string + mime_type: + description: This field indicates the nature and format of the form received by querying the url. MIME types are defined and standardized in IETF's RFC 6838. + type: string + enum: + - text/html + - application/xml + submission_id: + type: string + format: uuid + Fulfillment: + description: Describes how a an order will be rendered/fulfilled to the end-customer + type: object + properties: + id: + description: Unique reference ID to the fulfillment of an order + type: string + type: + description: "A code that describes the mode of fulfillment. This is typically set when there are multiple ways an order can be fulfilled. For example, a retail order can be fulfilled either via store pickup or a home delivery. Similarly, a medical consultation can be provided either in-person or via tele-consultation. The network policy must publish standard fulfillment type codes for the different modes of fulfillment." + type: string + rateable: + description: Whether the fulfillment can be rated or not + type: boolean + rating: + description: The rating value of the fulfullment service. + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + state: + description: The current state of fulfillment. The BPP must set this value whenever the state of the order fulfillment changes and fire an unsolicited `on_status` call. + allOf: + - $ref: "#/components/schemas/FulfillmentState" + tracking: + type: boolean + description: Indicates whether the fulfillment allows tracking + default: false + customer: + description: The person that will ultimately receive the order + allOf: + - $ref: "#/components/schemas/Customer" + agent: + description: The agent that is currently handling the fulfillment of the order + allOf: + - $ref: "#/components/schemas/Agent" + contact: + $ref: "#/components/schemas/Contact" + vehicle: + $ref: "#/components/schemas/Vehicle" + stops: + description: The list of logical stops encountered during the fulfillment of an order. + type: array + items: + $ref: "#/components/schemas/Stop" + path: + description: The physical path taken by the agent that can be rendered on a map. The allowed format of this property can be set by the network. + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + FulfillmentState: + description: Describes the state of fulfillment + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + updated_at: + type: string + format: date-time + updated_by: + type: string + description: ID of entity which changed the state + Gps: + description: Describes a GPS coordinate + type: string + pattern: '^[-+]?([1-8]?\d(\.\d+)?|90(\.0+)?),\s*[-+]?(180(\.0+)?|((1[0-7]\d)|([1-9]?\d))(\.\d+)?)$' + Image: + description: Describes an image + type: object + properties: + url: + description: URL to the image. This can be a data url or an remote url + type: string + format: uri + size_type: + description: The size of the image. The network policy can define the default dimensions of each type + type: string + enum: + - xs + - sm + - md + - lg + - xl + - custom + width: + description: Width of the image in pixels + type: string + height: + description: Height of the image in pixels + type: string + Intent: + description: "The intent to buy or avail a product or a service. The BAP can declare the intent of the consumer containing
  • What they want (A product, service, offer)
  • Who they want (A seller, service provider, agent etc)
  • Where they want it and where they want it from
  • When they want it (start and end time of fulfillment
  • How they want to pay for it

This has properties like descriptor,provider,fulfillment,payment,category,offer,item,tags
This is typically used by the BAP to send the purpose of the user's search to the BPP. This will be used by the BPP to find products or services it offers that may match the user's intent.
For example, in Mobility, the mobility consumer declares a mobility intent. In this case, the mobility consumer declares information that describes various aspects of their journey like,
  • Where would they like to begin their journey (intent.fulfillment.start.location)
  • Where would they like to end their journey (intent.fulfillment.end.location)
  • When would they like to begin their journey (intent.fulfillment.start.time)
  • When would they like to end their journey (intent.fulfillment.end.time)
  • Who is the transport service provider they would like to avail services from (intent.provider)
  • Who is traveling (This is not recommended in public networks) (intent.fulfillment.customer)
  • What kind of fare product would they like to purchase (intent.item)
  • What add-on services would they like to avail
  • What offers would they like to apply on their booking (intent.offer)
  • What category of services would they like to avail (intent.category)
  • What additional luggage are they carrying
  • How would they like to pay for their journey (intent.payment)

For example, in health domain, a consumer declares the intent for a lab booking the describes various aspects of their booking like,
  • Where would they like to get their scan/test done (intent.fulfillment.start.location)
  • When would they like to get their scan/test done (intent.fulfillment.start.time)
  • When would they like to get the results of their test/scan (intent.fulfillment.end.time)
  • Who is the service provider they would like to avail services from (intent.provider)
  • Who is getting the test/scan (intent.fulfillment.customer)
  • What kind of test/scan would they like to purchase (intent.item)
  • What category of services would they like to avail (intent.category)
  • How would they like to pay for their journey (intent.payment)
" + type: object + properties: + descriptor: + description: "A raw description of the search intent. Free text search strings, raw audio, etc can be sent in this object." + allOf: + - $ref: "#/components/schemas/Descriptor" + provider: + description: The provider from which the customer wants to place to the order from + allOf: + - $ref: "#/components/schemas/Provider" + fulfillment: + description: Details on how the customer wants their order fulfilled + allOf: + - $ref: "#/components/schemas/Fulfillment" + payment: + description: Details on how the customer wants to pay for the order + allOf: + - $ref: "#/components/schemas/Payment" + category: + description: Details on the item category + allOf: + - $ref: "#/components/schemas/Category" + offer: + description: details on the offer the customer wants to avail + allOf: + - $ref: "#/components/schemas/Offer" + item: + description: Details of the item that the consumer wants to order + allOf: + - $ref: "#/components/schemas/Item" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + ItemQuantity: + description: Describes the count or amount of an item + type: object + properties: + allocated: + description: This represents the exact quantity allocated for purchase of the item. + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + available: + description: This represents the exact quantity available for purchase of the item. The buyer can only purchase multiples of this + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + maximum: + description: This represents the maximum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 1 + measure: + $ref: "#/components/schemas/Scalar" + minimum: + description: This represents the minimum quantity allowed for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + selected: + description: This represents the quantity selected for purchase of the item + type: object + properties: + count: + type: integer + minimum: 0 + measure: + $ref: "#/components/schemas/Scalar" + unitized: + description: This represents the quantity available in a single unit of the item + type: object + properties: + count: + type: integer + minimum: 1 + maximum: 1 + measure: + $ref: "#/components/schemas/Scalar" + Item: + description: "Describes a product or a service offered to the end consumer by the provider. In the mobility sector, it can represent a fare product like one way journey. In the logistics sector, it can represent the delivery service offering. In the retail domain it can represent a product like a grocery item." + type: object + properties: + id: + description: ID of the item. + type: string + parent_item_id: + description: "ID of the item, this item is a variant of" + allOf: + - $ref: "#/components/schemas/Item/properties/id" + parent_item_quantity: + description: The number of units of the parent item this item is a multiple of + allOf: + - $ref: "#/components/schemas/ItemQuantity" + descriptor: + description: Physical description of the item + allOf: + - $ref: "#/components/schemas/Descriptor" + creator: + description: The creator of this item + allOf: + - $ref: "#/components/schemas/Organization" + price: + description: "The price of this item, if it has intrinsic value" + allOf: + - $ref: "#/components/schemas/Price" + quantity: + description: The selling quantity of the item + allOf: + - $ref: "#/components/schemas/ItemQuantity" + category_ids: + description: Categories this item can be listed under + type: array + items: + allOf: + - $ref: "#/components/schemas/Category/properties/id" + fulfillment_ids: + description: Modes through which this item can be fulfilled + type: array + items: + allOf: + - $ref: "#/components/schemas/Fulfillment/properties/id" + location_ids: + description: Provider Locations this item is available in + type: array + items: + allOf: + - $ref: "#/components/schemas/Location/properties/id" + payment_ids: + description: Payment modalities through which this item can be ordered + type: array + items: + allOf: + - $ref: "#/components/schemas/Payment/properties/id" + add_ons: + type: array + items: + $ref: "#/components/schemas/AddOn" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + description: Refund term of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + refund_eligible: + description: Indicates if cancellation will result in a refund + type: boolean + refund_within: + description: Time within which refund will be processed after successful cancellation. + allOf: + - $ref: "#/components/schemas/Time" + refund_amount: + $ref: "#/components/schemas/Price" + replacement_terms: + description: Terms that are applicable be met when this item is replaced + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Terms that are applicable when this item is returned + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + xinput: + description: Additional input required from the customer to purchase / avail this item + allOf: + - $ref: "#/components/schemas/XInput" + time: + description: Temporal attributes of this item. This property is used when the item exists on the catalog only for a limited period of time. + allOf: + - $ref: "#/components/schemas/Time" + rateable: + description: Whether this item can be rated + type: boolean + rating: + description: The rating of the item + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + matched: + description: Whether this item is an exact match of the request + type: boolean + related: + description: Whether this item is a related item to the exactly matched item + type: boolean + recommended: + description: Whether this item is a recommended item to a response + type: boolean + ttl: + description: Time to live in seconds for an instance of this schema + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Location: + description: The physical location of something + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + map_url: + description: The url to the map of the location. This can be a globally recognized map url or the one specified by the network policy. + type: string + format: uri + gps: + description: The GPS co-ordinates of this location. + allOf: + - $ref: "#/components/schemas/Gps" + address: + description: The address of this location. + allOf: + - $ref: "#/components/schemas/Address" + city: + description: "The city this location is, or is located within" + allOf: + - $ref: "#/components/schemas/City" + district: + description: "The state this location is, or is located within" + type: string + state: + description: "The state this location is, or is located within" + allOf: + - $ref: "#/components/schemas/State" + country: + description: "The country this location is, or is located within" + allOf: + - $ref: "#/components/schemas/Country" + area_code: + type: string + circle: + $ref: "#/components/schemas/Circle" + polygon: + description: The boundary polygon of this location + type: string + 3dspace: + description: The three dimensional region describing this location + type: string + rating: + description: The rating of this location + allOf: + - $ref: "#/components/schemas/Rating/properties/value" + MediaFile: + description: This object contains a url to a media file. + type: object + properties: + mimetype: + description: "indicates the nature and format of the document, file, or assortment of bytes. MIME types are defined and standardized in IETF's RFC 6838" + type: string + url: + description: The URL of the file + type: string + format: uri + signature: + description: The digital signature of the file signed by the sender + type: string + dsa: + description: The signing algorithm used by the sender + type: string + Offer: + description: An offer associated with a catalog. This is typically used to promote a particular product and enable more purchases. + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + location_ids: + type: array + items: + $ref: "#/components/schemas/Location/properties/id" + category_ids: + type: array + items: + $ref: "#/components/schemas/Category/properties/id" + item_ids: + type: array + items: + $ref: "#/components/schemas/Item/properties/id" + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Option: + description: Describes a selectable option + type: object + properties: + id: + type: string + descriptor: + $ref: "#/components/schemas/Descriptor" + Order: + description: Describes a legal purchase order. It contains the complete details of the legal contract created between the buyer and the seller. + type: object + properties: + id: + type: string + description: Human-readable ID of the order. This is generated at the BPP layer. The BPP can either generate order id within its system or forward the order ID created at the provider level. + ref_order_ids: + description: A list of order IDs to link this order to previous orders. + type: array + items: + type: string + description: ID of a previous order + status: + description: Status of the order. Allowed values can be defined by the network policy + type: string + enum: + - ACTIVE + - COMPLETE + - CANCELLED + type: + description: "This is used to indicate the type of order being created to BPPs. Sometimes orders can be linked to previous orders, like a replacement order in a retail domain. A follow-up consultation in healthcare domain. A single order part of a subscription order. The list of order types can be standardized at the network level." + type: string + default: DEFAULT + enum: + - DRAFT + - DEFAULT + provider: + description: Details of the provider whose catalog items have been selected. + allOf: + - $ref: "#/components/schemas/Provider" + items: + description: The items purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/Item" + add_ons: + description: The add-ons purchased / availed in this order + type: array + items: + $ref: "#/components/schemas/AddOn" + offers: + description: The offers applied in this order + type: array + items: + $ref: "#/components/schemas/Offer" + billing: + description: The billing details of this order + allOf: + - $ref: "#/components/schemas/Billing" + fulfillments: + description: The fulfillments involved in completing this order + type: array + items: + $ref: "#/components/schemas/Fulfillment" + cancellation: + description: The cancellation details of this order + allOf: + - $ref: "#/components/schemas/Cancellation" + cancellation_terms: + description: Cancellation terms of this item + type: array + items: + $ref: "#/components/schemas/CancellationTerm" + refund_terms: + description: Refund terms of this item + type: array + items: + $ref: "#/components/schemas/Item/properties/refund_terms/items" + replacement_terms: + description: Replacement terms of this item + type: array + items: + $ref: "#/components/schemas/ReplacementTerm" + return_terms: + description: Return terms of this item + type: array + items: + $ref: "#/components/schemas/ReturnTerm" + quote: + description: The mutually agreed upon quotation for this order. + allOf: + - $ref: "#/components/schemas/Quotation" + payments: + description: The terms of settlement for this order + type: array + items: + $ref: "#/components/schemas/Payment" + created_at: + description: The date-time of creation of this order + type: string + format: date-time + updated_at: + description: The date-time of updated of this order + type: string + format: date-time + xinput: + description: Additional input required from the customer to confirm this order + allOf: + - $ref: "#/components/schemas/XInput" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Organization: + description: An organization. Usually a recognized business entity. + type: object + properties: + descriptor: + $ref: "#/components/schemas/Descriptor" + address: + description: The postal address of the organization + allOf: + - $ref: "#/components/schemas/Address" + state: + description: The state where the organization's address is registered + allOf: + - $ref: "#/components/schemas/State" + city: + description: The city where the the organization's address is registered + allOf: + - $ref: "#/components/schemas/City" + contact: + $ref: "#/components/schemas/Contact" + Payment: + description: "Describes the terms of settlement between the BAP and the BPP for a single transaction. When instantiated, this object contains
  1. the amount that has to be settled,
  2. The payment destination destination details
  3. When the settlement should happen, and
  4. A transaction reference ID
. During a transaction, the BPP reserves the right to decide the terms of payment. However, the BAP can send its terms to the BPP first. If the BPP does not agree to those terms, it must overwrite the terms and return them to the BAP. If overridden, the BAP must either agree to the terms sent by the BPP in order to preserve the provider's autonomy, or abort the transaction. In case of such disagreements, the BAP and the BPP can perform offline negotiations on the payment terms. Once an agreement is reached, the BAP and BPP can resume transactions." + type: object + properties: + id: + description: ID of the payment term that can be referred at an item or an order level in a catalog + type: string + collected_by: + description: "This field indicates who is the collector of payment. The BAP can set this value to 'bap' if it wants to collect the payment first and settle it to the BPP. If the BPP agrees to those terms, the BPP should not send the payment url. Alternatively, the BPP can set this field with the value 'bpp' if it wants the payment to be made directly." + url: + type: string + description: "A payment url to be called by the BAP. If empty, then the payment is to be done offline. The details of payment should be present in the params object. If tl_method = http/get, then the payment details will be sent as url params. Two url param values, ```$transaction_id``` and ```$amount``` are mandatory." + format: uri + params: + type: object + properties: + transaction_id: + type: string + description: The reference transaction ID associated with a payment activity + amount: + type: string + currency: + type: string + bank_code: + type: string + bank_account_number: + type: string + virtual_payment_address: + type: string + source_bank_code: + type: string + source_bank_account_number: + type: string + source_virtual_payment_address: + type: string + type: + type: string + enum: + - PRE-ORDER + - PRE-FULFILLMENT + - ON-FULFILLMENT + - POST-FULFILLMENT + status: + type: string + enum: + - PAID + - NOT-PAID + time: + $ref: "#/components/schemas/Time" + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Person: + description: Describes a person as any individual + type: object + properties: + id: + type: string + description: Describes the identity of the person + url: + description: Profile url of the person + type: string + format: uri + name: + description: the name of the person + type: string + image: + $ref: "#/components/schemas/Image" + age: + description: Age of the person + allOf: + - $ref: "#/components/schemas/Duration" + dob: + description: Date of birth of the person + type: string + format: date + gender: + type: string + description: "Gender of something, typically a Person, but possibly also fictional characters, animals, etc. While Male and Female may be used, text strings are also acceptable for people who do not identify as a binary gender.Allowed values for this field can be published in the network policy" + creds: + type: array + items: + $ref: "#/components/schemas/Credential" + languages: + type: array + items: + description: Describes a language known to the person. + type: object + properties: + code: + type: string + name: + type: string + skills: + type: array + items: + description: Describes a skill of the person. + type: object + properties: + code: + type: string + name: + type: string + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Price: + description: Describes the price of a product or service + type: object + properties: + currency: + type: string + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + listed_value: + $ref: "#/components/schemas/DecimalValue" + offered_value: + $ref: "#/components/schemas/DecimalValue" + minimum_value: + $ref: "#/components/schemas/DecimalValue" + maximum_value: + $ref: "#/components/schemas/DecimalValue" + Provider: + description: Describes the catalog of a business. + type: object + properties: + id: + type: string + description: Id of the provider + descriptor: + $ref: "#/components/schemas/Descriptor" + category_id: + type: string + description: Category Id of the provider at the BPP-level catalog + rating: + $ref: "#/components/schemas/Rating/properties/value" + time: + $ref: "#/components/schemas/Time" + categories: + type: array + items: + $ref: "#/components/schemas/Category" + fulfillments: + type: array + items: + $ref: "#/components/schemas/Fulfillment" + payments: + type: array + items: + $ref: "#/components/schemas/Payment" + locations: + type: array + items: + $ref: "#/components/schemas/Location" + offers: + type: array + items: + $ref: "#/components/schemas/Offer" + items: + type: array + items: + $ref: "#/components/schemas/Item" + exp: + type: string + description: Time after which catalog has to be refreshed + format: date-time + rateable: + description: Whether this provider can be rated or not + type: boolean + ttl: + description: "The time-to-live in seconds, for this object. This can be overriden at deeper levels. A value of -1 indicates that this object is not cacheable." + type: integer + minimum: -1 + tags: + type: array + items: + $ref: "#/components/schemas/TagGroup" + Quotation: + description: "Describes a quote. It is the estimated price of products or services from the BPP.
This has properties like price, breakup, ttl" + type: object + properties: + id: + description: ID of the quote. + type: string + format: uuid + price: + description: The total quoted price + allOf: + - $ref: "#/components/schemas/Price" + breakup: + description: the breakup of the total quoted price + type: array + items: + type: object + properties: + item: + $ref: "#/components/schemas/Item" + title: + type: string + price: + $ref: "#/components/schemas/Price" + ttl: + $ref: "#/components/schemas/Duration" + Rating: + description: Describes the rating of an entity + type: object + properties: + rating_category: + description: Category of the entity being rated + type: string + enum: + - Item + - Order + - Fulfillment + - Provider + - Agent + - Support + id: + description: Id of the object being rated + type: string + value: + description: "Rating value given to the object. This can be a single value or can also contain an inequality operator like gt, gte, lt, lte. This can also contain an inequality expression containing logical operators like && and ||." + type: string + Region: + description: Describes an arbitrary region of space. The network policy should contain a published list of supported regions by the network. + type: object + properties: + dimensions: + description: "The number of dimensions that are used to describe any point inside that region. The most common dimensionality of a region is 2, that represents an area on a map. There are regions on the map that can be approximated to one-dimensional regions like roads, railway lines, or shipping lines. 3 dimensional regions are rarer, but are gaining popularity as flying drones are being adopted for various fulfillment services." + type: string + enum: + - "1" + - "2" + - "3" + type: + description: "The type of region. This is used to specify the granularity of the region represented by this object. Various examples of two-dimensional region types are city, country, state, district, and so on. The network policy should contain a list of all possible region types supported by the network." + type: string + name: + type: string + description: Name of the region as specified on the map where that region exists. + code: + type: string + description: A standard code representing the region. This should be interpreted in the same way by all network participants. + boundary: + type: string + description: "A string representing the boundary of the region. One-dimensional regions are represented by polylines. Two-dimensional regions are represented by polygons, and three-dimensional regions can represented by polyhedra." + map_url: + type: string + description: The url to the map of the region. This can be a globally recognized map or the one specified by the network policy. + ReplacementTerm: + description: The replacement policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term is applicable. + allOf: + - $ref: "#/components/schemas/State" + replace_within: + description: "Applicable only for buyer managed returns where the buyer has to replace the item before a certain date-time, failing which they will not be eligible for replacement" + allOf: + - $ref: "#/components/schemas/Time" + external_ref: + $ref: "#/components/schemas/MediaFile" + ReturnTerm: + description: Describes the return policy of an item or an order + type: object + properties: + fulfillment_state: + description: The state of fulfillment during which this term IETF''s applicable. + allOf: + - $ref: "#/components/schemas/State" + return_eligible: + description: Indicates whether the item is eligible for return + type: boolean + return_time: + description: "Applicable only for buyer managed returns where the buyer has to return the item to the origin before a certain date-time, failing which they will not be eligible for refund." + allOf: + - $ref: "#/components/schemas/Time" + return_location: + description: The location where the item or order must / will be returned to + allOf: + - $ref: "#/components/schemas/Location" + fulfillment_managed_by: + description: The entity that will perform the return + type: string + enum: + - CONSUMER + - PROVIDER + Scalar: + description: Describes a scalar + type: object + properties: + type: + type: string + enum: + - CONSTANT + - VARIABLE + value: + $ref: "#/components/schemas/DecimalValue" + estimated_value: + $ref: "#/components/schemas/DecimalValue" + computed_value: + $ref: "#/components/schemas/DecimalValue" + range: + type: object + properties: + min: + $ref: "#/components/schemas/DecimalValue" + max: + $ref: "#/components/schemas/DecimalValue" + unit: + type: string + Schedule: + description: "Describes schedule as a repeating time period used to describe a regularly recurring event. At a minimum a schedule will specify frequency which describes the interval between occurrences of the event. Additional information can be provided to specify the schedule more precisely. This includes identifying the timestamps(s) of when the event will take place. Schedules may also have holidays to exclude a specific day from the schedule.
This has properties like frequency, holidays, times" + type: object + properties: + frequency: + $ref: "#/components/schemas/Duration" + holidays: + type: array + items: + type: string + format: date-time + times: + type: array + items: + type: string + format: date-time + State: + description: A bounded geopolitical region of governance inside a country. + type: object + properties: + name: + type: string + description: Name of the state + code: + type: string + description: State code as per country or international standards + Stop: + description: A logical point in space and time during the fulfillment of an order. + type: object + properties: + id: + type: string + parent_stop_id: + type: string + location: + description: Location of the stop + allOf: + - $ref: "#/components/schemas/Location" + type: + description: The type of stop. Allowed values of this property can be defined by the network policy. + type: string + time: + description: Timings applicable at the stop. + allOf: + - $ref: "#/components/schemas/Time" + instructions: + description: Instructions that need to be followed at the stop + allOf: + - $ref: "#/components/schemas/Descriptor" + contact: + description: Contact details of the stop + allOf: + - $ref: "#/components/schemas/Contact" + person: + description: The details of the person present at the stop + allOf: + - $ref: "#/components/schemas/Person" + authorization: + $ref: "#/components/schemas/Authorization" + Support: + description: Details of customer support + type: object + properties: + ref_id: + type: string + callback_phone: + type: string + format: phone + phone: + type: string + format: phone + email: + type: string + format: email + url: + type: string + format: uri + Tag: + description: "Describes a tag. This is used to contain extended metadata. This object can be added as a property to any schema to describe extended attributes. For BAPs, tags can be sent during search to optimize and filter search results. BPPs can use tags to index their catalog to allow better search functionality. Tags are sent by the BPP as part of the catalog response in the `on_search` callback. Tags are also meant for display purposes. Upon receiving a tag, BAPs are meant to render them as name-value pairs. This is particularly useful when rendering tabular information about a product or service." + type: object + properties: + descriptor: + description: "Description of the Tag, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + value: + description: The value of the tag. This set by the BPP and rendered as-is by the BAP. + type: string + display: + description: "This value indicates if the tag is intended for display purposes. If set to `true`, then this tag must be displayed. If it is set to `false`, it should not be displayed. This value can override the group display value." + type: boolean + TagGroup: + description: "A collection of tag objects with group level attributes. For detailed documentation on the Tags and Tag Groups schema go to https://github.com/beckn/protocol-specifications/discussions/316" + type: object + properties: + display: + description: "Indicates the display properties of the tag group. If display is set to false, then the group will not be displayed. If it is set to true, it should be displayed. However, group-level display properties can be overriden by individual tag-level display property. As this schema is purely for catalog display purposes, it is not recommended to send this value during search." + type: boolean + default: true + descriptor: + description: "Description of the TagGroup, can be used to store detailed information." + allOf: + - $ref: "#/components/schemas/Descriptor" + list: + description: "An array of Tag objects listed under this group. This property can be set by BAPs during search to narrow the `search` and achieve more relevant results. When received during `on_search`, BAPs must render this list under the heading described by the `name` property of this schema." + type: array + items: + $ref: "#/components/schemas/Tag" + Time: + description: "Describes time in its various forms. It can be a single point in time; duration; or a structured timetable of operations
This has properties like label, time stamp,duration,range, days, schedule" + type: object + properties: + label: + type: string + timestamp: + type: string + format: date-time + duration: + $ref: "#/components/schemas/Duration" + range: + type: object + properties: + start: + type: string + format: date-time + end: + type: string + format: date-time + days: + type: string + description: comma separated values representing days of the week + schedule: + $ref: "#/components/schemas/Schedule" + Tracking: + description: Contains tracking information that can be used by the BAP to track the fulfillment of an order in real-time. which is useful for knowing the location of time sensitive deliveries. + type: object + properties: + id: + description: A unique tracking reference number + type: string + url: + description: "A URL to the tracking endpoint. This can be a link to a tracking webpage, a webhook URL created by the BAP where BPP can push the tracking data, or a GET url creaed by the BPP which the BAP can poll to get the tracking data. It can also be a websocket URL where the BPP can push real-time tracking data." + type: string + format: uri + location: + description: "In case there is no real-time tracking endpoint available, this field will contain the latest location of the entity being tracked. The BPP will update this value everytime the BAP calls the track API." + allOf: + - $ref: "#/components/schemas/Location" + status: + description: "This value indicates if the tracking is currently active or not. If this value is `active`, then the BAP can begin tracking the order. If this value is `inactive`, the tracking URL is considered to be expired and the BAP should stop tracking the order." + type: string + enum: + - active + - inactive + Vehicle: + description: "Describes a vehicle is a device that is designed or used to transport people or cargo over land, water, air, or through space.
This has properties like category, capacity, make, model, size,variant,color,energy_type,registration" + type: object + properties: + category: + type: string + capacity: + type: integer + make: + type: string + model: + type: string + size: + type: string + variant: + type: string + color: + type: string + energy_type: + type: string + registration: + type: string + wheels_count: + type: string + cargo_volumne: + type: string + wheelchair_access: + type: string + code: + type: string + emission_standard: + type: string + XInput: + description: "Contains any additional or extended inputs required to confirm an order. This is typically a Form Input. Sometimes, selection of catalog elements is not enough for the BPP to confirm an order. For example, to confirm a flight ticket, the airline requires details of the passengers along with information on baggage, identity, in addition to the class of ticket. Similarly, a logistics company may require details on the nature of shipment in order to confirm the shipping. A recruiting firm may require additional details on the applicant in order to confirm a job application. For all such purposes, the BPP can choose to send this object attached to any object in the catalog that is required to be sent while placing the order. This object can typically be sent at an item level or at the order level. The item level XInput will override the Order level XInput as it indicates a special requirement of information for that particular item. Hence the BAP must render a separate form for the Item and another form at the Order level before confirmation." + type: object + properties: + form: + $ref: "#/components/schemas/Form" + required: + description: Indicates whether the form data is mandatorily required by the BPP to confirm the order. + type: boolean From 7bd38793c5ffbb6206855c21a7ed3f91483fe850 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Tue, 14 May 2024 11:49:03 +0530 Subject: [PATCH 076/102] Fixes #3 Remove old shell scripts --- {install => docs/archive}/START_BECKN.md | 0 install/start_beckn.sh | 112 -------- install/start_beckn_v2.sh | 314 ----------------------- onix-gui/GUI/app/Infy_Pending.pdf | Bin 101618 -> 0 bytes 4 files changed, 426 deletions(-) rename {install => docs/archive}/START_BECKN.md (100%) delete mode 100755 install/start_beckn.sh delete mode 100755 install/start_beckn_v2.sh delete mode 100644 onix-gui/GUI/app/Infy_Pending.pdf diff --git a/install/START_BECKN.md b/docs/archive/START_BECKN.md similarity index 100% rename from install/START_BECKN.md rename to docs/archive/START_BECKN.md diff --git a/install/start_beckn.sh b/install/start_beckn.sh deleted file mode 100755 index 51df301..0000000 --- a/install/start_beckn.sh +++ /dev/null @@ -1,112 +0,0 @@ -#!/bin/bash -source ./scripts/variables.sh -source ./scripts/get_container_details.sh - -#below function will start specifice service inside docker-compose file -start_container(){ - echo "$1" - docker-compose up -d $1 - -} - -#below function will start the MongoDB, Redis and RabbitMQ Services. -start_support_services(){ - echo "${GREEN}................Installing MongoDB................${NC}" - docker compose -f docker-compose-app.yml up -d mongo_db - echo "MongoDB installation successful" - - echo "${GREEN}................Installing RabbitMQ................${NC}" - docker compose -f docker-compose-app.yml up -d queue_service - echo "RabbitMQ installation successful" - - echo "${GREEN}................Installing Redis................${NC}" - docker compose -f docker-compose-app.yml up -d redis_db - echo "Redis installation successful" -} -# Main script starts here -text=" -Welcome to Beckn-ONIX! -The following components will be installed - -1. MongoDB, RabbitMQ and Redis -2. Registry -3. Gateway -4. Sandbox -5. Sandbox Webhook -6. Protocol Server for BAP -7. Protocol Server for BPP -" -echo "$text" -sleep 5 -echo "${GREEN}................Installing required packages................${NC}" -./scripts/package_manager.sh -echo "Package Installation is done" - -export COMPOSE_IGNORE_ORPHANS=1 - -echo "${GREEN}................Installing Registry service................${NC}" -start_container registry -sleep 10 -echo "Registry installation successful" -sleep 5 -./scripts/update_gateway_details.sh registry -echo "${GREEN}................Installing Gateway service................${NC}" -start_container gateway -echo "Registering Gateway in the registry" -sleep 5 -./scripts/register_gateway.sh -echo " " -echo "Gateway installation successful" - -#Start the MongoDB, Redis and RabbitMQ Services. -start_support_services -sleep 10 - -echo "${GREEN}................Installing Protocol Server for BAP................${NC}" -./scripts/update_bap_config.sh -sleep 10 -start_container "bap-client" -start_container "bap-network" -sleep 10 -echo "Protocol server BAP installation successful" - -echo "${GREEN}................Installing Sandbox................${NC}" -start_container "sandbox-api" -sleep 5 -echo "Sandbox installation successful" - -echo "${GREEN}................Installing Protocol Server for BPP................${NC}" -bash scripts/update_bpp_config.sh -sleep 10 -start_container "bpp-client" -start_container "bpp-network" -sleep 10 -echo "Protocol server BPP installation successful" - -if [[ $(uname -s) == 'Darwin' ]]; then - ip=localhost - bap_network_ip=$ip - bap_client_ip=$ip - bpp_network_ip=$ip - bap_network_ip=$ip -elif [[ $(systemd-detect-virt) == 'wsl' ]]; then - ip=$(hostname -I | awk '{print $1}') - bap_network_ip=$ip - bap_client_ip=$ip - bpp_network_ip=$ip - bap_network_ip=$ip -else - bap_network_ip=$(get_container_ip bap-network) - bap_client_ip=$(get_container_ip bap-client) - bpp_network_ip=$(get_container_ip bpp-network) - bap_network_ip=$(get_container_ip bpp-client) -fi - -echo " " -echo "##########################################################" -echo "${GREEN}Please find below details of protocol server which required in postman collection${NC}" -echo "BASE_URL=http://$bap_client_ip:$bap_client_port/" -echo "BAP_ID=$bap_subscriber_id" -echo "BAP_URI=http://$bap_network_ip:$bap_network_port/" -echo "BPP_ID=$bpp_subscriber_id" -echo "BPP_URI=http://$bpp_network_ip:$bpp_network_port/" \ No newline at end of file diff --git a/install/start_beckn_v2.sh b/install/start_beckn_v2.sh deleted file mode 100755 index 43864e9..0000000 --- a/install/start_beckn_v2.sh +++ /dev/null @@ -1,314 +0,0 @@ -#!/bin/bash -source scripts/variables.sh -source scripts/get_container_details.sh - -# Function to start a specific service inside docker-compose file -install_package(){ - echo "${GREEN}................Installing required packages................${NC}" - bash scripts/package_manager.sh - echo "Package Installation is done" - -} -start_container(){ - #ignore orphaned containers warning - export COMPOSE_IGNORE_ORPHANS=1 - docker compose -f $1 up -d $2 -} - -update_registry_details() { - if [[ $1 ]];then - if [[ $1 == https://* ]]; then - if [[ $(uname -s) == 'Darwin' ]]; then - registry_url=$(echo "$1" | sed -E 's/https:\/\///') - else - registry_url=$(echo "$1" | sed 's/https:\/\///') - fi - registry_port=443 - protocol=https - elif [[ $1 == http://* ]]; then - if [[ $(uname -s) == 'Darwin' ]]; then - registry_url=$(echo "$1" | sed -E 's/http:\/\///') - else - registry_url=$(echo "$1" | sed 's/http:\/\///') - fi - registry_port=80 - protocol=http - fi - - else - registry_url=registry - registry_port=3030 - protocol=http - fi - echo $registry_url - cp $SCRIPT_DIR/../registry_data/config/swf.properties-sample $SCRIPT_DIR/../registry_data/config/swf.properties - config_file="$SCRIPT_DIR/../registry_data/config/swf.properties" - - tmp_file=$(mktemp "tempfile.XXXXXXXXXX") - sed "s|REGISTRY_URL|$registry_url|g; s|REGISTRY_PORT|$registry_port|g; s|PROTOCOL|$protocol|g" "$config_file" > "$tmp_file" - mv "$tmp_file" "$config_file" - -} -# Function to start the MongoDB, Redis, and RabbitMQ Services -start_support_services(){ - #ignore orphaned containers warning - export COMPOSE_IGNORE_ORPHANS=1 - echo "${GREEN}................Installing MongoDB................${NC}" - docker compose -f docker-compose-app.yml up -d mongo_db - echo "MongoDB installation successful" - - echo "${GREEN}................Installing RabbitMQ................${NC}" - docker compose -f docker-compose-app.yml up -d queue_service - echo "RabbitMQ installation successful" - - echo "${GREEN}................Installing Redis................${NC}" - docker compose -f docker-compose-app.yml up -d redis_db - echo "Redis installation successful" -} - -install_gateway() { - if [[ $1 && $2 ]]; then - bash scripts/update_gateway_details.sh $1 $2 - else - bash scripts/update_gateway_details.sh registry - fi - echo "${GREEN}................Installing Gateway service................${NC}" - start_container $gateway_docker_compose_file gateway - echo "Registering Gateway in the registry" - - sleep 10 - if [[ $1 && $2 ]]; then - bash scripts/register_gateway.sh $2 - else - bash scripts/register_gateway.sh - fi - echo " " - echo "Gateway installation successful" -} - -# Function to install Beckn Gateway and Beckn Registry -install_registry(){ - if [[ $1 ]]; then - update_registry_details $1 - else - update_registry_details - fi - - echo "${GREEN}................Installing Registry service................${NC}" - start_container $registry_docker_compose_file registry - sleep 10 - echo "Registry installation successful" -} - -# Function to install BAP Protocol Server -install_bap_protocol_server(){ - start_support_services - if [[ $1 ]];then - registry_url=$1 - bap_subscriber_id=$2 - bap_subscriber_key_id=$3 - bap_subscriber_url=$4 - bash scripts/update_bap_config.sh $registry_url $bap_subscriber_id $bap_subscriber_key_id $bap_subscriber_url - else - bash scripts/update_bap_config.sh - fi - sleep 10 - start_container $bap_docker_compose_file "bap-client" - start_container $bap_docker_compose_file "bap-network" - sleep 10 - echo "Protocol server BAP installation successful" -} - -# Function to install BPP Protocol Server with BPP Sandbox -install_bpp_protocol_server_with_sandbox(){ - start_support_services - echo "${GREEN}................Installing Sandbox................${NC}" - start_container $bpp_docker_compose_file_sandbox "sandbox-api" - sleep 5 - echo "Sandbox installation successful" - - echo "${GREEN}................Installing Protocol Server for BPP................${NC}" - - if [[ $1 ]];then - registry_url=$1 - bpp_subscriber_id=$2 - bpp_subscriber_key_id=$3 - bpp_subscriber_url=$4 - webhook_url=$5 - bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url - else - bash scripts/update_bpp_config.sh - fi - - sleep 10 - start_container $bpp_docker_compose_file_sandbox "bpp-client" - start_container $bpp_docker_compose_file_sandbox "bpp-network" - sleep 10 - echo "Protocol server BPP installation successful" -} - -# Function to install BPP Protocol Server without Sandbox -install_bpp_protocol_server(){ - start_support_services - echo "${GREEN}................Installing Protocol Server for BPP................${NC}" - - if [[ $1 ]];then - registry_url=$1 - bpp_subscriber_id=$2 - bpp_subscriber_key_id=$3 - bpp_subscriber_url=$4 - webhook_url=$5 - bash scripts/update_bpp_config.sh $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url - else - bash scripts/update_bpp_config.sh - fi - - sleep 10 - start_container $bpp_docker_compose_file "bpp-client" - start_container $bpp_docker_compose_file "bpp-network" - sleep 10 - echo "Protocol server BPP installation successful" -} - -text=" -The following components will be installed - -1. Registry -2. Gateway -3. Sandbox -4. Sandbox Webhook -5. Protocol Server for BAP -6. Protocol Server for BPP -" - -# Main script starts here -bash scripts/banner.sh -echo "Welcome to Beckn-ONIX" -echo "$text" - -read -p "${GREEN}Do you want to install all the components on the local system? (Y/n): ${NC}" install_all - -if [[ $install_all =~ ^[Yy]$ ]]; then - # Install and bring up everything - install_package - install_registry - install_gateway - start_support_services - install_bap_protocol_server - install_bpp_protocol_server_with_sandbox -else - # User selects specific components to install - echo "Please select the components that you want to install" - echo "1. Beckn Registry" - echo "2. Beckn Gateway" - echo "3. BAP Protocol Server" - echo "4. BPP Protocol Server with BPP Sandbox" - echo "5. BPP Protocol Server" - echo "6. Generic Client Layer" - echo "7. Exit" - - read -p "Enter your choice (1-6): " user_choice - - case $user_choice in - 1) - echo "${GREEN}Default Registry URL: $registry_url" - read -p "Do you want to change Registry URL? (Y/N): ${NC}" change_url - if [[ $change_url =~ ^[Yy]$ ]]; then - read -p "Enter publicly accessible registry URL: " registry_url - - if [[ $registry_url =~ /$ ]]; then - new_registry_url=${registry_url%/} - else - new_registry_url=$registry_url - fi - - install_package - install_registry $new_registry_url - #install_gateway $new_registry_url $gateway_url - - else - install_package - install_registry - #install_gateway - fi - ;; - 2) - echo "${GREEN}Default Registry URL: $registry_url" - echo "Default Gateway URL will be docker URL" - read -p "Do you want to change Registry and Gateway URL? (Y/N): ${NC}" change_url - if [[ $change_url =~ ^[Yy]$ ]]; then - read -p "Enter publicly accessible registry URL: " registry_url - read -p "Enter publicly accessible gateway URL: " gateway_url - - if [[ $registry_url =~ /$ ]]; then - new_registry_url=${registry_url%/} - else - new_registry_url=$registry_url - fi - if [[ $gateway_url =~ /$ ]]; then - gateway_url=${gateway_url%/} - fi - - install_package - install_gateway $new_registry_url $gateway_url - - else - install_package - install_gateway - fi - ;; - 3) - echo "${GREEN}................Installing Protocol Server for BAP................${NC}" - - read -p "Enter BAP Subscriber ID: " bap_subscriber_id - read -p "Enter BAP Subscriber URL: " bap_subscriber_url - # Ask the user if they want to change the registry_url - read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url - registry_url=${custom_registry_url:-$beckn_registry_url} - bap_subscriber_key_id=$bap_subscriber_id-key - install_package - install_bap_protocol_server $registry_url $bap_subscriber_id $bap_subscriber_key_id $bap_subscriber_url - ;; - 4) - read -p "Enter BPP Subscriber ID: " bpp_subscriber_id - read -p "Enter BPP Subscriber URL: " bpp_subscriber_url - read -p "Enter Webhook URL: " webhook_url - # Ask the user if they want to change the registry_url - read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url - registry_url=${custom_registry_url:-$beckn_registry_url} - bpp_subscriber_key_id=$bpp_subscriber_id-key - install_package - install_bpp_protocol_server_with_sandbox $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url - ;; - 5) - read -p "Enter BPP Subscriber ID: " bpp_subscriber_id - read -p "Enter BPP Subscriber URL: " bpp_subscriber_url - read -p "Enter Webhook URL: " webhook_url - - # Ask the user if they want to change the registry_url - read -p "Do you want to change the registry_url? (${GREEN}Press Enter to accept default: $beckn_registry_url${NC}): " custom_registry_url - registry_url=${custom_registry_url:-$beckn_registry_url} - bpp_subscriber_key_id=$bpp_subscriber_id-key - install_package - install_bpp_protocol_server $registry_url $bpp_subscriber_id $bpp_subscriber_key_id $bpp_subscriber_url $webhook_url - ;; - - 6) - echo "${GREEN}................Installing GENERIC CLIENT LAYER................${NC}" - read -p "Enter BAP Subscriber ID: " bap_subscriber_id - read -p "Enter BAP Subscriber URL: " bap_subscriber_url - read -p "Enter BAP Client URL: " bap_client_url - bash scripts/generic-client-layer.sh $bap_subscriber_id $bap_subscriber_url $bap_client_url - start_container $gcl_docker_compose_file "generic-client-layer" - ;; - - 7) - echo "Exiting Beckn-ONIX" - exit 0 - ;; - *) - echo "Invalid choice. Exiting Beckn-ONIX." - exit 1 - ;; - esac -fi diff --git a/onix-gui/GUI/app/Infy_Pending.pdf b/onix-gui/GUI/app/Infy_Pending.pdf deleted file mode 100644 index 30a4d43cb28dc10ae96ca3ae1803b15560e79c52..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 101618 zcmZ^J1yGya7A;P3D8=1fgS)%CySuv-cXxMpcXx;24y6>=BE=uQ|NZZqc{6WMW|HrG zNzU18uf5hu=8!3fh|w|8v%|u&5Hb?l8(G0pN}8D3xmdb*Qo)+qnfx7L{r8UG=cVcY zhB^K_%)yLn!aWi&O>8}#s zNs$eRc!tA+)n(!>kQG!EkbPR0HAGpgT3So2YU)~3H?-J6neuDC)oAUio)y(dq2zjz}zvnb?QpPqN1deieaVH6WNgV1{) zuB|(l($es6e;-2{X$pR@`5Wty z{PeA`kt3`zD{C(|R|k9EXyFl3$SnvWnkkvd{>ZYn#o9 zXRz=Xu+?HW@dGmIeP`+R8%Rfpu0M$@wJ^H3MXI0;8_Q=%LvF8ch#MT#p?R0Cr`gv&|eZi zbyYL=Eo>gfgHhqtB0iJ`gp@%q&8UJ_%r{SQ!ZC3y_R)#66J&pD=5pG?6?3bt~Ir`mF%8z$MH}J9H<1qlFX!(o!AU{&fZWG8BjD z1D#es+_UZU$OHaTz>g1~opz39)Oujf2p(#h;idBIfHQ8y0aC9B>wpR~^Ey*5n!-p! z7(a++!g!s#0oS-4zOFCy&^UeghfiMh=*h zvIC3bKk>dw_=Z0lulGF!Smu!CM7tGoLkAYZ1cWfy9Rt6?O&7usstT4jL|`3IrHx|? zQtbv&!Zkg+JjSr61MTH1FTiy+2aY4kLsdLf8+e~|Mk*8YM2#7*Cq z7o?bAWXAIeCd|j0lz5e35*B(=tXTw3p}lxJL{T++?X&R|3UTZoB~j+9D}CE~eTA(i zq?k&v8{(k&0YkyGBoG`Nz3{gm#nfXTAf=}NWD7+w4&wDQsID~#EBMPFB1~m4dg!Tg zieceOiSdBcuN9<2U)H`zCRSE{zzs#ffkKa=z=1-P!iST7DW~}Ir`SKet-s6(-6X!r zH~)L$HUc>#5o-`u1uV4^oJPEss}(qn5`vAyg@k(m__;*Rp1>&>g%UfEp&y*SSkHmv zp6Cttbx)KJ#P4SivH&*F5(Oe5lqmTPo|r2}2nC2K5|1wY%@X&dOaY9k7=}_TQ{-8n zGK2$2q!8E)pC~cqni&W@r(paRN?0>*NtR4f6Zj2is1V@70sIhPRUxhkpe`mc(0DM$ ztXNcJ#I>YbBCH8QS@#$2krN-1C^mN404a)(4bdt-$VWW!D4+9#u*8gU0gD#oLcxw_ zBYwk>32cy{7~&{aHt=zykO^S{8XJHCEg4Zx8n|o&#frxUNQ)N@r5=Pi^vVDR)Ic*1 zs1up=)HjN0;E4?f`U$SZk^xW zh`=NlFXri)cRa3q$P+LQ&=V>N{_i34p)M%X!kw6MB3{(fbG=AqCoV9}B)oWXlfBU9 z0?@bSr!G{q0-f-31Fua6M8GE3PF!@;-4L{T%o9!rY+wqPE~IqhRey&A7x4EUeDM*9 zFAn{8K!V_e^ydk|`cy|{Ja?huRX26C=-i}?d^;@`jZhTWN8zn$yv)Bh2CV7PYHh;qSu zMLuD0@nYW!ze{sK1?msP#qSg?>JQOLT!j#j%=FhtbS1oFdF`&lpFygHp9x=yUzlH^F2$a;bNC?oL^>h;LhjrhkbpJU z*2PFeJ?m+EDC2~0ye{S+5OJq>Ovi%H9MyBZU;Mu#NaTHgiRXjCN#KKgB=N=eO5g*} zis!3ZJTd?P`3Hj}^1^ma^uJ@o^C2+|+9$lj;0rx}wV8NF(OWs8sYg4hx@H9O50OZG z6fX7+UM2KG#S#1B;ZN~F+aJ5&yb`_8z9QrbJd^W8+|lLOg_XtkBFK~YLgxxT)AOYH zLhUS`yj+VH6ZHRHFWbMm1_SyZyFhn`-{oB^Jy88Y))VVgF8c^nkN1P9BYtCl#X1?| zdP90;eIfM$t0Q`2=#ITpE|%{%zlH+N8R7sL_Ut9xPh8l$Q{KSu2Hc7@J#eU2Pd=_( zpZj7Ra^4^7Y8H1tU~}Hz`MBPC>gG?bE{hg-pRl=nz5C?&%^7muSJaR1+FU-LKi?p$ zTh_-ZP}Wy*cE|3T^ZpAY=e^C><(W;l%zn}Jxs^nrtj{amkWzV1bg4Lb%Z$fh_ErNRb82HP}AakkIU z*Z>&;N{Wn{1g=m}fa}^c`$JbjOk{8G5A*SAofSl^Fr?7~$bYP2Y){y(rOd%)&!Qu) z2(^(`+hpMj6g3PX=2~qOHoQ%eDGO|(;2;8qT_dBZ!kXKu0nz8@#u8wb%X|=aqZQS@ zt(Q{<1}KU`r7~y6jJ{r`bXY}$y~98W&Y>}pfl4@}=kJ0)&N!S$fir5E>~W~%S0eo@ zvret&3ynF4y%_`WTOyihl29ae=>h^1Nf29n4HSEgit*7GACKV#U_= zgI23=u{$3N(1HGAe3(AtH4oxbZmITD(133vCICsPS#}b1A3)=DVE<04V5+aSpjmH5 z(5|Q>(cT`1k|A7H-_NXshodZ}j2ZF~o3GL2>o!WV->H&}jP2)-hlfjxAjPJ(@VYJ&HLz za5~q2id=M>7sOm&E*?$Obh9D|(w}Q)z_C~;s&bkgu-DS@_GC6~rplV7(nOer7NyB* z9BRb2IW1+!3$8*PNleX5jX4lV`-wBWn#1n2A?R}9KPJiaCtmv^F7@K`7Q9(`<*5pS znSzKWgrs3FmZG8zxhPwPNRg3B0%WQZ?Hf`*64>YZK4%@&vjLUdIODgt8Y@w}o{^Xo z*p0@stkwCLO)94Bw1?7U94CJ1O#%ypdFI7!)hGV-Pqy%Xv(g8XFksSMb^jJ}kd z{>!Y*+X48h<1!Ry)PYZf>zt~mA9 zAvPvFxG&)4MbjZ_*{n&6rE0)N^+Ih1maWRFrM*T?x>m>3Ys7#}x=?ay&6`yWP>OgE z1^vu>?H@4Rz<}6q(Eu`55V%JV{ojg*Z6&1_nQ~A00)nvEvVJX^(3B@if`Lor(n?lZ zHI$oGi7Kfi%^0bIDx)vYcC$dkU1sfn5^f*o7f6xg9vuCxpAI(LjNPh@T$kW7tz4Hf zc$ZnrW;feRDoq=sddz}V3Vh{&X^V!ST8!FnL!TRg$C+#YrlHTJ81yuP{#^W~a);<;CsdwEq>hKrasW$4ar8a4FGwew=n$wJP1{IdRN(w41i#;kcA9;#}< zxM^LWVUkVSu!9?ZJ_Ts_B8E0bIQrRxZlB$c99Z-{=x-Qb3of4g+x=xzXpR}U1^|s{ z!c7nvv7njKbz8Nt?feZ|`mQ0U%$dsdt@bvqQ+Clr7JywN)>mq2&^VEK$mmBU;y(31Y@EP8vC&|`{+|-b z8^wM$$!;o=S^IXbQQSIA=71H1CO9KbOs1K;1zXvW#X_}Rm@>EwCre!^-e1P3<8g4r zs)#J|DI^E*!yE6+osrwMt)96(^+f)1gXr;N_t=)J<34rkayoSDGHc5^M^s@P%^$LZ zZYt%l3A>Rd`pcUCmdfdGsW4^#*}Q)W@_*_3R~YM7)2=J*957k2zCnMd#=%1@n=0tg zZCp0|-MNM6z{OHFbmd?H?ThtZh4`1jMyPLp^@1km<@byS4`1FG+BKD19LX`9NB@!I z3(ttR4*>Bs9T##p8hqOAlWdsD93Tf%2%n8>WJB!mpMdB4X|rB5!ak&*fjNEs^eWkR zI`N6N=Wev}$NrZz8`lk=Y4#whG?G0B+*kFp4*Sr*B>Az1oGt_2=Tm%nR3+f&&v^WZ z4vAK_iwA@L1gb2!M6YLGyLIT+sY~9rS0`3f^|E(0>k9Pc7EAdEmd(i7v zO`Ni%y7d?|bg6%D;)Y#hd(y8_qC#X$%Q!HkMr0`cDzr*iFkw!I0pHn?>!HBNlU9@AA;1iNYk`$Jc7K}a zi`kz(fnRGF(Diy~f7w#t#P`2)tDBJva-ZlvjP9mt~chd%Suj8PE8%2l(rp6bP%=lgfXaWHc{chpGpZE8gN)cr*G5< zOpPpbz{C~QR=ob(<$ci54h}w8&;~we;GZ}-E-C%b^m!vVwOX5AQz8bUfk2{zu=XFw zYC&rAgCO)(WVjKdg99GZKVtq!8{aS*P@~KJr*_7mpTkR6s3p-yzvif~ed5!k3vVK=9Jrw0#j)o;T>=elC{#5$2J;tft;7-{jv{C}wi*+Ys$wdQ zJZU5uMB zX^ZQg85;`M$?$L;N{iDySw_m-Xf z##mZfS`hyUy*%#de;d$k=syj(%=qaV3Yjbav-XfrNg$y5`SHb=(OAWH8^*O@U%^hE zV?Y@Z*=b`+87<{-Vm~F;f|{?=$pcFzm5gQzdvYrA|0<-}E-Pa9PQXV3dGp`()!15; z*JRA^(bd&tZ!s32V_S){EX~&9s3y_WRnyj0->Ir`WmAnUO-@REN%5wc0+HHh6zmH_ z{x8R3{%)lg&%6HRyiJ zLjh3vwUTD4iiYAp;2nVdhiJdODTE0bucyQl`g>bOV{czBhpenAtgHhltn}_F)?Tu*2qM(rtY{(PC}E(_?#;yiRJIN|2J~}*u6_*v zipA3DoyGd>tvWdrfSgT^&)KOP)Ji8s@5>6va8GR}N{cIN3c`IZ5s4D&8IDzcZE0n# znU<{VvY>wGM>ilL*aw+n4q`2J zI2?bh>3Hhuy6WmG+UATYUt}n&t3x-ODr{d57KIOiym4!VU98%1KrwCU_gP_owgqhz z{{Opc`l}usW?GAtr9VZ=f2+I{lp_+JJT5J>N7vNkGR~$|)^V9_1#4kyYXe%{#B6P6 z1ocOuKes#Lw81`KKo=H~j9@t%(L~zu7RiuBmgB2v-FBh-ABm#w=KN-Varriy^Kl<3MMlf`p#$+#46(`D=K zz?@|+n-%9*YxevG6e9s5Q*fRBy?pd5=NQtnqEueH*Yc#Z8ZG}zwW;(R&%qs8Sx)Dl ze>m-{kz*$t_W8`AR0rK*Z;@%V888zej+*CX0Gw1V9CtUtL zv)b`-BiG-LO?DF{7vN9A)ml(YLPoEia*?OW^|si6c14YeMHm}nRDMFh$7nPa zSS3*8ml0jSWW2bE19gTb43KuHfMvUfosRxramLMn$7Y~pfgOg+Os7K+Ki>V7t`bwTcGD48>!#Hdpwg7Esl89;=sMR1{;9SgKaX>|A_Jrn_!E>^O$i zLQKO)LBPXBVC#bF+FJuA&R&)Gq5~{Ba}Ge;`Ghk2>v@2SY9*a8x5h-OP=q%<%?WMt z9l;KYxa3a0yuZ7c+{4E@OPup<;sVx>C;o2?vnlK|vFtP1tJpbP%L!MTrJUX+PKT~< zrk?Z%Ha2L1EOQI_`Duj;vsZP~Uu&$yWcKm|F-}E$#IQ<~=7<)kuxbv{acu!3M*6?= zch2S9lJPG%X?LfmkC%2%n7m6Kt#UWW41z{TZ8HINRa4FCSdm(nfs3~&Qasa^F`_sC zMhtT^un(^$?Nbd4I5XgyX-qZPq&_`O-d2?n<6Ik2x{DfoPGDqhm9-QPS4mZowV-|L z?_>{^D0kaJ?UR+-!z6Clz{RX>A6G`eVJ6#o6`6_4$UFzl$*I;7f)E%(5~3SwPK9lE zCmn!f8GSB0F>>rjP1KEEr+5%{*5X1qZb-zoqtoH^B}<3XL-&d-cCCQ=tmQ>PFq@l< z%^Ceb|~}bWwWdnix!Q6 z2ge?fyn~HijOKt9JYj=34(42luAA(pyK_C@IxjiiR&k!CTCW+!iiu~=o9CL7nr(l? zwO0pDUe^)guUTtde#Glnt`Tfhtn|_mG5BoZP9q~HKcPz15?$FQMKH~R3VI7{1zb~T zGYKANr`JHtt}Yqr*Fj9PQGnvoibe%aY3N30XW^d+<2qU!%Na#Ak4-y(+==WDCz6KWm$CWk)tp%wG-i0D&)uistbf;{fNIwj5+ z7n!@PNQX?RR7M!HZQw~O3R!+oHWM*k(&4=vbRt=MDr{+mG7|-v(FB{aaq=fj3kS8v z2T2%)2FzN)iwJsJK&BUEZ7Fb&!FW^3&7KIDl%q6;OZmVcVx6N z$D)myNH)BrYN6MKwnu2oLg20$SEin5OlPGoT&0#^AXLBQhHuN2HgRq&pkD~!37Hw0 zLlJ?tKc6o_Mjgm>n5B0gdF8bz4zCQH zufRieb^f3fUK<|%Rvld?Zw5bMNjungSn(%tWV(?%1mb?>J~HA2;V z@J`yABgcZAp@|_z6V4{L(i-Xmy|{XFFC2vr_bD|~M|}zSy_QOpT*Rqx4`Ddfd9Wqz zawx^5s>;`DV*I)fGQgD5_QmLMF7Dgaxk_zgb)G6aG4o6awb&a{23iID{fZ$`mnXAz zZZG|wK*Ma(*Ts78MM_mcHk6_g5A-i+VafntG7@Zg-0Dlo@c={nzLs z%asVh^R>uJ&MJ!Zkb-mJsDdxVLQ<4rP|;J~@S+KNhU3r047XcBLRdCK0wImLDvBma z3e?~3qa%vFL;iS$b#1T}2!$8I)&ecRovdSCj$Ft0w^CEU8BVXp>jf5|4)tK-4_@O! zZLJZRmMFrT8@D42v8fS%gDJ?h5Xn-Y{&SVOxz z$%uL9MSElepJw3kWk{}vl+MH3u6&@?+q-t9=-!;RW+e&EY2xX^%jpfqw!`CjT8GC{ zt9Ij9r)8hSX*~ti+3{pv=UhU?y>ZQ?VuyKv#N(QrckTL60>&4@CRhN%4r42RKmbyh zkAjY4C5^Po-dh4W;EM`j{TJeOI^hqk|dDk)K5L3OS0o(2j0+4CKJZ|WTIt8krPzR+`;Rw@I&#V^U;E( zbN73uUMEew6A=k8_|NdZ@ZD<%@{42lf2f|z@%bhF>&E>1Iihb+?-p_$Ajs1jaIY~D zj1dl~Y159cR?;|#*J0eAksov+EYU)5FwG1&u!dYQ;qQpFwwfq^^e6Fv$d7+#_1^R4 z?S;EcCh`>{&9M;yjb={7DFUB5{OT{2L$Gk?2A$X&&g38b3=}A^Ql_m}|!7&8!wbqo|h*yIFHA z_qAaO<;51xh%1ou_;S*O+2}P6DHR z2e;mc$5RC3nA%BpA1J5_gIJFe2sll!MXow;)gu1PrFiAW;k?Gs2uw1qztyd)AKMqTTbV>LEUfc!hEH>tMPy zI<6cisPrW!xQn4(QuA@pSn@tH>aFJy`nYeYQr8^u@j8J^l(JZi> z9hT9ptXNIYNvV)!HI1I3Xmvxq&0(9KnWu3)V=ik+Gtpc*C3J4E0TVi}szYe>7(cb% z+~_~zwC}d>HqP$xn=F2dkL8iQ2(V}9wJp1UWoe*OuKB%Adn=o9#iTw> zev7is=?NsiWk7FfvHLoj5Jx^|^fcHmX=^LnQ!H8st$52&9ai|8p(i)Gilqu#ku$r> z-MLl|EN;w;jCRl~5)7tCPe}33i`ekKQ$1BCcS%>NaP>yautd+igq^E?78RyCN#fX* zC+9j??+8YoqACfiOdTeqUW%hwoe1>HiK-B3zPjbQatXEmVdXou`ic72@m#I~9lWVl zA-pNJ>ZIpR4IZWx;Kt5W|ytgXB%{pjXJdpcUQLnCZsemmcIS+NzYx#i>W zFBH)cluccyr(gZpGh@+R3E*5#RXjiipu<;}8wrg-s0AxWp=oB+G3)>A@{plz�cl zuuQj&lMi01bXL!W>zyc*pM0wkF<7Z|)(ktcusT!+ogy~}!jaeLK+Y#qzJ0B#+_k?Ea)SivNrIHOss3a`jeLxhqF$5T#Qsral)tx zNwXO&({70<8pB9&^=%_M6iu5(t#u!vmXxZo(IM8SNttTABw*W_sG5s??(oG(m2Va= zBCML$MUr2`yyV&2CdE&yhgo}^fliELi$aPUDG69j45gFp zuubMSCTwz1SaVzHfM%>$OfcZw00a3t`2Kkp=8m!B?#cS224~a>bUCZ{Z%_lgEn&GZ z?>(Y5DYqYrkAviEAk&qZ5N-YJ`!DrS>XV-7&S=wvaluc!6z}Iy<$>G|HQnI3qn#A} zBlTE3!)d+*^a0C*a2`um^#V*gGJtG^)x?9wqd^}J;cj@VeGU$|)TCJ(>j&<2oJRhT zyaDq4n{zuxVG#5mM$-%h2 zv1@Ll0q&T@l%JbF$!^hYizyZf7T80sqWX~Y*y;Pb_+U~8TCS!4FgV6@F(+k9q{iDP zvi|J)Nq)=X8QU#RG0%A?^IT9bqCxa3mK~nA{zK}9`2_aFYRKES#y9Tnt>LO~{q!7- z5%q9i$>t4dPp!L2_L{akGLL;vmKX)l@Pk6i$b|k0%8#CWHIaLQ>lUsNwC)zyGpRcc zZqt7p<6D}oRlZtW&^&o|OpO+aPF&tg za9;%IjV4pnn+{z~ie1u*WM6Wt6gNWU&87t-PsYj)kU?F)Yjw*r7qj9bu;NIs?FtuSe@Ng*$L+|6Ql2erpo$wx_s35+>~#X#4e zQqOda0jUxgn4|MdKRwo{$Q$YiO4=6Wk1-9oEQy=;;WPa`clW+tjg|}gV7i4P{pjHh zGVkrrPmDSVgF^F~->V$6e%He!FAb*HpBuy(rrZJbN0A+tcAL+Go1uj4Lm88-K}NL; z(1)WLZ`Z@j;lpx%p|g1m`Tl`lK@cBlM3)a-r5fT|4}2aa})R_L%x0(gg7h z%OAw0c>BRF2aMTB<`Y`sjse+s0eOtB@+2D&>UXfK+T3JhL8pPkV%_%jYa(B?*${J4 z)NcA$SnUtmw-!d-Evgw}X$L4DxZ3Y%>(cu|6{Db_al@RLFj$9Y{&b++2Zw)k;hMccRfysR$ANdYV8|xdgt5W{ zxtZwIWMuHh*h=O_n4R1KK`TdEG3kpi*MYVla;=Z8zI=hA9os&s;%JLYDxEhkp<0LC z5Y;bfI@#zM!|>)7^tlH0^NWda1cJ|#^};t9`aEQw=P7iC<%jmb$O)dgbMGAT-@uN2 z(atZu^4Q49A*LOB@dYxm!T;lj9|Q~d#Z!+Zm1hdO%IT4HZI=G^s5u7~sW6_Z+=+T14ajG?w(ZdU;5c-*jlhWSX^WA#KVI&-BY>w~M5#?r;3}Me5d?&oO4Q*Fgvp=UU{rrguR|zR13nAT@ zl%L~MOSSCgW{Z2i)pP9rkO8EnxjZz?pGq+KrmC3e4vKkZp!cq?N52`*J+=-wWcl*k zX%T`!Ap*q#m@5oong{nvhi>5V2WGAZ&^yP#J6uM3ODiSjHd4QzbC)@Sb{L1|3RQ@tgh^dW(xNl4d?8eA-Ls4 zEYqwrW6bi;;(s_0B3FgWFp)1EFkw5IJ(vLG|H5h_@`p*Hnv;MOYe3Ib9B2CFbZJkd zmL+xs+&LG=xt%VsNl0@X80;7tUMa0~p%;m%go`RC ztmk2$LM<#j9V|+&C!H`1GB_@oT7(@xeX*3H+?JVcCt)qav-*aP6QViOPTxxeyBZ}j z?CZXXlHL;D#!_I}SVx3{exI24Pn0u~xatHaCb_86XsnnU#>*y4WAbgD zI@cfzRFea<=6r|96{3xCPMVDmdF~d2Hk)I#(6Z%{MtG6oWgW6_o5}z`9=%rT5Mpc! zR#N(52y+>URP1Q5nkN!l-;1;^f0wbUpZe^wREWzGS^RlI_~%(7M+q%ivwaU%*+|xk zBzHetk+6m>^;P_P=E(>83=Xd_fNsedYNQYH^0_wV{UfKH|*Ps}IGO$AFuUwVPJ z^<@$n`2`3);yb%j5r(;K-$RNQd(lN5xdsmpO-+%hVGlq=2MxK$`FL9EJ~Z?nir$TV z*X0@W@T{$F$Pg++oy?DCdXwbVY{ofh(TkzTzd&WQEagY#4vY)~87Uf8JyF4DvyS=e zRuUyDiQM#-hi6Nf4b|2=miiTJjQzd_*F06AvQ?m)09R5Sl8@(L*BU5`^K1-cfmm+% zCVad3(zdZojArH=!&*=m6->V~5+@L-E0v1NPc*%r5lIP-!m@5Uf0=`hVW8QA$2w7) znpdWBbjxhE9-IX7MizCemv`7#3<(lOZ-tf+CJ~!>rJjCG#EyejElG#1Z5XTM#c!K3 zFjau?B6(7~pa<^Gbw%^@& z#ArM(HaX~CaQ1VM-Q@-TYL$(W@2o1l8<<_}vI?q)uljrU_kJ^l}+Rjim)8)YJ zI$1jJ0(t`B6htc1UAEiea}`A-?H_s&s_Po;cck;C+bLDF(SLOIRhFaDGj!tHrTS65 zPB%)f8F)_L;@U7gyC-a)QZ{0s!5oGXJ=`j=FfRjta1Ct#&?nB(yh9jUj?D_ms%8&c zNyr1bKJaViSOh?@q@g1#%J%F4igWAl>9~sZn)V@JxrQo{;iDo`oAKZ#D2YgsZ_uH( zwJ}}n{pMxqc1%>r%hT?QOGH=5L?6O1X6I^RE8KiR9BC7t(&>l}+}Cqd1ArVz0 zvr%QT6zU?_WR*t@>J)kmE6U5|J`t`Iva5Eew|3~Za%c}4Hs6n z$+t@zQdZ`b+NyW8*&VXKI`)1Ne@q;$@h1}=<56k4_wMtses6TI{WFo3jQDXKwVTkC z>z_4!vGZUua>2f}{aO~Z8CTK>t6=}W3ll{nsn|5%|x_}ZBFUHBveWA4m)#zTQ z`4f*Zs{5^pa*#`mD1imlS2XWyWW)^gNZHYGl9WCXSORg)d=2(&C~nayZ)}p(%SO^^ zUx?(rrJ+*DBcS4T;-SY3cx@PiQ7R52SY#7VrkN}nw2N`A7_=VD)lZ7Kg`YNdf&wo% zfJ1^v^ED4Q5+!Z|9~`$&r4rYXDieD<|H8lW&^%-H;GScPKGK;Mr3ybK%cO*($&M`V z&1q-Ewn`1(f5AOZZ+lhtwC|;9KdJ1);pFD=j+e~V4Fk_zYPTuwwY%;L1FrH4i`D1$ z#l7eE?k!_e^rgsvAs;N@e12@oHh!?th9!`&kqAI#2pAV5KcJss8sre?V6%$UDyK3) zLEGpXJ%ScEQ8$|er38pR!Pb<=`wb^FV|qQS|en&nio7(GV^#B^P!q|h`+*qR&TFnyi0inxotHj@lB{gL*Tz;=dL_-k2xm#@bV8}LEnZOk1#=PvT1$LrX)gQ|ZDHkRgXkaN9J z+h%Fz4(NJWcs%Dr)9!@7KOQ`a~Tr(v1ciNBerdmGHdZBpAUAn6^A&;vy z)I>6LH_D`o!oNPU#zX+zi&xB)$1kc!d!a z3JDQF&Mgg3QX^s{Uqqmgo5c~>R3q0%G+N5v41I+GBqL*@0o9F!X}~rrAHCAIQoxlf zTdt~dsj3B5RarSTPGi?xk&TZB`!dX2-eA*ERk{T&e4o@6In=Yph%K6`J@dYNP=B`D ztj}fnIAjyDli0!GHa%FcYRe_4(iT2;XV~G4jr~Ad@43iM$r_ie>lRV7=X|d(qP)Q^O_Zr{aRv%)$&8H zkPrzOvV#!zv1MGb2&JaM|CIRqw76xHUA$$d;ApONhig&vv6!ZJS%^k?2O;#YK-_d^ zCkOv1PWGd8kIZ^SedF7SrwMigy6c~+ic3O;sb>L{z>y;nlBIZCjd zfWfDhKEl4|zu~r+6D#+jSJLsfU^5PF3*EU$)vXe1?NceZA`1QJ;*#$Lw zKI*#c94Q|^Z!g~1;R}tpP(5@AWNPNsm4&=uz{0cs;uaDx3nc4{d8zIjD(E*>m7JkV z2V;Iy?Hi8?(_@{pw=wLD{gLWF_1xJ&a@TGqLSKuS8Wom&_``!310%$_fgykF#3_o6 zm|B-%n`Ylf-20HL9gmq%O%OYCA7Kq9kt8x>H7H+wH4NY9iRne$aQa;nvq>JPWrtc8 zx1RGu+7=xBZ1kyyH>X|M+FsjHZs_uz4mozhW839)_oG_;upCLK_mN;@(haaS*Rt*& z0%-#+{Mz}xh`zW8Uv=CON<*i)I@dWq4O*JRuWvkb*?(MGI(6A^v*W1i(fTw`?Y<0S)itrAxrYL2O998Y zJ^DjJj_i`Y8#Gdx;%-qJ%K+QxQ?xVCC{4~_S;6ES{0KmsNWjo*hx!`4w& z_$FVGk&;OgX}FOJa|bDma(Mzgy^0h$s)PzDM~lNwCWI9^;RA5Na+5J)i{7-D4#*~% z9Gjw<>zSS);y9JZ1UstdHS%1yq|nZiQ3Tz2_+k;~*c{t|s^opXuzf+}<`W%2M~fiy z#==tny))$LTlI7qq3W{|F|(Mabv%xQ@+f;373$W3ph4E1`sqd|!a1Z?>RN|hOH=K3 z#sjhOeDwoLquH_;Wi-H&qvZG8(T0*YIr?mGvo6&rAO2|_h9)KA%0aQ8ZxOVnd`|#E zz`7y>M%U>`b5$Mundcy+6`06Y&MY`8FjM)Ai7Hz9L^)u`E%}l>EYRRB@YHtSBnOe}y+!Fi9>3a;#vQ zi(|08SY)Yuf@!c66~=vFIPwMaTn4qv(Ty!o5Hn&W#fG<|JLQc7CJ(!uv5X;IIP43%Vla7I| zal(vB;u&30HNYZ?aUwmnOq*OwmK~TC+%np7%e8+b78JBmy<+%PR8+)t*$9h#Vtn$H zc9S-dJbALwi1~onvc<|Kn+rDw@pMgQb^n&BTRd{I$K;Q1r4coU?eE<6W}s1I>9X|n za5t9yrqr}X+Jlh^3FAQU*&IG#KWPiw)gMm8c8ay|9+>)4q!hM9wGS)1TGIyL9nqJe3!TMNqn$&t}I;Mk4b6k0dnz6+a5N?=c#C^drhi8u(9qPdyD6mj_Gir z73a#lF17h}tDL_MT(<1;IMmf#r55yJs$zcGSi-SAon4rY z_|BZX_nd=R(=F#(%^#Ndj*RKI=HcD9e^l1#lbjAJX`}_8x4t-XCKgG2ui-7%T+4+e zGYrbkRf^MXH$6!9;?&JCt~!fp$7TxK7UOSR=1e^tb!D@SUB#)PhnGuz_b5VLFT~Xj zuFh)6b9-cvH|ejQgGr+%Kk+IfZry6;xOrLEp5B`^|rU+roE=+M}nJFb2Kk0+0>pJ`t!| zs?5%xX~{d!KH^@Qx{^>>fE-g?I-x_2Mm+O9O210hyXe?LC&%zE;SY;&yA?UAH#M!7Y-$za$5 zGj%AeC^|)&u*F0X_4H@;f38^z;DSR9C%myd>KOY*kx=n}A4>9`G_*~)r+{fp)&IsX z$F0FX5n%CsPru)s>aM+H{vg$lWW*^yw#;|i;XR;rGPewl#z{DlAU2RdZugv7U93%Y z8Balt##!L$;p%(kLnu|OG_9F}D$*h{# z5u7yM`8MyzItZs3vfm8O+Uavoh)b=Hdtd(Kr|T8Q2}~QdejO{H?;ig=%@$s6(dn44 zTqGyG_A6$)B?RX4*cX^FJ!9<7dDa>DXKTR_Y@NM`+=p zT1k=7%XNOwV&H}S?e+Ozw1T8!;X$Vh;3jtLGG8~2$8`afL56_&vHg5Z`zY5{NVNLI z{%7p6b==3k{Bx*emN}2#J{{3!-xI5=*}di6ZzzYjhYE>5COs9G-`5WjpMkt^rU}KPtqOhp3)IH~gn;(C9pm;8 zG7udz(HJPKg$@fhk}^oGD3cuf?Nm5skmbNpG>Ifhsx)~PeIxpJlpLm0$|AOTtR6WJ z86>%)K_X;nbN{ew$E4~kQv_HNEn~?vfF;CHn0Df;7I8AU*t*y-1sS>eOjPUe5qWCn zTz$4B?{dqUd%+X&lxVBHsk~QeesL-ilp-o9HohkxIr6QT;2t$I<0$8$yR|{%)_XA+J_iJ$+ zup<)9fP$$>XAuE+i85L>U&M1}Bb?Vm$kHxXzof-)-v9kw8;c7~mGO@T!R{sY?K)b(G4Nlk+;Bd^Vuvkeq+N<>be|b@tt}o9B<|TRQXf(=Pt#`#<^Y3TdSAXZy6KB-aoH=C7ednF~ z?8;U8`$@ylirCEF{UKg`$6zR^Tw{ST6ui2||Iw>!D0p>^|ASW-^|wUBC~Tnrpor2- zSFVrdUS+x85GAxqAOiCDk-Q)My|h`^^KxFve^l^qyjjrpy9(O9FSm1MXOuVIG|<(7 zLyrdj_V#y}KF`?=d%I*efNT(`K4OBdU#r=6EM||5WY4Oov#&_(>I+Jid+z!C->mQM zK>L|Jg>aEE`s!~=+FHd{`46(_>CHcn7$J_4r-;YO=h^O(-m@81p!Qz+K#xIj?X_UK z222Ro9#^a@NeeqD+P{OMTK=ijw%iViwnsfA>S^}S4$pE=r$_L7rB$}E#iBo;D(wGE z`s!&ate&RA+%fg9o+dHxvB<5SrvBB_)b3_GsXeP_&J#FYYtK7%`;BGYEK4!F%wWg9 z-MG}C05#{fD$E!oHTJxHtb22H$F5!M*t)3iix;2i`+WJ z_(%OqPN6fYwSOKc*$?_xJ-NVdXfe4gmfz;j`%WQ~l;qzLpasShDD2Kzwfx(2q@?gP z1(^Ykw6udgPt`4X6G)0I5h_)^_O$le)ApJg$nE-u4-2MCsw7elLxhB>N*$(ls8`8X zDc7r8)Saq1sy3@sq-L4s)|dMgqMCI--}v$R%U*c2Nl~J*fMX99VrQVO4 zKvovZWHFWXha^Mln`P1|UoT^tkhF!Sht!`;$#wKLN-4{+N2O+o4wE{h>!mHyPDzq_ z>6Pov9qV$gn-$wpeX`)wP#2?>74Yxyjc;JinfyCw>=m?}YsR(5{n7(A6vBV?C=S9R z*~R>cb#--lXU!0-J!Cb8W0LJr}^-urH%qDBm=gYMT87)?5&OyeAR%}SR2**e0X4g;|W0NGor`c?Zf?|Me@;MxK zJIDdAH=s>W$V`Z0kIe)(hBQcI=Ef*{v&!%9C0BRnHV^Fq|McAf-|pQ3|8C#$lNV2V zr+>##a5}QhLjIlN!Yh^22f85lj!-PuShYtULDKL@fg4Cr%xx&<_5qW^Ve+Bw&P{;? zmX#0mSL!n%@8q=ZDOj(jr8FMGrUp)vbK0Tby)H-`xLfvxy4Nc~%%*_>N zZmu{T7&&W5oUk`F3AwfJ8;`wF5~wo~?+4G%h=(fPdARSa2l}2YHF{lre?VP6{)a#K zdx`M+?m*u^{(bcZ;n$x}5!ZNPtG^fq*!JgVlKBP9izn2@@O+V<1z9a zv0a{To@broIE^e8&ydeFpKe|3I9I$#X4{7I9p^i*5W9?BrXPsC^8JoS#Xra|i?7J9 zT3>R!E50YcXMM*p6t~nLr0uF5?Q{>LW|>h`n4hj^On%OqRdBmBpUG}ud+_(tR>o-t zpcY(WDAm27OkPnea?`UNXQrYM_6u+V+G9?e)nXx5PJcOSB?TizTWGE>#t9c@YFkofeC#f?VY$Zk%aRHLX(AV<+DqHC=DoViHWfr1!p) z^D9Yj+GN;})|$0vH9^BlX;T#ZF89_LTS-#Kf6V4zyYFrPj`khx$mmnBeXlvVM%rt- z0lS;}dYg^Sum<^&fl+RTJ<_Hx4>^BQ|D4cw?q=q*_16=&Yxf1~9qd)iV7)UJiP()B zgY|N8u%3PSpeMwh18hl0LiJAE;R_fnR*$#A>F{{R$_jFVh@6@Efh!$&PDj02EsBjL zP!wx0n;1tKr#iiu=k#J8<0x`_&(eX@wvDX#^2Q{1zeQ$GYG~d+%-jWJ&pKC_wF<56 zQ{N?~+413xr1XW|yJ>1?-*u7LaChJJbQk??-<9W%Z$5#n-aUQSXVhFVvN_yG*tfLv z_LoXKboDK@&vp&4&pscp zliXvg*$NN53!4}9f7ra--y$oc1#t|H+q>%>UN&dnO{YV5x6y|U9>C^d@^cZCR zKla`PzKZH>7(ZvWduQe@bN3}T$t1Zq3EYr`EQEwWZXkgKLV_WLMIwYGkU&U67FMlT z72K+5)w;D}YpL2+5h5a1rIp&+YPGd?v9C+tqP108-j-6U6kM*NwY{Zuu>NBjZCbn?ykn1y+5+IVZNzDP>Iid5_pa zl>pP}MUYf`^P^ESXkR?t2|%E|Wc|Ma!J>mckRqX^mH%doXyJ|l`(?+^V5)`@GZ|Co zmq@4L;Xe$Fw;m4=zt+kN60I(54q;g!?k=fU1_NP&Vu_QB3LM7-)jF72V?X{7XDq3m zdl?S>``DArW_EFW{^ges?Zc0qJ3RJ9VjD~W>-Hd_O}tdo(USD}#5|Lv0f$dm|804KrP{)kWQKx|$0N1lA zy7n+gl;SOIbghKQWM-6Oe+FS!Z#@wxXEJFgMJfM-?m!Y<4hTB3z*DK>^D0Xe*4?!OdGyUJmm|=-{(Ty9F&X7*i33G z=ZRKvYQP$tI>kD5YPofWr!1vnYW>tUYunU~)}End)>-?A|FQ!ncV)>ArM-G;eB2Iai)n z&(-C%npZ~Gn|q>LEqg65TK-}EN7PYPV#AzL5H9f*Ww`xoru0u?ri2P?RkmAf_uIy8 z{Qb7aY=5?~wxE0l)63~xZCX}IVfpcLW`8*@_dzjFlFWT(V=aI$ z;?FEF>sTo;%$NdgD8?ME1>xs}R|FT z33OITu+bR>x(rvCK67H>WE4h)=Jkt46&N7oLEEW>FN4lBMc;jw_%BXIt4_h~N$P5! zczKKFQ!S_dRKoHoPb2Gv(3X@Z5gUzKEVd~}*=b}VDwHF!MHFUbzt0zPA7u*;^+Gor z>uIa#mKH}bkAZ=$~fsb-i3LKJiS2L*Ivi-=)5jKAs*>`2u@^yO6K4$M^>O5`I1Z zM(W?Vj}?pJv2nnDQbM4rNS=^QCY!A$CLR1q=51o*RV=gBAAVKFiX4;I%DZJw+t(q} zF)RD^l|^Tb`M1-?(#A8RWDo%G4jlwCbwv|Wl7~U?=tStyi10|OqZm1jiDk}eOe}NS zN(AbSEKV5etVZ*(Kr0(znBy4l!~5|;d>V7i5G= zLfx2BH&N(E$*`hHy`;+6PnW~fZDTl)wxDd1i;fWPptk0m#+?M>ADcWN2*txcx-Cl+ zP*!FR>-G`aB-2ls z0-pAb(ZR>pJ+>tl|I0Jq*~FAAyLIcgzCN<`Tl}%HzunSw%a4ZQe~$m+%lOXcmfiUB zk6(S^WsrhP#@}a8f!qi(?V9}djh{9&Ldn=>DjI;@02BitU6kxYE3sW^$9BR#m!JW} zBF-6-P5uxkW1GihCb%|HT$?O(#eqU_ZK9+8<)6Pmr&E*@ZAIiiakVWFEjT?i&o$4t z)V0*N*0t7mFLN(@kM%+2!Jx%#4M-cA9(E%?Vi~aRwjQuNAs&&Quvom7J(k}wtSxhm zz2APNowZ{S1F`Hvx*B;cRBIpFkKRG2!3?(BWi(O85LCTdN+NT6g3Rr$_OQ)N`IE8*$j8M0z{(AY2mtW#+_3IFK)3=pj0?9+CqIYB}=IX|UXFe03k^~$Ei zo}8rJX~1=nqr^#OViFTEgn-$~$5a3O=o|6B5B}l$Z~t5RV}UDIUH8a?*KE8QU+a7F z6`YEtZ(-)D#~w)8)cgEvzxdwgfm6;0%6(hghswApr@UNZIBUdOVy&_ArS8(ua;8OU zb}tQWU^@9OvBSMKbUgj%{Ohha1Mj-tb^qD-LEv4=5xwc@(I8=?i-Lrwn(~>jHQ!so zlv)=twbuFW`p|Nz)w;p@uJC*B$M}p*!5-EoD|X>qI(<`R8 zP2(nxP+yaYHKoxZOceuDnl`j4MN;L=6r>axNGn;A#3zaMOlL2~qREU?Tc8g7vht)p zu|fV%FiNt%FXeHTFi9|ASYRnOB*_}5ludSxQ&tr_%jv8~Mkx{TAmcS^Ba4UK6TFh0 z*>&Q|*GD$~{OYxL791W^zcsS;>ksYP{=lBE-1N!U?#Jv6msB&hkLNSamwxo!7v6a3 z1d+{)KsKiVuk--Lc`3#D(ox6*R%RRDCN7h^*iC%D*d?1iMEj$t1|Zf>=o07ZKy#?wxjEP#+AeJOoMq1X739TstIxN@OQxJyZ^*t+ z*{?8)!li^H6FSB`LdL2g#g4~lS1Z7C?r;GgBik@ff5tY<#6l!r%nB+gosF_;OTh#J zX!{AMS4GU3T5`~et-*A%zCMy&LVlklYG*o5_dabX#7A1a#R+*Zv0>9}$Y~{PiiM|^ z81!P0na-wS(N?llI6*=oN;n#;v}ujpB6BQ7kw&{#N`Siu%~GZhXg{dEEzywe12j+|9p+ zeE2eLJ(^p@_CP_PFc1q21n#xmXMNae4q9`q2Ls0gT!6a9g6SoxW-Dv4ha~J_qHY(* z3P`%&josret+SqNb;Y=e4a^2Z@aa2kWiTZ;#4@*Gx=8f!^qD1ev1l}uUa}A2K#Z`U zK+Fm(NcWTEQXfesVM-`Z_muoaUo7O-7YqH7>Q!{9IZ>;~a-t`xHTE@s;5+yj%0Oqa zgba5|qR)wA1#EK4C{9IBwP~IeFv(AqJG6~_Zp9&pCcz9=jUqZzkVCMi;3$qxz3M6) z1r{=x@&uB+E;0>0ZM2saBs*R21A>fpXmOFYLO83mxU{54y$JCM0F=cJu?z}g0-p}|`)}M16KCj?8$~-=r8*-VbrlY8+ zkm@;EBUXbRGdxNQ(IVullg!i}}|2 zcKf(I=tX8(9+g5qDusLrDdeM4$mgZch<}_)A(BcU_nH*)X*&r30D<{&5|8>=FVoWM z8@A&J%1k#1GTk7^be$l5t?A+C?6270wvXGnbbFP(33NPzt=M%*mEUToY{ecVWM|JL zwX%mujqFr1*{Ni*2cmhy8ALcm8z(r+7Ja>nk}RL7fTA4dY$dRmlZ4BhB)^sVTGcI} z4Z$GwvIx0CJk{g@! zI#-n)yb)Kvc^Aev-L?DN#*bdv{!Mo3Pme$M((^AoPx#4RgxL4#`id8|U7lVT-yR>? z74%MwTJ{mHl&xitSveZz@dZkJW{1V$W_gV4A>QPcCCemz#*#!;7DKm*<+NHNVyt*Z z$+(D*i`Yw*8E=ek{?DbMn-Gsk+$auu3;;Fm#2`s0Qok$dI+6N)M6yPL8jIxM0D6D+ z2;Di-NSB59N@kQC^q%%I1K$1KgWhp3=Vjam5xEUQaU1mIj%bVD6{y~6a`>qVgXSH? z(FL=*-}mE~k8(54*h`wU1pZ^qFhmSxUko)z8$An__>*<)Em315>6Yl3$y8+=-JuzU z#63*;m`$*mA~wO2f~{uYV2HSLuR_2AaWv(KEFp>IfpZm(_VVQ98_h^GwmQ<4P98^= zgOZEjaqJ!a-0`iCE*c%#wB!qwU=IG}wzdcF8(YIXuy@zeo39vq8o1VVKoFH=_bD8 zyT$wUsCUG1QA!uV;4^UyD+=t>Sd&r<0Jemu9)A$^FA}r zn>dc)co)J}nPJ@)&cVy3q&~@_eIg5{ki)(YbReG(nUqdq3~I_z?CS4H){!evxWkcD0* zkQ;kOV0SR?*^kJsUDm1XXtE{d z0mTcg)1reUVb3PidBFg9T}p>q1|;3P$n(_auB9TE2M4gi1Y^g zJHd27z*$1JDPk@cW{OqTChJOWrLe-ZQoMrO!QU;uApDH`g>X{%gX!sFfg;|b^Xq$&680H*V)y45-DUB>6i93qzF_Gu!v`D6z+<8>$pHZ~! zGyA}hn%E_5kg;sh4@{FIC^38zWX~kdx?v(1gRWhLnt)T2jp5U&IHL54w9WFAQxG>P zh#%?)LeyP_0v79UGZw5*rc6qhx(ZE}=x#Ynmgt^|o=QyWgW2sXCsSLTv9*}&F*X6E znk!iv>XUZXMIufYuVER{ZzUVH+P09%FS;&Y%u6j7&8exCWKZy+RI)Yr=Z94K^LU1~ z0)Hjlv9|^3Q~$#F@k1GOTh}2k`FZP*LN^q{552R{pT}im#~<-Rk)oV$a@g$lLTPSy zB@M{lheLky@`sP7XvuNgN^J^ZVp%cW-es47YjcP*gGl8BO_XYjri?wubOPT591uV9 zhxkVP+*|PnuH=uM`wl)B-#XUGr02lPLnemCp4yyCN!qhB#lWUPR;f+>xQ4Pj(B|B zSXrzKGt|gU7G^}6ktrknj0bx6DcN-xNm}RW-FEdTJ?=r%a)oTL$FkUdy4vYB@ z%A|c-6R;x*PEEpaC<#tUf`dtLYSMX*p(HpZ2@WQ~mZU|q)+E@L1lyBfSCYA=B*D%k z*pURgk`(l0W!;$sJCb0lzW>i`Yy>1LGh&NnYe|GV$(w8z_U+2%NjL)oQiT)H- zWZA5=kl-N}mI(`4!GI#Y8o~P_`y)&Qgsd&H&w(8r^;`O>&yvoVQop5}kcflueIFqc z2SdG=RK_~!T&cs@x;Ej%Jc`>6`^}%)yrfSKSzG;)eJMDFmXwkxDTS7lLbk;_NJ%MF zg-@Zr^Ay5WsZo()A!Vi*^Rp>X)DgrKXBmZL8SFVrXV31|tO$M;VKS}2q$9$lS<0kS zKgFb}5`nzB<#5jMft-oCsR^NxzfI%Y;mA?E{qXrpg*L%N?a-uYr?%vy0LlFrU8S{U zP&+E3itu}doGzDi;*rhbc4fOQjuh;)dJF@@@Q_76;}2|HMG69|#DeSrMdV1YY!X=^ z4ZuUaf@atjk$qFfIP}nM7d{eb1_^bhB%3A=6dl;O^-JlW`_We(Ih?h6&cN-XD>@sl zs^GHkXk4>y#j(eZjO8$2?p;%H$Ae>EVh(NJzT}=;$9`>CukXRQ_Tu-bm&L`if{S@b zIja1Q{k`ind)6gzL_f#`y4|7RyOdY`@A$|4oN9L4++HVGuUPO}C9BP1n`FY;l19EQ zVZw%5ZDBvPSpC#`m8sn-Q@d48*sU_;N&6{S-o}uRKqz6&stQoq;yXw@0J?j-5qGXm#5-TX# z4#Ad!?UGX`J90$U7NR_)#6+v)1>$0PCnYJ~@RcOUNuQrjqNTlG9eH!@14|TXbn2$M zp>J^6UwW)|U~$nEV?)fIzRlIQy)^b65K=Yc?{hgoEmjo3JWnF0%H8dV~lE z>LO5pK5&|(fMtPDXKoc%nl}hNW^;*B;jHkM`fHU%&PCo@|7w1<*sQcU+q}*G&HQGu zQ`zj??Ctb#!yZxKt(USbe2a9crI+pEyQE%=3i~(e^5$`TNPZiNwToj^2MSb=<^PVailzsNd!LH@wn>zvY>BpkdfGObzKlKMWJ-uGvs%h871#0WM2@I= zlurXXKuLUlAFfw`da*x8yhOdK4Bkx`NWT3 z|M8E034HZhgqRnAY8==^X=YY|3o9JX;!3!A+){2mH_Qp5!z`LbtIHu;5o^XW?QSHA zx%VPrjTS!HaZuaxR7J> zq|$a~kQ`M>uuL{!P!9)EUfgS=C&07~;UBx$Y7F4Yr9Q!$u{#E1evyTG~3%N9EZzU$M653#Zcrwc9 zFvv|B5;;k5b`l&(g2PF0RuY_<1ZO0{YC=u8yp_vzXI6*{#hP$yW>@Cr;?3eU;RCL3 z=6#Q~ioT%VSGXwe7d}3PS;jC*5tjU`&8x-L(rS6NWwmvqd84>d+9+?dY_yJMkLK9P z=GE|&8R1pZO1U$;Gj}*^IJ`UjMd?1vZMk2{yQA0!&)avsb*oc;Z5Z?2)PXBt43 z0fY@8S97%JX$X*I0AT}2CF|v#Y2~ZTIT4G*1=Va1C+DXI$>dUIAdfCY2vh}{0&4<~ z1zrgV_CR`|Kk#;dOAp)xodLV z7{>XlQ+rdH)R4!-X-g)lGxR;f;rU+7MQD)=<;&?o91I6yE`Lc8dA*2EKl-(haFc+S zkaIvKZw6HIR)G3o0(2soJgpWr-pE`!u@&)ft0_Dc@_Qmw{_0dbl@v{~nQEM-FjYHq zPawb_DJG{rZFKtK)~P{SmyDdLC2Nb07co^uyNj42G9e#EeogEIwqqNfHMjm4PJ=oT_xo@6wfA`5=tx9Zdux)PJv*<_zK`AM9Y>eIBjSkAPxEZ&`$ z?NFSGOJRjftD1tuTvH0>r$LbBhT9BVRtn0@vRcejq!gT+BT7P)OF`*MD$)D2Q&MR_ z&5fzitFF2VCGm6Ot8SZ!z?%7iFiw@Tvs3dq%DMC9KrrY@r4rs_N;*E(Q9Su5L$bs( zC!Z-TnNjwso#1eh!%FBxTh$@^^}8bZQQ*ISTs z&2wLB?RnvfSALCWhc*p%)y&TFM~dpNYFw}*H$7UnYlFXeb#qx(DAgr}i>ohRz3Tqu z-vVwG9{&q7mA@PLa3A$SsFQ4ddD5oY3D}eb3rVm<&f?52q2J#K1F$=Q5w=(*%p$KM zM(q;l1*~jWGEpYBUO+(W2Zm*WfVSXqlet!`U27UJ?KbT*aR?N|{icJaMD{6t zg6!m(O1k!EtdfXpM{%+8V$$IsDUY*WdKwTblaq9dVq!0rtX79j5~=W(1VRGEMMVX= zsu%HT%Yev)zN5@RCh_SGXhsP(RIcmIyXKn1Pdwp@=B7PxzcQ!mt4zmD*wh>U!cAje zT$~pqa^`A~Gw+bEf8i&!Inp3m8sqVmFsjQ-j)FNI3pm{+Q5O!IU0w@zd1VmO4!}Pu z_D-@Zy-7NnH_5K_M*Kcv00yab>7#a~&q*iK6U)kdR7U#}7NyUvPpj)Qp+4%g@DYpB zN>D!T!^eHt*BGSx z6Ai^dOehZeB&|fJX6c?AIvq=`Ns&&3ij9Fut~`CV^V4RdrbN)Sv6Y(gK-o-?Q*2hd zmF!q0=dXk5$XQa5)$GuwN2X4_O4~jLx*QO{gE}Nw*(*>os4^DKYAeBVvgxddZ{lE6 zw(9cNFZ)`PB9F?BzDq8-dDiHCqjj5`N{5)+#twgB`hrWA-f|sN{>d9a1wk@X4pbm9 z9iQ6glC)hNU3j}X<4rhgQIghRo>*&3&KyWyN9*IwNHPmpNNhz9(_`KWqRBhb>4x+t zOL>ek9pw^{+Ez!o=yirl%p_nyR2_z2tp7^HizlXKl%QM)s3tFFMoN$u0=Ro4_PN~r z5~M<4w@g8~VzyL{N~JoqKx)OU%u4eLaXnto^q70Z?Pwd`#_TX}7q>}!@m^*Rd%fv8 z^9|yc(Ou%L(zno8rDxESrpKih(f6e{(CgBN=y%d5=!}#H&5``bE9IhWsZ44@F-hcO zPHzbhWL%=pDTrhrzCe^+Lhg2Y7y_d5j^KhGl0}`9fE60c@VrGPn+M*E0&d{{%h8vk zs35Unzf3Zj%@I*@i=u>BhKXn!nR!VZFi9edFkfK7mP~Uj7Sq0Ngj1e~@w<73 z2Ph`0OblnrfBYFC=TpJJSld`z(0}S=o3^;DJTZ6TD4%@(A=$2_Z(Nx8OWrU~_Q=z| zPTnI=_x-wxF@7}O`|Qa`xnK%b#4ln01XLMhzE5>vyFanY zA+dJYa2OeYoimP3a2iekV(A<6ss><5q)#{jJ~cl}SjMxH9p@TDNv7mf$!%w4HWaWs z1zB*#oOV@?SyVgK*zAFVXz00UOarU@+JUfJ~)*X(W z?wy`%tv5Jsa^B>+-hG$!ko+CxX~!}5AEn>B|7IOi{^1@Er8!-Gn=P^F-s_S>DV)8= zevO^A2NI3Y%p7N8SACh?Zc!XgCs0?w?Q%t&k{fR97Q4d|ktI-oB^TK+B?}}26jDM= zLFl;<6FSONJz)oo#N0=jmY7`Sj5(P#&gYzr^C+Hs#EvsjZHh!5QJlq8OQEI7!Y;9l z)6Kkd4;R=0Lrm3Zih4N+R6yYv`S=hJB{`haubeppY9P}%vC&lquTu5Q^-C3){(MuDYLBH2At#xPq{-s zSZgKW?Brly+;-jyFLQI8U+4*rF&Lh zWu4EF&CBu4-+MEfnI8S!XuP*NTzGkFNqob@N^Ur1lRcHo9lLwvs>`=Bn?CvBV{=z7 zB@+Av2zJ6KVbL!7JsF0u7M?84RVYvW8lBw&1DQ;%o*YdaOK#PU!Z|&0P_tnn$EZPp zQmM!5Yn;XtbO{HF%X{?DJVL|7;7yv7dSR3N%RPcm@Har6rcn=ojRD=Q60?=) z$K0>~Mp+ChASagBE&M3{m55=AMPdM_Z{tln=pTEPWe0)FOKJgAHn4j^^yA$Q0_%S?x;vMt9 z@QxY%{g^rF9pztmM?rr+rfBadXgylRUCK2g6S9-<)T10!fXYx6S^&n-acVN zx)S{`*3sR&q@`u`itU%rtQ;85&0E_UZm6@EYhoNS!xd7)m3iTCUM0ICR8k1~l|R(D zaO>dUy7lwtes1TCqP~qzZ*wanRLp6GEAz5dX~9)HH?CT>aVNVzQ?gCX&(F?Wj|$#; zxxC=zS6`-wfE5%duYx#olmn=|Ou*#-G#xI`ewCkS>Ca32sq}yWcUER;NpVq*{_E0z zefqEQ+;rYO{!gBte;+w7f1^D1=Y=IDg}0O7@5R%Lr-um?FDrt-Zx>IWUd%L;a4bk7 zn5z?M#~v*#DJr6g@ej$f_-YdVog}`UK-AUX1gH3&lDAu zj@1ElM`0mo-+H3B34r&>YrifjEXfCeP!e681Y_QgdNi$_0c9uOY$>q`Vu-UN0b5zY z8bL7>E16k>Vjh2q9f*f%LgQo(57>c2Au0u(YsSDq7muA-b6FcvP_-{UfIdtX-*I-E zU>xGj(-k*4WC2bY(JygD@!UJ>Ycgk~FZN2K70)+zy6(0$W^LqF({HR#{7omThBuDC z$#3RgLq$NjyJCxPti?NPaZe5Iis9B6USENiPr(~<@v>aJAPv`~;)MY`MZqXf^>SEU zfEO&V)vMVV8MCu(8ESEw*E=^QEt{R2#)%@(HZWN7b*b`#Q$H!f1*eJ&PSM5{7oRv) zG`+Ab`7a|2RAn2Rl}T*nISd%fWhLZWBR0mAGl!*H&m3-d8jEeL$;NuzK8YO@WjGrR|H|Wm$_xn*IHc3|7p) z`IooFf7E?vf79IA%)eOzfq-l;Z&+1WepyYVr0cfJ^wW0x0fTA41MZJ)-jj_xBiI!2 zMVO75xHW)H0o>}x3;a0SvDLB1!QNoSyDYfJj5nHaDT{MhJcGfvq~Xt{;Z13HbsDZu z!)XY4vXQE&jH*sa_macC>{7bKNGMGOB&TGh+1ZpdUevzcrQ^4)?Nkv#@2R4KVv5uA zPz-;VU^qLQF7u_{2&c!Bk;W3~hck#@!p89Z>X!SSAADf!v9>jjesuS(@9kgq$up*f zyB_Y||5om~tJo3OFP`pvU|T)@>9!{?k8OMrXFc^GwtaVF&-daVd~3n(7xvD7_DQ_( zgR`@?KSAj207Cp~z)lFwjAd*U_lV53W*8zkg?^_1rP*cG>JZYrtc^hypqLY&;}ip} zXf2^F$Z+VCKxW^HJ;eq&aQ76f+1LL0hdXkPA2Fw|-MO!E`wwqj!YE~M`E}CZS>qDdTq>)LTyUW##qg@)A6?HI5%%*9Nfse>tw2i%a zLV5GV^g>sLhafPc6e=)_x#{G|vEldLJPH&|QVUXW!;#BM+K_dSeUAau?(>Wtj^ynVD&I zY0ON2ou6rS;1#xR8?(aPZDvwZJQ3`6YhG;}jfAyDq-$hO_6TaoshGSWR*<0?lm){- zKqKwV;sOQuaDqNFpeKo*t8rbB=EbGOm~^s1lF;ew+YfQmZ|m;*`nKxok*{|>)5(p- z=T>Z3oR?j{dH#Zp3$hB9^z2=-B>}$Mr$GO(R_Ahp<`Evj4%HBIyt-rgg zm`IxI21Ipai3j3IyxHf=AZd^ zp0MX7ef`Bpw2xQBrfVHbt!zm&F-VdkKeSQCTIq98!YSkeaUcgY6- zf;J#6+F_&v75@q7PttYM3p29xZY##@M{mZ}(NX-&FXQD*%GkR=*dzFC+(M}B`tiRo z5;@NbO^pRavnvvFVB}C8?>J67IEM?F`H*Ol5um?_v}()PPl|{hMUMzA^XX^@fjygd zPswuTdi}ZcLTkDTOrv;O&de+a&+a#yr?+lfz>!6M$OcHP;-|rw$&4woWRCD0BQsHf zHw(0%PrOV9%gZOmUZyReo<}mjm4&Z5^xf|sdiGiNo*S__{?UzOCNSR2zRN{W6g9-A z?a9O&?K|zvN;`HsQDn-L&@?$LN$C;LO~G88nkL9nIOO(8)(~$e5~mo%O%)lKhD0|g zDnh>1Ng74AlmHPWXp4Bj65NA*w`lXDyIODWuR7>@t-5DnE;r}yjXgKDWR6;=Enn2I zsV03iuY9q~`Z%cV7W6`dacU*euyrKJ6F(YHIt+=XX%JjCq%b37_Cm;DA?Ah^g zV-Ez-e*^g%H_^?wE!-9uCm!@@>@vH}CAmE;=i+7xcL|IDK!g|Eyim{MnLIY}nCD&V zT{y?J+{L&UvnZLcgd@o0h8)mN371Rt5|blgQ3?PnWZ00|1-s6_xn5C;kfivY&9mpGIZ+X?=}2@I-*gYvpI8jIVMz2x)34ksoH{WHjieY3!d zX7kw`kP#-9+w$@iab@^<{QOTE2W)P|B5=HHb=msx{P;0$%h)imuhQt$U?@7RG&}wq z@(uF4p#4#3zZ+$sd~|875alc36h54*reKt-?G=bw2g*uO9yscLfkY7;TR&Sd@v& z(s5Y;FSO!1GhS)J3r%<#iwf84CE?9Qw zE4w=H9c=U;S@6!P>sNz*d3Dp(UsG}aikrJ;EW7XD_TKQzFD@=zv1?Jr>lK^7+%f!( z-jW-y1WG17c|G)`87R3TmO0acYXm%x!CY9et9Hh2_jw}7teP3K6g5kpD1x4&bvLT4 z)z+1vlFh9d8D$gQa~FOT#CAsf_wo1Rv14a8-hNrMsPm4FQ{0yLALA$Ezl*>1mE!LE zd;9LXY>NI}BQ6VSBBRBz9J5*GxR{Km%NWTD&=4!j*eZw-gjEozrl=@lKFSa>lA<_4 zMyCuKBB(3|)B@Mb$e8%-Czo|@gzW>NzISW~^HXli{`img#~;*7XP<}CMbN&0agigD zIho-jWY&u@F;R{aaMTRtJuVPdo>W*d5!uB5K#KsPWS<|qg-IRz-7z-G{xtrB{c$to zt5MTYpr#Cm_!f|SZi zGfFeKqwmN6xcBY-E1K{9?LK^G>qFJ?zjxiezIbN$ookNW6F9>4RUiYF^atsE zsyxwrigEL?V-(+0#{b0p4j?DWjag<2*cnk2w-`1%;iV_cqD%)Nh=nRmizal8sdUUP zE%WMvkojHV>Z_MN{MaMx!xc4I;xW9j`_@%co_oyo?~&NDLgr(m-Ph7~?~GNLKv$Po zs2VUnH$uSrBo_ENLXue&BNFSDSg^Y#l_F{Uz>YQtpiJ0w(?vQxZ?p z>70yr9!-fkw9+H-3ppW4c zJI|R|PlRE7f+<2~7a5UtlO;h@LHc2{F8zv6Py#QaIt@9%7XFlkirAL8^(XE%RSUyK z1}FAG#?I}Vs8W{ao@R4z?!#YotnO(l6gz- z=N8(}eX+7-X_;98y?JHj3O4zrLu#I8Db0D9v9y9)R? z;V!QOcX6Q{v^G|?CmZik@eLt-y%$$F7dn|m7F=P$bIo{$8JC%G4TDP=%!g4x38(=! z5SWq`PPb#bJ0!_zAz<>+3o!W!sYI+|Lz4t<;)2mqmSm4G_gwk2FD+eq=WAD9^ZFf2 zTJC!7iWN7tmojA?H?%DK!us;kjxTUmFT3|w*IfOpds68IDx1j)<8_U`5xz5Avbll)zgfMa`pi8-IDHeMK*;E^2vqxpw zDg_cEYLYmhEpTNR6$f_XqH8}iL3Lu=xB5zoHXRs_zklr5xf^cCsq3!(h}$v^blFAM zbXLS$nT2he$`?i*dYxW`I{CmbS`nM(_L5b2VTHN|!(0GD9d;No7(~ z^D^^%Y-k2ifigorLj}?tj@mjR0FsQBwsIoGbw%)eKUsD{6Y}XQA`oLv8F7_q3P?^q zn^2qBD)IW=GuO<|3C-WR=Cb`GbLVb5(7F4&SJ!ZdxS6ZA&W&|1%uQ*!WoZ3vtD}_z z_jh!DWBYuLP4DRSOqmtQD9R1H+=Y!JD;8e9vS?=4&8?QIwmE6R!g*72Dhj9gJe5ry zvulQy7UZwk-K?K|$^M>N2dOd9gd@P;xu`&76+>hdv2=bi_A*r&vdAY6*x$!@9gSbf zKFj{}Tmk#j{UncDp_dvVk94#uHe+S5C&(=KZ16BQN*K%q%{#Q0$0Izxmcv^)45pxl z;|xU~4QUEt=Khe0;<@;OBN^l!2WaCo>yOig9@i*l%-MKf|E>d@W(L@&cvqxq_1q0R z<~W|lZ)YVPUZ7-eo78;G_nsxAmlUv)(TvyXh`3&zG;sI?t*oLS2;ZUyaE zw$g8#FkFOX+$_VgjMa{?6~nN_ZiJVRfrGEcco5@Gj4@;9$agSdoG_ZQ02a+`>Mo^5 z&4fdTO2g#a@^a$PA$#(Q!D`UBJhwJJ{e}4K7jdcCBAI!{?6%_?Zp$aP0ONeYlbMm> z&Z@~~D+tEZ5E5oV-6MELY&1u~ip^?KEVhW%;;aD#jNOWuGiY0zP-ZCkF1NVy{ldQ)TQ2;TKpKz=2>EG&>7NXyXy)LiipI z=W;j{U~7eRWVAPY^DW;O@cQCAhl1zPW$;>Gf&K8O0SH zg4xXbqh6Yk1a+g1S&F`V>T9eeQ^A}jvh|k>SH-3XSv7M;a_eEu4|=qy4fHlC^lIwW zHaFEXzxF4y_J#hP<*`eDPL^=TRT7Ql@FMKF-El{4*^~TE|CVfJEiK+SGD{IX@Vq4J zS_qfkzWKQO`aDY1AUl}%S6e}es%g9Y04pHqch@U*Ol)q$xbIX=jb;|FwUd{Dz^o6E zYrXB5GgEoDdQEH~%gUKYZt@6CchX386z9A;wUYPv+CI^i?WY@h_w4P%sH1mB{UkDL z?53kE(Qsp)^KYIiS0ceJ+CuhN*UWH7YTLMB)ZRS=M-vi-hiH5>;R<4%G|hRJ4q3hr z^c${~XJWYpw|U|G!*f5qyJk9e^YmSbEB}PtkOqtQLky@o7r));vcFRIBM|Ghcc#}o z9;l+Hl1h?J0E}xdW10Y|n@+OnO?)(iUU-o%xP%lR5@LNCNQ;tfT+)skmmcJ>NEop) z1O|=M1>d(p9>vGY|IL6z{t1un*$fD$8Xq+(v`8Z5VGl1}xn&1knUrE0RioSPO_$wz z|8*S*U!XWjF*M}%Add{0v1Cj8lw9wM^BW8K&ah{yNYmqMHEz)61hdv2qNtv(+}kP2 z2Z(Exhza?Kyxb!DNRjefs*6h;%g@*IF5#(|uf9vd0>AF#g2wa7Jh)*Vp?;rTl>5D4 zZ%qmpt)>r;LRUh2chH7x=hJ#P)T8(Y0U9php9#F&&isG2bet(05111&Xv1vjfjwN` z^QEYuY{XuuFMh7vh0}>>@)e{yTY+DCRsA&&IU0;Z+yZ|0ul5^6i^BeHoSGl4|6{}Y z@|%#Qc%O~1d|Gut_Eo7u{APE^CV72*(sROVH}Cq(?M$zm#*5yY#SP5Zee@PP)|@@K zdPx!ZDG>^Th*+E2^vAA_obLHtJre_uVH~R^|5FVCE$jK(tZx%H{GZD1?`FN6=KoK9 zHUMU0Gn$3;e1C1|{`0>pLJnAA$|J2Ypcq&dzn4C^?q5rS0g+z2{*K8LZ>K~~Uyk|e zbg=6^_91(gR~>7EqssE{n%zH~(dP-<6aif#re+4O+g%e|W?lo54=*>gH^JN&r8(vN ziK{ze7FiaeunZXb>VN;=`@ndKO9B?I62~UAddX0$@S2##g3-fl{tf)sh&TAziiQz` zdmATXvC%4!U{D#Yq0B*FR_LSf9~~NcVS-;KrTe-_U*7X{SVKF$7%B}dU$&AgK#^n= zp>!xiI2Ov29O1Y0bwxDQvY*t9A_&I1;xe=q7Bh=!NiAfp4;LE~A~2IeJ~>ug@}PBS zfBzV6AS-de*Wo!7c>oF!8B*1)nQ zkxh3<#gM5sDW%btowuPBW1>g!4^%acGH$woQ*#O;t@_cjA$|OR4%DLR!Wrb!b%b@kZ`6_@l*YeYLWH+mR z@02~l1p!dQb?l9d3#yeI7E=FyR%-xxv4#h*h{X>Q6dsm6=cZ0H(~p?MwTs2+>V~1s zdy^EiI!bR>p$8L}1}`DQBImLAq^u8rZ&UxGcaD6d%%PM+bz5?wW4)U4;gSu-Hz_^Gm9}NfGW)?Z4s{PBD7bLnu_rHJW?z`6Zsbf9QLo4 z-*Uo^CHLXKCUw*DJK1FYTCvWPhTzKdinn~3BlqY36F7Dt9yAjiPN}5R94(g1MWOV! z7xkBHkvL`H)a4_Ftp3Kw+f?U%ci9MwSeYs;`xt@IdC7a^uI_ zhne!Wr)C#h>7sl~Q6Jm}{R#>RjqdfbAfS%Z-hpOkS)n@v`R-Q^!?5r1FJ zXBwt~JFSHIw``7O`-UJqJqNl03+y(1htD8sL=h(1w(T4e4`T^>1`q%ir@#-~u6&r1 zgZx1`o^KNS;%ALbF*M}Ai)S{Hgm-#u4=JzbYZS|_xv`&Z)#=o!{Hfv9dZQ@Ad2m*i zPxv*TaE|GzHBK$f&1c@+B~s`|F=o=>cl{!8*P$4vusl^C{+1Q#QWDvRbMfx$N|u!#OI zU#s%l`z$hrkzhyfqedv1OI)i)O2RieC%#mtrK^?~B3xksrIOlek&li-CuQ0d0KCE{ zZ!(xt@RxD|N!5eujOW2Ejten}?cXHVyh`K~ z$1MPZ77ED37#maC6(3K(_D;k&lhaH)p8lC9JJUYMu;}3thk~ImT7=}EKM%+2si9iN zr7>G7!}PbDf?vY|F{9J4kzl?u_<5uk?9jJj!5rE0KK)HPat!^-h_f8&%3ERK>wwKX_O z+ktA@j7&af|2;h(rib=<--M#3TqAcbu+s!qqj)J^^TqssN83Kj(M^)VXs^htxtKp zx!+BqTmP2IU2N8QTX`kZXs+fVbJE7Ab!~T$2WvFe73x!UIfiHxKRn!FUyvMW zgYU4hZn4|3A8sEGYM1-^9KB{EARwByE~hFdcP9h8e#f>IpL(*hjS2xw@4L1n0O9G6zShA4C`!D3!BB-y7~Y`CiPAir$-lSADYl#dR~^glV@nO zwN(JKNgKI&v(InRKCZLfI|T{%=6YPX3%9bxCz`OauZqObI;x!&iM8^CTOZ$dTKO`H zI}S%#4Ml@p%~f`vs#=xvjb31FOG~ZJ`LfmW46r!icLDr@l(B-{s(XOOg=X;GS8Re0 z46U_8KhN{cayO9$t6xtg$wU>th2PtHtwtp8+)MKVJTykXN>*>AtpI=1Xsa3pThget zb}}U6%bQMreQ7V~$8=nLzS9)-$=TQ%09I0BxQaJmyc2|2N?df*uV(}n~KDzv{#<-1lYeF==0xIl-GSkRC zAMM(fyL0|}H9AH8jrU%ZgWtcCGjCx=@(d_S0|BSYG>`*|mS)~ug8E+1^HZBvfyHQF zFme{L<)wvq#Nf&{*5z}Q7Q6v>SgL=RF$()B{5=cmSa_D?z;TaH;3|)T~P90+4uM&KWoX>=%NZICj+iHi5SSZb#{^Gf_=MjX41^3 zk|peOBm(c>CS*vP@VxncC(qI(*;3*Z+vh*Yil#q|hO!-LeK$L|K&ER>q%P0*#Q!<- zcBh|&)`pFFH#A0bJHNim-TcYF%#7?-ye~A{H058}N{xz-@AU?Oap?@_Aa-kT=T{LQ zlUaAcXm#2SvHYzs=kcR`;!>5y>-6sl|HU$>-Z;rbht;_+q5&(ZyPPpe|KZxtX$n#_ zCf#-8@_di{Ql`!@H;7>Ws7dT@Kla~kTS7Uyz8=}7W|@G!x9Xy@^C@H(s96?S7{j~kvdHG)3VY|L&mF!DN+17*d>fm4PLdY*EY0#< zS`6`h2h{;8(RGMd7ym4KEViU(9Q4^ARND~^@(QWMGun5gKSe|ZkeAV_*^3rh% zQgeyV(di?AcwH|Y+;RA*O&aTdnK#{DYu0wjY0wu0>Jl#tuIyL0v1RbBa+=i$@YmkO zX7Vkq%9sZI>y5DCzl%p->bf+y#z!giCy7pSP)SurTWYCkFjM9+G2Ikvz;dkxuLv%6 z)J^GtS3CGp#K5u@%O@!(hZ)a)lcY7d%M6n_nS31e;d@Thn}44FJWXpVpYLtF$9b6v z_m(#FJGC-b^aT0lN@_Bt&vPAK5BWKa)=dYBfb#WDj#bs+V_j{UEhk-=ZN^%2ReqSu zcd<81IVU5_=#IxGYDp@*Y89)ler6o;Kdx&)yS*9D6$%S+eroX?)9$&*_0FzJz1_XR z4lV`8+ol6))Zc==@V{xyp}O(StN!i#W6VMP!_h}OQ3}s`JpkfWwvqlH>`5a`mBR- z`ok+=TEgtM&EkIvZ1870c^&IB*yxF$XbL2Jfe?_t|*W$KERK3;MY%ou@Cns6)8X1(k(}2IS z<4O=Kq{>mue0yuo)DWe*H4sNQK7D=KG?L`~+-Mi7n{|>ybSqF1rNnu`S0`TxBMs@v$McZ;>K7w*RPVum+5EeQI>!fJGeKp0Ia{< z0$7(qq6vmr9-u(cEJjG5+dX3jbmYBZO-p;QaW#?K8$@)MtcC zeM_=mo8eBlbZ5Bt2!Z+T;=cs5DCO2}eHK@7okYI+BmAX1bR5nC=Wr?3J)!Zo&IFb} zNrVnKzv2H15h#RzbfZn91rl`7=x=exqD-bZ%hx%ldchaa5+j<@h9Lfp+#iLLU=AVv zdoj)g_tp=!4z)6%#KViecv?M-Wg`~jHE3VO=Wnd^LZIgmV8Xlma&q zIr~vsPNGg?!@U(BaKXWrJ(0LG28;;9>am>QnpTS12>%|eOv0I4|MYa(Z3)8WZU>(S zhn>R*AX%Md-#ZU)c%6AsS4^0Hbf0=d`_-@kL%Br0$EKNPc?pr4vN#I~&*DXkZ5(7F zw<0tL;g+IIs7I}rpZ&<1Bs>y5!20;C-nHn#F_<8Zb)++Tjui#i0(IguCoDQ7Nqp%MK-K&={p`;LFz+kuu*ik~8^DK@49P89{GA zJ(=9Y-TPvsI8qbEK$;`t6H^+JoWG>Qv$EA${Yuq7_gQsFnY4YbF*9Oy z?h=UrGUJfEpGqsWA)7K`MMuLd@M#P$c~~98B;+V|oOcpxZ`o^b5kG+!`vktCRI5ImsCP!h?p7M7eQbfhMe>v>keTC8k$RetB3N;a2`Uvv$pF6N{X~V zavX=hoxKoZHQ>DcfM`SW{M#JYkp|Jm@IQnzoJ_1tG~E=XDtLKKfuqu{ui@(QT190J z)bi*@$}hCKamt!3IsZ+}sp?|2|7O>Xwhd7L!W_wEeHmX>2GHWNU}q1c>>%ob7&dow z$nel3X`pB@PU0T^BlwYCV#qx%7nPSm6?1XWn+G|o!;oup3}RVmBf0;>l%gYjb7*^< z;&1S9-|yU~PKWU7&DL%26>`2^=Qpg^1?^(;)XXub19-m8&sCTkC$!ScX6Y62>n{b|^|4}h6GVL(54ikBB~ z0dZV6Ca%vE&?GA+bkb?_tXHm`UvV^P>)X)E+&%!<^mKRncOi8vbjFzJm>mFF4dR{Z zoobyLPMJZiyZPskJ;(v&5haMzSHmZ>r*?}U(gvxA^g&90416jNEyDrQ{TK+c2}2d! zSzi-_7RrP%#K*fre>`6uR165RGOo`vZI=$p@rXEAy2B1ZLQH3z+9?aR!8h)sX46CY zThl{=!(r&Qg4hq7E|mSH>aEFIAn8+iGI_pbu;{iNnTqcBrS_^@?|6v~F)>^1n@c(` zoOT__j}CuYD~;asMqbu%7P$moKUECO-L7W6sqcTK3&2DPR$iK4y5NOg=`U&szKShU zEqQid4XK5s9M5vU+Eff25FGnv2mb^~Qt||~h$j}7^o}ZKy%8)Hx;?Y0!3fR+prIfQ zd#7jNirvZENIHrJmEgf)XC2X*Tf6Kx?Zw>%tFyicSlITh+ADsaam?#5^&*wqbBkJt zQEbzxYRCX6GwYn$Vb__Hg+bhUuqS6WYkU;99S7+-Y#pr8A^7^cLbBA4Qlmjis6t`Z zTksXWLUQ&No7OipsarHZ@_AvsLo==@RjDb9xgv%~BzcNZuf%vMiqNWljk-N1->N~# zzO2A;#j8fxRp%wAUwB4m+T$&G_IA1(W}kDM>nm2@aXicaN*4jEs}5P2x>)}gA-U~5 za{IBuZR5bJ;;l(cIn+HTzyhS#5gwUJvj(SWNY&@8#bv+bn0qusM@;xy~$pcb&XKtSDAoPq28Qle;9 zf3|D;=I!(+kxl1O4aTfD?x6+}>*or2SfX$X%&rnN%MBjQW{`oSA`mV-oBmI=lUFQZXm9@Tesa%qh6pfz+=+-dG|IJ zm#F~KQ7W!x_f{cvK8GAdL{1gA+$tlBj&+2#Np~rR->Pqo);CIgFI0$D zomqdR`Y|nOL490Lgw0R6e<9LWRMvigH^x_tp%u(hZZ=E4@xWe^ufcI1w6X}XLp~3| zVpdGUZ$yyb4oft!rWTlJAj#!@gG=DP|KjhGvfkuek#O&9t_atM|ijZZf1*LM{L8faR(6wH2Xs-C(O%)RlyK^oe%I((>beddoC z@Tmg9w%K796~UX0hd1|B9@F6Sgko+`6F2BsD}d^xhvFvZ;(P~-5Bq{V=vp;!l>8Jh z#qC!K^veNY<>%RE3jg!Xee4b(-)n6IZ@3u$b!~|}nQklI>9ugXHw@BK@oL&py#r>S znDH+6Sm!(p^|a)!K5gr99JG&;AB5cV1>twx8|Nkt?i`s{I$fmAqH4JIBW{a|Gnx|N z7ZBnDqflpKQ4L1Ih)2R|tp{VR2UV;FRjdd3xj_fqpmc6f8#m~V8>Ge!;@}3IbA!yd zL4DjHL~hVeZV(+e=->3vMRZo9IOCQ8<5>dgi}he}mb&>U{)%SkhY(ufLG=*sj#~(e`doB^>{*lVsiQ5gSn9LD=T0JiB(hU&p zPPY>T#67LL*Rd#itc$u@ch+z(L3$5gSH`P+pSrx<%DXaEekZVp14}BlaMYuxv<8<6 zGQO`ea!L~eD^EFG5j(hhd$k6jmbp7OZ+KyUm}W5iRxWC>9-bMw znsv^CHXCisrVs%Rw6qDP%rU3wUx4J*RVO|w_pG#>t@ktxD%CCLO9J`}KE9)oh3^U( zIr_|Vit#)jE3Hw^2dUS9NBn#<_uk>h@3yn^8jK;8E3>qmApn{gLW_2EZ1FZuQ!*f7 zJ>-YzO&7O9xlf{}Z-Sj?ttc-5QfLt9vu*G%HT>pZf1@45VK1;}!d=3mvYWzu?uTbm z=huXjjYnu!+3&p{-D7bm4WEzpd_jW0$xi(&oygx>jx9)o9>7_bAFDkcw-@6c5}BX4 z_ShhU7o@K%+86xCRu>9`m7Cyth)j1y3%ksue61)4Kti(cm9={|ME~KS`!ctQExmfQ zy7G7m|7Pc(35Nq$Tq)7zCyr*(PG)rnV%S^QcKFtAcwuF2CQHk}=aaJd3);&{?Za2v z8?(%{CJLf)&?G=tR7}TC{qCHJ6K%9m$c(j6B!3pp825SB&K6cUO4(qe8_N!ue&Ab>45&1`8(Yj68wy~Yvb7`WRJNf)6 z?P&+>;jy!A7ozyj%8Pj1{E_WuTKnewl<#NZYYRY(L7mrAhOB|^F$ za$}})b6T)IBGwRvBpIqaaoIPiYTgy35!5x>P=2|KA2whJ8R z?8cWl9Pb#+=1<#g)&8%9w{4iTCUk=IaR-^PEvVjg9HsgkNblo>CLqf1!Hik@WxqhU!phA25PP98J z#}$#Q8=k-3T1_*9>Qz(I@uxEVSN;E4qWCc283R+_C9YXA!+AsO8$V&-=#=KaXSZRoSbtMaaEx4>@8pG^ zAnacA!@z!<<*T+N{AEKXk5Y z{J7z_#Tbh~is1S8CJC|GEwR)qM@vX@srtTbZb$=GcMXx}R^Va4`sE5ES?P1$p3&0C zA+3I7ORbh2v;yPK#^rlglc$_KOm#~lU{ZA34x%;y4$gVf&z>dh&*J^`pj+bb{Jn|L8=KR-Wz)T6@rw}Q&Y_K_g6a8ovqEy+|!nuc}@_Z0$5Ht1a6TrJ#_2J zkB<$^E#%tHBxojj>B*AzzZH|!=~fBeiHBpUbVQsK~4C?%Xgh;K3m(phKqZN zF3#Fvt@AgtSmYt=SBsgE44Jp3?muY58}yb{o> zjrGOtiG4dOf2vG5Wa@6KXLFA0shH0pmBe+r#ZSrqir_`UJFX-NXyw-U=i3y_VE?}h>IR!zaH@AHiOdr**Ou){mPRGYv<4*ERIzLzX zdCitK{1-&cwCrLYOdbG*2kOg!lI0-aOB?`V{P4%_m=rc&cW02I4nmp6vo0jdWpke* zyQ*&yS{Vs!aq?=#cw@*LpRo#AJyErLOFTLr=n-0ia`mrJ{POcGyu0AGsE6eVzryex zUct$X#6V=pbJ%x`25#-ZWz)xS_xY|@D8Dec zcIFVK-5&}Q90-Lh$U$O<%uHc=!PQ;7FgL-W{OJ(qAY9m_4`^$>)R%2%1gf$0N$6il z$;^~T4*CO31iUH#)_{C%a7eW>lNkGoytZh;mQ%o*C+%RDe7NUhcauH24(r%F5Vo6! zt%+>wI?XgKd8vjpb-NeZ7VB)-tOXwyYJ25OLSbydOmQLTg`a}W`+jO|$tCV>`QTYlWpr;xK- z=4NJR;teX8mf4i66%EQB!2lfO8 z1FlruL4|@Z_rGnS_*lUV(Hft?*F77_eDAZ@MdGvB`Krci&ju*1<$FSk=ene#!?Vx+ zSjdmjIzn)_b-yWKYd)Ys<@_O@t5>vdS5TlJs9>GE_pC7JFgy5|1;Q4iV;II7Sd!nV zY{~{C7K|brQ7a)U?={<^gW&%h!Qoa7RDr6p<2A(W#_UFuHksDpI*o`lsq}J5XqH*& z>5i0tPorlrQqti`t4%jOAU!ZHPxb86212Ec>U)8`#m@TetZr-<%suIV^bl4mRw_2d zbQm*CPa;`{b%BwBN4-7SrCg_GfdStpMKyyan{m-5!kMY%K=0Zyn@#lHrQ_4w(ks2g z+%u8;P0+7pD%B!&`+%c4654&nGC*^4P~V){t41`oY2)S>c}91U7Ia|NTnMc=NUVhc^LnF9V{#-L5+U!)3Yk@3sxrfByRJUgtXoC(*1{h`==mb1qs&J18dLT zJl4u_?K@=0rsq22iWzOYTEY`@AK)|Z9r%Q6Dg2~iS^lKfvF$mh+t{r1&B&}4q7A6M zJLx$=K7qfpI8i*oy|ccndam9mir_D1$ys90k#(vS=GVKiH=nNj*jhxipxvs=VKzC( z)8>4x%%SMiU{-(NxN1+)>eP1HdfGO#foV*9u5iv+pX=L_Q5mFm3fwNao9i#$uGj|N ztw83U?E#KKZ9T1T8`~S=8&c=y=Mv|e#>w{-E@k&-E@}7gfTZ_9E^+r!0{Q{EWRLtrUY4tI*|kYjlnQk&{iJtnd}BW>P(V{a?CyYdF1XO}_UFYsnc-x9UIk1^H{>&X*J zH>(kQB<|tDH_y{2tNP}!ujwz!MV;~gd|aMbrVT$6FepnoH>X<|3vM7h{x*~^hqQim zN1w@dkOrnolhkyrOmtG zLEWRU_!Res+xRp#q7wKFHeycg`-SA0a(HXTiv9lKtuAgU5#&3((MOZnV==^X@+Hdb zDdea)l(0=#djIxfmEDrNsmVW5@M6p5GZ?RpvfyZ7EMW5*ndVy+i4x0kTa9U$&+Ae5 zuJl_q+LH0QK$`z~xEsHB%7@$&Q^1GqR?@TmP4EgcCs8mqFelY-Pd_Kq0>97R)t9(q z9@;BUFh_n)<67zW>@%MWW-Xt{eA>gxY3hiP;ByLy7Iiq>QFul$qJCb$=+EEZY3}HZ zwY{b&p_)FF*vsWBy&!mX(0?EVEKc>SU=*!yYitei=I!lrTo55T6ky{#ESL^N@*y5b zaYr3O`}QPq9)1pg&3So94sIl8hcIDuT42zSlh9I9vwxQ&z@sFHK}N-=B#=cVj);jw zA)~|_LZOO?b;DHY$B;sYr)JxW+kSX*I$Cca;xSWfD4XI$FkeAmsG(B@8XKSch~RAKme zM~sb_-~V{OpL_V3|b}6KbY; zX>0BBa+y&nkRe+$+Ox{wbcBAe0>CnZd@{gXn7CA$Hd~p4BT4Vv92Fg=hIK^((lNOr zuuRiYWz5r7y0@pi;sd1{sM1VbCo>j({DQyqWAD>oLsFJ9Nd|4OoKOa91#U)ptR3ns zPnddEhSF6_n{!M^xo>%v`eTOd^SyCEO2Z0}NDzPJAO?(b0mLm2^P?EP2@6<_;Th~d z9Y&7}u|lHxi@7H+^PAI(kp>jM#~?G5JIpRK?7C+oGm^Bv>OKLe9`6<^odtcOyvc(^GrmMCGvu%Nu-QFJqI3<^XlC$hsGX z@wyjAw7co&gb|POP`zgm(Cpy#Hvgw+G{6kYso^7|?*~S6c=BE>A$#h-cT&G*7C5%Uf+&x14V27I z!a~iD89v-9QPC7xJfpslF!YRvV&E)r>mQC6Vc;$B)7S#CX?0L8v~5^H6s6$R{|XEy zRI`<;G8tM>E=Xi=4hXN&21OMX%&(RG7(iwTQ^n0Bdg$K*)(bQfo7ysa70hMVR^@$Z zW}^I%FPpHFuGFcmEs8*9QbWPNe!C$czaYY2AR%DEA?zT2AV>Moo7s4g8|D$`{{VlC z5!XXSBKU#i0q!#phvb3!vn%sw2+h~6&tJDX_CE{9&7GTEn}oT>0q8;jyGT2P<8G5~ z_}$zm@oBrsyWC9|J-_<3e)V6#zbGKS^kbiqA)WZEl+_WGCCd9t`e_+!(;XQ`sTIya;vp2z7)AiH{gT zGO>$$DB_#;E+}^-8invF5{UHqXc$3ABqD@IPjp3Kz9Mjo)au`u9&w?-Iz(H9*@ z;fqgVrIv|9Yiy*JGykiRgs;(u)3aE5c6ddx8&Fz%rfu{|5D0C&lOJ69Pj{j(tdYy{ zXRGvkj!X*|f?e!?Er|{djtw!RZIbqFRtT2$I;y2~;U=6Qvs$PoCH`QEi8roY*R*G( zy>-vdijjRgust_?Gr0B@3)J$^w#$)nj(GkMgYgn{|01ss{qeXe=L=<0rxB@os0lA= zVOvb+xHj$Rbj7s*xOn%m_;>qu-p3+zEV~dsbQiiy(jawN_zti`ZdC7je2QkO(VlUHs9|Hg{f@#EOvS+*c=ItS)ZxjdM`-=@l zmYZ|y^F-G4tAS{X3f+04ix=g#`vf*>SsQIzT}&cFv3(DN|f>TK0Nv=V+fA2~9mj&ytE@e%5gTgPW)c-Bb1b*$?{>r@v)>mMWV z)|b}hE<{}oo<)h2Y%GyPp~OXjA)tt!8D>@Weh1w^-v;iI{IpI$%|}NIFs={W2w5H0 zN1x*F;>)34%_0c86$w__qc#7QqfZEYxD!}cgoae2#Z`8&vhR{??nMsFUzv=pi%+}We`3+{yd9FLN#}tR@S)U%lvGK zx6GWW%ph=v!Wd8zi1tw7E}4RihdCedU(8amw=tz6(?6x6Y68ykOH~&Ed(IJ?nkAwi zM2q4Tr1eCt$|lGgMK16zmA9%rt$iEtJ~6(Aq80p|b-;E<#fq^WY|wV-}l$J3w7>k-nsh`75l zguwr0R4*41((~5SWLJ&ro4y;fbkHQ*RFoN#K=f~wx9h$Oi>I2+Oi@*2W`6@rr0Uw! zouOoQ?90>TgU0)DtGdV+a$l72-hiA))wx@KjCXw1zv#oZgIFjR;eOHzoKT)oPAq*J zg5Va7y=p;lRn-K}C?^R}dq$l+RB=swG?tpTbz0RS$1@a=Pg?Ct`xD-oJ)TMny|`8x|I^QDUFoB29q)^0`5}rM0JvDP{du1> z)mr$iLY5xifp=R`+H0FBi=P!>{xD{V5Z!ib38w) zTVbz9L=^B@{xG+)N8sJsc^V*S#$drt(Fo*Y5oSSf(fJ88OW=1KS>b9YQ;{) z$i{X{&}MxNP+DUlyyti1?vxMYj4%=?(soV9@^*J2GzpT>+)}KnwpL}wb1ZD!-ksK@ zeo=(EBUlvsNX&tWq}5VvK#t`M>vR>b@-y3%~b(s%2F* zlE0s(_ctoJthEhJ*rby0%9^;wI2EfSZ~2Ye%`1Ht1VsQxt-&Xv%%;119p8Z-hP$hQ zz%HJ6j%ev}XK@njHD4k!e?eDVh}S3`wj5hHBe9V$4YLiQip%XvFnBU^}`XQ%HQRiV;%81au(@O7=Kae zhVuogOS^^$;IlCH^IqO)P)^Gf*g7Uo=U-4gN zL>H1jyML+-f)EsFSe8@-rEnEik4psgWvg$v@$GSgc#{QwuVVA1?`xN2dE8<;(c;l!Ywkkkf{12jH!E?_tCig z{TP8xeR^S$W`lm|N z!++?h0JusakiQ4=B=m`NUikL@Xba6^+`7Y3#QYt&`i zPkyhdB=krq<$w)2TtTS8UYK6Wqddw@(AZN|Vkh(R*4-xULgpUakm`eusi6)ud8GPS zrCkXq`$M!3{!IkN!c^N^-u^45$bM$DfpLiH6*9k=RBzw5LZH4-t&>SASz<9f0WZ7Q6CFemyid8_}Ek7;s;>u#GI7 zfU)79B4)7_DnwTFL}DX8QjawNH`6uUwmn+k;!(Ketitd{t{r|3@R&7>cgpK?)}~l%!=N~TLdLE!Wjh-c=|`5a5Gf0fnI293xe4FSo5gyPkL|OsNnZ5> zqu&YL$zKqwmM6!aY}N!a-^$tqJ&?h4SnL0aLo)wSgWtL7q7q#m1tBGp=jt&H8~wk@ zJv?15a6;nwC!9dPqi)2;0Y-1i9_%30E$~Y2=L&LI&?d?urlO|)r`45b9EawQvkec< z&IZ{6CsgH{o!LW-Y=bT=9sT-ojFVP@L&kCQn)^3&mwdpMJ0-&rj>Z@hYOwT-EEJBN zCUk3sr$Zd0b`vcicf#7SFp_&4ejTmr0}&5$#%{I?buU&|`kpKHRvX9_;kgT`bT*I^ zqR&(5*YuHSf$%zTYdTCUVgceK7OH=9BsnUKKM=$Jmt_p>Gb0V%##Mw?1&KRE3;`v6 zKoQHtqjEYr#7A2iK#70(EWTBN#E&LF3tohUS4nYg%xpjO&%-G5J-}g2{Z^PumTaf7XlWT(odluAP^qQ}g;V zmU>d%3mS`@x^M3RsU<`kb0A8jUB*#AMUv>OJfJkdM|4^?x!SkWER!rn2HYiCqX?~@ zD=eK?H|BFBf%C8X^A#_vBR+q#j{6R|0Gn$!t9>B(;%U-uS8nj=a_B5PjQuMZ_#vdA z>y@?j7SaBDnvXfxSU1UNJ5R#A>ElQCbC=tl2b>$$Vc{tAb9go$XVH8o8^8F+TFfx@ zYnmsz49TF6cT|5!(bp4~DH2A>XMZun(8YgQJ33^|Si=vSZ(Ir~h=p=1D~7xwypBUT z$r4p6^3N-iI3mxw1W&#y20@Tk?tTQ5-kQL7{trJ3ApXl$dC)A5v{C-RiFce3=?0%&HgFgtRn%tMmV3Y#oA? z1OEI27OD4_=vIo#{tan*b>8~p-{Zf*h9CcIJO{;XPm}b}k6HZ8i<|euhayg)=SW}s z9_o6zo8z-|Sjf!4^FTj|yR#|7a8}wK3SuS~Bta7W+hariNr zf7e1ei;jSw8$=aJAtM`n3EaiS|5>e=%m?%iP9RKWGKE_AkOmLcl5HYQj{+Mb!;j)6 zzrr-JpXAFY!j9Guo&u)_~ctPCt2m3DQ&%c6wlw~^55%%B7Wzzhyq_@?{$ea zFenF-apwp~u|IvLOj$Tlk5O_6B z6~Xo4kG5&H&ZZ)S$boh$b`zoh$;n1V;1c4-GrkI4GvTQ5IIw<6F0Tk?-59)!W&jpy zjb_WWL?7bmr6ee5a58oYe&G(11v;eBJz&)E`_#Teu)am;l(|tRl;L_#DtTB>;ugxr zq^OHVH{7dB-nHDnT;r0NtTkSK>Gk`?KR^Arz5eWAJI~$`Vu@^!2=E zd~w~VH2!(2Y@qH91nL2ofo;H5@kIYW{LBAIR^p%TkD)__%}gd!GnlH+5;>T{tf<^V z6k4M#s9+(q^H0e)QC}AH9cty8*~SU+XjYMdh_u@-UYl|iU>gnLb&6@tNeo(2ib?Wo zF#i0`gtpq7cF94-Y%7m)#kwQSeiP2MVLL8vjR}e+dze^;EF%T~D?XADs!yEoJO;Q`avw@)lv_4GCn-*s!m=W^>%L+|JF!ld#X{wViFL;*a zz9y*h^?U{TBJhT&>6*TCb+U2=juU)>^;GrZQx~ScGC}mt$<5)cMWtpCCBZi{ zgnBc&xS^wbV_#tSrNt-Q@IAMT!iuYS#ABq!URi2f*E5|{`9GfbKy;kGa$5BSM!8J2 zZcVz4a(=U{;XZ4Zx@(fjzHe7-#(yrJm0NTVsjUW-)Z3ORD`O&lnyw5E_}ja5fRt9l zl`%6_G1#)2vVCFJCN7+j)idT6a<0P}sN2LSrkor801tDQ+eLR0<;cSS( z7$H4JCfz=Ua7Gzvw`BSX982cdTeBQdiY`awM3d(SPsn=~HGg?sO3=6BGmVA7b#tsF zvoASpJrg^vluE}HfdONF^yS)JX5RvMO4dDr&1(9r0sArsIQ4=0F&5F?D`UnGWSVrB z3H48kwdK0^tjK9d2cPfe5XzPH*;J}V^^3OTbz5xcIm(T>GzC)lbY}Ex957P?6a71g zd@5ehR*O=uEmYa!^`33M5V6Yc^OQ#^Sd%*>5kEJoe=5PCQwz^i1j&~fRov=7N3YmP z72aTs{SN?rK!U#-U>5zZrOr7`Fxnp^|VYu4two0sKiwwi8avI zaEVH9!RNGjI6dy=Q?7C(+>ZDF=A`FUdMR_I8fS^#%qfQ+;FPCjgku!({^02x)6(4$ z;`*>Gw?osPPis^bm%fi>+lyQlwSf`kVWSny+jOw(6N+OL?^YclEA7{9<9YXQt+!9* zd~gydvKD;*`)u-FO2_n{G#~k_}Ah;i9ZqlX?)lzXeAw_-lq;$ z?^lP=dYa{G=emN{(l=b2U0YmRU4M6Nqc!zy*E_CVuHCM8U3*;bx%Ro^v;jnAg8_creDMYH{VcGNyUH%gA|@w*e{ zn|syBUOuv)A879BoA&hvu{VWuJ0T zIiehwLfWO1-{O=3nX2@X?MTyJcBHF|%p!xVsx$i2XgwQ?D_2F(t{p9_wBxF&RWEBFA! zSqGVWU>)kb&asDi+yw9`yb{F?p}s2Rr$u5nw}RS;=U?^;^bC)YP-ZZf9U)^Blq1k& zLoNhIi3)0{>_X|oiI11Jqi-d+1E~%|?hknhcweOI0VLJ{AeLyXAWz#8Ulj}{_KU~{gZ@G55>RtbI?RCHG;U`qS&rA^=m%m-j{|it?G>fQ$ zXdV&&QobJg%p_!w{} zQUwu*t>E~l#xq!cD)k3`rbls%v<2Xcm?MrjQH@a=BP>dlWe}Yc-PUn*+7Z?XIPc7~ zz9gjeW$Vjy{OTDuNZ8^A#}$fD+(U8S5*cwL;>L(}am8^Z;@Y?;#gCNf zN~u_^lq+wF-zsk_d&Ec9k=E}KVpLjxNjO$({gYy`uD5Ph+F18lKTtf@qc)3@U~6Z) zLdmjEx7R9H*jL*BqztmJwy#zO+t=COQ0}+?-CLMDla=y9H~mBBg65eQq|_k zHdCdo&9iN0O0~_8+f>NJHa~5%NG7*=txcW0y3OV`+vRO--fnYL-qq%lwm$it_%`uv z@D3%P&Q{)0QA8&(?|7n#Cb4b`(R4FC(+rc!&G>VO=zQm0Kvdlrzo|}3 ziIx);5UoTWTxTPVQLgZ=C0dVo(!0sjZ95C16TWv(6zwNEg#M7;qeLefiJ-^S9VIyq zbu;S6VeOP;-1o6Bcj`s@XnmYML7${g)l2o6`fPo!Ua2qC7wa{8Ey=6s?mE(J(6Id}0`Z2u$np&^b+t%yWk9qyxkiNy6NpUE?H;2;JcsqDIliZDS^Y$P<$=iX- zs`2)sn0+YbVsC%%Aa9{}xOb#?48<&lro=nhJ58VJE%VOuR(R)8{uSOT?;_$$D2HX< z72Y-8I`2mBR__kd*L(MQ4^o_E-Xq@QKH;+yclvbJ_yWFEUprrWUq@dTU!JcgX$pu} zcvtxPQmQK70N-HWP~QkjHOe>EH{LhVH^n!d^nEGj3}3l#j&DAtT|jbQl4tm;eM^1I zeJg!yed~Rjyn~2u^A6&E^X>HQ@$J`ZeTRHU_3geB3DTS6JCqQoZ}-ki(6|**{9u9) zGVz2UG}O9;bkb*2yH4T>xe1+o(-XQTbocJicO~Q}^d{adFS!iIz`3ELBPCG1T&Krs&|97|~McJN#MZM}p1ZtejimEZ5%?++Oo zf2Kdj-@)IRcsG9!e=p*F{Qdod{DqunGd|ouQr}K|3^>ch{u2Fw_nFInCjb;*v?zbW9Ofo z*gmmiVwc1`Uv*;7#Dau%`ohG%G#92~?$jm@NF1CvG%+u61l=8#IF|ZkV8ZCc)Wq?L z6DjSK#Oc0vi8B(*{gb^%^dgqMZK-tue}%7|e|SQJzMbM{Q@L|kPMn{(faL1Lr8Gtd z6PMGN?n!7!6bZSBD-+jJZJeqhSAOmqU z3R4r02DE@L5ac`q=>f7UL-y%`T(U7r8|W118tCp{WXkz0>!pF-`ociJz`($ez_37( zw*%Wl;)IcdA1KW9>e>lrzdn5;DvK*KVc`mgm6sSxX z9atEkRv6sFbh? z(?}igl_zb~*98S(Q9;n|tkv!ZE$@;dQzRYKhnxkWYzWrUvMXtyNAl%A3T(})?XMr>dm3v8^V?xJVEW!foY}5GEs0@ zjGxJIiK$8TWH}p>HCme%`YV!sUU#yV9Ml&krzdCA=xC3n?lCwEWIr(T+y zoSV2!Uzgn58%pk%Jdjqy3CWDcv}z;|(TkFYK~ogyL@`Gvk4v7AJc(jz$y1X{lV>K+ zPM*t1m0X#;FnO_lAi0LdqBu~QT+1s|pdZz|f?};oUYEQfd9J=CP?IQJaK2>XtAp=nVBp*7TX7UX)LDs1Kpm z%us(q3`Rno>lvI98Wbud8>kNr4~-0s2^EJ*LX$(&LS>;@p$hNt(7aGpXi;cMXjy25 zek`;mR2SM9+8Wvsst@f89Sj`_9rvzC5#G8Kdx|qfPYEQHrliumrvBvhn&$P~ly)R9 z;rX7@K6pZ}P3f4@B_&T^m(nv(%l4B};4e(+8(`cRl2VXZkTM`;uuo4JN;5H#G9qPE z%Gi|gq2iQ@p~)#zQl^JyrOZevCwnk4B)MP8oJ7GZLdyKag5U{1>3OwHX`iw{A4j<0 z^DpsRS!TQPFQNRa{UO7ClImDC*2myrf3Jkzfy2Q={tgj2p;K@~QU%*ypfY7CqXEm_ zgCy5cKFi4tQ&U!^to6HD_HImB=@WsODeEKlnN-mvd#x$eDVq|HCU;NSMthslN&WpL zDLYg4r0fq&N;#BrH06YMS#m$UGI40Cq_uZ$YMegWTgPLUs`1#R`gnF2tqAV)ZY6z? zXD;`iIXh^kr>3W7dpi&=`4ZBTw*-nPW>so#YNyn$-ul!|`UKiR)unc)-0}&3suNRF zd+U=@3J4*Ov(2aW10P6nhNKQlElTZ9d^F;ZP8~;lg1N!1*xUXY4%m5 z&ZPWjr_N2S^!8#~B1A=5%u@-OX+PC2b#ZV?gnN(c6H;po?z8(VQfofY1?-cZuy)WeL=Y?;9+smD?qlHB^-)P~@cR7Jwak4Y&7T%Z%As8!BgTqAQBs+2Mp|ZC4%K9FT8FgG`j)hAX*7~Nr_y?* z^$G4z>zvl#H<5TB>d8{?vb0dzAnH%*jij>FaVa|~hxuuRz6GhhlV>KC(JE6<8X7PE zLFQ@0y;Xstw2_R%X(Q7*Qyj7-9$BjAx}+Rm9+f`E*p;P@ODi_(Q<640Z5q{(cBg4& zWC^8deORBgF?C4Vth9=Rfl0>+CEVV^BpP>GCF@dprp-&M(ks&zr7cNYmbM~oP4djN zX~}cb>e4nQ_18zIZB5%jygqH8zAo(`&6m=&Bi^)>GpJ|cUHQd z(w_F-y%P7+zPc`Ht3D}6n+R{)^i*2uCZ)II9e8?sKd*Y@s4bJy1@Gt6J3{UPIWJ)t z%e-Qy_e>b5Pf8oZ`oy6=on+qs*Q6KFIIc<8StdQ?!~#Bpr1$0BzP~W(c=`a^+t;U! z39Hf{j5(P(WoB<{aDE3Sxy_1)K=e{G>y*-X>Pxp;&(`& z=xv*lM>D80xRTovT*`9#6v*w!Vkrl**woz_5+z5KVf@HUW|-=0-Z?G$xdo`&y%nnD_Tv) z%;4ID?HRKn_k%n)VPNu1+SPQmoY6q3YRMW2k&>qIDbl}>5!*LC)0#FdP;2tGneI$~W+*c=Gbgh{ zLQQ7pz=6zenLRRlW%kMJZ=8`c2l@7A7V=3mb2y(OGe>5Q$tu$Ixz#6( zd@}cC9`sgZ9?3kOCAi!yJIdY18m%x8l26K6 z?f8sL9PQ$hJLQb?HRBSeB|BfkD@ay*UO}=tvL>qw&%vzJtUT|cte!@0IDPNSD#+@a zH6Uwn*3h&H^XUYh7-WsmM`w-F7t=ncHfwCw_^gS>vk2qVpEV_Gde)4r@~k;o^NnW? zM!y+P6^!$H)`G0+tfj_?7|#dHCm48M!Ku`5*HvEhEr+x9prm!vq|0|w_r$YWC_)+jDg%bXq z8D}){@0jxM@Ra%^@b~e&^eJ%8(`Dwo95P~>d?a`maFi1M3;5IEcupVghi9rEKrZFy zx|}wAG>j*%HheB&T@Ahg{O90<5q~D0l&^vYW$~MY;RAU0+Xo)`d}9aaY-sqcd*W-r z$MGAFb{~Ic%UsUow#Y|Vw)TPM5oiuVQ;(Q_Xr{Al^C8Z3XkI~_#n9BU#yS!4)4^{- zoHudzO}rtQ$+GeocqZmr@4=Gg2kD<@tQLxNsE<56G2K3p`Pk~-HG`O1& z{okO^M|)=&J%iS@LH&ccoBb)jm!8jh@d54@8Zzu^H{|h%lMQ(X;*>z%jkb*7d~C;2 z;s})94f0N-w#=>Z;9a4)g>zFX5ht0svLEsf3>mfcqLfv(kMM>qYmOk!zYwPZrM!dO z-a#GqLB9(*Hz4MRxND5XEPkh*EUE`Ajo+Ak6D@j$KdmC08P6KT`2=y&Stjf1fw5!F zd>gEkxxAe}(UNhWZs#7xCyGVJ*g>{Jz6CK4LUSeRPzy~rSZO=R9WnYlS+>SQlfy9` zhW%d;%NftIy%MDlK|Z6@-y3rZeO1FbI1LNlH3D!Im-VvQ0o<$Ty1f0A|_F|#?Q zIF34`L-Qtc>S3Jeuthvlr_v4&-?|%Bn&CyHMvuV|>wy|00J9#QCpb z0~m`Njrv2Lj#NEt|0cc&qwt0?6Zx)HBIXMIMAZ5!avOwktV3UYfV3e)Z`1^7{|fyL z(40Wsu0qXUL>sR{8#m$;=Diq;v6!u^(V`{LG$8Fuh&jqYTK>L?2pd>u%sbY|NvKaU zG&7LHc9gF2EUeJAyHdbe2wdK!nrO#M9Am7g4%p!#3@8H~kIoQ^)aNO+( zo{uOaYTH_Pa~y?mE?4|mZ6DV$1Kg}&O&vc->lu7;c*ei6udCC2Vs+>`ui zvb5mtKIrEnew?{#%mm7nu*JfzZZ~%kJy1Gk0rwT5L=W@;^A!d@<1YHg@*DKY924Qg zJlD`~H{z~?zmsBLZ`dSq%Q03)yJ1n#K<mUQ=Z17R=!?eE) z8EdiqO7upaF<;Po2QWGcdc%h~^$P4E6)hcuHcmjf{a{PQ#{4qZO4jJOyAXBANB#?0 zPdg31d$*Cl%|Kd4jNz!~5RTvWQPiy#ZO1;=UW8VUMd_VUAJ~#&MLrKB=X!9v&9KHE zKx`l0qu`p{Vbt@}VxW34&mfG#D)iMx%*X8*qiho=xo*P@J2z$rzBOq9-)QtO@U|1m z9SFPXYm72-UT^Hjpi$AQ*JB4*Z|E^Ae+v06e9P$#=2A8Hw=9P+_m88ES0Uzq4UW=_ zk=xsdA7YIFjw$!S_68u;Z78KbdanoM0`y@4>=3K7<-546VXSu`w{Ih#-o~C8Wqpd8 ze1K9889P|ywi2=meK}^wTUcig85-EhPcc%3xO*M;Y>QFzqsES%-@}zUO6i9B%r^T3 zdw6~~&DP6U9}T?1-DQ{~&!EmP!a~q9)=yw*FT#FCnRnY^pTlp+UJnajh?okj;zh_o z^wj~w+Kv9ix*0O|U8vjb(BBUEZrH=^K-Wp&-M|-shrnlnFG2jjqV3gK*}EgpjktRQ z_$|g-26-6xJ4lre{Ss&%!Ads@?+$%{Z>Rp&V7b4Cd4Wxx_{2O=wi5mXi(4fvQApS1I zKY;i}#z_$RZ{hoxU6866E!_@oF}PvjeAhP5SksL@0sl5~XfW0_@U_Sv$UrN838%su zdIYQOzgV`cgk}cn_HDFosC5t3t=P)nxEyMn@=$Ie>>RUzPJCP+ppeB_DS!r+QuJ^s zdT*F<7pI0<#(9D5&Gs$qpZ&1yZ2lgrbsfI3-VvHd5VIJTxgTkr;Qj6V?)lp`LKx*I z$aySA=O!D!A^s?TGe+Koefu*u%FPmQ1eKQK<3;BSGyVVt8I+7rh! z6DgqSfINpF&kl&Wj9X;MLyNGQ%bywZou3F@u(HV6#)%u_?!>pz`U!qR z)5>qq#eE}=-@y#ZT-jB2legga+Y98K@}9=uXMa!*li!j>@_X_J_zm{QNF;t8Yqr_N}V&6`j5%Yc`-b@U8`AyS?xADGd8}pf24OSt> z2Ao-qCrRe6(<*sbng&F&COZ%q1v+=wnf^(Qvc#0r58qXvk{|Ou`k8zGS zPf<=|oizK8znNDd_&s37@eBTq$!6~hen*TJoy8dOnCK=R7f*?vcwg`iv6!wq#UJSE zE8e8*F0r4ke)c!07r*Jqa$F($JFawGDeiGx?YLSDbX?=;AntW^baWK=Il4Hyh{29- zj&9<9N1h{33~}7%C=d@g?sp6k4>}4Rh2kMRi(5~lYV_w$v4?U$B#w#`id5nhP4Ou~ z{??|Ft8`MjD&3WQ{-zH31Nl2V#&>&^3Cbj8s#2=VRAwu4l}cryvY2!elp3X0S*5H~ zHYi(^?aD5E&uCcGHNm_N^KS*yHKFlpFfM78ZKWIECGsmpGE?R#6J!UHI+MlqkiBFd z*`Gp#WT6}`NAj~o`62INY|F@o%dCrNj^y(5PwT%}w*C?N$C%sh=O?Jv29}ix%q@L! z_kW^E3 zq(h#<+&am^-^9KdsdAayK1BYTm|LNdk1(hCkSe6&R0tJ?BkuXQvbY!GuZ!;#e|`MF zXl`8j<-SX6vxqR>nSBuN%symaX@Y}NQwt2FxPxiz+ zu-ots>_6}h>|1yTb~oOE{ea(rwFLPcSW6DS18cd8-+{Gs8 zIz`tlnogBAmbk6_4aKeKaKrb(gIacnbE}QBE)TpP^50$XPl1P zvWUuz^i8Df=rQCxB5hovE^F40lTDxQN8&f8<9jRAHI026$(#K;vkok8RJX$4q1HF{ zd&G~F&0!wTh##pt_ZQcT+ptePcvAXE+amrE^|&T9yXMsNX7!9}%Sm-DiRp)kABw6Q zw!FF zM{BQj)VgSST2HM&>#GeoWxurK*PZ75y3@?>bjqnR`!~|hp_uXdEWfTPtPM8XeJbDV zm)O46h8q3!d4A)#m$cwVw`lG0C;vwF~{swAXdO zb=Y+*dYy7LxUKHCZnxX-4mHawvd$8@Gu=7v4(`s7ySaN{&5e*5-`&gI2Y!F|Aa|jA zxO=2~4BCGRau>Txm?C!Pp6s3mzsx-=dM$NVxaYa6+>4^u9`_PA)*|-`cM1BD$2WRy z?`+tCdyTt}+lw}CbZ>RbcWnK#y$c@(q$MPn)EeU#t0 z?#EzKGyhceogCAjG37O`m9gt;tiLD<@1p(4m{^UPmEcGl0t@NyAYTSoM@{8n6-h-NeRYi98~5p+-cKJ0J;h-^k_U7-`Vhn!rWbKpd{(vniFgTr zA3A)0xSr&P_*AR>((WS7Jz=^V?!#{f*#_dt8p7@3L%t7xE)4+i$|t-4M$X zvI5zPZyQSi`BBI>A^t+dzlUYV^N`oFtRR1Z{3YTjh+`WV$G=+fI&=F?%;S)=6*)Wb zd8MVyD4p+G-(?>8t}{wEKB@nKQ4_u^??L|Uk!lg-fh=2)N|}UmcO%sy=uuAv^|a!> z2ssjQ{sMWA(H7Kj2kJ8#ca7)gKSQgL%3`FtANp6J-+@$bg4+;BLhpebhxk1Ze;)J` zp#K_bG7kD~kQ*RBiJIUOaLZK4c$dR618EOKejIt?nY_IXG*;w*yApRT@o4Wei1`Wh zpCX42h@Xf!zeb!lA^#KdVV2u2#CT!s+F(qr7}L1nkUK$s67nrbI|peuptfbm|8W8NFCotDkVir8g4W%Q)?Eb|c4A3G z9Q>w>ydE;FR2o)_&pMU1knx6z@-X6*B2F*JLm_vBoCDbhc>wyyu%dKmz6<#V^ccoe z`7z|1A^#L(@q5(jEyze~fd$6FHmo-E*l&@~KalqONc(%}S3w-c1{(8If{zL%zd<;zpaXKQ-Y@{-tQx6jSdkIS1eL{-(X3ydt7ZXHh@k8;X=pw4= zx=H+vu5RKDu}R!4w$Sx8=g&ZVR1|}C|0Gd;uc#JzY^=}c?QAuIoO<175z6_)nQtwGyp z!S9NUW|T8E%ojuRbC#79#CJmfG;`adkozD`SMZtO1CiTG$Ro{smf~6TQhwJC@=Wln zkmq;tH1#Ev(g4j%_*IfHbBh!5Zj`thF())VeYH&CyYk!C>q&Ot8M4>*py2l>gZ$|~ za<~b61bBfVBkg?rBHIT1hKFGTgNrL?B(`3_W8sY z*sJYJNxz(=mG-sv^+cQO+w42-d+hs3cgTL!e!?LgaSqMla|CHG!93fMYd`AfC|8LbBD9oh$HZw?Qh23fJLm4$<=AUq z@90h?=7P91gAOXcK5pvA4>Z<=-0UJXXcOW;A9~c@K;mf2@Q4S1@CNnNDA~2E4ngxM^XnZXQObg7U7QPJqSSmAgyxWsW zN^oE8z`VeMz~aC%nTsNr69|l;Z?BLhusX0dupzM7F7!2s8su$fU0@rz8(&^7M9m^! zGZ^Iiz)muI0{a4MrS1gEf+q4|#7jfJIn?yCd#MhqO zs(iXW*vj5S`YX*=rFZrY|BhhWV25C5%G(nNo9*u&>?TXwV21xdFe8{1>=W!49N=py z%R`cHw!JE_fxa}D%I5Vl?1w)y(&vJbHaKDU?DYAva0gU$oK4|{YKsTLS!8x6xOq(8~981JaCL#n=@ zZQ)OCB_aG-4>#LYdZ91U9leve2;Ev01JpvKG%8z4-&!FleRnBZW=j#1l8%tnSfgSC zsesWVL*TogLc(1LR}sRs3zGB%f~R(>ih1;eR!C}ghCDNso?vF{ScS+qq&Syy&cItC z$QgpqgC*iexSTzRf9Q$55OF?E#*FAMsc$RrETlUFj+U#vS7{FXT#0zzAgMh~X`?zf z19r4ZjiGSwV0Y9V*e`XIk_WhI-L6oYse5}fkfxbP9f`C>igd@f7ONP5v_*)eAxNnt z*#825mc!3lkYtt0JFp{+Mge@AfOhi=oIH>Ung=`!U+jxC&4ZsE%G=GxcKB1MTG*iN zb-weVAdXbB<)50S%mid?DX0#-4NgwN~H^6YaxVI2|L z&DWa&-Iif=5KEh-8}ql2MeN-BO-px0X%QNt; z0>p4C?3s{!KT=^MkQqQGBP?5ibVKS72ki%%2HF`<7r^Cg>IcfRQwAWGqz_0P>uuzt z5zw@=A&DwQQT|YmD1`~?krQQ{>MvOa{r@%Rhw7csX2wI?F!zUt_81q1wuN@W?9oQr z_mL@6_pV7Mpl~;dOp10_rrnlRcu(8iIvUeB-c3?|MeSycy`DA!%~N8YMNC8e+${GC zG6u>`TzIy{$hs$ie~Dy@l`YmJRnH)-P1HBt=H+3J%2lSG%lL_tw}PqoeT1PbCcgK? zq>qk2ycf{l43vjCit99l3_6VRijBu;d?v-Xk8t^{RZJSkJd38G)Md|9(ER9?<+B(p`^x0BgLW-pojA(ZPLQKv$+Qc_)l*(aGF`}Yui#g`a^v+R(@WcPRN6#M z#Gn3}=aCsgX1EIf;fyy*nTXzbV>O=;imOY#$z-O6;>u}nhUT+%Jk|=u)$I{I@CsFU z5ym1ii}ZU-?&k=C`n?@=R6Y)ODi2?{YfQPT z-GzHp&=Vcs;mlB+&PL-XsXVOVZ1r6By44IHNy+{y?5|=*4fc4K)Otfw^HWLfOC%Mb zCZ3uDfzOfD_pqcK?gbDBZhU9J<(I&(2c0Xaq5S^@cD!r859Cewxe@luU|0A}uv?(X zK-$7S6z}GPmf?#b(7JfK2QF`b-48cFj3DqIfj0s2FVN2<4M2WB!s7G+eE?6V!sqdL z>wNf@iKiX#bU6H+1$-UoXdqvJxJybyPe&ho^VLz7$`q1A8Y>$ZTwZZ!JMz1&%nk z5dUH~?1&{_D%?B`f35;v1RsD~&0(Jodj{w>AkYx2siZ8#h7sM#cQL_gRX!KMY3Fof zrjy}huv49(&M=lj>GL2v-T9;QM^?xAv-1!;11AF1#fbnH1kVee&n^r$4K`)XgFAye z*~Ovdq1Rc9&>NvQSW7qAO<|X~sctH}>}UU8TgLb(GGm!M9fR@7WTujtL1s3YLVaIE zW)V}TYRda!ZB}VF>V(a5vnj?+K=3TkJ|G15I&rb($9yG8OtZ|$#hKxm0a0o z=(`+pHAKHVo8B#?Ybq~_xfUIM=eL^J^9_5u#qGwXc7dzBCtFp!u^ny)wz4h0$t3w! zUn?oOoFi1WMa^u)?kM_n7n}#J&wH_7234oK%ormTkN|) zhk;%J`XF+voPV;I%abNOoY}#g?#>NVy2vv-ES%X9z?mJcGuXM0r8*;>k(6&nIio4x zjCKCP>INGJf6eLzcLcv=4MN4CV%E?-%{`5s=brAK&Keyzf6tdg`eZ^COf79vHBTo~ zpG>0|)09jLGOe{q*QTB39b^2GZo4pfwv93&?RUh;XFY$?oR1kd@z;_{NY!|viyyrD z&~O&nlaS$*c7`)tBKr{H^d!AAq10PT%>Tbeuxpt5Bbv?nvNZe!J&Vm{ z&$6@GBD&6H#cVBW$TrjU8@7e6mTW6sm$1+2YQ?^w>r(b5U9DLuUB6}f*bl4?`;o4; z>>yp2bHN2`C$}_XS8$tJEA6?%{p@!<$b;-k?sAuP^q>)7UlqbbdPP!hgko#eUDv;AgO|{7il(yOy8D&tl#9+5BvF9Y2Sk!@Bcx`MKP zUt<0E%lu__Cx3;%!us=9`K#+Ej+27iMM;BWFb***L%{uayQZ}Yd= zK>iMYhvoBk`MYcoe~-V%2J>}%9lMvWr{2&IzJYIG_wkSTM{Fqnn19Uvz(3)iuwndD z{wcfPz0$ps4R;^%{Op0~`Rtf+LgsQgBiQaN|AKofJUOF5x~Rj-Pm*mH^NidkPpagH zY$@~LQx*J(bn$gcW^PY3OPE&%MtDf7qShXrVV3PCJaryn~n*kjdycZLV4re zbV?|3x^{=Y1-m+d%!1xmKB;hZP9SqdH`gSPxuTmc31qJ5=JyF?7UV)nt=x1?7|$t4 z4MC<3TwR+mrt89`+*c?CuDZqh<$aLQ)pZqItxxExdj(e;61uv+g7oyt3uE4#ZbVaiu_myXT-B&zIa{~2mQep zgNuSM1s4Zj4lW745?l(O8n7^#2COk_MlG5)RDX4%aHscfQsSuWH4f9}cgg0k@# zHP|7?i4N62Bukg?Fvl>&uyd}OjVRslnQ%E76mwTu5!UiJKtj}(GU*EwWbaHoEFPo& z?Bn8b<_|6lE@y$@zTiIQ(lei!E?$;rVT+Y4UA!$mXXo1Y+V?Wd3u9MMn3l5k;a%Zx zsCMyiZnuar@}5^P5;tOu#JW=ddAyh;rqI`BiMbSG3&j$#T&xsp#5%E2Y!TbVF5-K| zeo`3Q2pP4ER3qJ}Z!|KR8ZC_05gvWs&gf`#F}fQ)jb28M(cj23h8V+*Q4xQPvBm^r zvN6?|VazrPjUr=_vD7FwRv9J6dSjEZ)!1R|HcE{HlAF{=mG7ILS=&rA>zWPB#%43K zrP;=8Z+0@fnmxoUGtpyTr=P7YYsI>n4`^c=0vl=oMz56=TziT`667)7vWL& z5&sUus~d0TJad7$*j#3=FjrG})<)thf-5=94He@n8czx0CoW#986T1KiO3uKJ@~WP z+-B}H_e8_L&n&Y{D_|vADOMe;p4HH5Vl}r~S#8a1tAo`!l1^4PE5pjN`b2Q6pEbZ5 zYz?zUT4Sv7)}+J6iz%XWa?4(da$$%h^DfB98Fz5vB6do{0|{U7LMk{-g$dNn_q ze+&9+JjE<~HB*)U6$obKGt8Z5=iuGfLDS*J4}3Hz<_I5p6h2^{JO2|X-eMDBKLz#) zpcdRGt8xPfW;8R*r9FhT0&4a#2f`5ELu=tbzQz9zdIg@&!&CTN_BTlnekADu6%Ux5 zO|1^;<_A#B_ve`3&F=w)By2eB%RmuV>|;>OVP}89yMKoLEzp*r*8sl>Uw;x`{|9{N zi>IG~A~p_T9=gcJQ~1oE0fPDR0&&G3f*rHPxstyW2ZZbzl*CpVZK=JJX%b( zcrkV#on5~FsC>rL$hExI(UR6Nol^9)eDwV%AXzH6aJRfkMlD{_l>&N zsIRHi0!zo$tw#N=Pd+r#;{pT8E_I$t739?5VPmYWb|3p((obXJpew~ek2rTnFKevd zRZCEE93?2Jq*Jlqe_KCoK)f;aCR3`6(_>9H*&=U3S9VmAc*yuO4JFkHZ&^ zhvt+VSIsFou9{PFoHeK9IBQPHao3!Z1oi*1`uujn`oE@ptyurpl)o|tdg_urKk8>d zJQZ!dom49saxhdH#X^!H^*~rY7i^%0Gq>{ag}9QemP_g_A*M*&b;|Es_*1aaC=+ z>iVf#AAO^(kNg^M6I54{Nc*H;w0-i+$s+So-3ob0<+UTr5j|=kM;zIABYK@t1A2Yr zA#O-vu2(76B6a+cg&`|im*&?{8>714kJN^}qP5}AEx}L4WyvobmnFY=T$UVBTuzAA z;wMktG%?yjI2mM)r1K=SAx{>mW$o8Drtker*M9wCdgs5KERCtP-i)sPWODQ<>Mtja z%)dQqB>x^wO`1_7x$wxo9LY;PYa}ln`L}!NeqdS+me)^LTLRTr%tl`^Gpc<*uMFwT zM{m}ryjUN*c&7g%Qb-NViWyV*W!gc#VnzjiZV4je1`%!eC1f~0sZjEZr$WgIkP6k4 zL5*-sNsl5ag@{JWKWyp8<4-QO4f4uH>twBJ(tYW&>` zejogvbw=Cb8g`o8Ll}l>UeVZ^o0=PBM9lNp_pA!nn)@wg*;dG^MJCnUXr){AtwvT;GA*puRy(Vs zxyI^3Z*8}_TRp8_+GUQ_-^#OwkZm}bQPx;%LWTDxTT`tWWM9>Oi^wdcyJBmV zRbs8THqo0~tsUg&Zt`=t_H(jTN`97F2W(+G@qXH#UE3DCM~v+d1Rp}oyoWbY)iha^k0_gP)+ zGOLTv^aXrLR()TJuMU}dBxhcgcNOC$=FZnJ5-+|czUJ|Fc4J>FUt2OA>^8p6QWjq~ zUxqJB%Hr!ICG+*O_xJ|*2IJYV#LsF*LwqBBV|?R%W9-qsNxmt*>AqRMxn$=17W$UN z>qNZEBhZOBEvPcxt4iq_Nn77?-%8&a-#Xt$-xjN#Z@X`oZ!eks4zuezwiB`rI3cH& zlWO&H(w+KNEvLS(A8BlVYn9W;X=-h9S|CJmTHv&H8j;IJBrwA(sAk=$IZ>D!qxPXxyM*!pD0UcS*cp^#){vfWGX)fTi|TnY zYAUmRYR*aehfIS-3d>FlhrrP^c&1u2@e++V}nMG=Tf|~Wj!$2^TLG48UxuG*#ty!sW{BzCPu15ifgAX&_ps~=s^*e4#8b?sFjj&pNjd?? ztPFwq+-et3wMQmHS{Q1c4|ba5YL`&V0MR?Seh$1fsM^C7ZuDN5YWG&`uF4>f-p>_t zKlGmPND;M@rP`;Ht9eao_K2EW0=u~r6nj9j>9DuMTWYRX3($_BY6s1i;4@|`9ZDmg zWK0$zCdsbmu&F(61!lEz%ssP{=Vo}YYy`s)jAN_ zqeOa=85C_n9@z{lgW7ik{DXAcv@KJ!I2apz#6Ah>llEsY1f8Rj{fUIm|E@7 z=@D5t^>Y^wr9~cG98g zR>S@tE;Q?pOK8>~r_iXiHMLQjM8b0~tEs=#k<^#}NM&sxqJK&6{fWP%$Nr{_eHpHH zx?CG_#5s}s`!coODHFZxu`xacNdk&>@g((iUBtbIxDO-llPK=*Wyy&9ril9sA#1bn zSK+VNMM#I{M=6h50h5JOlE$4763O`uGN#9z5YnjhN;%=uEA<3QFSRuHoUK&s zqBJq;W6h<((aI(Nq~uT@NF&PGq!UOo8~ZKP!6nmW@(CoHfOg1ImFt$_(4+G2=lF*# zSFxs}{+m-aHmq{B-MIhiv~5gRI>{#YOkItUk@5e<;g#i* zY`MzaUYh9nfJ3Vs13J?7ZFS1YMyx4oLvH0BCoT0j+2N&7@qfIeks2=dDJ>v-`Mku# zNptiwL5@c}HjTI~hY^Q9as*>VXy*cb-K^8}a=~kfyb~N9t?(Em&@#PX$ z{r+MT-5P7C=bR3$k#GEC4 zNto}d8_RNhP5#F%z*tBYo5*Tv#OZjKa*bkS7ypy|XOUcuPs+dRQ<&PTYtl&~yTH5v zIUCNvzBQ45$3Mraw*Td_pI`Fw(R8J);v~}5lRKZO*(7p)?6J%yk?*|Cj%-edY>(B% zoRI2&J2JClH2WoHb{t6@rAH;@C$OBcvn*trdgKWlqvdk`5_2VvBu>j`Jd9<(#Egd{ ziPgxT{0Z!roVRc!vD+|4W_}V#96yIZ*5~6+f>@4~_?Mgsa3t{@`#*mY`z8P9S66De zlCCjoQrX_{^uFEM@jG|>^Mi8l?jt_6Lay383ez?2tlgfxfAmycd6sS-PR*Tx``NsZ zup+*QF9qJ87xPtwl<@U@6W_{r@ZG$WAK;6G5RULfZILGGiUy*wXeL^UHln@gB)WRKJ-k3#KHwv8g zpjOkWRk;FdIt5ma8sEc?HL~gi1HD2ND~>mkIWUem8u`9miU^~1Z+L$!|l5LN)I+)c48&!Osw z9+8a4M@VyIiJn4sr5le#bV)q!Pk1&1#k5>q-XDf*lY$i%)iM299vi}jQ(IHT#srGj zA&B)nvd^aHg)lNEd!eVx%EMcRHP&S)F%F_cD#LyT2N6GI$VUf}L(35MgE*JtAo6$_ z%7KGeBX$sRST>g>I`40Iv=*-FbPLX!ve**R4<)*kZ!sys8} zu+L=J`yAHr1Xw6~9+onZQ?cX@wYl`96W!+%J``pI`j1GdvbE*uqEi8@-Vb8mg|emP zDW$Zu3?+OS^s@}5<-rXxDc+66o^Obq2*^BuxOw;|;zLjgqRv)J!HgEpdPUzqTxrLt zy>;X(xYc(OOZiAOrL6e&2)sS@$KnM2pV>U=HifD%0$RZ_G<4=o2>1d0>G4x;r~hJ9tq2E^1Xs;+4oQ@+)W zsb6}c^pSr5k=5MVK6RGTGc0m)YbM57vyba{b7bFV6O!6H|iD062i}9ufc=i$V<=+y}M3;WbAY3bLrB$l&HhhxTL%jEJ^0kL!Td7 zEe(AA-n{{DS^IlY4HtWYWr+C>{BW>+Wpw{~)+YfvCK0-?xSA-*S@zX&K`3lL4y-K0 zk6$K|?8he)p+9_BO|{6QO&DRufJ5rG1kU%GoFpS~|U&D8=7_(FxLf zQNsA^dV*@fFN?^Sc{@=Y9QfTa>6`2)%k!^>AEur?vNj|2rbQB!3FSuK^9n|2-j#3X zyZBzdUoc^dkf*)3^AK%p(qlI#8Oc#R*4d^UThLu#SXDsl!^m}FdV}Zjf~nxno-wiU^F(G87+-A zbhR|v8=Z`|wZ;Zxv$4(CY3wofsn|2h zOw$Y~#7r_%%sOU0v!U4}LE7Pqk(xz~y9u28$<>}_XjSObGu8Q$7(3%Quao~uQawh7 zaVw6IEPa}!+FuTRF!mKFPQBzfwNve)#?`pkR#3GY8wZZv`53;a&NJ0#v*J`%eLki- zr4;9@>hZM)Bs~N?_N-F18ymkEzTq5CeJZHhu?@1RkvM@6akanP<*;9hw-8>ni=a>^ z!$R8FlSwO|BC2*ZG_XIOz}cf5YPxF)^Xq*WkBqyscI~S zs~zfY0HScUzamBh1x`2>YG*~Y&zl-!#m;g9XMmcZ23nQ^BSC7^#y~2Fr(j2{3XBKw zO?V5tYZy2`)VKgt?LBxUT&hvgklqamJyeV#9_d;?#^%CQJV&!6<{ZtXWG_Ge5~pbL zG+tMpkV%xT$T^z8aK)UX*^Hi)5LJGaNPpl<)DQYjA=^YqOS*5v+w)GmD}AX4@5(bt zgOx9hBl$<|IcSV8*J(AnY^bw!)j086O|=uBN^cXRbjGLUX=%>WX;w3*o}SoOWK6GqjfVMuC%sBq zGbg=9Ql&|B4;eWsF+)5pW{H1_XT?164%MpfiTA~Z@GgX{F1=9~C+W-c^qY}gjvuxp zTl;9(G4{u~2i{xKAUW|W#(tX5e|L_k{{=XwX;7WJw^0{5J@H<$L4??~+WB|Af(ai1-UTy)VNMD+}Gn=&#&AHIK=8 zj`^?$U@wL}6ZU&ycVS-vdlu|{VE15u5ccz7e*^ZLVP6P)7ubhL`=RqdUzP~32YeXZ z)PlVT_D-gmVvU2+d(c4 z$TEx->iU{4)ajd0o;m7@DFdk{mQ?$-1OC95s2`1~6l{t5xi;!(kMi6m&>d7)x0H1? z&t`G|oAuf5_;;oMyrNa9cav6sw$v&4YFB5qdvnY#&1yGh^~YN8ij2`Wz5lb?aa#Rp zR;TJ?CtC_l?=hSN$_qt!UM`Ocb$FCFFk^py?D=ol-iSZn(G)<~`SKaHu5#!QdoWAbNul^Qc05>BsJn_>sP zW3Ekw+DrZIa*g5G(_E zHuOGvHl+E2G`|Pwe&0y@Ga5Uufa0GiN6XPr{TcK()DG)h^+C}`i`pq%?Tr2b?D(%?V3v-dcB5DGThMzEL-DTayQ{wJhoI=m80i0)_rnf(jDG<^ zyVAg)lwTm_92Mu(4nLNZlfFd#NRV=A^rap|%X_8Klru1@V4R7V8U*{Bpcr}JKLW?N zfq~Hs)z?&`F=`yZxUW3rgc@%_Pv5|tCpFJWryp{R0Y43BjPW>dHD5~2&BFMDp>~+> z6_ZZrgP8a?W}OTB<-cs2MN_PqyrOB=EWt>E?17a~x>ZWE_>lxc+SB_guVvDgkYdr? zRz8w2wOotEdogJSEmkwvbX+frNwcLfak@Sx&Bn*%r~Ha(rt+5g=kk;@(_t?yPbZ;9 zHZW&RkNcocXyVKd^E=RLTRSRiqh_HcR~Y5n3VSc0D06Wh{NEE>b^R`%<1$QFrRGOf}O_ zoqD0>K%y09poHY=yalvN^k@-su$srHPZ3e)lc@7XFtbsON$L5D7$GuohJ%_nXrOe} zZIO#WQ5ULFLj!FWHMV6!hYU3qh`-oo{g|8@X_=~-4ppUle9N@*70nNNW~Q1InN_3T zYOHzPXibNinK=CbO}UpTV-BXwhEjhM=%>3ZU-{F7s; z#j&}H+TCe#Y%7|tHlby{L$||a`B`3?wwE;|Zyz`2MZU!N5h+2l$>na|m*?_)K9rB( zqxm>Kkr(i3d?ue0%~zP?B2=3rJ0{-MSwgCfg4Va1J*?&ptCM|%()GWTr<2M{DrXw_ z7q3pzQRCjaq*OUsjlZgYBC3s|N>Ka}dTA9k@N2xAdssMKpa;t~0iY1-j3}PP z&ZjcuV(NGNj@`(zL)`eZi zdb7SPkKN0Lu?N}cs5^rtQJdjbqM~#6j&)h{?%l4IC(tTC1WTrPYCz>+C-!^Ro%LaN zuz_p{yPu6@e})@5@1zzxgPqGRWtX$7Nn5UGx3PXKpWVlXvp>o?Rd8jpQ&>8+4qBsK zcP+IMa@d`05F5%KV58VWY;5ml1A7~7Ks$nV1I+}@>3wVed}9FUV9;TpBSFXX?tRw) zV?5{-&{?4KL6?B81YIksX@Yv7seSt2al2U$v=L}C&{m-BKs)uxz56b+D`*eUOwer5 zzBzZ~-fHH8=7SCe9RWHzC-2tY<~Y#FpwmI;fEL}6dq=*x1avv*O3*c+>+TqMcYkvu z=oZlJpu0f#l4!S@`z5s;&=k=6pw0T{4!X-~3)%s+GiW!^jQ)4`?r&v*_5tk&IskMq z=&-wP>vM-S5_Amcc+g3pQ^=b*8^<`+61&YXe-dR14%3F4xpVuyMbnaW(~Zn_W-*O zXfEgw(2=0y1`cd`p*MWBm7mx309t|HpZE&*K+x(ReE=nkS6*}FkY zK@Ujk6QE8$h27_Yrhuk{HUMohDEE%uz80XZLEC|L1eGIB29-69*#$>n}uAhY!#(Y`FA0eV;4~wc`=oBzoAm=5-LqDrE=i6R4!gd<=f>{B3wb`=kMa) zOk@*O;-*xC%aJch>r_cYRZxS<#5DG+Bd~Fl%ZI1IDyT)JY%MAuYeV{@z2ofMDk(-M znVQR>PD)g3V^sW}1?pBwe^mvQ>v`)}gL8IHmGrbKX;PIGBNZ&Y3TjXdbRKJT1U7x@ z-C=2Zm9%b^^vo)#pcX)bYVfMQaT8m}R!|##JKIOC>F&G_wV6jzOL-w*!PoQce4lVc zs%R)$ijE>ftP{J9fRSc2GFlm(jGjh6W2iCKm}1N^78xsz4aN>*zZo#o%tmG_vy<7= z>}L)&$C?YR&DL(4*-3U?yQ$sQ?rQh42iPO*3HEe*o^O_Kfv?z^(RZROl`{d^{MP@PGwJf<##Rpjap4L@1yw?%~vRXiqO1GjNkOF zQ}W?=`Tfue&xhb%P^nl;`!G!N8I_)_)O=68pS5dMxKEA0KW%*c{pma7@9T7mxu^K3 z(?33b&X^nj{EQV9o^OqRp57eKL)h!036<$>sQuc7+H+adqRYjaAqqwM2*uA#)4Y}D zyA`k7So6(_pQYWMRi=2ozKWlnt@#$k>#wO8Z|7*A&*=;~W1n=@yh19SGcjIc&Y2f; zFWt|r@O(vu`;9+wzdQcEL8}V)+vD%g%c*dm{WISe$KN-q6Mx@0y~6#-3ioT`HKxhx z3is=9Z&FQ|qIXE4SZ=aG@n6@`T&LErbK&|7Y8iB--b4oVefm=GX9)Ff#;^&jfK8_! z-#jYWmQvZahDx{1RKD$|5{^+Bm&8+fUF}b2&GmPh_EY>qotH11s`*~Un@!Suzv35Z z&AVuV;>~T%n`k~w^HRkx&eVLY<_i^Xk)iog#edU6^SPSq@3qw7Z#hfxOImBbR`FJO zieIX=`_g&wsnEJ(e5|)_U*W!Mh5P&p_tRqT$^SN8;-9yfTH$_f{QWhB@%LSN#NYqE zLb>w$UGZh*?@Mu?nxI4(PW{#KY%-h1X0bxHfGuIgY&BcQHnDANmy-7P%N6gMu6d#2 z*S6JM$6_~~irsQGU$6Lex<ZR{gv_ecebu@zbt0epV~dV1AOYtuHn!5T9KPtX1@HRK<&q& zaz3j0C=*UQryDb!3@3w~>I`*;u@vV4=RtP5^GD~8td8?%=OK26Gr^h4>N;OLd)NiR z^MdEI3xiFAO`!RjJM+LcqiVC_vG2UA0NPn@DY3rpMX*2S-g-h;7c$AZY|%)xAL8Q zFTJ^x+R$sL6}=fN2ugXGu!Sd5M7n4onqZAYd(l~R7n!1u=qK{TP%%=B6%$z=1jzeykoyGE$AYMnj`1y?MYejgV2>sAJTp zR(dmPr?;b)dN(7(=wN7J@(P zdl7t|ZxQil$o3NWGrq;(g}#@;pY<&PpXYmp3F1rXu8>^63jU058F-=ZHSlMB%faXQ zUMJUuzGAw2mR!F9{)}%0c%ko2@MnE1!RPtjBG=FQR?*!&a{V^=GrrZ}g}!&dpY^Q) zpXYm*T+j2BK>oSD_jLHy>hQgu`O7aBb1y`c#K&s}9#^I$YayxIRa?w(D?xp~JO9hwDonuAMquUm;w(bhy6O z;o7ak^^FeK9v!Z45w5*DT;J)`E7jrqUWad=4&M(*z5P0rKk85((4jl1LszE5bx4KF zVJch>SK)Gm3YTNZa5<(5mt(1LIkpOy<5S^s92G9dFT>>oRJfd=3YQa7;c{FRF2_^h za>6oPPLc|jldQt!)KcMcPEp}Cn~Fp*vfLuD%Xk10Ak&b+{VpaGj^a)kufye1xm9 z4%Y=bTupSieyzjRREO(AgsYhj*F`#9&2_jg*5PWQ!}S}4tECRtB|2QKbhs|nsn=SE z@3%<3HadKl>F~AH;k#UgkIDX_+y$W_Ye#m2HxX&#Y^otTP>a4N)#bU=o*&7^k*iTu zDi^RBY%aB5ma>&>Ew$>lvpw`=3){&`sbUH6+B}^%q;k47@4&l;-lKZr3g=pLVrZ?l zJsNr+wr+&2)3!%LACT>LaJOFD9u0j6n{>B9+a3-5C+gqEsDB?t{o54v@8hU{o1^}H z67_FO)W0vucBOL#VLP?$(a=}0{f@9*+V*JZ)981%M!)-6^t;=l-~BxL-R;ruei8ld zj_7y4j(&G{^t<0gzq=>$UD@ghEk%tjTWfWwwI%neXo){F9jTVipw^aLw=Pf0_(skq zur9GKrL+^2dU9?}XUvlC#^iqEJ()b4Tdp(jMRjasE&NdUZBYw#7^U(U>`gufdyb7a zYGGyajZ9dV7+1o6leD{8L|YkG0m;DAPO$gH)0?AD_riy7+#3kF6mGtQKYQFvxXh4l zr2pimr+g~?S5L)0>5nLt-xA+SAH?@q_uUY!6^6FTl~`~2gPfCL1dI?1*rV+~Ggr24 z?9R!PuoFTv?1WIens1b^>XbW!$kT@8*hk7yyj@*Mt>9C^8Nr#}`fx|c+p?PS#=aLX zbt|0FQyr-f=ZA?Ca#~|%XzEe=B4nvz|Jfcb4#`r*P;ZewyJ&lgo#HFyCP^gmBm-{D z;H;#|ao6#%U*^HTGj#%5^O!h0ocq`nyWIOQW}l46n^ztFOG!CL=>B#UI^zrb3`6E) z!#>llYoEmgU(P-@b{J<;JMny@3AGGc7$c2Q#-EHa##m|({?(XdJZ3yWt-=}9F8rtQ zFXI{GS>xZv^TvzD%f_q5>&8lBweha8&iK&y$oRzgjQrYZd`0cUJyyf;A?vr+W!B}^ z6;^wzgLReF$?9TtvwB!Ptt>0sy4||dy4xCP-D~~98g7lSMp~n+(bgDitToOWZ%wc! zT9d5FR)ICenrcn6rdugSMU@fv>=5^&jhF>r-pH zwbR;d?X~tZ33Uy14`qZhL%l+MLjAqX-d1nBx6|9@?eX?{rQUw8EG)ui*bY14K-de{ z3a5k{h8u^QhMR|5hFgdK5&l>B+3<7W7s4-vUkSe!ek1%=`0emJNp~dWCJji+Pa2Xm zG--U&#N?dhe#yDXdCB?7Lz0Ij%hA%0skMKmaW19c1;&NO#m0liA1MX@Y&>K@g=3;*Ty$iL#wgX+G=C9wb~&CJ61@+9IKy|Yvoyk zt)WMlf(znO@Ez-2>pklOor0fRUs_*V-&)@%NWs(XGY*r2&Ftosg01W}c3Zn0Qm~Jm z7yNhdx#05^QZPMKFPef)L(M}ik%H|*9YdWfq~OQir{3q@m)=+2H{Q42cis=)!7vXS zVJqwl`@?QHIecpP-0=C~UxzOW|0aBCcvg5$xG+3Fydb^i_ z8&4YlXZ+pxhw+^8g7K2^3esv7^}yCrAM8KW3;WdgobuXE>pbII>pbgx<1bcctE<)B z%CIu6UREEguhrigVC7pwtYOv+YnC;~DzxTP+`nj@Z!NKwS;f{$YqhbK_&RHY^^x_7 z^_jK9+GXvrO0E4?nJsMF4%n{oxz*V|)u?Cx%I}9j44EM(6bdDU zYKKxobwYJR^+QcU7lnQkx-@iI=!(#lp{ql`4|NOm2=xqQg|b6Ap!Y#tB!fnF;3_lb8cli16i{Y2UuZCX_znOGrQeM*FqzOrr zlKUq2PacpwIC*ID@MO7z$rI3frS%Vyu9s{2Pic5WzpK*en$g%ZNi(HhMszZfK2}c? zztTEbE!`unlR8(fZ*sM^}L&}wA8Y`to| zZoO%}ZM;YPed|N5ZC_YlS>IUSSwC0@ZEjn(KdNnKk+$6lZ95CvmP6Y1LPBk87HSb{ z6>1Y|7wQn|6zWnz+dlC=^Sda(?C{+1 zyl_!?VR&(PX?S^fMN+?{dy)nv{Wa;)>%myVDkU7%i2&Mp&#`L@~AH`lntlez-Ts> zdIEBnIhXWtvvrWlC{Cr6Mdg&=4uoV;%cKd~Ph5YvkY#O&iZmHLco{-`{w zkYkrHITKLM0hJ@ba&%XY5YK07|IGzt78>6%K`o>2iH@5yMMsD_v76(yjw@UYY&IZ z2S7)FJ_tGz^pBvUK>s9Z=vzs{UxMzGRFAL9eWB!RQo(FiE4YeT)Ha}4G7XjTFp_uCH6$vY*nHWHX~u>hA>KCfm2vj{PWka`cOnBVY8E zsV^yR?7--=N%|po`kbs=*3`;YeOaRx^&cJMO5cvTw9+VrK_u2cKmPf3AF?n?Iqu7Uy8-EA=C+MeI!g>_`dU`Gr!xq;mqacq+uDP z=N-`QDZd-QvUJ@4KBn9__HU~ef*Nv+k3B9A?^>Q*`Iw#@k>(Vmb>ORDFVV%ko?dUMd9wZL<*=_wyT0+3c&~VUyrtf& z-fc1Okl)^waen;tJF;z5+a2xx+53w(&U@G!>pkf`;yvy?;Z5|0-b8Pb z_n4>JB8@2(-y%(ao2_P_uzlR)NxT-H%jfa=d=cNv4+&3PD4H>OPS^$RDECk9Q1=h+ zF!z3Uxch)R!hO&k>Hg81+cEJh{xyI!V(!V>Y z48Du<|BErw?jU&$ZfTk8@_PJnE&20&0e^wyU%}V%t-b*DPCK%v+(GVOcZhqhd!IXq zox>WibKSw1RjX#8H(|e)Ph)3?yZ4pP4)^Z#`g;St`@KJUeZAYgJLtZj*PrzvEYHjL z29ZQ0mv=vVhrLTB_wB6E8|gjh{gK*zkC6L*>{+&m-pZ%92hkh!jB3s;RGxg!zF=Qc zIsXIuksaiYmrK{(-rd~x?xSm{HJ#=v!ird&UL6 zGWlvbqXMbcm2y`%b{(bO^;Cl2K;_1bR6^ZEDS0!M+`ZXtRFC$JOVzunRJn(GWdqqD zDtYc@L)d-PKl=lf{r6KJ>jCy4n@(Sz%buYY=ZjSKzQIs{HVQWbbK4qU#-MEA8 zWZ$#>RCAWGLtKz%n4}v%?&kp>q zWYVH1_>+7p{~Mpi|Bp}SPw~I=r};nlKl#7-GyGZpZ~h!Dhp*u!q<`!92mC|+AHIoi=37V`G1tg#jZy>ik=!ovxqi=ldGFrp z_EYzVN^yUuo3HNWKczVLv*Vv*H_piWf=cgSdzW~vyi2{--fz7&-eq1}?{cr5cZJv9 z`<>UpyVC3EUFCK1uJ$^6*LYpL-+NuXYrSsXbzXPxdas9fgO}l*?=|)=@S1qP_L_PZ zdd<9xyyo7;UJLIxUQ6#r{F&=1{!AZxNIXRONRT$v^8%jhdET$QI$pY0&pX?z@15fX zy^t67lDuTEmUoI*+dI`u@lNwny)<%nhIgh{*E`EQ&uip0@XqxbdeqxxCU3$olDmV7 zQEx`pmD?z8SZcfR{?_c^!7UEn_NzThr&Uvyt` z7rBewCGN}aQuh`2Rd<>DPxtTcEO(|S$p5F^Z#>(b?Y`#z!!2=lyKlHF+*R)DZn688 zyT*Oj-Ry30KXtdd+uR-Qm+n{YF85paJ9oePqi1@S`;oicebZg(zU{7d-*Mk_-*?x# z>)a3A_3nr62KPViCii3a6ZbRsb9cM@g}c-J+AVdzclWtJxCh*W9`}5n=N6J;)Z|1devK&}f!b6o8TxvhRQr>T7QH_Bs& z&tdWTYbE8a)jD5Q$W`tbt?O0k>apenrR$Bwjiixd#2Dy$M|Kuzb#jcBEA0)Cw#ytK z^*vtOPlvwOiPd=dmyMs#FQ5$k4ga3(KZvl*$J}8L9;J>KYTbU3^mrMxcMj?M%h2Ju zr0@SCjsG|4ywv#TN#hrj&Mzfhf2D$cZ`2yD^n2AWpy9HG^&n|@eN}7gwJ_0IyUI0P zvcBnq8s~PZbEqyxEmA0Jo6gT&OrRDZlhb;moh_N96wuI_cOWHIAtIA_-s zpOZGuO^6%f3wom3zU^7$yo2kAo|fpWo5SrTfD@JE%5~*a3;Z8Wi~99b=fuRmn}&Dm zR(MxFCmKDQp=wvzOr4}E=d{at@R@Meoz={q_(y(r++0X?D>L+Y0CIk_981nRq2$WK zsdaMZcTSDUb@ZpmmdmG3H|T|tQ8|0N?+GVi`S}%TS~jJXf?6U^Mg2U3{9MNxi1lI% zYbv&q|CieNc0RidUulc4T#m1_!&f>*{g?VI^>_y3`s9k53w=$>sdAg#X)haRZPc`! zkgC|oQc1# zWNyR^oTiytN#?^zn@4te5?Qa~8LM$}Moyrv9sOcW=%gGw`VRj0Mcxslp*63W(<^GPrp@A#aps$n4wF?ny%|=G6iIAmFwC1FnJb!>Typ4smVirc1`~IzW!4>A>&_; zh1QADqiIJ`%e~0T+X<1A(B=BT`jzzaSbdjg(H~FWv(WA;fDYDlY8;z%krvMJYJ=5; zeDZ8cDVx-|{>Mq1k4;L8biEEvUzBB`EE982NI6ZUbT+%AvNg`95-jRK1`Ih3# z6_1sKq;H{D7^rjhCQ=DB4KpO<%!tKo8C$_tv$bpk+swAHooo-=$I7_L13ZbRaJk;E zA#cK)^H#hq@4!3rZajl$@jh7fH<%COBl#FUo=@Ua_;fyt&lL~jB$M$(NnWB-W+8j> zM5#AVlzQ|;saH>wdiF#glYIa&Sv*ekaY_~0BYHx{f$SHFCn=2>o4Ly@HOnm9@~jjq-D+Spv07MdtPWNe ztA~|kNxeD>=`eF7@evf>am2@(6U@oPCz(^s>BOg*GtD`~XHzT`5ua}^G?x%xY%Vib z5HB`YnI**6P~2=JzQNpVZX>?c++pq}zRTQe?kB#FV$5WQB`nACh=;6NRx0rntBzHV zcwLIe#>5+0O|2Hhn_I1{w#3_5?X6D4J5ua+C*IA`#;yG4-i`uEy0E+Wr z#D`iVtkJ|rS!1mU#K&8ctSQ6`tZCLv;xnw-Rw41Z)_iLr@degmi%LRksa0&PBEHgE zW33~;*4kigCceqqYV9Dt-P&dCCBDbnXO$5@U<=z}hHcv+yB6^zJH@U;Jk73aHy~c$ zZe&w$+ioIfmJ)Aix3Sw3Z)bP3yAbbece68y_pmeVY~sD_9J@d9e)a%+F!6kQs6B%C zaC?+JmiQQZygiBdM7zMAMtrJ0!=6oimOa;=Pkf%ez+Oyzk-gL|CcfNWX|Ex^+FomK zAimz-WN#(D#oli3BEHk!WA7tgY9H{)m7>gN`{XLmfG^1>S7_GurTOHl%5-0SpIjB$ z(AUH#S2Q;Bwe-o=h^>9?d>x5*@OAceBi_~5!~bUhj<@fKi>f2xxRegP~t;; z!+oQOkMxc4jVC_NH_=x>e6nw+7uRL65_%N3FV?#-recx^dg?+^l|zT@9X3``NZ>_A=M z7~-Ryan3~I6P(G;RN_;d>CPSLT8CXHLSDDS>dcEzRD?a))Qan zY;?8|-|TF2b`sy=>~>0t?{)V38Syf|=?^f&@Ay4`ZQ`~3ss420b^P`G4T(4KH}*Fp z-qhd1Px;^9%HP&c`QP8(-^ow;-`~aGooYJ6pFwpR<$tQd`ucNaJ?o4^ZTki2c3I~V zG9JiyAb$n&S0H}{G6Bd0AQON*0^|`Oj{unnWFnA>KpqA1D3C{iOad|q$Rr?-0eK9_ zV?ZVYnG9qykjH^M4&-ql1waab6aaYw$P+-G0P-Y|CxJW(WIB-PK&AtE3dmDHo&quh z$P6GefczcE-+}xc$V?zJfy@N*G?1r(JPl+PkXb-x0r>}ze*pOhkl8?H1DOrvpFsWz zEV`4^CX0htSAE|9rEo&oXaxj=G(+zsSzAa?^90Av7=0YL5nau1MufaC$m1Cj@1AdrDT1_H?kk`E*w2(-ly zZ2{dbdy#|;1~M23^v4hV0o^XoL#KY6Um~E}gD7c(C}}~r2T{@nQPP5L52B{j`dvFPmB|w${c?HNTKwbf|6v$E_OM&bKvKPo+Af-S`fs_K- z2V@@*Nw>>BvNKLn@dfC1d1@CSyMXKh@->jJfqV^QH;~;xb_4ka$TvW~0kQ|k9w2*w zd<*1TAd<@6v*gOG7OWL(!`iV9tP|_Py0IRtC(B~lEQhJ{rXOc4_+9Wj7DT^Jj?&1! zw%of;?rbLaT$D5Fgmp=7Ko4f?S(8P=24r$70*!{AWZ%EMJ$=A zzn=1cq98Mb=n$N{Emxayn9*e9nI>``#5j5~9;3_BOxB~|a{O^BJ(-5pXyq%?42(@t zJAup+)Q|ZJnIMFpsT3Q)#BiJGSXwM_wPm;%%)1ys));%~&Mk0YiL-vT+L zc0I{BW;)iwIF1l6$~SPr05G&7{)U#rG_)4}h8DuKxDgupZ^cC2B;(C4eTqf?vdEc} zJ@LO%{q^s`YU*#g5OXPB)E6e;oXnI`$f5e%Ay#OSC0N~dAz@whWuME zPD>&#bD6NTs`Ml1a|C=oc-mYI1f-DkgK=k zztGs0)g1Nj3!_92V`S(t_|^ouuRYmvbX}LBTlkNW{Et&z;D>Ahdgj;jl%unh(dw>x zwz2$|9Tqdh-}M=;|F63>ghP)Vp%^3bA~ILpr}t;kWqz`E;iJN6Rzqmo3kxpIn|zzeqYW|D)xZ`OB7P z>rXDv)?Xx@IX^j_Ilo9c@BQR--up$;nf@PbpXtAB`)vNnP4%tTL;ueF zEHV}%=1=ZEx#H10Fmsy#5sAmJUZFnLBP4uzRt6EkGYfwFYVd?skNY(^BH;g_Z!0KV zgmz$mwLn&Ut=*sh%bkBGKmK?Jf5NnxX8&K(;{bhI4I^l3jj8`$YW^y(@sUC0FD#+M zFE8O_9+v;|d076-=V8S!pNG>W413NQWRTUD6$r-x^_#!$`16-5TDrnb^1|{te97IJ!30mF6{M@hN{g^nw1?u0`K>t zQ@RIMNL*O!aW1lm>&v5uY04V;n}w&Mw2QAow7&Lu^o#}a1y%>T1)c=f-g89azsHX_ zhhUFrk7|!#k79q>(%rF)8F23kT@Y0e_Z(v%ynw8Nj7WE{Juo$p?lDJdv1#Dt$Bm+A zOLor)>R(gSxR7~aj|*L`C19sN$8ZXh+U`a|mwX??K}UFb8V~@`=r|a^9+>NtD;x2N z6Wb=D^KBmg=+GI@S)6M+43%Pz*x)vt&yki zYP$rM#O$p|J%0a_5c|3(pgDpmcH;C7(e1)gB#FyF&3@4)C0z304qx;SI|eExIO>(2#WvGh;q zov_VPQh`UNo;ju%BE38`;+>1SIYcII0W+TC7_yzu8n7K-*3+IhTJO&wq0cA1+rpda z$%tUzf5=X8?u*kJ5f~Ymf*^LU_MSJQH-bYav~w6??dihEJ9C#s5r+pMe!ToaNfEC5 zeIY%34!5?c2ww^4u4V(UpChU$6}p48M4}5R7lfs)kvwgKsV0Tl@MJkF#61d*>z6?7&c=mIA8)_N1J%(eT zKpV$CNg^&+1Ic8BA$=7{hr8r z5=hG2*9+{X=9QuNE)`G9N}$n!SuXhqU!Via6eRh4s7Sh-fR0iKnkqR+E!1t9jlKl-TFQf@}c<&86%T2;Xjf(#&hNcw^qkw z)NlHaMZ|Tm_vsh#7q}K!TPFe?xt9E%28+$kA&kxxMgiUXddU zuwJj~>~q^pocB1?#kzdAH7xdJMaB(j!(c_`WMh!hC9`Pfp|P-TlS}69ruD-1?<=Z9D`sycEq zZi;H6OMF#W1iN@-`&@cAa>=-T*$|&|^?4&gB85%dc1`fERUkmoL)F>~>&=(EsQiLb zTw%vk>_V2ppu%Tknm@Gi$+_|_cp1swUuw`TO9?p#5TbnN{+`3}82DrQ_IQU=gH*pK z?CfkZI=T-yN3`_c^k#V%3Lo}rZiA`f5|yHc@kY%Tm4N%uuChtU2OGZ?p9kSH1d+E7 zLfVxO5rpS*3aWeP;_o*d%FSH&UDlJ=*6tJ!YrDPbtHoWF6+a<*SvcZmz0N%z6*QQTP;6JPzwhj7>yqPTFHhaa2SN zUXpmo-G{uIH7ajv*j018Fy9G*BBQ)asDN7LeZ0cjRv6;Spr$c}d8)Y;wA4rfiC@4{V~EqSjH|!*v|rrwB3n$6MP*>U8W7 ztxMt%#)B|FUbQt5_GWnuocIc&B}D#?SnXNU%wKWNia$r8k)d@ZwoS~;sGw1rh-ll_ z%g+BLKcBhqJ16!2qc38_exg4QD&L8_I_ABM#5U>t-1#|!o; z5MebasQy%S$Fuj3o{UfpDYBREnCup>^y!I}mw3qBKJ?mo zkFL`)8!BL;8FmUG9p`FNt1hc{x;ET$n2=AYskxf7(JLG?PT0zS{+69l zt1^D4?RhU-i8orEI%8gE{kXkb$MRNJ$uGhN+I8~8afVz@ntm@8XK!1Im+K>BB$#qZ z#mGufv5edfmWh1AxVBkjktXf#t+3fH?ry&Bd{@N% zjO=L+qEYUfLX866`ywUyAKI-Pa_%7_j{WS{Q^Ez6MR|-t%g+y#pwkO7#^i5Q>m@RXCLe#r)7t>mm zPoI9&(O+TbmhEz0IM8aA4*4Jx7rH4PKNp6^QM~XNr|)UzFmkDIOY&KB*ZK9{qb3qa ztl#Hf3r&?QpKIbJ%pMov^3FC<-Lw)f zb!eVm9ov5OnVmQ(w{&y*(J8O}$gd11_F9|5=6Ee#NvPa_^InpS5^36ZIUP0YkJ$=+ zQoKCee0eNcygz%SVse;2F~u=#|B$ltFokdx6qtdwU3K(L}1h^CGiMnAA;=Eqx4jZqmGbig$RjeIS6q2~J9j|)- zB&iBCU~qqe%C5<(ZCCQCMdp0nFg*p$d+K+8p@o222_Jt~x>)5rt@iY#)@tX?5^?1g zMYuF38_Ego@~G%%ABEWmafAhw_Xp@!n;Vp$hHp&ywu|vRa*xe-0hPv5rK$0yfM-;yTH3i#L_3o_lgx_fz z<1%Xz-k8^xhl$SHhy8vDA>O$5{Gykl2m7v_1n~+^5?o|3~wzA zAjkGWqndkfr^AfxPP_l2U+2Ev?_gj3@X(d z%2u3i=6>`tQ`zS)M$nz6j~bbgW;u`j(8h7|HB=&LvD%}W;~_Nti*jYt@@XN1H?sqM*ctG=%w3>d+@DBpTOUKW^21f4Q0#E>gtF zrS?6Eb5fr@>fqtGek1o4vnHH|1?SIhZ!pDv1R!Y=XIGuS2unyk&78)Z|N94E2ZMF);_WEjaGvz{1PJ!N+lB0tMc;Ec{T{yx9uJl4TS?~vDc^v9)Iy#@@{Ls-L~E+!b=*m1>@ZShFa zhq@^OGF+if2EK8t9cc0IT%L`PUZ=lal}GKp)>+e%aQxXBm!!kAb?sM8}{C<(Zc5k z@#}cKJX|kfLp`jChhgeUM3l(vJ9<9sK1P{pwOrKOSJiBdWSlEBvMs;=Jy78k=aT9-jaauzQntF}3cKqduZI zw1GEtc;gyavpTZQQMoBi$j8yi`08xHC75ruazf6?i)P#)T4O7b>UqydX4Z3WaRx?q z5GyCWd&<+}T7iWZcVy_wH?<8ndNYk?(|#D;64gdo&_k%+i*Y5KVPCL{Bm z4U_N`i1a26_4iAe$DRFegmJXKC-RaNwkkYvUY8IzGi|@M6?y*Cy)|*Cb=q)zUrsnG zy8SioXNVFd?P}3y&d)@O#{4?pmVcv;LUeS;P@r#gJan7}d_Jx@n`@)l=zb9m;>**| zifdIg8h<2CJ8UywnyCEVphA_5GGMo+ynwZ5i7?Ob$?2@pRG8$Wsh#pII{}OeQI7*3 zS+EJ0VmW8nY!$Vm*Qb|qIfxbPeLKo&>nTt83$AFrb%1ZTOgnQ?$Bh`G zYSqlrrt>Zqgzof5gyEBRnz>34OzWLtp;KTiHKtZSJUux47J*ipmzK4{ zu2opb=SnhCQB}{d`?Rg5P0Q~M7MN*dY!(n@j{hTh{D5Sl#c$nP&k*Q8mZejU;Y zCde9DZUM`d+`GF&bqZf-2};8q5_uiYku+oPXMNBzeREqBDz4kusn0&H+k*RaTa8|X z3@5QZVzfV1$o3tXDj3ptlb&=Ld;ai+JP$_`6E__$4pdSaH(-Dc1sMn93Gi?jT!wwt z>oKmro|*5Yib;)mVq(MJyL8$j7NH#1WC-CbLs?Kv=^|?DZsLm2n#bryb4b72cSc?Gj{f>zi>E!vZWGGUX5dY;z)3rRf~pb{BnL#^!FV0n%|z zs!R(`9e;sx9cle*op8rGwK`1k1gzTPyywbBtfLTC={867<>+JjMlxiFQDC{D(8IivI^`JANlSSJ2i1XA+5r<#g zQ+iM(Ix95&CAxVkGc5FV zA|5if$De-EJUcsA-1<7()C9(SNUW%*JBqexCfzFFk;HlM z{hxcyfcM&Javx-F<8xGM;5A=3J}0HW|GpvsrA$5)>}i9@j1Jy`i*0~ zlg~R(Ecq1t$5Y!-DKijb``(F(2}~qjs#_r^&1LdHg_vSJDH-sGqs?!t7B3E#TOB{k zs!OpruY$FpLij8b$7dXg_va1iSRSVB_Juz6#gfl9E8J=IBhXT~c|tXKy;jBkOkp|x zr%k=_4;y`ajzVJFBpM<%oQFYgo^&NYxY_)MVyAL$*!Fn%mtpzQ>0}J~{lo^4?jfE* zjpfIvTGrXQE_StJkr^cmLQv;JRkGho9u}*)+Ra*A<|2aJ(s^6Y?Hf*tNO29HsnQ<` zTBT8Y;>OWPy(=|zd)@BF<`Mj;zW){G&kdW|gc8I|)F_F>l0{u@BA)^an#AnUXkJ~p zNmhapQPCE#)x?RaS&pKop1#Aw4kHrJ>RIj8pVR4XNoc5{KIwcPuHETuPYc5fS7VxT z(GFh|dk_C2Lz4RNb@thS!J4__@uhN6&kPiOC+Cb!}N1-zQ7LYoBnS*a0XW zGcsptwg`J#gDOJQ?KQY(10q=&m2OrqjAQ1%17AO2Hz<`7(_Uzs;=+?+9)#~}Jrp8& zS{xy(oNB%28<|-BD!b$8IDgZwIyONgsf>4AEapmEwpf#)KQt{FqtI$af*=3(z^BH> zZG?n4(U@LgevXu|EG6K?^pi^nT9;-anU*w06Y^!VYy*=9uDxHAq!>70P_Ju6zjwsP zH=&uFXVIfMjZpZ@d&#&PU971fGv*(+(u0i4p`ZGC?HygIGqbST|f zDx6%S*esYS;qVi^7NudT&exYqIiG84qF3G|E;F}p( zf<77e--gDQ-Bj;#PKk6O znz1vUkIj_*fo4OKJ1er}Ez(*5eK4k_g9XIZ#nSX8?31IJEhaZNhzkV!AS#N5@?kRQ(PPq*0iRhoPvz9sS}7(!2+nT zarMIFgtZMr;$q|E>Ighp5`ZfS!{rJR;^G6eOr7K{ZLD9of&{qv|HAAFV&~xodLV0W zY7GGa#V{jMQjVS=et6@sysVAAB@amO?*bLmmzMwS0R>l6dmD2}2Wxvv03@dd&_8XE z09-@U%L$PFZ*+J4&~P(zy{r4l@fWxaeH z&$$3o=A(q;wCMZy!Lg$nMg3XDMC!;7n`F3j#msaDZkx5E3P-5?g~Y?mD{s!{TLON! zaJr336q?>t|JK(TGyh#++j4W0v++%CCSrM*AOrdHj2uzd@A>f9P(b>sE2H^lFJZay zrNq^8K(p`Vj^fElZGi9ZT9d8c0TLG+kw+o(H>Wu_y`Ph))Sq7GlTsgSIRcFgNet4*c=`?~L{N83!-JGw1ED)d{QLZZA>_OA<`B5=`D)M-^$O^Gm#Lpje3_ zwYr-24S=32&$FlwUPV^&cu0QnUlj0**t;CPy||bGEdQQKXc=U1Xk6nSWFWWWb4Fh* zPqcaPqoc#-De%yya(SUd&s1V{qe9_A3e6+gv2XY_LJzPS-__!98Yd@OCGqV)Xg^%H zjc>N2qSnlnQwi3%USYN-i7^{6`(e&!^yP~136;v(FI?>yTs8IpBQ59r8KTbHi|Mb8 zxi~?|B%cW=XGa>|baoBkTo)KG#4Ze6m4=PjEib=KIC56@+`?Lpi`x3p#g`_2Q#xnq zG;m*e{(|9V@ZOOkV24C%tXqrBost z$W^0w*Dbjc*SyI?<(U)_&1vLPz6jU^GdBcQukqr@f(40H(p}!*GmqnA42`X0U*_6T z4$%F`x;cs7G&0jPe=-9ZNI8DGhG)G0$vT!vaDkO{20Q9E>w1fxp?!4{;yImXD@cxV zY1PnPMAYnPdf%Zzcl6VbPFrhUoNpN!{iC%FEt})^P#y6YZ#?BM$|U(7OFuZhdN@(LML;@;<_7Cz~f91D21npFL&C0Ahixmnuo%X@5o1Ki~ln|mkd z2h>~|^E!D}G%AqjywoI_cYLu%2BF0m#RrVLFMh6bnJD|`cz9G6PdMuNKD&Gyb|JhJ zyC5cuc8Jfp9(Hl_olQF6tm`r}qn51x*dbrI>SWnX&`xu#qd@)egGRNyP<}%yr>(&R zDGpj=>cD(XsMMI>e0pKBpcc^QLK0@}v80<0`9mNQ%@U)Cl+b?w0sfDK_StETa!#h+~MmJVggaJ@r5w?V1$wZ6iOpc5h0E za%nK~VZ?(qZDF>}%^z<&Y}kNFlqoOt;MukJM1DjmiX)8W7Gi|Cyp<~v&(I7)^!S#Muu!38B^WtP? z?sPPr{BT1h=npS)$Ae7VsFe7kF)Q1&NcHU$;NKVMGa}K&Jdls&}2L} za7))#D0D3->`j}7+7Zp_$KM^rF0NK_<3n;oG4r|=>T!OglmkmdEL!wV&mMYW7OH3K zYUTb^*m2OD!bo)H{K}2P;xlYP`m^h+*V<^69Si!t!agcTnrKI#PXYHz_;do>oj>KcS|Ph%fKm`RoTkeW}p(= zD&3UoVb>@()@&s>d*lH5j4^1>BWBPr7yVmt_exHaVw$}~S5rBagm4J)O}!Jau4d#kzvJb^R193Mv; z>`L&opE%H0+^>jUZxbN0rn+C2UV|@ocZoC3894nU>`KN1?6c&t%j>eOe<@;1reZRx z3Q4Q=e#iH3E=l<^++f8OP|R!(?Rjtaf!sJuc0>A$595Q^f^n+pF0!9KggjF>?whw5 zc$nh2tNgZWvW8;LEMf~8(#6|ZvmgsVlYYZ_hF4xsKCm19L(#3ph0Cv&e_^VPE%vH*l^N(WdY%dpOVZR3ts^jrvl4codBVRBbcyQf!CVM5iicPOx{7HNbjoi_B z)`}wcAR+XN2j*@hRjS**XjaX3u7Di}IRJ&=>jS|3My|pcDVn1)5n{Bh z-CG7Gu?jn|6uLioH|EeQv@zEKu$hZ>R_(<64(8niFw z;9L#2(4?I!-j3$2&%XHV--nK(+-PJJ?~z7?oC9Go?usPbLOyV*ji zq~=jvnG)-d=IQyBLD$M}Mx?8z273IvZc?g(1j$`~3nf!3rPeU0*7JkZ?a8|#CDLYn z`uZIvP4r()&AVPnM&17Q4l*@}lISZ}UTCas?dCN6USm4&$>hBde-UB^GTwub9sr>t z-fVI&WHbj4N>MvgpypNG-k><)x|(Ve%EdXCzJXwdw)8{5t9ME=`_XoEepT+}DAZQv zMqIrCH(TIU?bMIh*h0w%KJ^+G{HDcR~bb5WIS;@nT$FP;I`uj$N+A zx~il?5%<=*tx7p5Uk)=+7-Qvp86W6DvRh>|A3lSaRzs^o4xGn!fH+UvVZ5P67MPrB ztWP8@LUI;mJtNdkH@WcIBtEA*4V4XqJjmGW!}QLZ z;i9Xq%<8xeysXa}NtfroMWZKoglnZ(p4xkM84R;IpJEQ3{zAP|0iv^wNg2f^Ja?Z z>NZFn*L^?su*LEf{gESjYiCKH@sIde9ACnwusqUpOyj``*IBY9|Afy%^}qHZ!Ck*= zW8W@)E!#PLw*=K_1Au$Rm=R}GGkdc|pUj;*nk@`Y`}8*&fSk*2v#A*f7qd}1#DtmH z0|nUu7qCChex(06^TEVI5vQF|jHq-{Ot#25`3rxaBM9as*2KT$q;s*wHJRK_s8_7 z>D-$pF!XAl+@8qc@DLRx5)V`j#!D>=1`Z9Xg1k3zt=b4s_SdO~Z^*rxGy6-Y8RIk= zoLM47S3fYT7xPqJ#WCkRtJk@ggE&Yv6|0z7($^zUqA{DuN#Q7GGNDB=BPW4vhk#^5 z)iH(Jtx@VXOiVc=r;TxQ=3SWg(JnMe*JOq6;Vc^>Ge^D&YarWtKx3C~i)GX{Fr5Wc z=Umu4g+hf+?Rq=eLpK;XEmW)@1*p}NTE+|Gdal;kjBt(n2!tp=M_qv(TRp~1IXSZQ z(mXvOGfqSHGAeQWeEC?pR_XHWlhM%3yKCs^ARrddu$px}#y&&mB(`CJx0gtyXDgjD z|5A0YX)VFy*|DQ-bQ1Q72&MZ^9y;DL%P#t}oT8M`#uOCJHPc3K*2qH)%JHZwUnb&- zdf$biF_B)o-0|HivtLE*M^W0y9OHgHQTOI~GZ^nwQ9xDw&epFJ)fXxf%St<*|jrV>T3&k^( zj!w{zIs7!(eWMy&J7ZmB4n$yimGgjm!@4f&kdDPHQVfT(l~RL>!)HSbVyfwvukLpe zj?XHU(@yEu)7R?>a(Mc7^+ZT?P}ETnj=F%Nhi4LDMT%qvyy zDjZnHFof|HbcUyxd=I~2)#=2dSF+pb04s|sD7c|aZL!W=!MR4pl zEO^hBqXHMWUp3x`de)~;de{{d9*UKpxvL$G%*=gHdyz2wa$Tf@qoW`IIDUr7m%9rI zp)S(hoRhw|P41QL5o{f^EGF1<&G0JSFWxJ|wwN(u0~X-Wi(_&9wm!EEFNbnEaOa}c z*+FPZF?3dL7ftB?27lk^kRX_&LAfKG(;Wrca$4)2FG%gh!yf zW|jD-Mi|rKf-j}hUHFNZ$E|LK-!&V(1-@lW;B;%#b1HR?;~YVpV6SNLc=K6X*hzNt z=5>)Akui(cgNvJvj+4lEy|26@{U2{~WPd{f2~Lnm`GBM3#glhhw=GtAWeF3BeMKSy zoy@cbYhOciE^U2{pg226OY`d}NB}nS^QXX3a^f<%wwot*(ZsN0!F)fpTC$p zFN`F8pZ63rbe56@X+ZmRGuOi$aml(%?qU0ON-f=}Up94(T2-hLdf%?*)z`OFlX4C6 zu`$~B&l(4l9gO)nh^FOz2}N7CqJi<{ZwWP<;Gee?jF#zGm-axmnbMV5TGUyScbyRy z_@b%wXxbsd{w)+b`T+<^Gho$7{YACAaocesr8S--(fhNWT-t*{)98yyd9~rE--b%S z$#8FGbZZ-#bK>N}8z(Z=ke23>v#9$bg5_An3zZk18LX`NG7Mo(>Q3lbzgzC9m zP_pkmw%nvFSvd}42l3ACmJTDn9UWO=ojzD>E3nFl!@m4G*^Vv`?m{Tv!4r|PE zN_=vL=BH=bcwSHiVLPc$p>MTelsza=1x^5V<- zDN`zL(^?(uE{FH=_CWtEbMyBKTjB<1guUXiCwm05Z`}LrNoNW3aDi2%mZo#_RQd~J z(X(~zz)+iBtv-huJR|kR8k$5PRDVzg!bv6B!oEI%idASwG`C9OC{_*b9NC!Y5Jlz2lzgh7mbqSKRzj z-)Y_iB(lNX<9w~l>vGX7LCrDL;IAbIE9cSnd$kgB#9oof#Kab(IeyPE>I?4yl>qW$ z*a^s9)$sv3YtQm!w<84O@TFrU}sHV8BGp(0? zFamcx^|E!v0*qtD3{dCA^R2BnLu##R7zdYUPfoQ=lAhGsz5KB{o|d-=bWq@{4YgTY z-$~r>u66#)lIBdJlP3CS332{siVq;d;mx5|6Eu*kzv)qo&R8MvLL4cuAmRV_MZ zys#$kQ@Vya(31p+t*uwhSS{|MSh}h}E={~+d#2{Tl=twuI)C2Mi5lZSm^)C|*G-Er z2U=6z)9HLE=I3gy1tl-3cu)J~c%i6SVaHu7pwMXP2aQ*+O@cb^G+#)#tj1Ns>uEl(`t9mpRu~L>E+G9 zxl1OvR%GzG8CHI5EnD^fz_ogRY_ocg7-ib(64*H*vzugj0 zL!6HzL`I8+3Cs-z{}R})^Ov3wtJ%VMg;wW}bZ5Yc3nNPYT;Oz^kTcz(3{miuL9~pT zA;!3?FH2A!aRimlKgRIYd5SMup$-D7EjY&}GlC?4qb?lcC^{j(-g2j0I>ezt*kd7l z8w(X>393lhS(CqhLowl~JNT-0==bOSd;bk!_M2bfpvOyR>Z%2U0o7~Nr3;)7tsXhZ zZEbX-G(i=OI~?YB>c47O9R3H~SzUL^-t;oROj~2MOsPMT^EK+zg+}$@h3ABnF^{KW zNL81OXgSjv#4Fa2J!MH`Kib2qX%#sG<>=H--x{#}E~PEKC1|qjLD;VnbyAsvH*P>_ zgBB$pxLvd99JYK@+RE5T8|4zhco@iS5r*7UB#$q8hz^FiXQGJ_XHWkqop<4=V!eJK zbN;bmOAz6C>4(RuN-NJWKFro^vB}&Gpnm_4{~4gxBCY+>Ae|z7s`01i|J%E!IE20F zBW=_r9K4gjyv0TQ-rT#Po7+FffHf{RUfI8@WHhReI@0k~v?te1XGfW!sMQ zr(Yn!#8-gp+`*-l_;&;I!nsY{OTXST18%>gM}{))@l+5!^+74{1KM|TybwcP$(#an z3aIYq6fSIJj6`Q?kxJ)>aq@gDg8zzX;P-aj;mEy_OusrkBACi(JRuEo41b06{+er4 zKM>Q@#edpeIBEGes8hkz-57)k#|7f_cChhw4D`-h;_16F4>6*@7!oy*zL}aQKF_ZE zc@KrMo&&w&3F4d<9XbaoVGyiKAuc$+6R4r)C<%>_R$7m$KeN%P9t9N^iqdWka;Sza z)Ia`-`LpUB=3UPR6noPLT*3!VFw9SXd1aF*iADV&OvpT2h$-Ci<=GFXNkmP5M#u5` zOB*dp?r)0@1zMhnZVysJOx6%NmgA)!b&VT)M^pgahjNstAA+l~xk9r-2&II{r>^TV zPI1Ghd6#6ZT2kbyXM6y6iUQ)@_Jcbw!PBo{3j{QnWQLKO&K%#7^NYkY8=WXahK?$R zndY~=6Eh+*C9~#NMsvT0bktHpS>|tulm%NsjOCjuI*mYJUyhEIF0g!}RGG+Z)k3t3 zj}EPS`XXgCjs|G5CXe+=o0ilsXJ_0*cSCw)A!bZUp^R=uzt>n#TC0{>J|%$t7Gkoj zdy2$=pc!l?4J?>)3Eit*(UNSoLxmTo?_(^co#R?%tQKQL1;jTlM!i^_;y^v6 zD^SwPUV7>yduY_93d}pnVXfH&Wjr=3Pao*^EApBPDuBN)u#GB} ziW7;-N;QUOIucUj!#p#HbjjqJlL4s3sJNqs`S;v%}c)S5wj! zW~b2$-GqdcJ(NpCYp2oBda+>IP&rS!+ECR*FKGs=IrKEp)38Q1<9A60LoRh6>RK(|X8w(&fEUO+1ifu<}KxoMLVxsvdPz zrK3VpdLJd3>P5Qp-4|Qjv<5jTk)2wwg65T61^xM}dTa|bj*x|JJ$%X@%LO7UvS?@$ zYA|iqV^6x#K-EOF#|&!-=#ic+`|_0cGPs_qGRSVA$nhF`(mfqw4F41h<#ugLQdOXY zep-gg)V0wOIJ6P;kWfOMjxd&oEX=Nw1eg0)zMq3LxP+A$WJ6J`b3tBo!u^clv+tqh z25kgc#FWt4Lk!v?i%rXJ)JXKgeR+#G)dy#EM9b;HV6;e4!m|}3S^A!i{OpCd;+Rn~ z^anC#Z=SzT{Iu{E2Q#Vz`}ZpXF&^$rM#0L)Zdw8{anq&!G5A z>x)FPrrjM(;S0+f;r%kEbr#RVUlI9zlSh_g1N@UCOt60H{>Wo zj_M#ie|3Pu!`%!lclXdKp_~iQ4$@Y-1C+K^T)usI-yqcoCLp3^tl-)_uULlWR>pA7 zXedy-Y@?k8<=n?u#;Z~{J`dmzNV1s4-wtS!7}(+dPgD4gIdtuV|7eHk$i&C~_Pq`ET+qi8`K-CWEqAs}v8<1o^eqbtB1f^nbV^d&V@Ys-H?ykjE$ zMK=1wE8^zj;rj=#2uABtaIgWWWoj;t<{Fl+AS)XO3zt7Ffy@9_m;oZoe)#{L(- zj2+PVTjH*h02V-l8x96WnSwZ(np?V`MBU}W>)4e zOaZbQAPok@xwv>>T3lS*@HZYAc#a!h_XPgNd-ulsr;rbx1kb@0cqHLDxB`z9JO@|ck%s5s3V$H+!WDSnka*z=JV0Lo@VsyZFuV`E@IHXy zaCzYhU^rY}xB?gsmk+K0h6Ch-i-6$(`QRd8I6yvlkHBz%d~gLY93UTD0SpJo2Uh^Y z0rJ5Wz;J+ka0M_NAm1Msz)kc2feSay{|7GIG(Q{*FWfZ$pW%R;=7%fr!cFtT75+Gj zAFlAnS^RK?KhENZEBtX5{~s)HXYv0T4!E=U|A2=(i~kRJI9z_X!XMZ1!xjFxP5`d( z$5{gK9{q8az@Gtt0~CPw=#R4m{tO2kpunHufP)YK3W4DM6UDGFht0!CK=3!_r+X zFNlv9UIv)uyF&mN0@7VApae(HCkO(P5P*kI2$o=0_yOo}^!zaBce?z7ARxi8@B>1C zD9jSjJPZWz#tln%Wk44JY_M7Y2;7qbydWUmmGOZDU~quiyTk+Z1Ly#d?mhu-1loYv z1G*@5S0=~>f+e8mg50nK(-j05vhX$pfnoqTtc(wqV521nWPpwWRs;oL2{x93fb-z! z1%*IBg4GJ~z!L0}(O*1O7!em91ne-6!1%g%t^r8Be+$8=wlE<;;xD~_(p#k+-GI#t z;Q1=rSirW%yG;wW@%_D7LH@a0{jmn45W_Yy$Y1*&TwK}|VEZ~+|5E`*UH)r(lXP=^ z0q~ERlqFTPK+3A}k}AxwE!fi3)yC052DVEw$q4gs@$hni!N5Wf=HupN<>F%mb1?#P z%8nNQFA-pSv~UCV8K4Cla~DU5qm`>LNDW|6yMi;Iz*^?;w1;>y|Dyw*E|yl9Tp(^f98B281%H9~`S`$mAS-woHy4+X z5a2l23*_*385rpMKg$3qZXV#2@n2=I3^1GjT?SbHuQH$wK_J@xT_(i+FFBY1Fhl+= z2L|TFf0Y4Pcz{^^?=nFlULY3#T_*Hzdw?z%FfaZ~jvLsQf%W1)Wv(u!05{y_jv9Z* uXXpNl!|vz^#2XM4z|ly<#v7nw|2gWIy13r?8nDCz=EtO`f1)aj`F{X3bEq}| From 64e8a089f5007c755941b9dd99c4bb6462801df3 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Thu, 23 May 2024 13:47:27 +0530 Subject: [PATCH 077/102] added issue templete to .github --- .github/ISSUE_TEMPLATE/issue.md | 64 +++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/issue.md diff --git a/.github/ISSUE_TEMPLATE/issue.md b/.github/ISSUE_TEMPLATE/issue.md new file mode 100644 index 0000000..7b10298 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/issue.md @@ -0,0 +1,64 @@ +## Description + + + +## Goals + +- [ ] Goal 1 +- [ ] +- [ ] + +## Expected Outcome + +**Objective Outcomes:** +1. Outcome 1 +2. Outcome 2 + +## Acceptance Criteria + +- [ ] Criteria 1 +- [ ] Criteria 2 +- [ ] Criteria 3 + +## Implementation Details + +1. +2. +3. + +## Screenshots & Videos + +## Mockups / Wireframes + +(Placeholder for any mockups or wireframes, if available) + +### Product Name + +Beckn + +### Project Name + +beckn-onix-gui + +### Organization Name: + +Beckn Open Collective + +### Domain + + +### Tech Skills Needed: + +React,bash,javascript,nextjs + +### Mentors + +@venkatramanm @raviprakash + +### Category + +Feature + +### Sub Category + +API, Frontend, Backend From 1548987dc484e8e90e4db4bc7ea30b00248049ba Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Fri, 24 May 2024 11:41:56 +0530 Subject: [PATCH 078/102] Change valid from for keys to a day in past --- install/scripts/update_bap_config.sh | 10 ++++------ install/scripts/update_bpp_config.sh | 9 +++++---- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/install/scripts/update_bap_config.sh b/install/scripts/update_bap_config.sh index c4aa61a..be65d06 100755 --- a/install/scripts/update_bap_config.sh +++ b/install/scripts/update_bap_config.sh @@ -50,14 +50,12 @@ echo "Your Private Key: $private_key" echo "Your Public Key: $public_key" -valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ") - if [[ $(uname -s ) == 'Darwin' ]];then - valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%000Z") - valid_until=$(date -u -v+1y +"%Y-%m-%dT%H:%M:%S.%000Z") + valid_from=$(date -u -v-1d +"%Y-%m-%dT%H:%M:%S.%000Z") + valid_until=$(date -u -v+3y +"%Y-%m-%dT%H:%M:%S.%000Z") else - valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ") - valid_until=$(date -u -d "+1 year" +"%Y-%m-%dT%H:%M:%S.%3NZ") + valid_from=$(date -u -d "-1 day" +"%Y-%m-%dT%H:%M:%S.%3NZ") + valid_until=$(date -u -d "+3 year" +"%Y-%m-%dT%H:%M:%S.%3NZ") fi type=BAP diff --git a/install/scripts/update_bpp_config.sh b/install/scripts/update_bpp_config.sh index fbd450d..e20cc3a 100755 --- a/install/scripts/update_bpp_config.sh +++ b/install/scripts/update_bpp_config.sh @@ -52,12 +52,13 @@ get_keys if [[ $(uname -s ) == 'Darwin' ]];then - valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%000Z") - valid_until=$(date -u -v+1y +"%Y-%m-%dT%H:%M:%S.%000Z") + valid_from=$(date -u -v-1d +"%Y-%m-%dT%H:%M:%S.%000Z") + valid_until=$(date -u -v+3y +"%Y-%m-%dT%H:%M:%S.%000Z") else - valid_from=$(date -u +"%Y-%m-%dT%H:%M:%S.%3NZ") - valid_until=$(date -u -d "+1 year" +"%Y-%m-%dT%H:%M:%S.%3NZ") + valid_from=$(date -u -d "-1 day" +"%Y-%m-%dT%H:%M:%S.%3NZ") + valid_until=$(date -u -d "+3 year" +"%Y-%m-%dT%H:%M:%S.%3NZ") fi + type=BPP From c45b774400f2d0971bf95203a6bc8c8a9f7e0478 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Sat, 25 May 2024 12:43:54 +0530 Subject: [PATCH 079/102] add basic prompts for merging nets --- install/beckn-onix.sh | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 429385a..160d684 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -162,6 +162,21 @@ install_bpp_protocol_server(){ echo "Protocol server BPP installation successful" } +mergingNetworks(){ + echo -e "1. Merge Two Different Registries \n2. Merge Multiple Registries into a Super Registry" + read -p "Enter your choice: " merging_network + if [[ $merging_network == 1 ]]; then + echo "Merging Two Different Registries" + elif [[ $merging_network == 2 ]]; then + echo "Merging Multiple Registries into a Super Registry" + else + echo "Invalid option. Please restart the script and select a valid option." + exit 1 + fi +} + + + # Function to install BPP Protocol Server with Sandbox install_bpp_protocol_server_with_sandbox(){ start_support_services @@ -292,20 +307,13 @@ boldGreen="\e[1m\e[92m" reset="\e[0m" if [[ $choice -eq 3 ]]; then - echo "Installing all components on the local machine" - install_package - install_registry - install_gateway - install_bap_protocol_server - install_bpp_protocol_server_with_sandbox -else - # Determine the platforms available based on the initial choice + echo "Determining the platforms available based on the initial choice" platforms=("Gateway" "BAP" "BPP") [ "$choice" -eq 2 ] && platforms=("Registry" "${platforms[@]}") # Add Registry for new network setups echo "Great choice! Get ready." echo -e "\nWhich platform would you like to set up?" - for i in "${!platforms[@]}"; do + for i in "${!platforms[@]}"; do echo "$((i+1)). ${platforms[$i]}" done @@ -319,6 +327,10 @@ else echo "Invalid option. Please restart the script and select a valid option." exit 1 fi +elif [[ $choice -eq 4 ]]; then + echo "Determining the platforms available based on the initial choice" + mergingNetworks + fi echo "Process complete. Thank you for using Beckn-ONIX!" From b873c6478e8a3d778f9ee744fe81606b99368c35 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Sun, 26 May 2024 05:43:52 +0530 Subject: [PATCH 080/102] Fetching data from registries --- install/beckn-onix.sh | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 160d684..2005b8a 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -163,11 +163,44 @@ install_bpp_protocol_server(){ } mergingNetworks(){ + # Now need implement the logic where registry A gets merged to registry B + # And also registry B & registry A gets merged into a super registry echo -e "1. Merge Two Different Registries \n2. Merge Multiple Registries into a Super Registry" read -p "Enter your choice: " merging_network if [[ $merging_network == 1 ]]; then + echo "Merging Registry A to Registry B" + read -p "Enter Registry A URL: " registry_a_url + read -p "Enter Registry B URL: " registry_b_url + response1=$(curl -s -H 'ACCEPT: application/json' -H 'CONTENT-TYPE: application/json' "$registry_a_url" -d '{}') + response2=$(curl -s -H 'ACCEPT: application/json' -H 'CONTENT-TYPE: application/json' "$registry_b_url" -d '{}') + combined_response="${response1}${response2}" + echo "$combined_response" + # Need to to know how to send data to registry B , facing issues in authorization echo "Merging Two Different Registries" elif [[ $merging_network == 2 ]]; then + urls=() + while true; do + read -p "Enter registry URL (or 'N' to stop): " url + if [[ $url == 'N' ]]; then + break + else + urls+=("$url") + fi + done + + if [[ ${#urls[@]} -gt 0 ]]; then + echo "Entered registry URLs:" + all_responses="" + for url in "${urls[@]}"; do + response=$(curl -s -H 'ACCEPT: application/json' -H 'CONTENT-TYPE: application/json' "$url/subscribers/lookup" -d '{}') + all_responses+="$response" + echo "$all_responses" + done + echo "$all_responses" + else + echo "No registry URLs entered." + fi + echo "Merging Multiple Registries into a Super Registry" else echo "Invalid option. Please restart the script and select a valid option." From dd32e919885d546135b347ddcb15c2f1fc8806f7 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Tue, 28 May 2024 15:00:41 +0530 Subject: [PATCH 081/102] Merging reg a to reg b --- install/beckn-onix.sh | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 2005b8a..23c732b 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -171,12 +171,15 @@ mergingNetworks(){ echo "Merging Registry A to Registry B" read -p "Enter Registry A URL: " registry_a_url read -p "Enter Registry B URL: " registry_b_url - response1=$(curl -s -H 'ACCEPT: application/json' -H 'CONTENT-TYPE: application/json' "$registry_a_url" -d '{}') - response2=$(curl -s -H 'ACCEPT: application/json' -H 'CONTENT-TYPE: application/json' "$registry_b_url" -d '{}') - combined_response="${response1}${response2}" - echo "$combined_response" - # Need to to know how to send data to registry B , facing issues in authorization - echo "Merging Two Different Registries" + response=$(curl -X -H 'Accept: application/json' -H 'Content-Type: application/json' "$registry_b_url"+/subscribers/lookup -d '{}') && + combined_response="${response}" + for element in $(echo "$combined_response" | jq -c '.[]'); do + curl --location "$registry_a_url"+/subscribers/register \ + --header 'Content-Type: application/json' \ + --data "$element" + echo + done + echo "Merging Two Different Registries Done ..." elif [[ $merging_network == 2 ]]; then urls=() while true; do From 11909f5e59873e27e8993894fb33f7807c09fe19 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Wed, 29 May 2024 12:12:08 +0530 Subject: [PATCH 082/102] Feat merging networks to a super registry --- install/beckn-onix.sh | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 23c732b..090f935 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -163,10 +163,9 @@ install_bpp_protocol_server(){ } mergingNetworks(){ - # Now need implement the logic where registry A gets merged to registry B - # And also registry B & registry A gets merged into a super registry echo -e "1. Merge Two Different Registries \n2. Merge Multiple Registries into a Super Registry" read -p "Enter your choice: " merging_network + # OPTION 1: Merging Two Different Registries if [[ $merging_network == 1 ]]; then echo "Merging Registry A to Registry B" read -p "Enter Registry A URL: " registry_a_url @@ -180,6 +179,7 @@ mergingNetworks(){ echo done echo "Merging Two Different Registries Done ..." + # OPTION 2: Merging Multiple Registries into a Super Registry elif [[ $merging_network == 2 ]]; then urls=() while true; do @@ -190,16 +190,21 @@ mergingNetworks(){ urls+=("$url") fi done - + read -p "Enter the Super Registry URL: " registry_super_url if [[ ${#urls[@]} -gt 0 ]]; then echo "Entered registry URLs:" all_responses="" for url in "${urls[@]}"; do - response=$(curl -s -H 'ACCEPT: application/json' -H 'CONTENT-TYPE: application/json' "$url/subscribers/lookup" -d '{}') + response=$(curl -s -H 'ACCEPT: application/json' -H 'CONTENT-TYPE: application/json' "$url"+/subscribers/lookup -d '{}') all_responses+="$response" - echo "$all_responses" done - echo "$all_responses" + for element in $(echo "$all_responses" | jq -c '.[]'); do + curl --location "$registry_super_url"+/subscribers/register \ + --header 'Content-Type: application/json' \ + --data "$element" + echo + done + echo "Merging Multiple Registries into a Super Registry Done ..." else echo "No registry URLs entered." fi From 0fad582806b9e2c08fec9ca3689054dc9032bad9 Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Wed, 29 May 2024 13:24:10 +0530 Subject: [PATCH 083/102] Cleaned mergin networks code --- install/beckn-onix.sh | 57 +++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index 090f935..f3399c8 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -165,32 +165,23 @@ install_bpp_protocol_server(){ mergingNetworks(){ echo -e "1. Merge Two Different Registries \n2. Merge Multiple Registries into a Super Registry" read -p "Enter your choice: " merging_network - # OPTION 1: Merging Two Different Registries - if [[ $merging_network == 1 ]]; then - echo "Merging Registry A to Registry B" - read -p "Enter Registry A URL: " registry_a_url - read -p "Enter Registry B URL: " registry_b_url - response=$(curl -X -H 'Accept: application/json' -H 'Content-Type: application/json' "$registry_b_url"+/subscribers/lookup -d '{}') && - combined_response="${response}" - for element in $(echo "$combined_response" | jq -c '.[]'); do - curl --location "$registry_a_url"+/subscribers/register \ - --header 'Content-Type: application/json' \ - --data "$element" - echo - done - echo "Merging Two Different Registries Done ..." - # OPTION 2: Merging Multiple Registries into a Super Registry - elif [[ $merging_network == 2 ]]; then urls=() - while true; do - read -p "Enter registry URL (or 'N' to stop): " url - if [[ $url == 'N' ]]; then - break - else - urls+=("$url") - fi - done - read -p "Enter the Super Registry URL: " registry_super_url + if [ "$merging_network" = "2" ]; then + while true; do + read -p "Enter registry URL (or 'N' to stop): " url + if [[ $url == 'N' ]]; then + break + else + urls+=("$url") + fi + done + read -p "Enter the Super Registry URL: " registry_super_url + else + read -p "Enter A registry URL: " registry_a_url + read -p "Enter B registry URL: " registry_b_url + urls+=("$registry_a_url") + + fi if [[ ${#urls[@]} -gt 0 ]]; then echo "Entered registry URLs:" all_responses="" @@ -199,16 +190,24 @@ mergingNetworks(){ all_responses+="$response" done for element in $(echo "$all_responses" | jq -c '.[]'); do - curl --location "$registry_super_url"+/subscribers/register \ - --header 'Content-Type: application/json' \ - --data "$element" - echo + if [ "$merging_network" -eq 1 ]; then + curl --location "$registry_b_url"+/subscribers/register \ + --header 'Content-Type: application/json' \ + --data "$element" + echo + else + curl --location "$registry_super_url"+/subscribers/register \ + --header 'Content-Type: application/json' \ + --data "$element" + echo + fi done echo "Merging Multiple Registries into a Super Registry Done ..." else echo "No registry URLs entered." fi + if [ "$merging_network" = "2" ]; then echo "Merging Multiple Registries into a Super Registry" else echo "Invalid option. Please restart the script and select a valid option." From 22903fd5d2fb8d34a09c50e669a12e15cd83dcda Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Wed, 29 May 2024 15:09:01 +0530 Subject: [PATCH 084/102] Fixed option bug --- install/beckn-onix.sh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/install/beckn-onix.sh b/install/beckn-onix.sh index f3399c8..8850c51 100755 --- a/install/beckn-onix.sh +++ b/install/beckn-onix.sh @@ -345,15 +345,24 @@ read -p "Enter your choice: " choice boldGreen="\e[1m\e[92m" reset="\e[0m" - if [[ $choice -eq 3 ]]; then + echo "Installing all components on the local machine" + install_package + install_registry + install_gateway + install_bap_protocol_server + install_bpp_protocol_server_with_sandbox +elif [[ $choice -eq 4 ]]; then echo "Determining the platforms available based on the initial choice" + mergingNetworks +else + # Determine the platforms available based on the initial choice platforms=("Gateway" "BAP" "BPP") [ "$choice" -eq 2 ] && platforms=("Registry" "${platforms[@]}") # Add Registry for new network setups echo "Great choice! Get ready." echo -e "\nWhich platform would you like to set up?" - for i in "${!platforms[@]}"; do + for i in "${!platforms[@]}"; do echo "$((i+1)). ${platforms[$i]}" done @@ -367,12 +376,11 @@ if [[ $choice -eq 3 ]]; then echo "Invalid option. Please restart the script and select a valid option." exit 1 fi -elif [[ $choice -eq 4 ]]; then - echo "Determining the platforms available based on the initial choice" - mergingNetworks - fi echo "Process complete. Thank you for using Beckn-ONIX!" +echo "Process complete. Thank you for using Beckn-ONIX!" + + From 42a5e47feaf306b3f51e120105e1a83b60a8d0ef Mon Sep 17 00:00:00 2001 From: Venkatesh Babu <154209057+vbabuEM@users.noreply.github.com> Date: Tue, 11 Jun 2024 13:15:12 +0530 Subject: [PATCH 085/102] Update user_guide.md with upgrade instructions --- docs/user_guide.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/user_guide.md b/docs/user_guide.md index 5045b7a..26aabaf 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -15,6 +15,7 @@ - [Connecting BAP Beckn Adapter to BAP Software](#connecting-bap-beckn-adapter-to-bapbuyer-side-software) - [Connecting BPP Beckn Adapter to BPP Software](#connecting-bpp-beckn-adapter-to-bppseller-side-software) - [Running Beckn-ONIX locally](#running-beckn-onix-locally) +- [Upgrading to a new version](#upgrading-to-a-new-version) - [Appendix A - subdomain/domain name configuration](#appendix-a---registering-or-adding-domain-or-subdomains) - [Appendix B - Nginx reverse proxy configuration](#appendix-b---nginx-reverse-proxy-configuration) @@ -242,6 +243,15 @@ Refer to the [core specification](https://github.com/beckn/protocol-specificatio - In order for people new to Beckn who want to try out Beckn on their own machine, choose the option to "Set up a network on your local machine" in the main screen. The all in one installation has preconfigured values for variables and so pretty much does not ask for any input. +## Upgrading to a new version +- The following commands illustrate upgrade of the docker image for Protocol Server (here BPP). Use similar process for other components + +``` +docker compose -f docker-compose-bpp.yml down +docker rmi fidedocker/protocol-server +docker compose -f docker-compose-bpp.yml up -d +``` + ## Appendix A - Registering or adding domain or subdomains All the components of Beckn network need to be publicly accessible. Using domain names for them is the easiest. There are two options for domain names. One is a separate domain name for each component(e.g. registrybp.io). Second is to use subdomains for the individual componetns (e.g. onix-registry.becknprotocol.io , onix-gateway.becknprotocol.io etc). Which one of these two to use depends on the business requirement. For example if an organization is the network facilitator, they might go for a domain name for the registry instead of subdomain. In the examples given above we have primarily used subdomain approach. From 603629e02bbd141a52cae018686c02fd2a35675d Mon Sep 17 00:00:00 2001 From: Mishalabdullah Date: Sun, 23 Jun 2024 11:50:33 +0530 Subject: [PATCH 086/102] realese notes and contributor info update --- docs/release_notes.md | 33 +++++++++++++++++++++++++++++++-- onix-gui/GUI/README.md | 5 ++--- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/docs/release_notes.md b/docs/release_notes.md index cfa3b35..7b98660 100644 --- a/docs/release_notes.md +++ b/docs/release_notes.md @@ -8,11 +8,41 @@ Experience the convenience and efficiency of Beckn-ONIX as you embark on your jo | Version | Release Date | | -------------------------------------------- | ------------ | +| [v0.4.1](#beckn-onix-version-041-2024-06-22) | 2024-06-22 | | [v0.4.0](#beckn-onix-version-040-2024-05-06) | 2024-05-06 | | [v0.3.0](#beckn-onix-version-030-2024-03-20) | 2024-03-20 | | [v0.2.0](#beckn-onix-version-020-2024-03-01) | 2024-03-01 | | [v0.1.0](#beckn-onix-version-010-2024-02-16) | 2024-02-16 | +## Beckn-ONIX Version 0.4.1 (2024-06-22) + +- This release adds a new feature for in CLI where its will be able to merge multiple registries. + +### New Features + +- Merging registry A to registry B +- Creting a new super-registry from multiple registries. + +### Enhancements + +- None + +### Bug fixes + +- None + +### Limitations + +- None + +### Upcoming Version + +- GUI support for the Merging feature. + +### Release date + +2024-06-22 + ## Beckn-ONIX Version 0.4.0 (2024-05-06) - This release adds a new browser based GUI for installing Beckn network components @@ -156,8 +186,7 @@ This release is specifically tailored for deployment on Linux machines, encompas ### Limitations -- The current installer is tested only for Linux (Ubuntu), it might support other flavors also. -- The current version installs all the components with the default configurations. +- None ### Upcoming Version diff --git a/onix-gui/GUI/README.md b/onix-gui/GUI/README.md index 26cf942..14ab8e1 100644 --- a/onix-gui/GUI/README.md +++ b/onix-gui/GUI/README.md @@ -42,7 +42,6 @@ Contributions are welcome! If you'd like to contribute to the beckn-onix-gui pro The beckn-onix-gui project is licensed under the MIT License. See the LICENSE file for more information. - ## Contact If you have any questions or issues with the beckn-onix-gui project, please don't hesitate to reach out. @@ -50,8 +49,8 @@ If you have any questions or issues with the beckn-onix-gui project, please don' ### Made with ❤️ built by the [Mulearn Team](https://mulearn.org/) + 1. [Mishal Abdullah](https://github.com/Mishalabdullah/) 2. [Aswin Asok](https://github.com/AswinAsok) 3. [Viraj Prabhu ](https://github.com/viraka) -4. [Adasrsh](https://adarshmohanks.framer.website/) - +4. [Adarsh Mohan](https://www.linkedin.com/in/adarshmohanks/) From 1c9711ba8ff56e00f74c6e79c7287cc77d48fcbb Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Tue, 2 Jul 2024 08:56:55 +0530 Subject: [PATCH 087/102] Added reverse proxy configuration diagram --- docs/images/reverse_proxy_configuration.png | Bin 0 -> 48422 bytes docs/{ => notes}/sample_nginx_configurations.md | 4 +++- docs/setup_walkthrough.md | 9 ++++++++- docs/user_guide.md | 7 ++++++- 4 files changed, 17 insertions(+), 3 deletions(-) create mode 100644 docs/images/reverse_proxy_configuration.png rename docs/{ => notes}/sample_nginx_configurations.md (98%) diff --git a/docs/images/reverse_proxy_configuration.png b/docs/images/reverse_proxy_configuration.png new file mode 100644 index 0000000000000000000000000000000000000000..144df8525740c83ea976613b647fb2c83154b6f2 GIT binary patch literal 48422 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 SDp8OEE)U#Zx7#iOss913-cZp1 literal 0 HcmV?d00001 diff --git a/docs/sample_nginx_configurations.md b/docs/notes/sample_nginx_configurations.md similarity index 98% rename from docs/sample_nginx_configurations.md rename to docs/notes/sample_nginx_configurations.md index 66fc99f..03d191e 100644 --- a/docs/sample_nginx_configurations.md +++ b/docs/notes/sample_nginx_configurations.md @@ -1,6 +1,8 @@ # Nginx sample configuration for the different components -This document lists the various Nginx configuration sample files used in the demo. These use the URLs used as example in the user guide and demo walkthrough. These can be used as a reference. +This document lists the various Nginx configuration sample files used in the demo. These use the URLs used as example in the user guide and demo walkthrough. These can be used as a reference. This diagram illustrates the proxy_pass configuration (which is the primary part required) of all the nodes. If you know reverse proxy configuration, this diagram is all you need and you can ignore the rest of this page. + +![Reverse Proxy Configuration](../images/reverse_proxy_configuration.png) ## Nginx sample configuration for Registry diff --git a/docs/setup_walkthrough.md b/docs/setup_walkthrough.md index 26f209c..eedcbe5 100644 --- a/docs/setup_walkthrough.md +++ b/docs/setup_walkthrough.md @@ -17,7 +17,12 @@ For the sake of illustration, all the urls are shown as subdomains of becknproto Some of the outputs listed below might be different when you run the script for the first time. The output depends on whether the required docker containers are present in the machine or not. -Note: Due to a [known issue](https://github.com/beckn/beckn-onix/issues/11), on certain machines, when the script is run for the first time, it errors out complaining about permission error in accessing docker daemon. Till this issue is fixed, the work around is to exit the terminal and restart the installation in a new terminal. +Run the following two commands on all machines where the script is being run for the first time. Login to a new shell for the command to take effect and continue with the installation. Not doing so will result in docker permisssion error + +``` +sudo groupadd docker +sudo usermod -aG docker $USER +``` Please refer to the [Beckn-ONIX User Guide](./user_guide.md) for detailed explanation of the below steps. @@ -48,6 +53,8 @@ The following diagram shows a conceptual view of a multi-node Bekn network that - https://onix-bpp-client.becknprotocol.io to port 6001 on the machine - https://onix-bpp.becknprotocol.io to port 6002 on the machine +![Reverse Proxy Configuration Illustrated](./images/reverse_proxy_configuration.png) + - This guide assumes you have a marketplace or a headless store and want to set it up to work with the Beckn network. It is still useful for people who are developing the buyer side software and want to set it up with the network. In such cases a [sandbox](https://github.com/beckn/beckn-sandbox) might be required to mimic a marketplace or a headless shop. ## Create a new network and install the registry diff --git a/docs/user_guide.md b/docs/user_guide.md index 26aabaf..fe2060a 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -40,6 +40,10 @@ The following diagram shows a conceptual view of a multi-node Beckn network. The ![Typical deployment](./images/sample_deployment.png) +The following diagram shows the reverse proxy configuration (referred to also in the individual installations below) using the URLs used in the examples. Refer to this diagram during the reverse proxy configuration steps. + +![Reverse Proxy Configuration](./images/reverse_proxy_configuration.png) + **Use of docker and reference implementations** Docker compose and docker are extensively used in the installation and running of the various component software. Similarly the Beckn-ONIX installer, itself being a reference implementation, installs the reference implentation of the Beckn Adapter for the BAP and BPP, reference implementation of the registry and gateway. In order to interact with the internals of these components, we will need to enter the container. Familiarity with Docker will be useful in working with the installation. To list the running containers use `docker ps`. Similarly for example to connect to a container and browse it using shell, use `docker exec -it bap-client sh` @@ -244,6 +248,7 @@ Refer to the [core specification](https://github.com/beckn/protocol-specificatio - In order for people new to Beckn who want to try out Beckn on their own machine, choose the option to "Set up a network on your local machine" in the main screen. The all in one installation has preconfigured values for variables and so pretty much does not ask for any input. ## Upgrading to a new version + - The following commands illustrate upgrade of the docker image for Protocol Server (here BPP). Use similar process for other components ``` @@ -288,4 +293,4 @@ In the role of reverse proxy, Nginx will forward communication that came on a pa [This document](https://docs.nginx.com/nginx/admin-guide/web-server/reverse-proxy/) explains the configuration of reverse proxy using proxy_pass -You can find sample Nginx configuration for the Registry, Gateway, BAP and BPP [here](./sample_nginx_configurations.md) +You can find sample Nginx configuration for the Registry, Gateway, BAP and BPP [here](./notes/sample_nginx_configurations.md) From 97fe2a93279e65e8c28ab02351fe0c80955d9f18 Mon Sep 17 00:00:00 2001 From: Ravi Prakash Date: Thu, 4 Jul 2024 17:43:37 +0530 Subject: [PATCH 088/102] Update README.md Added disclaimer --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 47d7a0c..7b55a96 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,8 @@ Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. This effort is also aimed at inviting contributions from the community to create secure, reliable builds for production environments. +> Disclaimer : Beckn-onix is a reference implementation of the Beckn-onix stack. It is a reference application only and has not been tested for production environmens. However, implementers can fork this repository and build it for scale. The maintainer of this repository holds no liabillity for deployments of this application in production environments. + ## GUI Installer There is a community contributed browser based GUI installer to install multi-node reference implementation Beckn network. Refer to the [Installation Guide](./onix-gui/GUI/README.md) and [wizard guide](./onix-gui/README.md) for details. From 934e7494801c12ca7803b78e578a0b2699103991 Mon Sep 17 00:00:00 2001 From: MishalAbdullah <85678545+Mishalabdullah@users.noreply.github.com> Date: Sat, 13 Jul 2024 04:24:12 +0530 Subject: [PATCH 089/102] Update README.md --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index 7b55a96..581d39c 100644 --- a/README.md +++ b/README.md @@ -8,10 +8,21 @@ Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and mainta There is a community contributed browser based GUI installer to install multi-node reference implementation Beckn network. Refer to the [Installation Guide](./onix-gui/GUI/README.md) and [wizard guide](./onix-gui/README.md) for details. +Here is a [Demo Video](https://www.youtube.com/watch?v=98mU3OQxbqQ) on how to use beckn-onix GUI: + +[![Beckn Onix GUI](https://img.youtube.com/vi/98mU3OQxbqQ/0.jpg)](https://www.youtube.com/watch?v=98mU3OQxbqQ) + + ## CLI Installer For those comfortable with CLI, there is a command line installer to install multi-node reference implementation Beckn network. Refer to the [User Guide](./docs/user_guide.md) and [Setup Walkthrough](./docs/setup_walkthrough.md) for details. +Here is a [Demo Video](https://youtu.be/eyFgQJgGHig) on how to use beckn-onix CLI: + +[![Beckn Onix CLI](https://img.youtube.com/vi/eyFgQJgGHig/0.jpg)](https://youtu.be/eyFgQJgGHig) + + + ## Other documents - [Release Notes](./docs/release_notes.md) From f6bc11bec57f6e254b5dec283da463826e3f07ff Mon Sep 17 00:00:00 2001 From: MishalAbdullah <85678545+Mishalabdullah@users.noreply.github.com> Date: Mon, 15 Jul 2024 14:34:31 +0530 Subject: [PATCH 090/102] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 581d39c..330ece2 100644 --- a/README.md +++ b/README.md @@ -8,18 +8,18 @@ Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and mainta There is a community contributed browser based GUI installer to install multi-node reference implementation Beckn network. Refer to the [Installation Guide](./onix-gui/GUI/README.md) and [wizard guide](./onix-gui/README.md) for details. -Here is a [Demo Video](https://www.youtube.com/watch?v=98mU3OQxbqQ) on how to use beckn-onix GUI: +Here is a [Demo Video](https://drive.google.com/file/d/1p1c1N9vCj-Rv0kBAsRIQ-KFfORTc1DjJ/view?usp=sharing) on how to use beckn-onix GUI: -[![Beckn Onix GUI](https://img.youtube.com/vi/98mU3OQxbqQ/0.jpg)](https://www.youtube.com/watch?v=98mU3OQxbqQ) +[![Beckn Onix GUI](https://mishalabdullah.xyz/images/beckn-cli-youtube.png)](https://drive.google.com/file/d/1p1c1N9vCj-Rv0kBAsRIQ-KFfORTc1DjJ/view?usp=sharing) ## CLI Installer For those comfortable with CLI, there is a command line installer to install multi-node reference implementation Beckn network. Refer to the [User Guide](./docs/user_guide.md) and [Setup Walkthrough](./docs/setup_walkthrough.md) for details. -Here is a [Demo Video](https://youtu.be/eyFgQJgGHig) on how to use beckn-onix CLI: +Here is a [Demo Video](https://drive.google.com/file/d/1PfdhIpq-Qo6sDy0wAnO0zllCMGX718FW/view?usp=sharing) on how to use beckn-onix CLI: -[![Beckn Onix CLI](https://img.youtube.com/vi/eyFgQJgGHig/0.jpg)](https://youtu.be/eyFgQJgGHig) +[![Beckn Onix CLI](https://mishalabdullah.xyz/images/beckn-gui-youtube.png)](https://drive.google.com/file/d/1PfdhIpq-Qo6sDy0wAnO0zllCMGX718FW/view?usp=sharing) From d232bdad34a0b49afef9dfd5773ac5f4b1b304d2 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Wed, 17 Jul 2024 15:05:58 +0530 Subject: [PATCH 091/102] fix(docker): specify platform in docker-compose.yml --- install/docker-compose-bap.yml | 2 ++ install/docker-compose-bpp-with-sandbox.yml | 3 +++ install/docker-compose-bpp.yml | 2 ++ install/docker-compose-gateway.yml | 1 + install/docker-compose-gcl.yml | 8 ++++++++ install/docker-compose-registry.yml | 1 + install/docker-compose-v2.yml | 8 ++++++++ 7 files changed, 25 insertions(+) diff --git a/install/docker-compose-bap.yml b/install/docker-compose-bap.yml index 5c9e83b..d9bb6a8 100644 --- a/install/docker-compose-bap.yml +++ b/install/docker-compose-bap.yml @@ -2,6 +2,7 @@ services: bap-client: image: fidedocker/protocol-server container_name: bap-client + platform: linux/amd64 networks: - beckn_network ports: @@ -15,6 +16,7 @@ services: bap-network: image: fidedocker/protocol-server container_name: bap-network + platform: linux/amd64 networks: - beckn_network ports: diff --git a/install/docker-compose-bpp-with-sandbox.yml b/install/docker-compose-bpp-with-sandbox.yml index 3b8dcc8..cd242d1 100644 --- a/install/docker-compose-bpp-with-sandbox.yml +++ b/install/docker-compose-bpp-with-sandbox.yml @@ -2,6 +2,7 @@ services: bpp-client: image: fidedocker/protocol-server container_name: bpp-client + platform: linux/amd64 networks: - beckn_network ports: @@ -15,6 +16,7 @@ services: bpp-network: image: fidedocker/protocol-server container_name: bpp-network + platform: linux/amd64 networks: - beckn_network ports: @@ -28,6 +30,7 @@ services: sandbox-api: image: fidedocker/sandbox-api container_name: sandbox-api + platform: linux/amd64 networks: - beckn_network ports: diff --git a/install/docker-compose-bpp.yml b/install/docker-compose-bpp.yml index 2747275..5282b8b 100644 --- a/install/docker-compose-bpp.yml +++ b/install/docker-compose-bpp.yml @@ -2,6 +2,7 @@ services: bpp-client: image: fidedocker/protocol-server container_name: bpp-client + platform: linux/amd64 networks: - beckn_network ports: @@ -15,6 +16,7 @@ services: bpp-network: image: fidedocker/protocol-server container_name: bpp-network + platform: linux/amd64 networks: - beckn_network ports: diff --git a/install/docker-compose-gateway.yml b/install/docker-compose-gateway.yml index 96322dc..0c2a3f7 100644 --- a/install/docker-compose-gateway.yml +++ b/install/docker-compose-gateway.yml @@ -2,6 +2,7 @@ services: gateway: image: fidedocker/gateway container_name: gateway + platform: linux/amd64 networks: - beckn_network ports: diff --git a/install/docker-compose-gcl.yml b/install/docker-compose-gcl.yml index 67ba486..aa0953c 100644 --- a/install/docker-compose-gcl.yml +++ b/install/docker-compose-gcl.yml @@ -2,6 +2,7 @@ services: registry: image: fidedocker/registry container_name: registry + platform: linux/amd64 networks: - beckn_network ports: @@ -15,6 +16,7 @@ services: gateway: image: fidedocker/gateway container_name: gateway + platform: linux/amd64 networks: - beckn_network ports: @@ -28,6 +30,7 @@ services: bap-client: image: fidedocker/protocol-server container_name: bap-client + platform: linux/amd64 networks: - beckn_network ports: @@ -39,6 +42,7 @@ services: bap-network: image: fidedocker/protocol-server container_name: bap-network + platform: linux/amd64 networks: - beckn_network ports: @@ -50,6 +54,7 @@ services: sandbox-api: image: fidedocker/sandbox-api container_name: sandbox-api + platform: linux/amd64 networks: - beckn_network ports: @@ -61,6 +66,7 @@ services: bpp-client: image: fidedocker/protocol-server container_name: bpp-client + platform: linux/amd64 networks: - beckn_network ports: @@ -72,6 +78,7 @@ services: bpp-network: image: fidedocker/protocol-server container_name: bpp-network + platform: linux/amd64 networks: - beckn_network ports: @@ -83,6 +90,7 @@ services: generic-client-layer: image: fidedocker/generic-client-layer container_name: generic-client-layer + platform: linux/amd64 networks: - beckn_network ports: diff --git a/install/docker-compose-registry.yml b/install/docker-compose-registry.yml index a07d43f..21cc8e8 100644 --- a/install/docker-compose-registry.yml +++ b/install/docker-compose-registry.yml @@ -2,6 +2,7 @@ services: registry: image: fidedocker/registry container_name: registry + platform: linux/amd64 networks: - beckn_network ports: diff --git a/install/docker-compose-v2.yml b/install/docker-compose-v2.yml index 67ba486..aa0953c 100644 --- a/install/docker-compose-v2.yml +++ b/install/docker-compose-v2.yml @@ -2,6 +2,7 @@ services: registry: image: fidedocker/registry container_name: registry + platform: linux/amd64 networks: - beckn_network ports: @@ -15,6 +16,7 @@ services: gateway: image: fidedocker/gateway container_name: gateway + platform: linux/amd64 networks: - beckn_network ports: @@ -28,6 +30,7 @@ services: bap-client: image: fidedocker/protocol-server container_name: bap-client + platform: linux/amd64 networks: - beckn_network ports: @@ -39,6 +42,7 @@ services: bap-network: image: fidedocker/protocol-server container_name: bap-network + platform: linux/amd64 networks: - beckn_network ports: @@ -50,6 +54,7 @@ services: sandbox-api: image: fidedocker/sandbox-api container_name: sandbox-api + platform: linux/amd64 networks: - beckn_network ports: @@ -61,6 +66,7 @@ services: bpp-client: image: fidedocker/protocol-server container_name: bpp-client + platform: linux/amd64 networks: - beckn_network ports: @@ -72,6 +78,7 @@ services: bpp-network: image: fidedocker/protocol-server container_name: bpp-network + platform: linux/amd64 networks: - beckn_network ports: @@ -83,6 +90,7 @@ services: generic-client-layer: image: fidedocker/generic-client-layer container_name: generic-client-layer + platform: linux/amd64 networks: - beckn_network ports: From 1dfff1528a5277cf2a5ad502bb331e347c5d2407 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Thu, 18 Jul 2024 15:43:12 +0530 Subject: [PATCH 092/102] Fixed sign up issue for registry --- install/registry_data/config/swf.properties-sample | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/install/registry_data/config/swf.properties-sample b/install/registry_data/config/swf.properties-sample index 3e2b112..1506f09 100644 --- a/install/registry_data/config/swf.properties-sample +++ b/install/registry_data/config/swf.properties-sample @@ -2,8 +2,7 @@ swf.load.complete.config.tables.if.count.less.than=500 swf.user.password.encrypted=false swf.plugins.background.core.workers.numThreads=3 swf.application.authentication.required=false - - +swf.application.requires.registration=true #swf.host=localhost swf.host=REGISTRY_URL From 0dc5e8175b130093da554d10bce1702c48df4ddb Mon Sep 17 00:00:00 2001 From: Venkatesh Babu <154209057+vbabuEM@users.noreply.github.com> Date: Sun, 21 Jul 2024 20:35:11 +0530 Subject: [PATCH 093/102] Update user_guide.md with instructions for mac --- docs/user_guide.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/user_guide.md b/docs/user_guide.md index fe2060a..7aadfcb 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -246,6 +246,7 @@ Refer to the [core specification](https://github.com/beckn/protocol-specificatio ## Running Beckn-ONIX locally - In order for people new to Beckn who want to try out Beckn on their own machine, choose the option to "Set up a network on your local machine" in the main screen. The all in one installation has preconfigured values for variables and so pretty much does not ask for any input. +- In order to run the installation on a Macintosh computer, run the following command in the terminal where you run the install before you start the installation. `export DOCKER_DEFAULT_PLATFORM=linux/amd64`. Ensure you close the terminal after installation, so this setting does not affect other docker containers you might install. ## Upgrading to a new version From f9311d439a9ff09ca00f6511f169f808dbc600ce Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Tue, 13 Aug 2024 09:58:32 +0530 Subject: [PATCH 094/102] Fixed 178: Layer 2 check is enabled --- install/protocol-server-data/bap-network.yaml-sample | 5 ++++- install/protocol-server-data/bpp-network.yaml-sample | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/install/protocol-server-data/bap-network.yaml-sample b/install/protocol-server-data/bap-network.yaml-sample index 1af96fd..8ed78c1 100644 --- a/install/protocol-server-data/bap-network.yaml-sample +++ b/install/protocol-server-data/bap-network.yaml-sample @@ -130,4 +130,7 @@ app: batchSize: 100 # In minutes syncInterval: 30 - redis_db: 3 \ No newline at end of file + redis_db: 3 + + useLayer2Config: USE_LAYER_2_CONFIG + mandateLayer2Config: MANDATE_LAYER_2_CONFIG \ No newline at end of file diff --git a/install/protocol-server-data/bpp-network.yaml-sample b/install/protocol-server-data/bpp-network.yaml-sample index b837568..ce7623b 100644 --- a/install/protocol-server-data/bpp-network.yaml-sample +++ b/install/protocol-server-data/bpp-network.yaml-sample @@ -128,4 +128,7 @@ app: batchSize: 100 # In minutes syncInterval: 30 - redis_db: 3 \ No newline at end of file + redis_db: 3 + + useLayer2Config: USE_LAYER_2_CONFIG + mandateLayer2Config: MANDATE_LAYER_2_CONFIG \ No newline at end of file From 2d8c8dbc6d07f3bb8247e9444139b8e03b7b0bf5 Mon Sep 17 00:00:00 2001 From: Venkatesh Babu <154209057+vbabuEM@users.noreply.github.com> Date: Wed, 21 Aug 2024 11:41:18 +0530 Subject: [PATCH 095/102] Update user_guide.md --- docs/user_guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/user_guide.md b/docs/user_guide.md index 7aadfcb..6d7a574 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -138,8 +138,8 @@ The BPP (Beckn Provider Platform) is the bridge between the seller side applicat - A domain or subdomain where the network endpoint of BPP will be accessible (e.g. https://onix-bpp.becknprtocol.io) - A virtual server with both the above mentioned domains/subdomains pointing to it. Refer [Appendix A](#appendix-a---registering-or-adding-domain-or-subdomains) for details - SSL certificate for the two endpoints and configured in Nginx. Refer [Appendix B](#ssl-certificates-configured-in-reverse-proxy) -- Reverse proxy configured to route the traffic at the bap client url (e.g. https://onix-bpp-client.becknprotocol.io) to port 6001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) -- Reverse proxy configured to route the traffic at the bap network url (e.g. https://onix-bpp.becknprotocol.io) to port 6002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bpp client url (e.g. https://onix-bpp-client.becknprotocol.io) to port 6001. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) +- Reverse proxy configured to route the traffic at the bpp network url (e.g. https://onix-bpp.becknprotocol.io) to port 6002. Refer [Appendix B](#configuring-nginx-reverse-proxy-using-proxy-pass) **Installation Steps** From 940bf6a76815c10b9db7c28aac4ec057c824dff5 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Mon, 26 Aug 2024 14:18:28 +0530 Subject: [PATCH 096/102] Add OS-specific Docker installation --- install/scripts/package_manager.sh | 66 +++++++++++++++++++----------- 1 file changed, 43 insertions(+), 23 deletions(-) diff --git a/install/scripts/package_manager.sh b/install/scripts/package_manager.sh index df49060..b510879 100755 --- a/install/scripts/package_manager.sh +++ b/install/scripts/package_manager.sh @@ -19,42 +19,49 @@ install_package() { if [ -x "$(command -v apt-get)" ]; then # APT (Debian/Ubuntu) if [ "$1" == "docker" ]; then - docker > /dev/null 2>&1 - if [ $? -ne 0 ]; then - curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg - echo "deb [signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + if ! docker --version > /dev/null 2>&1; then + if [ -f /etc/debian_version ]; then + curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + else + curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg + echo "deb [signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null + fi sudo apt update >/dev/null 2>&1 sudo apt install -y docker-ce docker-ce-cli containerd.io >/dev/null 2>&1 sudo usermod -aG docker $USER source ~/.bashrc - command_exists docker - if [ $? -eq 0 ]; then - sleep 10 - sudo systemctl enable docker.service - sudo systemctl restart docker.service - fi + sudo systemctl enable docker.service + sudo systemctl restart docker.service else echo "Docker is already installed." fi else if ! dpkg -l | grep -q "^ii $1 "; then sudo apt-get update >/dev/null 2>&1 - sudo apt-get install -y $1 > /dev/null 2>&1 + sudo apt-get install -y $1 >/dev/null 2>&1 else echo "$1 is already installed." fi fi elif [ -x "$(command -v yum)" ]; then - # YUM (Red Hat/CentOS) + # YUM (Red Hat/CentOS/Amazon Linux) if [ "$1" == "docker" ]; then - if ! rpm -qa | grep -q docker-ce; then - sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo - # Install Docker - sudo yum install -y docker >/dev/null 2>&1 - sudo systemctl enable docker.service - sudo systemctl start docker.service + if ! docker --version > /dev/null 2>&1; then + if [ -f /etc/centos-release ]; then + sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo + elif [ -f /etc/redhat-release ]; then + sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo + elif grep -q "Amazon Linux release 2" /etc/system-release; then + sudo amazon-linux-extras install docker -y + elif grep -q "Amazon Linux release" /etc/system-release; then + sudo yum install -y docker + fi + sudo yum install -y docker-ce docker-ce-cli containerd.io >/dev/null 2>&1 sudo usermod -aG docker $USER source ~/.bashrc + sudo systemctl enable docker.service + sudo systemctl restart docker.service else echo "Docker is already installed." fi @@ -66,19 +73,32 @@ install_package() { fi fi elif [ -x "$(command -v amazon-linux-extras)" ]; then - # Amazon Linux 2 - if ! amazon-linux-extras list | grep -q "^$1 "; then - sudo amazon-linux-extras install $1 >/dev/null 2>&1 + # Amazon Linux 2 specific + if [ "$1" == "docker" ]; then + if ! docker --version > /dev/null 2>&1; then + sudo amazon-linux-extras install docker -y >/dev/null 2>&1 + sudo systemctl enable docker.service + sudo systemctl start docker.service + sudo usermod -aG docker $USER + source ~/.bashrc + else + echo "Docker is already installed." + fi else - echo "$1 is already installed." + if ! amazon-linux-extras list | grep -q "$1"; then + sudo amazon-linux-extras install $1 -y >/dev/null 2>&1 + else + echo "$1 is already installed." + fi fi else - echo "${RED}Unsupported package manager. Please install $1 manually.${NC}" + echo "Unsupported package manager. Please install $1 manually." exit 1 fi } + remove_package(){ if [ -x "$(command -v apt-get)" ]; then # APT (Debian/Ubuntu) From de8764e8699ab197cf787d009bdeece88e21a760 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds Date: Tue, 27 Aug 2024 18:32:32 +0530 Subject: [PATCH 097/102] Updated document with Supported OS details --- docs/user_guide.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/user_guide.md b/docs/user_guide.md index 6d7a574..19aa960 100644 --- a/docs/user_guide.md +++ b/docs/user_guide.md @@ -49,8 +49,10 @@ Docker compose and docker are extensively used in the installation and running o ### Overall Pre-requisites +- OS supported and test Beckn-ONIX installer are Ubuntu (20.04, 22.04 and 24.04), Debian (12), Amazon Linux 2, Windows with WSL support and MacOS. - Atleast four virtual servers (EC2 instances) configured on the cloud provider with administrator login (e.g. ssh access) to them. - Access to domain name management with ability to create domain-name/subdomains for each of the components. +- Latest docker version. - Run the following two commands on all machines where the script is being run for the first time. Login to a new shell for the command to take effect and continue with the installation. Not doing so will result in docker permisssion error ``` From 67eab33bf0c3a8fb2d523a1fade1235c0837fa86 Mon Sep 17 00:00:00 2001 From: prasad-takale-eminds <84436945+prasad-takale-eminds@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:26:02 +0530 Subject: [PATCH 098/102] Create .gitignore --- aws-cdk/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 aws-cdk/.gitignore diff --git a/aws-cdk/.gitignore b/aws-cdk/.gitignore new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/aws-cdk/.gitignore @@ -0,0 +1 @@ + From 7f4a3f826308c09928aa9dde1b43643a766a30a6 Mon Sep 17 00:00:00 2001 From: Ankit Brahmbhatt Date: Mon, 9 Sep 2024 19:00:31 +0530 Subject: [PATCH 099/102] Troubleshooting links added to readme file --- README.md | 2 ++ install/gateway_data/config/networks/onix.json | 10 +++++----- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 330ece2..c440a09 100644 --- a/README.md +++ b/README.md @@ -28,5 +28,7 @@ Here is a [Demo Video](https://drive.google.com/file/d/1PfdhIpq-Qo6sDy0wAnO0zllC - [Release Notes](./docs/release_notes.md) - [Frequently asked questions (FAQ)](./docs/faq.md) - **[Note on mandatory layer 2 configuration(Important)](./docs/notes/mandatory_layer_2_config.md).** +- **[Troubleshooting doc](https://github.com/beckn/missions/blob/main/docs/troubleshoot.md).** +- **[Log Interpretation](https://github.com/beckn/missions/blob/main/docs/log-interpretation.md).** Experience the convenience and efficiency of Beckn-ONIX as you embark on your journey with Beckn protocols and open networks. diff --git a/install/gateway_data/config/networks/onix.json b/install/gateway_data/config/networks/onix.json index 2bb446a..f3190b7 100644 --- a/install/gateway_data/config/networks/onix.json +++ b/install/gateway_data/config/networks/onix.json @@ -1,11 +1,11 @@ { "core_version" : "1.1.0", - "registry_id": "registry-dev.becknprotocol.io..LREG", - "search_provider_id" : "gateway-dev.becknprotocol.io", + "registry_id": "registry..LREG", + "search_provider_id" : "gateway", "self_registration_supported": true, "subscription_needed_post_registration" : true, - "base_url": "https://registry-dev.becknprotocol.io", - "registry_url" : "https://registry-dev.becknprotocol.io/subscribers", + "base_url": "http://registry:3030", + "registry_url" : "http://registry:3030/subscribers", "extension_package": "in.succinct.beckn.boc", "wild_card" : "" -} \ No newline at end of file +} From 28766bec191ce3a499e4051879d9746474e3218e Mon Sep 17 00:00:00 2001 From: Ankit Brahmbhatt Date: Mon, 9 Sep 2024 19:04:11 +0530 Subject: [PATCH 100/102] onix json file corrected --- install/gateway_data/config/networks/onix.json | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/install/gateway_data/config/networks/onix.json b/install/gateway_data/config/networks/onix.json index f3190b7..2bb446a 100644 --- a/install/gateway_data/config/networks/onix.json +++ b/install/gateway_data/config/networks/onix.json @@ -1,11 +1,11 @@ { "core_version" : "1.1.0", - "registry_id": "registry..LREG", - "search_provider_id" : "gateway", + "registry_id": "registry-dev.becknprotocol.io..LREG", + "search_provider_id" : "gateway-dev.becknprotocol.io", "self_registration_supported": true, "subscription_needed_post_registration" : true, - "base_url": "http://registry:3030", - "registry_url" : "http://registry:3030/subscribers", + "base_url": "https://registry-dev.becknprotocol.io", + "registry_url" : "https://registry-dev.becknprotocol.io/subscribers", "extension_package": "in.succinct.beckn.boc", "wild_card" : "" -} +} \ No newline at end of file From 9bd9911407ff6ffb6de75d450f979002a3aab93d Mon Sep 17 00:00:00 2001 From: Faiz Mohammed Date: Tue, 10 Sep 2024 12:50:40 +0530 Subject: [PATCH 101/102] aws-cdk folder and readme.md aws-cdk folder and readme.md --- aws-cdk/readme.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 aws-cdk/readme.md diff --git a/aws-cdk/readme.md b/aws-cdk/readme.md new file mode 100644 index 0000000..b2dfdc6 --- /dev/null +++ b/aws-cdk/readme.md @@ -0,0 +1 @@ +### readme for aws-cdk From 544a34acf3d59d1ff6133594fc7bdd6a4d5b4c6b Mon Sep 17 00:00:00 2001 From: Venkatesh Babu Date: Wed, 11 Sep 2024 10:44:26 +0530 Subject: [PATCH 102/102] Add known issue on Gateway restarts --- README.md | 6 ++---- docs/known_issues.md | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 docs/known_issues.md diff --git a/README.md b/README.md index 330ece2..3349ae6 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ Beckn-ONIX is [FIDE](https://fide.org/) project aimed at easing setup and maintainance of a [Beckn](https://becknprotocol.io/) Network using reference implementations. Objectives include setting up reliable, configurable and fast Beckn network as a virtual appliance. This initiative is independent of the evolution of the Beckn protocol. This effort is also aimed at inviting contributions from the community to create secure, reliable builds for production environments. -> Disclaimer : Beckn-onix is a reference implementation of the Beckn-onix stack. It is a reference application only and has not been tested for production environmens. However, implementers can fork this repository and build it for scale. The maintainer of this repository holds no liabillity for deployments of this application in production environments. +> Disclaimer : Beckn-onix is a reference implementation of the Beckn-onix stack. It is a reference application only and has not been tested for production environmens. However, implementers can fork this repository and build it for scale. The maintainer of this repository holds no liabillity for deployments of this application in production environments. ## GUI Installer @@ -12,7 +12,6 @@ Here is a [Demo Video](https://drive.google.com/file/d/1p1c1N9vCj-Rv0kBAsRIQ-KFf [![Beckn Onix GUI](https://mishalabdullah.xyz/images/beckn-cli-youtube.png)](https://drive.google.com/file/d/1p1c1N9vCj-Rv0kBAsRIQ-KFfORTc1DjJ/view?usp=sharing) - ## CLI Installer For those comfortable with CLI, there is a command line installer to install multi-node reference implementation Beckn network. Refer to the [User Guide](./docs/user_guide.md) and [Setup Walkthrough](./docs/setup_walkthrough.md) for details. @@ -21,11 +20,10 @@ Here is a [Demo Video](https://drive.google.com/file/d/1PfdhIpq-Qo6sDy0wAnO0zllC [![Beckn Onix CLI](https://mishalabdullah.xyz/images/beckn-gui-youtube.png)](https://drive.google.com/file/d/1PfdhIpq-Qo6sDy0wAnO0zllCMGX718FW/view?usp=sharing) - - ## Other documents - [Release Notes](./docs/release_notes.md) +- [Known Issues](./docs/known_issues.md) - [Frequently asked questions (FAQ)](./docs/faq.md) - **[Note on mandatory layer 2 configuration(Important)](./docs/notes/mandatory_layer_2_config.md).** diff --git a/docs/known_issues.md b/docs/known_issues.md new file mode 100644 index 0000000..3ea1530 --- /dev/null +++ b/docs/known_issues.md @@ -0,0 +1,21 @@ +# Known issues + +## Gateway is not working after restart + +**First Reported:** +2024-07-19 + +**Problem:** +Gateway keeps on restarting on bootup. It happened after the machine was restarted. The gateway has not been updated and still it is crashing. + +**Root Cause:** +The version of Gateway that was installed prior to July 18 2024, had hard coded a short list of standard registries. This included a registry which has been decomissioned in August. The result of this is that the gateway tries to contact this decomissioned registry during bootup and since it cannot find it, crashes and restarts. This happens with older gateways even without updating the software. If the old gateway software was restarted due to whatever reason, this issue starts to show up. + +**Solution:** +Update the gateway software with the new image (built after July 18 2024). This has removed the hard code of the decomissioned registry and everything should work ok. The following is one way of updating the gateway software. Perform these on the machine that has the gateway container within the beckn-onix/install folder after updating the beckn-onix git clone. + +``` +$ docker-compose -f docker-compose-gateway.yml down +$ docker rmi fidedocker/gateway +$ docker-compose -f docker-compose-gateway.yml up --detach +```