From 8e97f625b75ada5f1ba85a901b184208844523c9 Mon Sep 17 00:00:00 2001 From: joelchu Date: Thu, 19 Sep 2019 22:15:34 +0800 Subject: [PATCH 01/12] remove the publish field that cause problem with npm publish --- packages/http-client/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/http-client/package.json b/packages/http-client/package.json index 562040d0..b19ed596 100755 --- a/packages/http-client/package.json +++ b/packages/http-client/package.json @@ -14,7 +14,7 @@ ], "scripts": { "test": "npm run build && npm run test:browser", - "publish": "npm publish --access public", + "_publish": "npm publish --access public", "prepare": "npm run build", "test:utils": "node ./main.js", "test:node": "DEBUG=jsonql* ava --verbose", -- Gitee From 8998b92f05726a8e4a4898075f05071807154acc Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 15:40:57 +0800 Subject: [PATCH 02/12] move @jsonql/koa back to the jsonql-koa --- .../_tests/fixtures/contract/contract.json | 43 --- .../fixtures/contract/public-contract.json | 50 ---- .../resolvers/mutation/change-something.js | 7 - .../fixtures/resolvers/query/get-something.js | 7 - packages/@jsonql/koa/_tests/fixtures/setup.js | 7 - packages/@jsonql/koa/_tests/fixtures/start.js | 0 packages/@jsonql/koa/_tests/main.test.js | 35 --- packages/@jsonql/koa/package.json | 2 +- packages/koa/Dockerfile | 8 + packages/koa/README.md | 255 +---------------- packages/koa/cjs-README.md | 256 ++++++++++++++++++ packages/koa/cjs-index.js | 50 ++++ .../koa/{src => cjs-src}/auth-middleware.js | 0 .../{src => cjs-src}/console-middleware.js | 0 .../{src => cjs-src}/contract-middleware.js | 0 .../koa/{src => cjs-src}/core-middleware.js | 0 .../errors-handler-middleware.js | 0 .../koa/{src => cjs-src}/hello-middleware.js | 0 packages/koa/{src => cjs-src}/index.js | 0 .../koa/{src => cjs-src}/init-middleware.js | 0 packages/koa/{src => cjs-src}/lib/cache.js | 0 .../lib/config-check/index.js | 0 .../lib/config-check/options.js | 0 .../lib/config-check/process-jwt-keys.js | 0 .../contract-generator/contract-generator.js | 0 .../lib/contract-generator/index.js | 0 .../contract-generator/process-contract.js | 0 .../lib/contract-generator/run.js | 0 packages/koa/{src => cjs-src}/lib/index.js | 0 packages/koa/{src => cjs-src}/lib/utils.js | 0 .../public-method-middleware.js | 0 packages/koa/cjs-tests/auth.test.js | 118 ++++++++ .../koa/{tests => cjs-tests}/chain-fn.test.js | 0 packages/koa/cjs-tests/config.test.js | 50 ++++ packages/koa/cjs-tests/contract.test.js | 28 ++ .../koa/cjs-tests/contractWithAuth.test.js | 62 +++++ packages/koa/cjs-tests/es6-module.test.js | 72 +++++ packages/koa/cjs-tests/fail.test.js | 32 +++ .../fixtures/es/mutation/save-something.js | 9 + .../fixtures/es/query/get-something.js | 8 + .../koa/cjs-tests/fixtures/html/index.html | 9 + .../cjs-tests/fixtures/keys/privateKey.pem | 15 + .../koa/cjs-tests/fixtures/keys/publicKey.pem | 6 + packages/koa/cjs-tests/fixtures/options.js | 28 ++ .../fixtures/resolvers/auth/custom-login.js | 13 + .../resolvers/auth/custom-validator.js | 13 + .../fixtures/resolvers/auth/login.js | 18 ++ .../fixtures/resolvers/auth/logout.js | 8 + .../fixtures/resolvers/auth/validator.js | 14 + .../resolvers/mutation/update-list.js | 12 + .../resolvers/mutation/update-ms-service.js | 13 + .../fixtures/resolvers/query/cause-error.js | 10 + .../fixtures/resolvers/query/get-user.js | 12 + .../resolvers/query/private/get-secret-msg.js | 9 + .../query/public/always-available.js | 7 + .../fixtures/resolvers/query/test-list.js | 13 + .../mutation/sub-update-ms-service.js | 8 + .../sub/resolver/query/sub-ms-service.js | 11 + packages/koa/cjs-tests/helpers/browser.js | 20 ++ packages/koa/cjs-tests/helpers/hello.js | 14 + packages/koa/cjs-tests/helpers/server.js | 21 ++ packages/koa/cjs-tests/helpers/sub-server.js | 24 ++ packages/koa/cjs-tests/jsonp.test.js | 38 +++ packages/koa/cjs-tests/jwt-auth.test.js | 77 ++++++ packages/koa/cjs-tests/jwt.test.js | 66 +++++ packages/koa/cjs-tests/koa.test.js | 124 +++++++++ .../koa/cjs-tests/node-client.donttest.js | 70 +++++ .../koa/cjs-tests/resolverNotFound.test.js | 49 ++++ packages/koa/cjs-tests/throw.test.js | 24 ++ packages/koa/docker-compose.yml | 11 + packages/koa/index.js | 19 +- packages/koa/main.js | 3 + packages/koa/package0.json | 96 +++++++ .../koa/src/contracts/contract-generator.js | 51 ++++ packages/koa/src/contracts/get-contract.js | 42 +++ packages/koa/src/contracts/helpers.js | 94 +++++++ packages/koa/src/contracts/import.js | 2 + packages/koa/src/contracts/index.js | 9 + .../koa/src/contracts/process-contract.js | 41 +++ packages/koa/src/contracts/run.js | 20 ++ .../koa/src/middlewares/auth-middleware.js | 155 +++++++++++ .../koa/src/middlewares/console-middleware.js | 8 + .../src/middlewares/contract-middleware.js | 54 ++++ .../koa/src/middlewares/core-middleware.js | 28 ++ .../koa/src/middlewares/hello-middleware.js | 19 ++ packages/koa/src/middlewares/index.js | 26 ++ .../koa/src/middlewares/init-middleware.js | 144 ++++++++++ .../middlewares/public-method-middleware.js | 28 ++ packages/koa/src/options/index.js | 79 ++++++ packages/koa/src/options/options.js | 113 ++++++++ packages/koa/src/options/process-jwt-keys.js | 70 +++++ packages/koa/src/utils/cache.js | 30 ++ packages/koa/src/utils/index.js | 73 +++++ packages/koa/src/utils/utils.js | 9 + packages/koa/tests/auth.test.js | 0 packages/koa/tests/config.test.js | 10 +- packages/koa/tests/contract.test.js | 8 +- packages/koa/tests/contractWithAuth.test.js | 0 packages/koa/tests/fail.test.js | 0 packages/koa/tests/fixtures/options.js | 0 .../tests/fixtures/resolvers/auth/login.js | 0 .../fixtures/resolvers/auth/validator.js | 0 .../resolvers/mutation/update-list.js | 0 .../fixtures/resolvers/query/cause-error.js | 0 .../fixtures/resolvers/query/get-user.js | 0 .../fixtures/resolvers/query/test-list.js | 0 .../unused/errors-handler-middleware.js | 25 ++ packages/koa/tests/helpers/browser.js | 2 +- packages/koa/tests/helpers/server.js | 11 +- packages/koa/tests/helpers/sub-server.js | 2 +- packages/koa/tests/koa.test.js | 1 + packages/koa/tests/resolverNotFound.test.js | 0 packages/koa/ts/README.md | 5 + 113 files changed, 2707 insertions(+), 426 deletions(-) delete mode 100644 packages/@jsonql/koa/_tests/fixtures/contract/contract.json delete mode 100644 packages/@jsonql/koa/_tests/fixtures/contract/public-contract.json delete mode 100644 packages/@jsonql/koa/_tests/fixtures/resolvers/mutation/change-something.js delete mode 100644 packages/@jsonql/koa/_tests/fixtures/resolvers/query/get-something.js delete mode 100644 packages/@jsonql/koa/_tests/fixtures/setup.js delete mode 100644 packages/@jsonql/koa/_tests/fixtures/start.js delete mode 100644 packages/@jsonql/koa/_tests/main.test.js create mode 100644 packages/koa/Dockerfile mode change 100755 => 100644 packages/koa/README.md create mode 100755 packages/koa/cjs-README.md create mode 100755 packages/koa/cjs-index.js rename packages/koa/{src => cjs-src}/auth-middleware.js (100%) rename packages/koa/{src => cjs-src}/console-middleware.js (100%) rename packages/koa/{src => cjs-src}/contract-middleware.js (100%) rename packages/koa/{src => cjs-src}/core-middleware.js (100%) rename packages/koa/{src => cjs-src}/errors-handler-middleware.js (100%) rename packages/koa/{src => cjs-src}/hello-middleware.js (100%) rename packages/koa/{src => cjs-src}/index.js (100%) rename packages/koa/{src => cjs-src}/init-middleware.js (100%) rename packages/koa/{src => cjs-src}/lib/cache.js (100%) rename packages/koa/{src => cjs-src}/lib/config-check/index.js (100%) rename packages/koa/{src => cjs-src}/lib/config-check/options.js (100%) rename packages/koa/{src => cjs-src}/lib/config-check/process-jwt-keys.js (100%) rename packages/koa/{src => cjs-src}/lib/contract-generator/contract-generator.js (100%) rename packages/koa/{src => cjs-src}/lib/contract-generator/index.js (100%) rename packages/koa/{src => cjs-src}/lib/contract-generator/process-contract.js (100%) rename packages/koa/{src => cjs-src}/lib/contract-generator/run.js (100%) rename packages/koa/{src => cjs-src}/lib/index.js (100%) rename packages/koa/{src => cjs-src}/lib/utils.js (100%) rename packages/koa/{src => cjs-src}/public-method-middleware.js (100%) create mode 100755 packages/koa/cjs-tests/auth.test.js rename packages/koa/{tests => cjs-tests}/chain-fn.test.js (100%) create mode 100644 packages/koa/cjs-tests/config.test.js create mode 100644 packages/koa/cjs-tests/contract.test.js create mode 100755 packages/koa/cjs-tests/contractWithAuth.test.js create mode 100644 packages/koa/cjs-tests/es6-module.test.js create mode 100755 packages/koa/cjs-tests/fail.test.js create mode 100644 packages/koa/cjs-tests/fixtures/es/mutation/save-something.js create mode 100644 packages/koa/cjs-tests/fixtures/es/query/get-something.js create mode 100644 packages/koa/cjs-tests/fixtures/html/index.html create mode 100644 packages/koa/cjs-tests/fixtures/keys/privateKey.pem create mode 100644 packages/koa/cjs-tests/fixtures/keys/publicKey.pem create mode 100755 packages/koa/cjs-tests/fixtures/options.js create mode 100644 packages/koa/cjs-tests/fixtures/resolvers/auth/custom-login.js create mode 100644 packages/koa/cjs-tests/fixtures/resolvers/auth/custom-validator.js create mode 100755 packages/koa/cjs-tests/fixtures/resolvers/auth/login.js create mode 100644 packages/koa/cjs-tests/fixtures/resolvers/auth/logout.js create mode 100755 packages/koa/cjs-tests/fixtures/resolvers/auth/validator.js create mode 100755 packages/koa/cjs-tests/fixtures/resolvers/mutation/update-list.js create mode 100644 packages/koa/cjs-tests/fixtures/resolvers/mutation/update-ms-service.js create mode 100755 packages/koa/cjs-tests/fixtures/resolvers/query/cause-error.js create mode 100755 packages/koa/cjs-tests/fixtures/resolvers/query/get-user.js create mode 100644 packages/koa/cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js create mode 100644 packages/koa/cjs-tests/fixtures/resolvers/query/public/always-available.js create mode 100755 packages/koa/cjs-tests/fixtures/resolvers/query/test-list.js create mode 100644 packages/koa/cjs-tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js create mode 100644 packages/koa/cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js create mode 100644 packages/koa/cjs-tests/helpers/browser.js create mode 100644 packages/koa/cjs-tests/helpers/hello.js create mode 100755 packages/koa/cjs-tests/helpers/server.js create mode 100644 packages/koa/cjs-tests/helpers/sub-server.js create mode 100644 packages/koa/cjs-tests/jsonp.test.js create mode 100644 packages/koa/cjs-tests/jwt-auth.test.js create mode 100644 packages/koa/cjs-tests/jwt.test.js create mode 100755 packages/koa/cjs-tests/koa.test.js create mode 100644 packages/koa/cjs-tests/node-client.donttest.js create mode 100755 packages/koa/cjs-tests/resolverNotFound.test.js create mode 100644 packages/koa/cjs-tests/throw.test.js create mode 100644 packages/koa/docker-compose.yml mode change 100755 => 100644 packages/koa/index.js create mode 100644 packages/koa/main.js create mode 100644 packages/koa/package0.json create mode 100644 packages/koa/src/contracts/contract-generator.js create mode 100644 packages/koa/src/contracts/get-contract.js create mode 100644 packages/koa/src/contracts/helpers.js create mode 100644 packages/koa/src/contracts/import.js create mode 100644 packages/koa/src/contracts/index.js create mode 100644 packages/koa/src/contracts/process-contract.js create mode 100644 packages/koa/src/contracts/run.js create mode 100644 packages/koa/src/middlewares/auth-middleware.js create mode 100644 packages/koa/src/middlewares/console-middleware.js create mode 100644 packages/koa/src/middlewares/contract-middleware.js create mode 100644 packages/koa/src/middlewares/core-middleware.js create mode 100644 packages/koa/src/middlewares/hello-middleware.js create mode 100644 packages/koa/src/middlewares/index.js create mode 100644 packages/koa/src/middlewares/init-middleware.js create mode 100644 packages/koa/src/middlewares/public-method-middleware.js create mode 100644 packages/koa/src/options/index.js create mode 100644 packages/koa/src/options/options.js create mode 100644 packages/koa/src/options/process-jwt-keys.js create mode 100644 packages/koa/src/utils/cache.js create mode 100644 packages/koa/src/utils/index.js create mode 100644 packages/koa/src/utils/utils.js mode change 100755 => 100644 packages/koa/tests/auth.test.js mode change 100755 => 100644 packages/koa/tests/contractWithAuth.test.js mode change 100755 => 100644 packages/koa/tests/fail.test.js mode change 100755 => 100644 packages/koa/tests/fixtures/options.js mode change 100755 => 100644 packages/koa/tests/fixtures/resolvers/auth/login.js mode change 100755 => 100644 packages/koa/tests/fixtures/resolvers/auth/validator.js mode change 100755 => 100644 packages/koa/tests/fixtures/resolvers/mutation/update-list.js mode change 100755 => 100644 packages/koa/tests/fixtures/resolvers/query/cause-error.js mode change 100755 => 100644 packages/koa/tests/fixtures/resolvers/query/get-user.js mode change 100755 => 100644 packages/koa/tests/fixtures/resolvers/query/test-list.js create mode 100644 packages/koa/tests/fixtures/unused/errors-handler-middleware.js mode change 100755 => 100644 packages/koa/tests/helpers/server.js mode change 100755 => 100644 packages/koa/tests/koa.test.js mode change 100755 => 100644 packages/koa/tests/resolverNotFound.test.js create mode 100644 packages/koa/ts/README.md diff --git a/packages/@jsonql/koa/_tests/fixtures/contract/contract.json b/packages/@jsonql/koa/_tests/fixtures/contract/contract.json deleted file mode 100644 index a2d1a028..00000000 --- a/packages/@jsonql/koa/_tests/fixtures/contract/contract.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "query": { - "getSomething": { - "file": "/home/t1s/projects/jsonql/packages/@jsonql/koa/tests/fixtures/resolvers/query/get-something.js", - "description": false, - "params": [], - "returns": [ - { - "type": [ - "string" - ], - "description": "msg" - } - ] - } - }, - "mutation": { - "changeSomething": { - "file": "/home/t1s/projects/jsonql/packages/@jsonql/koa/tests/fixtures/resolvers/mutation/change-something.js", - "description": false, - "params": [ - { - "type": [ - "string" - ], - "name": "payload", - "description": "what to change" - } - ], - "returns": [ - { - "type": [ - "string" - ], - "description": "a mutated message" - } - ] - } - }, - "auth": {}, - "timestamp": 1566673914939, - "sourceType": "script" -} diff --git a/packages/@jsonql/koa/_tests/fixtures/contract/public-contract.json b/packages/@jsonql/koa/_tests/fixtures/contract/public-contract.json deleted file mode 100644 index 8c197ff0..00000000 --- a/packages/@jsonql/koa/_tests/fixtures/contract/public-contract.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "query": { - "helloWorld": { - "description": "This is the stock resolver for testing purpose", - "params": [], - "returns": [ - { - "type": "string", - "description": "stock message" - } - ] - }, - "getSomething": { - "description": false, - "params": [], - "returns": [ - { - "type": [ - "string" - ], - "description": "msg" - } - ] - } - }, - "mutation": { - "changeSomething": { - "description": false, - "params": [ - { - "type": [ - "string" - ], - "name": "payload", - "description": "what to change" - } - ], - "returns": [ - { - "type": [ - "string" - ], - "description": "a mutated message" - } - ] - } - }, - "auth": {}, - "timestamp": 1566673914976 -} diff --git a/packages/@jsonql/koa/_tests/fixtures/resolvers/mutation/change-something.js b/packages/@jsonql/koa/_tests/fixtures/resolvers/mutation/change-something.js deleted file mode 100644 index 5bf48fa8..00000000 --- a/packages/@jsonql/koa/_tests/fixtures/resolvers/mutation/change-something.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @param {string} payload what to change - * @return {string} a mutated message - */ -module.exports = function changeSomething(payload) { - return `Bye ${payload}` -} diff --git a/packages/@jsonql/koa/_tests/fixtures/resolvers/query/get-something.js b/packages/@jsonql/koa/_tests/fixtures/resolvers/query/get-something.js deleted file mode 100644 index 8fa81a4e..00000000 --- a/packages/@jsonql/koa/_tests/fixtures/resolvers/query/get-something.js +++ /dev/null @@ -1,7 +0,0 @@ -/** - * @return {string} msg - * - */ -module.exports = function getSomething() { - return `Hello` -} diff --git a/packages/@jsonql/koa/_tests/fixtures/setup.js b/packages/@jsonql/koa/_tests/fixtures/setup.js deleted file mode 100644 index 07e066bb..00000000 --- a/packages/@jsonql/koa/_tests/fixtures/setup.js +++ /dev/null @@ -1,7 +0,0 @@ -const server = require('../../') -const { join } = require('path') - -module.exports = () => server({ - resolverDir: join(__dirname, 'resolvers'), - contractDir: join(__dirname, 'contract') -}) diff --git a/packages/@jsonql/koa/_tests/fixtures/start.js b/packages/@jsonql/koa/_tests/fixtures/start.js deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/@jsonql/koa/_tests/main.test.js b/packages/@jsonql/koa/_tests/main.test.js deleted file mode 100644 index 49f24071..00000000 --- a/packages/@jsonql/koa/_tests/main.test.js +++ /dev/null @@ -1,35 +0,0 @@ -// The main test -const test = require('ava') -const server = require('./fixtures/setup') -const superkoa = require('superkoa') - -const { DEFAULT_HEADER } = require('jsonql-constants') - -test.before(t => { - const { app, stop } = server() - t.context.app = app; - t.context.stop = stop; -}) - -test.after(t => { - t.context.stop() -}) - -test(`It should able to say hello world`, async t=>{ - let res = await superkoa(t.context.app) - .post('/jsonql') - .set(DEFAULT_HEADER) - .send({ - helloWorld: { - args: [] - } - }) - - - t.is(200, res.status) - -}) - -test.todo(`It should able to query the jsonql api`) - -test.todo(`It should able to mutated with jsonql api`) diff --git a/packages/@jsonql/koa/package.json b/packages/@jsonql/koa/package.json index ab9ee391..261d09c2 100644 --- a/packages/@jsonql/koa/package.json +++ b/packages/@jsonql/koa/package.json @@ -1,6 +1,6 @@ { "name": "@jsonql/koa", - "version": "0.2.6", + "version": "0.3.0", "description": "jsonql Koa middleware", "main": "main.js", "module": "index.js", diff --git a/packages/koa/Dockerfile b/packages/koa/Dockerfile new file mode 100644 index 00000000..97ae4701 --- /dev/null +++ b/packages/koa/Dockerfile @@ -0,0 +1,8 @@ +FROM node:lts-alpine + +WORKDIR /usr/app + +COPY package.json . +RUN npm install --quiet + +COPY . . diff --git a/packages/koa/README.md b/packages/koa/README.md old mode 100755 new mode 100644 index 9ae1048b..43d59f64 --- a/packages/koa/README.md +++ b/packages/koa/README.md @@ -1,256 +1,9 @@ -[![NPM](https://nodei.co/npm/jsonql-koa.png?compact=true)](https://npmjs.org/package/jsonql-koa) +# @jsonql/koa -# jsonql Koa middleware +> This is the jsonql middleware previously published as jsonql-koa, and completely rewritten with ES6 -> An API construction tool for super fast development. - -**Many of this README is already outdated, we are preparing the complete documentation at this moment. -And it will publish to our website [jsonql.org](http://jsonql.org) shortly** - -## Installation - -```sh -$ npm install jsonql-koa --save -``` - -or - -```sh -$ yarn add jsonql-koa -``` - -## Configuration - -## Required Middlewares - -Also you need to install middleware to parse the JSON content. -Here we use [koa-bodyparser](https://github.com/koajs/bodyparser). - -```js -const Koa = require('koa'); -const jsonqlKoa = require('jsonql-koa'); -const bodyparser = require('koa-bodyparser'); -const { join } = require('path'); - -const app = new Koa(); -app.use(bodyparser()); -app.use(jsonqlKoa({ - resolverDir: join(__dirname, 'resolvers'), // this is the default value - jsonqlPath: '/jsonql' // default value -})); - -``` - -## Resolver(s) - -We expect the file in dasherized name style. - -For example you resolver directory in `/resolvers`, -and your resolver name `fetchList`, therefore you file name should be: -`/resolvers/query/fetch-list.js`. - -To properly organise your application. You should have something like This - -```sh -/resolvers/query/name-of-your-call/index.js - /lib.js - /utils.js -/resolvers/mutation/name-of-your-update/index.js -... -``` - -This way you can separate the export main function to your helpers / utils what not. -Also that makes the contract generator much easier to understand your project and create -the contract without your input. - -And your resolver should look like this - -```js -// fetchList -/** - * @param {object} params bunch of stuff - * @return {object} modified bunch of stuff - */ -module.exports = function(params) { - params.modified = parseInt((new Date()).getTime()/1000, 10); - // some more things with your params - return params; -} -``` - -The middleware is using Async/Await internally, so you could return a promise. - -### ES6 support - -As of V1.3.0 release. You can use ES6 module syntax for your resolver. If you using ES6 then you have to use -all of them as ES6 modules, it doesn't support mix and match. The reason is we have to inject a [esm](https://www.npmjs.com/package/esm) export script -to transpire your ES6 module to common js on the fly and import into your Koa middleware. - -```js -/** - * @param {number} id - * @return {any} your result - */ -export default function getSomethingById(id) { - // return your result -} -``` - -## Return Data format - -The result data will be wrap inside this signature - -``` -{ - data: { - yourData: 'something' - } -} -``` - -We will be adapting more of the [JSON API](http://jsonapi.org/) shortly - -## What you can do with this system - -There are four types within this system you can call. - -- query - Think of it as the REST API GET, where you get things -- mutation - Use this when you want to change something -- auth - Authorization methods -- socket - Coming soon - -### Query - -When you using our [js client](https://www.npmjs.com/package/jsonql-client) or [node client](https://www.npmjs.com/package/jsonql-node-client) - -It will generate function for you based on the `contract` file it received. - -__From V.1 onward we will turn on the useDoc option, which means you are **REQUIRED** to write correct jsdoc for your resolvers__ - -For example you have this resolver: - -```js -// ~/project/resolvers/query/ask-what-date.js -/** - * @return {string} UTC Date - */ -module.exports = function() { - return Date.UTC(); -} - -``` - -On your client will received what wrap inside the `data` property. - -If you throw an error inside your function call: - -```js -/** - * @return {object} just throw - */ -module.exports = function() { - throw new Error("I don't know"); -} -``` - -This will get catch and wrap inside the `result.error` field. And it will get throw on the client. -But you will always received a status 200. Because this is application level error. Nothing todo with the transport. - -Query can have as many arguments as you want. - -```js -/** - * @param {number} a - * @param {number} b - * @param {number} c - * @param {number} [d=10] - * @return {number} sum of them - */ -module.exports = function(a, b, c, d=10) { - return a + b + c + d; -} -``` - -The follow is no longer valid, we will provide you with a `CURRENT_LOGIN_USER` global object. - -~~And when this application is using the `auth` option (lock down mode). After you have successfully login and obtain the -authorisation token, every time after the successfully auth call, you will received the return value from your `validator` -method as your arguments + 1, so the above method in fact will become:~~ - ---- - -We have one built in query call `helloWorld`, it return `Hello world!`. -It will always be available. And even if you use `auth:true` option. -You do not need to login before you can access it. This is handy to ping the server and see if your set is correct. -Especially when you are writing test for your application. - -### Mutation - -The different between query and mutation is, mutation has fixed number of arguments - -```js -/** - * For the payload it will be a bit more tricky to write jsdoc - * @param {object} payload - the submit payload - * @param {string} payload.username user name - * @param {object} conditions where cause - * @param {number} conditions.user_id to id the user - * @return {boolean} true on success - */ -module.exports = function(payload, conditions) { - // your code -} - -``` - -### Auth - -There are only two authorisation methods - -1. `issuer` - basically what you do to login -2. `validator` - every time the client request your API, this method will get call and validator against the token in the header. -3. `logout` - it does what it said on the tin. - -How you implement the login and validation, it's entirely up to you as a developer. And `issuer` is just a type of `query`. -It has all the signature just like a normal query. The only different is, it will never received any additional parameter. - -The naming is important, you must name your function file as `/projects/resolvers/auth/issuer.js` and `/projects/resolvers/auth/validator.js`. Any other location or file name will not be found, and middleware will throw error. - -### socket - -This require out other module `jsonql-ws-server` to setup. More coming soon. - -## Contract - -**BREAKING CHANAGE** - -We will start using the jsdoc to capture your parameter and returns type. Therefore from V.1 release onward it will be **REQUIRED** to write correct jsdoc. This is important because -the client side will be expecting correct type information for -the validation to work correctly. Also this solve a problem of -unable to pass default parameter to pass the resolver. - -__And the typescript port currently under development will able to work with the standard JS server side, ,as well as the Typescript version__ - ---- - -Contracts are generate automatically when you start up your application. We have a separate tool [jsonql-contract](https://www.npmjs.com/package/jsonql-contract) to generate the contract file (it just a json file contain information about your applications). For internal user, the file is call `contract.json` it will located in the `contractDir` -you specify when you config the middleware, default location will be `~/project/contracts`. - -There is another contract that is for your client to consume, which is name `public-contract.json`. It has the same structure -but without some of the sensitive information, such as the `file` field (where your code located) and the `validator` field. - -If you are not using `auth:true` option, then even if you implement the `auth/issuer.js` method, it will get remove as well. - -Also whenever the client request the contract. It will look for additional json file in the same folder. - -For instance, your `NODE_ENV=development` therefore, it will search for `~/project/contracts/development.json` and this will -get merge with the stock `public-contract.json`. Therefore you can overwrite information (but not remove) or add additional -information, such as change the return field, and write a auto validator based on the result you received. - -Also you can set a password to avoid unwanted access to your contract. Just pass the `contractKey:[password]` to the config -object. +Please check [jsonql.org](https://jsonql.js.org) for more information. --- -MIT (c) 2019 [to1source China](https://to1source.cn) -in collaboration with [NEWBRAN LTD UK](https://newbran.ch) +NB & T1S diff --git a/packages/koa/cjs-README.md b/packages/koa/cjs-README.md new file mode 100755 index 00000000..9ae1048b --- /dev/null +++ b/packages/koa/cjs-README.md @@ -0,0 +1,256 @@ +[![NPM](https://nodei.co/npm/jsonql-koa.png?compact=true)](https://npmjs.org/package/jsonql-koa) + +# jsonql Koa middleware + +> An API construction tool for super fast development. + +**Many of this README is already outdated, we are preparing the complete documentation at this moment. +And it will publish to our website [jsonql.org](http://jsonql.org) shortly** + +## Installation + +```sh +$ npm install jsonql-koa --save +``` + +or + +```sh +$ yarn add jsonql-koa +``` + +## Configuration + +## Required Middlewares + +Also you need to install middleware to parse the JSON content. +Here we use [koa-bodyparser](https://github.com/koajs/bodyparser). + +```js +const Koa = require('koa'); +const jsonqlKoa = require('jsonql-koa'); +const bodyparser = require('koa-bodyparser'); +const { join } = require('path'); + +const app = new Koa(); +app.use(bodyparser()); +app.use(jsonqlKoa({ + resolverDir: join(__dirname, 'resolvers'), // this is the default value + jsonqlPath: '/jsonql' // default value +})); + +``` + +## Resolver(s) + +We expect the file in dasherized name style. + +For example you resolver directory in `/resolvers`, +and your resolver name `fetchList`, therefore you file name should be: +`/resolvers/query/fetch-list.js`. + +To properly organise your application. You should have something like This + +```sh +/resolvers/query/name-of-your-call/index.js + /lib.js + /utils.js +/resolvers/mutation/name-of-your-update/index.js +... +``` + +This way you can separate the export main function to your helpers / utils what not. +Also that makes the contract generator much easier to understand your project and create +the contract without your input. + +And your resolver should look like this + +```js +// fetchList +/** + * @param {object} params bunch of stuff + * @return {object} modified bunch of stuff + */ +module.exports = function(params) { + params.modified = parseInt((new Date()).getTime()/1000, 10); + // some more things with your params + return params; +} +``` + +The middleware is using Async/Await internally, so you could return a promise. + +### ES6 support + +As of V1.3.0 release. You can use ES6 module syntax for your resolver. If you using ES6 then you have to use +all of them as ES6 modules, it doesn't support mix and match. The reason is we have to inject a [esm](https://www.npmjs.com/package/esm) export script +to transpire your ES6 module to common js on the fly and import into your Koa middleware. + +```js +/** + * @param {number} id + * @return {any} your result + */ +export default function getSomethingById(id) { + // return your result +} +``` + +## Return Data format + +The result data will be wrap inside this signature + +``` +{ + data: { + yourData: 'something' + } +} +``` + +We will be adapting more of the [JSON API](http://jsonapi.org/) shortly + +## What you can do with this system + +There are four types within this system you can call. + +- query - Think of it as the REST API GET, where you get things +- mutation - Use this when you want to change something +- auth - Authorization methods +- socket - Coming soon + +### Query + +When you using our [js client](https://www.npmjs.com/package/jsonql-client) or [node client](https://www.npmjs.com/package/jsonql-node-client) + +It will generate function for you based on the `contract` file it received. + +__From V.1 onward we will turn on the useDoc option, which means you are **REQUIRED** to write correct jsdoc for your resolvers__ + +For example you have this resolver: + +```js +// ~/project/resolvers/query/ask-what-date.js +/** + * @return {string} UTC Date + */ +module.exports = function() { + return Date.UTC(); +} + +``` + +On your client will received what wrap inside the `data` property. + +If you throw an error inside your function call: + +```js +/** + * @return {object} just throw + */ +module.exports = function() { + throw new Error("I don't know"); +} +``` + +This will get catch and wrap inside the `result.error` field. And it will get throw on the client. +But you will always received a status 200. Because this is application level error. Nothing todo with the transport. + +Query can have as many arguments as you want. + +```js +/** + * @param {number} a + * @param {number} b + * @param {number} c + * @param {number} [d=10] + * @return {number} sum of them + */ +module.exports = function(a, b, c, d=10) { + return a + b + c + d; +} +``` + +The follow is no longer valid, we will provide you with a `CURRENT_LOGIN_USER` global object. + +~~And when this application is using the `auth` option (lock down mode). After you have successfully login and obtain the +authorisation token, every time after the successfully auth call, you will received the return value from your `validator` +method as your arguments + 1, so the above method in fact will become:~~ + +--- + +We have one built in query call `helloWorld`, it return `Hello world!`. +It will always be available. And even if you use `auth:true` option. +You do not need to login before you can access it. This is handy to ping the server and see if your set is correct. +Especially when you are writing test for your application. + +### Mutation + +The different between query and mutation is, mutation has fixed number of arguments + +```js +/** + * For the payload it will be a bit more tricky to write jsdoc + * @param {object} payload - the submit payload + * @param {string} payload.username user name + * @param {object} conditions where cause + * @param {number} conditions.user_id to id the user + * @return {boolean} true on success + */ +module.exports = function(payload, conditions) { + // your code +} + +``` + +### Auth + +There are only two authorisation methods + +1. `issuer` - basically what you do to login +2. `validator` - every time the client request your API, this method will get call and validator against the token in the header. +3. `logout` - it does what it said on the tin. + +How you implement the login and validation, it's entirely up to you as a developer. And `issuer` is just a type of `query`. +It has all the signature just like a normal query. The only different is, it will never received any additional parameter. + +The naming is important, you must name your function file as `/projects/resolvers/auth/issuer.js` and `/projects/resolvers/auth/validator.js`. Any other location or file name will not be found, and middleware will throw error. + +### socket + +This require out other module `jsonql-ws-server` to setup. More coming soon. + +## Contract + +**BREAKING CHANAGE** + +We will start using the jsdoc to capture your parameter and returns type. Therefore from V.1 release onward it will be **REQUIRED** to write correct jsdoc. This is important because +the client side will be expecting correct type information for +the validation to work correctly. Also this solve a problem of +unable to pass default parameter to pass the resolver. + +__And the typescript port currently under development will able to work with the standard JS server side, ,as well as the Typescript version__ + +--- + +Contracts are generate automatically when you start up your application. We have a separate tool [jsonql-contract](https://www.npmjs.com/package/jsonql-contract) to generate the contract file (it just a json file contain information about your applications). For internal user, the file is call `contract.json` it will located in the `contractDir` +you specify when you config the middleware, default location will be `~/project/contracts`. + +There is another contract that is for your client to consume, which is name `public-contract.json`. It has the same structure +but without some of the sensitive information, such as the `file` field (where your code located) and the `validator` field. + +If you are not using `auth:true` option, then even if you implement the `auth/issuer.js` method, it will get remove as well. + +Also whenever the client request the contract. It will look for additional json file in the same folder. + +For instance, your `NODE_ENV=development` therefore, it will search for `~/project/contracts/development.json` and this will +get merge with the stock `public-contract.json`. Therefore you can overwrite information (but not remove) or add additional +information, such as change the return field, and write a auto validator based on the result you received. + +Also you can set a password to avoid unwanted access to your contract. Just pass the `contractKey:[password]` to the config +object. + +--- + +MIT (c) 2019 [to1source China](https://to1source.cn) +in collaboration with [NEWBRAN LTD UK](https://newbran.ch) diff --git a/packages/koa/cjs-index.js b/packages/koa/cjs-index.js new file mode 100755 index 00000000..eb25d4da --- /dev/null +++ b/packages/koa/cjs-index.js @@ -0,0 +1,50 @@ +'use strict'; +/** + * This is the main interface to export the middleware(s) + * we will take the config here and export array of middleware using koa-compose + */ +const fs = require('fs') +const merge = require('lodash.merge') +const compose = require('koa-compose') +const { + configCheck, + coreMiddleware, + authMiddleware, + contractMiddleware, + helloMiddleware, + consoleMiddleware, + publicMethodMiddleware, + errorsHandlerMiddleware, + initMiddleware +} = require('./src') +const { getDebug } = require('./src/lib') + +const debug = getDebug('main') +// main +module.exports = function(config = {}) { + // first check the config + const opts = configCheck(config) + debug('[jsonql-koa] init opts', opts) + // export + let middlewares = [ + initMiddleware(opts), + helloMiddleware(opts), + contractMiddleware(opts) + ] + // only available when enable it + if (config.enableWebConsole) { + middlewares.push(consoleMiddleware(opts)) + } + + if (opts.enableAuth) { + middlewares.push( + publicMethodMiddleware(opts), + authMiddleware(opts) + ) + } + middlewares.push( + coreMiddleware(opts) + ) + // finally + return compose(middlewares) +} diff --git a/packages/koa/src/auth-middleware.js b/packages/koa/cjs-src/auth-middleware.js similarity index 100% rename from packages/koa/src/auth-middleware.js rename to packages/koa/cjs-src/auth-middleware.js diff --git a/packages/koa/src/console-middleware.js b/packages/koa/cjs-src/console-middleware.js similarity index 100% rename from packages/koa/src/console-middleware.js rename to packages/koa/cjs-src/console-middleware.js diff --git a/packages/koa/src/contract-middleware.js b/packages/koa/cjs-src/contract-middleware.js similarity index 100% rename from packages/koa/src/contract-middleware.js rename to packages/koa/cjs-src/contract-middleware.js diff --git a/packages/koa/src/core-middleware.js b/packages/koa/cjs-src/core-middleware.js similarity index 100% rename from packages/koa/src/core-middleware.js rename to packages/koa/cjs-src/core-middleware.js diff --git a/packages/koa/src/errors-handler-middleware.js b/packages/koa/cjs-src/errors-handler-middleware.js similarity index 100% rename from packages/koa/src/errors-handler-middleware.js rename to packages/koa/cjs-src/errors-handler-middleware.js diff --git a/packages/koa/src/hello-middleware.js b/packages/koa/cjs-src/hello-middleware.js similarity index 100% rename from packages/koa/src/hello-middleware.js rename to packages/koa/cjs-src/hello-middleware.js diff --git a/packages/koa/src/index.js b/packages/koa/cjs-src/index.js similarity index 100% rename from packages/koa/src/index.js rename to packages/koa/cjs-src/index.js diff --git a/packages/koa/src/init-middleware.js b/packages/koa/cjs-src/init-middleware.js similarity index 100% rename from packages/koa/src/init-middleware.js rename to packages/koa/cjs-src/init-middleware.js diff --git a/packages/koa/src/lib/cache.js b/packages/koa/cjs-src/lib/cache.js similarity index 100% rename from packages/koa/src/lib/cache.js rename to packages/koa/cjs-src/lib/cache.js diff --git a/packages/koa/src/lib/config-check/index.js b/packages/koa/cjs-src/lib/config-check/index.js similarity index 100% rename from packages/koa/src/lib/config-check/index.js rename to packages/koa/cjs-src/lib/config-check/index.js diff --git a/packages/koa/src/lib/config-check/options.js b/packages/koa/cjs-src/lib/config-check/options.js similarity index 100% rename from packages/koa/src/lib/config-check/options.js rename to packages/koa/cjs-src/lib/config-check/options.js diff --git a/packages/koa/src/lib/config-check/process-jwt-keys.js b/packages/koa/cjs-src/lib/config-check/process-jwt-keys.js similarity index 100% rename from packages/koa/src/lib/config-check/process-jwt-keys.js rename to packages/koa/cjs-src/lib/config-check/process-jwt-keys.js diff --git a/packages/koa/src/lib/contract-generator/contract-generator.js b/packages/koa/cjs-src/lib/contract-generator/contract-generator.js similarity index 100% rename from packages/koa/src/lib/contract-generator/contract-generator.js rename to packages/koa/cjs-src/lib/contract-generator/contract-generator.js diff --git a/packages/koa/src/lib/contract-generator/index.js b/packages/koa/cjs-src/lib/contract-generator/index.js similarity index 100% rename from packages/koa/src/lib/contract-generator/index.js rename to packages/koa/cjs-src/lib/contract-generator/index.js diff --git a/packages/koa/src/lib/contract-generator/process-contract.js b/packages/koa/cjs-src/lib/contract-generator/process-contract.js similarity index 100% rename from packages/koa/src/lib/contract-generator/process-contract.js rename to packages/koa/cjs-src/lib/contract-generator/process-contract.js diff --git a/packages/koa/src/lib/contract-generator/run.js b/packages/koa/cjs-src/lib/contract-generator/run.js similarity index 100% rename from packages/koa/src/lib/contract-generator/run.js rename to packages/koa/cjs-src/lib/contract-generator/run.js diff --git a/packages/koa/src/lib/index.js b/packages/koa/cjs-src/lib/index.js similarity index 100% rename from packages/koa/src/lib/index.js rename to packages/koa/cjs-src/lib/index.js diff --git a/packages/koa/src/lib/utils.js b/packages/koa/cjs-src/lib/utils.js similarity index 100% rename from packages/koa/src/lib/utils.js rename to packages/koa/cjs-src/lib/utils.js diff --git a/packages/koa/src/public-method-middleware.js b/packages/koa/cjs-src/public-method-middleware.js similarity index 100% rename from packages/koa/src/public-method-middleware.js rename to packages/koa/cjs-src/public-method-middleware.js diff --git a/packages/koa/cjs-tests/auth.test.js b/packages/koa/cjs-tests/auth.test.js new file mode 100755 index 00000000..6f627ba8 --- /dev/null +++ b/packages/koa/cjs-tests/auth.test.js @@ -0,0 +1,118 @@ +const test = require('ava') + +const superkoa = require('superkoa') +const { join } = require('path') +const debug = require('debug')('jsonql-koa:test:auth') +const { createQuery } = require('jsonql-utils') +const fsx = require('fs-extra') +const { merge } = require('lodash') +const { HELLO_FN } = require('jsonql-constants') +const jsonqlMiddleware = require(join(__dirname, '..', 'index')) +const { type, headers, dirs, bearer, contractKeyName } = require('./fixtures/options') +const createServer = require('./helpers/server') +const myKey = '4670994sdfkl'; +const dir = 'auth'; +const thisHeader = merge({}, {[contractKeyName]: myKey}, headers) + +test.before((t) => { + t.context.app = createServer({ + useJwt: false, + enableAuth: true, + contractKey: myKey + }, dir) +}) + +test.after( () => { + // remove the files after + fsx.removeSync(join(dirs.contractDir, dir)) +}) + +// Start running test(s) + +test("Should NOT fail this Hello world test even I am not login", async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(thisHeader) + .send( + createQuery(HELLO_FN) + ); + t.is(200, res.status) +}) + +test("The public-contract.json file should contain issuer information", async t => { + let res = await superkoa(t.context.app) + .get('/jsonql') + .query({_cb: Date.now()}) + .set(thisHeader); + + t.truthy(res.body.data.auth.login) +}) + + +test('Should able to login with this credential', async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(thisHeader) + .send( + createQuery('login', ['nobody', myKey]) + ); + t.is(200, res.status) + t.is(bearer, res.body.data) +}) + +test('Should cause a JsonqlAuthorisationError if I pass the wrong username or password', async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(thisHeader) + .send( + createQuery('login', ['body-x', myKey]) + ); + + t.is(200, res.status) + t.truthy(res.body.error) +}) + + +test("It should able to call a method that is mark as public without login", async t => { + // alwaysAvailable + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(headers) + .send( + createQuery('alwaysAvailable') + ); + t.is(200, res.status) + t.is('Hello there', res.body.data) +}) + +test('Now I should able to call the api with credential', async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(merge({} , thisHeader, {Authorization: `Bearer ${bearer}`})) + .send( + createQuery('getUser', ['testing', 'userId']) + ); + t.is(200, res.status) + // debug(res.body) + t.is(1, res.body.data.userId) +}) + +test("Should NOT able to call the logout method without the Bearer", async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(merge({} , thisHeader)) + .send( + createQuery('logout') + ); + + t.is(200, res.status) + // should get an error object + t.truthy(res.body.error) + +}) diff --git a/packages/koa/tests/chain-fn.test.js b/packages/koa/cjs-tests/chain-fn.test.js similarity index 100% rename from packages/koa/tests/chain-fn.test.js rename to packages/koa/cjs-tests/chain-fn.test.js diff --git a/packages/koa/cjs-tests/config.test.js b/packages/koa/cjs-tests/config.test.js new file mode 100644 index 00000000..f9ea2ac1 --- /dev/null +++ b/packages/koa/cjs-tests/config.test.js @@ -0,0 +1,50 @@ +// testing the config +const test = require('ava') +const fsx = require('fs-extra') +const { join, resolve } = require('path') +const configCheck = require('../src/lib/config-check') +const { processJwtKeys } = require('../src/lib') +const { jwtProcessKey } = require('../src/lib/config-check/options') +const debug = require('debug')('jsonql-koa:test:config') +const resolverDir = join(__dirname, 'fixtures', 'resolvers') +const contractDir = join(__dirname, 'fixtures', 'tmp', 'config-test') +const keysDir = join(__dirname, 'fixtures', 'tmp', 'keys') + +// mocking a ctx object +let ctx = { + state: { + jsonql: { + setter: () => {}, + getter: () => {} + } + } +} + +test.after( t => { + // fsx.removeSync(keysDir) +}) + +test('It should able to check the in dir', t => { + const opts = configCheck({ + resolverDir, + contractDir + }) + + const dir = resolve(resolverDir) + t.is( dir, opts.resolverDir ) +}); + +test('It should have privateKey and publicKey when set useJwt = true', async t => { + let opts = configCheck({ + enableAuth: true, + useJwt: true, + resolverDir, + contractDir, + keysDir + }) + + opts = await processJwtKeys(ctx, opts) + + t.truthy(opts.privateKey && opts.publicKey) + +}) diff --git a/packages/koa/cjs-tests/contract.test.js b/packages/koa/cjs-tests/contract.test.js new file mode 100644 index 00000000..40b2466d --- /dev/null +++ b/packages/koa/cjs-tests/contract.test.js @@ -0,0 +1,28 @@ +// separate test for the contract interface +const test = require('ava') +const { join } = require('path') +const fsx = require('fs-extra') +const generator = require('../src/lib/contract-generator') +const { isContractJson } = require('../src/lib') +const debug = require('debug')('jsonql-koa:test:gen') +const contractDir = join(__dirname, 'fixtures', 'tmp', 'generator') +const resolverDir = join(__dirname, 'fixtures', 'resolvers') + +test.before(t => { + t.context.initContract = generator({ + contractDir, + resolverDir, + returnAs: 'json' + }) +}) + +test.after( t => { + fsx.removeSync(contractDir) +}) + +test('It should able to generate a contract file', async t => { + // this way can test if this setup works for the middleware as well + const contract = await t.context.initContract; + debug(contract) + t.truthy(isContractJson(contract)) +}) diff --git a/packages/koa/cjs-tests/contractWithAuth.test.js b/packages/koa/cjs-tests/contractWithAuth.test.js new file mode 100755 index 00000000..beb345c8 --- /dev/null +++ b/packages/koa/cjs-tests/contractWithAuth.test.js @@ -0,0 +1,62 @@ +// we test all the fail scenario here +const test = require('ava') + +const superkoa = require('superkoa') +const { join } = require('path') +const debug = require('debug')('jsonql-koa:test:fail') +const { merge } = require('lodash') +const { type, headers, dirs, returns, contractKeyName } = require('./fixtures/options') +const fsx = require('fs-extra') +const myKey = '4670994sdfkl'; +const expired = Date.now() + 60*24*365*1000; +const createServer = require('./helpers/server') +const dir = 'withauth'; + +test.before((t) => { + + t.context.app = createServer({ + expired, + contractKey: myKey + }, dir) +}) + +test.after( () => { + fsx.removeSync(join(dirs.contractDir, dir)) + +}) + + +test("It should Not return a contract", async (t) => { + let res = await superkoa(t.context.app) + .get('/jsonql') + .query({_cb: Date.now()}) + .set(headers) + + t.is(401, res.body.error.statusCode) +}) + + +test("It should able to get contract with a key", async (t) => { + + let res = await superkoa(t.context.app) + .get('/jsonql') + .query({_cb: Date.now()}) + .set(merge({}, headers, { + [contractKeyName]: myKey + })) + + t.is(200, res.status) + t.is(res.body.data.expired, expired) + t.deepEqual(returns, res.body.data.query.helloWorld.returns) +}) + +test("It should fail to get contract if we provide the wrong password", async t => { + let res = await superkoa(t.context.app) + .get('/jsonql') + .query({_cb: Date.now()}) + .set(merge({}, headers, { + [contractKeyName]: 'what-ever-that-key' + })) + + t.is(401, res.body.error.statusCode) +}) diff --git a/packages/koa/cjs-tests/es6-module.test.js b/packages/koa/cjs-tests/es6-module.test.js new file mode 100644 index 00000000..a5dbcf0d --- /dev/null +++ b/packages/koa/cjs-tests/es6-module.test.js @@ -0,0 +1,72 @@ +// testing the new ES6 modules import +const test = require('ava') +const { join } = require('path') +const fsx = require('fs-extra') +const superkoa = require('superkoa') +const { + DEFAULT_RESOLVER_LIST_FILE_NAME, + DEFAULT_RESOLVER_IMPORT_FILE_NAME, + HELLO_FN +} = require('jsonql-constants') +const { createQuery } = require('jsonql-utils') +const debug = require('debug')('jsonql-koa:test:es6') + +const { headers } = require('./fixtures/options') +const createServer = require('./helpers/server') + +const esResolverDir = join(__dirname, 'fixtures', 'es') +const esContractDir = join(__dirname, 'fixtures', 'tmp', 'es') + +const dir = 'es6'; + +test.before( t => { + t.context.app = createServer({ + resolverDir: esResolverDir, + contractDir: esContractDir + }, dir) +}) + +test.after( t => { + fsx.removeSync( esContractDir ) + fsx.removeSync( join(esResolverDir, DEFAULT_RESOLVER_LIST_FILE_NAME) ) + fsx.removeSync( join(esResolverDir, DEFAULT_RESOLVER_IMPORT_FILE_NAME) ) +}) + +test('It should able to generate the contract with es6 modules', async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(headers) + .send( + createQuery(HELLO_FN) + ) + t.is(200, res.status) + t.true( fsx.existsSync( join(esContractDir, 'contract.json') ) ) +}) + +test('It should able to handle a ES6 function', async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(headers) + .send( + createQuery('getSomething') + ) + t.is(200, res.status) + + t.true(Array.isArray(res.body.data)) + +}) + +test('It should able to serve up the correct public contract', async t => { + + let res = await superkoa(t.context.app) + .get('/jsonql') + .query({_cb: Date.now()}) + .set(headers) + + t.is(200, res.status) + + t.truthy(res.body.data.timestamp) + +}) diff --git a/packages/koa/cjs-tests/fail.test.js b/packages/koa/cjs-tests/fail.test.js new file mode 100755 index 00000000..c7a6acd6 --- /dev/null +++ b/packages/koa/cjs-tests/fail.test.js @@ -0,0 +1,32 @@ +// we test all the fail scenario here +const test = require('ava') +const superkoa = require('superkoa') +const { join } = require('path') +const debug = require('debug')('jsonql-koa:test:fail') +const jsonqlMiddleware = require(join(__dirname, '..', 'index')) +const { type, headers, dirs } = require('./fixtures/options') +const fsx = require('fs-extra') + +const createServer = require('./helpers/server') + +test.before((t) => { + t.context.app = createServer({}, 'failed'); +}) + +test.after( () => { + // remove the files after + fsx.removeSync(join(dirs.contractDir, 'failed')) +}) + +test("Should fail this Hello world test", async t => { + let res = await superkoa(t.context.app) + .post('/jsonql/somethingelse?_cb=9082390483204830') + .set(headers) + .send({ + helloWorld: { + args: {} + } + }) + t.is(404, res.status) + +}) diff --git a/packages/koa/cjs-tests/fixtures/es/mutation/save-something.js b/packages/koa/cjs-tests/fixtures/es/mutation/save-something.js new file mode 100644 index 00000000..ea30ca67 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/es/mutation/save-something.js @@ -0,0 +1,9 @@ + +/** + * @param {object} payload + * @param {object} condition + * @return {boolean} true on OK + */ +export default function saveSomething(payload, condition) { + return true; +} diff --git a/packages/koa/cjs-tests/fixtures/es/query/get-something.js b/packages/koa/cjs-tests/fixtures/es/query/get-something.js new file mode 100644 index 00000000..9a5d7c8c --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/es/query/get-something.js @@ -0,0 +1,8 @@ + + +/** + * @return {array} list of something + */ +export default function getSomething() { + return ['Hello there'] +} diff --git a/packages/koa/cjs-tests/fixtures/html/index.html b/packages/koa/cjs-tests/fixtures/html/index.html new file mode 100644 index 00000000..d1fdcefb --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/html/index.html @@ -0,0 +1,9 @@ + + + + dummy + + + dummy + + diff --git a/packages/koa/cjs-tests/fixtures/keys/privateKey.pem b/packages/koa/cjs-tests/fixtures/keys/privateKey.pem new file mode 100644 index 00000000..52ceae92 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/keys/privateKey.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDfDqpnh8TceIRuemm8GWM6nvE6KumK/Lq+POrZqghgHpZa5zjv +wwjsJ2iK45zWIRpggMkSlQZWvnRRjj/TWfv7448qhhiTB7hmqV63XjfYXJ5OgTtN +fPW36ZQ48Ha0y4sjlU4gvSijHpnzrJ5yV/vjLLLp9WxTux4ColeZu2B/XQIDAQAB +AoGAEmLJFQOR7IJamCiq8oA9N6XGSH8lBPnUAr5OtWZYjmO3DQMmJE01PRH6gghE +8zmDTRUQfeGexiOovtg01p0CMhehwS8D8d0m01s43zQ77xVJuFAvuW1U1kER4Xze +tVkLEvvO9PcWpKUEmxYpDoCJXGIfXuHaSAVbVLYDKn2MEUECQQD4FeWlpkxSNQT9 +u6w01zR/byjXzUmibOP5zrpaEsDGIxxTlxc/7WJZlKLNybXUyZE8oHgepuefdcL0 +ybk6gvQpAkEA5ixdMtnsbUImJYNFrt5BbLzEU9eF76hovsOSjOc2eTUJHEeiXeDA +Q66WZwXNBf/CRrZdsAvBPMQcWzJLwp24FQJBAPaojtPMLEXwAS5l0ioXblLlqq4l +pfigW2qcaBv2WUSm1BsoNi2RUB/Q8K26x9bxMj4dLlELkW+yHkxT5J6QZUECQFRO +A4TQlOwfwmETB77Y4RW2viIHWqNBB7x3XYIGXclfR4r4IdxIqaMgmy34zfNYjgvg +V8hXRdu/6LLuZRlPM1ECQHUppZNG7WKP9F7ywAr33u3xD0+9MqsfqcgKPfP9VOxs +Lo8EdmjmB30lyyP/Cd1hzxb+BsJjGmxzU/DikGbWos8= +-----END RSA PRIVATE KEY----- diff --git a/packages/koa/cjs-tests/fixtures/keys/publicKey.pem b/packages/koa/cjs-tests/fixtures/keys/publicKey.pem new file mode 100644 index 00000000..7bd2532a --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/keys/publicKey.pem @@ -0,0 +1,6 @@ +-----BEGIN PUBLIC KEY----- +MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfDqpnh8TceIRuemm8GWM6nvE6 +KumK/Lq+POrZqghgHpZa5zjvwwjsJ2iK45zWIRpggMkSlQZWvnRRjj/TWfv7448q +hhiTB7hmqV63XjfYXJ5OgTtNfPW36ZQ48Ha0y4sjlU4gvSijHpnzrJ5yV/vjLLLp +9WxTux4ColeZu2B/XQIDAQAB +-----END PUBLIC KEY----- diff --git a/packages/koa/cjs-tests/fixtures/options.js b/packages/koa/cjs-tests/fixtures/options.js new file mode 100755 index 00000000..b8e5c8e0 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/options.js @@ -0,0 +1,28 @@ +// reusable options +const { join } = require('path'); + +const { DEFAULT_HEADER, CONTRACT_KEY_NAME, CONTENT_TYPE } = require('jsonql-constants'); + +const type = CONTENT_TYPE; +const headers = DEFAULT_HEADER; +const contractKeyName = CONTRACT_KEY_NAME; + +const dirs = { + resolverDir: join(__dirname, 'resolvers'), + contractDir: join(__dirname, 'tmp') +}; + +const secret = 'A little cat is watching you'; + +const bearer = 'sofud89723904lksd98234230823jlkjklsdfds'; + +const returns = [ + { + "type": "string", + "description": "stock message" + } +]; + +const dummy = 'yes I am dummy'; + +module.exports = { type, headers, dirs, secret, bearer, returns, contractKeyName, dummy }; diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/custom-login.js b/packages/koa/cjs-tests/fixtures/resolvers/auth/custom-login.js new file mode 100644 index 00000000..ca19bb40 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/auth/custom-login.js @@ -0,0 +1,13 @@ + +/** + * This is a custom login method instead of the stock version + * @param {string} username username + * @param {string} password password + * @return {object} userdata payload + */ +module.exports = function customLogin(username, password) { + if (password === '123456') { + return {name: username} + } + throw new Error('Login failed!') +} diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/custom-validator.js b/packages/koa/cjs-tests/fixtures/resolvers/auth/custom-validator.js new file mode 100644 index 00000000..08d617a8 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/auth/custom-validator.js @@ -0,0 +1,13 @@ +// this will use for testing the chaining validator methods +const debug = require('debug')('jsonql-koa:custom-validator') +const { dummy } = require('../../options') + +/** + * @param {*} userdata pass by the jsonql-jwt method + * @return {*} just pass it back + */ +module.exports = function(userdata) { + debug('I am being call by the chain') + userdata.dummy = dummy; + return userdata; +} diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/login.js b/packages/koa/cjs-tests/fixtures/resolvers/auth/login.js new file mode 100755 index 00000000..5f8d1e79 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/auth/login.js @@ -0,0 +1,18 @@ +const debug = require('debug')('jsonql:koa:issuer'); +const { bearer } = require('../../options'); + +// this is the stock method for giving out author header + +/** + * Auth method + * @param {string} username user name + * @param {string} password password + * @return {string|boolean} token on success, false on fail + */ +module.exports = function(username, password) { + debug('received this', username, password); + if (username === 'nobody' && password) { + return bearer; + } + return false; +} diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/logout.js b/packages/koa/cjs-tests/fixtures/resolvers/auth/logout.js new file mode 100644 index 00000000..d9b2af68 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/auth/logout.js @@ -0,0 +1,8 @@ +// complete the 3 pieces + +/** + * @return {boolean} just return something + */ +module.exports = function() { + return true; +}; diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/validator.js b/packages/koa/cjs-tests/fixtures/resolvers/auth/validator.js new file mode 100755 index 00000000..b588aa81 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/auth/validator.js @@ -0,0 +1,14 @@ +const debug = require('debug')('jsonql:koa:validator'); +const { bearer } = require('../../options'); +// this is the core method for checking the Auth header +/** + * @param {string} token jwt + * @return {object|boolean} user data on success, false on fail + */ +module.exports = function(token) { + debug('received this token', token, bearer); + if (token === bearer) { + return {userId: 1}; + } + return false; +} diff --git a/packages/koa/cjs-tests/fixtures/resolvers/mutation/update-list.js b/packages/koa/cjs-tests/fixtures/resolvers/mutation/update-list.js new file mode 100755 index 00000000..bac22581 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/mutation/update-list.js @@ -0,0 +1,12 @@ +const debug = require('debug')('jsonql-koa:resolver:mutation:updateList'); +/** + * @param {object} payload + * @param {number} payload.user + * @param {object} condition + * @return {object} with user as key + */ +module.exports = function(payload, condition) { + debug('calling updateList with', payload, condition); + let p = payload.user + 1; + return {user: p}; +}; diff --git a/packages/koa/cjs-tests/fixtures/resolvers/mutation/update-ms-service.js b/packages/koa/cjs-tests/fixtures/resolvers/mutation/update-ms-service.js new file mode 100644 index 00000000..62b17524 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/mutation/update-ms-service.js @@ -0,0 +1,13 @@ +const debug = require('debug')('jsonql-koa:mutation:update-ms-service') +/** + * this will be calling a microserivce setup using the nodeClient + * @param {string} payload incoming + * @return {string} msg return from nodeClient + */ +module.exports = async function updateMsService(payload) { + const client = await updateMsService.client() + + debug(client) + + return client.query.subMsService(payload) +} diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/cause-error.js b/packages/koa/cjs-tests/fixtures/resolvers/query/cause-error.js new file mode 100755 index 00000000..0a5eb534 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/query/cause-error.js @@ -0,0 +1,10 @@ + +// this method will cause an error to throw +/** + * @param {*} x param + * @return {*} unknown + */ +module.exports = function(x) { + // none of the variable exists certainly will cause an error + return x ? y : z; +} diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/get-user.js b/packages/koa/cjs-tests/fixtures/resolvers/query/get-user.js new file mode 100755 index 00000000..49b836f2 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/query/get-user.js @@ -0,0 +1,12 @@ +// This is a new query method to test out if we actually get the userData props at the end of call +/** + * This use a spread as parameter + * @param {...string} args passing unknown number of param + * @return {any} extract from last of the args + */ +module.exports = function getUser(...args) { + const ctn = args.length; + const lastProp = args[ctn - 1]; + // also test with the assigned property + return getUser.userdata || {userId: 'dummy bear'}; +} diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js b/packages/koa/cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js new file mode 100644 index 00000000..b655360d --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js @@ -0,0 +1,9 @@ +// this resolver will not be include if the privateMethodDir is not set + +/** + * a hidden private method + * @return {string} a secret message + */ +module.exports = function getSecretMsg() { + return 'Let me tell ya a secret ...'; +} diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/public/always-available.js b/packages/koa/cjs-tests/fixtures/resolvers/query/public/always-available.js new file mode 100644 index 00000000..0a086798 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/query/public/always-available.js @@ -0,0 +1,7 @@ +/** + * This is a public method that is always available + * @return {string} a message + */ +module.exports = function() { + return 'Hello there'; +}; diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/test-list.js b/packages/koa/cjs-tests/fixtures/resolvers/query/test-list.js new file mode 100755 index 00000000..b063eee6 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/resolvers/query/test-list.js @@ -0,0 +1,13 @@ +const debug = require('debug')('jsonql-koa:resolver:query:testList'); +/** + * @param {number} num a number + * @return {object} @TODO need to figure out how to give keys to the returns + */ +module.exports = function testList(num) { + debug('Call testList with this params', num); + return { + modified: Date.now(), + text: testList.userdata && testList.userdata.dummy ? testList.userdata.dummy : 'nope', + num: num ? --num : -1 + }; +}; diff --git a/packages/koa/cjs-tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js b/packages/koa/cjs-tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js new file mode 100644 index 00000000..9da096d7 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js @@ -0,0 +1,8 @@ +/** + * create a mutation to test why the call said the payload already declared + * @param {string} payload incoming + * @return {string} output + */ +module.exports = function subUpdateMsService(payload) { + return payload + ' updated'; +} diff --git a/packages/koa/cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js b/packages/koa/cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js new file mode 100644 index 00000000..c8c0a047 --- /dev/null +++ b/packages/koa/cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js @@ -0,0 +1,11 @@ +const debug = require('debug')('jsonql-koa:query:ms-service') +/** + * @param {string} msg incoming message + * @return {string} out going message + */ +module.exports = function subMsService(msg) { + + debug('msg', msg) + + return msg + ' ms service'; +} diff --git a/packages/koa/cjs-tests/helpers/browser.js b/packages/koa/cjs-tests/helpers/browser.js new file mode 100644 index 00000000..b6217f2a --- /dev/null +++ b/packages/koa/cjs-tests/helpers/browser.js @@ -0,0 +1,20 @@ +// browser test the web console + +const serverIoCore = require('server-io-core') +const { join } = require('path') +const jsonqlKoa = require('../../') + +const baseDir = join(__dirname, '..', 'fixtures') + +serverIoCore({ + webroot: [ + join(baseDir, 'tmp', 'browser') + ], + middlewares: [ + jsonqlKoa({ + resolverDir: join(baseDir, 'resolvers'), + contractDir: join(baseDir, 'tmp', 'browser'), + enableWebConsole: true + }) + ] +}) diff --git a/packages/koa/cjs-tests/helpers/hello.js b/packages/koa/cjs-tests/helpers/hello.js new file mode 100644 index 00000000..462b32e6 --- /dev/null +++ b/packages/koa/cjs-tests/helpers/hello.js @@ -0,0 +1,14 @@ +// wrapper function to test the server is running or not +const superkoa = require('superkoa') +const { headers } = require('../fixtures/options') +// export +module.exports = function hello(app) { + return superkoa(app) + .post('/jsonql') + .set(headers) + .send({ + helloWorld: { + args: [] + } + }); +} diff --git a/packages/koa/cjs-tests/helpers/server.js b/packages/koa/cjs-tests/helpers/server.js new file mode 100755 index 00000000..2c20f069 --- /dev/null +++ b/packages/koa/cjs-tests/helpers/server.js @@ -0,0 +1,21 @@ +// this will export the server for other test to use +// const test = require('ava'); +const Koa = require('koa') +const { join } = require('path') +const bodyparser = require('koa-bodyparser') +const jsonqlMiddleware = require(join(__dirname, '..', '..','index')) +const { type, headers, dirs } = require('../fixtures/options') +const fsx = require('fs-extra') +const myKey = '4670994sdfkl'; +// add a dir to seperate the contract files +module.exports = (config={}, dir = '') => { + const app = new Koa(); + app.use(bodyparser()); + app.use(jsonqlMiddleware( + Object.assign({},{ + resolverDir: dirs.resolverDir, + contractDir: join(dirs.contractDir, dir) + }, config) + )); + return app; +} diff --git a/packages/koa/cjs-tests/helpers/sub-server.js b/packages/koa/cjs-tests/helpers/sub-server.js new file mode 100644 index 00000000..aef59910 --- /dev/null +++ b/packages/koa/cjs-tests/helpers/sub-server.js @@ -0,0 +1,24 @@ +const { join } = require('path') +const fixturesDir = join(__dirname, '..', 'fixtures') + +const serverIoCore = require('server-io-core') +const jsonqlKoa = require('../../index') + +function startSubServer(msPort) { + return serverIoCore({ + webroot: join(fixturesDir, 'html'), + socket:false, + open:false, + debugger: false, + port: msPort, + middlewares: [ + jsonqlKoa({ + name: `server${msPort}`, + contractDir: join(fixturesDir, 'tmp', `sub-server-${msPort}`), + resolverDir: join(fixturesDir, 'sub', 'resolver') + }) + ] + }) +} + +module.exports = startSubServer diff --git a/packages/koa/cjs-tests/jsonp.test.js b/packages/koa/cjs-tests/jsonp.test.js new file mode 100644 index 00000000..0fc1ca79 --- /dev/null +++ b/packages/koa/cjs-tests/jsonp.test.js @@ -0,0 +1,38 @@ +// testing the new jsonp methods +const test = require('ava') +const { JSONP_CALLBACK_NAME } = require('jsonql-constants') +const superkoa = require('superkoa') +const { join } = require('path') +const debug = require('debug')('jsonql-koa:test:jsonp') +const { type, headers, dirs, returns } = require('./fixtures/options') +const fsx = require('fs-extra') + +const { resolverDir, contractDir } = dirs; + +const createServer = require('./helpers/server') +const dir = 'standard'; + +test.before((t) => { + t.context.app = createServer({enableJsonp: true}, dir) +}) + +test.after( () => { + +}) +// @TODO this is not the proper JSONP need to think about it before continue with this feature +test('It should able to tell if this is access using jsonp', async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .set(headers) + .query({ + _cb: Date.now(), + [JSONP_CALLBACK_NAME]: 'helloWorld' + }) + .send({ + args: [] + }) + // debug(res.body) + t.is(200, res.status) + t.is('Hello world!', res.body.data) + +}) diff --git a/packages/koa/cjs-tests/jwt-auth.test.js b/packages/koa/cjs-tests/jwt-auth.test.js new file mode 100644 index 00000000..e3eacc10 --- /dev/null +++ b/packages/koa/cjs-tests/jwt-auth.test.js @@ -0,0 +1,77 @@ +// this will use the enableAuth and useJwt options to test out all the new modules +const test = require('ava') + +const superkoa = require('superkoa'); +const { join } = require('path'); +const clientJwtDecode = require('jwt-decode') +const { jwtDecode } = require('jsonql-jwt') +const { merge } = require('lodash') +const fsx = require('fs-extra') +const { RSA_ALGO } = require('jsonql-constants') + +const debug = require('debug')('jsonql-koa:test:jwt'); + +const { type, headers, dirs, dummy } = require('./fixtures/options'); +const createServer = require('./helpers/server') +const dir = 'jwt'; +const keysDir = join(__dirname, 'fixtures', 'keys') + +const { createTokenValidator, loginResultToJwt } = require('jsonql-jwt') + +const name = 'Joel'; + +// start test +test.before( t => { + t.context.app = createServer({ + enableAuth: true, + useJwt: true, + loginHandlerName: 'customLogin', + validatorHandlerName: false, //'customValidator', + privateMethodDir: 'private', + keysDir + }, dir) + + const privateKey = fsx.readFileSync(join(keysDir, 'privateKey.pem')) + const options = { exp: 60*60 }; + + t.context.encoder = loginResultToJwt(privateKey, options, RSA_ALGO) + + t.context.token = t.context.encoder({ name }) + +}) + + +test('It should able to query the private method with token', async t => { + + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(merge({}, headers, {Authorization: `Bearer ${t.context.token}`})) + .send({ + testList: { + args: [667] + } + }) + + t.is(200, res.status) + let payload = res.body.data; + + t.is(666, payload.num) + t.is('nope', payload.text) +}) + +test('It should able to query a private method that is inside the private folder', async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(merge({}, headers, {Authorization: `Bearer ${t.context.token}`})) + .send({ + getSecretMsg: { + args: [] + } + }) + + t.is(200, res.status) + t.truthy( res.body.data.indexOf('secret') ) + +}) diff --git a/packages/koa/cjs-tests/jwt.test.js b/packages/koa/cjs-tests/jwt.test.js new file mode 100644 index 00000000..2a928ecb --- /dev/null +++ b/packages/koa/cjs-tests/jwt.test.js @@ -0,0 +1,66 @@ +// this will use the enableAuth and useJwt options to test out all the new modules +const test = require('ava') + +const superkoa = require('superkoa'); +const { join } = require('path'); +const clientJwtDecode = require('jwt-decode') +const { jwtDecode } = require('jsonql-jwt') +const { merge } = require('lodash') +const fsx = require('fs-extra') +const { RSA_ALGO } = require('jsonql-constants') + +const debug = require('debug')('jsonql-koa:test:jwt'); + +const { type, headers, dirs } = require('./fixtures/options'); +const createServer = require('./helpers/server') +const dir = 'jwt'; +const keysDir = join(__dirname, 'fixtures', 'tmp', 'keys') + +const { createTokenValidator, loginResultToJwt } = require('jsonql-jwt') + +// start test +test.before( t => { + t.context.app = createServer({ + enableAuth: true, + useJwt: true, + jwtTokenOption: { exp: 60*60 }, + loginHandlerName: 'customLogin', + keysDir + }, dir) + + const publicKey = fsx.readFileSync(join(keysDir, 'publicKey.pem')) + + t.context.validator = createTokenValidator({ + publicKey, + useJwt: true + }) + +}) +// we need this one run first to get the token +test('It should able to provide a token that can be decode with the client side module', async t => { + let name = 'Joel'; + let res = await superkoa(t.context.app) + .post('/jsonql') + .query({_cb: Date.now()}) + .set(headers) + .send({ + customLogin: { + args: [name, '123456'] + } + }) + + t.is(200, res.status) + let token = res.body.data; + t.context.token = token; + + + let payload = clientJwtDecode(token) + t.is(payload.name, name) + t.truthy(payload.exp) + + let payload2 = t.context.validator(token) + + t.is(payload2.name, name) + t.truthy(payload2.exp) + +}) diff --git a/packages/koa/cjs-tests/koa.test.js b/packages/koa/cjs-tests/koa.test.js new file mode 100755 index 00000000..037f90b9 --- /dev/null +++ b/packages/koa/cjs-tests/koa.test.js @@ -0,0 +1,124 @@ +const test = require('ava') + +const { SHOW_CONTRACT_DESC_PARAM } = require('jsonql-constants') +const superkoa = require('superkoa') +const { join } = require('path') +const debug = require('debug')('jsonql-koa:test:koa') +const { type, headers, dirs, returns } = require('./fixtures/options') +const fsx = require('fs-extra') + +const { resolverDir, contractDir } = dirs; + +const createServer = require('./helpers/server') +const dir = 'standard'; + +const makeServer = function() { + return new Promise(resolver => { + const app = createServer({}, dir) + setTimeout(() => { + resolver(app) + }, 5000) + }) +} + +test.before( async (t) => { + t.context.app = await makeServer() +}) + +test.after( () => { + // remove the files after + fsx.removeSync(join(contractDir, dir)) +}) + +// start test +// @1.3.4 test if there is a public / private contract generated +test('It should create a contract and a public contract file at the same time', t => { + + const cd = join(contractDir, dir) + + t.truthy( fsx.existsSync(join(cd, 'contract.json')) ) + t.truthy( fsx.existsSync(join(cd, 'public-contract.json')) ) + +}) + +test("Hello world test", async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .set(headers) + .send({ + helloWorld: { + args: [] + } + }); + // debug(res.body) + t.is(200, res.status) + t.is('Hello world!', res.body.data) +}) + +test("It should return a public contract with helloWorld", async (t) => { + let res = await superkoa(t.context.app) + .get('/jsonql') + .set(headers) + let contract = res.body.data; + + t.is(200, res.status) + + t.deepEqual(returns, contract.query.helloWorld.returns) + // it should not have a description field + t.falsy(contract.query.helloWorld.description) +}) + + +// start test +test('It should return json object',async (t) => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .set(headers) + .send({ + testList: { + args: [2] + } + }); + t.is(200, res.status) + t.is(1, res.body.data.num) +}) + +test('It should change the json object', async(t) => { + let res = await superkoa(t.context.app) + .put('/jsonql') + .set(headers) + .send({ + updateList: { + payload: { + user: 1 + }, + condition: { + where: 'nothing' + } + } + }); + t.is(200, res.status) + t.is(2, res.body.data.user) +}) + +// test the web console +test("It should able see a dummy web console page", async t => { + let res = await superkoa(t.context.app) + .get('/jsonql') + t.is(200, res.status) +}) + +// for some reason if I run this as standalone then it works but run with other with +// the new test with both contract created failed +test.only("It should return a contract file without the description field", async t => { + let res = await superkoa(t.context.app) + .get('/jsonql') + .query(SHOW_CONTRACT_DESC_PARAM) + .set(headers) + let contract = res.body.data; + + debug(SHOW_CONTRACT_DESC_PARAM, contract.query) + + t.truthy(contract.query.helloWorld.description) + +}) diff --git a/packages/koa/cjs-tests/node-client.donttest.js b/packages/koa/cjs-tests/node-client.donttest.js new file mode 100644 index 00000000..c749becf --- /dev/null +++ b/packages/koa/cjs-tests/node-client.donttest.js @@ -0,0 +1,70 @@ +// testing the ms feature +const test = require('ava') +const { join } = require('path') +const fsx = require('fs-extra') +const debug = require('debug')('jsonql-koa:test:node-client') +const nodeClient = require('jsonql-node-client') +const serverIoCore = require('server-io-core') +// setup +const jsonqlKoa = require('../') +const hello = require('./helpers/hello') +const baseDir = join(__dirname, 'fixtures') +const clientContractDir = join(__dirname, 'fixtures', 'tmp', 'client6002') +const createServer = require('./helpers/server') + +const port = 6002; +const dir = 'server6002'; +const msPort = 8001; +const startSubServer = require('./helpers/sub-server') + +// base test setup +test.before(async t => { + + t.context.baseApp = createServer({ + name: `server${port}`, + clientConfig: [{ + hostname: `http://localhost:${msPort}`, + name: 'client0' + }] + }, dir) + t.context.baseServer = t.context.baseApp.listen(port) + + const { app, stop } = startSubServer(msPort) + + t.context.app = app + t.context.stop = stop +}) + +test.after(t => { + t.context.stop() + t.context.baseServer.close() + fsx.removeSync(clientContractDir) + fsx.removeSync(join(baseDir, 'tmp', dir)) +}) + +test.skip(`First test both server is running`, async t => { + const res1 = await hello(t.context.baseApp) + t.is(res1.status, 200) + const res2 = await hello(t.context.app) + t.is(res2.status, 200) +}) + +test.skip(`First test calling the 6001 directly with the mutation call`, async t => { + const client = await nodeClient({ + hostname: `http://localhost:${msPort}`, + contractDir: join(__dirname, 'fixtures', 'tmp', `client${msPort}`) + }) + const result = await client.query.subMsService('testing') + t.truthy(result.indexOf(`ms service`)) +}) + +test(`It should able to call a resolver that access another ms`, async t => { + // the problem now is calling the 6001 but received the 8001 public contract? + const client = await nodeClient({ + hostname: `http://localhost:${port}`, + contractDir: clientContractDir + }) + + const result = await client.mutation.updateMsService('testing') + t.truthy(result.indexOf(`ms service`)) +}) diff --git a/packages/koa/cjs-tests/resolverNotFound.test.js b/packages/koa/cjs-tests/resolverNotFound.test.js new file mode 100755 index 00000000..19986ac0 --- /dev/null +++ b/packages/koa/cjs-tests/resolverNotFound.test.js @@ -0,0 +1,49 @@ +// this one will test the resolver not found and the application error + +const test = require('ava') +const createServer = require('./helpers/server') +const superkoa = require('superkoa') +const { headers } = require('./fixtures/options') +const debug = require('debug')('jsonql-koa:test:ResolverNotFoundError') +const fsx = require('fs-extra') +const { join } = require('path') + +test.before( t => { + t.context.app = createServer({}, 'notfound') +}) + +test.after( t => { + fsx.removeSync(join(__dirname, 'fixtures', 'tmp', 'notfound')) +}) + +test('it should throw a ResolverNotFoundError', async (t) => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .set(headers) + .send({ + helloWorld2: { + args: [] + } + }) + + debug(res.body) + + t.is(res.body.error.statusCode, 404) + +}) + +test("It should cause an Application error but nothing throw", async t => { + let res = await superkoa(t.context.app) + .post('/jsonql') + .set(headers) + .send({ + causeError: { + args: [1] + } + }) + + debug(res.body) + + t.is(true, res.status === 200) + +}) diff --git a/packages/koa/cjs-tests/throw.test.js b/packages/koa/cjs-tests/throw.test.js new file mode 100644 index 00000000..26e5aa71 --- /dev/null +++ b/packages/koa/cjs-tests/throw.test.js @@ -0,0 +1,24 @@ +// this will only test all kind of throw error scenarios +const test = require('ava') +const superkoa = require('superkoa') +const jsonqlErrors = require('jsonql-errors') +// @TODO some of the idea already cover in other test so this one just keep here for now +const { + clientErrorsHandler, + getErrorByStatus, + JsonqlResolverNotFoundError +} = jsonqlErrors; + +test('Should able understand the Error being throw from clientErrorsHandler', async t => { + + const error = t.throws(() => { + return clientErrorsHandler({ + error: { + statusCode: 404, + className: 'JsonqlResolverNotFoundError' + } + }) + }, JsonqlResolverNotFoundError, 'Only give it a statusCode to find the error to throw') + + +}) diff --git a/packages/koa/docker-compose.yml b/packages/koa/docker-compose.yml new file mode 100644 index 00000000..223c2dcb --- /dev/null +++ b/packages/koa/docker-compose.yml @@ -0,0 +1,11 @@ +version: '3' + +services: + web: + build: . + command: npm run start + volumes: + - .:/usr/app/ + - /usr/app/node_modules + ports: + - "8001:8001" diff --git a/packages/koa/index.js b/packages/koa/index.js old mode 100755 new mode 100644 index eb25d4da..f7df12b2 --- a/packages/koa/index.js +++ b/packages/koa/index.js @@ -1,27 +1,24 @@ -'use strict'; /** * This is the main interface to export the middleware(s) * we will take the config here and export array of middleware using koa-compose */ -const fs = require('fs') -const merge = require('lodash.merge') -const compose = require('koa-compose') -const { - configCheck, +import fs from 'fs' +import { merge } from 'lodash' +import compose from 'koa-compose' +import { coreMiddleware, authMiddleware, contractMiddleware, helloMiddleware, consoleMiddleware, publicMethodMiddleware, - errorsHandlerMiddleware, initMiddleware -} = require('./src') -const { getDebug } = require('./src/lib') - +} from './src/middlewares' +import { configCheck } from './src/options' +import { getDebug } from './src/utils' const debug = getDebug('main') // main -module.exports = function(config = {}) { +export default function jsonqlKoa(config = {}) { // first check the config const opts = configCheck(config) debug('[jsonql-koa] init opts', opts) diff --git a/packages/koa/main.js b/packages/koa/main.js new file mode 100644 index 00000000..188245a2 --- /dev/null +++ b/packages/koa/main.js @@ -0,0 +1,3 @@ +// export for CJS modules using esm modules +require = require('esm')(module) +module.exports = require('./index.js') diff --git a/packages/koa/package0.json b/packages/koa/package0.json new file mode 100644 index 00000000..261d09c2 --- /dev/null +++ b/packages/koa/package0.json @@ -0,0 +1,96 @@ +{ + "name": "@jsonql/koa", + "version": "0.3.0", + "description": "jsonql Koa middleware", + "main": "main.js", + "module": "index.js", + "files": [ + "src", + "index.js", + "main.js" + ], + "scripts": { + "test": "ava --verbose", + "prepare": "npm run test", + "start": "node ./test/fixtures/start.js", + "test:debug": "DEBUG=jsonql* ava --verbose", + "coverage": "nyc ava --verbose", + "test:basic": "DEBUG=jsonql* ava ./tests/koa.test.js", + "test:notfound": "DEBUG=jsonql-koa* ava --verbose ./tests/resolverNotFound.test.js", + "test:es6": "DEBUG=jsonql-koa* ava --verbose ./tests/es6-module.test.js", + "test:jwt": "DEBUG=jsonql-koa*,jsonql-jwt* ava ./tests/jwt.test.js", + "test:jwt-auth": "DEBUG=jsonql-koa* ava ./tests/jwt-auth.test.js", + "test:fail": "ava ./tests/fail.test.js", + "test:contract": "DEBUG=jsonql-koa* ava ./tests/contractWithAuth.test.js", + "test:auth": "DEBUG=jsonql* ava ./tests/auth.test.js", + "test:error": "DEBUG=jsonql-koa* ava ./tests/resolverNotFound.test.js", + "test:config": "DEBUG=jsonql-* ava ./tests/config.test.js", + "test:throw": "DEBUG=jsonql-* ava ./tests/throw.test.js", + "test:gen": "DEBUG=jsonql* ava ./tests/contract.test.js", + "test:jsonp": "DEBUG=jsonql* ava --verbose ./tests/jsonp.test.js", + "test:chain": "DEBUG=jsonql* ava --verbose ./tests/chain-fn.test.js", + "test:clients": "DEBUG=jsonql* ava --verbose ./tests/node-client.test.js", + "web-console": "DEBUG=jsonql-koa*,jsonql-web-console* node ./tests/helpers/browser.js", + "contract": "node ./node_modules/jsonql-contract/cmd.js ./tests/fixtures/resolvers ./tests/fixtures/contracts" + }, + "keywords": [ + "jsonql", + "koa", + "server", + "socket", + "WebSocket", + "API" + ], + "author": "Joel Chu ", + "license": "ISC", + "repository": { + "type": "git", + "url": "git+ssh://git@gitee.com:to1source/jsonql.git" + }, + "bugs": { + "url": "https://gitee.com/to1source/jsonql/issues" + }, + "homepage": "jsonql.org", + "ava": { + "files": [ + "tests/*.test.js", + "!tests/helpers/*.*", + "!tests/fixtures/*.*" + ], + "require": [ + "esm" + ], + "cache": true, + "concurrency": 5, + "failFast": true, + "failWithoutAssertions": false, + "tap": false, + "compileEnhancements": false + }, + "dependencies": { + "debug": "^4.1.1", + "esm": "^3.2.25", + "fs-extra": "^8.1.0", + "jsonql-constants": "^1.8.3", + "jsonql-contract": "^1.7.9", + "jsonql-errors": "^1.1.3", + "jsonql-jwt": "^1.3.2", + "jsonql-node-client": "^1.1.9", + "jsonql-params-validator": "^1.4.11", + "jsonql-resolver": "^0.8.7", + "jsonql-utils": "^0.6.10", + "jsonql-web-console": "^0.4.3", + "koa": "^2.8.1", + "koa-compose": "^4.1.0", + "lodash": "^4.17.15" + }, + "devDependencies": { + "ava": "^2.4.0", + "jwt-decode": "^2.2.0", + "koa-bodyparser": "^4.2.1", + "nyc": "^14.1.1", + "request": "^2.88.0", + "server-io-core": "^1.2.0", + "superkoa": "^1.0.3" + } +} diff --git a/packages/koa/src/contracts/contract-generator.js b/packages/koa/src/contracts/contract-generator.js new file mode 100644 index 00000000..eb2325e7 --- /dev/null +++ b/packages/koa/src/contracts/contract-generator.js @@ -0,0 +1,51 @@ +// this need to get call from the beginning +// so make this available in different places +import fsx from 'fs-extra' +import { join } from 'path' +import contractApi from 'jsonql-contract' +import { + DEFAULT_CONTRACT_FILE_NAME, + PUBLIC_CONTRACT_FILE_NAME +} from 'jsonql-constants' +import { getDebug } from '../utils' +const debug = getDebug('contract-generator') +/** + * @param {string} contractDir where the contract is + * @param {boolean} pub system of public + * @return {mixed} false on not found + */ +const readContract = function(contractDir, pub) { + const file = join(contractDir, pub ? PUBLIC_CONTRACT_FILE_NAME : DEFAULT_CONTRACT_FILE_NAME) + if (fsx.existsSync(file)) { + debug('Serving up the existing one from ', file) + return fsx.readJsonSync(file) + } + return false; +} + +/** + * contract create handler + * @param {object} opts options + * @param {boolean} pub where to serve this + * @param {boolean} start is this the first call + * @return {object} promise to resolve contract json + */ +const contractGenerator = function(opts, pub = false, start = false) { + return new Promise((resolver, rejecter) => { + if (opts.buildContractOnStart === false && start === false) { + const contract = readContract(opts.contractDir, pub) + if (contract !== false) { + return resolver(contract) + } + } + contractApi(Object.assign({}, opts, { public: pub })) + .then(resolver) + .catch(rejecter) + }) +} + +// export +export { + contractGenerator, + readContract +} diff --git a/packages/koa/src/contracts/get-contract.js b/packages/koa/src/contracts/get-contract.js new file mode 100644 index 00000000..cda821a2 --- /dev/null +++ b/packages/koa/src/contracts/get-contract.js @@ -0,0 +1,42 @@ +// move all the code into it's folder +// we are going to fork the process to lighten the load when it start +import { fork } from 'child_process' +import { join } from 'path' + +import { getDebug } from '../utils' +const debug = getDebug('contract-generator') +// try to cache it +let contractCache = {}; +/** + * getContract main + * @param {object} config options + * @param {boolean} pub public contract or not + * @return {object} Promise to resolve the contract json + */ +export function getContract(config, pub = false) { + const ps = fork(join(__dirname, 'run.js')) + const key = pub ? 'public' : 'private'; + if (contractCache[key]) { + debug(`return ${key} contract from cache`, contractCache[key]) + // this is the problem - if we want to keep it consistent then + // we should always provide the contract key --> cache is optional! + // { contract: contractCache[key], cache: true } + return Promise.resolve(contractCache[key]) + } + ps.send({ config, pub }) + // return + return new Promise((resolver, rejecter) => { + ps.on('message', msg => { + if (msg.contract) { + // contractCache[key] = msg.contract; // <-- disable cache + // return + return resolver(msg.contract) + } + rejecter(msg) + }) + ps.on('error', err => { + debug('ps error', err) + rejecter(err) + }) + }) +} diff --git a/packages/koa/src/contracts/helpers.js b/packages/koa/src/contracts/helpers.js new file mode 100644 index 00000000..48d9badd --- /dev/null +++ b/packages/koa/src/contracts/helpers.js @@ -0,0 +1,94 @@ +// all these methods were inside the contract-middleware +// now move all of them here to keep the middleware clean +import { trim } from 'lodash' +import { SHOW_CONTRACT_DESC_PARAM } from 'jsonql-constants' +import { + isKeyInObject, + getDebug, + handleOutput, + packResult, + ctxErrorHandler +} from '../utils' +const debug = getDebug('contracts:helpers') +/** + * remove the description field + * @param {boolean} showDesc true to keep + * @param {object} contract json + * @return {object} clean contract + */ +export const removeDesc = (showDesc, contract) => { + debug('showDesc', showDesc) + if (showDesc) { + return contract; + } + let c = contract; + for (let type in c) { + for (let fn in c[type]) { + if (isKeyInObject(c[type][fn], 'description')) { + delete c[type][fn].description; + if (c[type][fn].returns && isKeyInObject(c[type][fn].returns, 'description')) { + delete c[type][fn].returns.description; + } + } + } + } + return c; +} + +/** + * get the contract data @TODO might require some sort of security here + * @param {object} opts options + * @param {object} ctx koa + * @return {undefined} + */ +export const handleContract = (opts, ctx, contract) => { + // @1.3.2 add a filter here to exclude the description field + // just to reduce the size, but we serve it up if this is request with + // desc=1 param - useful for the jsonql-web-console + // debug('handleContract', ctx.query.desc) + const key = Object.keys(SHOW_CONTRACT_DESC_PARAM)[0] + let desc = !!(ctx.query[key] && ctx.query[key] === SHOW_CONTRACT_DESC_PARAM[key]) + handleOutput(opts)(ctx, packResult( + removeDesc(desc, contract) + )) +} + +/** + * Search for the value from the CONTRACT_KEY_NAME + * @param {object} ctx koa context + * @param {string} contractKeyName the key to search + * @return {string} the value from header + */ +export const searchContractAuth = function(ctx, contractKeyName) { + // debug(`Try to get ${contractKeyName} from header`, ctx.request.header); + return ctx.request.get(contractKeyName) +} + +/** + * Handle contract authorisation using a key + * @param {object} ctx koa + * @param {object} opts options + * @return {boolean} true ok + */ +export const contractAuth = function(ctx, opts) { + if (opts.contractKey !== false && opts.contractKeyName !== false) { + const { contractKey, contractKeyName } = opts; + // debug('Received this for auth', contractKeyName, contractKey); + // @2019-05-08 we change from url query to header + // const keyValueFromClient = trim(ctx.query[contractKeyName]); + // debug('the query value', ctx.query); + const keyValueFromClient = searchContractAuth(ctx, contractKeyName) + + switch (true) { + case typeof contractKey === 'string': + // debug('compare this two', keyValueFromClient, contractKey); + return keyValueFromClient === contractKey; + break; + default: + // @TODO what if we want to read the header? + debug('Unsupported contract auth type method', typeof contractKey) + return false; + } + } + return true; +} diff --git a/packages/koa/src/contracts/import.js b/packages/koa/src/contracts/import.js new file mode 100644 index 00000000..85b8689a --- /dev/null +++ b/packages/koa/src/contracts/import.js @@ -0,0 +1,2 @@ +require = require('esm')(module) +module.exports = require('./contract-generator.js') diff --git a/packages/koa/src/contracts/index.js b/packages/koa/src/contracts/index.js new file mode 100644 index 00000000..c824080a --- /dev/null +++ b/packages/koa/src/contracts/index.js @@ -0,0 +1,9 @@ +// import export +import { getContract } from './get-contract' +import { handleContract, contractAuth } from './helpers' + +export { + getContract, + handleContract, + contractAuth +} diff --git a/packages/koa/src/contracts/process-contract.js b/packages/koa/src/contracts/process-contract.js new file mode 100644 index 00000000..80fd40b8 --- /dev/null +++ b/packages/koa/src/contracts/process-contract.js @@ -0,0 +1,41 @@ +// wrap the method in the init-middleware here +import { JsonqlError } from 'jsonql-errors' +import { isContract, getDebug } from '../utils' +const debug = getDebug('process-contract') + +/** + * Create the start of chain + * @param {object} opts configuration + * @return {object} promise resolve the contract if found + */ +const getFromOpts = opts => { + return Promise.resolve( + isContract(opts.contract) + ) +} + +/** + * @param {object} ctx koa context + * @param {object} opts configuration + * @return {object} promise to resolve the contract + */ +export default async function processContract(ctx, opts) { + // const { setter, getter } = ctx.state.jsonql; + return getFromOpts(opts) + .then(c => c || false) + // .then(c => !c ? getter('contract') : c) + .then(c => { + if (!c) { + if (!ctx.state.jsonql.contract && opts.initContract && opts.initContract.then) { + debug('calling the initContract to get the contract') + return opts.initContract.then(c => { + // disable the cache for the time being + // setter('contract', c) + return c; + }) + } + throw new JsonqlError('Unable to get the contract!') + } + return c; + }) +} diff --git a/packages/koa/src/contracts/run.js b/packages/koa/src/contracts/run.js new file mode 100644 index 00000000..378f8ab3 --- /dev/null +++ b/packages/koa/src/contracts/run.js @@ -0,0 +1,20 @@ +// /lib/contract-generator/run.js +// @BUG throw error when we call this using ES6 +const { contractGenerator, readContract } = require('./import') +// listening +process.on('message', m => { + const { config, pub } = m; + if (config) { + let contract = readContract(config.contractDir, pub) + if (contract !== false) { + return process.send({ contract }) + } + contractGenerator(config, pub) + .then(contract => { + process.send({ contract }) + }) + .catch(error => { + process.send({ error }) + }) + } +}) diff --git a/packages/koa/src/middlewares/auth-middleware.js b/packages/koa/src/middlewares/auth-middleware.js new file mode 100644 index 00000000..fea1cc12 --- /dev/null +++ b/packages/koa/src/middlewares/auth-middleware.js @@ -0,0 +1,155 @@ +// jsonql-auth middleware +import { + AUTH_TYPE, + ISSUER_NAME, + VALIDATOR_NAME, + AUTH_CHECK_HEADER, + BEARER +} from 'jsonql-constants' +import { + chainFns, + getDebug, + packResult, + headerParser, + printError, + isNotEmpty, + handleOutput, + forbiddenHandler, + ctxErrorHandler, + + createTokenValidator, // import from the jwt + + isObject +} from '../utils' +import { + JsonqlResolverNotFoundError, + JsonqlAuthorisationError, + JsonqlValidationError, + finalCatch +} from 'jsonql-errors' +import { getLocalValidator } from 'jsonql-resolver' +import { trim } from 'lodash' + +const debug = getDebug('auth-middleware') + +// this will create a cache version without keep calling the getter +var validatorFn; + +// declare a global variable to store the userdata with null value +// this way we don't mess up with the resolver have to check +// the last param is the user data + +/** + * @param {object} ctx Koa context + * @param {string} type to look for + * @return {mixed} the bearer token on success + */ +const authHeaderParser = ctx => { + // const header = headers[AUTH_CHECK_HEADER]; + let header = ctx.request.get(AUTH_CHECK_HEADER) + // debug(_header, AUTH_CHECK_HEADER); + // debug('Did we get the token?', header); + return header ? getToken(header) : false; +} + +/** + * just return the token string + * @param {string} header + * @return {string} token + */ +const getToken = header => { + return trim(header.replace(BEARER, '')) +} + +/** + * when using useJwt we allow the user to provide their own validator + * and we pass the result to this validator for them to do further processing + * This is useful because the user can control if they want to invalidate the client side + * from here based on their need + * @param {object} config configuration + * @param {function|boolean} validator false if there is none + * @return {function} the combine validator + */ +const createJwtValidatorChain = (config, validator = false) => { + const jwtFn = createTokenValidator(config) + if (!validator || typeof validator !== 'function') { + return jwtFn; + } + return chainFns(jwtFn, validator) +} + +/** + * if useJwt = true then use the jsonql-jwt version + * @param {object} config configuration + * @param {string} type type of call + * @param {object} contract contract.json + * @return {function} the correct handler + */ +const getValidator = (config, type, contract) => { + if (validatorFn && typeof validatorFn === 'function') { + return validatorFn; + } + let localValidator; + try { + localValidator = getLocalValidator(config, type, contract) + } catch(e) { + // we ignore this error becasue they might not have one? + if (!(e instanceof JsonqlResolverNotFoundError)) { + return finalCatch(e) + } + } + if (config.useJwt) { + return createJwtValidatorChain(config, localValidator) + } + return localValidator; +} + +/** + * Auth middleware, we support + * 1) OAuth 2 + * 2) JWT token + * This is just front we don't do any real auth here, + * instead we expect you to supply a function and pass you data and let you + * handle the actual authentication + * @TODO need to break this down further at the moment its very hard to debug what is going on here + */ +export default function authMiddleware(config) { + // return middleware + return async function(ctx, next) { + // we should only care if there is api call involved + const { isReq, contract } = ctx.state.jsonql; + if (isReq && config.enableAuth) { + try { + const token = authHeaderParser(ctx) + if (token) { + debug('got a token', token) + validatorFn = getValidator(config , AUTH_TYPE, contract) + let userdata = await validatorFn(token) + debug('validatorFn result', userdata) + if (isNotEmpty(userdata) && isObject(userdata)) { + // here we add the userData to the global + // @TODO need more testing to see if this is going to work or not + ctx.state.jsonql.userdata = userdata; + // debug('get user data result', userdata) + await next() + } else { + debug('throw at wrong result', userdata) + return forbiddenHandler(ctx, {message: 'userdata is empty?'}) + } + } else { + debug('throw at headers not found', ctx.request.headers) + return forbiddenHandler(ctx, {message: 'header is not found!'}) + } + } catch(e) { + if (e instanceof JsonqlResolverNotFoundError) { + return ctxErrorHandler(ctx, 404, e) + } else { + debug('throw at some where throw error', e) + return forbiddenHandler(ctx, e) + } + } + } else { + await next() + } + } +} diff --git a/packages/koa/src/middlewares/console-middleware.js b/packages/koa/src/middlewares/console-middleware.js new file mode 100644 index 00000000..af05a672 --- /dev/null +++ b/packages/koa/src/middlewares/console-middleware.js @@ -0,0 +1,8 @@ +// This will be handling the json:ql console +import webConsole from 'jsonql-web-console' +import { isJsonqlConsoleUrl } from '../utils' + +// export +export default function consoleMiddleware(opts) { + return webConsole(opts, isJsonqlConsoleUrl) +} diff --git a/packages/koa/src/middlewares/contract-middleware.js b/packages/koa/src/middlewares/contract-middleware.js new file mode 100644 index 00000000..a789597d --- /dev/null +++ b/packages/koa/src/middlewares/contract-middleware.js @@ -0,0 +1,54 @@ +// This is the first part of the middlewares that try to work out the contract +// the reason is, it will get re-use by subsequences middlewares +// so we might as well do this here +// Also we could hijack it off and serve the html files up for documentation purpose +import { CONTRACT_NAME } from 'jsonql-constants' +import { + getContract, + handleContract, + contractAuth +} from '../contracts' +import { + getDebug, + ctxErrorHandler +} from '../utils' + +const debug = getDebug('contract-middleware') + +/** + * @TODO is there a bug in here somewhere that I am not aware of + * it seems to me that everytime the middleware get call, it keep trying to + * generate contract, or reading from the contract, which is not ideal + * it should able to cache it some how? + */ +export default function contractMiddleware(opts) { + // export + return async function(ctx, next) { + // this will only handle certain methods + const { isReq, resolverType } = ctx.state.jsonql; + // @2019-05-24 We need to make sure the call is actually a jsonql call + // because when http access happen it could make multiple call to the + // server and contract generator just run multiple times on a very short time + // and cause the file read failure + if (isReq) { + // now is this request asking for the public contract + if (resolverType === CONTRACT_NAME) { + if (contractAuth(ctx, opts)) { + let publicContractJson = ctx.state.jsonql.publicContract; + if (!publicContractJson) { + debug(`call the get public contract here`, opts.name) + // This should be a one off event + publicContractJson = await getContract(opts, true) + ctx.state.jsonql.publicContract = publicContractJson; + } + // debug('call handle public contract method here'); + // this is a public contract + return handleContract(opts, ctx, publicContractJson) + } else { + return ctxErrorHandler(ctx, 'JsonqlContractAuthError') + } + } + } + await next() + } +} diff --git a/packages/koa/src/middlewares/core-middleware.js b/packages/koa/src/middlewares/core-middleware.js new file mode 100644 index 00000000..fdf8c607 --- /dev/null +++ b/packages/koa/src/middlewares/core-middleware.js @@ -0,0 +1,28 @@ +// The core of the jsonql middleware +import { QUERY_NAME, MUTATION_NAME } from 'jsonql-constants' +import { resolveMethod } from 'jsonql-resolver' +import { getDebug } from '../utils' +const debug = getDebug('core') + +/** + * Top level entry point for jsonql Koa middleware + * @param {object} config options + * @return {mixed} depends whether if we catch the call + */ +export default function coreMiddleware(opts) { + // ouput the middleware + return async function(ctx, next) { + if (ctx.state.jsonql.isReq) { + const { contract, resolverType } = ctx.state.jsonql; + debug('isJsonqlRequest', resolverType) + if (resolverType === QUERY_NAME || resolverType === MUTATION_NAME) { + // debug(`Is jsonql query`, contract, opts) + // The problem is - the config is correct + // but the contract return the previous one + return resolveMethod(ctx, resolverType, opts, contract) + } + } else { + await next() + } + } +} diff --git a/packages/koa/src/middlewares/hello-middleware.js b/packages/koa/src/middlewares/hello-middleware.js new file mode 100644 index 00000000..1f72b576 --- /dev/null +++ b/packages/koa/src/middlewares/hello-middleware.js @@ -0,0 +1,19 @@ +// The helloWorld should always be available. Because this can serve as a ping even when its auth:true +import { getDebug, handleOutput, packResult } from '../utils' +import { HELLO, HELLO_FN, QUERY_NAME } from 'jsonql-constants' +const debug = getDebug('hello-middlware') +// export +export default function helloMiddleware(opts) { + return async function(ctx, next) { + const { isReq, resolverType, resolverName } = ctx.state.jsonql; + // so here we check two things, the header and the url if they match or not + if (isReq && resolverName === HELLO_FN && resolverType === QUERY_NAME) { + debug('********* ITS CALLING THE HELLO WORLD *********') + return handleOutput(opts)(ctx, packResult(HELLO)) + } else { + // @NOTE For some reason if I don't wrap this in an else statment + // I got an error said next get call multiple times + await next() + } + } +} diff --git a/packages/koa/src/middlewares/index.js b/packages/koa/src/middlewares/index.js new file mode 100644 index 00000000..1b90a495 --- /dev/null +++ b/packages/koa/src/middlewares/index.js @@ -0,0 +1,26 @@ +// main export interface +import authMiddleware from './auth-middleware' +import coreMiddleware from './core-middleware' +import contractMiddleware from './contract-middleware' +import helloMiddleware from './hello-middleware' + + +import consoleMiddleware from './console-middleware' +import publicMethodMiddleware from './public-method-middleware' +// import errorsHandlerMiddleware from './errors-handler-middleware' +import initMiddleware from './init-middleware' + +// export +export { + // configCheck, + + consoleMiddleware, + authMiddleware, + coreMiddleware, + contractMiddleware, + helloMiddleware, + + publicMethodMiddleware, + // errorsHandlerMiddleware, + initMiddleware +} diff --git a/packages/koa/src/middlewares/init-middleware.js b/packages/koa/src/middlewares/init-middleware.js new file mode 100644 index 00000000..214c900c --- /dev/null +++ b/packages/koa/src/middlewares/init-middleware.js @@ -0,0 +1,144 @@ +// this will be the first part of the middleware that checkout the +// headers and request and extract the parts that we need for the operation +import { + inArray, + getDebug, + isJsonqlRequest, + isObject, + ctxErrorHandler, + processJwtKeys, + getQueryFromPayload, + getMutationFromPayload +} from '../utils' +import { + AUTH_TYPE, + QUERY_NAME, + MUTATION_NAME, + CONTRACT_NAME, + CONTRACT_REQUEST_METHODS, + API_REQUEST_METHODS, + PAYLOAD_PARAM_NAME, + CONDITION_PARAM_NAME, + RESOLVER_PARAM_NAME, + JSONP_CALLBACK_NAME +} from 'jsonql-constants' +import { Jsonql406Error } from 'jsonql-errors' +import processContract from '../contracts/process-contract' +// should move to the utils as well + +const debug = getDebug('init-middleware') + +/** + * Just figure out what is the calling methods here + * @param {object} ctx koa context + * @return {*} false on unknown + */ +const getBaseResolverType = function(ctx) { + const [ POST, PUT ] = API_REQUEST_METHODS; + const { method } = ctx; + switch (true) { + case inArray(CONTRACT_REQUEST_METHODS, method): + return CONTRACT_NAME; + case method === POST: + return QUERY_NAME; + case method === PUT: + return MUTATION_NAME; + } +} + +/** + * check if it is auth type + * @param {string} type we need this to be the QUERY_TYPE + * @param {string} name from ctx.request.body to find the issuer name present or not + * @param {object} opts config we need that to find the custom names + */ +const isAuthType = function(type, name, opts) { + const { logoutHandlerName, loginHandlerName } = opts; + const AUTH_TYPE_METHODS = [loginHandlerName, logoutHandlerName] + if (type === QUERY_NAME) { + return inArray(AUTH_TYPE_METHODS, name) ? AUTH_TYPE : type; + } + return type; +} + +/** + * new in v1.3.0 jsonp handler + * @param {object} ctx koa context + * @return {boolean|string} return resolverName or false when its not + */ +const isJsonpCall = function(ctx) { + if (ctx.query && ctx.query[JSONP_CALLBACK_NAME]) { + return ctx.query[JSONP_CALLBACK_NAME] + } + return false; +} + +/** + * v1.2.0 add setter and getter and store in the ctx for use later + * @param {object} opts configuration + * @param {function} setter nodeCache set + * @param {function} getter nodeCache get + * @return {function} middleware + */ +export default function initMiddleware(opts) { + // export + return async function(ctx, next) { + ctx.state.jsonql = {}; + // ctx.state.jsonql.setter = setter; + // ctx.state.jsonql.getter = getter; + // first check if its calling the jsonql api + const isJsonql = isJsonqlRequest(ctx, opts) + // init our own context + ctx.state.jsonql.isReq = isJsonql; + if (isJsonql) { + // its only call once + ctx.state.jsonql.contract = await processContract(ctx, opts) + // v1.2.0 grabbing the public / private keys + opts = await processJwtKeys(ctx, opts) + // debug('processJwtKeys', opts) + // get what is calling + let payload = ctx.request.body; + // new in v1.3.0 - test for jsonp type + if (opts.enableJsonp === true) { + const jsonp = isJsonpCall(ctx) + if (jsonp !== false) { + ctx.state.jsonql.jsonp = jsonp; + // mutate the payload to let the rest to work + payload = {[jsonp]: payload} + debug('jsonp', jsonp, payload) + } + } + // start + let type = getBaseResolverType(ctx) + if (type) { + let params; + switch(type) { + case CONTRACT_NAME: + ctx.state.jsonql.resolverType = CONTRACT_NAME; + break; + case QUERY_NAME: + params = getQueryFromPayload(payload) + break; + case MUTATION_NAME: + params = getMutationFromPayload(payload) + break; + default: // should never happen! + throw new JsonqlError(`[init-middleware] ${type} is unknown!`) + } + if (type !== CONTRACT_NAME) { + let name = params[RESOLVER_PARAM_NAME]; + ctx.state.jsonql.resolverName = name; + ctx.state.jsonql.payload = params; + ctx.state.jsonql.resolverType = isAuthType(type, name, opts) + } + } else { + return ctxErrorHandler(ctx, 406, { + message: 'Payload is not the expected object type', + payload + } + ); + } + } + await next() + } +} diff --git a/packages/koa/src/middlewares/public-method-middleware.js b/packages/koa/src/middlewares/public-method-middleware.js new file mode 100644 index 00000000..c9548312 --- /dev/null +++ b/packages/koa/src/middlewares/public-method-middleware.js @@ -0,0 +1,28 @@ +// we need to let this middleware take the public method first before +// running pass to the auth-middleware otherwise, it will not able to +// get to the next one +import { QUERY_NAME, MUTATION_NAME, AUTH_TYPE } from 'jsonql-constants' +import { resolveMethod, handleAuthMethods } from 'jsonql-resolver' +import { getDebug, extractParamsFromContract } from '../utils' + +const debug = getDebug('public-method-middleware') + +// main export +export default function publicMethodMiddleware(opts) { + return async function(ctx, next) { + const { isReq, resolverType, resolverName, payload, contract } = ctx.state.jsonql; + // we pre-check if this is auth enable, if it's not then let the other middleware to deal with it + if (isReq && opts.enableAuth) { + if (resolverType === QUERY_NAME || resolverType === MUTATION_NAME) { + let params = extractParamsFromContract(contract, resolverType, resolverName) + if (params.public === true) { + return resolveMethod(ctx, resolverType, opts, contract) + } + } else if (resolverType === AUTH_TYPE && resolverName === opts.loginHandlerName) { + debug(`This is an auth ${opts.loginHandlerName} call`); + return handleAuthMethods(ctx, resolverName, payload, opts, contract) + } + } + await next() + } +} diff --git a/packages/koa/src/options/index.js b/packages/koa/src/options/index.js new file mode 100644 index 00000000..d0d55fcc --- /dev/null +++ b/packages/koa/src/options/index.js @@ -0,0 +1,79 @@ +// wrap all the options and method in one instead of all over the places +import { join, resolve } from 'path' +import fsx from 'fs-extra' +import _ from 'lodash' +import { checkConfig, isString } from 'jsonql-params-validator' +import { rsaPemKeys } from 'jsonql-jwt' + +import { appProps, constProps, jwtProcessKey } from './options' +import { isContract, chainFns, getDebug, inArray } from '../utils' +import { getContract } from '../contracts' +const debug = getDebug('config-check') + +/** + * break out from the applyAuthOptions because it's not suppose to be there + * @NOTE v1.3.8 change it to a fully functional interface + * @param {object} config configuration + * @return {object} with additional properties + */ +const applyGetContract = function(config) { + return _(config) + .chain() + .thru(config => { + const { contract } = config; + if (isContract(contract)) { + config.contract = contract; + return [true, config] + } + return [false, config] + }) + .thru(result => { + let [processed, config] = result + if (!processed) { + debug(`call initContract`) + // get resolve later inside the middleware + config.initContract = getContract(config) + } + return config; + }) + .thru(config => { + if (config.withPublicContract) { + debug(`call generate public contract`) + getContract(config, true) + } + return config; + }) + .value() +} + +/** + * we need an extra step to cache some of the auth related configuration data + * ASYNC AWAIT IS A FUCKING JOKE + * @param {object} config configuration + * @return {object} config with extra property + */ +const applyAuthOptions = function(config) { + if (config.enableAuth && config.useJwt && !isString(config.useJwt)) { + const { keysDir, publicKeyFileName, privateKeyFileName } = config; + const publicKeyPath = join(keysDir, publicKeyFileName) + const privateKeyPath = join(keysDir, privateKeyFileName) + if (fsx.existsSync(publicKeyPath) && fsx.existsSync(privateKeyPath)) { + config.publicKey = fsx.readFileSync(publicKeyPath) + config.privateKey = fsx.readFileSync(privateKeyPath) + } else { + // we only call here then resolve inside the init-middleware + config[jwtProcessKey] = rsaPemKeys(config.rsaModulusLength, config.keysDir) + } + } + return config; +} + +/** + * @param {object} config configuration supply by developer + * @return {object} configuration been checked + * @api public + */ +export function configCheck(config) { + const fn = chainFns(checkConfig, applyGetContract, applyAuthOptions) + return fn(config, appProps, constProps) +} diff --git a/packages/koa/src/options/options.js b/packages/koa/src/options/options.js new file mode 100644 index 00000000..36c6afbc --- /dev/null +++ b/packages/koa/src/options/options.js @@ -0,0 +1,113 @@ +import { join } from 'path' +import fs from 'fs' +import { + PUBLIC_KEY, + PRIVATE_KEY, + JSONQL_PATH, + CONTENT_TYPE, + DEFAULT_RESOLVER_DIR, + DEFAULT_CONTRACT_DIR, + CONTRACT_KEY_NAME, + ARRAY_TYPE, + BOOLEAN_TYPE, + STRING_TYPE, + NUMBER_TYPE, + OBJECT_TYPE, + ARGS_KEY, + TYPE_KEY, + ENUM_KEY, + CHECKER_KEY, + ACCEPTED_JS_TYPES, + CJS_TYPE, + ISSUER_NAME, + LOGOUT_NAME, + VALIDATOR_NAME, + RETURN_AS_JSON, + DEFAULT_KEYS_DIR, + DEFAULT_PUBLIC_KEY_FILE, + DEFAULT_PRIVATE_KEY_FILE, + RSA_MIN_MODULE_LEN +} from 'jsonql-constants' +import { + createConfig, + constructConfig +} from 'jsonql-params-validator' +// const NodeCache from 'node-cache'); +// const mcache = new NodeCache; +// @BUG when we deploy it in docker, or using systemd the workingDirectory affect the +// execute path, it might be better to allow a config option of workingDirectory and +// use that as base +const dirname = process.cwd() +// @TODO we need to create the same fn to clear out the options like I did in server-io-core +const constProps = { + __checked__: true, + contentType: CONTENT_TYPE, + contract: false, + initContract: false, + useDoc: true, + returnAs: RETURN_AS_JSON, + privateKey: false, + publicKey: false, + initJwtKeys: false +} + +const appProps = { + name: createConfig('jsonql-koa', [STRING_TYPE]), // this is for ID which one is which when use as ms + expired: createConfig(0, [NUMBER_TYPE]), + // allow user to change their auth type methods name + loginHandlerName: createConfig(ISSUER_NAME, [STRING_TYPE]), + logoutHandlerName: createConfig(LOGOUT_NAME, [STRING_TYPE]), + validatorHandlerName: createConfig(VALIDATOR_NAME, [STRING_TYPE, BOOLEAN_TYPE]), + // this flag will change many things + enableAuth: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE}, + // from now on always turn this to on + useJwt: createConfig(true, [BOOLEAN_TYPE, STRING_TYPE]), + jwtTokenOption: createConfig(false, [BOOLEAN_TYPE, OBJECT_TYPE]), + // add in v1.3.0 + enableJsonp: createConfig(false, [BOOLEAN_TYPE]), + // show or hide the description field in the public contract + contractWithDesc: createConfig(false, [BOOLEAN_TYPE]), + // @1.3.4 whenever generate a contract will generate the public contract as well + withPublicContract: createConfig(true, [BOOLEAN_TYPE]), + keysDir: createConfig(join(dirname, DEFAULT_KEYS_DIR), [STRING_TYPE]), + publicKeyFileName: createConfig(DEFAULT_PUBLIC_KEY_FILE, [STRING_TYPE]), + privateKeyFileName: createConfig(DEFAULT_PRIVATE_KEY_FILE, [STRING_TYPE]), + rsaModulusLength: createConfig(RSA_MIN_MODULE_LEN, [NUMBER_TYPE]), + + jsonqlPath: {[ARGS_KEY]: ['/', JSONQL_PATH].join(''), [TYPE_KEY]: STRING_TYPE}, + resolverDir: {[ARGS_KEY]: join(dirname, DEFAULT_RESOLVER_DIR), [TYPE_KEY]: STRING_TYPE, [CHECKER_KEY]: fs.existsSync}, + // we don't really need to check if the contract directory exist or not, it will get created + contractDir: {[ARGS_KEY]: join(dirname, DEFAULT_CONTRACT_DIR), [TYPE_KEY]: STRING_TYPE}, + + contractKey: {[ARGS_KEY]: false, [TYPE_KEY]: [BOOLEAN_TYPE, STRING_TYPE]}, + contractKeyName: {[ARGS_KEY]: CONTRACT_KEY_NAME, [TYPE_KEY]: STRING_TYPE}, + + publicMethodDir: createConfig(PUBLIC_KEY, [STRING_TYPE]), + // just try this with string type first + privateMethodDir: constructConfig(PRIVATE_KEY, [STRING_TYPE], true), + + // new feature for v.1.1 release + // if the developer pass the nodeClient config then we will pre-generate the calling method + // for them. We expect them to named the client so it will be key:value pair + + enableWebConsole: {[ARGS_KEY]: false, [TYPE_KEY]: [BOOLEAN_TYPE, OBJECT_TYPE]}, // you need to actively enable this option to have the web console enable + jsType: {[ARGS_KEY]: CJS_TYPE, [TYPE_KEY]: STRING_TYPE, [ENUM_KEY]: ACCEPTED_JS_TYPES}, + + // undecided properties + // clientConfig: {[ARGS_KEY]: [], [TYPE_KEY]: ARRAY_TYPE}, // need to develop a new tool to validate and inject this + exposeError: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE}, // this will allow you to control if you want to throw your error back to your client + + // Perhaps I should build the same create options style like server-io-core + autoCreateContract: {[ARGS_KEY]: true, [TYPE_KEY]: BOOLEAN_TYPE}, + buildContractOnStart: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE}, // process.env.NODE_ENV === 'development', + keepLastContract: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE}, // true keep last one, integer > 0 keep that number of files + validateReturns: {[ARGS_KEY]: false, [TYPE_KEY]: BOOLEAN_TYPE}, // reserved for use in the future + // For v1.5.0 to integrate the node-client + clientConfig: createConfig([], [ARRAY_TYPE]) +}; +const jwtProcessKey = 'INIT_JWT_KEYS' // just for id the promise call +export { + constProps, + appProps, + jwtProcessKey +} diff --git a/packages/koa/src/options/process-jwt-keys.js b/packages/koa/src/options/process-jwt-keys.js new file mode 100644 index 00000000..ead53011 --- /dev/null +++ b/packages/koa/src/options/process-jwt-keys.js @@ -0,0 +1,70 @@ +// Async Await is a fucking joke +// We can't use aynsc await during the start up because you can't wrap that output call +// as a async await ... on and on and on +// so we need to do this in two steps +// if we find a keys file, great, read it and store it +// if not then wait until inside the init-middleware and call the rsaPemKeys there +import _ from 'lodash' +import fsx from 'fs-extra' +import { jwtProcessKey } from './options' +import { isKeyInObject } from '../utils' +import { isString } from 'jsonql-params-validator' + +/** + * Get the keys from cache call + * @param {object} ctx koa context + * @param {object} config configuration + * @return {mixed} boolean on failed or object on success + */ +const getKeysFromCache = (ctx, config) => { + const { setter, getter } = ctx.state.jsonql; + if (config.enableAuth && + config.useJwt && + !isString(config.useJwt) && + (!config.publicKey || !config.privateKey)) { + let privateKey = getter('privateKey') + let publicKey = getter('publicKey') + if (privateKey && publicKey) { + return _.extend(config, { publicKey, privateKey }) + } + } + return false; +} + +/** + * Get the keys from the init promise call + * @param {object} ctx koa context + * @param {object} config configuration + * @return {mixed} boolean on failed or object on success + */ +const getCreatedKeys = (ctx, config) => { + if (isKeyInObject(config, jwtProcessKey) && config[jwtProcessKey].then) { + const { setter } = ctx.state.jsonql; + return config[jwtProcessKey] + .then( result => _.extend( config, _.mapValues(result, value => fsx.readFileSync(value) ) ) ) + .then(keys => { + _.forEach(keys, (value, key) => { + setter(key, value) + }) + return keys; + }) + } + return false; +} + +/** + * we only call this here to init it + * @param {object} ctx koa context + * @param {object} config configuration + * @return {object} config with the privateKey and publicKey stored + */ +export default function processJwtKeys(ctx, config) { + let result; + if ((result = getKeysFromCache(ctx, config)) !== false) { + return result; + } + if ((result = getCreatedKeys(ctx, config)) !== false) { + return result; + } + return config; +} diff --git a/packages/koa/src/utils/cache.js b/packages/koa/src/utils/cache.js new file mode 100644 index 00000000..b6f2296e --- /dev/null +++ b/packages/koa/src/utils/cache.js @@ -0,0 +1,30 @@ +// hope this will solve the missing contract of what not problem once and for all +import nodeCache from 'node-cache' +import { getDebug } from './utils' + +const cache = new nodeCache() +const debug = getDebug('node-cache') + +// @TODO perhaps we should have an extra key if it's presented + +/** + * @param {string} key to id + * @param {*} value value to store + * @return {*} value on success + */ +const setter = (key, value) => cache.set(key, value) ? value : false; + +/** + * throw error if the data is missing + * @param {string} key to id + * @return {*} value or throw error if missing + */ +const getter = key => { + debug(key, ' read from cache') + return cache.get(key) +} + +export { + setter, + getter +} diff --git a/packages/koa/src/utils/index.js b/packages/koa/src/utils/index.js new file mode 100644 index 00000000..23ab4017 --- /dev/null +++ b/packages/koa/src/utils/index.js @@ -0,0 +1,73 @@ +// Just group all the imports here then export them in one go +import processJwtKeys from '../options/process-jwt-keys' +import { createTokenValidator } from 'jsonql-jwt' +import { isObject, isArray } from 'jsonql-params-validator' + +import { getDebug } from './utils' +import { + isKeyInObject, + chainFns, + inArray, + headerParser, + getDocLen, + packResult, + printError, + forbiddenHandler, + ctxErrorHandler, + + isJsonqlPath, + isJsonqlRequest, + isJsonqlConsoleUrl, + + getCallMethod, + isHeaderPresent, + + isNotEmpty, + isContract, + handleOutput, + extractArgsFromPayload, + getNameFromPayload, + + extractParamsFromContract, + + getQueryFromPayload, + getMutationFromPayload +} from 'jsonql-utils' + +// export +export { + processJwtKeys, + createTokenValidator, + + getDebug, + + isObject, + isArray, + + isKeyInObject, + chainFns, + inArray, + headerParser, + getDocLen, + packResult, + printError, + forbiddenHandler, + ctxErrorHandler, + + isJsonqlPath, + isJsonqlRequest, + isJsonqlConsoleUrl, + + getCallMethod, + isHeaderPresent, + + isNotEmpty, + isContract, + handleOutput, + extractArgsFromPayload, + getNameFromPayload, + + extractParamsFromContract, + getQueryFromPayload, + getMutationFromPayload +} diff --git a/packages/koa/src/utils/utils.js b/packages/koa/src/utils/utils.js new file mode 100644 index 00000000..8d332799 --- /dev/null +++ b/packages/koa/src/utils/utils.js @@ -0,0 +1,9 @@ +// All of the functions here we moved to jsonql-utils +import debug from 'debug'; +const MODULE_NAME = 'jsonql-koa' // just keep the old name + +const getDebug = (name) => debug(MODULE_NAME).extend(name) + +export { + getDebug +} diff --git a/packages/koa/tests/auth.test.js b/packages/koa/tests/auth.test.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/config.test.js b/packages/koa/tests/config.test.js index f9ea2ac1..d4ad7913 100644 --- a/packages/koa/tests/config.test.js +++ b/packages/koa/tests/config.test.js @@ -2,9 +2,13 @@ const test = require('ava') const fsx = require('fs-extra') const { join, resolve } = require('path') -const configCheck = require('../src/lib/config-check') -const { processJwtKeys } = require('../src/lib') -const { jwtProcessKey } = require('../src/lib/config-check/options') + +const { configCheck } = require('../src/options') +const processJwtKeysDefault = require('../src/options/process-jwt-keys') +const processJwtKeys = processJwtKeysDefault.default + +const { jwtProcessKey } = require('../src/options/options') + const debug = require('debug')('jsonql-koa:test:config') const resolverDir = join(__dirname, 'fixtures', 'resolvers') const contractDir = join(__dirname, 'fixtures', 'tmp', 'config-test') diff --git a/packages/koa/tests/contract.test.js b/packages/koa/tests/contract.test.js index 40b2466d..5aa4beb1 100644 --- a/packages/koa/tests/contract.test.js +++ b/packages/koa/tests/contract.test.js @@ -2,14 +2,14 @@ const test = require('ava') const { join } = require('path') const fsx = require('fs-extra') -const generator = require('../src/lib/contract-generator') -const { isContractJson } = require('../src/lib') +const { contractGenerator } = require('../src/contracts/contract-generator') +const { isContract } = require('jsonql-utils') const debug = require('debug')('jsonql-koa:test:gen') const contractDir = join(__dirname, 'fixtures', 'tmp', 'generator') const resolverDir = join(__dirname, 'fixtures', 'resolvers') test.before(t => { - t.context.initContract = generator({ + t.context.initContract = contractGenerator({ contractDir, resolverDir, returnAs: 'json' @@ -24,5 +24,5 @@ test('It should able to generate a contract file', async t => { // this way can test if this setup works for the middleware as well const contract = await t.context.initContract; debug(contract) - t.truthy(isContractJson(contract)) + t.truthy(isContract(contract)) }) diff --git a/packages/koa/tests/contractWithAuth.test.js b/packages/koa/tests/contractWithAuth.test.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/fail.test.js b/packages/koa/tests/fail.test.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/fixtures/options.js b/packages/koa/tests/fixtures/options.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/fixtures/resolvers/auth/login.js b/packages/koa/tests/fixtures/resolvers/auth/login.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/fixtures/resolvers/auth/validator.js b/packages/koa/tests/fixtures/resolvers/auth/validator.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/fixtures/resolvers/mutation/update-list.js b/packages/koa/tests/fixtures/resolvers/mutation/update-list.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/fixtures/resolvers/query/cause-error.js b/packages/koa/tests/fixtures/resolvers/query/cause-error.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/fixtures/resolvers/query/get-user.js b/packages/koa/tests/fixtures/resolvers/query/get-user.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/fixtures/resolvers/query/test-list.js b/packages/koa/tests/fixtures/resolvers/query/test-list.js old mode 100755 new mode 100644 diff --git a/packages/koa/tests/fixtures/unused/errors-handler-middleware.js b/packages/koa/tests/fixtures/unused/errors-handler-middleware.js new file mode 100644 index 00000000..2a6e7f8c --- /dev/null +++ b/packages/koa/tests/fixtures/unused/errors-handler-middleware.js @@ -0,0 +1,25 @@ +// we will get rip of all the try catch inside each of the middleware +// and collect all the throw here +const { isContractJson, getDebug } = require('./lib') +const debug = getDebug('errors-handler-middleware') +// @TODO NOT IN USE AT THE MOMEMENT + +module.exports = function(config) { + // return middleware + return async function(ctx, next) { + return next().catch(err => { + // ctx.assert(err instanceof JsonqlServerError, 404 , 'Checking of this is what throw earlier'); + debug('Catch an error here', err) + const { statusCode, message } = err; + ctx.type = 'json'; + ctx.status = statusCode || 500; + ctx.body = JSON.stringify({ + error: { + className: 'JsonqlServerError', + message + } + }); + ctx.app.emit('error', err, ctx) + }) + } +} diff --git a/packages/koa/tests/helpers/browser.js b/packages/koa/tests/helpers/browser.js index b6217f2a..bdabdc3b 100644 --- a/packages/koa/tests/helpers/browser.js +++ b/packages/koa/tests/helpers/browser.js @@ -2,7 +2,7 @@ const serverIoCore = require('server-io-core') const { join } = require('path') -const jsonqlKoa = require('../../') +const jsonqlKoa = require('../../main') const baseDir = join(__dirname, '..', 'fixtures') diff --git a/packages/koa/tests/helpers/server.js b/packages/koa/tests/helpers/server.js old mode 100755 new mode 100644 index 2c20f069..4c69beac --- a/packages/koa/tests/helpers/server.js +++ b/packages/koa/tests/helpers/server.js @@ -3,19 +3,20 @@ const Koa = require('koa') const { join } = require('path') const bodyparser = require('koa-bodyparser') -const jsonqlMiddleware = require(join(__dirname, '..', '..','index')) +const jsonqlKoa = require('../../main') +console.info(jsonqlKoa) const { type, headers, dirs } = require('../fixtures/options') const fsx = require('fs-extra') const myKey = '4670994sdfkl'; // add a dir to seperate the contract files module.exports = (config={}, dir = '') => { - const app = new Koa(); - app.use(bodyparser()); - app.use(jsonqlMiddleware( + const app = new Koa() + app.use(bodyparser()) + app.use(jsonqlKoa.default( Object.assign({},{ resolverDir: dirs.resolverDir, contractDir: join(dirs.contractDir, dir) }, config) - )); + )) return app; } diff --git a/packages/koa/tests/helpers/sub-server.js b/packages/koa/tests/helpers/sub-server.js index aef59910..29bd9b87 100644 --- a/packages/koa/tests/helpers/sub-server.js +++ b/packages/koa/tests/helpers/sub-server.js @@ -2,7 +2,7 @@ const { join } = require('path') const fixturesDir = join(__dirname, '..', 'fixtures') const serverIoCore = require('server-io-core') -const jsonqlKoa = require('../../index') +const jsonqlKoa = require('../../main') function startSubServer(msPort) { return serverIoCore({ diff --git a/packages/koa/tests/koa.test.js b/packages/koa/tests/koa.test.js old mode 100755 new mode 100644 index 037f90b9..9b3fee2f --- a/packages/koa/tests/koa.test.js +++ b/packages/koa/tests/koa.test.js @@ -1,3 +1,4 @@ +// Koa basic test const test = require('ava') const { SHOW_CONTRACT_DESC_PARAM } = require('jsonql-constants') diff --git a/packages/koa/tests/resolverNotFound.test.js b/packages/koa/tests/resolverNotFound.test.js old mode 100755 new mode 100644 diff --git a/packages/koa/ts/README.md b/packages/koa/ts/README.md new file mode 100644 index 00000000..2761d5e3 --- /dev/null +++ b/packages/koa/ts/README.md @@ -0,0 +1,5 @@ +# Typescript port + +There was an idea to port this into Typescript but later on, I found it completely pointless and waste of time. +Since Typescript running from node.js is NOT real language. Instead we move our focus onto deno.js instead, +which Typescript is support natively -- Gitee From 887663ba4f8b7ccfc24ccebd93c1c64a215a8bd7 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 15:44:21 +0800 Subject: [PATCH 03/12] rename the old files with cjs- prefix --- packages/koa/README.md | 264 +++++++++++++++++- .../koa/{package0.json => cjs-package.json} | 108 +++---- packages/koa/index.js | 2 +- packages/koa/package.json | 106 ++++--- 4 files changed, 369 insertions(+), 111 deletions(-) rename packages/koa/{package0.json => cjs-package.json} (33%) mode change 100644 => 100755 mode change 100755 => 100644 packages/koa/package.json diff --git a/packages/koa/README.md b/packages/koa/README.md index 43d59f64..56f24ee8 100644 --- a/packages/koa/README.md +++ b/packages/koa/README.md @@ -1,9 +1,267 @@ -# @jsonql/koa +[![NPM](https://nodei.co/npm/jsonql-koa.png?compact=true)](https://npmjs.org/package/jsonql-koa) + + +# jsonql Koa middleware > This is the jsonql middleware previously published as jsonql-koa, and completely rewritten with ES6 -Please check [jsonql.org](https://jsonql.js.org) for more information. +## BREAKING CHANGE @ V1.4.0 + +The module now use named export `jsonqlKoaMiddleware` + +```js +import { jsonqlKoaMiddleware } from 'jsonql-koa' +``` + +Please change all your code accordingly. + +## Installation + +```sh +$ npm install jsonql-koa --save +``` + +or + +```sh +$ yarn add jsonql-koa +``` + +## Configuration + + + + +## Required Middlewares + +Also you need to install middleware to parse the JSON content. +Here we use [koa-bodyparser](https://github.com/koajs/bodyparser). + +```js +const Koa = require('koa'); +const jsonqlKoa = require('jsonql-koa'); +const bodyparser = require('koa-bodyparser'); +const { join } = require('path'); + +const app = new Koa(); +app.use(bodyparser()); +app.use(jsonqlKoa({ + resolverDir: join(__dirname, 'resolvers'), // this is the default value + jsonqlPath: '/jsonql' // default value +})); + +``` + +## Resolver(s) + +We expect the file in dasherized name style. + +For example you resolver directory in `/resolvers`, +and your resolver name `fetchList`, therefore you file name should be: +`/resolvers/query/fetch-list.js`. + +To properly organise your application. You should have something like This + +```sh +/resolvers/query/name-of-your-call/index.js + /lib.js + /utils.js +/resolvers/mutation/name-of-your-update/index.js +... +``` + +This way you can separate the export main function to your helpers / utils what not. +Also that makes the contract generator much easier to understand your project and create +the contract without your input. + +And your resolver should look like this + +```js +// fetchList +/** + * @param {object} params bunch of stuff + * @return {object} modified bunch of stuff + */ +module.exports = function(params) { + params.modified = parseInt((new Date()).getTime()/1000, 10); + // some more things with your params + return params; +} +``` + +The middleware is using Async/Await internally, so you could return a promise. + +### ES6 support + +As of V1.3.0 release. You can use ES6 module syntax for your resolver. If you using ES6 then you have to use +all of them as ES6 modules, it doesn't support mix and match. The reason is we have to inject a [esm](https://www.npmjs.com/package/esm) export script +to transpire your ES6 module to common js on the fly and import into your Koa middleware. + +```js +/** + * @param {number} id + * @return {any} your result + */ +export default function getSomethingById(id) { + // return your result +} +``` + +## Return Data format + +The result data will be wrap inside this signature + +``` +{ + data: { + yourData: 'something' + } +} +``` + +We will be adapting more of the [JSON API](http://jsonapi.org/) shortly + +## What you can do with this system + +There are four types within this system you can call. + +- query - Think of it as the REST API GET, where you get things +- mutation - Use this when you want to change something +- auth - Authorization methods +- socket - Coming soon + +### Query + +When you using our [js client](https://www.npmjs.com/package/jsonql-client) or [node client](https://www.npmjs.com/package/jsonql-node-client) + +It will generate function for you based on the `contract` file it received. + +__From V.1 onward we will turn on the useDoc option, which means you are **REQUIRED** to write correct jsdoc for your resolvers__ + +For example you have this resolver: + +```js +// ~/project/resolvers/query/ask-what-date.js +/** + * @return {string} UTC Date + */ +module.exports = function() { + return Date.UTC(); +} + +``` + +On your client will received what wrap inside the `data` property. + +If you throw an error inside your function call: + +```js +/** + * @return {object} just throw + */ +module.exports = function() { + throw new Error("I don't know"); +} +``` + +This will get catch and wrap inside the `result.error` field. And it will get throw on the client. +But you will always received a status 200. Because this is application level error. Nothing todo with the transport. + +Query can have as many arguments as you want. + +```js +/** + * @param {number} a + * @param {number} b + * @param {number} c + * @param {number} [d=10] + * @return {number} sum of them + */ +module.exports = function(a, b, c, d=10) { + return a + b + c + d; +} +``` + +The follow is no longer valid, we will provide you with a `CURRENT_LOGIN_USER` global object. + +~~And when this application is using the `auth` option (lock down mode). After you have successfully login and obtain the +authorisation token, every time after the successfully auth call, you will received the return value from your `validator` +method as your arguments + 1, so the above method in fact will become:~~ + +--- + +We have one built in query call `helloWorld`, it return `Hello world!`. +It will always be available. And even if you use `auth:true` option. +You do not need to login before you can access it. This is handy to ping the server and see if your set is correct. +Especially when you are writing test for your application. + +### Mutation + +The different between query and mutation is, mutation has fixed number of arguments + +```js +/** + * For the payload it will be a bit more tricky to write jsdoc + * @param {object} payload - the submit payload + * @param {string} payload.username user name + * @param {object} conditions where cause + * @param {number} conditions.user_id to id the user + * @return {boolean} true on success + */ +module.exports = function(payload, conditions) { + // your code +} + +``` + +### Auth + +There are only two authorisation methods + +1. `issuer` - basically what you do to login +2. `validator` - every time the client request your API, this method will get call and validator against the token in the header. +3. `logout` - it does what it said on the tin. + +How you implement the login and validation, it's entirely up to you as a developer. And `issuer` is just a type of `query`. +It has all the signature just like a normal query. The only different is, it will never received any additional parameter. + +The naming is important, you must name your function file as `/projects/resolvers/auth/issuer.js` and `/projects/resolvers/auth/validator.js`. Any other location or file name will not be found, and middleware will throw error. + +### socket + +This require out other module `jsonql-ws-server` to setup. More coming soon. + +## Contract + +**BREAKING CHANAGE** + +We will start using the jsdoc to capture your parameter and returns type. Therefore from V.1 release onward it will be **REQUIRED** to write correct jsdoc. This is important because +the client side will be expecting correct type information for +the validation to work correctly. Also this solve a problem of +unable to pass default parameter to pass the resolver. + +__And the typescript port currently under development will able to work with the standard JS server side, ,as well as the Typescript version__ + +--- + +Contracts are generate automatically when you start up your application. We have a separate tool [jsonql-contract](https://www.npmjs.com/package/jsonql-contract) to generate the contract file (it just a json file contain information about your applications). For internal user, the file is call `contract.json` it will located in the `contractDir` +you specify when you config the middleware, default location will be `~/project/contracts`. + +There is another contract that is for your client to consume, which is name `public-contract.json`. It has the same structure +but without some of the sensitive information, such as the `file` field (where your code located) and the `validator` field. + +If you are not using `auth:true` option, then even if you implement the `auth/issuer.js` method, it will get remove as well. + +Also whenever the client request the contract. It will look for additional json file in the same folder. + +For instance, your `NODE_ENV=development` therefore, it will search for `~/project/contracts/development.json` and this will +get merge with the stock `public-contract.json`. Therefore you can overwrite information (but not remove) or add additional +information, such as change the return field, and write a auto validator based on the result you received. + +Also you can set a password to avoid unwanted access to your contract. Just pass the `contractKey:[password]` to the config +object. --- -NB & T1S +MIT (c) 2019 [to1source China](https://to1source.cn) +in collaboration with [NEWBRAN LTD UK](https://newbran.ch) diff --git a/packages/koa/package0.json b/packages/koa/cjs-package.json old mode 100644 new mode 100755 similarity index 33% rename from packages/koa/package0.json rename to packages/koa/cjs-package.json index 261d09c2..565ecbae --- a/packages/koa/package0.json +++ b/packages/koa/cjs-package.json @@ -1,96 +1,74 @@ { - "name": "@jsonql/koa", - "version": "0.3.0", + "name": "jsonql-koa", + "version": "1.3.4", "description": "jsonql Koa middleware", - "main": "main.js", - "module": "index.js", + "main": "index.js", "files": [ "src", "index.js", - "main.js" + "contract.js" ], "scripts": { - "test": "ava --verbose", - "prepare": "npm run test", - "start": "node ./test/fixtures/start.js", - "test:debug": "DEBUG=jsonql* ava --verbose", - "coverage": "nyc ava --verbose", - "test:basic": "DEBUG=jsonql* ava ./tests/koa.test.js", - "test:notfound": "DEBUG=jsonql-koa* ava --verbose ./tests/resolverNotFound.test.js", - "test:es6": "DEBUG=jsonql-koa* ava --verbose ./tests/es6-module.test.js", - "test:jwt": "DEBUG=jsonql-koa*,jsonql-jwt* ava ./tests/jwt.test.js", - "test:jwt-auth": "DEBUG=jsonql-koa* ava ./tests/jwt-auth.test.js", - "test:fail": "ava ./tests/fail.test.js", - "test:contract": "DEBUG=jsonql-koa* ava ./tests/contractWithAuth.test.js", - "test:auth": "DEBUG=jsonql* ava ./tests/auth.test.js", - "test:error": "DEBUG=jsonql-koa* ava ./tests/resolverNotFound.test.js", - "test:config": "DEBUG=jsonql-* ava ./tests/config.test.js", - "test:throw": "DEBUG=jsonql-* ava ./tests/throw.test.js", - "test:gen": "DEBUG=jsonql* ava ./tests/contract.test.js", - "test:jsonp": "DEBUG=jsonql* ava --verbose ./tests/jsonp.test.js", - "test:chain": "DEBUG=jsonql* ava --verbose ./tests/chain-fn.test.js", - "test:clients": "DEBUG=jsonql* ava --verbose ./tests/node-client.test.js", - "web-console": "DEBUG=jsonql-koa*,jsonql-web-console* node ./tests/helpers/browser.js", - "contract": "node ./node_modules/jsonql-contract/cmd.js ./tests/fixtures/resolvers ./tests/fixtures/contracts" + "deprecated": "npm deprecate jsonql-ws-client \"This module is no longer maintain, please install our latest @jsonql/koa and check https://jsonql.js.org for up to date version\"" }, "keywords": [ "jsonql", - "koa", - "server", - "socket", - "WebSocket", - "API" + "JSON", + "Js", + "QL", + "Middleware", + "Koa" ], - "author": "Joel Chu ", - "license": "ISC", - "repository": { - "type": "git", - "url": "git+ssh://git@gitee.com:to1source/jsonql.git" - }, - "bugs": { - "url": "https://gitee.com/to1source/jsonql/issues" - }, - "homepage": "jsonql.org", - "ava": { - "files": [ - "tests/*.test.js", - "!tests/helpers/*.*", - "!tests/fixtures/*.*" - ], - "require": [ - "esm" - ], - "cache": true, - "concurrency": 5, - "failFast": true, - "failWithoutAssertions": false, - "tap": false, - "compileEnhancements": false - }, "dependencies": { "debug": "^4.1.1", "esm": "^3.2.25", "fs-extra": "^8.1.0", "jsonql-constants": "^1.8.3", - "jsonql-contract": "^1.7.9", + "jsonql-contract": "^1.7.8", "jsonql-errors": "^1.1.3", - "jsonql-jwt": "^1.3.2", - "jsonql-node-client": "^1.1.9", - "jsonql-params-validator": "^1.4.11", - "jsonql-resolver": "^0.8.7", - "jsonql-utils": "^0.6.10", + "jsonql-jwt": "^1.3.1", + "jsonql-node-client": "^1.1.8", + "jsonql-params-validator": "^1.4.8", + "jsonql-resolver": "^0.8.0", + "jsonql-utils": "^0.4.9", "jsonql-web-console": "^0.4.3", "koa": "^2.8.1", "koa-compose": "^4.1.0", "lodash": "^4.17.15" }, "devDependencies": { - "ava": "^2.4.0", + "ava": "^2.3.0", "jwt-decode": "^2.2.0", "koa-bodyparser": "^4.2.1", "nyc": "^14.1.1", "request": "^2.88.0", "server-io-core": "^1.2.0", "superkoa": "^1.0.3" + }, + "author": "to1source ", + "contributors": [ + "NEWBRAN LTD " + ], + "homepage": "jsonql.org", + "license": "MIT", + "repository": { + "type": "git", + "url": "git+ssh://git@gitee.com:to1source/jsonql.git" + }, + "ava": { + "files": [ + "tests/*.test.js", + "!tests/helpers/*.*", + "!tests/fixtures/*.*" + ], + "cache": true, + "concurrency": 5, + "failFast": true, + "failWithoutAssertions": false, + "tap": false, + "compileEnhancements": false + }, + "engine": { + "node": ">=8" } } diff --git a/packages/koa/index.js b/packages/koa/index.js index f7df12b2..869be65f 100644 --- a/packages/koa/index.js +++ b/packages/koa/index.js @@ -18,7 +18,7 @@ import { configCheck } from './src/options' import { getDebug } from './src/utils' const debug = getDebug('main') // main -export default function jsonqlKoa(config = {}) { +export function jsonqlKoaMiddleware(config = {}) { // first check the config const opts = configCheck(config) debug('[jsonql-koa] init opts', opts) diff --git a/packages/koa/package.json b/packages/koa/package.json old mode 100755 new mode 100644 index 565ecbae..7cc6be26 --- a/packages/koa/package.json +++ b/packages/koa/package.json @@ -1,74 +1,96 @@ { "name": "jsonql-koa", - "version": "1.3.4", + "version": "1.4.0", "description": "jsonql Koa middleware", - "main": "index.js", + "main": "main.js", + "module": "index.js", "files": [ "src", "index.js", - "contract.js" + "main.js" ], "scripts": { - "deprecated": "npm deprecate jsonql-ws-client \"This module is no longer maintain, please install our latest @jsonql/koa and check https://jsonql.js.org for up to date version\"" + "test": "ava --verbose", + "prepare": "npm run test", + "start": "node ./test/fixtures/start.js", + "test:debug": "DEBUG=jsonql* ava --verbose", + "coverage": "nyc ava --verbose", + "test:basic": "DEBUG=jsonql* ava ./tests/koa.test.js", + "test:notfound": "DEBUG=jsonql-koa* ava --verbose ./tests/resolverNotFound.test.js", + "test:es6": "DEBUG=jsonql-koa* ava --verbose ./tests/es6-module.test.js", + "test:jwt": "DEBUG=jsonql-koa*,jsonql-jwt* ava ./tests/jwt.test.js", + "test:jwt-auth": "DEBUG=jsonql-koa* ava ./tests/jwt-auth.test.js", + "test:fail": "ava ./tests/fail.test.js", + "test:contract": "DEBUG=jsonql-koa* ava ./tests/contractWithAuth.test.js", + "test:auth": "DEBUG=jsonql* ava ./tests/auth.test.js", + "test:error": "DEBUG=jsonql-koa* ava ./tests/resolverNotFound.test.js", + "test:config": "DEBUG=jsonql-* ava ./tests/config.test.js", + "test:throw": "DEBUG=jsonql-* ava ./tests/throw.test.js", + "test:gen": "DEBUG=jsonql* ava ./tests/contract.test.js", + "test:jsonp": "DEBUG=jsonql* ava --verbose ./tests/jsonp.test.js", + "test:chain": "DEBUG=jsonql* ava --verbose ./tests/chain-fn.test.js", + "test:clients": "DEBUG=jsonql* ava --verbose ./tests/node-client.test.js", + "web-console": "DEBUG=jsonql-koa*,jsonql-web-console* node ./tests/helpers/browser.js", + "contract": "node ./node_modules/jsonql-contract/cmd.js ./tests/fixtures/resolvers ./tests/fixtures/contracts" }, "keywords": [ "jsonql", - "JSON", - "Js", - "QL", - "Middleware", - "Koa" + "koa", + "server", + "socket", + "WebSocket", + "API" ], + "author": "Joel Chu ", + "license": "ISC", + "repository": { + "type": "git", + "url": "git+ssh://git@gitee.com:to1source/jsonql.git" + }, + "bugs": { + "url": "https://gitee.com/to1source/jsonql/issues" + }, + "homepage": "jsonql.org", + "ava": { + "files": [ + "tests/*.test.js", + "!tests/helpers/*.*", + "!tests/fixtures/*.*" + ], + "require": [ + "esm" + ], + "cache": true, + "concurrency": 5, + "failFast": true, + "failWithoutAssertions": false, + "tap": false, + "compileEnhancements": false + }, "dependencies": { "debug": "^4.1.1", "esm": "^3.2.25", "fs-extra": "^8.1.0", "jsonql-constants": "^1.8.3", - "jsonql-contract": "^1.7.8", + "jsonql-contract": "^1.7.9", "jsonql-errors": "^1.1.3", - "jsonql-jwt": "^1.3.1", - "jsonql-node-client": "^1.1.8", - "jsonql-params-validator": "^1.4.8", - "jsonql-resolver": "^0.8.0", - "jsonql-utils": "^0.4.9", + "jsonql-jwt": "^1.3.2", + "jsonql-node-client": "^1.1.9", + "jsonql-params-validator": "^1.4.11", + "jsonql-resolver": "^0.8.7", + "jsonql-utils": "^0.6.10", "jsonql-web-console": "^0.4.3", "koa": "^2.8.1", "koa-compose": "^4.1.0", "lodash": "^4.17.15" }, "devDependencies": { - "ava": "^2.3.0", + "ava": "^2.4.0", "jwt-decode": "^2.2.0", "koa-bodyparser": "^4.2.1", "nyc": "^14.1.1", "request": "^2.88.0", "server-io-core": "^1.2.0", "superkoa": "^1.0.3" - }, - "author": "to1source ", - "contributors": [ - "NEWBRAN LTD " - ], - "homepage": "jsonql.org", - "license": "MIT", - "repository": { - "type": "git", - "url": "git+ssh://git@gitee.com:to1source/jsonql.git" - }, - "ava": { - "files": [ - "tests/*.test.js", - "!tests/helpers/*.*", - "!tests/fixtures/*.*" - ], - "cache": true, - "concurrency": 5, - "failFast": true, - "failWithoutAssertions": false, - "tap": false, - "compileEnhancements": false - }, - "engine": { - "node": ">=8" } } -- Gitee From 1e00c606250e4671da0eb3aa6f27c8511e1d7cac Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 15:48:55 +0800 Subject: [PATCH 04/12] update readme with new options --- packages/koa/README.md | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/koa/README.md b/packages/koa/README.md index 56f24ee8..dc5415ee 100644 --- a/packages/koa/README.md +++ b/packages/koa/README.md @@ -27,10 +27,14 @@ or $ yarn add jsonql-koa ``` -## Configuration - +## Configuration options +| Name | Description | Expected Type | Default value | +| ----------- |:----------------------| :------------:| :--------------| +| resolversDir | Where the resolvers is | `String` | `join(process.cwd(), 'resolvers')` | +| contractDir | Where to store the contract | `String` | `join(process.cwd(), 'contract')` | +More options to come later ## Required Middlewares @@ -39,16 +43,15 @@ Here we use [koa-bodyparser](https://github.com/koajs/bodyparser). ```js const Koa = require('koa'); -const jsonqlKoa = require('jsonql-koa'); +const { jsonqlKoaMiddleware } = require('jsonql-koa'); const bodyparser = require('koa-bodyparser'); const { join } = require('path'); const app = new Koa(); app.use(bodyparser()); -app.use(jsonqlKoa({ - resolverDir: join(__dirname, 'resolvers'), // this is the default value - jsonqlPath: '/jsonql' // default value -})); +app.use(jsonqlKoaMiddleware({ + resolverDir: join(__dirname, 'resolvers') // this is the default value +})) ``` -- Gitee From bc07190fabdfb401f2934f4e846cb7f553bd124d Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 15:52:17 +0800 Subject: [PATCH 05/12] fix some of the grammer in README --- packages/koa/README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/koa/README.md b/packages/koa/README.md index dc5415ee..30535564 100644 --- a/packages/koa/README.md +++ b/packages/koa/README.md @@ -34,7 +34,7 @@ $ yarn add jsonql-koa | resolversDir | Where the resolvers is | `String` | `join(process.cwd(), 'resolvers')` | | contractDir | Where to store the contract | `String` | `join(process.cwd(), 'contract')` | -More options to come later +More options to come later ## Required Middlewares @@ -59,11 +59,11 @@ app.use(jsonqlKoaMiddleware({ We expect the file in dasherized name style. -For example you resolver directory in `/resolvers`, -and your resolver name `fetchList`, therefore you file name should be: +For example your resolver directory is `/resolvers`, +and your resolver name `fetchList`, therefore the expected resolver file name will be: `/resolvers/query/fetch-list.js`. -To properly organise your application. You should have something like This +To properly organise your application. You should have something like this (otherwise it won't work) ```sh /resolvers/query/name-of-your-call/index.js @@ -73,11 +73,11 @@ To properly organise your application. You should have something like This ... ``` -This way you can separate the export main function to your helpers / utils what not. -Also that makes the contract generator much easier to understand your project and create +This way you can separate the export main function to your helpers / utility what not. +Also that makes the contract generator to understand your project and create the contract without your input. -And your resolver should look like this +And your resolver should look something like this: ```js // fetchList -- Gitee From fc06b47b5b4e0cc6e26d708dd4c17b2d4f51eada Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 15:59:05 +0800 Subject: [PATCH 06/12] getting the test ready --- packages/koa/README.md | 6 +++--- packages/koa/index.js | 2 +- packages/koa/tests/auth.test.js | 2 +- packages/koa/tests/fail.test.js | 2 +- packages/koa/tests/fixtures/options.js | 2 +- packages/koa/tests/helpers/browser.js | 2 +- packages/koa/tests/helpers/server.js | 4 ++-- packages/koa/tests/helpers/sub-server.js | 2 +- packages/koa/tests/jsonp.test.js | 2 +- packages/koa/tests/resolverNotFound.test.js | 2 +- 10 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/koa/README.md b/packages/koa/README.md index 30535564..9280cf00 100644 --- a/packages/koa/README.md +++ b/packages/koa/README.md @@ -10,7 +10,7 @@ The module now use named export `jsonqlKoaMiddleware` ```js -import { jsonqlKoaMiddleware } from 'jsonql-koa' +import { jsonqlKoa } from 'jsonql-koa' ``` Please change all your code accordingly. @@ -43,13 +43,13 @@ Here we use [koa-bodyparser](https://github.com/koajs/bodyparser). ```js const Koa = require('koa'); -const { jsonqlKoaMiddleware } = require('jsonql-koa'); +const { jsonqlKoa } = require('jsonql-koa'); const bodyparser = require('koa-bodyparser'); const { join } = require('path'); const app = new Koa(); app.use(bodyparser()); -app.use(jsonqlKoaMiddleware({ +app.use(jsonqlKoa({ resolverDir: join(__dirname, 'resolvers') // this is the default value })) diff --git a/packages/koa/index.js b/packages/koa/index.js index 869be65f..06aba1d7 100644 --- a/packages/koa/index.js +++ b/packages/koa/index.js @@ -18,7 +18,7 @@ import { configCheck } from './src/options' import { getDebug } from './src/utils' const debug = getDebug('main') // main -export function jsonqlKoaMiddleware(config = {}) { +export function jsonqlKoa(config = {}) { // first check the config const opts = configCheck(config) debug('[jsonql-koa] init opts', opts) diff --git a/packages/koa/tests/auth.test.js b/packages/koa/tests/auth.test.js index 6f627ba8..9081738d 100644 --- a/packages/koa/tests/auth.test.js +++ b/packages/koa/tests/auth.test.js @@ -7,7 +7,7 @@ const { createQuery } = require('jsonql-utils') const fsx = require('fs-extra') const { merge } = require('lodash') const { HELLO_FN } = require('jsonql-constants') -const jsonqlMiddleware = require(join(__dirname, '..', 'index')) +// const jsonqlMiddleware = require(join(__dirname, '..', 'index')) const { type, headers, dirs, bearer, contractKeyName } = require('./fixtures/options') const createServer = require('./helpers/server') const myKey = '4670994sdfkl'; diff --git a/packages/koa/tests/fail.test.js b/packages/koa/tests/fail.test.js index c7a6acd6..a5e69c66 100644 --- a/packages/koa/tests/fail.test.js +++ b/packages/koa/tests/fail.test.js @@ -3,7 +3,7 @@ const test = require('ava') const superkoa = require('superkoa') const { join } = require('path') const debug = require('debug')('jsonql-koa:test:fail') -const jsonqlMiddleware = require(join(__dirname, '..', 'index')) +// const jsonqlMiddleware = require(join(__dirname, '..', 'index')) const { type, headers, dirs } = require('./fixtures/options') const fsx = require('fs-extra') diff --git a/packages/koa/tests/fixtures/options.js b/packages/koa/tests/fixtures/options.js index b8e5c8e0..d5798a29 100644 --- a/packages/koa/tests/fixtures/options.js +++ b/packages/koa/tests/fixtures/options.js @@ -10,7 +10,7 @@ const contractKeyName = CONTRACT_KEY_NAME; const dirs = { resolverDir: join(__dirname, 'resolvers'), contractDir: join(__dirname, 'tmp') -}; +} const secret = 'A little cat is watching you'; diff --git a/packages/koa/tests/helpers/browser.js b/packages/koa/tests/helpers/browser.js index bdabdc3b..23be9cc3 100644 --- a/packages/koa/tests/helpers/browser.js +++ b/packages/koa/tests/helpers/browser.js @@ -2,7 +2,7 @@ const serverIoCore = require('server-io-core') const { join } = require('path') -const jsonqlKoa = require('../../main') +const {{ jsonqlKoa } = require('../../main') const baseDir = join(__dirname, '..', 'fixtures') diff --git a/packages/koa/tests/helpers/server.js b/packages/koa/tests/helpers/server.js index 4c69beac..ef59b5d6 100644 --- a/packages/koa/tests/helpers/server.js +++ b/packages/koa/tests/helpers/server.js @@ -3,8 +3,8 @@ const Koa = require('koa') const { join } = require('path') const bodyparser = require('koa-bodyparser') -const jsonqlKoa = require('../../main') -console.info(jsonqlKoa) +const { jsonqlKoa } = require('../../main') + const { type, headers, dirs } = require('../fixtures/options') const fsx = require('fs-extra') const myKey = '4670994sdfkl'; diff --git a/packages/koa/tests/helpers/sub-server.js b/packages/koa/tests/helpers/sub-server.js index 29bd9b87..63aed5b3 100644 --- a/packages/koa/tests/helpers/sub-server.js +++ b/packages/koa/tests/helpers/sub-server.js @@ -2,7 +2,7 @@ const { join } = require('path') const fixturesDir = join(__dirname, '..', 'fixtures') const serverIoCore = require('server-io-core') -const jsonqlKoa = require('../../main') +const { jsonqlKoa } = require('../../main') function startSubServer(msPort) { return serverIoCore({ diff --git a/packages/koa/tests/jsonp.test.js b/packages/koa/tests/jsonp.test.js index 0fc1ca79..ca9741d5 100644 --- a/packages/koa/tests/jsonp.test.js +++ b/packages/koa/tests/jsonp.test.js @@ -20,7 +20,7 @@ test.after( () => { }) // @TODO this is not the proper JSONP need to think about it before continue with this feature -test('It should able to tell if this is access using jsonp', async t => { +test.skip('It should able to tell if this is access using jsonp', async t => { let res = await superkoa(t.context.app) .post('/jsonql') .set(headers) diff --git a/packages/koa/tests/resolverNotFound.test.js b/packages/koa/tests/resolverNotFound.test.js index 19986ac0..4412f27e 100644 --- a/packages/koa/tests/resolverNotFound.test.js +++ b/packages/koa/tests/resolverNotFound.test.js @@ -31,7 +31,7 @@ test('it should throw a ResolverNotFoundError', async (t) => { t.is(res.body.error.statusCode, 404) }) - +// @BUG need fixing test("It should cause an Application error but nothing throw", async t => { let res = await superkoa(t.context.app) .post('/jsonql') -- Gitee From ac7ddcf4cd8280ed8e81f45df68c70dac7a6cfdf Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 16:03:51 +0800 Subject: [PATCH 07/12] fix the middleware but the contract cli seems to be broken now --- packages/koa/tests/helpers/browser.js | 2 +- packages/koa/tests/helpers/server.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/koa/tests/helpers/browser.js b/packages/koa/tests/helpers/browser.js index 23be9cc3..bfe55df7 100644 --- a/packages/koa/tests/helpers/browser.js +++ b/packages/koa/tests/helpers/browser.js @@ -2,7 +2,7 @@ const serverIoCore = require('server-io-core') const { join } = require('path') -const {{ jsonqlKoa } = require('../../main') +const { jsonqlKoa } = require('../../main') const baseDir = join(__dirname, '..', 'fixtures') diff --git a/packages/koa/tests/helpers/server.js b/packages/koa/tests/helpers/server.js index ef59b5d6..2a4812b6 100644 --- a/packages/koa/tests/helpers/server.js +++ b/packages/koa/tests/helpers/server.js @@ -12,7 +12,7 @@ const myKey = '4670994sdfkl'; module.exports = (config={}, dir = '') => { const app = new Koa() app.use(bodyparser()) - app.use(jsonqlKoa.default( + app.use(jsonqlKoa( Object.assign({},{ resolverDir: dirs.resolverDir, contractDir: join(dirs.contractDir, dir) -- Gitee From 90cfe2cedcd3f47324de08f2fdd049019b1f53ba Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 16:06:43 +0800 Subject: [PATCH 08/12] move all the old code into the previous folder until its ready to publish --- packages/koa/{ => previous}/cjs-README.md | 0 packages/koa/{ => previous}/cjs-index.js | 0 packages/koa/{ => previous}/cjs-package.json | 0 packages/koa/{ => previous}/cjs-src/auth-middleware.js | 0 packages/koa/{ => previous}/cjs-src/console-middleware.js | 0 packages/koa/{ => previous}/cjs-src/contract-middleware.js | 0 packages/koa/{ => previous}/cjs-src/core-middleware.js | 0 packages/koa/{ => previous}/cjs-src/errors-handler-middleware.js | 0 packages/koa/{ => previous}/cjs-src/hello-middleware.js | 0 packages/koa/{ => previous}/cjs-src/index.js | 0 packages/koa/{ => previous}/cjs-src/init-middleware.js | 0 packages/koa/{ => previous}/cjs-src/lib/cache.js | 0 packages/koa/{ => previous}/cjs-src/lib/config-check/index.js | 0 packages/koa/{ => previous}/cjs-src/lib/config-check/options.js | 0 .../{ => previous}/cjs-src/lib/config-check/process-jwt-keys.js | 0 .../cjs-src/lib/contract-generator/contract-generator.js | 0 .../koa/{ => previous}/cjs-src/lib/contract-generator/index.js | 0 .../cjs-src/lib/contract-generator/process-contract.js | 0 packages/koa/{ => previous}/cjs-src/lib/contract-generator/run.js | 0 packages/koa/{ => previous}/cjs-src/lib/index.js | 0 packages/koa/{ => previous}/cjs-src/lib/utils.js | 0 packages/koa/{ => previous}/cjs-src/public-method-middleware.js | 0 packages/koa/{ => previous}/cjs-tests/auth.test.js | 0 packages/koa/{ => previous}/cjs-tests/chain-fn.test.js | 0 packages/koa/{ => previous}/cjs-tests/config.test.js | 0 packages/koa/{ => previous}/cjs-tests/contract.test.js | 0 packages/koa/{ => previous}/cjs-tests/contractWithAuth.test.js | 0 packages/koa/{ => previous}/cjs-tests/es6-module.test.js | 0 packages/koa/{ => previous}/cjs-tests/fail.test.js | 0 .../cjs-tests/fixtures/es/mutation/save-something.js | 0 .../{ => previous}/cjs-tests/fixtures/es/query/get-something.js | 0 packages/koa/{ => previous}/cjs-tests/fixtures/html/index.html | 0 .../koa/{ => previous}/cjs-tests/fixtures/keys/privateKey.pem | 0 packages/koa/{ => previous}/cjs-tests/fixtures/keys/publicKey.pem | 0 packages/koa/{ => previous}/cjs-tests/fixtures/options.js | 0 .../cjs-tests/fixtures/resolvers/auth/custom-login.js | 0 .../cjs-tests/fixtures/resolvers/auth/custom-validator.js | 0 .../koa/{ => previous}/cjs-tests/fixtures/resolvers/auth/login.js | 0 .../{ => previous}/cjs-tests/fixtures/resolvers/auth/logout.js | 0 .../{ => previous}/cjs-tests/fixtures/resolvers/auth/validator.js | 0 .../cjs-tests/fixtures/resolvers/mutation/update-list.js | 0 .../cjs-tests/fixtures/resolvers/mutation/update-ms-service.js | 0 .../cjs-tests/fixtures/resolvers/query/cause-error.js | 0 .../{ => previous}/cjs-tests/fixtures/resolvers/query/get-user.js | 0 .../cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js | 0 .../cjs-tests/fixtures/resolvers/query/public/always-available.js | 0 .../cjs-tests/fixtures/resolvers/query/test-list.js | 0 .../fixtures/sub/resolver/mutation/sub-update-ms-service.js | 0 .../cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js | 0 packages/koa/{ => previous}/cjs-tests/helpers/browser.js | 0 packages/koa/{ => previous}/cjs-tests/helpers/hello.js | 0 packages/koa/{ => previous}/cjs-tests/helpers/server.js | 0 packages/koa/{ => previous}/cjs-tests/helpers/sub-server.js | 0 packages/koa/{ => previous}/cjs-tests/jsonp.test.js | 0 packages/koa/{ => previous}/cjs-tests/jwt-auth.test.js | 0 packages/koa/{ => previous}/cjs-tests/jwt.test.js | 0 packages/koa/{ => previous}/cjs-tests/koa.test.js | 0 packages/koa/{ => previous}/cjs-tests/node-client.donttest.js | 0 packages/koa/{ => previous}/cjs-tests/resolverNotFound.test.js | 0 packages/koa/{ => previous}/cjs-tests/throw.test.js | 0 60 files changed, 0 insertions(+), 0 deletions(-) rename packages/koa/{ => previous}/cjs-README.md (100%) rename packages/koa/{ => previous}/cjs-index.js (100%) rename packages/koa/{ => previous}/cjs-package.json (100%) rename packages/koa/{ => previous}/cjs-src/auth-middleware.js (100%) rename packages/koa/{ => previous}/cjs-src/console-middleware.js (100%) rename packages/koa/{ => previous}/cjs-src/contract-middleware.js (100%) rename packages/koa/{ => previous}/cjs-src/core-middleware.js (100%) rename packages/koa/{ => previous}/cjs-src/errors-handler-middleware.js (100%) rename packages/koa/{ => previous}/cjs-src/hello-middleware.js (100%) rename packages/koa/{ => previous}/cjs-src/index.js (100%) rename packages/koa/{ => previous}/cjs-src/init-middleware.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/cache.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/config-check/index.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/config-check/options.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/config-check/process-jwt-keys.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/contract-generator/contract-generator.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/contract-generator/index.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/contract-generator/process-contract.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/contract-generator/run.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/index.js (100%) rename packages/koa/{ => previous}/cjs-src/lib/utils.js (100%) rename packages/koa/{ => previous}/cjs-src/public-method-middleware.js (100%) rename packages/koa/{ => previous}/cjs-tests/auth.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/chain-fn.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/config.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/contract.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/contractWithAuth.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/es6-module.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/fail.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/es/mutation/save-something.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/es/query/get-something.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/html/index.html (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/keys/privateKey.pem (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/keys/publicKey.pem (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/options.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/auth/custom-login.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/auth/custom-validator.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/auth/login.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/auth/logout.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/auth/validator.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/mutation/update-list.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/mutation/update-ms-service.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/query/cause-error.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/query/get-user.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/query/public/always-available.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/resolvers/query/test-list.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js (100%) rename packages/koa/{ => previous}/cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js (100%) rename packages/koa/{ => previous}/cjs-tests/helpers/browser.js (100%) rename packages/koa/{ => previous}/cjs-tests/helpers/hello.js (100%) rename packages/koa/{ => previous}/cjs-tests/helpers/server.js (100%) rename packages/koa/{ => previous}/cjs-tests/helpers/sub-server.js (100%) rename packages/koa/{ => previous}/cjs-tests/jsonp.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/jwt-auth.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/jwt.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/koa.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/node-client.donttest.js (100%) rename packages/koa/{ => previous}/cjs-tests/resolverNotFound.test.js (100%) rename packages/koa/{ => previous}/cjs-tests/throw.test.js (100%) diff --git a/packages/koa/cjs-README.md b/packages/koa/previous/cjs-README.md similarity index 100% rename from packages/koa/cjs-README.md rename to packages/koa/previous/cjs-README.md diff --git a/packages/koa/cjs-index.js b/packages/koa/previous/cjs-index.js similarity index 100% rename from packages/koa/cjs-index.js rename to packages/koa/previous/cjs-index.js diff --git a/packages/koa/cjs-package.json b/packages/koa/previous/cjs-package.json similarity index 100% rename from packages/koa/cjs-package.json rename to packages/koa/previous/cjs-package.json diff --git a/packages/koa/cjs-src/auth-middleware.js b/packages/koa/previous/cjs-src/auth-middleware.js similarity index 100% rename from packages/koa/cjs-src/auth-middleware.js rename to packages/koa/previous/cjs-src/auth-middleware.js diff --git a/packages/koa/cjs-src/console-middleware.js b/packages/koa/previous/cjs-src/console-middleware.js similarity index 100% rename from packages/koa/cjs-src/console-middleware.js rename to packages/koa/previous/cjs-src/console-middleware.js diff --git a/packages/koa/cjs-src/contract-middleware.js b/packages/koa/previous/cjs-src/contract-middleware.js similarity index 100% rename from packages/koa/cjs-src/contract-middleware.js rename to packages/koa/previous/cjs-src/contract-middleware.js diff --git a/packages/koa/cjs-src/core-middleware.js b/packages/koa/previous/cjs-src/core-middleware.js similarity index 100% rename from packages/koa/cjs-src/core-middleware.js rename to packages/koa/previous/cjs-src/core-middleware.js diff --git a/packages/koa/cjs-src/errors-handler-middleware.js b/packages/koa/previous/cjs-src/errors-handler-middleware.js similarity index 100% rename from packages/koa/cjs-src/errors-handler-middleware.js rename to packages/koa/previous/cjs-src/errors-handler-middleware.js diff --git a/packages/koa/cjs-src/hello-middleware.js b/packages/koa/previous/cjs-src/hello-middleware.js similarity index 100% rename from packages/koa/cjs-src/hello-middleware.js rename to packages/koa/previous/cjs-src/hello-middleware.js diff --git a/packages/koa/cjs-src/index.js b/packages/koa/previous/cjs-src/index.js similarity index 100% rename from packages/koa/cjs-src/index.js rename to packages/koa/previous/cjs-src/index.js diff --git a/packages/koa/cjs-src/init-middleware.js b/packages/koa/previous/cjs-src/init-middleware.js similarity index 100% rename from packages/koa/cjs-src/init-middleware.js rename to packages/koa/previous/cjs-src/init-middleware.js diff --git a/packages/koa/cjs-src/lib/cache.js b/packages/koa/previous/cjs-src/lib/cache.js similarity index 100% rename from packages/koa/cjs-src/lib/cache.js rename to packages/koa/previous/cjs-src/lib/cache.js diff --git a/packages/koa/cjs-src/lib/config-check/index.js b/packages/koa/previous/cjs-src/lib/config-check/index.js similarity index 100% rename from packages/koa/cjs-src/lib/config-check/index.js rename to packages/koa/previous/cjs-src/lib/config-check/index.js diff --git a/packages/koa/cjs-src/lib/config-check/options.js b/packages/koa/previous/cjs-src/lib/config-check/options.js similarity index 100% rename from packages/koa/cjs-src/lib/config-check/options.js rename to packages/koa/previous/cjs-src/lib/config-check/options.js diff --git a/packages/koa/cjs-src/lib/config-check/process-jwt-keys.js b/packages/koa/previous/cjs-src/lib/config-check/process-jwt-keys.js similarity index 100% rename from packages/koa/cjs-src/lib/config-check/process-jwt-keys.js rename to packages/koa/previous/cjs-src/lib/config-check/process-jwt-keys.js diff --git a/packages/koa/cjs-src/lib/contract-generator/contract-generator.js b/packages/koa/previous/cjs-src/lib/contract-generator/contract-generator.js similarity index 100% rename from packages/koa/cjs-src/lib/contract-generator/contract-generator.js rename to packages/koa/previous/cjs-src/lib/contract-generator/contract-generator.js diff --git a/packages/koa/cjs-src/lib/contract-generator/index.js b/packages/koa/previous/cjs-src/lib/contract-generator/index.js similarity index 100% rename from packages/koa/cjs-src/lib/contract-generator/index.js rename to packages/koa/previous/cjs-src/lib/contract-generator/index.js diff --git a/packages/koa/cjs-src/lib/contract-generator/process-contract.js b/packages/koa/previous/cjs-src/lib/contract-generator/process-contract.js similarity index 100% rename from packages/koa/cjs-src/lib/contract-generator/process-contract.js rename to packages/koa/previous/cjs-src/lib/contract-generator/process-contract.js diff --git a/packages/koa/cjs-src/lib/contract-generator/run.js b/packages/koa/previous/cjs-src/lib/contract-generator/run.js similarity index 100% rename from packages/koa/cjs-src/lib/contract-generator/run.js rename to packages/koa/previous/cjs-src/lib/contract-generator/run.js diff --git a/packages/koa/cjs-src/lib/index.js b/packages/koa/previous/cjs-src/lib/index.js similarity index 100% rename from packages/koa/cjs-src/lib/index.js rename to packages/koa/previous/cjs-src/lib/index.js diff --git a/packages/koa/cjs-src/lib/utils.js b/packages/koa/previous/cjs-src/lib/utils.js similarity index 100% rename from packages/koa/cjs-src/lib/utils.js rename to packages/koa/previous/cjs-src/lib/utils.js diff --git a/packages/koa/cjs-src/public-method-middleware.js b/packages/koa/previous/cjs-src/public-method-middleware.js similarity index 100% rename from packages/koa/cjs-src/public-method-middleware.js rename to packages/koa/previous/cjs-src/public-method-middleware.js diff --git a/packages/koa/cjs-tests/auth.test.js b/packages/koa/previous/cjs-tests/auth.test.js similarity index 100% rename from packages/koa/cjs-tests/auth.test.js rename to packages/koa/previous/cjs-tests/auth.test.js diff --git a/packages/koa/cjs-tests/chain-fn.test.js b/packages/koa/previous/cjs-tests/chain-fn.test.js similarity index 100% rename from packages/koa/cjs-tests/chain-fn.test.js rename to packages/koa/previous/cjs-tests/chain-fn.test.js diff --git a/packages/koa/cjs-tests/config.test.js b/packages/koa/previous/cjs-tests/config.test.js similarity index 100% rename from packages/koa/cjs-tests/config.test.js rename to packages/koa/previous/cjs-tests/config.test.js diff --git a/packages/koa/cjs-tests/contract.test.js b/packages/koa/previous/cjs-tests/contract.test.js similarity index 100% rename from packages/koa/cjs-tests/contract.test.js rename to packages/koa/previous/cjs-tests/contract.test.js diff --git a/packages/koa/cjs-tests/contractWithAuth.test.js b/packages/koa/previous/cjs-tests/contractWithAuth.test.js similarity index 100% rename from packages/koa/cjs-tests/contractWithAuth.test.js rename to packages/koa/previous/cjs-tests/contractWithAuth.test.js diff --git a/packages/koa/cjs-tests/es6-module.test.js b/packages/koa/previous/cjs-tests/es6-module.test.js similarity index 100% rename from packages/koa/cjs-tests/es6-module.test.js rename to packages/koa/previous/cjs-tests/es6-module.test.js diff --git a/packages/koa/cjs-tests/fail.test.js b/packages/koa/previous/cjs-tests/fail.test.js similarity index 100% rename from packages/koa/cjs-tests/fail.test.js rename to packages/koa/previous/cjs-tests/fail.test.js diff --git a/packages/koa/cjs-tests/fixtures/es/mutation/save-something.js b/packages/koa/previous/cjs-tests/fixtures/es/mutation/save-something.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/es/mutation/save-something.js rename to packages/koa/previous/cjs-tests/fixtures/es/mutation/save-something.js diff --git a/packages/koa/cjs-tests/fixtures/es/query/get-something.js b/packages/koa/previous/cjs-tests/fixtures/es/query/get-something.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/es/query/get-something.js rename to packages/koa/previous/cjs-tests/fixtures/es/query/get-something.js diff --git a/packages/koa/cjs-tests/fixtures/html/index.html b/packages/koa/previous/cjs-tests/fixtures/html/index.html similarity index 100% rename from packages/koa/cjs-tests/fixtures/html/index.html rename to packages/koa/previous/cjs-tests/fixtures/html/index.html diff --git a/packages/koa/cjs-tests/fixtures/keys/privateKey.pem b/packages/koa/previous/cjs-tests/fixtures/keys/privateKey.pem similarity index 100% rename from packages/koa/cjs-tests/fixtures/keys/privateKey.pem rename to packages/koa/previous/cjs-tests/fixtures/keys/privateKey.pem diff --git a/packages/koa/cjs-tests/fixtures/keys/publicKey.pem b/packages/koa/previous/cjs-tests/fixtures/keys/publicKey.pem similarity index 100% rename from packages/koa/cjs-tests/fixtures/keys/publicKey.pem rename to packages/koa/previous/cjs-tests/fixtures/keys/publicKey.pem diff --git a/packages/koa/cjs-tests/fixtures/options.js b/packages/koa/previous/cjs-tests/fixtures/options.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/options.js rename to packages/koa/previous/cjs-tests/fixtures/options.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/custom-login.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/auth/custom-login.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/auth/custom-login.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/auth/custom-login.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/custom-validator.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/auth/custom-validator.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/auth/custom-validator.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/auth/custom-validator.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/login.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/auth/login.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/auth/login.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/auth/login.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/logout.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/auth/logout.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/auth/logout.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/auth/logout.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/auth/validator.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/auth/validator.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/auth/validator.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/auth/validator.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/mutation/update-list.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/mutation/update-list.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/mutation/update-list.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/mutation/update-list.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/mutation/update-ms-service.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/mutation/update-ms-service.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/mutation/update-ms-service.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/mutation/update-ms-service.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/cause-error.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/query/cause-error.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/query/cause-error.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/query/cause-error.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/get-user.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/query/get-user.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/query/get-user.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/query/get-user.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/query/private/get-secret-msg.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/public/always-available.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/query/public/always-available.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/query/public/always-available.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/query/public/always-available.js diff --git a/packages/koa/cjs-tests/fixtures/resolvers/query/test-list.js b/packages/koa/previous/cjs-tests/fixtures/resolvers/query/test-list.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/resolvers/query/test-list.js rename to packages/koa/previous/cjs-tests/fixtures/resolvers/query/test-list.js diff --git a/packages/koa/cjs-tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js b/packages/koa/previous/cjs-tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js rename to packages/koa/previous/cjs-tests/fixtures/sub/resolver/mutation/sub-update-ms-service.js diff --git a/packages/koa/cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js b/packages/koa/previous/cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js similarity index 100% rename from packages/koa/cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js rename to packages/koa/previous/cjs-tests/fixtures/sub/resolver/query/sub-ms-service.js diff --git a/packages/koa/cjs-tests/helpers/browser.js b/packages/koa/previous/cjs-tests/helpers/browser.js similarity index 100% rename from packages/koa/cjs-tests/helpers/browser.js rename to packages/koa/previous/cjs-tests/helpers/browser.js diff --git a/packages/koa/cjs-tests/helpers/hello.js b/packages/koa/previous/cjs-tests/helpers/hello.js similarity index 100% rename from packages/koa/cjs-tests/helpers/hello.js rename to packages/koa/previous/cjs-tests/helpers/hello.js diff --git a/packages/koa/cjs-tests/helpers/server.js b/packages/koa/previous/cjs-tests/helpers/server.js similarity index 100% rename from packages/koa/cjs-tests/helpers/server.js rename to packages/koa/previous/cjs-tests/helpers/server.js diff --git a/packages/koa/cjs-tests/helpers/sub-server.js b/packages/koa/previous/cjs-tests/helpers/sub-server.js similarity index 100% rename from packages/koa/cjs-tests/helpers/sub-server.js rename to packages/koa/previous/cjs-tests/helpers/sub-server.js diff --git a/packages/koa/cjs-tests/jsonp.test.js b/packages/koa/previous/cjs-tests/jsonp.test.js similarity index 100% rename from packages/koa/cjs-tests/jsonp.test.js rename to packages/koa/previous/cjs-tests/jsonp.test.js diff --git a/packages/koa/cjs-tests/jwt-auth.test.js b/packages/koa/previous/cjs-tests/jwt-auth.test.js similarity index 100% rename from packages/koa/cjs-tests/jwt-auth.test.js rename to packages/koa/previous/cjs-tests/jwt-auth.test.js diff --git a/packages/koa/cjs-tests/jwt.test.js b/packages/koa/previous/cjs-tests/jwt.test.js similarity index 100% rename from packages/koa/cjs-tests/jwt.test.js rename to packages/koa/previous/cjs-tests/jwt.test.js diff --git a/packages/koa/cjs-tests/koa.test.js b/packages/koa/previous/cjs-tests/koa.test.js similarity index 100% rename from packages/koa/cjs-tests/koa.test.js rename to packages/koa/previous/cjs-tests/koa.test.js diff --git a/packages/koa/cjs-tests/node-client.donttest.js b/packages/koa/previous/cjs-tests/node-client.donttest.js similarity index 100% rename from packages/koa/cjs-tests/node-client.donttest.js rename to packages/koa/previous/cjs-tests/node-client.donttest.js diff --git a/packages/koa/cjs-tests/resolverNotFound.test.js b/packages/koa/previous/cjs-tests/resolverNotFound.test.js similarity index 100% rename from packages/koa/cjs-tests/resolverNotFound.test.js rename to packages/koa/previous/cjs-tests/resolverNotFound.test.js diff --git a/packages/koa/cjs-tests/throw.test.js b/packages/koa/previous/cjs-tests/throw.test.js similarity index 100% rename from packages/koa/cjs-tests/throw.test.js rename to packages/koa/previous/cjs-tests/throw.test.js -- Gitee From 2e5d38d08308506ec8af7a5c942b968aaf0f3fd6 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 16:10:21 +0800 Subject: [PATCH 09/12] capture the log for now and fix it later --- packages/koa/tests/fixtures/log/jsoc.txt | 11 +++++++++++ .../koa/tests/fixtures/resolvers/query/test-list.js | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 packages/koa/tests/fixtures/log/jsoc.txt diff --git a/packages/koa/tests/fixtures/log/jsoc.txt b/packages/koa/tests/fixtures/log/jsoc.txt new file mode 100644 index 00000000..3bdace15 --- /dev/null +++ b/packages/koa/tests/fixtures/log/jsoc.txt @@ -0,0 +1,11 @@ +Error: Could not parse the jsdoc for updateMsService! + at clearForOutput (/home/joel/projects/open-source/jsonql/packages/koa/node_modules/jsonql-contract/src/ast/jsdoc.js:203:13) + at getJsdoc (/home/joel/projects/open-source/jsonql/packages/koa/node_modules/jsonql-contract/src/ast/jsdoc.js:219:10) + at extractExtraProps (/home/joel/projects/open-source/jsonql/packages/koa/node_modules/jsonql-contract/src/generator/helpers.js:156:10) + at files.map.filter.map.obj (/home/joel/projects/open-source/jsonql/packages/koa/node_modules/jsonql-contract/src/generator/files.js:75:48) + at Array.map () + at processFiles (/home/joel/projects/open-source/jsonql/packages/koa/node_modules/jsonql-contract/src/generator/files.js:63:6) + at glob (/home/joel/projects/open-source/jsonql/packages/koa/node_modules/jsonql-contract/src/generator/files.js:113:9) + at f (/home/joel/projects/open-source/jsonql/packages/koa/node_modules/once/once.js:25:25) + at Glob. (/home/joel/projects/open-source/jsonql/packages/koa/node_modules/glob/glob.js:151:7) + at Glob.emit (events.js:198:13) diff --git a/packages/koa/tests/fixtures/resolvers/query/test-list.js b/packages/koa/tests/fixtures/resolvers/query/test-list.js index b063eee6..c1359fc2 100644 --- a/packages/koa/tests/fixtures/resolvers/query/test-list.js +++ b/packages/koa/tests/fixtures/resolvers/query/test-list.js @@ -9,5 +9,5 @@ module.exports = function testList(num) { modified: Date.now(), text: testList.userdata && testList.userdata.dummy ? testList.userdata.dummy : 'nope', num: num ? --num : -1 - }; -}; + } +} -- Gitee From 7b714a324c3a1c8b03802cdb4db798ac46e8d58a Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 22:44:32 +0800 Subject: [PATCH 10/12] move the jsonql-koa test resolvers for debugging --- .../koa-resolvers/auth/custom-login.js | 13 +++++++++++++ .../koa-resolvers/auth/custom-validator.js | 13 +++++++++++++ .../tests/fixtures/koa-resolvers/auth/login.js | 18 ++++++++++++++++++ .../fixtures/koa-resolvers/auth/logout.js | 8 ++++++++ .../fixtures/koa-resolvers/auth/validator.js | 14 ++++++++++++++ .../koa-resolvers/mutation/update-list.js | 12 ++++++++++++ .../mutation/update-ms-service.js | 13 +++++++++++++ .../koa-resolvers/query/cause-error.js | 10 ++++++++++ .../fixtures/koa-resolvers/query/get-user.js | 12 ++++++++++++ .../query/private/get-secret-msg.js | 9 +++++++++ .../query/public/always-available.js | 7 +++++++ .../fixtures/koa-resolvers/query/test-list.js | 13 +++++++++++++ 12 files changed, 142 insertions(+) create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/auth/custom-login.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/auth/custom-validator.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/auth/login.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/auth/logout.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/auth/validator.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/mutation/update-list.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/mutation/update-ms-service.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/query/cause-error.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/query/get-user.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/query/private/get-secret-msg.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/query/public/always-available.js create mode 100644 packages/contract-cli/tests/fixtures/koa-resolvers/query/test-list.js diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/auth/custom-login.js b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/custom-login.js new file mode 100644 index 00000000..ca19bb40 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/custom-login.js @@ -0,0 +1,13 @@ + +/** + * This is a custom login method instead of the stock version + * @param {string} username username + * @param {string} password password + * @return {object} userdata payload + */ +module.exports = function customLogin(username, password) { + if (password === '123456') { + return {name: username} + } + throw new Error('Login failed!') +} diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/auth/custom-validator.js b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/custom-validator.js new file mode 100644 index 00000000..08d617a8 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/custom-validator.js @@ -0,0 +1,13 @@ +// this will use for testing the chaining validator methods +const debug = require('debug')('jsonql-koa:custom-validator') +const { dummy } = require('../../options') + +/** + * @param {*} userdata pass by the jsonql-jwt method + * @return {*} just pass it back + */ +module.exports = function(userdata) { + debug('I am being call by the chain') + userdata.dummy = dummy; + return userdata; +} diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/auth/login.js b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/login.js new file mode 100644 index 00000000..5f8d1e79 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/login.js @@ -0,0 +1,18 @@ +const debug = require('debug')('jsonql:koa:issuer'); +const { bearer } = require('../../options'); + +// this is the stock method for giving out author header + +/** + * Auth method + * @param {string} username user name + * @param {string} password password + * @return {string|boolean} token on success, false on fail + */ +module.exports = function(username, password) { + debug('received this', username, password); + if (username === 'nobody' && password) { + return bearer; + } + return false; +} diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/auth/logout.js b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/logout.js new file mode 100644 index 00000000..d9b2af68 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/logout.js @@ -0,0 +1,8 @@ +// complete the 3 pieces + +/** + * @return {boolean} just return something + */ +module.exports = function() { + return true; +}; diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/auth/validator.js b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/validator.js new file mode 100644 index 00000000..b588aa81 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/auth/validator.js @@ -0,0 +1,14 @@ +const debug = require('debug')('jsonql:koa:validator'); +const { bearer } = require('../../options'); +// this is the core method for checking the Auth header +/** + * @param {string} token jwt + * @return {object|boolean} user data on success, false on fail + */ +module.exports = function(token) { + debug('received this token', token, bearer); + if (token === bearer) { + return {userId: 1}; + } + return false; +} diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/mutation/update-list.js b/packages/contract-cli/tests/fixtures/koa-resolvers/mutation/update-list.js new file mode 100644 index 00000000..bac22581 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/mutation/update-list.js @@ -0,0 +1,12 @@ +const debug = require('debug')('jsonql-koa:resolver:mutation:updateList'); +/** + * @param {object} payload + * @param {number} payload.user + * @param {object} condition + * @return {object} with user as key + */ +module.exports = function(payload, condition) { + debug('calling updateList with', payload, condition); + let p = payload.user + 1; + return {user: p}; +}; diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/mutation/update-ms-service.js b/packages/contract-cli/tests/fixtures/koa-resolvers/mutation/update-ms-service.js new file mode 100644 index 00000000..62b17524 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/mutation/update-ms-service.js @@ -0,0 +1,13 @@ +const debug = require('debug')('jsonql-koa:mutation:update-ms-service') +/** + * this will be calling a microserivce setup using the nodeClient + * @param {string} payload incoming + * @return {string} msg return from nodeClient + */ +module.exports = async function updateMsService(payload) { + const client = await updateMsService.client() + + debug(client) + + return client.query.subMsService(payload) +} diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/query/cause-error.js b/packages/contract-cli/tests/fixtures/koa-resolvers/query/cause-error.js new file mode 100644 index 00000000..0a5eb534 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/query/cause-error.js @@ -0,0 +1,10 @@ + +// this method will cause an error to throw +/** + * @param {*} x param + * @return {*} unknown + */ +module.exports = function(x) { + // none of the variable exists certainly will cause an error + return x ? y : z; +} diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/query/get-user.js b/packages/contract-cli/tests/fixtures/koa-resolvers/query/get-user.js new file mode 100644 index 00000000..49b836f2 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/query/get-user.js @@ -0,0 +1,12 @@ +// This is a new query method to test out if we actually get the userData props at the end of call +/** + * This use a spread as parameter + * @param {...string} args passing unknown number of param + * @return {any} extract from last of the args + */ +module.exports = function getUser(...args) { + const ctn = args.length; + const lastProp = args[ctn - 1]; + // also test with the assigned property + return getUser.userdata || {userId: 'dummy bear'}; +} diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/query/private/get-secret-msg.js b/packages/contract-cli/tests/fixtures/koa-resolvers/query/private/get-secret-msg.js new file mode 100644 index 00000000..b655360d --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/query/private/get-secret-msg.js @@ -0,0 +1,9 @@ +// this resolver will not be include if the privateMethodDir is not set + +/** + * a hidden private method + * @return {string} a secret message + */ +module.exports = function getSecretMsg() { + return 'Let me tell ya a secret ...'; +} diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/query/public/always-available.js b/packages/contract-cli/tests/fixtures/koa-resolvers/query/public/always-available.js new file mode 100644 index 00000000..0a086798 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/query/public/always-available.js @@ -0,0 +1,7 @@ +/** + * This is a public method that is always available + * @return {string} a message + */ +module.exports = function() { + return 'Hello there'; +}; diff --git a/packages/contract-cli/tests/fixtures/koa-resolvers/query/test-list.js b/packages/contract-cli/tests/fixtures/koa-resolvers/query/test-list.js new file mode 100644 index 00000000..c1359fc2 --- /dev/null +++ b/packages/contract-cli/tests/fixtures/koa-resolvers/query/test-list.js @@ -0,0 +1,13 @@ +const debug = require('debug')('jsonql-koa:resolver:query:testList'); +/** + * @param {number} num a number + * @return {object} @TODO need to figure out how to give keys to the returns + */ +module.exports = function testList(num) { + debug('Call testList with this params', num); + return { + modified: Date.now(), + text: testList.userdata && testList.userdata.dummy ? testList.userdata.dummy : 'nope', + num: num ? --num : -1 + } +} -- Gitee From c1d7ed9db0c884852ff7bff3df06c60791c926a1 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 22:51:21 +0800 Subject: [PATCH 11/12] add the koa debug and passed so the problem is not within the contract-cli --- packages/contract-cli/package.json | 3 ++- packages/contract-cli/tests/koa-debug.test.js | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 packages/contract-cli/tests/koa-debug.test.js diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index 746df99a..495f9600 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -22,7 +22,8 @@ "test:cmd": "DEBUG=jsonql-contract:* ava tests/cmd.test.js", "test:watch": "DEBUG=jsonql-contract:* ava tests/watch.test.js", "test:config": "DEBUG=jsonql-contract:* ava tests/config-params.test.js", - "test:custom": "DEBUG=jsonql-contract:* ava tests/custom-login.test.js" + "test:custom": "DEBUG=jsonql-contract:* ava tests/custom-login.test.js", + "test:debug": "DEBUG=jsonql-contract:* ava tests/koa-debug.test.js" }, "keywords": [ "jsonql", diff --git a/packages/contract-cli/tests/koa-debug.test.js b/packages/contract-cli/tests/koa-debug.test.js new file mode 100644 index 00000000..1d7db19e --- /dev/null +++ b/packages/contract-cli/tests/koa-debug.test.js @@ -0,0 +1,26 @@ +// this resolvers cause an error with the updateMsService resolver when call from within jsonql-koa +const test = require('ava') +const { join } = require('path') +const fsx = require('fs-extra') +const debug = require('debug')('jsonql-contract:koa-debugging') + +const generator = require('../index') + +const resolverDir = join(__dirname, 'fixtures', 'koa-resolvers') +const contractDir = join(__dirname, 'tmp', 'koa-debug') + +test.after(t => { + fsx.removeSync(contractDir) +}) + +test(`It should able to generate a contract without error`, async t => { + const result = await generator({ + resolverDir, + contractDir, + returnAs: 'json' + }) + + debug(result) + + t.truthy(result.query) +}) -- Gitee From a3c924173b726ae6032f7e9ab67f9d163c128ad7 Mon Sep 17 00:00:00 2001 From: joelchu Date: Sat, 21 Sep 2019 23:38:21 +0800 Subject: [PATCH 12/12] Add a debug before the jst parser throw error to take a look what is happening inside --- packages/contract-cli/package.json | 2 +- packages/contract-cli/src/ast/jsdoc.js | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/contract-cli/package.json b/packages/contract-cli/package.json index 495f9600..9e7a8035 100755 --- a/packages/contract-cli/package.json +++ b/packages/contract-cli/package.json @@ -1,6 +1,6 @@ { "name": "jsonql-contract", - "version": "1.7.9", + "version": "1.7.10", "description": "JS API / command line tool to generate the contract.json for jsonql", "main": "index.js", "files": [ diff --git a/packages/contract-cli/src/ast/jsdoc.js b/packages/contract-cli/src/ast/jsdoc.js index 7f0f4740..1c963afd 100644 --- a/packages/contract-cli/src/ast/jsdoc.js +++ b/packages/contract-cli/src/ast/jsdoc.js @@ -24,7 +24,7 @@ const { const OBJECT_TYPE = 'object'; const LFT = 'array.<'; const RHT = '>'; - +const debug = require('debug')('jsonql-contract:jsdoc') /** * normalize the type to the one we support therefore mini the risk of error * @param {string} type from jsdoc @@ -198,8 +198,9 @@ const searchForParams = function(output) { */ const clearForOutput = function(result, name) { if (Array.isArray(result)) { - const res = searchForParams(result); + const res = searchForParams(result) if (!res.params) { + debug(res) throw new Error(`Could not parse the jsdoc for ${name}!`) } return res; -- Gitee