diff --git a/out/index.html b/out/index.html new file mode 100644 index 0000000..2c0b89d --- /dev/null +++ b/out/index.html @@ -0,0 +1 @@ +NOMO Demo Plugin

NOMO Demo Plugin - Get started by editing src/app/page.tsx. Scroll down to explore features of NOMO-plugins!

NOMO Logo
Platform info: null
Wallet addresses: null
Chat messenger address: null..
NOMO theme: null..
Device name: null

Sign EVM transaction with web3.js->

Send a transaction to the ZENIQ Smartchain, signed by the Nomo app with web3js-nomo-plugins.

Sign EVM transaction with ethers.js->

Send a transaction to the ZENIQ Smartchain, signed by the Nomo app with ethersjs-nomo-plugins.

Take picture ->

Use the NOMO-app for getting a picture into the plugin.

Your camera image will be shown here

Open gallery->

Upload documents or images from a NOMO-plugin.

Your gallery image will be shown here

Open a chat ->

Open a chat with a human or with a chat-bot, powered by the zeniq.chat service.

Speech to text->

Say something to the NOMO-app and get the text into the plugin.

NOMO-Auth->

NOMO-Auth is a protocol for seamless authentication of plugins, utilizing the NOMO-wallet.

NOMO-ID->

Log in instantly with NOMO-ID. With NOMO-plugins, there is no need to scan a QRCode.

Send assets->

With consent from the user, plugins can send assets from the NOMO-wallet.

Sign EVM message->

With consent from the user, plugins can sign messages to prove that the user controls a specific wallet.

Add custom token->

Plugins can expand the list of tokens

Unittest transaction signing ->

Unittest for signing a transaction with the Nomo app.

\ No newline at end of file diff --git a/out/nomo.tar.gz b/out/nomo.tar.gz new file mode 100644 index 0000000..7eaaa74 Binary files /dev/null and b/out/nomo.tar.gz differ diff --git a/out/nomo_icon.svg b/out/nomo_icon.svg new file mode 100644 index 0000000..c54b138 Binary files /dev/null and b/out/nomo_icon.svg differ diff --git a/out/nomo_manifest.json b/out/nomo_manifest.json new file mode 100644 index 0000000..b9e416a --- /dev/null +++ b/out/nomo_manifest.json @@ -0,0 +1,8 @@ +{ + "nomo_manifest_version": "1.1.0", + "webon_id": "demo.nomo.app", + "webon_name": "DEMO APP", + "webon_version": "0.1.0", + "min_nomo_version": "0.3.1", + "permissions": [] +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index cd8989c..29bb305 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "commander": "^6.1.0", "dotenv": "^16.3.1", + "inquirer": "^7.3.3", "semver": "^7.5.4", "tar": "^6.2.0", "tslib": "^2.6.2" @@ -18,6 +19,7 @@ "nomo-webon-cli": "bin/nomo-webon-cli" }, "devDependencies": { + "@types/inquirer": "^7.3.3", "@types/jest": "^29.5.8", "@types/node": "^14.11.8", "@types/semver": "^7.5.0", @@ -1105,6 +1107,16 @@ "@types/node": "*" } }, + "node_modules/@types/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/@types/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-HhxyLejTHMfohAuhRun4csWigAMjXTmRyiJTU1Y/I1xmggikFMkOUoMQRlFm+zQcPEGHSs3io/0FAmNZf8EymQ==", + "dev": true, + "dependencies": { + "@types/through": "*", + "rxjs": "^6.4.0" + } + }, "node_modules/@types/istanbul-lib-coverage": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", @@ -1176,6 +1188,15 @@ "node": ">=8" } }, + "node_modules/@types/through": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/@types/through/-/through-0.0.33.tgz", + "integrity": "sha512-HsJ+z3QuETzP3cswwtzt2vEIiHBk/dCcHGhbmG5X3ecnwFD/lPrMpliGXxSCg03L9AhrdwA4Oz/qfspkDW+xGQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.31", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.31.tgz", @@ -1195,7 +1216,6 @@ "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, "dependencies": { "type-fest": "^0.21.3" }, @@ -1210,7 +1230,6 @@ "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" } @@ -1219,7 +1238,6 @@ "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" }, @@ -1497,7 +1515,6 @@ "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" @@ -1518,6 +1535,11 @@ "node": ">=10" } }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, "node_modules/chownr": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", @@ -1547,6 +1569,25 @@ "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", "dev": true }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "engines": { + "node": ">= 10" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -1581,7 +1622,6 @@ "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" }, @@ -1592,8 +1632,7 @@ "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 + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/commander": { "version": "6.2.1", @@ -1740,8 +1779,7 @@ "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 + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/error-ex": { "version": "1.3.2", @@ -1831,6 +1869,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, "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", @@ -1846,6 +1897,28 @@ "bser": "2.1.1" } }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/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/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2005,7 +2078,6 @@ "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" } @@ -2037,6 +2109,17 @@ "node": ">=10.17.0" } }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -2081,6 +2164,29 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", @@ -2103,7 +2209,6 @@ "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" } @@ -2850,6 +2955,11 @@ "node": ">=8" } }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -2918,7 +3028,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, "engines": { "node": ">=6" } @@ -2988,6 +3097,11 @@ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", "dev": true }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -3040,7 +3154,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, "dependencies": { "mimic-fn": "^2.1.0" }, @@ -3051,6 +3164,14 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -3309,6 +3430,47 @@ "node": ">=10" } }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, "node_modules/semver": { "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", @@ -3363,8 +3525,7 @@ "node_modules/signal-exit": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" }, "node_modules/sisteransi": { "version": "1.0.5", @@ -3435,7 +3596,6 @@ "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", @@ -3449,7 +3609,6 @@ "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" }, @@ -3491,7 +3650,6 @@ "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" }, @@ -3546,6 +3704,22 @@ "node": ">=8" } }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -3634,7 +3808,6 @@ "version": "0.21.3", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 22bd7f3..3657f1c 100644 --- a/package.json +++ b/package.json @@ -25,13 +25,15 @@ "dependencies": { "commander": "^6.1.0", "dotenv": "^16.3.1", + "inquirer": "^7.3.3", "semver": "^7.5.4", "tar": "^6.2.0", "tslib": "^2.6.2" }, "devDependencies": { - "@types/node": "^14.11.8", + "@types/inquirer": "^7.3.3", "@types/jest": "^29.5.8", + "@types/node": "^14.11.8", "@types/semver": "^7.5.0", "@types/tar": "^6.1.9", "jest": "^29.7.0", diff --git a/src/build-webon/build-webon.ts b/src/build-webon/build-webon.ts index 313fcea..ec37315 100644 --- a/src/build-webon/build-webon.ts +++ b/src/build-webon/build-webon.ts @@ -46,9 +46,9 @@ export async function buildWebOn(args: { assetDir: string }) { console.error( `Error: The 'out' directory is missing the following required files: ${missingFiles.join( ", " - )}` + )} Use nomo-webon-cli init if you do not have a nomo_manifest.json yet.` ); - return; // or handle the error as needed + return; } // Create a tar.gz file diff --git a/src/build-webon/nomo-webon-cli.code-workspace b/src/build-webon/nomo-webon-cli.code-workspace new file mode 100644 index 0000000..f22c099 --- /dev/null +++ b/src/build-webon/nomo-webon-cli.code-workspace @@ -0,0 +1,9 @@ +{ + "folders": [ + { + "name": "nomo-webon-cli", + "path": "../.." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index b6a81cb..5448f56 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,6 +3,7 @@ import "dotenv/config"; import { extractVersion } from "./util/extract-version"; import { buildWebOn } from "./build-webon/build-webon"; import { deployWebOn } from "./deploy-webon/deploy-webon"; +import { init } from "./init/init"; process.on("unhandledRejection", (error) => { console.error("[fatal]", error); @@ -19,6 +20,17 @@ function commanderBuildWebOn() { }); } +function commanderInitWebOn() { + commander + .command("init ") + .description("Init nomo-webon-cli, create configs and manifest if not existing.") + .action((assetDir) => { + runAsyncCommand(async () => { + await init({ assetDir }); + }); + }); +} + function commanderDeployWebOn() { commander .command("deploy ") @@ -48,6 +60,7 @@ export function run(process: NodeJS.Process, cliBinDir: string): void { commander.addHelpCommand(false); commanderBuildWebOn(); commanderDeployWebOn(); + commanderInitWebOn(); commander .version(extractVersion({ cliBinDir }), "-v, --version") .parse(process.argv); diff --git a/src/init/init.ts b/src/init/init.ts new file mode 100644 index 0000000..8ab2775 --- /dev/null +++ b/src/init/init.ts @@ -0,0 +1,44 @@ +import * as fs from "fs"; +import * as path from "path"; +import { NomoManifest } from "./interface"; + +async function getUserInput(prompt: string): Promise { + // Import inquirer dynamically + const inquirer = require("inquirer"); + + const { userInput } = await (inquirer as any).prompt([ + { + type: "input", + name: "userInput", + message: prompt, + }, + ]); + + return userInput; +} + +export async function init(args: { assetDir: string }): Promise { + const assetDir = args.assetDir; + const manifestFilePath = path.join(assetDir, "nomo_manifest.json"); + + // Check if nomo_manifest.json already exists + if (fs.existsSync(manifestFilePath)) { + console.log("nomo_manifest.json already exists."); + } else { + // Prompt user for input + const webonId = await getUserInput("Enter webon_id: "); + const webonName = await getUserInput("Enter webon_name: "); + + // Create nomo_manifest.json with user input + const nomoManifest: NomoManifest = { + nomo_manifest_version: "1.1.0", + webon_id: webonId, + webon_name: webonName, + webon_version: "0.1.0", + permissions: [], + }; + + fs.writeFileSync(manifestFilePath, JSON.stringify(nomoManifest, null, 2)); + console.log("nomo_manifest.json created successfully."); + } +} diff --git a/src/init/interface.ts b/src/init/interface.ts new file mode 100644 index 0000000..cfc2f88 --- /dev/null +++ b/src/init/interface.ts @@ -0,0 +1,38 @@ +export interface NomoManifest { + /** + * If min_nomo_version is set, then outdated versions of the Nomo App will refuse to install the WebOn. + */ + min_nomo_version?: string | null; + /** + * nomo_manifest_version should be 1.1.0. + */ + nomo_manifest_version: string; + /** + * A list of permissions for security-critical features. + */ + permissions: string[]; + /** + * webon_id should be the reverse-domain of a domain that is owned by the WebOn-author. + * See https://en.wikipedia.org/wiki/Reverse_domain_name_notation for more details about the reverse domain name notation. + */ + webon_id: string; + /** + * webon_name is the user-visible name of the WebOn. + */ + webon_name: string; + /** + * webon_version should comply with the semantic versioning standard. + * See https://semver.org/ for details. + */ + webon_version: string; + /** + * If true, then the WebOn could be displayed in both card-mode and fullscreen-mode. + * If false, then the WebOn will only be displayed in fullscreen-mode. + */ + card_mode?: boolean; + /** + * If defined, then the WebOn can decide whether a navigation bar should be shown or not. + */ + show_navbar?: boolean; + } + \ No newline at end of file diff --git a/src/util/util.ts b/src/util/util.ts index 8f4ff03..121ccd1 100644 --- a/src/util/util.ts +++ b/src/util/util.ts @@ -6,6 +6,8 @@ import { import { join, resolve } from "path"; import semver from "semver"; +let _isUnitTest:boolean = false; + export function joinDirWithFileName(dir: string, fileName: string): string { checkDir(dir); return join(resolve(dir), fileName); @@ -45,7 +47,16 @@ export function getDebugPath(path: string): string { } export function logFatal(msg: string): void { - console.error(`error: ${msg}`); + if(isUnitTest()) { + throw new Error(`error: ${msg}`); + } + else { + console.error(`error: ${msg}`); + process.exit(1); + } + + + // Do not exit immediately for testing purposes } @@ -62,3 +73,10 @@ export function nodeVersionSatisfies(feature: string, range: string): void { } +export function isUnitTest() { + return _isUnitTest; +} + +export function enableUnitTest(): void { + _isUnitTest = true; +} diff --git a/test/build-webon-test/invalid-build-options.test.ts b/test/build-webon-test/invalid-build-options.test.ts deleted file mode 100644 index b6feb10..0000000 --- a/test/build-webon-test/invalid-build-options.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { runCliTestExpectFailure } from "../test-util/test-util"; -import { buildWebOn } from "../../src/build-webon/build-webon"; -//import { runCliTestExpectFailure } from "../test-util/test-util"; -import { getDebugPath } from "../../src/util/util"; - -test("assetDir not existing", async () => { - const output = await runCliTestExpectFailure("build some-non-existing-dir"); - expect(output).toBe( - `error: ${getDebugPath("some-non-existing-dir")} does not exist.\n` - ); -}); - -test("assetDir not a dir", async () => { - const output = await runCliTestExpectFailure("build README.md"); - expect(output).toBe( - `error: ${getDebugPath("README.md")} is not a directory.\n` - ); -}); - -/* -describe('buildWebOn', () => { - test('it should build the Next.js app and create a tar.gz file', async () => { - // Use a temporary directory for testing - const tempDir = 'build'; - const assetDir = 'out'; - - // Mock necessary functions or modules - const mockExecSync = jest.fn(); - const mockExistsSync = jest.fn(); - const mockMkdirSync = jest.fn(); - const mockTarCreate = jest.fn(() => Promise.resolve()); - - jest.mock('child_process', () => ({ - execSync: mockExecSync, - })); - - jest.mock('fs', () => ({ - existsSync: mockExistsSync, - mkdirSync: mockMkdirSync, - })); - - jest.mock('tar', () => ({ - create: mockTarCreate, - })); - - await buildWebOn({ assetDir }); - - // Add your assertions based on the expected behavior of your function - expect(mockExistsSync).toHaveBeenCalledWith(assetDir); - expect(mockExecSync).toHaveBeenCalledWith('npm run build', { stdio: 'inherit' }); - // Add more assertions based on your implementation - }); -});*/ \ No newline at end of file diff --git a/test/deploy-webon-test/invalid-deploy-options.test.ts b/test/deploy-webon-test/invalid-deploy-options.test.ts deleted file mode 100644 index c94ee19..0000000 --- a/test/deploy-webon-test/invalid-deploy-options.test.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { runCliTestExpectFailure } from "../test-util/test-util"; -import { getDebugPath } from "../../src/util/util"; - -test("archive not existing", async () => { - const output = await runCliTestExpectFailure("deploy some-non-existing-archive"); - expect(output).toBe( - `error: ${getDebugPath("some-non-existing-archive")} does not exist.\n` - ); -}); - -test("archive not a file", async () => { - const output = await runCliTestExpectFailure("deploy src"); - expect(output).toBe( - `error: ${getDebugPath("src")} is a directory.\n` - ); -}); diff --git a/test/e2e/build-webon-test/invalid-build-options.test.ts b/test/e2e/build-webon-test/invalid-build-options.test.ts new file mode 100644 index 0000000..7a9106d --- /dev/null +++ b/test/e2e/build-webon-test/invalid-build-options.test.ts @@ -0,0 +1,18 @@ +import { runCliTestExpectFailure } from "../../test-util/test-util"; +//import { buildWebOn } from "../../src/build-webon/build-webon"; +//import { runCliTestExpectFailure } from "../test-util/test-util"; +import { getDebugPath } from "../../../src/util/util"; + +test("assetDir not existing", async () => { + const output = await runCliTestExpectFailure("build some-non-existing-dir"); + expect(output).toBe( + `error: ${getDebugPath("some-non-existing-dir")} does not exist.\n` + ); +}); + +test("assetDir not a dir", async () => { + const output = await runCliTestExpectFailure("build README.md"); + expect(output).toBe( + `error: ${getDebugPath("README.md")} is not a directory.\n` + ); +}); diff --git a/test/e2e/deploy-webon-test/invalid-deploy-options.test.ts b/test/e2e/deploy-webon-test/invalid-deploy-options.test.ts new file mode 100644 index 0000000..012a078 --- /dev/null +++ b/test/e2e/deploy-webon-test/invalid-deploy-options.test.ts @@ -0,0 +1,16 @@ +import { runCliTestExpectFailure } from "../../test-util/test-util"; +import { getDebugPath } from "../../../src/util/util"; + +test("archive not existing", async () => { + const output = await runCliTestExpectFailure( + "deploy some-non-existing-archive" + ); + expect(output).toBe( + `error: ${getDebugPath("some-non-existing-archive")} does not exist.\n` + ); +}); + +test("archive not a file", async () => { + const output = await runCliTestExpectFailure("deploy src"); + expect(output).toBe(`error: ${getDebugPath("src")} is a directory.\n`); +}); diff --git a/test/help-test/help.test.ts b/test/e2e/help-test/help.test.ts similarity index 95% rename from test/help-test/help.test.ts rename to test/e2e/help-test/help.test.ts index dbe6aa2..a7f8548 100644 --- a/test/help-test/help.test.ts +++ b/test/e2e/help-test/help.test.ts @@ -1,7 +1,7 @@ import { runCliTest, runCliTestExpectFailure -} from "../test-util/test-util"; +} from "../../test-util/test-util"; test("--help", async () => { const output = await runCliTest(`--help`, { diff --git a/test/help-test/version.test.ts b/test/e2e/help-test/version.test.ts similarity index 76% rename from test/help-test/version.test.ts rename to test/e2e/help-test/version.test.ts index f45b6e2..a6c2835 100644 --- a/test/help-test/version.test.ts +++ b/test/e2e/help-test/version.test.ts @@ -1,9 +1,8 @@ -import { runCliTest } from "../test-util/test-util"; - +import { runCliTest } from "../../test-util/test-util"; test("--version", async () => { const output = await runCliTest(`--version`, { - pwd: "/" + pwd: "/", }); expect(output).toContain("0."); }); diff --git a/test/out/index.html b/test/out/index.html new file mode 100644 index 0000000..2c0b89d --- /dev/null +++ b/test/out/index.html @@ -0,0 +1 @@ +NOMO Demo Plugin

NOMO Demo Plugin - Get started by editing src/app/page.tsx. Scroll down to explore features of NOMO-plugins!

NOMO Logo
Platform info: null
Wallet addresses: null
Chat messenger address: null..
NOMO theme: null..
Device name: null

Sign EVM transaction with web3.js->

Send a transaction to the ZENIQ Smartchain, signed by the Nomo app with web3js-nomo-plugins.

Sign EVM transaction with ethers.js->

Send a transaction to the ZENIQ Smartchain, signed by the Nomo app with ethersjs-nomo-plugins.

Take picture ->

Use the NOMO-app for getting a picture into the plugin.

Your camera image will be shown here

Open gallery->

Upload documents or images from a NOMO-plugin.

Your gallery image will be shown here

Open a chat ->

Open a chat with a human or with a chat-bot, powered by the zeniq.chat service.

Speech to text->

Say something to the NOMO-app and get the text into the plugin.

NOMO-Auth->

NOMO-Auth is a protocol for seamless authentication of plugins, utilizing the NOMO-wallet.

NOMO-ID->

Log in instantly with NOMO-ID. With NOMO-plugins, there is no need to scan a QRCode.

Send assets->

With consent from the user, plugins can send assets from the NOMO-wallet.

Sign EVM message->

With consent from the user, plugins can sign messages to prove that the user controls a specific wallet.

Add custom token->

Plugins can expand the list of tokens

Unittest transaction signing ->

Unittest for signing a transaction with the Nomo app.

\ No newline at end of file diff --git a/test/out/nomo_icon.svg b/test/out/nomo_icon.svg new file mode 100644 index 0000000..c54b138 Binary files /dev/null and b/test/out/nomo_icon.svg differ diff --git a/test/out/nomo_manifest.json b/test/out/nomo_manifest.json new file mode 100644 index 0000000..7e03e3b --- /dev/null +++ b/test/out/nomo_manifest.json @@ -0,0 +1,18 @@ +{ + "nomo_manifest_version": "1.1.0", + "plugin_id": "app.nomo.demoplugin", + "plugin_name": "Demo Plugin", + "plugin_version": "0.1.0", + "min_nomo_version": "0.3.1", + "dependencies": [], + "permissions": [ + "nomo.permission.CAMERA", + "nomo.permission.SEND_MESSAGE", + "nomo.permission.SEND_ASSETS", + "nomo.permission.READ_MEDIA", + "nomo.permission.DEVICE_FINGERPRINTING", + "nomo.permission.ADD_CUSTOM_TOKEN", + "nomo.permission.SIGN_EVM_TRANSACTION", + "nomo.permission.SIGN_EVM_MESSAGE" + ] +} diff --git a/test/unitTest/build-tar-gz/build-tar.test.ts b/test/unitTest/build-tar-gz/build-tar.test.ts new file mode 100644 index 0000000..85ae314 --- /dev/null +++ b/test/unitTest/build-tar-gz/build-tar.test.ts @@ -0,0 +1,49 @@ +import { buildWebOn } from "../../../src/build-webon/build-webon"; +import { enableUnitTest } from "../../../src/util/util"; +import tar from "tar"; +import { join, resolve } from "path"; +import { existsSync, mkdirSync, readdirSync, renameSync } from "fs"; + +enableUnitTest(); + +jest.mock("fs"); +jest.mock("tar"); + +test("Should create a tar.gz WebOn file", async () => { + const mockExistsSync = jest.spyOn(require("fs"), "existsSync"); + const mockMkdirSync = jest.spyOn(require("fs"), "mkdirSync"); + const mockRenameSync = jest.spyOn(require("fs"), "renameSync"); + const mockTarCreate = jest.spyOn(tar, "create"); + + // Set up mock data and expectations + const assetDir = "test/out"; + const outDir = resolve(assetDir); + const outDirPath = resolve(assetDir, "..", "out"); + + mockExistsSync.mockReturnValueOnce(true); // "out" directory doesn't exist + mockRenameSync.mockImplementationOnce((source, destination) => { + expect(source).toBe(assetDir); + expect(destination).toBe(outDirPath); + }); + mockMkdirSync.mockImplementationOnce((path) => { + expect(path).toBe(outDir); + }); + + console.log('Directory exists:', existsSync(assetDir)); + // Run the function + await buildWebOn({ assetDir }); + + expect(mockExistsSync).toHaveBeenCalledWith(assetDir); + // expect(mockRenameSync).toHaveBeenCalled(); + expect(mockMkdirSync).toHaveBeenCalled(); + expect(mockTarCreate).toHaveBeenCalledWith( + { + file: expect.any(String), + gzip: true, + }, + [outDir] + ); + + // Clear mocks after the test + jest.clearAllMocks(); +}); \ No newline at end of file