diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f06235c --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +dist diff --git a/README.md b/README.md index e69de29..4e84434 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,58 @@ +# Request Network Injector CLI + +## Problem + +Integrating the Request Network Protocol into your application can be a complex and time-consuming process, especially for new developers. It requires understanding the protocol, setting up the necessary dependencies, and implementing various functions to interact with the network. + +## Solution + +The Request Network Injector CLI simplifies this process by automatically injecting pre-built, customizable functions into your project. This tool allows both new and experienced builders to quickly integrate the Request Network Protocol into their applications with minimal setup. + +## Features + +- Automatic injection of essential Request Network functions +- Support for both TypeScript and JavaScript projects +- Customizable function selection +- Automatic package installation +- Support for various package managers (npm, yarn, pnpm, bun) + +## How It Works + +1. The CLI analyzes your project structure +2. You select the functions you want to inject +3. You choose your preferred language (TypeScript or JavaScript) +4. The tool injects the selected functions into your project +5. Necessary dependencies are automatically installed + +## Usage + +To use the Request Network Injector CLI, follow these steps: + +1. Navigate to your project directory +2. Run the following command: + + ```shell + npx request-cli + ``` + +3. Follow the prompts to select your desired functions and configurations +4. The CLI will inject the code and install necessary dependencies + +## Available Functions + +- `prepareRequest`: Prepare the input needed to create a request +- `createRequest`: Create a new request +- `payRequest`: Pay an existing request +- `persistInMemoryRequest`: Persist in-memory requests +- `getRequestByID`: Get request data by request ID +- `getRequestsByWalletAddress`: Get requests data that belong to a wallet address + +## Benefits + +- Rapid integration of Request Network Protocol +- Reduced development time and complexity +- Customizable to fit your project needs +- Automatic setup of dependencies +- Supports multiple project configurations + +Start building with the Request Network Protocol quickly and efficiently using the Request Network Injector CLI! diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..2318153 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,831 @@ +{ + "name": "request-cli", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "request-cli", + "version": "0.0.1", + "license": "ISC", + "dependencies": { + "@clack/prompts": "^0.7.0", + "remove-types": "^1.0.0" + }, + "bin": { + "request-cli": "dist/index.js" + }, + "devDependencies": { + "@types/node": "^22.4.1", + "typescript": "^5.5.4" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.25.5", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.5.tgz", + "integrity": "sha512-abd43wyLfbWoxC6ahM8xTkqLpGB2iWBVyuKC9/srhFunCd1SDNrV1s72bBpK4hLj8KLzHBBcOblvLQZBNw9r3w==", + "dependencies": { + "@babel/types": "^7.25.4", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz", + "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", + "dependencies": { + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.25.4.tgz", + "integrity": "sha512-ro/bFs3/84MDgDmMwbcHgDa8/E6J3QKNTk4xJJnVeFtGE+tL0K26E3pNxhYz2b67fJpt7Aphw5XcploKXuCvCQ==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/helper-replace-supers": "^7.25.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/traverse": "^7.25.4", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.8.tgz", + "integrity": "sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==", + "dependencies": { + "@babel/traverse": "^7.24.8", + "@babel/types": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", + "dependencies": { + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz", + "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==", + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.25.0.tgz", + "integrity": "sha512-q688zIvQVYtZu+i2PsdIu/uWGRpfxzr5WESsfpShfZECkO+d2o+WROWezCi/Q6kJ0tfPa5+pUGUlfx2HhrA3Bg==", + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.24.8", + "@babel/helper-optimise-call-expression": "^7.24.7", + "@babel/traverse": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz", + "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==", + "dependencies": { + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.0.tgz", + "integrity": "sha512-MjgLZ42aCm0oGjJj8CtSM3DB8NOOf8h2l7DCTePJs29u+v7yO/RBX9nShlKMgFnRks/Q4tBAe7Hxnov9VkGwLw==", + "dependencies": { + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.4.tgz", + "integrity": "sha512-nq+eWrOgdtu3jG5Os4TQP3x3cLA8hR8TvJNjD8vnPa20WGycimcparWnLK4jJhElTK6SDyuJo1weMKO/5LpmLA==", + "dependencies": { + "@babel/types": "^7.25.4" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-decorators": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.24.7.tgz", + "integrity": "sha512-Ui4uLJJrRV1lb38zg1yYTmRKmiZLiftDEvZN2iq3kd9kUFU+PttmzTbAFC2ucRk/XJmtek6G23gPsuZbhrT8fQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz", + "integrity": "sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.25.2.tgz", + "integrity": "sha512-lBwRvjSmqiMYe/pS0+1gggjJleUJi7NzjvQ1Fkqtt69hBa/0t1YuW/MLQMAPixfwaQOHUXsd6jeU3Z+vdGv3+A==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.24.7", + "@babel/helper-create-class-features-plugin": "^7.25.0", + "@babel/helper-plugin-utils": "^7.24.8", + "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7", + "@babel/plugin-syntax-typescript": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.4.tgz", + "integrity": "sha512-VJ4XsrD+nOvlXyLzmLzUs/0qjFS4sK30te5yEFlvbbUNEgKaVb2BHZUpAL+ttLPQAHNrsI3zZisbfha5Cvr8vg==", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.4", + "@babel/parser": "^7.25.4", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.4", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.4.tgz", + "integrity": "sha512-zQ1ijeeCXVEh+aNL0RlmkPkG8HUiDcU2pzQQFjtbntgAczRASFzj4H+6+bV+dy1ntKR14I/DypeuRG1uma98iQ==", + "dependencies": { + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@clack/core": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.3.4.tgz", + "integrity": "sha512-H4hxZDXgHtWTwV3RAVenqcC4VbJZNegbBjlPvzOzCouXtS2y3sDvlO3IsbrPNWuLWPPlYVYPghQdSF64683Ldw==", + "dependencies": { + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@clack/prompts": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@clack/prompts/-/prompts-0.7.0.tgz", + "integrity": "sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA==", + "bundleDependencies": [ + "is-unicode-supported" + ], + "dependencies": { + "@clack/core": "^0.3.3", + "is-unicode-supported": "*", + "picocolors": "^1.0.0", + "sisteransi": "^1.0.5" + } + }, + "node_modules/@clack/prompts/node_modules/is-unicode-supported": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==" + }, + "node_modules/@types/node": { + "version": "22.4.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.4.1.tgz", + "integrity": "sha512-1tbpb9325+gPnKK0dMm+/LMriX0vKxf6RnB0SZUqfyVkQ4fMgUSySqhxE/y8Jvs4NyF1yHzTfG9KlnkIODxPKg==", + "dev": true, + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/browserslist": { + "version": "4.23.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz", + "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001646", + "electron-to-chromium": "^1.5.4", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001651", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001651.tgz", + "integrity": "sha512-9Cf+Xv1jJNe1xPZLGuUXLNkE1BoDkqRqYyFJ9TDYSqhduqA4hu4oR9HluGoWYQC/aj8WHjsGVV+bwkh0+tegRg==", + "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": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/debug": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", + "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.13", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz", + "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==" + }, + "node_modules/escalade": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", + "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "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/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/node-releases": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" + }, + "node_modules/picocolors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==" + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/remove-types": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/remove-types/-/remove-types-1.0.0.tgz", + "integrity": "sha512-G7Hk1Q+UJ5DvlNAoJZObxANkBZGiGdp589rVcTW/tYqJWJ5rwfraSnKSQaETN8Epaytw8J40nS/zC7bcHGv36w==", + "dependencies": { + "@babel/core": "^7.16.10", + "@babel/plugin-syntax-decorators": "^7.16.7", + "@babel/plugin-transform-typescript": "^7.16.8", + "prettier": "^2.5.1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/typescript": { + "version": "5.5.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", + "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + }, + "node_modules/update-browserslist-db": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.2", + "picocolors": "^1.0.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3a8aad4 --- /dev/null +++ b/package.json @@ -0,0 +1,23 @@ +{ + "name": "request-cli", + "version": "0.1.0", + "description": "CLI tool for injecting Request Network functionality", + "bin": { + "request-cli": "./dist/index.js" + }, + "scripts": { + "build": "tsc", + "start": "node dist/index.js", + "prepublishOnly": "npm run build" + }, + "author": "", + "license": "ISC", + "dependencies": { + "@clack/prompts": "^0.7.0", + "remove-types": "^1.0.0" + }, + "devDependencies": { + "@types/node": "^22.4.1", + "typescript": "^5.5.4" + } +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..4126410 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,157 @@ +#!/usr/bin/env node + +import * as p from "@clack/prompts"; +import { exec } from "child_process"; +import * as fs from "fs"; +import * as path from "path"; +import { injectCode } from "./injector"; + +async function main() { + console.clear(); + p.intro(`Welcome to the Request Network Injector`); + + // Step 1: Check if running inside a project + if (!fs.existsSync("package.json")) { + p.note("This tool must be run inside a project with a package.json file."); + process.exit(1); + } + + // Step 2: Detect package manager + const packageManager = await detectPackageManager(); + + // Step 3: Show list of functions + const functionOptions = [ + { + value: "prepareRequest", + label: + "prepareRequest | Method to prepare the input needed to create a request", + }, + { value: "createRequest", label: "createRequest | Create a request" }, + { value: "payRequest", label: "payRequest | Pay request" }, + { + value: "persistInMemoryRequest", + label: "persistInMemoryRequest | Persist in Memory requests", + }, + { + value: "getRequestByID", + label: "getRequestByID | Get request data by request id", + }, + { + value: "getRequestsByWalletAdderess", + label: + "getRequestsByWalletAdderess | Get requests data that belong to a wallet address", + }, + ]; + + const defaultSelected = ["prepareRequest", "createRequest", "payRequest"]; + + const selectedFunctions = await p.multiselect({ + message: "Select the functions you want to inject:", + options: functionOptions, + initialValues: defaultSelected, + }); + + // Step 4: Choose TypeScript or JavaScript + const language = await p.select({ + message: "Choose the language:", + options: [ + { value: "typescript", label: "TypeScript" }, + { value: "javascript", label: "JavaScript" }, + ], + }); + + let jsModuleType: "esm" | "cjs" = "esm"; + + if (language === "javascript") { + jsModuleType = (await p.select({ + message: "Choose the JavaScript module type:", + options: [ + { value: "esm", label: "ECMAScript Modules (ESM)" }, + { value: "cjs", label: "CommonJS" }, + ], + })) as "esm" | "cjs"; + } + + // Step 5: Choose injection path + const injectionPath = await p.text({ + message: + "Enter the path where you want to inject the requestNetwork directory:", + initialValue: "src", + validate: (value) => { + if (value.trim() === "") return "Path cannot be empty"; + return; + }, + }); + + // Step 6: Inject the code + try { + const { filePath, packages } = await injectCode( + injectionPath as string, + selectedFunctions as string[], + language as string, + jsModuleType + ); + p.note( + `Request Network functionality has been successfully injected into your project at ${filePath}!` + ); + + // Step 7: Install necessary packages + await installPackages(packageManager, packages); + } catch (error) { + if (error instanceof Error) { + p.note(`Error: Code injection failed. Details: ${error.message}`); + } + } +} + +async function detectPackageManager(): Promise { + const checkLockFile = (file: string) => + fs.existsSync(path.join(process.cwd(), file)); + + if (checkLockFile("bun.lockb")) return "bun"; + if (checkLockFile("pnpm-lock.yaml")) return "pnpm"; + if (checkLockFile("yarn.lock")) return "yarn"; + if (checkLockFile("package-lock.json")) return "npm"; + + return await p.select({ + message: "We couldn't detect your package manager. Please choose one:", + options: [ + { value: "npm", label: "npm" }, + { value: "yarn", label: "Yarn" }, + { value: "pnpm", label: "pnpm" }, + { value: "bun", label: "Bun" }, + ], + }); +} + +async function installPackages(packageManager: string, packages: Set) { + const installCommands = { + bun: "bun add", + pnpm: "pnpm add", + yarn: "yarn add", + npm: "npm install", + }; + + const installCommand = installCommands[packageManager]; + + const spinner = p.spinner(); + spinner.start(`Installing packages using ${packageManager}`); + + try { + await new Promise((resolve, reject) => { + exec(`${installCommand} ${Array.from(packages).join(" ")}`, (error) => { + if (error) { + reject(error); + } else { + resolve(); + } + }); + }); + spinner.stop(`Packages installed successfully using ${packageManager}`); + } catch (error) { + spinner.stop(`Failed to install packages: ${error.message}`); + throw error; + } +} + +main().catch(console.error); diff --git a/src/injector.ts b/src/injector.ts new file mode 100644 index 0000000..b388fa3 --- /dev/null +++ b/src/injector.ts @@ -0,0 +1,151 @@ +import * as fs from "fs"; +import * as path from "path"; +import { removeTypes } from "remove-types"; + +import { + prepareRequestJSDoc, + createRequestJSDoc, + payRequestJSDoc, + persistInMemoryRequestJSDoc, + getRequestByIDJSDoc, + getRequestsByWalletAddressJSDoc, +} from "./methods/jsDoc"; +import { + prepareRequestMethod, + createRequestMethod, + payRequestMethod, + persistInMemoryRequestMethod, + getRequestByIDMethod, + getRequestsByWalletAdderessMethod, +} from "./methods"; +import { typesContent } from "./types"; +import { esmToCommonjs } from "./utils/esmToCommonjs"; + +interface FunctionInfo { + implementation: string; + jsDoc: string; + imports: string[]; + packages: string[]; +} + +const functionInfoMap: { [key: string]: FunctionInfo } = { + prepareRequest: { + implementation: prepareRequestMethod, + jsDoc: prepareRequestJSDoc, + imports: ["RequestNetwork", "types"], + packages: ["@requestnetwork/request-client.js"], + }, + createRequest: { + implementation: createRequestMethod, + jsDoc: createRequestJSDoc, + imports: ["RequestNetwork", "Web3SignatureProvider"], + packages: [ + "@requestnetwork/request-client.js", + "@requestnetwork/web3-signature", + ], + }, + payRequest: { + implementation: payRequestMethod, + jsDoc: payRequestJSDoc, + imports: ["RequestPaymentProcessor", "RequestNetwork"], + packages: [ + "@requestnetwork/request-client.js", + "@requestnetwork/payment-processor", + ], + }, + persistInMemoryRequest: { + implementation: persistInMemoryRequestMethod, + jsDoc: persistInMemoryRequestJSDoc, + imports: ["RequestNetwork"], + packages: ["@requestnetwork/request-client.js"], + }, + getRequestByID: { + implementation: getRequestByIDMethod, + jsDoc: getRequestByIDJSDoc, + imports: ["RequestNetwork"], + packages: ["@requestnetwork/request-client.js"], + }, + getRequestsByWalletAdderess: { + implementation: getRequestsByWalletAdderessMethod, + jsDoc: getRequestsByWalletAddressJSDoc, + imports: ["RequestNetwork"], + packages: ["@requestnetwork/request-client.js"], + }, +}; + +const imports: { [key: string]: string } = { + RequestNetwork: + "import { Types, Utils, RequestNetwork } from '@requestnetwork/request-client.js';", + types: "import { Currency, IContentData } from './types';", + Web3SignatureProvider: + "import { Web3SignatureProvider } from '@requestnetwork/web3-signature';", + RequestPaymentProcessor: + "import {approveErc20, hasErc20Approval, hasSufficientFunds, payRequest as processPayment} from '@requestnetwork/payment-processor'", +}; + +export async function generateCode( + selectedFunctions: string[], + language: string, + jsModuleType: "esm" | "cjs" = "esm" +): Promise<{ code: string; packages: Set }> { + const requiredImports = new Set(); + const requiredPackages = new Set(); + selectedFunctions.forEach((func) => { + functionInfoMap[func].imports.forEach((imp) => requiredImports.add(imp)); + functionInfoMap[func].packages.forEach((pkg) => requiredPackages.add(pkg)); + }); + + const importStatements = Array.from(requiredImports) + .map((imp) => imports[imp]) + .join("\n"); + + const selectedImplementations = selectedFunctions + .map((func) => { + const { jsDoc, implementation } = functionInfoMap[func]; + const cleanJsDoc = jsDoc + .replace(`export const ${func}JSDoc = \`\n`, "") + .replace("`;", ""); + return `${cleanJsDoc}\n${implementation}`; + }) + .join("\n\n"); + + let code = `${importStatements}\n\n${selectedImplementations}\n`; + + if (language === "javascript") { + code = await removeTypes(code); + if (jsModuleType === "cjs") { + code = await esmToCommonjs(code); + } + } + + return { code, packages: requiredPackages }; +} + +export async function injectCode( + injectionPath: string, + selectedFunctions: string[], + language: string, + jsModuleType: "esm" | "cjs" = "esm" +): Promise<{ filePath: string; packages: Set }> { + const fullPath = path.join(process.cwd(), injectionPath, "requestNetwork"); + fs.mkdirSync(fullPath, { recursive: true }); + + const fileName = `index.${language === "typescript" ? "ts" : "js"}`; + const filePath = path.join(fullPath, fileName); + + const { code, packages } = await generateCode( + selectedFunctions, + language, + jsModuleType + ); + + fs.writeFileSync(filePath, code); + + if (language === "typescript") { + const typesDestPath = path.join(fullPath, "types", "index.ts"); + fs.mkdirSync(path.dirname(typesDestPath), { recursive: true }); + fs.writeFileSync(typesDestPath, typesContent.trim()); + } + + return { filePath, packages }; +} diff --git a/src/methods/index.ts b/src/methods/index.ts new file mode 100644 index 0000000..f87bd04 --- /dev/null +++ b/src/methods/index.ts @@ -0,0 +1,219 @@ +export const prepareRequestMethod = `export async function prepareRequest({ + currency, + payerAddress, + payeeAddress, + amount, + invoiceDetails, +}: { + currency: Currency; + payerAddress: string; + payeeAddress: string; + amount: string; + invoiceDetails: IContentData; +}) { + const isERC20 = currency.type === Types.RequestLogic.CURRENCY.ERC20; + const currencyValue = isERC20 ? currency.address : "eth"; + + return { + requestInfo: { + currency: { + type: currency.type, + value: currencyValue, + network: currency.network, + }, + expectedAmount: amount, + payee: { + type: Types.Identity.TYPE.ETHEREUM_ADDRESS, + value: payeeAddress, + }, + payer: { + type: Types.Identity.TYPE.ETHEREUM_ADDRESS, + value: payerAddress, + }, + timestamp: Utils.getCurrentTimestampInSecond(), + }, + paymentNetwork: { + id: isERC20 + ? Types.Extension.PAYMENT_NETWORK_ID.ERC20_FEE_PROXY_CONTRACT + : Types.Extension.PAYMENT_NETWORK_ID.ETH_FEE_PROXY_CONTRACT, + parameters: { + paymentNetworkName: currency.network, + paymentAddress: payeeAddress, + feeAddress: "0x0000000000000000000000000000000000000000", + feeAmount: "0", + tokenAddress: currencyValue, + }, + }, + contentData: { + meta: { + format: "rnf_invoice", + version: "0.0.3", + }, + creationDate: invoiceDetails.creationDate, + invoiceNumber: invoiceDetails.invoiceNumber, + note: invoiceDetails.note, + invoiceItems: invoiceDetails.invoiceItems, + paymentTerms: invoiceDetails.paymentTerms, + sellerInfo: invoiceDetails.sellerInfo, + buyerInfo: invoiceDetails.buyerInfo, + miscellaneous: invoiceDetails.miscellaneous, + }, + signer: { + type: Types.Identity.TYPE.ETHEREUM_ADDRESS, + value: payerAddress, + }, + }; +}`; + +export const createRequestMethod = `export async function createRequest({ + requestParams, + walletProvider, + inMemory = false, +}: { + requestParams: Types.ICreateRequestParameters; + walletProvider: any; + inMemory : boolean; +}) { + const web3SignatureProvider = new Web3SignatureProvider(walletProvider); + + const requestClient = new RequestNetwork({ + nodeConnectionConfig: { + baseURL: "https://gnosis.gateway.request.network", + }, + skipPersistence: inMemory, + signatureProvider: web3SignatureProvider, + }); + + const request = await requestClient.createRequest(requestParams); + + if(!inMemory){ + await request.waitForConfirmation(); + } + + return request; +} +`; + +export const payRequestMethod = `export async function payRequest({ + requestId, + inMemoryRequest, + signer, + provider, + confirmationBlocks = 2, +}: { + requestId?: string; + inMemoryRequest?: any; + signer: any; + provider: any; + confirmationBlocks: number; +}) { + let requestData; + + if (inMemoryRequest) { + requestData = inMemoryRequest.inMemoryInfo?.requestData; + if (!requestData) { + throw new Error("Invalid in-memory request"); + } + } else if (requestId) { + const requestClient = new RequestNetwork({ + nodeConnectionConfig: { + baseURL: "https://gnosis.gateway.request.network", + }, + }); + + const request = await requestClient.fromRequestId(requestId); + requestData = request.getData(); + } else { + throw new Error("Either requestId or inMemoryRequest must be provided"); + } + + const isERC20 = + requestData.currencyInfo.type === Types.RequestLogic.CURRENCY.ERC20; + const payerAddress = requestData.payer?.value; + + if (isERC20) { + const _hasSufficientFunds = await hasSufficientFunds({ + request: requestData, + address: payerAddress as string, + providerOptions: { + provider, + }, + }); + + if (!_hasSufficientFunds) { + throw new Error("Insufficient funds"); + } + + const _hasApproval = await hasErc20Approval( + requestData, + payerAddress as string, + provider + ); + + if (!_hasApproval) { + const _approve = await approveErc20(requestData, signer); + + await _approve.wait(confirmationBlocks); + } + } + + const paymentTx = await processPayment(requestData, signer); + + await paymentTx.wait(confirmationBlocks); + + return paymentTx; +} +`; + +export const persistInMemoryRequestMethod = `export async function persistInMemoryRequest(request: any) { + const requestClient = new RequestNetwork({ + nodeConnectionConfig: { + baseURL: "https://gnosis.gateway.request.network", + }, + }); + + if (!request.inMemoryInfo) { + throw new Error( + "This request is not in-memory and cannot be persisted. Only in-memory requests can be persisted." + ); + } + + await requestClient.persistRequest(request); +}`; + +export const getRequestByIDMethod = `export async function getRequestByID(requestId: string) { + const requestClient = new RequestNetwork({ + nodeConnectionConfig: { + baseURL: "https://gnosis.gateway.request.network", + }, + }); + + const request = await requestClient.fromRequestId(requestId); + + const requestData = request.getData(); + + return requestData; +} +`; + +export const getRequestsByWalletAdderessMethod = `export async function getRequestsByWalletAdderess(walletAddress: string) { + const requestClient = new RequestNetwork({ + nodeConnectionConfig: { + baseURL: "https://gnosis.gateway.request.network", + }, + }); + + const requests = await requestClient.fromIdentity({ + type: Types.Identity.TYPE.ETHEREUM_ADDRESS, + value: walletAddress, + }); + + const requestsData = []; + + for (const request of requests) { + requestsData.push(request.getData()); + } + + return requestsData; +} +`; diff --git a/src/methods/jsDoc.ts b/src/methods/jsDoc.ts new file mode 100644 index 0000000..38d3fc6 --- /dev/null +++ b/src/methods/jsDoc.ts @@ -0,0 +1,151 @@ +export const prepareRequestJSDoc = ` +/** + * Prepares a request object for creating a request. + * + * @param {Object} params - The parameters for preparing the request. + * @param {Currency} params.currency - The currency object for the payment. + * @param {string} params.currency.type - The type of currency ('ERC20' or 'ETH'). + * @param {string} params.currency.address - The address of the ERC20 token (if applicable). + * @param {string} params.currency.network - The network of the currency. + * @param {string} params.payerAddress - The Ethereum address of the payer. + * @param {string} params.payeeAddress - The Ethereum address of the payee. + * @param {string} params.amount - The amount to be paid, needs to be in blockchain readable format. + * @param {IContentData} params.invoiceDetails - The invoice details. + * @param {string} params.invoiceDetails.creationDate - The creation date of the invoice. + * @param {string} params.invoiceDetails.invoiceNumber - The invoice number. + * @param {string} params.invoiceDetails.note - Any additional notes for the invoice. + * @param {Array} params.invoiceDetails.invoiceItems - The list of items in the invoice. + * @param {string} params.invoiceDetails.paymentTerms - The payment terms for the invoice. + * @param {Object} params.invoiceDetails.sellerInfo - Information about the seller. + * @param {Object} params.invoiceDetails.buyerInfo - Information about the buyer. + * @param {Object} params.invoiceDetails.miscellaneous - Any miscellaneous information. + * + * @returns {Promise} A promise that resolves to an object containing: + * - requestInfo: Information about the payment request. + * - paymentNetwork: Details about the payment network to be used. + * - contentData: Detailed invoice information. + * - signer: Information about the signer of the request. + * + * @example + * const requestData = await prepareRequest({ + * currency: { type: 'ERC20', address: '0x...', network: 'mainnet' }, + * payerAddress: '0x...', + * payeeAddress: '0x...', + * amount: '1000000000000000000', + * invoiceDetails: { + * creationDate: '2023-04-01', + * invoiceNumber: 'INV-001', + * // ... other invoice details + * } + * }); + */ +`; + +export const createRequestJSDoc = ` +/** + * Creates a new request using the provided parameters and wallet provider. + * + * @param {Object} params - The parameters for creating the request. + * @param {Types.ICreateRequestParameters} params.requestParams - The request parameters. + * @param {any} params.walletProvider - The wallet provider for signing the request. + * @param {boolean} [params.inMemory=false] - Whether to create the request without persisting it on the blockchain (default: false). + * + * @returns {Promise} A promise that resolves to the created request object. + * The request object includes methods like waitForConfirmation() if not created in-memory. + * + * @example + * // Create a persistent request + * const request = await createRequest({ + * requestParams: { + * // ... request parameters + * }, + * walletProvider: web3Provider + * }); + * + * @example + * // Create an in-memory request + * const inMemoryRequest = await createRequest({ + * requestParams: { + * // ... request parameters + * }, + * walletProvider: web3Provider, + * inMemory: true + * }); + */ +`; + +export const payRequestJSDoc = ` +/** + * Pay the request for a given request ID or an in-memory request. + * + * @param {Object} params - The parameters for processing the payment request. + * @param {string} [params.requestId] - The ID of the request to process (required if inMemoryRequest is not provided). + * @param {any} [params.inMemoryRequest] - The in-memory request object (required if requestId is not provided). + * @param {any} params.signer - The signer object for transaction signing. + * @param {any} params.provider - The provider object for blockchain interaction. + * @param {number} [params.confirmationBlocks=2] - The number of blocks to wait for confirmation. + * + * @returns {Promise} A promise that resolves to the payment transaction object. + * + * @throws {Error} Throws an error if there are insufficient funds for ERC20 payments or if neither requestId nor inMemoryRequest is provided. + * + * @example + * // Pay a request using requestId + * const paymentTx = await payRequest({ + * requestId: '0x1234...', // The request ID + * signer: web3Signer, + * provider: web3Provider, + * confirmationBlocks: 3 + * }); + * + * @example + * // Pay an in-memory request + * const paymentTx = await payRequest({ + * inMemoryRequest: inMemoryRequestObject, + * signer: web3Signer, + * provider: web3Provider, + * confirmationBlocks: 3 + * }); + * + * // The payment transaction has been processed and confirmed + * console.log('Payment transaction:', paymentTx); + */ +`; +export const persistInMemoryRequestJSDoc = ` +/** + * Persists an in-memory request to the Request Network. + * + * @param {any} request - The in-memory request object to be persisted. + * @throws {Error} If the request is not an in-memory request. + * @returns {Promise} A promise that resolves when the request is successfully persisted. + */ +`; + +export const getRequestByIDJSDoc = ` +/** + * Retrieves a request by its ID from the Request Network. + * + * @param {string} requestId - The ID of the request to retrieve. + * + * @returns {Promise} A promise that resolves to the request data object. + * + * @example + * const requestData = await getRequestByID('0x1234...'); + * console.log('Request data:', requestData); + */ +`; + +export const getRequestsByWalletAddressJSDoc = ` +/** + * Retrieves all requests associated with a given wallet address. + * + * @param {string} walletAddress - The Ethereum address of the wallet to query. + * + * @returns {Promise>} A promise that resolves to an array of request data objects. + * + * @example + * const requests = await getRequestsByWalletAdderess('0x5678...'); + * console.log('Number of requests:', requests.length); + * requests.forEach(request => console.log('Request:', request)); + */ +`; diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 0000000..b2318bf --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,64 @@ +export const typesContent = ` +export type Currency = { + id: string; + hash: string; + address?: string; + network: string; + decimals: number; + symbol: string; + type: "ERC20" | "ETH"; + name?: string; +}; + +export interface IContentData { + miscellaneous?: { + labels: string[]; + [key: string]: any; + }; + creationDate: string; + invoiceNumber: string; + note?: string; + invoiceItems: Array<{ + name: string; + quantity: number; + unitPrice: string; + discount: string; + tax: { + type: string; + amount: string; + }; + currency: string; + }>; + paymentTerms: { + dueDate: string; + }; + buyerInfo?: { + firstName?: string; + lastName?: string; + address?: { + "country-name"?: string; + locality?: string; + "postal-code"?: string; + region?: string; + "street-address"?: string; + }; + businessName?: string; + taxRegistration?: string; + email?: string; + }; + sellerInfo?: { + firstName?: string; + lastName?: string; + address?: { + "country-name"?: string; + locality?: string; + "postal-code"?: string; + region?: string; + "street-address"?: string; + }; + businessName?: string; + taxRegistration?: string; + email?: string; + }; +} +`; diff --git a/src/utils/esmToCommonjs.ts b/src/utils/esmToCommonjs.ts new file mode 100644 index 0000000..ffb1930 --- /dev/null +++ b/src/utils/esmToCommonjs.ts @@ -0,0 +1,39 @@ +export function esmToCommonjs(code: string): string { + // Convert import statements + let modifiedCode = code.replace( + /import\s+{\s*([^}]+)\s*}\s+from\s+['"](.+?)['"]/g, + (match, imports, path) => { + const cleanImports = imports + .split(",") + .map((i: string) => i.trim().split(" as ")) + .map(([name, alias]: [string, string]) => + alias ? `${name}: ${alias}` : name + ) + .join(", "); + return `const { ${cleanImports} } = require('${path}');`; + } + ); + + // Convert export statements + modifiedCode = modifiedCode.replace( + /export\s+async\s+function\s+(\w+)/g, + "async function $1" + ); + modifiedCode = modifiedCode.replace( + /export\s+function\s+(\w+)/g, + "function $1" + ); + + // Add module.exports at the end of the file + const exportedFunctions = Array.from( + modifiedCode.matchAll(/(?:async\s+)?function\s+(\w+)/g) + ).map((match) => match[1]); + if (exportedFunctions.length > 0) { + const exportStatements = exportedFunctions + .map((name) => ` ${name},`) + .join("\n"); + modifiedCode += `\nmodule.exports = {\n${exportStatements}\n};\n`; + } + + return modifiedCode; +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..b263aba --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "target": "ES2018", + "module": "commonjs", + "outDir": "./dist", + "rootDir": "./src", + "strict": true, + "esModuleInterop": true, + "moduleResolution": "node", + "resolveJsonModule": true, + }, +}