{"_id":"@hal-wang/cloudbase-access","_rev":"123-4c9eecda50e129bf6fa3f9398c9106ef","name":"@hal-wang/cloudbase-access","dist-tags":{"latest":"2.0.4","beta":"2.0.0-beta.11"},"versions":{"0.7.0":{"name":"@hal-wang/cloudbase-access","version":"0.7.0","description":"利用 NodeJS 和 CloudBase 快速创建 MVC 架构的 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["mvc","hal-wang","cloudbase","cloudbase-access"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"tsc","deploy":"tsc && npm publish --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@types/node":"^14.14.10","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.15","@types/node":"^14.14.6","@typescript-eslint/eslint-plugin":"^4.8.2","@typescript-eslint/parser":"^4.8.2","eslint":"^7.14.0","eslint-config-prettier":"^6.15.0","eslint-plugin-prettier":"^3.1.4","jest":"^26.6.3","prettier":"^2.2.0","ts-jest":"^26.4.4","typescript":"^4.1.2"},"gitHead":"ca01db7b873ab0344533aa91dd187339c7481f3c","_id":"@hal-wang/cloudbase-access@0.7.0","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-kpcb8j9//HzauVqPmpKucATMazej7A6wAjGuJxdWvfdykNwNrrTH+ZsZbOesggfJeLw5IYWahe98fq1Q8u81cg==","shasum":"95502d3f39ba843a0f2c82823b4a609ec9d71075","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.7.0.tgz","fileCount":16,"unpackedSize":22723,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0d1OCRA9TVsSAnZWagAA6b0P/jQ1uVi9jaMRgZ7UVpwQ\nTjG+qo0sT8K8KMVscScoRUDauj7b4DnBFv1cIlp48zoXVYV7fct2hMRNbLR2\nmlI2nVue8oZbIVBFntWfFN5bEUXsucyrV4PElZN/YZGuvx7XwmJF9Yur3NtA\nPu+DlaWRV7fWaSm2SwmnR5cwMA9OSc0V/dPrm0eHdT3EkMN8OVLf9VP1P8wV\nWlwJ5OPU7OOZHz6LY9Rn+8gy4bWCTjJ3jjv7RJ/NA1xSWKiLmS03mSnnoaGf\nT/oThoRVOT6nrmjByx+YacUf/YhhjRoZkFUVe14cOmmZyV7xMWcwfJ2JpO4/\n7X63y084NJ1wO/yWrZ8yJkn8/2IAlrjAq7clLTiuGUBfqwiPGzlX+u7Uy+0Q\ndhIQJJ3zAbAUOhLsoRz/q0oU300HTP1jQfF9qKNUaF++Fm49WFFHdvUhzAbJ\nEd3IAY4X2yaEA8+kFqbErBZ1EzRdT3tE79bCtS+sOJJ8oxpPjIi2IhFzqKiW\nDE8bZByP3vS5wBxtPYw1UcXht6ofxnNvhaE7u6Tg+hWrnGpTkduN6B/WP/qN\nHLG3zR3oxswdg/FhfnHOCVQD4yaf2xx0lCR0oz/60roRREbteD3X6ORf7B4Q\n1cnFT9YmuoJedOeMZtoBOIhK9WcJAuc+ceoA1fVTQ+zkTrAqefdiH+mvcalE\nGDG4\r\n=N+Rf\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIBRRCTzfrZoebmoRwL5Ah5BjfRP7ng3SFhrQZfP63Iw4AiEA0W/d0ZoK2cMOI9GCaWz+wJZRpkWLtuh2ko2iC8ervZE="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.7.0_1607589198137_0.6136361718291583"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"0.7.1":{"name":"@hal-wang/cloudbase-access","version":"0.7.1","description":"利用 NodeJS 和 CloudBase 快速创建 MVC 架构的 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["mvc","hal-wang","cloudbase","cloudbase-access"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"tsc","deploy":"tsc && npm publish --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@types/node":"^14.14.10","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.16","@types/node":"^14.14.10","@typescript-eslint/eslint-plugin":"^4.9.0","@typescript-eslint/parser":"^4.9.0","eslint":"^7.14.0","eslint-config-prettier":"^6.15.0","eslint-plugin-prettier":"^3.2.0","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.4.4","typescript":"^4.1.2"},"gitHead":"5f50691e08d7f40505317456820d0339620e3efc","_id":"@hal-wang/cloudbase-access@0.7.1","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-7dXK9zZkc0jGvP9u03BT0N83DUxiCK1CnfJiqlL9rBk+llAcinXMnzxysF0SlKZwTwO+gqRM1W06G0+xlK+CDA==","shasum":"06542464742654b1cee3f69c98f4801280d2d3c3","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.7.1.tgz","fileCount":16,"unpackedSize":22585,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf0eCRCRA9TVsSAnZWagAArTkP/2VMbvpkLMVcU/nySH63\n0konNC4uR+UGVmpJndJHhg0fvkGWFUwz2TEX/ax25FHeAbtpzkSb4g3wDtKP\nzn38vXR3E7nUqoDGSm80PqqrIkapV6ylRWVjZNweZLkSvFbDS97ss7eCq8hE\nHwd60x2JHdQkOlvh1jO4knioBOsBjY3R+za/1svd0dYAr7NR508fE6lNazHA\nvPVa7f5GAZDNFwhzfLwLGkiowf7rq/DGcHdzPWTdLxFwhtif25GRiNBZ82hG\njJJ0klU/Ij3HbbDK8qadm9H4NIuW4t8rIMy09DD174rBPSmXkD2jBgqBHWno\ndnj/k3nsF5WXCdeZADHPq4rSvGpO09ir9I8O9eljrP1AUW0YDeUugAvo+rsY\nKJU6c772Q8HeuuOFpZIz87sR/esjQ+Ro7hB1NuSy6CRYA9DF594vEtZgYIbo\nql72bJ4I4T9KWZfRA9ri8ZerV/b2PT5BohtAaj0HJtDaTgHEi8uDCxT5RpwD\nJAwIWm55RDSyt7GOavOfgTDfEHRL/uTYyQiGo+cq/4D3oSGwSNRUcqsbIRoc\na3+sU1LSqAasygvO6sfzwk4JxsKT9YIIJJmI1Tn2B81V5aTaGerEDNBQT+NH\nOGiJdSI9JZxuY3S4g1QhR3U2GMYQbRIi7Po7NIt30yeL/55HI3x1/b9KYAk7\neqCE\r\n=BoHq\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDW5cBHHml/rW0LKtXYd6Ll3Y9QIY+kRX4J+kWbGhEvigIgJDVeRlywgEGdBtBclpo2LEYozofJOBGWIwOdWpB4tio="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.7.1_1607590032818_0.26450448452721464"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"0.7.2":{"name":"@hal-wang/cloudbase-access","version":"0.7.2","description":"利用 NodeJS 和 CloudBase 快速创建 MVC 架构的 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["mvc","hal-wang","cloudbase","cloudbase-access"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"tsc","deploy":"tsc && npm publish --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.4.7","@types/node":"^14.14.14","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.19","@types/node":"^14.14.14","@typescript-eslint/eslint-plugin":"^4.10.0","@typescript-eslint/parser":"^4.10.0","eslint":"^7.16.0","eslint-config-prettier":"^7.1.0","eslint-plugin-prettier":"^3.3.0","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.4.4","typescript":"^4.1.3"},"gitHead":"1f596ad308f71b4d5753751f06f0e123275e7371","_id":"@hal-wang/cloudbase-access@0.7.2","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-Ut408IHz84sxra4F5UdXpsHP9YpOw1qsh1PgmCll++re5phQ4xSveNbc6NjUZ3q342e71zmYRnCoF1ZYhuf00g==","shasum":"09003a44243e35688359c88f4b9e07fddd84eefd","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.7.2.tgz","fileCount":20,"unpackedSize":26968,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf4BG9CRA9TVsSAnZWagAAzw4P/j+HQZNUEo07v7gj9VtF\nDVJVLidonU0L2kmswkoHjEvA+NgD2HwwnnzDk0t5q8EoP8IwuBNkZBtLdJ2C\nZqnFwu353xszuCjEuZVZahN7Me+ENNkWPoz9TBAFnLEc8Xenm50c5vACnxUJ\nbHuDMP8jNNFEMefbdkk7gswbKuW9Fl0Awm0kznWFYknnmtVtNy/VLi9H0QyA\naDqbHLL4zUSi0jwsHRwkgmNkSrA3z3h9HaODY9zkpRztkVwu4NYChCw/DTZH\n0PnakUaSW+vrNqyQty2CSY3LIF8QVQZO5aOeJuY8e4uqZmrxs737kkLDuIjF\nOZYN5qMPIFqGVBKlhToqRTQSnGJhHa/WsrpirWyo44FCIvLj4ZdJLix/aECe\n6ArELu7XWvG8YD7uxCR0Y0jqm2ZWqvdr9I9ukNtHRCg7YJXCQlgzxZB+ARUx\n9kYZ5FawL8NqEAgdmpk3ePu75OSklW25bQxA3TqQofhrMJN/Mcieq77aB3et\neiDUWeOFeXtvQ+likO9uIYtkIkpySJDlb5hCvdmUJVDAu9fJodldmblDTA1t\nE72ccIegqHJsuhKcUzYUmvEDHOevQbGlErw61yLaEJZUUIhn9KUT1cU/MRyZ\nkN/ksSEVDq279S7RBQRJQYX1Qodfm0oFsYA2qgTfsFg2urnwQ8ZZHdFYsvt4\noNmT\r\n=4R9i\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIC7r6heipdIXDKJgLdSELye8SDA+IpCS82GxonDMzJuWAiEAqoNI8Sd91BzhzR32q0EwjTFGH7L48xvgtfyMC8Q3kIE="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.7.2_1608520124790_0.4613455071653876"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"0.8.1":{"name":"@hal-wang/cloudbase-access","version":"0.8.1","description":"利用 NodeJS 和 CloudBase 快速创建 MVC 架构的 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["mvc","hal-wang","cloudbase","cloudbase-access"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"tsc","deploy":"tsc && npm publish --access=public","deploy:beta":"tsc && npm publish --tag beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.4.7","@types/node":"^14.14.14","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.19","@types/node":"^14.14.14","@typescript-eslint/eslint-plugin":"^4.10.0","@typescript-eslint/parser":"^4.10.0","eslint":"^7.16.0","eslint-config-prettier":"^7.1.0","eslint-plugin-prettier":"^3.3.0","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.4.4","typescript":"^4.1.3"},"gitHead":"c8937a4371b8c82546a3b77e38166f16a80ca3ee","_id":"@hal-wang/cloudbase-access@0.8.1","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-wLhWJ2aHupqATHlifM5LHrZjfQzirHhtJUbphqZmqgUwYGZbNmpzRLbB4yWs+u3lm9kaZyMH9rl+gZbsvTPXWA==","shasum":"2fa9c1fd836cd770aad626fd652f04c21f67255a","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.8.1.tgz","fileCount":72,"unpackedSize":63115,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5YuICRA9TVsSAnZWagAAxyYP/24ecvhEfjA8ITA1hLlu\nmZZH4VV2GBuLKLN2QclJF0a7jWFcCl74Ll+R7TJy1K4yROvvB2EeSNXDgW01\nA+TkxTig5iOlR/b3oHQOs+MVdO1OuZ2Ag556bDoB5/jfJakCWmgWUa5WvedJ\nlGEO3WGBRbSdNEtsznp2dTn7jBpTv2G/kcLMESo5ny3GQjJ6ZFvawb88yOb9\nQbTewpwNRUFxWXjVhSGDik/Y+Et+9GGPADzwr2qFjTVslAAdj8pQ4Cot1TyC\nBxe51Q+POgB4SNgsaasrNFKmJW41bxhFOPE6LnAidFPYB40htDAdU2epTZnm\nw3ZWcDTbn4gaHb9qRdpjHAeXsu7j0OITHwSLIGZduRvignY185JwtOvxqOjj\nv0uUuKfxX/Qgn+fs/wRVt/xhc/oeT19IRRKWWHoXGgOC6Ct6l9pEcnvSZTNZ\n/7jq14I1OtxzB6zYcoXqKOhIAld+JttLepbhYit0AWYEbVWYC/iVAHtSkbk3\nC5kmAAR7IlWPD+F33ms75OvOD0fbEqQT8ju6lfDc2ntobvCecAGI9CMsVTBK\n7SvjyJhVeXKH9cpgDJl9sHb+ISVBx2MH4UNbrSDlTVwUch9r9o9oi1y7aFhM\nB2wq2K+akeu9pmr62A2JPsPLJ3WMnrtSg+6envTl19gxG6r+QdBnxf9cd+KF\n+kI8\r\n=6yBa\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGljM91NsMwukXCyRk8IvG3LvRevEi4HLOo5OCvRFq3NAiBZm9yQb1HM/7OP6CqIhyHZgozDnIQuazp4/izg9LEcww=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.8.1_1608878983508_0.046173010722309504"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"0.8.2":{"name":"@hal-wang/cloudbase-access","version":"0.8.2","description":"利用 NodeJS 和 CloudBase 快速创建 MVC 架构的 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["mvc","hal-wang","cloudbase","cloudbase-access"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"tsc","deploy":"tsc && npm publish --access=public","deploy:beta":"tsc && npm publish --tag beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.4.7","@types/node":"^14.14.14","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.19","@types/node":"^14.14.14","@typescript-eslint/eslint-plugin":"^4.10.0","@typescript-eslint/parser":"^4.10.0","eslint":"^7.16.0","eslint-config-prettier":"^7.1.0","eslint-plugin-prettier":"^3.3.0","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.4.4","typescript":"^4.1.3"},"gitHead":"d885f850f2656ac29e9b8b5b5f1acb251785ced3","_id":"@hal-wang/cloudbase-access@0.8.2","_nodeVersion":"14.15.0","_npmVersion":"6.14.8","dist":{"integrity":"sha512-31moBIk3B3kGjOkXWeos4CW0Grc+H31136ys3MbD5QFKS0t8ZPKrOWvTn3rhiO/C89iUT6NnIO/BJ0MNWCJMOw==","shasum":"7c0f9ee708cd5311c69e1d00503034bba431c693","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.8.2.tgz","fileCount":24,"unpackedSize":29084,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJf5aVUCRA9TVsSAnZWagAANkgP/RJDvfi+fDreSi04UdgY\nugbDuWjYRs9RAwhTFzBCcaPebqVwCtQWey8FNnfmkEHx+snMpEOwKzGr/0Dg\nQDgiyQPWRAHo2/LGPehNqb+4kiPI1Ad0bDwhCDC/KO1Kl4O+zIT2sq+IZIWK\nJo9KPFoVQD8FBf18HW2golit/oC8FU2/+YKqkHUBdZaADjPDMwBnUNh5OXnk\n4NCrdfbIBR4c8i+5x5o1yd79ahHaNCddiwLznrtyHvU0Xwas5viw13IxxiaP\n78kViG3Xb/Az5Y8XGmS/GBH5jmuxMWWYY/PRMe5jfhRggtfKb6SRSoHqfdZ1\npOs3R4R7d0Np+r2Ex+0RYMMNdm9T7RBnSOTJVF2RT7J6UUWjXcFNkKSjGnNU\n/r5fa/wi3zsXHf/9/FzVQaZFZG5KclWtPGWKGVRNQsDPLdiajP1UluQv6ARO\nMwHWjq8xsGJ0Qm3vji8n+gaglyWBXqX6dqjq5lHBLvvpPKIfxJq/sZMknXHa\neM7LKlo50xpmil9r8uVic4jCKe4c1Gi7kJUQFp3HbEDBH42zoQEioKuz8bG+\nJcEMnHqiLP5hAzB6LwwvcDZcRtPJh4U8558T1zUVhEkstcV0gr9h+8PyUhHh\nMhZUcl2K5z0CRApdtQp0bx7ZuTb6TZILGiGfTaNrh70Gd3OH/Hpb6b7qoe/K\nOLHf\r\n=Fspz\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIFaEk+BLxwxBrBlL1ufDQsbTRE7d1Fr5rGfIZTnxKgY2AiEAgX8FQyOt28MPlOcAWhzr3I8TyQi3lJECQbsjIsZyQfg="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.8.2_1608885588024_0.7080136695520749"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"0.8.3":{"name":"@hal-wang/cloudbase-access","version":"0.8.3","description":"利用 NodeJS 和 CloudBase 快速创建 MVC 架构的 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"tsc","deploy":"tsc && npm publish --access=public","deploy:beta":"tsc && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.22","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.22","@typescript-eslint/eslint-plugin":"^4.14.0","@typescript-eslint/parser":"^4.14.0","eslint":"^7.18.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.4.4","typescript":"^4.1.3"},"gitHead":"87ed029bd47d842f8528a1c3243f5b1b44a69ea1","_id":"@hal-wang/cloudbase-access@0.8.3","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-ebQAbfLhjiT4THDSLc1yAe9+CkN0esi1HdjkIoHIzDmMVqSBM2RRby8nxMJrGS3IGGk4wjGk3jD4GwVWysnLsg==","shasum":"d87e2db7be1ebb0cb137af81d28f54108d40aa7c","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.8.3.tgz","fileCount":26,"unpackedSize":31697,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgCBhKCRA9TVsSAnZWagAAhMwP/jTXORndzZfmBhmCREFP\nkhcX/CStIBhgpGVdnXFDsEliH8PWmTujS4EbKI2cqfw+45/fWPpiGl6Vf8bs\nd2T9EyCp7BE+Vx7dIfh5YoIARm4R1jWg2o30jx41fZgRxxFXo9NVxm7TNVnj\nfb45czf+FkKHc3aQWbJ0kbHHu+dm+ZSbnJ+hgFjV8HhHVfYn/wIlLXc3GGe+\nOtrilyaXQ15u89/ILzY63PnTTEPxZyVOnvNRD7EgSxCKSkXLR6E72kCF8ivK\nJREoIeWk61AEXUP4LcNer11yE4Ov5n6teTURpMO2ejaM6A+mG3pDLyPkWzEv\nv+3mUdshUtE/dYs7nHOjKeqFaPF65WcP99xCNQd2X5XZr/YhyZfaRMBftJWK\nTakT2waC3Vqw0Gd6sNfmJuJTwkJNWgGQZR5UymQLr190UYouhoDy+1MnOraE\nLCdO5U40AyVNULimE0TwhmUAgJ+FL1T0cZfEidPBmpGPYG6VYqXdXr9Yi/bi\nvdwBjT2392Lz8zMZdlVlDDBqdMF5XNlKLCh9wtYGjOGF6UuF9JdKfibCmAkH\nGnpjITOPnz0aWxDAlo1vsUStXzc/NN6PFr3xCwtSbOeJT+cjnDWiWOP8Z6sx\nXdkApXga5TUill1HJ578HGBDHEe382+84vea3GYqe12ZmFAXPfxqtRh50eRY\n5gg1\r\n=t2TS\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIGexvblygog9DMwPohslFuWmydVo3c1vk7LuS/vMY22+AiAmPj5QAXJXaOX5X/YD2JcfaYSbtdlNgT5eEkUv9Qhmfg=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.8.3_1611143242220_0.2754875027476915"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"0.9.0-beta.8":{"name":"@hal-wang/cloudbase-access","version":"0.9.0-beta.8","description":"利用 NodeJS 和 CloudBase 快速创建 MVC 架构的 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"tsc","deploy":"tsc && npm publish --access=public","deploy:beta":"tsc && npm publish --tag=beta --access=public","map":"cba-map","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.22","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.22","@typescript-eslint/eslint-plugin":"^4.14.0","@typescript-eslint/parser":"^4.14.0","eslint":"^7.18.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.4.4","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js"},"readme":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n示例请查看后面的 [#Demo](#Demo)\n\n或者查看本项目 `test` 文件夹中的一些单元测试。\n\n## Router\n\n路由管理类，也是 `cloudbase-access` 的控制中心。构造函数传入环境 `event` 和 `context`。\n\n如在 `main` 函数中：\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n) => {\n  const router = new Router(event, context);\n  return (await router.do()).result;\n};\n```\n\n以上几行代码即创建一个简单的 RESTful 规范的 API。\n\n如果访问的路径不存在，会返回 404 NotFound 结构。\n\n### 权限参数\n\n`Router` 第三个参数（可选）传入权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### controllers 目录\n\n`Router` 第四个参数（可选）传入 `controllers` 目录名称，默认为 `controllers`。\n\n`controllers` 统一放在一个文件夹中，建议不传此参数，即 `controllers`。\n\n在 `controllers` 目录中，建立各 `controller` 文件夹，再在 `controller` 文件夹中建 `action` 文件。详情后面 [Action](#Action) 部分有介绍。\n\n## HttpResult\n\n`HttpResult` 封装了 HTTP 返回结构。可在构造函数传入相关参数。\n\n`HttpResult` 有个属性 `result` ，可获取最终 HTTP 返回结构。\n\n### 内置类型\n\n目前 `HttpResult` 内置一些返回类型，都是以静态方式调用：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nreturn HttpResult.ok(\"success\");\n```\n\n普通内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n### 举例\n\n以下例子中返回 200 请求成功：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.ok({\n  list: [],\n  count: 0,\n});\n```\n\n以下例子中返回 400 请求错误：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.badRequestMsg({ message: \"请求错误\" });\n// 或 return HttpResult.badRequestMsg(\"请求错误\");\n```\n\n### 在 Action 中\n\n在 `Action` 中已经加入了 `HttpResult` 内置函数，可以直接以 `this.func` 方式调用\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n    // or return this.ok('success');\n  }\n}\n```\n\n## 请求参数\n\n`RequestParams` 类解析并封装请求参数，构造函数传入云函数 `event`。\n\n实例包含以下字段：\n\n1. event，云函数环境 event\n2. headers, 请求头部\n3. path，访问路径，如`POST https://domain.com/api/user/login`，path 值为`/user/login`\n4. params，查询参数\n5. data，请求 body，如果是 JSON 字符串，则转为 JSON 对象\n\n在 Router 中，有 `RequestParams` 实例对象 `requestParams`，可通过 `this.requestParams.headers` 方式使用\n\n## Action\n\n每次调用 API，如果顺利进行，主要执行的是 `Action` 中的 `do` 函数。\n\n所有 `Action` 都应派生自 `Action` 类，并重写 `do` 函数。\n\n### 新建文件\n\n- 在云函数根目录（即与 index.ts 同级）创建名为`controllers`文件夹。也可以为其他，需要在 Router 构造函数第四个参数可以指定，默认为`controllers`\n- 根据各业务，创建不同 controller 文件夹，名称自定，但名称与路由名称对应。\n- 在 controller 文件夹中，创建`.ts`文件，每个`.ts`文件对应一个`action`\n- 在`.ts`文件中创建类，并继承 `Action`，重写 `do` 函数\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n  }\n}\n```\n\n比如你需要一个用户登录的 API，那么路径应如下（user 和 login 名称自定）：\n\n```\n/controllers/user/login.ts\n```\n\n### Action 文件内容\n\n在`.ts`文件中，模块返回一个类，该类继承 `Action`，构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n例 1\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    const { account, password } = this.requestParams.data\n\n    if(/*账号或密码错误*/) return this.notFound('账号或密码错误')\n    return this.ok(new {/*返回信息*/})\n  }\n}\n```\n\n例 2\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async do(): Promise<HttpResult> {\n    const { account } = this.requestParams.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    return this.ok(todoList);\n  }\n}\n```\n\n## 中间件\n\n中间件可以在 API 每次调用的生命周期各个阶段执行，如果记录日志，验证权限等。\n\n所有中间件应派生自类 `Middleware`，实现 `do` 函数，返回 `MiddlewareResult`\n\n### 中间件类型\n\n在 `cloudbase-access` 中，中间件有以下几种类别：\n\n1.  BeforeStart `Router` 初始化时就调用，此时 `Action` 未被加载\n1.  BeforeAction `Action` 执行前调用\n1.  BeforeEnd `Action` 执行后调用\n1.  BeforeSuccessEnd `Action` 执行后，而且返回结果为 2xx 时调用\n1.  BeforeErrEnd `Action` 执行后，而且返回结果不为 2xx 时调用\n\n### 中间件结果\n\n```ts\n// 成功\nreturn new MiddlewareResult(true);\n// 或\nreturn MiddlewareResult.getSuccessResult();\n\n// 失败\nreturn new MiddlewareResult(false, HttpResult.badRequest(\"中间件调用失败\"));\n// 或\nreturn MiddlewareResult.getFailedResult(\n  HttpResult.badRequest(\"中间件调用失败\")\n);\n```\n\n如果返回失败，则 API 此次调用结束，返回中间件结果。\n\n### 注册中间件\n\n你需要使用 router.configure 注册中间件，如\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n) => {\n  const router = new Router(event, context);\n  router.configure(new YourMiddleware());\n\n  return (await router.do()).result;\n};\n```\n\n## 权限\n\n`Router` 构造函数第三个参数是权限验证 `Authority` 对象。\n\n你需要新写个类，继承 `Authority`，并实现 `do` 函数。\n\n其实 `Authority` 也是个中间件，只是加载方式较特殊。当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同。\n\n权限是用于判断用户能否使用 API，可以精确到控制每个 `Action` 。下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```ts\nclass Auth extends Authority {\n  async do(): Promise<MiddlewareResult> {\n    if (!this.roles || !this.roles.length) {\n      return MiddlewareResult.getSuccessResult();\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      return MiddlewareResult.getFailedResult(\n        HttpResult.forbidden(\"账号或密码错误\")\n      );\n    }\n\n    return MiddlewareResult.getSuccessResult();\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.requestParams.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n) => {\n  const router = new Router(event, context, new Auth());\n  return (await router.do()).result;\n};\n```\n\n## Demo\n\nDemo 内容在本项目 `demo` 文件夹，用于演示 `cloudbase-access` 用法。\n\n### 一个简单的 todo API\n\n此 demo 没有访问数据库，只有模拟账号，在 `lib/Global.ts` 中。\n\n1. account: abc, password: 123456\n1. account: admin, password: abcdef\n\n### 发布\n\n本示例是使用 `ts` 写的，需要编译后发布至自己的 cloudbase。\n\n修改 `/cloudbaserc.json` 文件，将 `evnId` 值改为你自己的 cloudbase 环境\n\n```JSON\n\"envId\": \"env-***\",\n```\n\n运行以下命令发布：\n\n```shell\ncd demo/cloudbase-access-api\nnpm install\nnpm run build\n```\n\n首次发布需要登录。发布成功后，在 `CloudaBase` 云函数控制台，配置 HTTP 访问服务。\n\n#### 生成的内容\n\n编译后会在云函数目录 `functions` 生成文件夹 `cloudbase-access`，\n\n在 cloudbase-access 文件夹中包含以下内容：\n\n- controllers：符合 cloudbase-access 规则的 controllers 目录\n- lib：除 controllers 外的其他帮助类\n- index.js：入口函数\n\n### 调用 API 测试\n\n使用 `vscode` 插件 `REST Client` 测试，测试文件都是以 `.test.txt` 结尾\n\n`vscode` 安装插件后，打开 `.test.txt` 文件，快捷键 `Ctrl + Alt + R` 可测试\n\n目前测试的 API，环境是本人免费 `cloudbase` 环境，不保证长期有效。使用前请将 `cloudbase` 环境改为你自己的。\n\n如\n\n```txt\nPOST https://env-***.service.tcloudbase.com/cloudbase-access/user/login\ncontent-type:application/json\n\n{\n  \"account\":\"abc\",\n  \"password\":\"123456\"\n}\n```\n\n### 权限认证\n\n示例只写了 `login`、`admin` 两个身份，实际业务需要访问数据库来验证访问权限。\n\n其中，`login` 权限在示例中，是根据头部的 `account` 和 `password` 验证的。在实际业务中，`password` 可能会加密，或者使用 `token` 方式等。\n","readmeFilename":"README.md","gitHead":"94f651c480812b5fdb37625b86f3a841760a5bde","_id":"@hal-wang/cloudbase-access@0.9.0-beta.8","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-t/vkgyA5k4VFKZxgMe3oZ8yKhzEBuIc85+Ti6UrQcahX/dVSSJEfa57usQrp8QZ5PiG8AzJcMw8OHbDN/TkARw==","shasum":"8bbbfb0eadfec4ebc3f1d0258bacbbb71bc5a19f","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.9.0-beta.8.tgz","fileCount":94,"unpackedSize":80090,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgGgN+CRA9TVsSAnZWagAAjjsP/RP6rSW+HomPA7Q5RW8p\niaGxaJHxNPgYlcipmzWsRSUl7aGEy5QGWHjPj9f7JCDvvJBLIhmSkgEDtim/\nseBaFtWeFR1ijkbk/OQ8ZKIOeiwEEsL7V5baqZn4puOiJRuB17027/fSk6NE\nrREFyPkuvYjZuzUnFNT37uLiu50PXuPm0ZjRGZyBvm6xdVTPh8TgPdsBOlda\nDaP2fAJzvYSEo8SxHO2r1dRpCQLlEeVMuDRHnAJJaInqVYGeJEavM6o+QY8v\nv3IhldmK0lfBcyqgHh8jdRMrjYBuj8GgZ6B2eOtkxJhtJJiwWQcTe22R9cE3\nMgE6vvH+p28swVzG+Fk5E5avbVFEm4UnkEs9dxXeGcvEh3WQ94jYcxd++lT7\nT7XNfMHKMycgpPKjbJ9ABrB37xSZGRbhxmmuc5wEVpNPpg/HGa8YXKmje0JP\naPlK11MoW+08eOba5H7Ib5xA//RaBp+9KVhCVdw0XA3ZeF8jeWxq2Y7p+ycF\nF0LnLTlq9oluvJtLGiCCTmP2QLEBnJZmXnxL2J/j2ulXDlcpsH0gyi7Ixfjg\n5vRAQgPKquriF0CYg4dssbYV9h+PrxCnJjaXyFS/by+/P59CUMoXJnoDD8JZ\nK2FzfPvpIRCdFLv0GxjUNfbT5imQzccGU/BoAz7laEovdirlgShj6hvdW8l1\n5gAp\r\n=Hco6\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCv31/b0e/lbNKxAY5U5UZEnt4GnA+0ISWWfuDPyfyq5AIhAJFUAfR5SvcH+j2MMFMoELeSe7hVRVKaArNFzEFkWwFA"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.9.0-beta.8_1612317566086_0.3281416006263389"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"0.9.0":{"name":"@hal-wang/cloudbase-access","version":"0.9.0","description":"利用 NodeJS 和 CloudBase 快速创建 MVC 架构的 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.22","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.22","@typescript-eslint/eslint-plugin":"^4.14.0","@typescript-eslint/parser":"^4.14.0","eslint":"^7.18.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.4.4","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js"},"gitHead":"19cedfb76c2b977a2f49fb519784c32cbbf1e909","_id":"@hal-wang/cloudbase-access@0.9.0","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-8bxKgA1mL/CdGhALwb47jxlJr+b9InfW/eAz7YyCs78qQTbNO//2jj7pcpgBbY2yYFJ5VppFqWNbV++b8jXjgQ==","shasum":"d563450b37a9409289df849a0086e88afd60cf52","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.9.0.tgz","fileCount":95,"unpackedSize":82821,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgGmYBCRA9TVsSAnZWagAAZ8QP/1MyBcXL3rtzhh1JMVwi\n1nGtExFlOyJTnFtLbF5NjVqxQC7Fca5MUIWEESFFM7in2Fo6zucG5dJOUN2V\nog+0FQC9y/oXFRHWOwAGTh3/0hue6H1A88AJAFRBDqD/WnSYHN6NzGBph6+D\nq/1ErKGcJzExkJMcCsrhNL7lpsPkmqwq7myjAMrokzErZdH4Ky5HIEQR0v8M\n0h9ClBr/wYsb4wYIYIxGeHlSCkBhcyf77vUGwWhCiua1tMo/QfvPShDvWopi\nt/bjqNd9Iba2ev/U23bXc4muxj1xasPvlQO7Gvun0FRb+5Wpi1iohdO1q9vE\n6jPjXapAZTMkbCUB1Wp+nD17oA0vJvM2CZ26h6IojdOYpLUD8RquRJZHT3/9\npYI5YIvQfTDjQrBcZckSSW9Zu8LcBWyldnkMvwO1O8jPvxuwNF1u6Qkr2c3a\njMC4lfXEE9XmoACX+9MAnZp9dn67CXViGUCQ5p+aUG8ha8ZMk9X6dkEssY8P\naSCxNOnZMasUr9FM4oK8MbJ6S4qXQ4gmZwfoylAnRN/jEiZTWya7pqI85se3\n/3axwy6hIYwuqxTK7Bb7f0JLbi5r4JbbbUUlkmMTYpAKuEK7u4DlhAsO85Fs\n3WJumzviTE90Cef3C7mRa5n3fB0DJBDySDCmLTnKXzSW33Z5tg/ioLk2gkCr\n0DKN\r\n=0vDW\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDLTHOwHExsLZAOXrdFNIqvR0HZGXxEVtcA0pBL42/k5AiAIdwUCKAYQSSOO9MYrOd7udxwvlacB8HWGJpgQFAKbHw=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.9.0_1612342784376_0.8976051233667459"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"0.9.4":{"name":"@hal-wang/cloudbase-access","version":"0.9.4","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js"},"gitHead":"0288521d58be8bad89ce0badcb2c75b57b763752","_id":"@hal-wang/cloudbase-access@0.9.4","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-k8/P1sGds+GGM+hH/2y2A8z3kxdaMAeBhQ7hkQqJ3HUsl52z2TdKRVhzvzWOM5MjaLvBOm4Il1wAeIxQLN55mw==","shasum":"341e46505f247d15969e1429f2f1deff5027fc3a","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.9.4.tgz","fileCount":96,"unpackedSize":89090,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgG5qdCRA9TVsSAnZWagAAaqkQAKSFJeKRzNOYl7J4GPO2\nw1Au1Isj+iTHBuxb0bnWjCdEt4aZMKr7ILhfCzTegtLQXcaRjKFh/GL+UWmN\nUAjY+7NkUGaaOzGjGhj1WBwmdFqHutfbmmJ8HUkFe3bjBnKroIa2334pD67P\nTF+zvRla3o+N0ngbMUbcKi4IGrZvMAY3XPmzbgX2I5dWZJXxH5IES/yBJgMM\nEYPqvnE+yap9VLa+Fhu6HgyvNO5D/G5/mfd5219BnI6wIyqCbCD/jO1BVSlF\nkdI7raKoJqzmiCZtcQRqJ8eDvje5eIzhIlzk0GcJYP7Il/A+EwFQxy2oLmuk\nuRy+WfpRRDH0DduZ1nn3XbUpzOdIr0GN8uTMONxOEDVt3sZYtL36GPMwOh1r\ne1D9EeqxgkQweIIRlQ0SZJx6Fy40FuuhUijLa/QiS4loOR+75dXhMIFHl0cv\nDeLswhVq36abAtWLq+Fec1NultmNUrcNvbocJZEfTMS/14ZTxsn/EzynYg0g\nvaHcw5vjx5UxZmhJMnJCK7wQHlAru5Gq7U9nxhQ6aKTRb+Avy2JrYZX1kwZQ\nkZXhP6/2g2hYrIbW6+INrpERmFJdYNsdhsjMCAJn+WoicsX4NcSBmhEjkEA1\ng8M5tPrKBcarvuzYraauNoSG628Q0OiFJK9ggxSZQ0aYggQKMqTTW/9MkgnP\n5Bd0\r\n=zbYB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHBrwUJ8EurgB1V4GnCkfoJPbmf1QVdQJmXxNs6+nebSAiBE46Lu5AbY5Wd8Aoq3oINU/Gh2ODEGS1yKCzLkzK0A1Q=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.9.4_1612421788645_0.009867638535626444"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"0.9.5-beta.1":{"name":"@hal-wang/cloudbase-access","version":"0.9.5-beta.1","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js"},"readme":"# cloudbase-access ( cba )\n\n利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n示例请查看后面的 [#Demo](##Demo)\n\n或者查看本项目 `test` 文件夹中的一些单元测试。\n\n## 建议\n\n强烈建议使用 `typescript` 并生成 `javascript`代码后上传，可参考 [#Demo](##Demo)。理论上 `javascript` 完全没问题，但作者并未进行测试。\n\n## Router\n\n路由管理类，也是 `cba` 的控制中心。构造函数传入环境 `event` 和 `context`。\n\n如在 `main` 函数中：\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n) => {\n  const router = new Router(event, context);\n  return (await router.do()).result;\n};\n```\n\n以上几行代码即创建一个简单的 RESTful 规范的 API。\n\n如果访问的路径不存在，会返回 404 NotFound 结构。\n\n### 权限参数\n\n`Router` 第三个参数（可选）传入权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### controllers 目录\n\n`Router` 第四个参数（可选）传入 `controllers` 目录名称，默认为 `controllers`，建议不传此参数，即 `controllers`。\n\n所有 `controllers` 统一放在这个文件夹中，在 `controllers` 目录中，建立各 `controller` 文件夹，再在 `controller` 文件夹中建 `action` 文件。详情后面 [##Action](##Action) 部分有介绍。\n\n### 路由匹配\n\n在`cba`中，路由与文件系统匹配。\n\n路由查询参数命名以 `^` 开头（文件系统中命名不允许出现字符 `:`），如果存在多个查询参数则后面的会覆盖前面的，如 `get user/^id/todo/^id`，则 `id` 值为 `todoId`。正确命名应如 `user/^userId/todo/^todoId`。\n\n如果限制 `httpMethod`, `action` 应以 `post.ts`、`get.ts`、`delete.ts`、`patch.ts`、`put.ts` （或 `.js` ）命名，否则任意 `httpMethod` 都可以访问。\n\n#### isMethodNecessary\n\n如果设置 `router.isMethodNecessary = true;`, 则所有 `Action` 必须严格使用 `httpMethod` 命名，与 RESTFul 规范相符。否则会找不到路由并返回 `404`。\n\n如果 `isMethodNecessary` 为 `false` 或不设置，则 RESTFul 规范的 API 可能会以非 RESTFul 方式调用。如路由 `user/login`，本应是 `get user/login`，但 `post user/login/get` 也能调用。因此如果使用 RESTFul，建议设置 `isMethodNecessary` 为 `true`。\n\n#### 例 1\n\n获取 todo list\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- get.ts\n```\n\n访问地址为 `get /todo`，\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoList.ts\n```\n\n访问地址为 `get /todo/getTodoList` 、 `post /todo/getTodoList` 、 `put /todo/getTodoList` 等等，效果相同。\n\n#### 例 2\n\n获取单个 todo item\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- ^id\n|           +-- get.ts\n```\n\n访问地址为 `get /todo/66`\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoItem.ts\n```\n\n访问地址为 `get(post 等) /todo/getTodoItem`，需要在 `body` 、 `header` 或 `queryParams` 传入 `todoId` 参数\n\n#### 示例建议\n\n上述两个示例都给了两种定义方式。\n\ncloudbase 云函数没有限制 httpMethod，但建议使用方式 1 更符合规范，易读性也更好。\n\n因此建议设置 router.isMethodNecessary 为 true 。\n\n## HttpResult\n\n`HttpResult` 封装了 HTTP 返回结构。可在构造函数传入相关参数。\n\n`HttpResult` 有个属性 `result` ，可获取最终 HTTP 返回结构 `HttpResultStruct` 。\n\n### 内置类型\n\n目前 `HttpResult` 内置一些返回类型，都是以静态方式调用：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- methodNotAllowed, 405\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nreturn HttpResult.ok(\"success\");\n```\n\n普通内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，命名以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n### 举例\n\n以下例子中返回 200 请求成功：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.ok({\n  list: [],\n  count: 0,\n});\n```\n\n以下例子中返回 400 请求错误：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.badRequestMsg({ message: \"请求错误\" });\n// 或 return HttpResult.badRequest(\"请求错误\");\n```\n\n### 在 Action 中\n\n在 `Action` 中已经加入了 `HttpResult` 内置函数，可以直接以 `this.func` 方式调用\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n    // or return this.ok('success');\n  }\n}\n```\n\n## 请求参数\n\n`RequestParams` 类解析并封装请求参数，构造函数传入云函数 `event` 和 `context`。\n\n在 `Action` 中，有 `RequestParams` 实例对象 `requestParams`，可通过 `this.requestParams` 方式使用。\n\n实例包含以下字段\n\n### event\n\n云函数环境 event\n\n### context\n\n云函数环境 context\n\n### path\n\n访问路径，如`POST https://domain.com/api/user/login`，path 值为`user/login`。\n\n_注意：在 event 中，path 实为 `/` 开头，上例为 `/user/login`。但在 `cba` 中移除了开头的 `/`_\n\n### headers\n\n请求头部\n\n### params\n\n查询参数\n\n### data\n\n请求 body，如果是 JSON 字符串，则转为 JSON 对象。\n\n在 event 中，json 为字符串，在 `RequestParams` 中已解析。\n\n### query\n\nv0.9.0 中新增。\n\nRESTFul 规范的路径中查询参数。如 `user/:id` 调用时是 `user/66`，在 query 中即存在\n\n```ts\nquery.id == \"66\"; // true;\n```\n\n## Action\n\n每次调用 API，如果顺利进行，主要执行的是 `Action` 中的 `do` 函数。\n\n所有 `Action` 都应派生自 `Action` 类，并重写 `do` 函数。\n\n### 创建一个 Action\n\n1. 在云函数根目录（即与 index.ts 同级）创建名为`controllers`文件夹。也可以为其他，需要在 Router 构造函数第四个参数可以指定，默认为`controllers`\n1. 根据各业务，创建不同 controller 文件夹，名称自定，但名称与路由名称对应。\n1. 在 controller 文件夹中，创建`.ts`文件，每个`.ts`文件对应一个`action`\n1. 在`.ts`文件中创建类，并继承 `Action`，重写 `do` 函数\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n  }\n}\n```\n\n### Action 文件内容\n\n在`.ts`文件中，模块返回一个类，该类继承 `Action`，构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n例 1\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    const { account, password } = this.requestParams.data\n\n    if(/*账号或密码错误*/) return this.notFound('账号或密码错误')\n    return this.ok(new {/*返回信息*/})\n  }\n}\n```\n\n例 2\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async do(): Promise<HttpResult> {\n    const { account } = this.requestParams.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    return this.ok(todoList);\n  }\n}\n```\n\n## 中间件\n\n中间件可以在 API 每次调用的生命周期各个阶段执行，如记录日志，验证权限等。\n\n所有中间件应派生自类 `Middleware`，实现 `do` 函数，返回 `MiddlewareResult`\n\n### 中间件类型\n\n在 `cba` 中，中间件有以下几种类别：\n\n1.  BeforeStart： `Router` 初始化时就调用\n1.  BeforeAction： `Action` 执行前调用\n1.  BeforeEnd： `Action` 执行后调用\n1.  BeforeSuccessEnd： `Action` 执行后，而且返回结果为 2xx 时调用\n1.  BeforeErrEnd： `Action` 执行后，而且返回结果不为 2xx 时调用\n\n类型为 `BeforeStart` 的中间件执行时，`Action` 未被加载，因此无法获取 `query`, `roles` 等。\n\n类型为 `BeforeStart` 和 `BeforeAction` 的中间件执行时，`Action` 未执行，因此无法获取 `Action` 执行结果。\n\n### 中间件结果\n\n```ts\n// 成功\nreturn new MiddlewareResult(true);\n// 或\nreturn MiddlewareResult.getSuccessResult();\n\n// 失败\nreturn new MiddlewareResult(\n  false,\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n// 或\nreturn MiddlewareResult.getFailedResult(\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n```\n\n如果返回失败，则 API 此次调用结束，返回中间件结果。\n\n### 注册中间件\n\n你需要使用 router.configure 注册中间件，如\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n) => {\n  const router = new Router(event, context);\n  router.configure(new YourMiddleware());\n\n  return (await router.do()).result;\n};\n```\n\n## 权限\n\n`Router` 构造函数第三个参数是权限验证 `Authority` 对象。\n\n你需要新写个类，继承 `Authority`，并实现 `do` 函数。\n\n其实 `Authority` 也是个中间件，只是加载方式较特殊。当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同。\n\n权限是用于判断用户能否使用 API，可以精确到控制每个 `Action` 。下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```ts\nclass Auth extends Authority {\n  async do(): Promise<MiddlewareResult> {\n    if (!this.roles || !this.roles.length) {\n      return MiddlewareResult.getSuccessResult();\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      return MiddlewareResult.getFailedResult(\n        HttpResult.forbidden(\"账号或密码错误\")\n      );\n    }\n\n    return MiddlewareResult.getSuccessResult();\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.requestParams.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n) => {\n  const router = new Router(event, context, new Auth());\n  return (await router.do()).result;\n};\n```\n\n## cba-map\n\n`cba-map` 是可选的，它能提升路由匹配速度，其本身为 json 文件，并且要上传至 `cloudbase`云函数根目录。\n\n### 建议使用\n\n如果不使用`cba-map`，路由匹配方式是先遍历 `controllers` 中的各个 `action`，再进行匹配，如果项目较大可能会影响匹配速度。\n\n在 100 个 `action` 的项目中，经测试`cba-map`提升路由匹配速度大概 20 倍左右（有 `cba-map` 耗时 1-2ms，无`cba-map`耗时 30-40ms）。因此在 `action` 数量较多时建议使用 `cba-map`。\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-map\": \"cba-map dist/controllers\",\n  },\n```\n\n`dist/controllers` 应改为你的 js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录。\n\n执行 `npm run cba-map` 会以`dist/controllers`目录，在项目目录下生成 `cba-map.json` 文件（建议将其加入 `.gitignore`文件）。\n\n## Demo\n\nDemo 内容在本项目 `demo` 文件夹，用于演示 `cba` 用法。\n\n### 一个简单的 todo API\n\n使用了 `RESTFul` 规范的 API 格式，并且设置 `router.isMethodNecessary = true;`。\n\n使用了数据库两个文档：`cba-user`, `cba-todo`。\n\n测试账号为 `test@hal.wang` 并且无法更改，管理员账号为 `support@hal.wang`。您可以在`Global.ts`中修改以上账号。\n\n### 发布\n\n本示例是使用 `ts` 写的，需要编译后发布至自己的 cloudbase。\n\n修改 `/.env` 文件，将 `ENV_ID` 值改为你自己的 cloudbase 环境 id.\n\n```\nENV_ID=env-***\n```\n\n运行以下命令发布：\n\n```shell\ncd demo/cba-todo/cba-todo-api\nnpm install\nnpm run build\n```\n\n首次发布需要登录。发布成功后，在 `CloudaBase` 云函数控制台，配置 HTTP 访问服务。\n\n#### 生成的内容\n\n编译后会在云函数目录 `functions` 生成文件夹 `cba-todo`，\n\n在 `cba-todo` 文件夹中包含以下内容：\n\n- controllers：符合 `cba` 规则的 `controllers` 目录\n- lib：除 `controllers` 外的其他帮助类\n- models: ts model\n- index.js：入口函数\n\n### 调用 API 测试\n\n测试文件位于 `rest-test` 文件夹中\n\n使用 `vscode` 插件 `REST Client` 测试，测试文件都是以 `.test.txt` 结尾\n\n`vscode` 安装插件后，打开 `.test.txt` 文件，快捷键 `Ctrl + Alt + R` 可测试\n\n目前测试的 API，环境是本人免费 `cloudbase` 环境，不保证长期有效。使用前请将 `cloudbase` 环境改为你自己的。\n\n如\n\n```txt\nPOST https://env-***.service.tcloudbase.com/cba-todo/user/login\ncontent-type:application/json\n\n{\n  \"account\":\"abc\",\n  \"password\":\"123456\"\n}\n```\n\n### 权限认证\n\n#### 身份\n\n示例写了 `hl`、`ql`、`admin` 三个身份\n\n##### hl\n\n即 `header login`，通过 `header` 的 `account` 和 `password` 验证登录\n\n##### ql\n\n即 `query login`, 通过 `query` 的 `account` 和 `header` 的 `password` 验证登录\n\n##### admin\n\n验证 `header`或 `query` 中的 `account` 是否管理员\n\n#### 实际业务\n\n在实际业务中，`password` 可能会加密，或者使用 `token` 方式等，验证方法与 `demo` 类似\n","readmeFilename":"README.md","gitHead":"b4918d9fcf19fa4b212b720c993e3a606fe4d669","_id":"@hal-wang/cloudbase-access@0.9.5-beta.1","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-9vEKwlAB/NcFU9fsR4JKYO50p0Nx10mBRe4M+hg5IQFpQBIFLF39CDgixvFFLlF3qXkHnSWfygZVA0fDWEvLag==","shasum":"4b43166a861728d422e832bcd9ca129090dd4ff3","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-0.9.5-beta.1.tgz","fileCount":96,"unpackedSize":90541,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgH+hDCRA9TVsSAnZWagAAZ4IP/jR1O7UirG7C+TY6H0e6\nNtsA9xWsgDJLff/jzkyDdC61mJ3WOF4fpoonBw+LtZ+KFQBMTay7wmunSGMn\nOWB84cQsZKBj2KCu+ztASs+svkZM4dtzICudWI0SC/fvCDWy0COadL7fDCd3\n8/M0tuZ/vLc36JtBrHr1KR+H7mHsi75k4Fv6RFEqqjAUvQKrRX2ANJWfdznJ\nbxhiOIvq9iGPt9tLwjnJfR9yfmqXKzeGyrqMKEkznxvgKSuMMzWiY5JvUFGR\n6/HlHEZAU22M6EVaaZ82JQDB5/c235z1AR1PofvdijbgM8ULDq57EzTjXxMv\n0+BusEO1PK9C579GBbX9xyX1s6EmRq04D2XD3fmcpk7ha3VcEOprfqtYEztk\njWOIgB6OesVDyqbpdPeRaLWc/s5c8F85VthZ7Yf0tYMYxr2kMGfovuHs62Xp\ngQ4ziXAWPBl5FCxWCDveUpFtoSNZZRZSojgVd9A/g+wiUDJJ11ARJHq7rTzQ\nTXg50ONOKDVRGm4kCAlDz2wzv+wOWJdxejvIbcPmoyTEti/P6n216k4fTqLY\nB5v1TwLwcEAOeHW6BVGv6HsRcVV92jDeyhMw6TJG8JGTSL0oP3aJqQJtxQZm\n+zX+7F/Gl+8jLQacGhvMamotHuoM59oYlyOhPlaInsRDY9QLA8fn4+C93Ejh\nqlpA\r\n=IUVZ\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDL0WsPrLb4Dxi6m3GfEy1eRWzIb0duqZC96EnlLbNOLwIhAMn1KAdD6mrRrV4kvJCUWL84hrr4rwmck2CkDTaiuXOS"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_0.9.5-beta.1_1612703811154_0.47513581643871006"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.0.0-beta.2":{"name":"@hal-wang/cloudbase-access","version":"1.0.0-beta.2","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js"},"readme":"# cloudbase-access ( cba )\n\n利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n你可以体验线上示例: <https://cba-todo.hal.wang>\n\n也可以一键部署到自己的 `cloudbase`\n\n[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fcloudbase-access&workDir=demo%2Fcba-todo&branch=main)\n\n此示例项目是一个简易的 todo 项目，包含后端和前端，详情请查看后面的 [#Demo](##Demo)\n\n或者你也可以查看本项目 `test` 文件夹中的一些单元测试\n\n## 建议\n\n强烈建议使用 `typescript` 并生成 `javascript` 代码后上传，可参考 [#Demo](##Demo)，做法是 ts 生成 js 文件，并删除 `.d.ts` 文件。\n\n理论上 `javascript` 完全没问题，但作者并未进行测试。\n\n## Router\n\n路由管理类，也是 `cba` 的控制中心。构造函数传入环境 `event` 和 `context`。\n\n如在 `main` 函数中：\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n) => {\n  const router = new Router(event, context);\n  return (await router.do()).result;\n};\n```\n\n以上几行代码即创建一个简单的 RESTful 规范的 API。\n\n如果访问的路径不存在，会返回 404 NotFound 结构。\n\n### 权限参数\n\n`Router` 第三个参数（可选）传入权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### controllers 目录\n\n`Router` 第四个参数（可选）传入 `controllers` 目录名称，默认为 `controllers`，建议不传此参数，即 `controllers`。\n\n所有 `controllers` 统一放在这个文件夹中，在 `controllers` 目录中，建立各 `controller` 文件夹，再在 `controller` 文件夹中建 `action` 文件。详情后面 [##Action](##Action) 部分有介绍。\n\n### 路由匹配\n\n在`cba`中，路由与文件系统匹配。\n\n路由查询参数命名以 `^` 开头（文件系统中命名不允许出现字符 `:`），如果存在多个查询参数则后面的会覆盖前面的，如 `get user/^id/todo/^id`，则 `id` 值为 `todoId`。正确命名应如 `user/^userId/todo/^todoId`。\n\n如果限制 `httpMethod`, `action` 应以 `post.ts`、`get.ts`、`delete.ts`、`patch.ts`、`put.ts` （或 `.js` ）命名，否则任意 `httpMethod` 都可以访问。\n\n#### isMethodNecessary\n\n如果设置 `router.isMethodNecessary = true;`, 则所有 `Action` 必须严格使用 `httpMethod` 命名，与 RESTFul 规范相符。否则会找不到路由并返回 `404`。\n\n如果 `isMethodNecessary` 为 `false` 或不设置，则 RESTFul 规范的 API 可能会以非 RESTFul 方式调用。如路由 `user/login`，本应是 `get user/login`，但 `post user/login/get` 也能调用。因此如果使用 RESTFul，建议设置 `isMethodNecessary` 为 `true`。\n\n#### 例 1\n\n获取 todo list\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- get.ts\n```\n\n访问地址为 `get /todo`，\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoList.ts\n```\n\n访问地址为 `get /todo/getTodoList` 、 `post /todo/getTodoList` 、 `put /todo/getTodoList` 等等，效果相同。\n\n#### 例 2\n\n获取单个 todo item\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- ^id\n|           +-- get.ts\n```\n\n访问地址为 `get /todo/66`\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoItem.ts\n```\n\n访问地址为 `get(post 等) /todo/getTodoItem`，需要在 `body` 、 `header` 或 `queryParams` 传入 `todoId` 参数\n\n#### 示例建议\n\n上述两个示例都给了两种定义方式。\n\ncloudbase 云函数没有限制 httpMethod，但建议使用方式 1 更符合规范，易读性也更好。\n\n因此建议设置 router.isMethodNecessary 为 true 。\n\n## HttpResult\n\n`HttpResult` 封装了 HTTP 返回结构。可在构造函数传入相关参数。\n\n`HttpResult` 有个属性 `result` ，可获取最终 HTTP 返回结构 `HttpResultStruct` 。\n\n### 内置类型\n\n目前 `HttpResult` 内置一些返回类型，都是以静态方式调用：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- methodNotAllowed, 405\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nreturn HttpResult.ok(\"success\");\n```\n\n普通内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，命名以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n### 举例\n\n以下例子中返回 200 请求成功：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.ok({\n  list: [],\n  count: 0,\n});\n```\n\n以下例子中返回 400 请求错误：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.badRequestMsg({ message: \"请求错误\" });\n// 或 return HttpResult.badRequest(\"请求错误\");\n```\n\n### 在 Action 中\n\n在 `Action` 中已经加入了 `HttpResult` 内置函数，可以直接以 `this.func` 方式调用\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n    // or return this.ok('success');\n  }\n}\n```\n\n## 请求参数\n\n`RequestParams` 类解析并封装请求参数，构造函数传入云函数 `event` 和 `context`。\n\n在 `Action` 中，有 `RequestParams` 实例对象 `requestParams`，可通过 `this.requestParams` 方式使用。\n\n实例包含以下字段\n\n### event\n\n云函数环境 event\n\n### context\n\n云函数环境 context\n\n### path\n\n访问路径，如`POST https://domain.com/api/user/login`，path 值为`user/login`。\n\n_注意：在 event 中，path 实为 `/` 开头，上例为 `/user/login`。但在 `cba` 中移除了开头的 `/`_\n\n### headers\n\n请求头部\n\n### params\n\n查询参数\n\n### data\n\n请求 body，如果是 JSON 字符串，则转为 JSON 对象。\n\n在 event 中，json 为字符串，在 `RequestParams` 中已解析。\n\n### query\n\nv0.9.0 中新增。\n\nRESTFul 规范的路径中查询参数。如 `user/:id` 调用时是 `user/66`，在 query 中即存在\n\n```ts\nquery.id == \"66\"; // true;\n```\n\n## Action\n\n每次调用 API，如果顺利进行，主要执行的是 `Action` 中的 `do` 函数。\n\n所有 `Action` 都应派生自 `Action` 类，并重写 `do` 函数。\n\n### 创建一个 Action\n\n1. 在云函数根目录（即与 index.ts 同级）创建名为`controllers`文件夹。也可以为其他，需要在 Router 构造函数第四个参数可以指定，默认为`controllers`\n1. 根据各业务，创建不同 controller 文件夹，名称自定，但名称与路由名称对应。\n1. 在 controller 文件夹中，创建`.ts`文件，每个`.ts`文件对应一个`action`\n1. 在`.ts`文件中创建类，并继承 `Action`，重写 `do` 函数\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n  }\n}\n```\n\n### Action 文件内容\n\n在`.ts`文件中，模块返回一个类，该类继承 `Action`，构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n例 1\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    const { account, password } = this.requestParams.data\n\n    if(/*账号或密码错误*/) return this.notFound('账号或密码错误')\n    return this.ok(new {/*返回信息*/})\n  }\n}\n```\n\n例 2\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async do(): Promise<HttpResult> {\n    const { account } = this.requestParams.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    return this.ok(todoList);\n  }\n}\n```\n\n## 中间件\n\n中间件可以在 API 每次调用的生命周期各个阶段执行，如记录日志，验证权限等。\n\n所有中间件应派生自类 `Middleware`，实现 `do` 函数，返回 `MiddlewareResult`\n\n### 中间件类型\n\n在 `cba` 中，中间件有以下几种类别：\n\n1.  BeforeStart： `Router` 初始化时就调用\n1.  BeforeAction： `Action` 执行前调用\n1.  BeforeEnd： `Action` 执行后调用\n1.  BeforeSuccessEnd： `Action` 执行后，而且返回结果为 2xx 时调用\n1.  BeforeErrEnd： `Action` 执行后，而且返回结果不为 2xx 时调用\n\n类型为 `BeforeStart` 的中间件执行时，`Action` 未被加载，因此无法获取 `query`, `roles` 等。\n\n类型为 `BeforeStart` 和 `BeforeAction` 的中间件执行时，`Action` 未执行，因此无法获取 `Action` 执行结果。\n\n### 中间件结果\n\n```ts\n// 成功\nreturn new MiddlewareResult(true);\n// 或\nreturn MiddlewareResult.getSuccessResult();\n\n// 失败\nreturn new MiddlewareResult(\n  false,\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n// 或\nreturn MiddlewareResult.getFailedResult(\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n```\n\n如果返回失败，则 API 此次调用结束，返回中间件结果。\n\n### 注册中间件\n\n你需要使用 router.configure 注册中间件，如\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n) => {\n  const router = new Router(event, context);\n  router.configure(new YourMiddleware());\n\n  return (await router.do()).result;\n};\n```\n\n## 权限\n\n`Router` 构造函数第三个参数是权限验证 `Authority` 对象。\n\n你需要新写个类，继承 `Authority`，并实现 `do` 函数。\n\n其实 `Authority` 也是个中间件，只是加载方式较特殊。当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同。\n\n权限是用于判断用户能否使用 API，可以精确到控制每个 `Action` 。下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```ts\nclass Auth extends Authority {\n  async do(): Promise<MiddlewareResult> {\n    if (!this.roles || !this.roles.length) {\n      return MiddlewareResult.getSuccessResult();\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      return MiddlewareResult.getFailedResult(\n        HttpResult.forbidden(\"账号或密码错误\")\n      );\n    }\n\n    return MiddlewareResult.getSuccessResult();\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.requestParams.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n) => {\n  const router = new Router(event, context, new Auth());\n  return (await router.do()).result;\n};\n```\n\n## cba-map\n\n`cba-map` 是可选的，它能提升路由匹配速度，其本身为 json 文件，并且要上传至 `cloudbase`云函数根目录。\n\n### 建议使用\n\n如果不使用`cba-map`，路由匹配方式是先遍历 `controllers` 中的各个 `action`，再进行匹配，如果项目较大可能会影响匹配速度。\n\n在 100 个 `action` 的项目中，经测试`cba-map`提升路由匹配速度大概 20 倍左右（有 `cba-map` 耗时 1-2ms，无`cba-map`耗时 30-40ms）。因此在 `action` 数量较多时建议使用 `cba-map`。\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-map\": \"cba-map dist/controllers\",\n  },\n```\n\n`dist/controllers` 应改为你的 js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录。\n\n执行 `npm run cba-map` 会以`dist/controllers`目录，在项目目录下生成 `cba-map.json` 文件（建议将其加入 `.gitignore`文件）。\n\n## Demo\n\nDemo 内容在本项目 `demo/cba-todo` 文件夹，用于演示 `cba` 用法。\n\nAPI 使用了 `cloudbase-access` 符合 `RESTFul` 规范的 API 格式，并且设置 `router.isMethodNecessary = true;`。\n\n使用了数据库两个文档：`cba-user`, `cba-todo`。\n\n测试账号为 `test@hal.wang` 并且无法更改，管理员账号为 `support@hal.wang`。\n\n### 一键部署\n\n你可以一键部署到自己的 `cloudbase`\n\n[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fcloudbase-access&workDir=demo%2Fcba-todo&branch=main)\n\n### Fork\n\n你也可以 Fork 本项目后，修改示例项目中的 `.env` 文件中的 `ENV_ID`，值为你的 cloudbase 环境 id 如 `your_name-***`\n\n在示例项目目录下（`demo/cba-todo`），执行以下语句发布 `tcb framework deploy`\n\n### build 生成的内容\n\nAPI 编译后会在云函数目录 `functions` 生成文件夹 `cba-todo`，\n\n在 `cba-todo` 文件夹中包含以下内容：\n\n- controllers：符合 `cba` 规则的 `controllers` 目录\n- lib：除 `controllers` 外的其他帮助类\n- models: ts model\n- middlewares: 中间件\n- index.js：入口函数\n\nweb 编译后会生成 `cba-todo-web/dist` 目录，发布的 web 是此文件夹中的内容\n\n### 调用 API 测试\n\n测试文件都在 `cba-todo-api/rest-test`文件夹中，并且以 `.test.txt` 结尾\n\n使用 `vscode` 插件 `REST Client` 测试，安装插件后，打开 `.test.txt` 文件，快捷键 `Ctrl + Alt + R` 可测试调用\n\n目前测试的 API，环境是本人免费 `cloudbase` 环境，不保证长期有效。使用前请将 `cloudbase` 环境改为你自己的\n\n如\n\n```txt\nGET https://cba-todo-api.hal.wang/cba-todo/user/test@hal.wang\ncontent-type:application/json\npassword:123456\n```\n\n```txt\nPOST https://cba-todo-api.hal.wang/cba-todo/user\ncontent-type:application/json\n\n{\n  \"account\": \"test@hal.wang\",\n  \"password\":\"123456\"\n}\n```\n\n### 权限认证\n\n#### 身份\n\n示例写了 `hl`、`ql`、`admin` 三个身份\n\n##### hl\n\n即 `header login`，通过 `header` 的 `account` 和 `password` 验证登录\n\n##### ql\n\n即 `query login`, 通过 `query` 的 `account` 和 `header` 的 `password` 验证登录\n\n##### admin\n\n验证 `header`或 `query` 中的 `account` 是否管理员\n\n#### 实际业务\n\n在实际业务中，`password` 可能会加密，或者使用 `token` 方式等，验证方法与 `demo` 类似\n","readmeFilename":"README.md","gitHead":"3967d18a6223b7d2a67ea035bffdcf20c99ad0d3","_id":"@hal-wang/cloudbase-access@1.0.0-beta.2","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-LJ5gjKdwJ/ewC4b/MdTaZLvP2U+WPO9Yvqphsnk2iA7NGGUuhZ4TOaXzstLZaYpndoB/GfYZLcHk0gNr1rb4Aw==","shasum":"8f12ad2cc12458ed82c2f869145c84630a01ab03","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.0.0-beta.2.tgz","fileCount":96,"unpackedSize":91421,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgJOMVCRA9TVsSAnZWagAA08cP/RQ9INPzNd6Lub0sC2Br\nN+ZKBFtz3tGKS9WzrK3V2NswS0VhGYEEwkr6ZNZxndot4QrIs2SQopTcB3wG\nVqX85SOupBeMJEGgbEmpJIHK+nRiI67u45kJoaXg8m2CLDV1jVvXKyuFLtSK\nAsRb2wUxVgbuOF+/MUVzbLCmhdb3sajASAHbr6w+IizFf+RJzE87KI6eoU80\n1CTFx3I9qFewfd/B1BuYQiBi3nkMH+dEHCSYiCmWi/eXbIMXHNgXtdAgaOnT\nQNsvH7Ghbi5uQrd4zKHJ/l8w2JpvFs83ahxyjIZ9E3GRDoee/2/vqYNQw7Lb\nKu0Y1veXssq3NcoOTB0D8UIN8Kc1tN6Sjdh+SbEexaxFSmYcicq9mps97W94\nEXIExLQ+zSnDQJMfNqh8SZirKJx1ntv/jnsvKgDCiQguHe8uAgpi8YGIqT9g\noLqyLQ9ad25B65XT6XcKuPeSH0Xnz2N0EZ05DF9XOfxEKQ6bELccWqDQhgYm\nr+2SCZTC2v2D09D6EFv9zm2ysYQbcwLkfxTR7Il/ushwiHZsUa8/p4EXDbFo\n+OZsarFmmQjnIlVkmxKpAtP1neICG+/+uCf4Vlst6ZTOMImMAaXTFEESUBGd\n9eeP5m6oR/jiTeWTU/12XBgHfIBGono8tsXdzGFsH73OfCY80ZcmDdOtDChu\ny+EX\r\n=TYbM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQDIt7mfXhGEZSfKI07ZXFXVX1ua3/971DiJWpViflu3xQIhAOOk+occDxIGkMHqBSswUzqo9coirpFCKIzov8oVnq7C"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.0.0-beta.2_1613030164780_0.5657679820017569"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.0.0":{"name":"@hal-wang/cloudbase-access","version":"1.0.0","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js"},"gitHead":"817b1da93a37d060f6f2e4b5389d4a2b5dc31fd7","_id":"@hal-wang/cloudbase-access@1.0.0","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-bCYVbLkiWMYebAmrStlA4c9MfBAKAzW9u6XsCfQ4iQfnC6fMF3yTEQG7kHcZPU5eXli+naAbPvFYjvvo3LIA5A==","shasum":"4d21a9383fc081b120f6373f3570a9cc81cd2e63","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.0.0.tgz","fileCount":96,"unpackedSize":91414,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgJOO3CRA9TVsSAnZWagAA3y4P/A0zxrR6Wrckbgtbuc81\n4Lhjtyr4EvRM1swJhPntigVEuLovg40LnP1RBF1tA7W/Knwlq0QlnYia0kaY\nooZjDLKMqyTST5DF45TOY43phSDtPjBiMRpSkRkOMkm4C23wHoeiGdLc3PzL\nU6s+NBqhdvXxYEzz+WBlspb8hAJTLjZq7V7je5fztCmUs+vSKq1men6rj6jD\n/bXTlQEbMf7yJlZ3+Y1SJUeIicTFbxItCEET/NjTKQlhmbSdifRsHgyDOlhF\nUwskMrUOkWck1rgcujTSr/OBJpBAo3/FE1Qgsz0XCSjaE8yI62wv/7EW0jSv\n+GTOvzoU77WBQVyFSTfHNHDfyYwn2LC4sT5ZNZTeQ4lsoPBc5kZNUSMcZqeR\nSeZgadofI5tpsVUlEov3Z8lWeRsP7RLQbnXsIOrQVSsYN6oUQD9aeErfbxL1\nTKR4fBQuxucPetpao6igH9Pcl5kDS+SluBJHFJE7cnJQOnfhhvrjMr4Ta7wG\nXPKOUfITDlszfF4KR3jVGahSsrxQpXR6vPv22Jw2YzUzHxXH0gX2+2YYl/Mc\n9vT5vGlkexMHGnzEy/FdE1MpNbY3M0oJCcnGdH+KHDnkHiqgSchTv0OjUSkV\nuJi/5g8oWt5fMfFbQDBXUbUjgKfSo0gsoAccD9H2hBbXCZLA6bl8bLMQ1huj\nmsbp\r\n=/IhM\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQClnH8P6pe0RuN42nSiffoj+uUoZBEtphNjGFryUwx6tAIgCmLf7Ob6RdeFVNnUP4MJuKi3n6g8f428cB9Y6/iV/Wg="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.0.0_1613030326706_0.5448690323792151"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.0.1":{"name":"@hal-wang/cloudbase-access","version":"1.0.1","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js"},"gitHead":"3c74d6c654c242592b7cea47f5ede0b54cb6b49c","_id":"@hal-wang/cloudbase-access@1.0.1","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-WUuOvCHaKLFJzh4BeFR34oIGfvBkJZzrYJL+mRcKDzf2NXn7mhMtBnKOCXh/xqVxq3eWAQGJ6bTStR7KxMUoqQ==","shasum":"a39ed850ab0985c5ec32947bac4ef54e4bfa6cb3","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.0.1.tgz","fileCount":96,"unpackedSize":91506,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgJOcaCRA9TVsSAnZWagAAGgsQAJHq+d7osp3nR+Por33t\nseO08DR0qJO97KJm3DwOJ6hhb76+IqBqmzZMmWc2IIrWa5bMkQZV6IUkjk5c\nU6F9fGWSXGqocw5x+f3xF/yp0g65HpDBrX5VgT8fbPVXpfVqAEvkU8+3M5Wy\nIP51w17wO2e7TMW8MlQ/bl7K0B1qdUfHKB3NBDesEaUqJuJFVqsq7OcnRB/9\nRllq3GWHlNev8nOWaKpzoiU4hB4YXUXIRjaTvPkjP7NRDiQcQRhu184BYtPC\n+x2vouz3PcP9iokmhuSrzAh4mf/cVQPkwxuWdE8ayxkaujKVbnf10AEoqYTt\nq19cfk1uEQ5Uz6aGcHOAVDgD5w407JmiNum4l3pXVjh1AR6pTTiQotu00dEX\nxEaluCgwhnIt0UwPYc1AKAv9MmhNOS/h56GSap2brSTpUercIn1gPcTAmSWb\n/88QlwI6yMJ+lNXOjsnviy0BfxT7h1QSg+86i+AQa6MckIIvM4rgqZxAx//u\nWBvKywWWhBuYqgDdsBfRPpj0Hq0qsIJ6aNFA+NmTaEcgPQqi6AKm9CDqb71x\nhmaHf5GMP/JQ3eMtUKh+BoEAcM+R7vWao1N3BSwAHLNXxdYEzoRLWe0yhIWA\nogd4eGzdLTFKKRlRl3ewuAQFvdKXAXGQ3zzWQdAv5NVsvZyxrk3SWYH7u2OB\nXbCb\r\n=snVw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC0gGMhOiA4nDYEtx9HDt52B5u7xpDSvz0qrvF8kkQnJAIhAPdCe/V2o6BN2GI5c4ubPZwSQDxWXYXoHo4iicFt76Go"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.0.1_1613031194479_0.25472511920690066"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.0.2":{"name":"@hal-wang/cloudbase-access","version":"1.0.2","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js"},"gitHead":"a87693b0795170e38c9ee5bf01d209354bbeeb21","_id":"@hal-wang/cloudbase-access@1.0.2","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-22ZtyVXDYF5ybEOeuxoPHafEu8bU6Z9OJizVAU7pP5vhmq+xqxFc/5hmi2p+YTqu5FkPKIk29mLaoZA9zGJ+cA==","shasum":"dfe19e4cfc3ab6575cbf182dddca325df3bd09f4","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.0.2.tgz","fileCount":96,"unpackedSize":91583,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgJl3VCRA9TVsSAnZWagAAEKMQAKKLWQ9XC69+arYenjbg\nGDnpdkLvD4I48dblFghC42BmN1cQapBW+PF7fnuESrDcmKbzEJhAohtPzbyK\n0UlAsKBRs+JIlh9RDdbcmMDLvYl5upyUe0bTZ4aU6w+0q/QAl4lOWzsEG9Vl\nSL8fOXj9PDNx5yBbRY+ZGDcjIHRiUobyyYPRFQMK++nZVfwmELivBChTs20y\nuAgyZL1WvkRLlzqf15HIYTajdTEdDaYRGhPbUDs66xWFEYolYoJ5p3uw2aiY\nPhPieRJ99hiJYbGHAgQj5iM/Xkj1q5eLHfCvdPh/l/IkUGOHTgocrwkMgfpD\nloQmM/5fY1KirZjK/vKBPvtMFVXmhXjUH7kMaT0SVsK2lxeXmlAYwSZy7UGG\nk1MgRgsRNBm6knGtivjG8TZRttAgjCcRu4v81B519/C+V9s85Y7bOAs21WbD\nXXDBnmN452X2KxxgNCxe8LZh+OfTfradj1Cj/tmtknKqZkZCJNImALuGYBQB\ne5Uy/nihFEl2n9sr1RWZxtIRgzs9EMp9RSG72w3aca2z5XNBewnFgGLQG/xa\ns394ch0RC78+WDXU1x43+L8Wa2q6WDb8yd1oeA8mwgGrq0RjZ7ZXd33oRVPw\npw6XCF1YPr5eDQ1NDT2jVKqu/2IY10iksqa+w/ONo7nP6h8lp4GlYL3jT1zt\nEJIl\r\n=2sFB\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIG49npCZboBKdsLzxD2BL1amIRjCkMvvc0LT/8dfftj9AiAQEOxqXg+C0Sm2l+bppmtqbfvCiAU+ubVYhFZkUgrX3Q=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.0.2_1613127125107_0.9930387652335042"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.0.3":{"name":"@hal-wang/cloudbase-access","version":"1.0.3","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js"},"gitHead":"3f88f11379620c9d273275bea9e2ddc898ec0609","_id":"@hal-wang/cloudbase-access@1.0.3","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-ybLGgwjfK+A0pdJeOCRY5io5COOfFVsyY8IYNexLV4ChQjaYOBSLp7KV71YSW0RwoALteV8EPGUB2CqM8gV2Hg==","shasum":"1ec972fe9b4329d214b222cf5e98e851a71e9186","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.0.3.tgz","fileCount":99,"unpackedSize":92964,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgPLrUCRA9TVsSAnZWagAASWoP/ilkt1iV8j7HEzKLZl9y\nwNdc4sM901QZiQQqlKAV01sd6jFCZCjlU4cQ+WMzC48HhtKnfijs1yqeDuOZ\nrU9HIortPhWy1wsVruA0uVpKfTNk4yiflNrcG0CZSneQrorXakIeIwHY9EmV\n20mWajACeOJw7nTIfG3rvk65JIEL4e6iUP5+MTgTZEIiyA3LRJWJ96sUf3by\nC2B3/RjBUYjoAORjlU1JB0JPGvBdAfBtHrY+C2E/AD3DDiSjnuuD4DZjuxMi\nQeRS5PaIHtSkeRz6Kok56Mm4xfMuAirQlpoWx5B3DztlWYJrbPZH+e1dV151\nKiD2GE9q89or12cvQocfoOxku8NumbV9eZU2H6WdYCje3PUmN84b7lzbSFPK\nzHNf0f/KXmFvfekD2kPUfM50MeANwVUI3ldBX0cxRUA7nJWljdJB/JqANnj+\nus6C1EP0CTAqrZ5oeTWO6g7MYaumolvKQYjIwFGKT9qKUNzaHed/9AFocSWk\nhWbyPynzoOwOFX5ZRlw5ebbWXBVgo3uNlx170YETr/b2u4MSisjZJkzY8gVH\nDIer13qcJyRs0klKywTHeYvQ7D9L6EGnKpRJwoP4ONIwKuhuxIVL61HjpJ+z\ncyWwcr8+7CtKVvh9mLPAS9bcZfZTVv3+p3qtV9iqN/g3vOmcsOEejTqEgtX2\nmwYe\r\n=/rJV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIG73pS/zPxAgxtFL98RuqXYM082H4kdAUfujoq6yy0K4AiEA7Lb99HPnPIGOZwDiJsnbJfzIrE+WYm7vdFzQfkCRRu0="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.0.3_1614592724118_0.851108915547917"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.0-beta.9":{"name":"@hal-wang/cloudbase-access","version":"1.1.0-beta.9","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"readme":"# cloudbase-access ( cba )\n\n利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n一个简易的 todo 项目，包含后端和前端，详情请查看 `demo/cba-todo` (<https://cba-todo.hal.wang/docs>)\n\n你可以体验线上示例: <https://cba-todo.hal.wang>\n\n也可以一键部署到自己的 `cloudbase`\n\n[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fcloudbase-access&workDir=demo%2Fcba-todo&branch=main)\n\n或者你也可以查看本项目 `test` 文件夹中的一些单元测试\n\n## 建议\n\n强烈建议使用 `typescript` 并生成 `javascript` 代码后上传，可参考 `demo/cba-todo` (<https://cba-todo.hal.wang/docs>)，做法是 ts 生成 js 文件，并删除 `.d.ts` 文件。\n\n理论上 `javascript` 完全没问题，但作者并未进行测试。\n\n## Router\n\n路由管理类，也是 `cba` 的控制中心。构造函数传入环境 `event` 和 `context`。\n\n如在 `main` 函数中：\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  return (await router.do()).result;\n};\n```\n\n以上几行代码即创建一个简单的 RESTful 规范的 API。\n\n如果访问的路径不存在，会返回 404 NotFound 结构。\n\n### 权限参数\n\n`Router` 第三个参数（可选）传入权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### controllers 目录\n\n`Router` 第四个参数（可选）传入 `controllers` 目录名称，默认为 `controllers`，建议不传此参数，即 `controllers`。\n\n所有 `controllers` 统一放在这个文件夹中，在 `controllers` 目录中，建立各 `controller` 文件夹，再在 `controller` 文件夹中建 `action` 文件。详情后面 [##Action](##Action) 部分有介绍。\n\n### 路由匹配\n\n在`cba`中，路由与文件系统匹配。\n\n路由查询参数命名以 `^` 开头（文件系统中命名不允许出现字符 `:`），如果存在多个查询参数则后面的会覆盖前面的，如 `get user/^id/todo/^id`，则 `id` 值为 `todoId`。正确命名应如 `user/^userId/todo/^todoId`。\n\n如果限制 `httpMethod`, `action` 应以 `post.ts`、`get.ts`、`delete.ts`、`patch.ts`、`put.ts` （或 `.js` ）命名，否则任意 `httpMethod` 都可以访问。\n\n#### isMethodNecessary\n\n如果设置 `router.isMethodNecessary = true;`, 则所有 `Action` 必须严格使用 `httpMethod` 命名，与 RESTFul 规范相符。否则会找不到路由并返回 `404`。\n\n如果 `isMethodNecessary` 为 `false` 或不设置，则 RESTFul 规范的 API 可能会以非 RESTFul 方式调用。如路由 `user/login`，本应是 `get user/login`，但 `post user/login/get` 也能调用。因此如果使用 RESTFul，建议设置 `isMethodNecessary` 为 `true`。\n\n#### 例 1\n\n获取 todo list\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- get.ts\n```\n\n访问地址为 `get /todo`，\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoList.ts\n```\n\n访问地址为 `get /todo/getTodoList` 、 `post /todo/getTodoList` 、 `put /todo/getTodoList` 等等，效果相同。\n\n#### 例 2\n\n获取单个 todo item\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- ^id\n|           +-- get.ts\n```\n\n访问地址为 `get /todo/66`\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoItem.ts\n```\n\n访问地址为 `get(post 等) /todo/getTodoItem`，需要在 `body` 、 `header` 或 `queryParams` 传入 `todoId` 参数\n\n#### 示例建议\n\n上述两个示例都给了两种定义方式。\n\ncloudbase 云函数没有限制 httpMethod，但建议使用方式 1 更符合规范，易读性也更好。\n\n因此建议设置 router.isMethodNecessary 为 true 。\n\n## HttpResult\n\n`HttpResult` 封装了 HTTP 返回结构。可在构造函数传入相关参数。\n\n`HttpResult` 有个属性 `result` ，可获取最终 HTTP 返回结构 `HttpResultStruct` 。\n\n### 内置类型\n\n目前 `HttpResult` 内置一些返回类型，都是以静态方式调用：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- methodNotAllowed, 405\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nreturn HttpResult.ok(\"success\");\n```\n\n普通内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，命名以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n### 举例\n\n以下例子中返回 200 请求成功：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.ok({\n  list: [],\n  count: 0,\n});\n```\n\n以下例子中返回 400 请求错误：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.badRequestMsg({ message: \"请求错误\" });\n// 或 return HttpResult.badRequest(\"请求错误\");\n```\n\n### 在 Action 中\n\n在 `Action` 中已经加入了 `HttpResult` 内置函数，可以直接以 `this.func` 方式调用\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n    // or return this.ok('success');\n  }\n}\n```\n\n## 请求参数\n\n`RequestParams` 类解析并封装请求参数，构造函数传入云函数 `event` 和 `context`。\n\n在 `Action` 中，有 `RequestParams` 实例对象 `requestParams`，可通过 `this.requestParams` 方式使用。\n\n实例包含以下字段\n\n### event\n\n云函数环境 event\n\n### context\n\n云函数环境 context\n\n### path\n\n访问路径，如`POST https://domain.com/api/user/login`，path 值为`user/login`。\n\n_注意：在 event 中，path 实为 `/` 开头，上例为 `/user/login`。但在 `cba` 中移除了开头的 `/`_\n\n### headers\n\n请求头部\n\n### params\n\n查询参数\n\n### data\n\n请求 body，如果是 JSON 字符串，则转为 JSON 对象。\n\n在 event 中，json 为字符串，在 `RequestParams` 中已解析。\n\n### query\n\nv0.9.0 中新增。\n\nRESTFul 规范的路径中查询参数。如 `user/:id` 调用时是 `user/66`，在 query 中即存在\n\n```ts\nquery.id == \"66\"; // true;\n```\n\n## Action\n\n每次调用 API，如果顺利进行，主要执行的是 `Action` 中的 `do` 函数。\n\n所有 `Action` 都应派生自 `Action` 类，并重写 `do` 函数。\n\n### 创建一个 Action\n\n1. 在云函数根目录（即与 index.ts 同级）创建名为`controllers`文件夹。也可以为其他，需要在 Router 构造函数第四个参数可以指定，默认为`controllers`\n1. 根据各业务，创建不同 controller 文件夹，名称自定，但名称与路由名称对应。\n1. 在 controller 文件夹中，创建`.ts`文件，每个`.ts`文件对应一个`action`\n1. 在`.ts`文件中创建类，并继承 `Action`，重写 `do` 函数\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n  }\n}\n```\n\n### Action 文件内容\n\n在`.ts`文件中，模块返回一个类，该类继承 `Action`，构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n例 1\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    const { account, password } = this.requestParams.data\n\n    if(/*账号或密码错误*/) return this.notFound('账号或密码错误')\n    return this.ok(new {/*返回信息*/})\n  }\n}\n```\n\n例 2\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async do(): Promise<HttpResult> {\n    const { account } = this.requestParams.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    return this.ok(todoList);\n  }\n}\n```\n\n## 中间件\n\n中间件可以在 API 每次调用的生命周期各个阶段执行，如记录日志，验证权限等。\n\n所有中间件应派生自类 `Middleware`，实现 `do` 函数，返回 `MiddlewareResult`\n\n### 中间件类型\n\n在 `cba` 中，中间件有以下几种类别：\n\n1.  BeforeStart： `Action` 初始化前调用\n1.  BeforeAction： `Action` 执行前调用\n1.  BeforeEnd： `Action` 执行后调用\n1.  BeforeSuccessEnd： `Action` 执行后，而且返回结果为 2xx 时调用\n1.  BeforeErrEnd： `Action` 执行后，而且返回结果不为 2xx 时调用\n\n类型为 `BeforeStart` 的中间件执行时，`Action` 未被加载，也未进行路由匹配，因此无法获取 `query`, `roles` 等。\n\n类型为 `BeforeStart` 和 `BeforeAction` 的中间件执行时，`Action` 未执行，因此无法获取 `Action` 执行结果。\n\n### 中间件结果\n\n```ts\n// 成功\nreturn new MiddlewareResult(true);\n// 或\nreturn MiddlewareResult.getSuccessResult();\n\n// 失败\nreturn new MiddlewareResult(\n  false,\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n// 或\nreturn MiddlewareResult.getFailedResult(\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n```\n\n如果返回失败，则 API 此次调用结束，返回中间件结果。\n\n### 注册中间件\n\n你需要使用 router.configure 注册中间件，如\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  router.configure(new YourMiddleware());\n  return (await router.do()).result;\n};\n```\n\n## 权限\n\n`Router` 构造函数第三个参数是权限验证 `Authority` 对象。\n\n你需要新写个类，继承 `Authority`，并实现 `do` 函数。\n\n其实 `Authority` 也是个中间件，只是加载方式较特殊。当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同。\n\n权限是用于判断用户能否使用 API，可以精确到控制每个 `Action` 。下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```ts\nclass Auth extends Authority {\n  async do(): Promise<MiddlewareResult> {\n    if (!this.roles || !this.roles.length) {\n      return MiddlewareResult.getSuccessResult();\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      return MiddlewareResult.getFailedResult(\n        HttpResult.forbidden(\"账号或密码错误\")\n      );\n    }\n\n    return MiddlewareResult.getSuccessResult();\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.requestParams.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context, new Auth());\n  return (await router.do()).result;\n};\n```\n\n## cba-map\n\n`cba-map` 是可选的，它能提升路由匹配速度，其本身为 json 文件，并且要上传至 `cloudbase`云函数根目录。\n\n### 建议使用\n\n如果不使用`cba-map`，路由匹配方式是先遍历 `controllers` 中的各个 `action`，再进行匹配，如果项目较大可能会影响匹配速度。\n\n在 100 个 `action` 的项目中，经测试`cba-map`提升路由匹配速度大概 20 倍左右（有 `cba-map` 耗时 1-2ms，无`cba-map`耗时 30-40ms）。因此在 `action` 数量较多时建议使用 `cba-map`。\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-map\": \"cba-map dist/controllers\",\n  },\n```\n\n`dist/controllers` 应改为你的 js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录。\n\n执行 `npm run cba-map` 会以`dist/controllers`目录，在项目目录下生成 `cba-map.json` 文件（建议将其加入 `.gitignore`文件）。\n","readmeFilename":"README.md","gitHead":"3d19b8de93591cf9e815c7551c69f5861d9a4ad5","_id":"@hal-wang/cloudbase-access@1.1.0-beta.9","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-PZIZY0i68um5GzIVPn+xvwmZQ2pDE6ExkfWcmpDWD4KjPRrHdWXxI528Rq9zdbtgrv8vjDHfJYGnKG20kxG7Tw==","shasum":"bdda27967f2a73aa1a3eaa11146c34853a1f1656","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.0-beta.9.tgz","fileCount":145,"unpackedSize":143545,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgQJcWCRA9TVsSAnZWagAAByAQAJfsZmDZSZiSxhaBSOo0\ngtsp/FNPXHaML57xZ1GSXNGXXerNE/kUlT9RdnMPVof7fwYr1Z4BlN/0/PIN\naGHd+D7elcXc/OpDLxZDc2m7WgeXyTFu5e2ZbSnB4PfVzRbZ8zQ9dxkPcULn\nt0nDKwKsQ6crPohTeu+9N1jUPWCGSmsxmZduPoXCpqMCTm4uRNOMXDjmtMlU\nwJuqKiSq++FtkpKnd7yoMn9EgRR6Fc8YDbqlnnjSeeHlH0jXvcQOd088hPqW\nL6qoly7cXfdTIp04FJb2dVObbLNwwNTrpEulsTSeqJZjM4Lw6Cci9F55iago\nW1bf149hKCgNPQlzYQftx6XEK2d7/GMZVWYMlp+aSEwJKzwS/F4xmVK+nnti\nNezkeJoLqFhKdT+8nGqhgOUvHY6RRo8L9g+FXU57aqPY3kWZpePTI6AucB/r\nbRvokipJFLDzQcgK1xdHqzLQrquVBBrnInPQeUcoCVLOWqczm6polkn8nup8\nSmkvPOI7JhrQ+cO2wlbcMzDQlpm0nN07yoPRDK8ix02zlAxXpvVgBTz8oMtc\nFFFST7MCW2h7f6X+sgNjOFZBtT6e7e/vPeG/GC7I6s/YIj3QjZnOSpAh9AOV\nUln7HihfegfKMTm9IHYLJsbGK08PuaAxtOMG+lfA6w21VQaTDJM5w5xCmdCv\nyeVp\r\n=hSsu\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDnTBczYTUoUcbxykl8Ne24aJMyYj4lO2oxHvvmKd7Q5AIgRmHUaW0EaDDuWHDoqE3RSV2eJ8h344cxOl4Ng+bVW+s="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.0-beta.9_1614845717979_0.26336614152578997"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.0":{"name":"@hal-wang/cloudbase-access","version":"1.1.0","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"8a444d575b2e03691cfd8f9597b128c830231dd5","_id":"@hal-wang/cloudbase-access@1.1.0","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-qwPwpeRim6PNKdsac8jRBujyRaU2Ybwdo6SG9WAtBap5bF2zsoYHWsqOCG3pzK5h6LD5t9lgW46WkJErbptjKA==","shasum":"a828ec6eaefb77d372b39865658f2e55de163d65","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.0.tgz","fileCount":145,"unpackedSize":151133,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgQK5LCRA9TVsSAnZWagAAczoP/2yVuDVQnIGp5LitvzB8\nnnjuHBc1Py8SO2TM2P0YmO8lLuEQsvLXBRHdH9+kiXomZYHcJG89yzoqEzqB\nex1JwvtO7wLwjKvPlBKF6WmpzBZK9Hn7svbqdlydNlKHfqOFxkcnNyj4QydS\nWu18Qud+LJZVuDbTpzbFoWZ0b1XbeFaLlF0xw9TqDlxrxlBMsfdypk7uuFSm\nZducYB0B0ZQ4m2kCtJAnCpE78SZQWE86GaXk6+NWDpOWHSRNTXIXCKMvpOZk\nUegwjGUeit4YtRqBFtC7h1QceaSgozrCg9WEzjMqF4+fhQZ5Nwhu1VUU03iq\nSP0+2AKo6ReNgSgOOK/PrQzd8OvOmqUbljfQyv4ZqxxAlkjq4jzixuNCsS7r\nI+8bebovoH9HKztPVW/ZZDfn5v9/THa6wMIsstsz9bZ4H61+cLRjr37q42+Q\n3ODZeLOf6drgLzYreN+lLQsENMbC5tHRQ7eahD7ypew1ltXxbeo33BDf2PoK\noHEpjgvPtJJBYgPbRb8qFcncS4zOYSQTnzDYIoKP5ygSePLtpkUALc2K3WD8\n5F7xQvFnir3w55fIYy//8j0RbcCsEEXW/heD5ISbLCXq0RC/7YGTRIpbclyg\nPyqHxJs57cchxUODdEBjN9mmme+R8ey2nXAXWzZ9DeoR03DUTjONwJSvNx1o\ndiJa\r\n=Pc2Y\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDylHo6MSEnLHDuhPM8lxJYuVgEJRXyUERrynGS1ebjSAiBSh4Cs0SRaIBIIxMiWy6VBmv0ZV6DkKheegRLWscsbNg=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.0_1614851659397_0.8349596663196017"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.1":{"name":"@hal-wang/cloudbase-access","version":"1.1.1","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"7e03345f8c28bbb1a68af687bab3b0db83bb1709","_id":"@hal-wang/cloudbase-access@1.1.1","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-MYNTWllPjEioyPl7nKlhXn7DETzpD3b8u4EFzvSo+RfyIeWZ5OuIWAR8GK78nrPLS0707Q7oBA2gvQ5Q3popXQ==","shasum":"ecf7b3b19fdbea7311e8a231825d85cba78e65cf","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.1.tgz","fileCount":146,"unpackedSize":151708,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgQfZUCRA9TVsSAnZWagAAPe8P/iuk8HUa/TU6HB02ScSn\nL5bxqGqy9eldwvluJEzFTdt3pmDcoCvPIivpW+PzPr01Himh5SRMu0MF9ax6\n37FgRo90bWFcyzNfVk6GuEDgRMiXScW/2l24svmCf1uuO/bA1lw/KlaaR2Uy\nVJSCEGHK0H7wL8WW04nHGSCa8k+LaiBRkQQ9EqeLR9OkU3pim110GlvXqb26\nfNOHm44z6SP6tkNB0NT8ZEbMSuDHUWxy49drBbE+L4UVjMTu4LNVOpErakpu\n3hKmT22mVb3GQlqHIH2+MmrWglDyZmRWlLaqc5DG61SFPFlKHiBbptXW999B\na9JK36GAhF2NsIlt//JkVbJNSptBpYTfaoXU9Ve30xE8mYkk0VU18d3F/5ar\nd9f1CZPdLvll9NkwPG8PywOQWXp9F6OJyP8X8QdMVnxMCeB1ITX9TkD2nXi/\nY+7S5M9UteztJH5Ddusj2LOnTJTx8svD/LjZPWfoWzU9MGU+u0c2BVz6DMAz\n0bdCZ1JHB8cgOtFAIW63JdpIlsTj87JBe+PnSYfSlxUcEK5w2ZkLm9BoPhp3\nkCqXbSr3csQMqXju8HNdrV8AmlUUtvRKLhLJLY/StxieqElyXjyFgXu+/wDd\nqx/r9ICHqnfpg3bzA8MU+iHG/jGwezUcDBP9sQNmAEd2kcGdkrapOHX2AnHt\nnjcI\r\n=3mzc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEeRh0lZ5S9RkgcrLY9GMaoXooCi0XRrrbT89oOg0GfPAiEA1NBp5IeSLLuwi1mDu5WksNxia/BtqmwfOhJuoCqFiHw="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.1_1614935636275_0.9364516872458386"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.2":{"name":"@hal-wang/cloudbase-access","version":"1.1.2","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"20e528e9eff8a96899a7b1a0c5e1db1883677b6b","_id":"@hal-wang/cloudbase-access@1.1.2","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-B7GkIMCszdSfLmD9ejNgpMXSiN1HtormLEsr2KRTT0ycJ5lZ8nGCsBViN01Qx9PJjEx0FmP7H3Dl5S0ImXlAZg==","shasum":"f4b34ff285fbd9bef6c5e97e7bbb60df63dca94c","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.2.tgz","fileCount":161,"unpackedSize":154953,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgQxKpCRA9TVsSAnZWagAA5EAQAIiCgS3W6Cg2v3rxEYvx\nfcFCHDJ4tSjmANqYwfsAKVVDSUwn0iVLLU/jjfLqrAB74wVut+IFLXAOl7f/\neRxAc1tTdO51rnERDx9wFlQL2bouhLVv4x5AVcTA0qV3Gbni3txhz64KHusP\nFh3DOLRnwHbIWZVsytNSuIsCTCQtZYdOz61ONhaIRGRDB7dRjVDndma+jOG/\nfB5HvOIa3nka4gOA3H2o+TiV2kcvDIcT2EpZobJ3S+irUODUmGtCs8MtVxNy\nbuRWLw+tiwZa5XeYxZ4IYnDLJP4JeV0xale68be2CK6MXPSEKfWHwhc31098\nPrUXyWmxrAUBXAeXeJ5x/dpJjN3hh1uwen3iMa//Ua2JRCfOs0N1kD3A/FM3\nvD6IJDUkl5smfgU+GEXIkYWWztXx+i6o7QhSBYsfKQ1oWgxQD4luAjRely9q\nwuPkklec9I0i2sBPPLjee6og56MwABGM5R8ulAYOtO5RAwXg85jQF9I9e2J0\npO/btOqr7Yz/p++ZJV2gQmvdJ0FK0IYos8WrXtl6HDIxK73cYOv3V1j5V08D\nO97e/M++MIosWpv81r5cjsrXPvLM0Y4awj4NnfeKcJI4wat4XuN8ZPGslwKK\nCoB+7rAVbGmk/mwbelUAccxTgB+DUPft4m+xRDDH17k92qvl+xg8d1nG3VGz\nm7Iv\r\n=dDQ1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEHQ4prjkmU/QKar6qIjoGGgOyvgGEX2G8knyFqrN+jXAiEAvKKGLBQ24jpI5ceJHXKmTVpgPyfmwzDWH+SlFpGKtIA="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.2_1615008425117_0.003988507166612587"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.3":{"name":"@hal-wang/cloudbase-access","version":"1.1.3","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"2ad50fba45f8c204c18c1df71f25da5880a56dbc","_id":"@hal-wang/cloudbase-access@1.1.3","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-E/Tjs2ja+lHr5Xourv+WIxgfzx6Ei1wF2i/kUqMlY5eBUxqh4YupAxLOP6/dxO3FsxigiiAjyD+9yKXV7QTQYQ==","shasum":"7018b69c89ac9443df71bcfd986ae123b3a21f9d","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.3.tgz","fileCount":161,"unpackedSize":157778,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgQx8NCRA9TVsSAnZWagAAw1EP/3ihnzxlyX3rixPufAKL\nPjkpNUJNCEc9F4R8ky5NQ4d8uY9ak1hGsu7H8F+PXjRtmh7IBhayBlYodTjC\nd98GyKOTTKdiSYJXT0NlDWZc0knlNY+15Ff2t0V/YmVCt7LvqFtE0pkDiYNP\nj7dGSw26GdOYpwypmiye5oIzBwQdZoS7W0onTHbBtcd9Djkld6JNo/a/dHUZ\ng/hlmoD/TCLZgpq6ALVIyGPckjXj/vg1n8chDO4UNIUbtcLk9h1kcg2/34LJ\n+bfRmAk2jHGzkc7JO9sucO4OhsdFXQIpNTGdnyyJ6+dKp8auIUJbcIuysZ3u\n9qgAJALtdcI+g98AXGR7Jq08GyKxop6dbAQMlGzIzBmHjqUy9Xzyw5Ymms1b\nO58qlsiZRbjPCE1roFDLWkHoLZ4deFsCb7D2nxxLdwhDgom3wt7KBw9j+AmB\nen4R4MDTfXmgD3PNmJvB6FJyW7Ch5roZcBl2f8XU5Ts+TbX1fW8d6AKrdw7S\nTBeqZJnnhCyP63R+YCr5jT6TKilioeYs+04ck1CAkEoCXcPHyQwcc6d6kMn2\nRpiXtWYqtr5YBFjx3FGv4wBEz0cLfGi+iRt9Ku/dq7xncuwjTV4NdHYUpjME\nC4hWxKWtmEuy3nMxCftNlhqWGQkCF/1SdifT5n0U9GNL8G0DSARk4BV8oi3I\nC50M\r\n=Baao\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIHAWZEQ2F5e6fjeK2EIjPPejkq9EzTtyi9UIlGViNGvfAiAugTFIKZrFz1iw7ZAprY/k3FFxmMNzC0waKWsU4wTuDg=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.3_1615011596542_0.5612848174067608"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.4":{"name":"@hal-wang/cloudbase-access","version":"1.1.4","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"3f83f3ffd3526bbb3503e84ea58695ce66c53a0a","_id":"@hal-wang/cloudbase-access@1.1.4","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-o6uz9qWdvvhu2gTio0VSzDmrMWd8oyQesbZmxSuRKHSw7zMf8upKUK1Zwzpni4d2ENMGtiHvVqrJYY95/l0sMw==","shasum":"68dc3ba1102b0511c919b7ef39ff67a3013e5805","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.4.tgz","fileCount":164,"unpackedSize":159495,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgRjpFCRA9TVsSAnZWagAAdr8P/ja5Q0BQL2tVSVW6EdD5\nKGyrwrgDjTrwdCtE0DAMQ8B1Lw5QHANg//eWtuCDogReSzXfed9glzoagBDn\nVyHgwz4+wvqrJVVw6f2Ac8wBsSO2P/o97X5WacqplfRPMo/pKLRavKbXkt26\n4q4kYxKrTNhEsj16BMfIm2hpwy4hC+yk3Md6ci9Abi6GNS/3Lk/VNZZPD/+p\nMMdRvhAxrT2K3wRajGANwU6Un04ydV3NxAuksJtKVT0AYnnyU6K4Pj6ZEyVd\nRQFd1GUX5Xyg8Z/MnCdd8Rjbvhf9Ml52Ge6Z2RC5rf3UvwGNOvk9dby/tRFn\ngL6ZaqAeWDIWimdw1IvtpL5I9WeyybSaB9bSVfBYWNAlyiEv7dSic5ptGGVw\nEX7Xxj6li5OrnsY4ikInKuE4F45oi0WBlrbAKgz6pRJvxSz9Yn9iH6smKVLA\noBZbETCAG+lvJWFiPuQEFR1YTuwR3xR4yESXu8XtTlc3FlOOCvdirEZD9ws6\ndmh8aKxWVkX85ez6P/ImbqDfthB/b0VenmsN44BY7heb+iG46N2JVn+wWS+r\nAMuIipczwxiICWtNRILE5PJrCJVf+iBbzMx4tSA0BS6faARlQ862YTwAUT9P\nqcT9+jN9wz3Bg67keMxF+2eelS+a7p4pQf3dIznjrnl3WyOm0VPddF8l6hFH\nCYVq\r\n=7AiX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIHRKT4dac/8RKeJWUZlgfGw9IJLR2bRA2e8BJviO1ri5AiEAyWeva7ym59VaQEsga+Q+2KHEKhpMenR9U9lzYYBwJYg="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.4_1615215172266_0.10948793158694858"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.5":{"name":"@hal-wang/cloudbase-access","version":"1.1.5","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"8135daba35cd1811eddaf4516a932b9dabcdc40b","_id":"@hal-wang/cloudbase-access@1.1.5","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-vxJiqFg9cyd76evfzcfUaDZtmSLbBTs2Fvov2Us/WVWTNvCLxPa/E3r6WHjY+m///pAOl/bxKXIUP61jk6t/GA==","shasum":"cc5102b54504345a2a8e78f1d37bf3ab1664c67b","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.5.tgz","fileCount":164,"unpackedSize":161616,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgRzPeCRA9TVsSAnZWagAAUuQQAJr2vRhRjHWszagjQ2sF\nWXqMuCXynrrbnkuWfsBhwJ+023pH4i6r5+mrfTN2vXn5J+j3z1NiKQ8wlGw5\nDQS49piXeE6U9ly1H/icZ5OLY+pEVQ0KlyqzE7cN8s1YzlTUeflKSXn/FJ72\nXLvSyDK5zeJqoHVe79YeO9qXScBg6+ubnV+zpwjtTc0VmuCwyBDX6rcYN0Mp\nVdGZIKRD0AGr9dpO01rEUaIl2jWVGVMuhgD33n2TJP0prqtWmSmVq9ORc9Nw\nMShPz3K8TQOnuYwWChUuHynj7FmIyP4IuyXFWimDRCilqTZPM/4JY5Hl3UPx\n8JDa6xE15g89oXXPsJ/ycREns8RqtbK5o7717FsJNXfaqh/pLVMsf2xq+dAX\ni5h6cHLqxcj7RtUVG8weWD9bHj5VV9Cn3xggZfj5JG6ujAEQu5YML4U827Bk\nDPy/UnBvMbpr+kl2iaLmSrUfD/qNLFb6IQMkHJITIVp5RG0o3XAqVAr06VPl\npQuJ3C8sxcvUD31nu25ej907nhv1bpUDftdctLc1o1+t2sWITPMImg+2km/d\njC0UcLd60AmL8vS3imkMv35x/NyMYIXH/Fk2CqyausetLRZRJkSAkM5t7Hp5\nuaeuq0nc6rjICS6CJZE80Ita2X4JI1vGdjYm3C2ffgdLFIfBy59bp5C6eX9A\nA1I5\r\n=ILjX\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEtpfsYljw7A2gJCjQhTu1RSc5djibtRNt4GSqUwFPnhAiEAwi7tWQ/xDobYRF9rVVKTTtYT1ORr7c3fYhaJtDF7YI4="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.5_1615279070030_0.4209104343538974"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.6":{"name":"@hal-wang/cloudbase-access","version":"1.1.6","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"44f1dc7bc72eb997bf565a1c90f9475ff4cccf56","_id":"@hal-wang/cloudbase-access@1.1.6","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-DGKBNKgT3U+ODcdEzBe2MRY06+ZnZFRwU4uqKcFcDM7RaRhoJNQXl5w9yVXSglPQ0cXOgM/JdjwR1fJQZpSM1A==","shasum":"6f02ff21ce1d2099432ffe1941b9524ca262cf1d","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.6.tgz","fileCount":165,"unpackedSize":164073,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgThHFCRA9TVsSAnZWagAAmz0P/j1h59myWiNYCQufJUyK\n4mV1OLQeMv7kIxCO2jlOCS3XbA9aiRUCOGh4GjrghjRm2vFNk+Ynh4JBy9AY\nEDeavMRINC8ODBmp+OfazfA/QHg75hMUufViY1e1n/MUPmpwtofCtL+pmOyB\nfat5gpO7FazPFhyq7G4EZd0oIMH5D8VA9wGshRiae/9WtnCCAAnjHet/z53p\n5iFsCYB6SQSWmAqp00M8tKgQMGp5nLjKHFU2Tb9km+jbuBJ3gidYGL9HF+6H\nBxJR4ELaTq9b4/tfWic+/uRfoEpUyBRGZM28TCPJtlyl0v5eJXOj4QnijyAl\nAhZLp6ujcZQOXp1MASzZ/WLwgZb6e704FdyVRyXwnm75vM1uxTQ1KCrTob2i\nTvB5NhbHTXV2KFW1Ki7h7d9YNYHVO+X1ok4bazkedRG/f2DwnSD8mfbKElN+\nS+ECNXytYXuIRtqVRESt6clr+zRoYcP0XqrVPx1QtmP8tOUERNAasR6NB8Xv\n3/Qd3k4r5a7BQG1A8V+RGbaBsdZ3u+e7crY2LAk35aUe4xPyI+sHtT1FaoMk\n2w9xl4ckFl2Z5fgiU/oxX/KAlLvPKnEypLrgVMDHqEGzT3B05Ww7CQ1r4FnK\nyUuDvS+VICqjeB5KdMsxwuTasSoCQx8U/5hq7H6ee4u+G2yOCsolqPC6dvna\nIDWw\r\n=tsPw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC/AnOny452Z2ZMHOPrXi18cu/vX4F4K/QSUBTQ/AY3jQIhAJ6mVprwM3PBavqw1r9LAW0+rzNf6ZkAic/k0vEZ72kX"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.6_1615729092813_0.4978453069126503"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.7":{"name":"@hal-wang/cloudbase-access","version":"1.1.7","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"6f3d90d0aa52e1253287206c044898e907420e9e","_id":"@hal-wang/cloudbase-access@1.1.7","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-7d08tLoedLfR0UWbT4xEez8/9aMspI0eokzqmF2J8Ild4vMawYYNnWANjcVdvS34CX21QjZn4DvSf+9FIg0gkQ==","shasum":"8bfabe16813508b06ca6e66ef9cb9f5794208606","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.7.tgz","fileCount":166,"unpackedSize":167566,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgUfnMCRA9TVsSAnZWagAAX20QAJKYepMLDTjRU6jP5NFu\n1fPuSrMnDMg0lc+HpC1skMmtKCX7PVtZYXd7dlk6UY0NVzqXLIsAvrv0F8tg\nVXkLa3t/zydWdXDFwsj7WIbo/Ad+sOH3lRO5bLICj9TTPr/Eg/VE8iTF0bxq\noqNnhVeCAaxPgWA2VZj+74+gfSJ9ETofWe40lacnJ4SlddjFLQMkpX8PlQO3\n6hr3p2DubQykmf1dMwGOkmTUNPtDsXzmgHQgFkbMtYLJBeGRwkjcOjYjs77D\nnpzfn/gN3ekfswaguGmFrSjS9/R9Mspm8ZCqRh/qL6h9bOtWjuOBu5Vvp4Fp\nzPczW4TxIeY4lMlixk0CidomVDR0BmXBQj6fZnXPSss2BTu46Omf0h1Vxqkd\nrmhL/1qL/dMgEC875yKveZZf6w1VMu/XBeYmRFEf1suNH1zOIsiWD/scEQWC\n4xPTU0RYnhFJYmhlKzMm6N6iHvGIlsCycWotG0sY9hmFq9CLTongd7gs5mGg\nz2wexJUWHi95Z3Dtv9NWKbKzQd6Av0jSudqfNaD+mSvP30bL9N/LvejdVZsL\nQt7XzYAOr1/NjOuF0dbvj8NOsudQg9BrgKXzvpDlMC+iMeHlAb6YBOTcZyBI\nAdXRd8R5T24dvOBVNIrfFrWs+fHPKBJgah1zf1SJNgJExPj8fD8gnK6NynNU\nDuEj\r\n=MpB5\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIBSAQp863604vs12ou17Jqt9lE4adKKwlnMEHa64G/OiAiAY0HH5t71VbzOX4+Z/pf61pZlguiOO6+v7SKe1+hqPYw=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.7_1615985099981_0.39588550038971104"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.1.8":{"name":"@hal-wang/cloudbase-access","version":"1.1.8","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"ae3d4adcff1eda41f8b478e058d46c4f8672de23","_id":"@hal-wang/cloudbase-access@1.1.8","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-A2O/3Q+yVwO/l9PDdD64OLUf3H5vxm5svGifM2rnqBYjv4onPMuSLLCWulSiMOxEEZQeMwyf8R2RFZQvr/ekhw==","shasum":"02c244509c67e9f2519e94cbdfa32bfa57b326b0","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.1.8.tgz","fileCount":174,"unpackedSize":174191,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgUg7gCRA9TVsSAnZWagAAAlQP/R0KMS52PAbXZyggte0m\nmUPnKU1Z6yX+Fv3Wyosk8SJHPxMwC8LRrqHvHkj4CK/EZi6lbEquTkwQBUje\nZ+5UIXdLMWJRa9sYBS0WPWycCQTCNFwAYkx7h8MyrTV+vBT3KlQrb/Zh8Gey\nVeJ9TYRze7WNbKSWSPMBo2Er0eBByb6c4XVzc1kcW6UnB07auRbjvvSa7oEp\naEDKRf+dGX5KB1JuReQDzD69niRtejtKJBJx/iwKxFpP4ltai1+QMkfQ1fXt\n1ns/h6HlBoYG2YmmbYMSlW6/ANo0uVXMu20r/0i671/jM5DP/oRNO0k39CgU\nVFriQHTj0mvvsIqs4cmKL4hLsAlQxap6oTM+mTg/r7S4Fm1bv+p67iFMBG7J\naHTn4OsFNlnEmq9jWPJgBHsOHkhwUlREWJl1k4hNNiBizonlRmAypXttRdLh\nsqhd4PtMSa3BPqkNzEUY1peLuk5WjRRJCXBP1BvBSiDAxO+eTnvUyjzvUjni\n5dzOnDV4YHHtJ6KDD03MfW97AJn4nIqxaFCAjcI0zHyzSMKnsfuDVhzZU0zn\negZ7SPr/28DSbu4b4jknBZvgXoO6SFNT61RcUwRrfB/c7ZF82CAj65WNBJ7y\n/4xzLXIdrUCOW/71m9Bv5F0yTZ6PLhnyvfO7stNahH6CdrZsWAiBqsSDqjUh\nZ9/q\r\n=kOkx\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCeW0eg6SfMzHb4OZ8Sk0ThKlvVpVV473Xm1QDDwC0wlAIhAJg8RWG7/0zGNOrX8l7YxkG3UZUgUH1G/7iu9D0pzh3F"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.1.8_1615990495860_0.19175763525705958"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.0-beta.1":{"name":"@hal-wang/cloudbase-access","version":"1.2.0-beta.1","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"readme":"# cloudbase-access ( cba )\n\n利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n一个简易的 todo 项目，包含后端和前端，详情请查看 `demo/cba-todo` (<https://cba-todo.hal.wang/docs>)\n\n你可以体验线上示例: <https://cba-todo.hal.wang>\n\n也可以一键部署到自己的 `cloudbase`\n\n[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fcloudbase-access&workDir=demo%2Fcba-todo&branch=main)\n\n或者你也可以查看本项目 `test` 文件夹中的一些单元测试\n\n## 建议\n\n强烈建议使用 `typescript` 并生成 `javascript` 代码后上传，可参考 `demo/cba-todo` (<https://cba-todo.hal.wang/docs>)，做法是 ts 生成 js 文件，并删除 `.d.ts` 文件。\n\n理论上 `javascript` 完全没问题，但作者并未进行测试。\n\n## Router\n\n路由管理类，也是 `cba` 的控制中心。构造函数传入环境 `event` 和 `context`。\n\n如在 `main` 函数中：\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  return (await router.do()).result;\n};\n```\n\n以上几行代码即创建一个简单的 RESTful 规范的 API。\n\n如果访问的路径不存在，会返回 404 NotFound 结构。\n\n### 权限参数\n\n`Router` 第三个参数（可选）传入权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### controllers 目录\n\n`Router` 第四个参数（可选）传入 `controllers` 目录名称，默认为 `controllers`，建议不传此参数，即 `controllers`。\n\n所有 `controllers` 统一放在这个文件夹中，在 `controllers` 目录中，建立各 `controller` 文件夹，再在 `controller` 文件夹中建 `action` 文件。详情后面 [##Action](##Action) 部分有介绍。\n\n### 路由匹配\n\n在`cba`中，路由与文件系统匹配。\n\n路由查询参数命名以 `^` 开头（文件系统中命名不允许出现字符 `:`），如果存在多个查询参数则后面的会覆盖前面的，如 `get user/^id/todo/^id`，则 `id` 值为 `todoId`。正确命名应如 `user/^userId/todo/^todoId`。\n\n如果限制 `httpMethod`, `action` 应以 `post.ts`、`get.ts`、`delete.ts`、`patch.ts`、`put.ts` （或 `.js` ）命名，否则任意 `httpMethod` 都可以访问。\n\n#### X-HTTP-Method-Override\n\n如果请求头部包含 `X-HTTP-Method-Override` 参数，则访问方法以 `X-HTTP-Method-Override` 值为准\n\n比如 Action 要求 `PATCH` 请求，但微信小程序不支持 `PATCH`，那么可以使用 `POST` 访问，并在头部加上此参数，值为 `PATCH`\n\n```JSON\n\"headers\":{\n  \"X-HTTP-Method-Override\":\"PATCH\"\n}\n```\n\n#### isMethodNecessary\n\n如果设置 `router.isMethodNecessary = true;`, 则所有 `Action` 必须严格使用 `httpMethod` 命名，与 RESTFul 规范相符。否则会找不到路由并返回 `404`。\n\n如果 `isMethodNecessary` 为 `false` 或不设置，则 RESTFul 规范的 API 可能会以非 RESTFul 方式调用。如路由 `user/login`，本应是 `get user/login`，但 `post user/login/get` 也能调用。因此如果使用 RESTFul，建议设置 `isMethodNecessary` 为 `true`。\n\n#### 例 1\n\n获取 todo list\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- get.ts\n```\n\n访问地址为 `get /todo`，\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoList.ts\n```\n\n访问地址为 `get /todo/getTodoList` 、 `post /todo/getTodoList` 、 `put /todo/getTodoList` 等等，效果相同。\n\n#### 例 2\n\n获取单个 todo item\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- ^id\n|           +-- get.ts\n```\n\n访问地址为 `get /todo/66`\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoItem.ts\n```\n\n访问地址为 `get(post 等) /todo/getTodoItem`，需要在 `body` 、 `header` 或 `queryParams` 传入 `todoId` 参数\n\n#### 示例建议\n\n上述两个示例都给了两种定义方式。\n\ncloudbase 云函数没有限制 httpMethod，但建议使用方式 1 更符合规范，易读性也更好。\n\n因此建议设置 router.isMethodNecessary 为 true 。\n\n## HttpResult\n\n`HttpResult` 封装了 HTTP 返回结构。可在构造函数传入相关参数。\n\n`HttpResult` 有个属性 `result` ，可获取最终 HTTP 返回结构 `HttpResultStruct` 。\n\n### 内置类型\n\n目前 `HttpResult` 内置一些返回类型，都是以静态方式调用：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- methodNotAllowed, 405\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nreturn HttpResult.ok(\"success\");\n```\n\n普通内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，命名以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n### 举例\n\n以下例子中返回 200 请求成功：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.ok({\n  list: [],\n  count: 0,\n});\n```\n\n以下例子中返回 400 请求错误：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.badRequestMsg({ message: \"请求错误\" });\n// 或 return HttpResult.badRequest(\"请求错误\");\n```\n\n### 在 Action 中\n\n在 `Action` 中已经加入了 `HttpResult` 内置函数，可以直接以 `this.func` 方式调用\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n    // or return this.ok('success');\n  }\n}\n```\n\n## 请求参数\n\n`RequestParams` 类解析并封装请求参数，构造函数传入云函数 `event` 和 `context`。\n\n在 `Action` 中，有 `RequestParams` 实例对象 `requestParams`，可通过 `this.requestParams` 方式使用。\n\n实例包含以下字段\n\n### event\n\n云函数环境 event\n\n### context\n\n云函数环境 context\n\n### path\n\n访问路径，如`POST https://domain.com/api/user/login`，path 值为`user/login`。\n\n_注意：在 event 中，path 实为 `/` 开头，上例为 `/user/login`。但在 `cba` 中移除了开头的 `/`_\n\n### headers\n\n请求头部\n\n### params\n\n查询参数\n\n### data\n\n请求 body，如果是 JSON 字符串，则转为 JSON 对象。\n\n在 event 中，json 为字符串，在 `RequestParams` 中已解析。\n\n### query\n\nv0.9.0 中新增。\n\nRESTFul 规范的路径中查询参数。如 `user/:id` 调用时是 `user/66`，在 query 中即存在\n\n```ts\nquery.id == \"66\"; // true;\n```\n\n## Action\n\n每次调用 API，如果顺利进行，主要执行的是 `Action` 中的 `do` 函数。\n\n所有 `Action` 都应派生自 `Action` 类，并重写 `do` 函数。\n\n### 创建一个 Action\n\n1. 在云函数根目录（即与 index.ts 同级）创建名为`controllers`文件夹。也可以为其他，需要在 Router 构造函数第四个参数可以指定，默认为`controllers`\n1. 根据各业务，创建不同 controller 文件夹，名称自定，但名称与路由名称对应。\n1. 在 controller 文件夹中，创建`.ts`文件，每个`.ts`文件对应一个`action`\n1. 在`.ts`文件中创建类，并继承 `Action`，重写 `do` 函数\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n  }\n}\n```\n\n### Action 文件内容\n\n在`.ts`文件中，模块返回一个类，该类继承 `Action`，构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n例 1\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    const { account, password } = this.requestParams.data\n\n    if(/*账号或密码错误*/) return this.notFound('账号或密码错误')\n    return this.ok(new {/*返回信息*/})\n  }\n}\n```\n\n例 2\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async do(): Promise<HttpResult> {\n    const { account } = this.requestParams.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    return this.ok(todoList);\n  }\n}\n```\n\n## 中间件\n\n中间件可以在 API 每次调用的生命周期各个阶段执行，如记录日志，验证权限等。\n\n所有中间件应派生自类 `Middleware`，实现 `do` 函数，返回 `MiddlewareResult`\n\n### 中间件类型\n\n在 `cba` 中，中间件有以下几种类别：\n\n1.  BeforeStart： `Action` 初始化前调用\n1.  BeforeAction： `Action` 执行前调用\n1.  BeforeEnd： `Action` 执行后调用\n1.  BeforeSuccessEnd： `Action` 执行后，而且返回结果为 2xx 时调用\n1.  BeforeErrEnd： `Action` 执行后，而且返回结果不为 2xx 时调用\n\n类型为 `BeforeStart` 的中间件执行时，`Action` 未被加载，也未进行路由匹配，因此无法获取 `query`, `roles` 等。\n\n类型为 `BeforeStart` 和 `BeforeAction` 的中间件执行时，`Action` 未执行，因此无法获取 `Action` 执行结果。\n\n### 中间件结果\n\n```ts\n// 成功\nreturn new MiddlewareResult(true);\n// 或\nreturn MiddlewareResult.getSuccessResult();\n\n// 失败\nreturn new MiddlewareResult(\n  false,\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n// 或\nreturn MiddlewareResult.getFailedResult(\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n```\n\n如果返回失败，则 API 此次调用结束，返回中间件结果。\n\n### 注册中间件\n\n你需要使用 router.configure 注册中间件，如\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  router.configure(new YourMiddleware());\n  return (await router.do()).result;\n};\n```\n\n## 权限\n\n`Router` 构造函数第三个参数是权限验证 `Authority` 对象。\n\n你需要新写个类，继承 `Authority`，并实现 `do` 函数。\n\n其实 `Authority` 也是个中间件，只是加载方式较特殊。当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同。\n\n权限是用于判断用户能否使用 API，可以精确到控制每个 `Action` 。下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```ts\nclass Auth extends Authority {\n  async do(): Promise<MiddlewareResult> {\n    if (!this.roles || !this.roles.length) {\n      return MiddlewareResult.getSuccessResult();\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      return MiddlewareResult.getFailedResult(\n        HttpResult.forbidden(\"账号或密码错误\")\n      );\n    }\n\n    return MiddlewareResult.getSuccessResult();\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.requestParams.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context, new Auth());\n  return (await router.do()).result;\n};\n```\n\n## cba-map\n\n`cba-map` 是可选的，它能提升路由匹配速度，其本身为 json 文件，并且要上传至 `cloudbase`云函数根目录。\n\n### 建议使用\n\n如果不使用`cba-map`，路由匹配方式是先遍历 `controllers` 中的各个 `action`，再进行匹配，如果项目较大可能会影响匹配速度。\n\n在 100 个 `action` 的项目中，经测试`cba-map`提升路由匹配速度大概 20 倍左右（有 `cba-map` 耗时 1-2ms，无`cba-map`耗时 30-40ms）。因此在 `action` 数量较多时建议使用 `cba-map`。\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-map\": \"cba-map dist/controllers\",\n  },\n```\n\n`dist/controllers` 应改为你的 js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录。\n\n执行 `npm run cba-map` 会以`dist/controllers`目录，在项目目录下生成 `cba-map.json` 文件（建议将其加入 `.gitignore`文件）。\n\n## cba-doc\n\n`cba` 支持自动化文档创建，目前已支持输出 `md` 格式文档。\n\n文档的编写支持两种方式：\n\n1. 给 `Action` 类实例对象的 docs 属性赋值\n2. 按特定格式注释 `Action` 定义文件\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-doc\": \"cba-doc dist/controllers doc.md doc.config.json\",\n  },\n```\n\n`cba-doc` 命令传入三个参数\n\n1. js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录\n2. 目标文件相对路径\n3. 配置文件路径\n\n执行 `npm run cba-doc`\n\n### `action` 注释\n\n参考如下格式在文件任意处注释：\n\n```\n/**\n * @action delete docs\n *\n * a docs test named delete\n *\n * @parts test1 test2 custom\n * @input\n * @@headers\n * @@@test-header1 {string} a test header of deleting docs NO.1\n * @@@test-header2 {number}\n * @@@test-header3 {object} a test header of deleting docs NO.3\n * @@@@test-header31 {string} a test header of deleting docs NO.3.1\n * @@@@test-header32 {number} a test header of deleting docs NO.3.2\n * @@@test-header4 a test header of deleting docs NO.4\n * @@@test-header5 {number} a test header of deleting docs NO.5\n * @@body {object} ok result\n * @@@method {string} http method\n * @@params\n * @@query\n * @output\n * @@codes\n * @@@200 success\n * @@@404\n * @@body\n * @@@method {string} http method\n */\n```\n\n`@` 的数量可对比 JSON 对象的深度，其中一级和二级是固定的，如 `@action`、`@parts`、`@input`、`@output`、`@@headers`、`@@query`、`@@body`、`@@params`、`@@code`，三级或以上不做限制\n\n只有 `@action` 是必须的，如果没有则不会生成文档。其他都可选\n\n#### @action\n\n作为自动化文档注释的标识，其后所带内容为该 `Action` 名称，新起一行的内容则为该 `Action` 介绍\n\n#### `@input`/`@output`\n\n输入/输出的参数\n\n`@input` 可选 `@@headers`、`@@query`、`@@body`、`@@params`\n\n`@output` 可选 `@@headers`、`@@body`、`@@code`\n\n1. `@@headers`: 头部参数\n\n2. `@@params`: 查询参数\n\n3. `@@query`: RESTFul 地址参数\n\n4. `@@body`: 内容参数\n\n`@@body` 与 `@@headers`、`@@query`、`@@params` 有些不同，其右侧内容可选，内容是对 body 做介绍的文档\n\n5. `@@code`: 返回状态码\n\n#### 参数\n\n参数格式统一为 `@*prop-name {type} desc`，`@`的数量表示深度，可无限递归\n\n#### parts\n\nparts 的内容较为复杂，参考 [parts](###parts) 部分\n\n### `docs` 属性赋值\n\n参考如下内容给`Action`实例对象的 `docs` 属性赋值：\n\n```TS\n    this.docs = {\n      name: \"get docs\",\n      desc: \"a docs test named get\",\n      input: {\n        headers: [\n          {\n            name: \"test-header1\",\n            desc: \"a test header of getting docs NO.1\",\n            type: \"string\",\n          },\n          {\n            name: \"test-header2\",\n            type: \"number\",\n          },\n          {\n            name: \"test-header3\",\n            desc: \"a test header of getting docs NO.3\",\n            type: \"object\",\n            children: [\n              {\n                name: \"test-header31\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"string\",\n              },\n              {\n                name: \"test-header32\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"number\",\n              },\n            ],\n          },\n          {\n            name: \"test-header4\",\n            desc: \"a test header of getting docs NO.4\",\n            type: \"number\",\n          },\n        ],\n        body: {\n          type: \"string\",\n          desc: \"http method\",\n        },\n      },\n      output: {\n        codes: [\n          {\n            code: 200,\n            desc: \"success\",\n          },\n          {\n            code: 404,\n          },\n        ],\n        body: [\n          {\n            name: \"method\",\n            type: \"string\",\n            desc: \"http method\",\n          },\n        ],\n      },\n      parts: [\"test1\", \"test2\", \"custom\"],\n    };\n```\n\n其实 [action 注释](###action注释) 的方式最终会编译为 `ApiDocs` 对象，如果编写内容相同，则二者最终生成的文档也相同。\n\n因此各属性的介绍与 [action 注释](###action注释) 的方式相同，此处不再赘述。\n\n### 配置文件\n\n前面所说 `cba-doc` 命令的第三个参数为配置文件路径，配置文件格式如下：\n\n```JSON\n{\n  \"title\": \"cba-title\",\n  \"subtitle\": \"cba-subtitle\",\n  \"parts\": [\n    \"docs/configs/test1.json\",\n    \"docs/configs/test2.json\",\n    \"docs/configs/test3.json\"\n  ],\n  \"partsFromAuth\": true\n}\n```\n\n1. title: 生成文档的标题\n2. subtitle: 生成文档的简介\n3. parts: 参考 [parts](###parts) 部分\n4. partsFromAuth: 参考 [parts](###parts) 部分\n\n### parts\n\n有些参数可能会被多个 API 使用，对于一个网站，可能大多数 API 都需要在头部传入`cookie`、`account`等。\n\n利用 `parts` 功能可以重复使用某些参数。\n\n#### 配置\n\n前面配置文件的 `parts` 属性值为字符串数组，内容为重复部分的配置文件路径，每个文件都是一个可配置项。\n\n每个可配置项格式如下：\n\n```JSON\n{\n  \"name\": \"custom\",\n  \"query\": [\n    {\n      \"name\": \"base-query\",\n      \"desc\": \"this is a base query\",\n      \"type\": \"string\"\n    }\n  ],\n  \"outputHeaders\":[],\n  \"inputHeaders\":[],\n  \"params\":[],\n  \"codes\":[]\n}\n\n```\n\n其中 `name` 值为该配置项的标识。如果该值为空或未设置，则会使用该配置项的文件名。\n\n#### ApiDocs 对象\n\n对于 `ApiDocs`，其属性 parts 值为字符串数组，字符串是配置项的标识。\n\n如果 `ApiDocs.parts` 包含某个可配置项，则生成的文档会包含该可配置项的内容。\n\n优势 `parts` 与 `auth` 使用场景可能重复。为了简单化，属性 parts 值也可以为一个特殊值 `@auth`，此时这个 `Action` 的 `parts`属性值将取自 `auth` 属性值。\n\n更进一步，如果配置文件中的 `partsFromAuth` 属性值为 `true`，那么所有 `parts` 如果未设置值，都将取自 `auth` 属性值。（未写自动化文档 `Action `将被忽略，没有 `@input` 将忽略输入参数，没有 `@output` 将忽略输出参数 ）。\n\n#### 注释中的格式\n\n在注释中，格式如：\n\n```\n@parts part1 part2\n```\n\n或取自 `auth` 属性值：\n\n```\n@parts @auth\n```\n","readmeFilename":"README.md","gitHead":"8e643a8d5de5b0a87f0d3003a257c27aef12e4aa","_id":"@hal-wang/cloudbase-access@1.2.0-beta.1","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-28uBzDXF9kAE1B7r44pOUnQ2ncx2mMUdSxnDb+JaF1em0Te2vMvutWCAU7IeQX4VGI1kMi6f/i/+JCkFJtKPpg==","shasum":"14182e0e815438e3c5c88e3e24133e23520851a6","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.0-beta.1.tgz","fileCount":174,"unpackedSize":173144,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaWKKCRA9TVsSAnZWagAA0c0QAJDLKQuL0Stmx8XsWoAi\n1KhSzGdmsfL1OfNWEnPHotZL9v6LNUkaTM9GKepzcqPcztT6+nA9LrJPDa4Z\nyIcJxjkHOWz6OxXL4kk8RM8QsNpMwRMDFvT6ctPCiMcZtzypi2H+fEpO7RYe\nnLxNjAUa0WrcdGDMhHcySSRnKrIn94nIeLUybWKieq0KnjRXpacoIUrkwMHl\n9qMLhavt5HkUC+fAdGf6qhBdWNIHL4V8SqJ3Z73xBCtpDG6hENnV+O85HRAF\nD8/SxM3imLnXDEp/D05W+IaHaFmABcgcG5PLJ3NH/KKChD1YwSWkrJlGWE9j\nfP70o+9rWNqILmi5Fz5vSR9zfhyIwm0YN0ooJ+NfvF+93/91sQiD6ybzaEPX\n233F47f61vrHr7ftscBuh5po9f2BL25nh9ohKa+Iac9XMP+WzDKtaSu2q595\ndkltZnwxUn/c/H3M5xgv6271Eori/iumcnyrtmFyj8J5upbPJdJDobLxW/BC\n97TP3DrQkSlalR6wmJfeVoO2SiaS19ShEiMQT6qSK6cb0VHzC4vmY1KzsbyV\n/NVVU7lTESpoiOF+BtAlmsdxI0KOVK18eZyLmPgBeY194mkPAyKDfupRQ/fD\nOqoSRGylDgrUpMEVDZs4EXWbBDOhtX1qnRK2EJORdg/z8yvhJ4DRuxSWyhRL\nKYBP\r\n=WPsR\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDtYvhrjuZk4opChtGfD8XjUnY81pKwfAwcxOO/6IHW7AiBOcjOoXG0Nki2JZL0ZcUtW5a84n2lP9d/dfqPLSojZhQ=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.0-beta.1_1617519241633_0.973756603639151"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.0-beta.2":{"name":"@hal-wang/cloudbase-access","version":"1.2.0-beta.2","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.24","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.20","@types/node":"^14.14.24","@typescript-eslint/eslint-plugin":"^4.14.2","@typescript-eslint/parser":"^4.14.2","eslint":"^7.19.0","eslint-config-prettier":"^7.2.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.0","typescript":"^4.1.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"readme":"# cloudbase-access ( cba )\n\n利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n一个简易的 todo 项目，包含后端和前端，详情请查看 `demo/cba-todo` (<https://cba-todo.hal.wang/docs>)\n\n你可以体验线上示例: <https://cba-todo.hal.wang>\n\n也可以一键部署到自己的 `cloudbase`\n\n[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fcloudbase-access&workDir=demo%2Fcba-todo&branch=main)\n\n或者你也可以查看本项目 `test` 文件夹中的一些单元测试\n\n## 建议\n\n强烈建议使用 `typescript` 并生成 `javascript` 代码后上传，可参考 `demo/cba-todo` (<https://cba-todo.hal.wang/docs>)，做法是 ts 生成 js 文件，并删除 `.d.ts` 文件。\n\n理论上 `javascript` 完全没问题，但作者并未进行测试。\n\n## Router\n\n路由管理类，也是 `cba` 的控制中心。构造函数传入环境 `event` 和 `context`。\n\n如在 `main` 函数中：\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  return (await router.do()).result;\n};\n```\n\n以上几行代码即创建一个简单的 RESTful 规范的 API。\n\n如果访问的路径不存在，会返回 404 NotFound 结构。\n\n### 权限参数\n\n`Router` 第三个参数（可选）传入权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### controllers 目录\n\n`Router` 第四个参数（可选）传入 `controllers` 目录名称，默认为 `controllers`，建议不传此参数，即 `controllers`。\n\n所有 `controllers` 统一放在这个文件夹中，在 `controllers` 目录中，建立各 `controller` 文件夹，再在 `controller` 文件夹中建 `action` 文件。详情后面 [##Action](##Action) 部分有介绍。\n\n### 路由匹配\n\n在`cba`中，路由与文件系统匹配。\n\n路由查询参数命名以 `^` 开头（文件系统中命名不允许出现字符 `:`），如果存在多个查询参数则后面的会覆盖前面的，如 `get user/^id/todo/^id`，则 `id` 值为 `todoId`。正确命名应如 `user/^userId/todo/^todoId`。\n\n如果限制 `httpMethod`, `action` 应以 `post.ts`、`get.ts`、`delete.ts`、`patch.ts`、`put.ts` （或 `.js` ）命名，否则任意 `httpMethod` 都可以访问。\n\n#### X-HTTP-Method-Override\n\n如果请求头部包含 `X-HTTP-Method-Override` 参数，则访问方法以 `X-HTTP-Method-Override` 值为准\n\n比如 Action 要求 `PATCH` 请求，但微信小程序不支持 `PATCH`，那么可以使用 `POST` 访问，并在头部加上此参数，值为 `PATCH`\n\n```JSON\n\"headers\":{\n  \"X-HTTP-Method-Override\":\"PATCH\"\n}\n```\n\n#### isMethodNecessary\n\n如果设置 `router.isMethodNecessary = true;`, 则所有 `Action` 必须严格使用 `httpMethod` 命名，与 RESTFul 规范相符。否则会找不到路由并返回 `404`。\n\n如果 `isMethodNecessary` 为 `false` 或不设置，则 RESTFul 规范的 API 可能会以非 RESTFul 方式调用。如路由 `user/login`，本应是 `get user/login`，但 `post user/login/get` 也能调用。因此如果使用 RESTFul，建议设置 `isMethodNecessary` 为 `true`。\n\n#### 例 1\n\n获取 todo list\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- get.ts\n```\n\n访问地址为 `get /todo`，\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoList.ts\n```\n\n访问地址为 `get /todo/getTodoList` 、 `post /todo/getTodoList` 、 `put /todo/getTodoList` 等等，效果相同。\n\n#### 例 2\n\n获取单个 todo item\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- ^id\n|           +-- get.ts\n```\n\n访问地址为 `get /todo/66`\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoItem.ts\n```\n\n访问地址为 `get(post 等) /todo/getTodoItem`，需要在 `body` 、 `header` 或 `queryParams` 传入 `todoId` 参数\n\n#### 示例建议\n\n上述两个示例都给了两种定义方式。\n\ncloudbase 云函数没有限制 httpMethod，但建议使用方式 1 更符合规范，易读性也更好。\n\n因此建议设置 router.isMethodNecessary 为 true 。\n\n## HttpResult\n\n`HttpResult` 封装了 HTTP 返回结构。可在构造函数传入相关参数。\n\n`HttpResult` 有个属性 `result` ，可获取最终 HTTP 返回结构 `HttpResultStruct` 。\n\n### 内置类型\n\n目前 `HttpResult` 内置一些返回类型，都是以静态方式调用：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- methodNotAllowed, 405\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nreturn HttpResult.ok(\"success\");\n```\n\n普通内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，命名以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n### 举例\n\n以下例子中返回 200 请求成功：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.ok({\n  list: [],\n  count: 0,\n});\n```\n\n以下例子中返回 400 请求错误：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.badRequestMsg({ message: \"请求错误\" });\n// 或 return HttpResult.badRequest(\"请求错误\");\n```\n\n### 在 Action 中\n\n在 `Action` 中已经加入了 `HttpResult` 内置函数，可以直接以 `this.func` 方式调用\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n    // or return this.ok('success');\n  }\n}\n```\n\n## 请求参数\n\n`RequestParams` 类解析并封装请求参数，构造函数传入云函数 `event` 和 `context`。\n\n在 `Action` 中，有 `RequestParams` 实例对象 `requestParams`，可通过 `this.requestParams` 方式使用。\n\n实例包含以下字段\n\n### event\n\n云函数环境 event\n\n### context\n\n云函数环境 context\n\n### path\n\n访问路径，如`POST https://domain.com/api/user/login`，path 值为`user/login`。\n\n_注意：在 event 中，path 实为 `/` 开头，上例为 `/user/login`。但在 `cba` 中移除了开头的 `/`_\n\n### headers\n\n请求头部\n\n### params\n\n查询参数\n\n### data\n\n请求 body，如果是 JSON 字符串，则转为 JSON 对象。\n\n在 event 中，json 为字符串，在 `RequestParams` 中已解析。\n\n### query\n\nv0.9.0 中新增。\n\nRESTFul 规范的路径中查询参数。如 `user/:id` 调用时是 `user/66`，在 query 中即存在\n\n```ts\nquery.id == \"66\"; // true;\n```\n\n## Action\n\n每次调用 API，如果顺利进行，主要执行的是 `Action` 中的 `do` 函数。\n\n所有 `Action` 都应派生自 `Action` 类，并重写 `do` 函数。\n\n### 创建一个 Action\n\n1. 在云函数根目录（即与 index.ts 同级）创建名为`controllers`文件夹。也可以为其他，需要在 Router 构造函数第四个参数可以指定，默认为`controllers`\n1. 根据各业务，创建不同 controller 文件夹，名称自定，但名称与路由名称对应。\n1. 在 controller 文件夹中，创建`.ts`文件，每个`.ts`文件对应一个`action`\n1. 在`.ts`文件中创建类，并继承 `Action`，重写 `do` 函数\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n  }\n}\n```\n\n### Action 文件内容\n\n在`.ts`文件中，模块返回一个类，该类继承 `Action`，构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n例 1\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    const { account, password } = this.requestParams.data\n\n    if(/*账号或密码错误*/) return this.notFound('账号或密码错误')\n    return this.ok(new {/*返回信息*/})\n  }\n}\n```\n\n例 2\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async do(): Promise<HttpResult> {\n    const { account } = this.requestParams.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    return this.ok(todoList);\n  }\n}\n```\n\n## 中间件\n\n中间件可以在 API 每次调用的生命周期各个阶段执行，如记录日志，验证权限等。\n\n所有中间件应派生自类 `Middleware`，实现 `do` 函数，返回 `MiddlewareResult`\n\n### 中间件类型\n\n在 `cba` 中，中间件有以下几种类别：\n\n1.  BeforeStart： `Action` 初始化前调用\n1.  BeforeAction： `Action` 执行前调用\n1.  BeforeEnd： `Action` 执行后调用\n1.  BeforeSuccessEnd： `Action` 执行后，而且返回结果为 2xx 时调用\n1.  BeforeErrEnd： `Action` 执行后，而且返回结果不为 2xx 时调用\n\n类型为 `BeforeStart` 的中间件执行时，`Action` 未被加载，也未进行路由匹配，因此无法获取 `query`, `roles` 等。\n\n类型为 `BeforeStart` 和 `BeforeAction` 的中间件执行时，`Action` 未执行，因此无法获取 `Action` 执行结果。\n\n### 中间件结果\n\n```ts\n// 成功\nreturn new MiddlewareResult(true);\n// 或\nreturn MiddlewareResult.getSuccessResult();\n\n// 失败\nreturn new MiddlewareResult(\n  false,\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n// 或\nreturn MiddlewareResult.getFailedResult(\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n```\n\n如果返回失败，则 API 此次调用结束，返回中间件结果。\n\n### 注册中间件\n\n你需要使用 router.configure 注册中间件，如\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  router.configure(new YourMiddleware());\n  return (await router.do()).result;\n};\n```\n\n## 权限\n\n`Router` 构造函数第三个参数是权限验证 `Authority` 对象。\n\n你需要新写个类，继承 `Authority`，并实现 `do` 函数。\n\n其实 `Authority` 也是个中间件，只是加载方式较特殊。当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同。\n\n权限是用于判断用户能否使用 API，可以精确到控制每个 `Action` 。下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```ts\nclass Auth extends Authority {\n  async do(): Promise<MiddlewareResult> {\n    if (!this.roles || !this.roles.length) {\n      return MiddlewareResult.getSuccessResult();\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      return MiddlewareResult.getFailedResult(\n        HttpResult.forbidden(\"账号或密码错误\")\n      );\n    }\n\n    return MiddlewareResult.getSuccessResult();\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.requestParams.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context, new Auth());\n  return (await router.do()).result;\n};\n```\n\n## cba-map\n\n`cba-map` 是可选的，它能提升路由匹配速度，其本身为 json 文件，并且要上传至 `cloudbase`云函数根目录。\n\n### 建议使用\n\n如果不使用`cba-map`，路由匹配方式是先遍历 `controllers` 中的各个 `action`，再进行匹配，如果项目较大可能会影响匹配速度。\n\n在 100 个 `action` 的项目中，经测试`cba-map`提升路由匹配速度大概 20 倍左右（有 `cba-map` 耗时 1-2ms，无`cba-map`耗时 30-40ms）。因此在 `action` 数量较多时建议使用 `cba-map`。\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-map\": \"cba-map dist/controllers\",\n  },\n```\n\n`dist/controllers` 应改为你的 js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录。\n\n执行 `npm run cba-map` 会以`dist/controllers`目录，在项目目录下生成 `cba-map.json` 文件（建议将其加入 `.gitignore`文件）。\n\n## cba-doc\n\n`cba` 支持自动化文档创建，目前已支持输出 `md` 格式文档。\n\n文档的编写支持两种方式：\n\n1. 给 `Action` 类实例对象的 docs 属性赋值\n2. 按特定格式注释 `Action` 定义文件\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-doc\": \"cba-doc dist/controllers doc.md doc.config.json\",\n  },\n```\n\n`cba-doc` 命令传入三个参数\n\n1. js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录\n2. 目标文件相对路径\n3. 配置文件路径\n\n执行 `npm run cba-doc`\n\n### `action` 注释\n\n参考如下格式在文件任意处注释：\n\n```\n/**\n * @action delete docs\n *\n * a docs test named delete\n *\n * @parts test1 test2 custom\n * @input\n * @@headers\n * @@@test-header1 {string} a test header of deleting docs NO.1\n * @@@test-header2 {number}\n * @@@test-header3 {object} a test header of deleting docs NO.3\n * @@@@test-header31 {string} a test header of deleting docs NO.3.1\n * @@@@test-header32 {number} a test header of deleting docs NO.3.2\n * @@@test-header4 a test header of deleting docs NO.4\n * @@@test-header5 {number} a test header of deleting docs NO.5\n * @@body {object} ok result\n * @@@method {string} http method\n * @@params\n * @@query\n * @output\n * @@codes\n * @@@200 success\n * @@@404\n * @@body\n * @@@method {string} http method\n */\n```\n\n`@` 的数量可对比 JSON 对象的深度，其中一级和二级是固定的，如 `@action`、`@parts`、`@input`、`@output`、`@@headers`、`@@query`、`@@body`、`@@params`、`@@code`，三级或以上不做限制\n\n只有 `@action` 是必须的，如果没有则不会生成文档。其他都可选\n\n#### @action\n\n作为自动化文档注释的标识，其后所带内容为该 `Action` 名称，新起一行的内容则为该 `Action` 介绍\n\n#### `@input`/`@output`\n\n输入/输出的参数\n\n`@input` 可选 `@@headers`、`@@query`、`@@body`、`@@params`\n\n`@output` 可选 `@@headers`、`@@body`、`@@code`\n\n1. `@@headers`: 头部参数\n\n2. `@@params`: 查询参数\n\n3. `@@query`: RESTFul 地址参数\n\n4. `@@body`: 内容参数\n\n`@@body` 与 `@@headers`、`@@query`、`@@params` 有些不同，其右侧内容可选，内容是对 body 做介绍的文档\n\n5. `@@code`: 返回状态码\n\n#### 参数\n\n参数格式统一为 `@*prop-name {type} desc`，`@`的数量表示深度，可无限递归\n\n#### parts\n\nparts 的内容较为复杂，参考 [parts](###parts) 部分\n\n### `docs` 属性赋值\n\n参考如下内容给`Action`实例对象的 `docs` 属性赋值：\n\n```TS\n    this.docs = {\n      name: \"get docs\",\n      desc: \"a docs test named get\",\n      input: {\n        headers: [\n          {\n            name: \"test-header1\",\n            desc: \"a test header of getting docs NO.1\",\n            type: \"string\",\n          },\n          {\n            name: \"test-header2\",\n            type: \"number\",\n          },\n          {\n            name: \"test-header3\",\n            desc: \"a test header of getting docs NO.3\",\n            type: \"object\",\n            children: [\n              {\n                name: \"test-header31\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"string\",\n              },\n              {\n                name: \"test-header32\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"number\",\n              },\n            ],\n          },\n          {\n            name: \"test-header4\",\n            desc: \"a test header of getting docs NO.4\",\n            type: \"number\",\n          },\n        ],\n        body: {\n          type: \"string\",\n          desc: \"http method\",\n        },\n      },\n      output: {\n        codes: [\n          {\n            code: 200,\n            desc: \"success\",\n          },\n          {\n            code: 404,\n          },\n        ],\n        body: [\n          {\n            name: \"method\",\n            type: \"string\",\n            desc: \"http method\",\n          },\n        ],\n      },\n      parts: [\"test1\", \"test2\", \"custom\"],\n    };\n```\n\n其实 [action 注释](###action注释) 的方式最终会编译为 `ApiDocs` 对象，如果编写内容相同，则二者最终生成的文档也相同。\n\n因此各属性的介绍与 [action 注释](###action注释) 的方式相同，此处不再赘述。\n\n### 配置文件\n\n前面所说 `cba-doc` 命令的第三个参数为配置文件路径，配置文件格式如下：\n\n```JSON\n{\n  \"title\": \"cba-title\",\n  \"subtitle\": \"cba-subtitle\",\n  \"parts\": [\n    \"docs/configs/test1.json\",\n    \"docs/configs/test2.json\",\n    \"docs/configs/test3.json\"\n  ],\n  \"partsFromAuth\": true\n}\n```\n\n1. title: 生成文档的标题\n2. subtitle: 生成文档的简介\n3. parts: 参考 [parts](###parts) 部分\n4. partsFromAuth: 参考 [parts](###parts) 部分\n\n### parts\n\n有些参数可能会被多个 API 使用，对于一个网站，可能大多数 API 都需要在头部传入`cookie`、`account`等。\n\n利用 `parts` 功能可以重复使用某些参数。\n\n#### 配置\n\n前面配置文件的 `parts` 属性值为字符串数组，内容为重复部分的配置文件路径，每个文件都是一个可配置项。\n\n每个可配置项格式如下：\n\n```JSON\n{\n  \"name\": \"custom\",\n  \"query\": [\n    {\n      \"name\": \"base-query\",\n      \"desc\": \"this is a base query\",\n      \"type\": \"string\"\n    }\n  ],\n  \"outputHeaders\":[],\n  \"inputHeaders\":[],\n  \"params\":[],\n  \"codes\":[]\n}\n\n```\n\n其中 `name` 值为该配置项的标识。如果该值为空或未设置，则会使用该配置项的文件名。\n\n#### ApiDocs 对象\n\n对于 `ApiDocs`，其属性 parts 值为字符串数组，字符串是配置项的标识。\n\n如果 `ApiDocs.parts` 包含某个可配置项，则生成的文档会包含该可配置项的内容。\n\n优势 `parts` 与 `auth` 使用场景可能重复。为了简单化，属性 parts 值也可以为一个特殊值 `@auth`，此时这个 `Action` 的 `parts`属性值将取自 `auth` 属性值。\n\n更进一步，如果配置文件中的 `partsFromAuth` 属性值为 `true`，那么所有 `parts` 如果未设置值，都将取自 `auth` 属性值。（未写自动化文档 `Action `将被忽略，没有 `@input` 将忽略输入参数，没有 `@output` 将忽略输出参数 ）。\n\n#### 注释中的格式\n\n在注释中，格式如：\n\n```\n@parts part1 part2\n```\n\n或取自 `auth` 属性值：\n\n```\n@parts @auth\n```\n","readmeFilename":"README.md","gitHead":"8e643a8d5de5b0a87f0d3003a257c27aef12e4aa","_id":"@hal-wang/cloudbase-access@1.2.0-beta.2","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-KJIvd+ZFXqbm70OhhkiyZ3CytTOo8suNMSQdWjGGJStSWR2xNOUGK7tEBbaAWJRX/s2cv2Br5OeHUPD7wj+4BA==","shasum":"68f959e2825ecad0aa6e2c841c4f1d5abad9a505","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.0-beta.2.tgz","fileCount":174,"unpackedSize":173096,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaWQUCRA9TVsSAnZWagAAlt4QAJnAKJtTch8zTiOYKSKf\n6yXJ+Yi5xBo9PrThD63oJz5KCRCjj+TzCgQbQKiwPY5IJrzESqU3M50mUFdo\nRHHNuQ7QrjiCFsClzJ8EFJCdjkaOl/AOk1iRX1eDGRNPVT5u64UgMF4JW7Fh\nRBkj+DT+gtZj8SfiPesFyNyySyNuuh7A+d7if7tR4x/YYwCiKbe91ryPhfwa\nu1bZS0qQoqDwpUNQzMQYdwjI0waIn7Fyf5rYHspnjDrSsTamXsQP1wUtLIYm\nTzb1Eco837SVgmNlbBK/+NIvdc0VHKNJqKbbq+EHt5/wuY1o7VN6J2UYOefS\ndkyhZISjk3dz+UH2RjyU1PypCsd2gfnXrptSKQ8NeZ3lCFKV5Y2mhxk5DtkI\nS4j/4FeultrOlDj58fMYZohXn6doyqBuW55pB76MnW2oEUFfK572us9L/+r/\ne+HlqzCzAu5Y8KLGCnsqo32KySH+xoM1NL/9P9EXYeeBXQn3w35K2qxw7nOM\nep/Yy+55yx2ehuytIbTeEU3mod5t7hjggUg0LZKiGzUe8ldMog7Tkkq7RaY+\nJ/SwJojs+7be1zGcZVpYPZsSC7zClqSnbrUN9iCaX+zrqkYH66VDWbr43996\nCBnJR51gYea60E2pAxZac7EjA7Rz8KAYmVqtDB4DNYgXWacdwQaksZPugMPO\nJqJ+\r\n=vsEp\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCEgloFEsLL77Qh8IVP78K3RyJjHwkC+zo+qhW2cSyF4QIgCd55atZmf9lqJMFuPC4QA44HeOoW+nE6Sfwu1RRDT6M="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.0-beta.2_1617519636207_0.7418086674778168"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.1":{"name":"@hal-wang/cloudbase-access","version":"1.2.1","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"9877d619541fd07fd40edfa2e86de52ca25c2bc6","_id":"@hal-wang/cloudbase-access@1.2.1","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-MiKGeQmrlHFhi/4ZypoH1ZUsX2cdPI+T0eO+/0W7o1+qBYj229b/1GkjkZ2wE6LVKs1Kj+UEgLFudnXXitkQ0A==","shasum":"24ef304463920621529600f706a6b956b38e14f8","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.1.tgz","fileCount":174,"unpackedSize":173089,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgaWwICRA9TVsSAnZWagAAK60QAIUkbNvg1RLiNp607sDz\n0rBfNg+80WY9bvb/uBtT1v6XHLfzvpltLerpia/O/C5EUneDqUrpnynnaufl\n8VntCBTZjeDEWdd4KBU2R0c2BBp52KArmiEe4N3wDBAnuetR6j5xsSFTYPBa\nSpDCsbmXIEZOBYQWLjFiv/Md25iBP3QhY53gyFir+q0/va0Y4dQpWgAGbB+5\nOLyjb/vt2MLkV61SiyI8WyEiW8svZDnKU8NRBHYtz5xk7t5Nk0Gu/lj8wihV\nOGS4NG8Zz9LRTKSMkAomFDiRlMmNVfwr8DtVBDgA3KXRx+BampwdiqrdBapd\nL8drltU0IjStQASbFgGDNXranCN24xXwElkXH2j3eENT4tpTyp8aqSC4vxcL\nDvdaiLaqY16PjUG+rv2WNwxuYXhniyhC9RFVHXSDD6VOrXbqTw/c54ceK5wH\nt4+rKrGoLlspbvG7lAmVrbK+qUhdjUj9SBLk+D4wYBFEqUDDq4RCyJWnEEZc\nUZcmKuAVK7FTfiaKWVmuPQqltqgSijfgWQDMa8qk3jG2rkKTlQIT2TV8l/rT\n3IhWhvHm4p+lc/w7wvqdZJqpCIwsm0AoSxE/wgnAsALvMHXU4byNM6iQwe4q\nBzBhonUa9mbjjdXmdpLhp5CvHxUJeL0BwJj9l4PITwPClUt5dQqmsStyDuDg\nxh27\r\n=vfFV\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCEGgF9sv2AM3zQdkyNHEPN63Nm2pT/UVaW6kcDxLnDjgIhAMvtNo/xxAMYnno+c2S0snAwM8iJcL+9XNUbso5Mdm+A"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.1_1617521671409_0.9576800896117603"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.2":{"name":"@hal-wang/cloudbase-access","version":"1.2.2","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"e3627f2a4348d602590879b89f991e92023d93ce","_id":"@hal-wang/cloudbase-access@1.2.2","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-gwkeCukqfigNUOk6/O1zUbYV83Kv9dpU01we8ePVqgKYZqhH5JohmRJcpWm7CFxDUm1/hrZZYGbeEoXlnkdDhg==","shasum":"af7246e06fcb7ceaf9148619c5c2160376f2cf11","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.2.tgz","fileCount":177,"unpackedSize":176667,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgbZopCRA9TVsSAnZWagAAw9sP/24EJCt7fHtV9H4Z2zGn\nZk/YN3b35QoCu1DxELnYTBvT7XW/rlVKsuOWY77hatglZUYARfQpBkv0J3Fp\nRIJupi31TybPThW7G/wTbj3AtXRGT405P1cUZMrjqdzmc/7+gD4RtfttR9Mc\nmSRak0bjft6wfe8dyDDJEDuux8I+VHvffG51Xd2GZPfUzZ5wKYbiEKHS456O\n0HhvCCtVoXwb+nDor0TdI/7Ca+MYlwsIkLyh9prEbcNhpl6dowgpxeBA2em5\nNJvtUIL3FWHdq2J4CZ6maoXeQvGUbk3XOMnAIUirK9gOEnQ8Bak/fX1AQmKP\nbo5HPkSAn9zI0Lk4Px1ar596MwCdNYRyYOqx+WDxU7ZLbeXNWJP2y+ACqEnO\naAHfIjEtBZacNjIZgNvQmbaYJS/7MYk9VVwp6edb7moDQ8HMpbJmHHfN1G1a\ny9BsyTJDBTNi5Z/7SOsYPBY/ixqhe5HmnlaBybgjlgJk6LbjBZJpfCZnM8ct\nqmRU11vakAkyh6aFdGxU6gjL441Wh+jfZJxg+K4NiHvD+E6th1lQjYRXaRDD\nKscHxfDRBCfQCv24WI2hFP/8UgSw/1fA9dcKY+bTzc+7TbxNi/S7vBBgYrNv\nnUx4E4v5XII5EhGLgD14eUXpgVGI3H411PRqgGoi2lShMvN2AsvW2PaOMhwx\nt5ss\r\n=Mxvc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIEncgBebeET2t4yRnncwbrTWhgNEWOk+BCe+H+n9qxNtAiBjOeXfIyZUU0A1gA5RGQDc48ELZQD34QkIYL8bmICVsA=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.2_1617795624984_0.5105947039836338"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.3-beta.1":{"name":"@hal-wang/cloudbase-access","version":"1.2.3-beta.1","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"readme":"# cloudbase-access ( cba )\n\n利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n一个简易的 todo 项目，包含后端和前端，详情请查看 `demo/cba-todo` (<https://cba-todo.hal.wang/docs>)\n\n你可以体验线上示例: <https://cba-todo.hal.wang>\n\n也可以一键部署到自己的 `cloudbase`\n\n[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fcloudbase-access&workDir=demo%2Fcba-todo&branch=main)\n\n或者你也可以查看本项目 `test` 文件夹中的一些单元测试\n\n## 建议\n\n强烈建议使用 `typescript` 并生成 `javascript` 代码后上传，可参考 `demo/cba-todo` (<https://cba-todo.hal.wang/docs>)，做法是 ts 生成 js 文件，并删除 `.d.ts` 文件。\n\n理论上 `javascript` 完全没问题，但作者并未进行测试。\n\n## Router\n\n路由管理类，也是 `cba` 的控制中心。构造函数传入环境 `event` 和 `context`。\n\n如在 `main` 函数中：\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  return (await router.do()).result;\n};\n```\n\n以上几行代码即创建一个简单的 RESTful 规范的 API。\n\n如果访问的路径不存在，会返回 404 NotFound 结构。\n\n### 权限参数\n\n`Router` 第三个参数（可选）传入权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### controllers 目录\n\n`Router` 第四个参数（可选）传入 `controllers` 目录名称，默认为 `controllers`，建议不传此参数，即 `controllers`。\n\n所有 `controllers` 统一放在这个文件夹中，在 `controllers` 目录中，建立各 `controller` 文件夹，再在 `controller` 文件夹中建 `action` 文件。详情后面 [##Action](##Action) 部分有介绍。\n\n### 路由匹配\n\n在`cba`中，路由与文件系统匹配。\n\n路由查询参数命名以 `^` 开头（文件系统中命名不允许出现字符 `:`），如果存在多个查询参数则后面的会覆盖前面的，如 `get user/^id/todo/^id`，则 `id` 值为 `todoId`。正确命名应如 `user/^userId/todo/^todoId`。\n\n如果限制 `httpMethod`, `action` 应以 `post.ts`、`get.ts`、`delete.ts`、`patch.ts`、`put.ts` （或 `.js` ）命名，否则任意 `httpMethod` 都可以访问。\n\n#### X-HTTP-Method-Override\n\n如果请求头部包含 `X-HTTP-Method-Override` 参数，则访问方法以 `X-HTTP-Method-Override` 值为准\n\n比如 Action 要求 `PATCH` 请求，但微信小程序不支持 `PATCH`，那么可以使用 `POST` 访问，并在头部加上此参数，值为 `PATCH`\n\n```JSON\n\"headers\":{\n  \"X-HTTP-Method-Override\":\"PATCH\"\n}\n```\n\n#### isMethodNecessary\n\n如果设置 `router.isMethodNecessary = true;`, 则所有 `Action` 必须严格使用 `httpMethod` 命名，与 RESTFul 规范相符。否则会找不到路由并返回 `404`。\n\n如果 `isMethodNecessary` 为 `false` 或不设置，则 RESTFul 规范的 API 可能会以非 RESTFul 方式调用。如路由 `user/login`，本应是 `get user/login`，但 `post user/login/get` 也能调用。因此如果使用 RESTFul，建议设置 `isMethodNecessary` 为 `true`。\n\n#### 例 1\n\n获取 todo list\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- get.ts\n```\n\n访问地址为 `get /todo`，\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoList.ts\n```\n\n访问地址为 `get /todo/getTodoList` 、 `post /todo/getTodoList` 、 `put /todo/getTodoList` 等等，效果相同。\n\n#### 例 2\n\n获取单个 todo item\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- ^id\n|           +-- get.ts\n```\n\n访问地址为 `get /todo/66`\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoItem.ts\n```\n\n访问地址为 `get(post 等) /todo/getTodoItem`，需要在 `body` 、 `header` 或 `queryParams` 传入 `todoId` 参数\n\n#### 示例建议\n\n上述两个示例都给了两种定义方式。\n\ncloudbase 云函数没有限制 httpMethod，但建议使用方式 1 更符合规范，易读性也更好。\n\n因此建议设置 router.isMethodNecessary 为 true 。\n\n## HttpResult\n\n`HttpResult` 封装了 HTTP 返回结构。可在构造函数传入相关参数。\n\n`HttpResult` 有个属性 `result` ，可获取最终 HTTP 返回结构 `HttpResultStruct` 。\n\n### 内置类型\n\n目前 `HttpResult` 内置一些返回类型，都是以静态方式调用：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- methodNotAllowed, 405\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nreturn HttpResult.ok(\"success\");\n```\n\n普通内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，命名以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n### 举例\n\n以下例子中返回 200 请求成功：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.ok({\n  list: [],\n  count: 0,\n});\n```\n\n以下例子中返回 400 请求错误：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.badRequestMsg({ message: \"请求错误\" });\n// 或 return HttpResult.badRequest(\"请求错误\");\n```\n\n### 在 Action 中\n\n在 `Action` 中已经加入了 `HttpResult` 内置函数，可以直接以 `this.func` 方式调用\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n    // or return this.ok('success');\n  }\n}\n```\n\n## 请求参数\n\n`RequestParams` 类解析并封装请求参数，构造函数传入云函数 `event` 和 `context`。\n\n在 `Action` 中，有 `RequestParams` 实例对象 `requestParams`，可通过 `this.requestParams` 方式使用。\n\n实例包含以下字段\n\n### event\n\n云函数环境 event\n\n### context\n\n云函数环境 context\n\n### path\n\n访问路径，如`POST https://domain.com/api/user/login`，path 值为`user/login`。\n\n_注意：在 event 中，path 实为 `/` 开头，上例为 `/user/login`。但在 `cba` 中移除了开头的 `/`_\n\n### headers\n\n请求头部\n\n### params\n\n查询参数\n\n### data\n\n请求 body，如果是 JSON 字符串，则转为 JSON 对象。\n\n在 event 中，json 为字符串，在 `RequestParams` 中已解析。\n\n### query\n\nv0.9.0 中新增。\n\nRESTFul 规范的路径中查询参数。如 `user/:id` 调用时是 `user/66`，在 query 中即存在\n\n```ts\nquery.id == \"66\"; // true;\n```\n\n## Action\n\n每次调用 API，如果顺利进行，主要执行的是 `Action` 中的 `do` 函数。\n\n所有 `Action` 都应派生自 `Action` 类，并重写 `do` 函数。\n\n### 创建一个 Action\n\n1. 在云函数根目录（即与 index.ts 同级）创建名为`controllers`文件夹。也可以为其他，需要在 Router 构造函数第四个参数可以指定，默认为`controllers`\n1. 根据各业务，创建不同 controller 文件夹，名称自定，但名称与路由名称对应。\n1. 在 controller 文件夹中，创建`.ts`文件，每个`.ts`文件对应一个`action`\n1. 在`.ts`文件中创建类，并继承 `Action`，重写 `do` 函数\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n  }\n}\n```\n\n### Action 文件内容\n\n在`.ts`文件中，模块返回一个类，该类继承 `Action`，构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n例 1\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    const { account, password } = this.requestParams.data\n\n    if(/*账号或密码错误*/) return this.notFound('账号或密码错误')\n    return this.ok(new {/*返回信息*/})\n  }\n}\n```\n\n例 2\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async do(): Promise<HttpResult> {\n    const { account } = this.requestParams.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    return this.ok(todoList);\n  }\n}\n```\n\n## 中间件\n\n中间件可以在 API 每次调用的生命周期各个阶段执行，如记录日志，验证权限等。\n\n所有中间件应派生自类 `Middleware`，实现 `do` 函数，返回 `MiddlewareResult`\n\n### 中间件类型\n\n在 `cba` 中，中间件有以下几种类别：\n\n1.  BeforeStart： `Action` 初始化前调用\n1.  BeforeAction： `Action` 执行前调用\n1.  BeforeEnd： `Action` 执行后调用\n1.  BeforeSuccessEnd： `Action` 执行后，而且返回结果为 2xx 时调用\n1.  BeforeErrEnd： `Action` 执行后，而且返回结果不为 2xx 时调用\n\n类型为 `BeforeStart` 的中间件执行时，`Action` 未被加载，也未进行路由匹配，因此无法获取 `query`, `roles` 等。\n\n类型为 `BeforeStart` 和 `BeforeAction` 的中间件执行时，`Action` 未执行，因此无法获取 `Action` 执行结果。\n\n### 中间件结果\n\n```ts\n// 成功\nreturn new MiddlewareResult(true);\n// 或\nreturn MiddlewareResult.getSuccessResult();\n\n// 失败\nreturn new MiddlewareResult(\n  false,\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n// 或\nreturn MiddlewareResult.getFailedResult(\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n```\n\n如果返回失败，则 API 此次调用结束，返回中间件结果。\n\n### 注册中间件\n\n你需要使用 router.configure 注册中间件，如\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  router.configure(new YourMiddleware());\n  return (await router.do()).result;\n};\n```\n\n## 权限\n\n`Router` 构造函数第三个参数是权限验证 `Authority` 对象。\n\n你需要新写个类，继承 `Authority`，并实现 `do` 函数。\n\n其实 `Authority` 也是个中间件，只是加载方式较特殊。当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同。\n\n权限是用于判断用户能否使用 API，可以精确到控制每个 `Action` 。下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```ts\nclass Auth extends Authority {\n  async do(): Promise<MiddlewareResult> {\n    if (!this.roles || !this.roles.length) {\n      return MiddlewareResult.getSuccessResult();\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      return MiddlewareResult.getFailedResult(\n        HttpResult.forbidden(\"账号或密码错误\")\n      );\n    }\n\n    return MiddlewareResult.getSuccessResult();\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.requestParams.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context, new Auth());\n  return (await router.do()).result;\n};\n```\n\n## cba-map\n\n`cba-map` 是可选的，它能提升路由匹配速度，其本身为 json 文件，并且要上传至 `cloudbase`云函数根目录。\n\n### 建议使用\n\n如果不使用`cba-map`，路由匹配方式是先遍历 `controllers` 中的各个 `action`，再进行匹配，如果项目较大可能会影响匹配速度。\n\n在 100 个 `action` 的项目中，经测试`cba-map`提升路由匹配速度大概 20 倍左右（有 `cba-map` 耗时 1-2ms，无`cba-map`耗时 30-40ms）。因此在 `action` 数量较多时建议使用 `cba-map`。\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-map\": \"cba-map dist/controllers\",\n  },\n```\n\n`dist/controllers` 应改为你的 js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录。\n\n执行 `npm run cba-map` 会以`dist/controllers`目录，在项目目录下生成 `cba-map.json` 文件（建议将其加入 `.gitignore`文件）。\n\n## cba-doc\n\n`cba` 支持自动化文档创建，目前已支持输出 `md` 格式文档。\n\n文档的编写支持两种方式：\n\n1. 给 `Action` 类实例对象的 docs 属性赋值\n2. 按特定格式注释 `Action` 定义文件\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-doc\": \"cba-doc dist/controllers doc.md doc.config.json\",\n  },\n```\n\n`cba-doc` 命令传入三个参数\n\n1. js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录\n2. 目标文件相对路径\n3. 配置文件路径\n\n执行 `npm run cba-doc`\n\n### `action` 注释\n\n参考如下格式在文件任意处注释：\n\n```\n/**\n * @action delete docs\n *\n * a docs test named delete\n *\n * @parts test1 test2 custom\n * @input\n * @@headers\n * @@@test-header1 {string} a test header of deleting docs NO.1\n * @@@test-header2 {number}\n * @@@test-header3 {object} a test header of deleting docs NO.3\n * @@@@test-header31 {string} a test header of deleting docs NO.3.1\n * @@@@test-header32 {number} a test header of deleting docs NO.3.2\n * @@@test-header4 a test header of deleting docs NO.4\n * @@@test-header5 {number} a test header of deleting docs NO.5\n * @@body {object} ok result\n * @@@method {string} http method\n * @@params\n * @@query\n * @output\n * @@codes\n * @@@200 success\n * @@@404\n * @@body\n * @@@method {string} http method\n */\n```\n\n`@` 的数量可对比 JSON 对象的深度，其中一级和二级是固定的，如 `@action`、`@parts`、`@input`、`@output`、`@@headers`、`@@query`、`@@body`、`@@params`、`@@code`，三级或以上不做限制\n\n只有 `@action` 是必须的，如果没有则不会生成文档。其他都可选\n\n#### @action\n\n作为自动化文档注释的标识，其后所带内容为该 `Action` 名称，新起一行的内容则为该 `Action` 介绍\n\n#### `@input`/`@output`\n\n输入/输出的参数\n\n`@input` 可选 `@@headers`、`@@query`、`@@body`、`@@params`\n\n`@output` 可选 `@@headers`、`@@body`、`@@code`\n\n1. `@@headers`: 头部参数\n\n2. `@@params`: 查询参数\n\n3. `@@query`: RESTFul 地址参数\n\n4. `@@body`: 内容参数\n\n`@@body` 与 `@@headers`、`@@query`、`@@params` 有些不同，其右侧内容可选，内容是对 body 做介绍的文档\n\n5. `@@code`: 返回状态码\n\n#### 参数\n\n参数格式统一为 `@*prop-name {type} desc`，`@`的数量表示深度，可无限递归\n\n#### parts\n\nparts 的内容较为复杂，参考 [parts](###parts) 部分\n\n### `docs` 属性赋值\n\n参考如下内容给`Action`实例对象的 `docs` 属性赋值：\n\n```TS\n    this.docs = {\n      name: \"get docs\",\n      desc: \"a docs test named get\",\n      input: {\n        headers: [\n          {\n            name: \"test-header1\",\n            desc: \"a test header of getting docs NO.1\",\n            type: \"string\",\n          },\n          {\n            name: \"test-header2\",\n            type: \"number\",\n          },\n          {\n            name: \"test-header3\",\n            desc: \"a test header of getting docs NO.3\",\n            type: \"object\",\n            children: [\n              {\n                name: \"test-header31\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"string\",\n              },\n              {\n                name: \"test-header32\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"number\",\n              },\n            ],\n          },\n          {\n            name: \"test-header4\",\n            desc: \"a test header of getting docs NO.4\",\n            type: \"number\",\n          },\n        ],\n        body: {\n          type: \"string\",\n          desc: \"http method\",\n        },\n      },\n      output: {\n        codes: [\n          {\n            code: 200,\n            desc: \"success\",\n          },\n          {\n            code: 404,\n          },\n        ],\n        body: [\n          {\n            name: \"method\",\n            type: \"string\",\n            desc: \"http method\",\n          },\n        ],\n      },\n      parts: [\"test1\", \"test2\", \"custom\"],\n    };\n```\n\n其实 [action 注释](###action注释) 的方式最终会编译为 `ApiDocs` 对象，如果编写内容相同，则二者最终生成的文档也相同。\n\n因此各属性的介绍与 [action 注释](###action注释) 的方式相同，此处不再赘述。\n\n### 配置文件\n\n前面所说 `cba-doc` 命令的第三个参数为配置文件路径，配置文件格式如下：\n\n```JSON\n{\n  \"title\": \"cba-title\",\n  \"subtitle\": \"cba-subtitle\",\n  \"parts\": [\n    \"docs/configs/test1.json\",\n    \"docs/configs/test2.json\",\n    \"docs/configs/test3.json\"\n  ],\n  \"partsFromAuth\": true\n}\n```\n\n1. title: 生成文档的标题\n2. subtitle: 生成文档的简介\n3. parts: 参考 [parts](###parts) 部分\n4. partsFromAuth: 参考 [parts](###parts) 部分\n\n### parts\n\n有些参数可能会被多个 API 使用，对于一个网站，可能大多数 API 都需要在头部传入`cookie`、`account`等。\n\n利用 `parts` 功能可以重复使用某些参数。\n\n#### 配置\n\n前面配置文件的 `parts` 属性值为字符串数组，内容为重复部分的配置文件路径，每个文件都是一个可配置项。\n\n每个可配置项格式如下：\n\n```JSON\n{\n  \"name\": \"custom\",\n  \"query\": [\n    {\n      \"name\": \"base-query\",\n      \"desc\": \"this is a base query\",\n      \"type\": \"string\"\n    }\n  ],\n  \"outputHeaders\":[],\n  \"inputHeaders\":[],\n  \"params\":[],\n  \"codes\":[]\n}\n\n```\n\n其中 `name` 值为该配置项的标识。如果该值为空或未设置，则会使用该配置项的文件名。\n\n#### ApiDocs 对象\n\n对于 `ApiDocs`，其属性 parts 值为字符串数组，字符串是配置项的标识。\n\n如果 `ApiDocs.parts` 包含某个可配置项，则生成的文档会包含该可配置项的内容。\n\n优势 `parts` 与 `auth` 使用场景可能重复。为了简单化，属性 parts 值也可以为一个特殊值 `@auth`，此时这个 `Action` 的 `parts`属性值将取自 `auth` 属性值。\n\n更进一步，如果配置文件中的 `partsFromAuth` 属性值为 `true`，那么所有 `parts` 如果未设置值，都将取自 `auth` 属性值。（未写自动化文档 `Action `将被忽略，没有 `@input` 将忽略输入参数，没有 `@output` 将忽略输出参数 ）。\n\n#### 注释中的格式\n\n在注释中，格式如：\n\n```\n@parts part1 part2\n```\n\n或取自 `auth` 属性值：\n\n```\n@parts @auth\n```\n","readmeFilename":"README.md","gitHead":"a5b3f62de9bab9f7fc9bd42063919c5fe5093538","_id":"@hal-wang/cloudbase-access@1.2.3-beta.1","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-NdPi0afyIgOSomVJqn24xPOOnB5dIq8BTWlVaeaDlk+X+1rm9vXYDrOGOAT95ShUNWvQyPQ/SrTK+rGTYLeJxw==","shasum":"8de405888131d0ea29eda4918f67d032a023e440","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.3-beta.1.tgz","fileCount":182,"unpackedSize":180876,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgb/z6CRA9TVsSAnZWagAAFbYQAIB37kwesAQbumdzQHZm\nl4t/zkoDKHTKLwQKFkyRIfRjHTLPudJP/s9PXN+PfBdImdtD86p3cM8/VGji\n1Bap/1iX85ngxiSSoRAwevOEhIMRNFrYnjGyZHhwqU2e8k3GZDSaRG1IcEcH\naLUcgBgd39MT0JhpVVzmMzwrBgcyXTtccH3pQxNSoqsJNDi6DtZu0aOdX4DL\nnXfzQrrYAnXjDEnJAQMiM+J9vZz2YLkqx9P3Yces8ulAfLG8cP3ZC3dJhMjn\njfe9s1H/Sewc2hyIOlVKJjs16sbnSwkt61ChcHq/Qv7eS4e87SZvDkfhsMGH\ntHfbOjfnRy0Mhd4NkOlebpOw4FaFtI9chowc5EyCfuzND1bvAUGWJRaUnJ8J\nmyj4KuYloLgC5SRgpPwGl27w3+Ybi3+qILgAPq2042OonwTfjKNEc+klcABw\nvXivIsXCgepJ1b1zKhc2kTPcLFV8M9TXo1FtCffUQnwJHVcw1Z4CJsdU5sqO\naL6EZfDGqdXqVdq29AsY4GsEThy6W1v3k2RQdA8V7a0OAzNmNbgdIHwL4Bg2\nOHvIePOXYLUcsXPps1UWVIXNMSXqXHT90Lf/ig5V9ujwLT86oQDn1m8B3PVr\nIT1rsNHtbNqeR5J7kIMtsiBjDVYBTcukwVKtEEc2gm2o4VKt+60m9kmrVZzI\nHamE\r\n=JGyw\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIDCDOhCQCV70KKpMyIWHmrHy+dIYvcbxnXGaPTb0n78sAiASE5AiF3pneuE0VDf3b75IFLmOtGYERB+DqYy5Zyt90A=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.3-beta.1_1617951993903_0.5472491426361497"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.3":{"name":"@hal-wang/cloudbase-access","version":"1.2.3","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"bash build.sh","deploy":"bash build.sh && npm publish --access=public","deploy:beta":"bash build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"a5b3f62de9bab9f7fc9bd42063919c5fe5093538","_id":"@hal-wang/cloudbase-access@1.2.3","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-563TkigrFhCubYz8mONYFPhxWkDVXKUiVVW3rB/k3ibbVAoP6b6dk4pixZopX3Q9R5rqCJgwno5HdepBx6/oMA==","shasum":"0de0f4d33adb38fa6c821a424dd58c6ea5e32d9c","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.3.tgz","fileCount":182,"unpackedSize":180869,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgcEE1CRA9TVsSAnZWagAA214P/1zxnBlPp/PEtt4rPD4O\nxBYVhKIb8blxManBBjIfDqrR51EwTuiw8mpm658DpInyLLqoPnbfDGLHFvL2\nWfY+fUqeNX9m+M6cQPeSpI+tHWFjRdIVtXQ886xc51/UfquJZRE5moU7kdJU\n0TYNKyKIfDQAEkDzFCIe565h6Qn34o3eWzpQbkinrP314kjLlfNhIheK/fKB\n61UingKCHdu5+YTbg7wtrHSwkUseMz8eAv7004kx2WN5xgvVyikhytqHnasa\nMgRctlSV6bniZtlDMKmEGWyD2RiaWfcSeA5le8CJwqGEyXxFsVNgwgd9XRhN\n87QdUhthrTuZan6sCA+TFI4RlffEiyscRxMf3la69pGlLqEF52LN5criycKG\nwc1VSMx9O5o7M384xrFGPA+ZcfA6A9DPf4VJ19fjsXDWAH/fcoXbz/YQJUYK\nZJnVksJGy6NTU67+tHTDhKDSGisFNPgYPUPcrR0fBlGEq31IyEoCPXd2g20n\n3mJgnmhZoiVLZqSygahNT9S6COSWYhlyqG2BpqUiKWt8INaFqKKgbDWds3GI\noo3qbl9hXr9NN309Nc7Kpm/MyKqbUj1C9orSX/548LpEyfgGgJomeqDqwpUv\nXxR7slawYsXzxgAOssFFVXhW6raFfgRqzCnblCnYVKPZJtigZM4aujvXrYS6\nripx\r\n=xX4J\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCFvMVKCokNRE+TWqR4DtDRfGvSvyxY0ENVN/q8U7zt+QIhAMj2TG5W2dRfImWzM7st4QuV/J6dfbGFv/WG/58CeRBc"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.3_1617969460981_0.3833736108399475"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.4":{"name":"@hal-wang/cloudbase-access","version":"1.2.4","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"678f7cc819a2c400c07faeed0aa57f815532a288","_id":"@hal-wang/cloudbase-access@1.2.4","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-dB3u78IIBSLmgV3/KIp+tmfd9z4K3k5DdwCfS7njs5eDCgi7xMrCVHsmheJ6cKfrtn8FLO7H1s6T0UKiknb0Mw==","shasum":"31a1bb74dd74d6391731ddc2364c25a9e97359da","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.4.tgz","fileCount":182,"unpackedSize":183105,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgcrFWCRA9TVsSAnZWagAA2UQP/j2kwlNoH/P0dokocknz\nGTgpiED3Cl368j/nQv9zi0tprHmpGq4bLohPDsYcw6i+eZqGBmmCZ2Yeua6X\n68AXT1oA1+68jYND3Rlkqs3cltDPTy25sH70QMxhtui2iACpwPsqkvqta62O\nHPX+wymwLwDd54zO8uaj8eA3Yw0GGflOMb1H/t9OXff+N7zKHDN3NgXk6nPK\npWH17OZydjHykN5AYB/dzmbRQmjUJtiiZwKcp8fgGYuzD/y/lFGggIN+LemO\n6sHneErO5OhfNuu59YDIuG2lh8eLu01QpX/UUDdL5DgpBMyp2DXs/iXzrEBT\ngNhxgKZhXXIt9L+tUNfU1zwYBRBW2BGFqh1nFP8FIcrGmOK6AWHd6PUVMtHR\nyh5Vz5ccwQj2AxfSooCJqVUjNjC4wmBdusdRxk0PeNJStlNLqKHredE15fsW\nPp66IAsBwT9iCb8bgbYqqp23rDsbGkcSZev/9AgVkvvwpaZgcqpGD627v5kn\nHs6nCu/8HocXzx5nwa34YMsHYvE2c1Sy8fKToh14wYNATwxcgiaiLQratBv9\noFXiLhnylJeUEuvW5Jk1EVVi76jN4UQhHuZJziMUT0qLegKxw+4aSxvN38zh\nL6Y95mm4p3RIEdokF1nrsRq9iZdnXNse9K/D+qwJ74OkMebaNllNTn3l0MLe\nqNPi\r\n=J4zF\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCCSchf3BXHXBXl32CwX4UQImi+vTySaROlvc9xrmKzaAIhANBtlJ2IogF2dcwl4KaYWBhG8rjYyK+HXhJKxfieN0kO"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.4_1618129237990_0.2823610828389185"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.7":{"name":"@hal-wang/cloudbase-access","version":"1.2.7","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"5fbf1bfc8929a36fdadc33062dfb425c19b2c2cb","_id":"@hal-wang/cloudbase-access@1.2.7","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-/r5z+rMjy5wQFi9p9mISSMi+Tcb/OxMX5N74RBJDUtgzdFgf8D8v9PszovKmo/cQEGnJhOaz7NqUHB9GKauG3Q==","shasum":"02271433e85fa709405cf15d35935b75befe0430","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.7.tgz","fileCount":182,"unpackedSize":183249,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJggUV4CRA9TVsSAnZWagAALKYP/AmNqJGQnqWCCb8/kn1B\nMXGkaZrLv2eg3236Qw1NII0SaEO9c/o2fRnlX1+qG3HotfufrwmIeHt8SSNA\nVGgju1/Yd2FCx68AKgPo7kicCzDnMt4rAaG9bFkS+X7JJ+lBFlN7IPbtiSM1\n3zxLMBJOWvDgmVqfGkjrqhNytwnnBpl+B9SgltB58pb0hlSQm4LjhskZlxHC\nWU8QYa9P/J5rucp2Uc+ngk0J0lTSSNR2hySFqUXOqXgt82RVTKcHd3tH7fw7\n9gr7uzwk6C5w+ylQ32q0wSRnN/yeP1yGY6NdGWfV/ixhCQQ54gLXMyWSUkHt\nK4rbwT5yMv3NijNA+kGR62mqdabMNQ8XhSbX5R2cUO2e7gi0UNbWEhMvMA4j\nQu9OPgd2gSR4R4QY0Z1SZfxMM0g6IS9ZAaThs/F5zv9w2eL8FH/k9tt0y6BS\nLZu2YMDI7zizZPo13u7bDG19CAmh5nybEfVz/l7R7YVgT/1LAQjYRr+BilW1\nBB9ZMy5SQlSjZIybLX6H7NjNAxE7L5RQqv8K22XWJX1GEQklm9yvEHDGcKVN\nuKgiqGVstYHubkNVEjehaLo9A9edckMzgGJpFCoxYbp8z+qCQF6hsj44CESJ\nyj62TSiDJpjX6rHsTm6WhpF0c6FnU9PW2O/xoMauT1sMwIDx17JFHHDVvw/p\nz0UY\r\n=cF9p\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEQCIFUfjvNDxFuyvAICqLmG5yG9geSbGLYsrT2xS4ys8HscAiAQrY1pQ0t0qwvtUxi4VTFONFDFNGAfA51xY9cFlUsMXw=="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.7_1619084664058_0.008540289327038542"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.8-beta.2":{"name":"@hal-wang/cloudbase-access","version":"1.2.8-beta.2","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"readme":"# cloudbase-access ( cba )\n\n利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n### todo\n\n一个简易的 todo 项目，包含后端和前端，详情请查看 <https://todo.hal.wang/docs>\n\n线上示例：<https://todo.hal.wang>\n\n一键部署：[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Ftodo&branch=main)\n\n### short-url\n\n使用自己的域名简化链接，详情请查看 <https://github.com/hal-wang/short-url>\n\n线上示例：<https://s.hal.wang>\n\n一键部署：[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fshort-url&branch=main)\n\n### wedding-card\n\n网络喜帖，能够生成邀请二维码。详情请查看 <https://github.com/hal-wang/wedding-card>\n\n线上示例：<https://wedding.hal.wang>\n\n一键部署：[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fwedding-card&branch=main)\n\n## 关于 CBA 的建议\n\n强烈建议使用 `typescript` 并生成 `javascript` 代码后上传，可参考以上示例，做法是 ts 生成 js 文件，并用脚本删除 `.d.ts` 文件。\n\n理论上 `javascript` 完全没问题，但作者并未进行测试。\n\n## Router\n\n路由管理类，也是 `cba` 的控制中心。构造函数传入环境 `event` 和 `context`。\n\n如在 `main` 函数中：\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  return (await router.do()).result;\n};\n```\n\n以上几行代码即创建一个简单的 RESTful 规范的 API。\n\n如果访问的路径不存在，会返回 404 NotFound 结构。\n\n### 权限参数\n\n`Router` 第三个参数（可选）传入权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### controllers 目录\n\n`Router` 第四个参数（可选）传入 `controllers` 目录名称，默认为 `controllers`，建议不传此参数，即 `controllers`。\n\n所有 `controllers` 统一放在这个文件夹中，在 `controllers` 目录中，建立各 `controller` 文件夹，再在 `controller` 文件夹中建 `action` 文件。详情后面 [##Action](##Action) 部分有介绍。\n\n### 路由匹配\n\n在`cba`中，路由与文件系统匹配。\n\n路由查询参数命名以 `^` 开头（文件系统中命名不允许出现字符 `:`），如果存在多个查询参数则后面的会覆盖前面的，如 `get user/^id/todo/^id`，则 `id` 值为 `todoId`。正确命名应如 `user/^userId/todo/^todoId`。\n\n如果限制 `httpMethod`, `action` 应以 `post.ts`、`get.ts`、`delete.ts`、`patch.ts`、`put.ts` （或 `.js` ）命名，否则任意 `httpMethod` 都可以访问。\n\n#### X-HTTP-Method-Override\n\n如果请求头部包含 `X-HTTP-Method-Override` 参数，则访问方法以 `X-HTTP-Method-Override` 值为准\n\n比如 Action 要求 `PATCH` 请求，但微信小程序不支持 `PATCH`，那么可以使用 `POST` 访问，并在头部加上此参数，值为 `PATCH`\n\n```JSON\n\"headers\":{\n  \"X-HTTP-Method-Override\":\"PATCH\"\n}\n```\n\n#### isMethodNecessary\n\n如果设置 `router.isMethodNecessary = true;`, 则所有 `Action` 必须严格使用 `httpMethod` 命名，与 RESTFul 规范相符。否则会找不到路由并返回 `404`。\n\n如果 `isMethodNecessary` 为 `false` 或不设置，则 RESTFul 规范的 API 可能会以非 RESTFul 方式调用。如路由 `user/login`，本应是 `get user/login`，但 `post user/login/get` 也能调用。因此如果使用 RESTFul，建议设置 `isMethodNecessary` 为 `true`。\n\n#### 例 1\n\n获取 todo list\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- get.ts\n```\n\n访问地址为 `get /todo`，\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoList.ts\n```\n\n访问地址为 `get /todo/getTodoList` 、 `post /todo/getTodoList` 、 `put /todo/getTodoList` 等等，效果相同。\n\n#### 例 2\n\n获取单个 todo item\n\n##### 方式 1\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- ^id\n|           +-- get.ts\n```\n\n访问地址为 `get /todo/66`\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoItem.ts\n```\n\n访问地址为 `get(post 等) /todo/getTodoItem`，需要在 `body` 、 `header` 或 `queryParams` 传入 `todoId` 参数\n\n#### 示例建议\n\n上述两个示例都给了两种定义方式。\n\ncloudbase 云函数没有限制 httpMethod，但建议使用方式 1 更符合规范，易读性也更好。\n\n因此建议设置 router.isMethodNecessary 为 true 。\n\n## HttpResult\n\n`HttpResult` 封装了 HTTP 返回结构。可在构造函数传入相关参数。\n\n`HttpResult` 有个属性 `result` ，可获取最终 HTTP 返回结构 `HttpResultStruct` 。\n\n### 内置类型\n\n目前 `HttpResult` 内置一些返回类型，都是以静态方式调用：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- methodNotAllowed, 405\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nreturn HttpResult.ok(\"success\");\n```\n\n普通内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，命名以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n### 举例\n\n以下例子中返回 200 请求成功：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.ok({\n  list: [],\n  count: 0,\n});\n```\n\n以下例子中返回 400 请求错误：\n\n```ts\nimport { HttpResult } from \"@hal-wang/cloudbase-access\";\nreturn HttpResult.badRequestMsg({ message: \"请求错误\" });\n// 或 return HttpResult.badRequest(\"请求错误\");\n```\n\n### 在 Action 中\n\n在 `Action` 中已经加入了 `HttpResult` 内置函数，可以直接以 `this.func` 方式调用\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n    // or return this.ok('success');\n  }\n}\n```\n\n## 请求参数\n\n`RequestParams` 类解析并封装请求参数，构造函数传入云函数 `event` 和 `context`。\n\n在 `Action` 中，有 `RequestParams` 实例对象 `requestParams`，可通过 `this.requestParams` 方式使用。\n\n实例包含以下字段\n\n### event\n\n云函数环境 event\n\n### context\n\n云函数环境 context\n\n### path\n\n访问路径，如`POST https://domain.com/api/user/login`，path 值为`user/login`。\n\n_注意：在 event 中，path 实为 `/` 开头，上例为 `/user/login`。但在 `cba` 中移除了开头的 `/`_\n\n### headers\n\n请求头部\n\n### params\n\n查询参数\n\n### data\n\n请求 body，如果是 JSON 字符串，则转为 JSON 对象。\n\n在 event 中，json 为字符串，在 `RequestParams` 中已解析。\n\n### query\n\nv0.9.0 中新增。\n\nRESTFul 规范的路径中查询参数。如 `user/:id` 调用时是 `user/66`，在 query 中即存在\n\n```ts\nquery.id == \"66\"; // true;\n```\n\n## Action\n\n每次调用 API，如果顺利进行，主要执行的是 `Action` 中的 `do` 函数。\n\n所有 `Action` 都应派生自 `Action` 类，并重写 `do` 函数。\n\n### 创建一个 Action\n\n1. 在云函数根目录（即与 index.ts 同级）创建名为`controllers`文件夹。也可以为其他，需要在 Router 构造函数第四个参数可以指定，默认为`controllers`\n1. 根据各业务，创建不同 controller 文件夹，名称自定，但名称与路由名称对应。\n1. 在 controller 文件夹中，创建`.ts`文件，每个`.ts`文件对应一个`action`\n1. 在`.ts`文件中创建类，并继承 `Action`，重写 `do` 函数\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    return this.noContent();\n  }\n}\n```\n\n### Action 文件内容\n\n在`.ts`文件中，模块返回一个类，该类继承 `Action`，构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n例 1\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  async do(): Promise<HttpResult> {\n    const { account, password } = this.requestParams.data\n\n    if(/*账号或密码错误*/) return this.notFound('账号或密码错误')\n    return this.ok(new {/*返回信息*/})\n  }\n}\n```\n\n例 2\n\n```ts\nimport { Action, HttpResult } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async do(): Promise<HttpResult> {\n    const { account } = this.requestParams.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    return this.ok(todoList);\n  }\n}\n```\n\n## 中间件\n\n中间件可以在 API 每次调用的生命周期各个阶段执行，如记录日志，验证权限等。\n\n所有中间件应派生自类 `Middleware`，实现 `do` 函数，返回 `MiddlewareResult`\n\n### 中间件类型\n\n在 `cba` 中，中间件有以下几种类别：\n\n1.  BeforeStart： `Action` 初始化前调用\n1.  BeforeAction： `Action` 执行前调用\n1.  BeforeEnd： `Action` 执行后调用\n1.  BeforeSuccessEnd： `Action` 执行后，而且返回结果为 2xx 时调用\n1.  BeforeErrEnd： `Action` 执行后，而且返回结果不为 2xx 时调用\n\n类型为 `BeforeStart` 的中间件执行时，`Action` 未被加载，也未进行路由匹配，因此无法获取 `query`, `roles` 等。\n\n类型为 `BeforeStart` 和 `BeforeAction` 的中间件执行时，`Action` 未执行，因此无法获取 `Action` 执行结果。\n\n### 中间件结果\n\n```ts\n// 成功\nreturn new MiddlewareResult(true);\n// 或\nreturn MiddlewareResult.getSuccessResult();\n\n// 失败\nreturn new MiddlewareResult(\n  false,\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n// 或\nreturn MiddlewareResult.getFailedResult(\n  HttpResult.badRequestMsg({ message: \"中间件调用失败\" })\n);\n```\n\n如果返回失败，则 API 此次调用结束，返回中间件结果。\n\n### 注册中间件\n\n你需要使用 router.configure 注册中间件，如\n\n```ts\nimport { Router } from \"@hal-wang/cloudbase-access\";\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context);\n  router.configure(new YourMiddleware());\n  return (await router.do()).result;\n};\n```\n\n## 权限\n\n`Router` 构造函数第三个参数是权限验证 `Authority` 对象。\n\n你需要新写个类，继承 `Authority`，并实现 `do` 函数。\n\n其实 `Authority` 也是个中间件，只是加载方式较特殊。当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同。\n\n权限是用于判断用户能否使用 API，可以精确到控制每个 `Action` 。下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```ts\nclass Auth extends Authority {\n  async do(): Promise<MiddlewareResult> {\n    if (!this.roles || !this.roles.length) {\n      return MiddlewareResult.getSuccessResult();\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      return MiddlewareResult.getFailedResult(\n        HttpResult.forbidden(\"账号或密码错误\")\n      );\n    }\n\n    return MiddlewareResult.getSuccessResult();\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.requestParams.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const router = new Router(event, context, new Auth());\n  return (await router.do()).result;\n};\n```\n\n## cba-map\n\n`cba-map` 是可选的，它能提升路由匹配速度，其本身为 json 文件，并且要上传至 `cloudbase`云函数根目录。\n\n### 建议使用\n\n如果不使用`cba-map`，路由匹配方式是先遍历 `controllers` 中的各个 `action`，再进行匹配，如果项目较大可能会影响匹配速度。\n\n在 100 个 `action` 的项目中，经测试`cba-map`提升路由匹配速度大概 20 倍左右（有 `cba-map` 耗时 1-2ms，无`cba-map`耗时 30-40ms）。因此在 `action` 数量较多时建议使用 `cba-map`。\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-map\": \"cba-map dist/controllers\",\n  },\n```\n\n`dist/controllers` 应改为你的 js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录。\n\n执行 `npm run cba-map` 会以`dist/controllers`目录，在项目目录下生成 `cba-map.json` 文件（建议将其加入 `.gitignore`文件）。\n\n## cba-doc\n\n`cba` 支持自动化文档创建，目前已支持输出 `md` 格式文档。\n\n文档的编写支持两种方式：\n\n1. 给 `Action` 类实例对象的 docs 属性赋值\n2. 按特定格式注释 `Action` 定义文件\n\n### 使用方式\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"cba-doc\": \"cba-doc dist/controllers doc.md doc.config.json\",\n  },\n```\n\n`cba-doc` 命令传入三个参数\n\n1. js 文件的 `controllers` 目录路径。在 ts 项目中，应该是执行 tsc 生成的 js 目录\n2. 目标文件相对路径\n3. 配置文件路径\n\n执行 `npm run cba-doc`\n\n### `action` 注释\n\n参考如下格式在文件任意处注释：\n\n```\n/**\n * @action delete docs\n *\n * a docs test named delete\n *\n * @parts test1 test2 custom\n * @input\n * @@headers\n * @@@test-header1 {string} a test header of deleting docs NO.1\n * @@@test-header2 {number}\n * @@@test-header3 {object} a test header of deleting docs NO.3\n * @@@@test-header31 {string} a test header of deleting docs NO.3.1\n * @@@@test-header32 {number} a test header of deleting docs NO.3.2\n * @@@test-header4 a test header of deleting docs NO.4\n * @@@test-header5 {number} a test header of deleting docs NO.5\n * @@body {object} ok result\n * @@@method {string} http method\n * @@params\n * @@query\n * @output\n * @@codes\n * @@@200 success\n * @@@404\n * @@body\n * @@@method {string} http method\n */\n```\n\n`@` 的数量可对比 JSON 对象的深度，其中一级和二级是固定的，如 `@action`、`@parts`、`@input`、`@output`、`@@headers`、`@@query`、`@@body`、`@@params`、`@@code`，三级或以上不做限制\n\n只有 `@action` 是必须的，如果没有则不会生成文档。其他都可选\n\n#### @action\n\n作为自动化文档注释的标识，其后所带内容为该 `Action` 名称，新起一行的内容则为该 `Action` 介绍\n\n#### `@input`/`@output`\n\n输入/输出的参数\n\n`@input` 可选 `@@headers`、`@@query`、`@@body`、`@@params`\n\n`@output` 可选 `@@headers`、`@@body`、`@@code`\n\n1. `@@headers`: 头部参数\n\n2. `@@params`: 查询参数\n\n3. `@@query`: RESTFul 地址参数\n\n4. `@@body`: 内容参数\n\n`@@body` 与 `@@headers`、`@@query`、`@@params` 有些不同，其右侧内容可选，内容是对 body 做介绍的文档\n\n5. `@@code`: 返回状态码\n\n#### 参数\n\n参数格式统一为 `@*prop-name {type} desc`，`@`的数量表示深度，可无限递归\n\n#### parts\n\nparts 的内容较为复杂，参考 [parts](###parts) 部分\n\n### `docs` 属性赋值\n\n参考如下内容给`Action`实例对象的 `docs` 属性赋值：\n\n```TS\n    this.docs = {\n      name: \"get docs\",\n      desc: \"a docs test named get\",\n      input: {\n        headers: [\n          {\n            name: \"test-header1\",\n            desc: \"a test header of getting docs NO.1\",\n            type: \"string\",\n          },\n          {\n            name: \"test-header2\",\n            type: \"number\",\n          },\n          {\n            name: \"test-header3\",\n            desc: \"a test header of getting docs NO.3\",\n            type: \"object\",\n            children: [\n              {\n                name: \"test-header31\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"string\",\n              },\n              {\n                name: \"test-header32\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"number\",\n              },\n            ],\n          },\n          {\n            name: \"test-header4\",\n            desc: \"a test header of getting docs NO.4\",\n            type: \"number\",\n          },\n        ],\n        body: {\n          type: \"string\",\n          desc: \"http method\",\n        },\n      },\n      output: {\n        codes: [\n          {\n            code: 200,\n            desc: \"success\",\n          },\n          {\n            code: 404,\n          },\n        ],\n        body: [\n          {\n            name: \"method\",\n            type: \"string\",\n            desc: \"http method\",\n          },\n        ],\n      },\n      parts: [\"test1\", \"test2\", \"custom\"],\n    };\n```\n\n其实 [action 注释](###action注释) 的方式最终会编译为 `ApiDocs` 对象，如果编写内容相同，则二者最终生成的文档也相同。\n\n因此各属性的介绍与 [action 注释](###action注释) 的方式相同，此处不再赘述。\n\n### 配置文件\n\n前面所说 `cba-doc` 命令的第三个参数为配置文件路径，配置文件格式如下：\n\n```JSON\n{\n  \"title\": \"cba-title\",\n  \"subtitle\": \"cba-subtitle\",\n  \"parts\": [\n    \"docs/configs/test1.json\",\n    \"docs/configs/test2.json\",\n    \"docs/configs/test3.json\"\n  ],\n  \"partsFromAuth\": true\n}\n```\n\n1. title: 生成文档的标题\n2. subtitle: 生成文档的简介\n3. parts: 参考 [parts](###parts) 部分\n4. partsFromAuth: 参考 [parts](###parts) 部分\n\n### parts\n\n有些参数可能会被多个 API 使用，对于一个网站，可能大多数 API 都需要在头部传入`cookie`、`account`等。\n\n利用 `parts` 功能可以重复使用某些参数。\n\n#### 配置\n\n前面配置文件的 `parts` 属性值为字符串数组，内容为重复部分的配置文件路径，每个文件都是一个可配置项。\n\n每个可配置项格式如下：\n\n```JSON\n{\n  \"name\": \"custom\",\n  \"query\": [\n    {\n      \"name\": \"base-query\",\n      \"desc\": \"this is a base query\",\n      \"type\": \"string\"\n    }\n  ],\n  \"outputHeaders\":[],\n  \"inputHeaders\":[],\n  \"params\":[],\n  \"codes\":[]\n}\n\n```\n\n其中 `name` 值为该配置项的标识。如果该值为空或未设置，则会使用该配置项的文件名。\n\n#### ApiDocs 对象\n\n对于 `ApiDocs`，其属性 parts 值为字符串数组，字符串是配置项的标识。\n\n如果 `ApiDocs.parts` 包含某个可配置项，则生成的文档会包含该可配置项的内容。\n\n优势 `parts` 与 `auth` 使用场景可能重复。为了简单化，属性 parts 值也可以为一个特殊值 `@auth`，此时这个 `Action` 的 `parts`属性值将取自 `auth` 属性值。\n\n更进一步，如果配置文件中的 `partsFromAuth` 属性值为 `true`，那么所有 `parts` 如果未设置值，都将取自 `auth` 属性值。（未写自动化文档 `Action `将被忽略，没有 `@input` 将忽略输入参数，没有 `@output` 将忽略输出参数 ）。\n\n#### 注释中的格式\n\n在注释中，格式如：\n\n```\n@parts part1 part2\n```\n\n或取自 `auth` 属性值：\n\n```\n@parts @auth\n```\n","readmeFilename":"README.md","gitHead":"5fbf1bfc8929a36fdadc33062dfb425c19b2c2cb","_id":"@hal-wang/cloudbase-access@1.2.8-beta.2","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-9eNHiWC51+ytlp65mW/PqQcwDEz7myMubBBAR86fOo8TAbG1g36tj/0seTwxm66zn+4PoAoawIX65/oSS3L9Yg==","shasum":"0a3db93f5dd235e112882ad3de1303c8ab53d693","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.8-beta.2.tgz","fileCount":182,"unpackedSize":183296,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJghP7SCRA9TVsSAnZWagAAxREP/ibsSK2NcfzMTA+BT3qq\nE8W3PHZ6D46zmBcq816Lrf6rk5DSTA3vw7SnJUuuq83HZFV0Voq9+fMZsUen\nyvD3IM5M947bkHQrxBDLzsM2x6pUiSsMEkTil+kbD7vbfVlxBuGgbdiwL15S\nJrZLQxe/OZcTdpfXC0ssKGRUXVo0OQsXxpWdo54eRLrPc4sXe9OKKAWm8og4\nKo6lIVh4jKImnsVPDNC+E3wjBXXLEgT/iK/Iz6Kvs/3668pVNQPK5JlQQCVc\nYB6kT4PMGYyWSjvmz9Z9TRo6Uza5z19PFqwC32Q+RGIsGus4EV5OX4q7Bcd+\nUxDGJgWIB5kT/qJ9pYxQyHBTN1wcvIwbcVFUc8wKLlpfFsGHhPKmzqjKVpEc\ngwVJX9u1//eGZS7j+fTIJZyuMZJCY8BOuu8tC3Pp2+jM/NQ9sqydyL8r9Gz/\nSVlgZS4J9m4CpvvH1PGhfEqer2pnOTsw8VKOqmuEMQkwsrjSP3QJEW28KMSk\nu23FVroYkz/cVeQzbyr4itkynNgTGtrHSfptvRKViJfo0azrsmpe/CWdfnSo\n8oWl65WJm7mZHPflVmzsMM4jMAW/pOHLD/aUGYBbKc1PvEVB6XQCoqALcVyv\nRZKaM6tJ6+Rcml5BDNjbkS03hMVBTg06mRKPbIgVLJwM34y+oMFgByEBNlj9\nT7D7\r\n=PefC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDpmHA+3wkIdOpb0DDPY0u766ioAIS9Ht8xRHb5nD4aWgIgX7e9CF4wcaMT6P+kXO97r66nRoGKOJeQak1ifk7/3XU="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.8-beta.2_1619328721630_0.6922813887626587"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.8":{"name":"@hal-wang/cloudbase-access","version":"1.2.8","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"90e4ee1f1bee4db2862a17cbd04febf323a1c6e6","_id":"@hal-wang/cloudbase-access@1.2.8","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-XWpvcSDo1Cxg1xFy28MxgzIyxfNjAzqNZsfCFNWMqfcFLbKGvK45iwvKjpdSpcZdOKvDmVi/vzFuUuI219eh9Q==","shasum":"5165c17745432759b66eb4abfacdd51f99d93e0b","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.8.tgz","fileCount":182,"unpackedSize":183289,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJghQVFCRA9TVsSAnZWagAAuWMP/2CEIrFtFk0B9JssulGJ\nIRlUoLv9ok2zG3RlNYRAmwnaUvEGf7buDjA91C37V3EF+A5mte+AFlBpj91g\nRPmsFFRWSW6GlULbtCOWaveXbiRyckiRcVfkM3CDlW2ZiTxB6dN0AVA5vssF\nPHAyTYts0I7xuqQcUnTJ8qchb2ao1QDn3FYduS4dhlxHDpxi4PvfFLEp7Dra\n0DFA8+6rQHUsdpyTON/QN61IkC6/1OP/z4nMy4gTlSmRZPUCx3Ciag4MaC0y\n+mz0YKh7vwaiKYS54jfBPikHkAqX9KZbMjp1zsDsGJXZtR51bNn+KFEVCgOp\nb45HtC3j+gXkW/pyAQbGgL5qgMBygaNHvvb4/S2MFKLP74qdqQfrogwfPa4F\nVSqtiL5sPO5sShbD1kpBXtqpfK0qpeSOcz/sJw9ZrHDdmBo5VWZH97HSmgRX\nLQWRlLxPtU8tD0J2VnvT44nhR4jaEOBy90BJ7tj6bkmoSj8ZrP7CDGZ9YaMf\nyD6Q5CKdg8tzscA7rE2rEQXnrmZ1ly+HsuEnD23VapefzICwtUBwao9dxJgY\ntVuGprLIRZRs5nrPZqaoX+Qg8mM7vWDujras8PuK91ajfcsSxiXPyJHhI4lO\nFRzth9e+UEY4kbW+R+8Rh6FkH2GWmLN8KZRCXPHgmOlf1ecgc8KENeHWWrMv\nP7nZ\r\n=J8gc\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDcRVW3PwchyoH8MqPqkoh5cJjUfBy86K91j9gsGhlphwIgQ1RfGv2MTgyIlvTh1AAdlnX5BfWiO27mie/gkITUDMA="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.8_1619330373254_0.6629623338419386"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.9":{"name":"@hal-wang/cloudbase-access","version":"1.2.9","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"b6f34876287c17301952dd496960225bb5b167f1","_id":"@hal-wang/cloudbase-access@1.2.9","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-MZ8yWTbA7pLK6f0qT2/qbOz0soPUa3iAzi7zOLhYgEz2vGU/KUKNhf5ziHAlDUP0fnhbZnKoZvWDfprld3Da0w==","shasum":"bf4584d04d6e4a75aa1c541ff0e11932aad74a68","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.9.tgz","fileCount":182,"unpackedSize":183304,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgl10cCRA9TVsSAnZWagAAYvQP/3veqFOAOQHvNJn4wRbx\n9VG1izYiHjnHmQnClChTR8fMqMpNVYWU3BBFqs3n3HAOCPXJ+A541PD1GFSV\nREOKsCkmaBJ+uClZg2nvGLD9sGa9bsPdhznpa45ZJwygefHSWF9lhqQLpqZ0\nmdjAsjMmxHL0HkScF/HCvnijuLYgigvUvBY7tiYFIyK+uNRKJK5+oHzcYZRT\nWhZhNL2SXCmU/XRGXOvw+hjqGxWrzd/41G+5wxMPDffWbsEWVW7LpZ/MELw+\n5EtLsCcpVrD+G/knkbtW5wshz1dj0JyW8T6nhqtpoTv3TTIrks+SRETfyrtr\nvg7IhlCblF90OCr32FpzJhJh1x6zfloU/1I745nXedvX64Xlkk8AUNQ/x5Qq\nTSQb8nq2wvtHCE8XfFQwzA5XHCKludTmIwt9iSI3Ydosy0Uwksxs8OJc1/BR\nSYsEm3eu/TxTrEHrItKWyK26cboiQiqRJDu0tYnhYt9uzS3zC6QCWiQTqhU9\n1JOtmGsfJhG3jXIJgey/CFh9yuVMsbs66CgIqKWTKX0TSx6YEUYEYFQR67iQ\nr4Cs6WPvE1+jwWqrzwyfDJYys0bzWcSqsrVroPjOLYgyOab6tBNS74kb3zo2\ngJxzwh0OvDt1p7Hsh/qYRC7/RlZdGUbMG1A6kvWHA4kQL9NjK1gwJMbPPiFo\noE6d\r\n=TKx4\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQD643X5YVkz+arm8IUXg9HEEOsms2HFovZCo9jnp4oFYgIhAOdqy+HTvbaHp/HSyskujVwCJzehYHT0BiC5ciyiIps6"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.9_1620532506766_0.4630043242549817"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"1.2.10":{"name":"@hal-wang/cloudbase-access","version":"1.2.10","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase-access","mvc","nodejs-api","cloudbase","restful-api","mongodb","cloud-function","nodejs-server","serverless","tencent-cloud","tencent-scf","nodejs","ts","typescript","javascript","js"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"jest","eslint":"eslint src --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@cloudbase/node-sdk":"^2.5.0","@types/node":"^14.14.37","fs":"0.0.1-security","linq":"^3.2.3"},"devDependencies":{"@types/jest":"^26.0.22","@types/node":"^14.14.37","@typescript-eslint/eslint-plugin":"^4.20.0","@typescript-eslint/parser":"^4.20.0","eslint":"^7.23.0","eslint-config-prettier":"^8.1.0","eslint-plugin-prettier":"^3.3.1","jest":"^26.6.3","prettier":"^2.2.1","ts-jest":"^26.5.4","typescript":"^4.2.3"},"bin":{"cba-map":"bin/cba-map.js","cba-doc":"bin/cba-doc.js"},"gitHead":"9cfa00d51a5f31e1b0c0e24f478f441fa4713a39","_id":"@hal-wang/cloudbase-access@1.2.10","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-aNTpshFpxom94/uMTXD+uB01VZM4ZHNtNowX2onq8lFN350dANrwas6z1GJVVbb/tZH5FIKVV0gm/rzqMwWGvg==","shasum":"b20f843380030287cbeaf3b343fa624d2dcf6e20","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-1.2.10.tgz","fileCount":182,"unpackedSize":183948,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgm8gnCRA9TVsSAnZWagAAXhcP+gI366kJW2dyN6ZUvD/b\nojz42KuiLiAJPmiqCK7jUELCwFS8xYUPszTw/EgkXhmcdr3iR1u+Sxb3+AI4\n41wVkSTETerLDBWpl0DZu38tgSW7SCe7PzNVsF5wWAoVm10RDRmkeq1FL0cr\nsamhjn+aXaYolxaWi82Bo7TQVuLvKPfdMJqg+Xyh+1Onj2isYjZ6zY7dtGxF\n8mUcwRfoY+fTP8WtoeOMk1ryvtygVnLZsFzyHwWMupfAriDQ0j+xIHBfQrQl\nKSSIdvPAmgm1sZXqQ/HOagJZnbwY++XN67jigP3mrbUPAlRRVLPYTgWPlICo\neCxn0C2n8UfCDH8+490IEK5wcBgd+VWmZlKXiJU524Iut6XT5Lqd0n12nB7l\ntC4PICobbO+CKDXLhW2X0TJWEkTnPCjMsnuX6ix+RAAifgIq9tQu2TZLH3vA\nqAfBRcdIa3v+T9FTe7n2SOywDVMqoW68Uh0G5LpiTgUQeZiWO8yHHqzO7W+9\nRN3PvKXxBcASb2xbCs9j4ZlcCRSp4vrWwVeKK97XgsFRn1Qvxw39328fEN6H\nNrLE85QKvD2A6TlgCyngiYYoldIuhLyRNR8DOPGAt0DCkl7sx/vgiEQhYWIi\nA6Vd19Ra82xgJpqlkobd84Q+6QPk0uvlJT0Qd9scmHKlrbYYW34kPMQhyUr9\nRhJe\r\n=isW+\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIEx859+gLlIzg6Hr+6rOkfKxsA8JLe/XJMK2AoMWLHPOAiEA/lfe/VffaHQ+kCamYN8jZ5zJCArrDlaJIqVl6fjkg+E="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_1.2.10_1620822054763_0.020142236125880952"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"2.0.0-beta.11":{"name":"@hal-wang/cloudbase-access","version":"2.0.0-beta.11","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase","restful","nodejs-server","serverless","nodejs","typescript","javascript"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"npm run build && jest","lint":"eslint src test --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@types/node":"^15.3.0","linq":"^3.2.3","shelljs":"^0.8.4"},"devDependencies":{"@types/jest":"^26.0.23","@types/shelljs":"^0.8.8","@typescript-eslint/eslint-plugin":"^4.24.0","@typescript-eslint/parser":"^4.24.0","eslint":"^7.26.0","eslint-config-prettier":"^8.3.0","eslint-plugin-prettier":"^3.4.0","jest":"^26.6.3","prettier":"^2.3.0","ts-jest":"^26.5.6","typescript":"^4.2.4"},"bin":{"cba-doc":"bin/cba-doc.js","cba-build":"bin/cba.js"},"readme":"# cloudbase-access ( cba )\n\n利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n### 简单 demo\n\n项目 demo 目录下包含 `ts 项目` 和 `js 项目` 的简单 demo\n\n### todo\n\n一个简易的 todo 项目，包含后端和前端，详情请查看 <https://todo.hal.wang/docs>\n\n线上示例：<https://todo.hal.wang>\n\n一键部署：[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Ftodo&branch=main)\n\n### short-url\n\n使用自己的域名简化链接，详情请查看 <https://github.com/hal-wang/short-url>\n\n线上示例：<https://s.hal.wang>\n\n一键部署：[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fshort-url&branch=main)\n\n### wedding-card\n\n网络喜帖，能够生成邀请二维码。详情请查看 <https://github.com/hal-wang/wedding-card>\n\n线上示例：<https://wedding.hal.wang>\n\n一键部署：[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fwedding-card&branch=main)\n\n## 关于 CBA 的建议\n\n强烈建议使用 `ts` ，通过对 `cba` 的配置，能够生成云函数可用的 `js` 文件\n\n理论上 `js` 完全没问题，但作者更多的是对 `ts` 进行测试\n\n## Startup\n\n`Startup` 是 `cba` 的控制中心，构造函数传入环境 `event` 和 `context`。\n\n如在入口文件中编写（JS）：\n\n```js\nconst { Startup } = require(\"@hal-wang/cloudbase-access\");\nexports.main = async (event, context) => {\n  const startup = new Startup(event, context);\n  startup.use(async (ctx) => {\n    ctx.res.body = \"hello world\";\n  });\n  return await startup.invoke();\n};\n```\n\n以上几行代码即创建一个简单的 API\n\n## 构建\n\n在 package.json 文件的 scripts 节点下添加\n\n```JSON\n\"build\": \"cba-build\"\n```\n\n```JSON\n{\n  \"scripts\": {\n    \"build\": \"cba-build\"\n  },\n  \"dependencies\": {\n    \"@hal-wang/cloudbase-access\": \"^2.0.1\"\n  }\n}\n```\n\n构建时运行\n\n```\nnpm run build\n```\n\n## 配置文件\n\n在项目目录下定义 `cba.config.json` 文件，一个常规配置文件如下：\n\n```JSON\n{\n  \"router\": {  // 路由相关\n    \"dir\": \"controllers\", // 路由文件夹目录\n    \"strict\": false // 是否严格控制 httpMethod\n  },\n  \"ts\": { // ts编写代码的配置\n    \"static\": [ // 静态文件/文件夹。由于ts的生成目录一般在其他位置，如果有生产环境需要的非 .ts 文件，需要在此声明\n      {\n        \"source\": \"static\", // 原文件/文件夹相对路径\n        \"target\": \"assets\" // 目标文件/文件夹相对路径\n      },\n      {\n        \"source\": \"static.txt\",\n        \"target\": \"read.txt\"\n      }\n    ]\n  },\n  \"doc\": { // 使用 cba-map 命令生成文档时必须，详情参考后面的 “自动化文档”\n    \"output\": \"../docs/api/README.md\",\n    \"title\": \"cba-title\",\n    \"subtitle\": \"cba-subtitle\",\n    \"parts\": [\n      {\n        \"inputHeaders\": [\n          {\n            \"name\": \"base-input-header\",\n            \"desc\": \"this is a base input header\",\n            \"type\": \"string\"\n          }\n        ]\n      },\n      {\n        \"outputHeaders\": [\n          {\n            \"name\": \"base-output-header\",\n            \"desc\": \"this is a base output header\",\n            \"type\": \"string\"\n          }\n        ]\n      },\n      {\n        \"name\": \"custom\",\n        \"query\": [\n          {\n            \"name\": \"base-query\",\n            \"desc\": \"this is a base query\",\n            \"type\": \"string\"\n          }\n        ]\n      }\n    ],\n    \"partsFromAuth\": true\n  }\n}\n```\n\n## 路由（useRouter）\n\n调用 `startup.useRouter` 函数即可开启路由中间件，开启后能够支持路由功能，常规项目都需要使用。\n\n`useRouter` 接收一个可选配置参数 `config` ，该参数包含一个可选字段\n\n- authFunc: 函数类型，函数返回值为权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### 路由文件夹\n\n配置文件的 `router.dir` 值是路由文件夹路径，`cba` 能够将路由文件夹下的所有 `Action` 映射为 `http` 访问路径\n\n如果配置文件没有该值，默认为 `controllers`，并且在根目录下（ts 则是目标目录下）需要定义此文件夹\n\n所有 API Action 统一放在这个文件夹中，在 `controllers` 目录中，建立各文件或文件夹。文件是 API 的最小执行单元 Action，详情后面 [Action](##Action) 部分有介绍。\n\n### 路由匹配\n\n在`cba`中，路由与文件系统匹配。\n\n路由查询参数命名以 `^` 开头（文件系统中命名不允许出现字符 `:`），如果存在多个查询参数则后面的会覆盖前面的，如 `get user/^id/todo/^id`，则 `id` 值为 `todoId`。正确命名应如 `user/^userId/todo/^todoId`。\n\n如果限制 `httpMethod`, `action` 应以 `post.ts`、`get.ts`、`delete.ts`、`patch.ts`、`put.ts` （或其他自定义 method，扩展名为.js 效果相同 ）命名，否则任意 `httpMethod` 都可以访问。\n\n#### X-HTTP-Method-Override\n\n如果请求头部包含 `X-HTTP-Method-Override` 参数，则访问方法以 `X-HTTP-Method-Override` 值为准\n\n比如 Action 要求 `PATCH` 请求，但微信小程序不支持 `PATCH`，那么可以使用 `POST` 访问，并在头部加上此参数，值为 `PATCH`\n\n```JSON\n\"headers\":{\n  \"X-HTTP-Method-Override\":\"PATCH\"\n}\n```\n\n### strict\n\n配置文件的 `router.strict` 值决定是否开启严格模式\n\n如果设置 `router.strict: true`, 则所有 `Action` 必须严格使用 `httpMethod` 命名，与 RESTFul 规范相符。否则会找不到路由并返回 `404`。\n\n如果 `strict` 为 `false` 或不设置，则 RESTFul 规范的 API 可能会以非 RESTFul 方式调用。如路由 `user/login`，本应是 `get user/login`，但 `post user/login/get` 也能调用。因此如果使用 RESTFul 或限制 method，建议设置 `strict` 为 `true`。\n\n#### 例 1\n\n获取 todo list\n\n##### 方式 1（推荐）\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- get.ts\n```\n\n访问地址为 `get /todo`，\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoList.ts\n```\n\n访问地址为 `get /todo/getTodoList` 、 `post /todo/getTodoList` 、 `put /todo/getTodoList` 等等，效果相同。\n\n#### 例 2\n\n获取单个 todo item\n\n##### 方式 1（推荐）\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- ^id\n|           +-- get.ts\n```\n\n访问地址为 `get /todo/66`\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoItem.ts\n```\n\n访问地址为 `get(post 等) /todo/getTodoItem`，需要在 `body` 、 `header` 或 `queryParams` 传入 `todoId` 参数\n\n#### 示例建议\n\n上述两个示例都给了两种定义方式。\n\ncloudbase 云函数没有限制 httpMethod，但建议使用方式 1 更符合规范，易读性也更好。\n\n因此建议设置 `strict` 为 true 。\n\n## 中间件\n\n中间件是 `cba` 最重要的部分之一，如记录日志，验证权限\n\n以下内容都继承自中间件：\n\n1. API 执行最小单元 `Action`\n2. 权限认证 `Authority`\n3. 其他派生自类 `Middleware`的中间件\n\n所有中间件应派生自类 `Middleware`，并实现 `invoke` 函数\n\n### 执行顺序\n\n中间件是以递归方式严格按声明顺序执行，每个中间件都可以修改正向或反向管道内容\n\n在中间件里如果需要调用下一个中间件，需执行 `await this.next()`，若不调用下一个中间件，中间件将反向递归执行，并最终返回当前管道内容\n\n```\n 中间件1   中间件2 ... 中间件n\n    _       _           _\n->-|-|-----|-|---------|-|-->   没有执行 next\n   | |     | |         | |   ↓  或是最后一个\n-<-|-|-----|-|---------|-|--<   反向递归\n    -       -           -\n```\n\n### 注册中间件\n\n你需要使用 `startup.use` 注册中间件，传参是一个创建中间件的回调函数，如（JS）\n\n```js\nconst { Startup } = require(\"@hal-wang/cloudbase-access\");\nexports.main = async (event, context) => {\n  const startup = new Startup(event, context);\n\n  // 简单中间件\n  startup.use(async (ctx) => {\n    ctx.res.body = \"hello world\";\n  });\n\n  // 类中间件\n  startup.use(() => new YourMiddleware());\n\n  return await startup.invoke();\n};\n```\n\n#### 简单中间件\n\n简单中间件不需要单独写一个中间件类，但其底层仍然会被转化为普通中间件来执行\n\n```TS\nstartup.use(async (ctx) => {\n  ctx.res.body = \"hello world\";\n});\n```\n\n或\n\n```TS\nstartup.use(async (ctx,next) => {\n  ctx.res.body = \"hello world\";\n  await next();\n  ctx.res.headers.h = \"h\";\n});\n```\n\n## 路由（`startup.useRouter()`）\n\n`startup.useRouter` 是一个特殊的注册中间件的方式，调用该方法能够使 `cba` 支持路由功能\n\n该方法可能会注册一个或两个中间件：\n\n- 根据路由找到的 Action\n- 权限验证 Authority（如果传参 auth）\n\n## HttpContext\n\n管道中的内容都在 `HttpContext` 对象之中，每个中间件都可以调用 `this.ctx` 来获取或修改管道内容\n\n该对象包含以下属性：\n\n- res: `Response` 对象，API 返回结果\n- req: `Request` 对象，API 请求内容\n- action: `Action` 对象，只有执行了 `Authority` 或 `Action` 的中间件后，此值才会有内容，因此可以在任意中间件中的 `await next()` 之后使用（如果没有执行 `Authority` 或 `Action` 中间件，`action` 值仍然为 `undefined`）\n\n### Response\n\n管道的返回内容，可以调用 `ctx.res.result` 来获取最终 HTTP 返回结构 `ResponseStruct`\n\n在每个中间件中都可以修改 `this.ctx.res` 内容\n\n### Request\n\n`ctx.req` 对象已经解析并封装了请求参数\n\n在中间件中，可通过 `this.ctx.req` 方式获取请求内容\n\n`req` 对象包含以下字段\n\n- event\n- context\n- path\n- headers\n- params\n- data\n- query\n\n#### event\n\n云函数环境 `event`\n\n#### context\n\n云函数环境 `context`\n\n#### path\n\n访问路径，如`POST https://domain.com/user/login`，path 值为`user/login`。\n\n_注意：在 event 中，path 实为 `/` 开头，上例为 `/user/login`。但在 `cba` 中移除了开头的 `/`_\n\n#### headers\n\n请求头部\n\n#### params\n\n查询参数\n\n#### data\n\n请求 body，如果是 JSON 字符串，则自动转为 JSON 对象。\n\n#### query\n\nRESTFul 规范的路径中查询参数。如 `user/:id` 调用时是 `user/66`，在 query 中即存在\n\n```ts\nquery.id == \"66\"; // true;\n```\n\n## Action\n\n`Action` 也是中间件，该类继承于中间件类 `Middleware`， 正常情况 Action 会终止管道继续向后执行\n\n每次调用 API，如果顺利进行，主要执行的是自定义 `Action` 对象中的 `invoke` 函数。\n\n所有自定义 `Action` 都应派生自 `Action` 类，并重写 `invoke` 函数。\n\n### 创建一个 Action\n\n1. 在云函数根目录（即与 `index.ts` 同级）创建名为 `controllers` （也可以为其他路径或名称，但需要在配置文件设置，此处为默认 `controllers`）\n1. 根据各业务，创建 `.ts/.js` 文件或文件夹，名称自定，但名称和路径会映射为访问路径，每个文件对应一个 `action`\n1. 在 `.ts/.js` 文件中创建继承 `Action` 的类，并重写 `invoke` 函数\n\n```\n+-- controllers\n|   +-- type1\n|       +-- action1.ts\n|       +-- action2.ts\n|       +-- ...\n|   +-- type2\n|       +-- action3.ts\n|       +-- action4.ts\n|       +-- ^id\n|           +-- action5.ts\n|           +-- ...\n```\n\n### Action 文件内容\n\n模块返回一个类，该类继承 `Action` 并实现 `invoke` 函数\n\n```ts\nimport { Action } from \"@hal-wang/cloudbase-access\";\nexport default class extends Action {\n  async invoke(): Promise<void> {}\n}\n```\n\n#### 权限参数\n\n构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n```ts\nimport { Action } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async invoke(): Promise<void> {\n    const { account } = this.ctx.req.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    this.ok(todoList);\n  }\n}\n```\n\n### Action 内置结果\n\n目前 `Action` 内置一些返回结果：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- methodNotAllowed, 405\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nthis.ok(\"success\");\n```\n\n```ts\nimport { Action } from \"@hal-wang/cloudbase-access\";\nexport default class extends Action {\n  async invoke(): Promise<void> {\n    this.noContent();\n    // or this.ok('success');\n  }\n}\n```\n\n```ts\nimport { Action } from \"@hal-wang/cloudbase-access\";\nexport default class extends Action {\n  async invoke(): Promise<void> {\n    const { account, password } = this.ctx.req.params\n\n    if(/*账号或密码错误*/) {\n      this.notFound('账号或密码错误')\n    }\n    else {\n      this.ok({/*返回信息*/})\n    }\n  }\n}\n```\n\n多数内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，命名以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n## 权限\n\n默认的权限功能是用于判断用户能否使用 API，可以精确到控制每个 `Action`\n\n`startup.useRouter()` 参数接收一个 `authFunc` 字段，值为创建 `Authority` 派生类对象的回调\n\n`Authority` 类继承于中间件类 `Middleware`，因此该类对象也是中间件，但加载方式比较特殊\n\n因此你需要新写个类，继承 `Authority`，并实现 `invoke` 函数\n\n当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同，但可能无法在 `Action` 执行前访问 `Action` 中的 `roles` 字段\n\n下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```TS\n// Authority 类，用于权限验证\nclass Auth extends Authority {\n  async invoke(): Promise<void> {\n    if (!this.roles || !this.roles.length) {\n      await this.next(); // 无需验证，执行下一个中间件\n      return;\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      this.forbidden(\"账号或密码错误\"); // 终止中间件的执行\n      return;\n    }\n\n    await this.next(); // 验证通过，执行下一个中间件\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.ctx.req.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n```\n\n```TS\n// 云函数入口\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const startup = new Startup(event, context);\n  startup.useRouter(\n    authFunc: () => new Auth(),\n  );\n  return await startup.invoke();\n};\n```\n\n```TS\n// Action\nimport { Action } from \"@hal-wang/cloudbase-access\";\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  // 只有 login 身份验证通过，才会执行此 invoke 函数\n  async invoke(): Promise<void> {\n    this.ok();\n  }\n}\n```\n\n## 自动化文档\n\n`cba` 支持自动化文档创建，目前已支持输出 `md` 格式文档。\n\n文档的编写支持两种方式：\n\n1. 字段赋值：给 `Action` 类实例对象的 `docs` 属性赋值\n2. 注释解析：按特定格式注释 `Action` 定义文件 （建议）\n\n### 使用方式\n\n使用此功能需要预先配置，后面 [自动化文档配置文件](###自动化文档配置文件) 部分有详细介绍。\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"doc\": \"cba-doc\",\n  },\n```\n\n执行 `npm run doc`\n\n### `action` 注释\n\n参考如下格式在文件任意处注释（建议在 Action 类声明之前）：\n\n```\n/**\n * @action delete docs\n *\n * a docs test named delete\n *\n * @parts test1 test2 custom\n * @input\n * @@headers\n * @@@test-header1 {string} a test header of deleting docs NO.1\n * @@@test-header2 {number}\n * @@@test-header3 {object} a test header of deleting docs NO.3\n * @@@@test-header31 {string} a test header of deleting docs NO.3.1\n * @@@@test-header32 {number} a test header of deleting docs NO.3.2\n * @@@test-header4 a test header of deleting docs NO.4\n * @@@test-header5 {number} a test header of deleting docs NO.5\n * @@body {object} ok result\n * @@@method {string} http method\n * @@params\n * @@query\n * @output\n * @@codes\n * @@@200 success\n * @@@404\n * @@body\n * @@@method {string} http method\n */\n```\n\n`@` 的数量可对比 JSON 对象的深度，其中一级和二级是固定的，如 `@action`、`@parts`、`@input`、`@output`、`@@headers`、`@@query`、`@@body`、`@@params`、`@@code`，三级或以上不做限制\n\n只有 `@action` 是必须的，如果没有则不会生成文档，其他都是可选的\n\n#### @action\n\n作为自动化文档注释的标识，其后所带内容为该 `Action` 名称，新起一行的内容则为该 `Action` 介绍\n\n#### `@input`/`@output`\n\n输入/输出的参数\n\n`@input` 可选 `@@headers`、`@@query`、`@@body`、`@@params`\n\n`@output` 可选 `@@headers`、`@@body`、`@@code`\n\n1. `@@headers`: 头部参数\n\n2. `@@params`: 查询参数\n\n3. `@@query`: RESTFul 地址参数\n\n4. `@@body`: 内容参数\n\n`@@body` 与 `@@headers`、`@@query`、`@@params` 有些不同，其右侧内容可选，内容是对 body 做介绍的文档\n\n5. `@@code`: 返回状态码\n\n#### 参数\n\n参数格式统一为 `@*prop-name {type} desc`，`@`的数量表示深度，可无限递归\n\n#### parts\n\nparts 的内容较为复杂，参考 [parts](###parts) 部分\n\n### `docs` 属性赋值\n\n`docs` 是 `ApiDocs` 对象\n\n参考如下内容给 `Action` 实例对象的 `docs` 属性赋值：\n\n```TS\n    this.docs = {\n      name: \"get docs\",\n      desc: \"a docs test named get\",\n      input: {\n        headers: [\n          {\n            name: \"test-header1\",\n            desc: \"a test header of getting docs NO.1\",\n            type: \"string\",\n          },\n          {\n            name: \"test-header2\",\n            type: \"number\",\n          },\n          {\n            name: \"test-header3\",\n            desc: \"a test header of getting docs NO.3\",\n            type: \"object\",\n            children: [\n              {\n                name: \"test-header31\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"string\",\n              },\n              {\n                name: \"test-header32\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"number\",\n              },\n            ],\n          },\n          {\n            name: \"test-header4\",\n            desc: \"a test header of getting docs NO.4\",\n            type: \"number\",\n          },\n        ],\n        body: {\n          type: \"string\",\n          desc: \"http method\",\n        },\n      },\n      output: {\n        codes: [\n          {\n            code: 200,\n            desc: \"success\",\n          },\n          {\n            code: 404,\n          },\n        ],\n        body: [\n          {\n            name: \"method\",\n            type: \"string\",\n            desc: \"http method\",\n          },\n        ],\n      },\n      parts: [\"test1\", \"test2\", \"custom\"],\n    };\n```\n\n其实 [action 注释](###action注释) 的方式最终会编译为 `ApiDocs` 对象，如果编写内容相同，则二者最终生成的文档也相同。\n\n因此各属性的介绍与 [action 注释](###action注释) 的方式相同，此处不再赘述。\n\n### @auth\n\n为了简单化，`action` 注释或 `docs` 属性赋值的方式，字段 `parts` 值也可以为一个特殊值 `@auth`，此时这个 `Action` 的 `parts` 字段值将取自 `action.roles` 字段值。\n\n更进一步，如果配置文件中的 `partsFromAuth` 属性值为 `true`，那么所有 `parts` 如果未设置值，都将取自 `action.roles` 属性值。（没有 `@input` 将忽略输入参数，没有 `@output` 将忽略输出参数 ）。\n\n### 自动化文档配置文件\n\n在 `cba.config.json` 配置文件中，doc 字段即为自动化文档的相关配置，配置格式如下：\n\n```JSON\n{\n  \"doc\": {\n    \"output\": \"../docs/api/README.md\",\n    \"title\": \"cba-title\",\n    \"subtitle\": \"cba-subtitle\",\n    \"parts\": [\n      {\n        \"name\": \"part1\",\n        \"inputHeaders\": [\n          {\n            \"name\": \"base-input-header\",\n            \"desc\": \"this is a base input header\",\n            \"type\": \"string\"\n          }\n        ]\n      },\n      {\n        \"name\": \"part2\",\n        \"outputHeaders\": [\n          {\n            \"name\": \"base-output-header\",\n            \"desc\": \"this is a base output header\",\n            \"type\": \"string\"\n          }\n        ]\n      },\n      {\n        \"name\": \"part3\",\n        \"query\": [\n          {\n            \"name\": \"base-query\",\n            \"desc\": \"this is a base query\",\n            \"type\": \"string\"\n          }\n        ]\n      }\n    ],\n    \"partsFromAuth\": true\n  }\n}\n```\n\n1. output\n1. title\n1. subtitle\n1. parts\n1. partsFromAuth\n\n#### output\n\n生成目标文件的相对路径\n\n#### title\n\n生成文档的标题\n\n#### subtitle\n\n生成文档的简介\n\n#### parts\n\n有些参数可能会被多个 API 使用，对于一个网站，可能大多数 API 都需要在头部传入`cookie`、`account`等。\n\n利用 `parts` 功能可以重复使用某些参数。\n\n每个 `part` 为一个`可配置项`\n\n##### 配置\n\n前面配置文件的 `parts` 属性值为`可配置项`数组。\n\n每个`可配置项`格式如下：\n\n```JSON\n{\n  \"name\": \"custom\",\n  \"query\": [\n    {\n      \"name\": \"base-query\",\n      \"desc\": \"this is a base query\",\n      \"type\": \"string\"\n    }\n  ],\n  \"outputHeaders\":[],\n  \"inputHeaders\":[],\n  \"params\":[],\n  \"codes\":[]\n}\n```\n\n其中 `name` 值为该配置项的标识，如果设置不正确会找不到该配置项\n\n##### 注释中的格式\n\n在注释中，parts 格式如：\n\n```\n@parts part1 part2\n```\n\n或取自 `auth` 属性值：\n\n```\n@parts @auth\n```\n","readmeFilename":"README.md","gitHead":"80340cf7246975a2e41fff8e8ade0af910f9d095","_id":"@hal-wang/cloudbase-access@2.0.0-beta.11","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-Fgb2K7avNYafwg+OANQnmgiJQMYI/ngi7x0G1fMfaxZW1YtVgB/gpSe2f75ooamc98xGl2CQF1fJ/qZqXf3F8Q==","shasum":"200630da92983d648489a44dd03bcef0eb661840","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-2.0.0-beta.11.tgz","fileCount":207,"unpackedSize":182991,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgqSj7CRA9TVsSAnZWagAARfAP/35DaUfHjZo2MzorfJXY\nwhwlMXMVSKCKfeD/Bvqo/KjRr3tOD8AZWPwqPoKLx/Zyq0lcW1eTFHYeb2mu\nAhEFIi7LNWkNp4ytYlH60l8BhBkK8hJECW8Q68ZUjV432z1aZlVv7CtFv1gf\nQeENgNVXTIAzEHt2mivRvcbQUqlH74CqzLObqNBmPP+nnTjOJkw5oHmqEMsx\nBo+h6yN7SIeAI1pEdwzoj12aX6i43Fra+iR5xhbdnkBzl7T/9/zoQH5+AGJ0\nxo4cPAW9VBCgN8xFJ9whaoIFE6o0Wha+VtARpT1ImPm4+bNO+NQ4HJCIZxyi\nw6Jm5RBHR0K1DfaAqNeUMS/TBGAyG2deAm5/oXNmPN97nUnxYRtJ9bjOdu1n\n8hA9eHR5YZm2FNQ/673sSAgdxXeei5qKYE2nISccOAIT+7Ef1q7IazdFwdS/\n56wSrZXsXxLn4msvu3OQUhjAvqJRnCogRmkcdRDqDsgVfv6W73gM9e6dhHjP\nxLG7XAhNw5ZfOorGNrvmlBiEneuL31ho6+0lxtHfU1NcLSpNoXv2mV1rBtqE\nBgTBN+oJtfuzM5MmkcC2IIu2WZzs0yvxYHorSLaMFvWghALN0paIImy7z/rw\nNbldkiegpI10jblYTGLmOD9WFkknVarAQ+dKVedolansgIfzUvRLfOFJbhe/\nGEcy\r\n=zXsC\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQCAw6Ay1lQ/kY4y0U6OtOQ8F86IT2kt8hy2LoZ30/3Y8wIgC2Pj6xN0LkeXL2VXPZYYY9zjTgrY9FtOpn+XeqsPGKk="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_2.0.0-beta.11_1621698810284_0.818956358192789"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"2.0.1":{"name":"@hal-wang/cloudbase-access","version":"2.0.1","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase","restful","nodejs-server","serverless","nodejs","typescript","javascript"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"npm run build && jest","lint":"eslint src test --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"@types/node":"^15.6.0","linq":"^3.2.3","shelljs":"^0.8.4"},"devDependencies":{"@types/jest":"^26.0.23","@types/shelljs":"^0.8.8","@typescript-eslint/eslint-plugin":"^4.24.0","@typescript-eslint/parser":"^4.24.0","eslint":"^7.27.0","eslint-config-prettier":"^8.3.0","eslint-plugin-prettier":"^3.4.0","jest":"^26.6.3","prettier":"^2.3.0","ts-jest":"^26.5.6","typescript":"^4.2.4"},"bin":{"cba-doc":"bin/cba-doc.js","cba-build":"bin/cba.js"},"gitHead":"5cf4827dff926dabeb5171dc4c6d96a5f6bca261","_id":"@hal-wang/cloudbase-access@2.0.1","_nodeVersion":"14.15.4","_npmVersion":"6.14.10","dist":{"integrity":"sha512-t9z+RP0VZH+TJmV3RMUpSv3QC9jRPZg7I6sKh2ZxusFiTMXHDbDm690nC5LTFdMIHOREFoDWqgnP9Ie9d5zhIA==","shasum":"8c35a698e7e14b328e2d2621b12207c45951a04d","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-2.0.1.tgz","fileCount":239,"unpackedSize":232431,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v3.0.13\r\nComment: https://openpgpjs.org\r\n\r\nwsFcBAEBCAAQBQJgq5uzCRA9TVsSAnZWagAAuMcP/i0p6hHNluCtPNEMOwYG\n5fkA19Nfn7n0Tpi2EQjx+ubnqr606gRhZK7HGSALaRz4JSpVppCRtQiAyhAT\nIY90MVgeTyQ9I3FCI7VwWMwsO36pHmd+aiges1/mCJXEzsCVMcN+6Pk1co/9\n0v/6JOPMIXdB7OXQ1BCeacQXrTgNT+fZBi5EpEKjCR5OPYsSjulthm5PoxVa\nKpCgpxjFLdwOTyBd9i2pWZKgQ4VZL52Z7Jv2G4cmHSiRQU7n+UDY8ISz3hWT\n3Lhpmk93VDxqsHsBvJK0STgpFNtDMfdQHmth6Zm2ixl5xQfz4jyAlgkSMQDq\nbXeBX2mHw38LzAAmPDFNYMk2epxppkoml9yqzyDWx/JHWWaDjOoXb3AzAjsv\n0KCoa4y8JR49jjC9iSYEwq1thPRtZK8N84P4nVCBkkF7eXjuhQRdS/pid3hr\n0CX1RUKpR5zBMkow1K06nQGWGsTa34wdw1P3hgp/gP+usitHeGy9g06EQ8xG\ngl1T+U+gZNswYVHbvm49LjXWjqr9FRSfs253CcXWSyCdcYsQ2YG63ojUE9pK\nHo5v9jSpbeC+kr4HsUsyXsdtuKsLMhYYoZbU5TaQUamt3okzzQ1YGadBVzRd\nboSE4Y8z2Gs/U1c4Wq+R2QTsW+yX/QDU+pwBD3VKW28vB470M21YPoCXD2uD\nGebj\r\n=9ov1\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIQDhCcGSx+4WoZiixq/P6QHLRsDX3/8asntPZNiGvik/xwIgDF4aEF0Nqsc+9e0kHgAEfW3DbYCh8cQA8ixoma++Djs="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_2.0.1_1621859250710_0.1692614768663303"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"2.0.2":{"name":"@hal-wang/cloudbase-access","version":"2.0.2","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase","restful","nodejs-server","serverless","nodejs","typescript","javascript"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"npm run build && jest","lint":"eslint src test --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"linq":"^3.2.3","shelljs":"^0.8.4"},"devDependencies":{"@types/node":"^15.6.0","@types/jest":"^26.0.23","@types/shelljs":"^0.8.8","@typescript-eslint/eslint-plugin":"^4.24.0","@typescript-eslint/parser":"^4.24.0","eslint":"^7.27.0","eslint-config-prettier":"^8.3.0","eslint-plugin-prettier":"^3.4.0","jest":"^26.6.3","prettier":"^2.3.0","ts-jest":"^26.5.6","typescript":"^4.2.4"},"bin":{"cba-doc":"bin/cba-doc.js","cba-build":"bin/cba.js"},"types":"./dist\\index.d.ts","gitHead":"4778dbea2388597f8d625373b729f642b7e27e89","_id":"@hal-wang/cloudbase-access@2.0.2","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-HMrD7tU9Ju5YTNERHlwGnt/bMO2ZNbrQ6r92m9//O7gecd1SexeQJ0j5ad/Aq0rD1KJIug3wdbMGRyheASwKFQ==","shasum":"fc2ed35a2975323ae501d179edfacc9a4e9bc349","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-2.0.2.tgz","fileCount":149,"unpackedSize":126284,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiPY8xACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqNzBAAhXaPGJMfwMT+gzAiR9JGJgMDrwvO4q+Twhg2PaB8gJEiuqiQ\r\nasalypEH4b+KI9DqY7DPR6/aACUNKfSAHIxqrUaLYeYaTzmrkntVqzowdNYe\r\nMFfLns6tGuFfp2+0yr+xrrj4c/LGu5OkTEbF3ZRvy7SDkz8ZhgFFO0J4u4f8\r\nczIWVNZDY8RQw3zCHGAAK2AZqvV336FYuzYWRHgTzY7JJ0GUs4r16KSxdN14\r\nb/y3rc0mU3AFGWNupWp2PoUS3SWBvVluYcswSt+NhIUEfT82h6y9Hkmj/zve\r\nxD9vE5f14fT6augc9Ni4QPTySzZXjbuL1jxXbnRMLIclK9/m3kipvZVCkL6f\r\n/y68Ep2SjkgRidq7M2zV+I8JiP5OqKDOuhMUu6cl3YMULJ+VI3/qsurqVTPH\r\nFnRHmdbvYQoUYk9C9s2WPIUmxGmubxGLqV/mTkHKWYaQE4GyAFmMsusQriBz\r\nhDBKQw+6w00ySYp0wpyPz4vMkKtrUoLybqNWB6/VGUPtZ1+IckFNC4/A10P9\r\nuPtpSyxqQ6cH558pQ91wlvcJrx99Ejr1k1WZq1aRs+oPkrOsJVZLevHpuXJk\r\nHHt7o5QOuH39ecx1BiHebbZTqSFkIvLEwvBk7P9ERsfFQegAx1xD34oX7NK6\r\nWpDrENx3SAzLETAm5c+wnQIphfEgeIZp4QU=\r\n=iyVU\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQCHYWXTIOyBaw+axelwgH0hcBsC22a9CINax05wpB3rjwIhALNmK0hv/R/DCAr0+CP04ErgCUi/mSix0yekQU1rLp2W"}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_2.0.2_1648201520943_0.03063612534436988"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"2.0.3":{"name":"@hal-wang/cloudbase-access","version":"2.0.3","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase","restful","nodejs-server","serverless","nodejs","typescript","javascript"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"npm run build && jest","lint":"eslint src test --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"linq":"^3.2.3","shelljs":"^0.8.4"},"devDependencies":{"@types/node":"^15.6.0","@types/jest":"^26.0.23","@types/shelljs":"^0.8.8","@typescript-eslint/eslint-plugin":"^4.24.0","@typescript-eslint/parser":"^4.24.0","eslint":"^7.27.0","eslint-config-prettier":"^8.3.0","eslint-plugin-prettier":"^3.4.0","jest":"^26.6.3","prettier":"^2.3.0","ts-jest":"^26.5.6","typescript":"^4.2.4"},"bin":{"cba-doc":"bin/cba-doc.js","cba-build":"bin/cba.js"},"types":"./dist\\index.d.ts","gitHead":"73ad0b6954a9d7e6e399e9c1745b0bf76ffdbc55","_id":"@hal-wang/cloudbase-access@2.0.3","_nodeVersion":"16.14.2","_npmVersion":"8.5.0","dist":{"integrity":"sha512-adPnQEvbRygmyG6D+ci5bJQ6W8tkaRQ4pM0aTXOKlE0Uv3qSOTLL1nnjpcWS7xlXAvSPPWS8syKZwghdjcS9Zw==","shasum":"86313fe49ce41d27f3fd69a8e86ebf5817693231","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-2.0.3.tgz","fileCount":149,"unpackedSize":126285,"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJiPZArACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmoFhxAAmlni8vUuAjDjpWfjSqJKKTZhXp6sWDHQ2AzlWevn9ceFMGyZ\r\n+pe21RJjhOBc5E1SFDhJnPA6Oqn9cdnXub0Q3GfqOPub0slOtFlRD/+zL41L\r\n+h6FspIak80g5J47iTofLt1m4Hx7RpCZEd79302sIdB/3u+H1D118AZzL9kz\r\nNb+nvL9wAeklXCzT8DBXi103Pjm3qU+mGK+MUKtGRHBijcOstI9/jtlEJyjj\r\nl+3SsR27R9AFL+z2hrwYyxUlGUj/7OcKcFjwXAZa4ZXImW9NqoYirHLTMB2S\r\nHdgusIQF710vyXmBfgCGkQBnuNLedyn4G0eLZoQvRyStYvguxM+88d0AohBn\r\nCQQSNQQmT9gdp/k+ytW3BwcPlEgHnlTAN3Dc4NGvQdIBL0a/gXBrdPdR3eDN\r\nmiUbClnlKmxMTpDEZOz8wl+zYPomIT9/N5HPqvH6IPmXW3kU0QShsar0Bjak\r\nzrhtRbwtxj/i3a39KE5t/uLO8gW4DLiN5l/jmgl68EhE4dUNrM/iJdYA/CmY\r\nP3q2LKkNY5+0vwa0GO2M+fTL2bF0GqSHo/I0Bk71snHbDoFCk1HSExGSlFzq\r\nqqGPiInL65HDSmpbuHxnpjNBbX6lbl73Uh/ZgIa/PBxz9dvttwOrI2R2RVWU\r\nUQzYNbgUsnHSlvNo5HTQeLLmSIsxllTnd2g=\r\n=QByH\r\n-----END PGP SIGNATURE-----\r\n","signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCIB1GOwB1/8j+NWJ72VDklvIU8Lo/J0t1KEplUOIkIs7iAiEAvtYG4S2VgGuP0LhaeBgi5iOvW5MznqnPE2Th1XysSZ8="}]},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_2.0.3_1648201771569_0.8061711593601157"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"},"2.0.4":{"name":"@hal-wang/cloudbase-access","version":"2.0.4","description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"keywords":["cloudbase","restful","nodejs-server","serverless","nodejs","typescript","javascript"],"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"main":"dist/index.js","scripts":{"build":"sh build.sh","deploy":"sh build.sh && npm publish --access=public","deploy:beta":"sh build.sh && npm publish --tag=beta --access=public","test":"npm run build && jest","lint":"eslint src test --ext .ts"},"jest":{"testEnvironment":"node"},"author":{"name":"hal-wang"},"license":"MIT","dependencies":{"linq":"^3.2.3","shelljs":"^0.8.4"},"devDependencies":{"@types/node":"^15.6.0","@types/jest":"^26.0.23","@types/shelljs":"^0.8.8","@typescript-eslint/eslint-plugin":"^4.24.0","@typescript-eslint/parser":"^4.24.0","eslint":"^7.27.0","eslint-config-prettier":"^8.3.0","eslint-plugin-prettier":"^3.4.0","jest":"^26.6.3","prettier":"^2.3.0","ts-jest":"^26.5.6","typescript":"^4.2.4"},"bin":{"cba-doc":"bin/cba-doc.js","cba-build":"bin/cba.js"},"types":"./dist/index.d.ts","gitHead":"eaabb816b37ca4952326ad4267f8c996a77c2fe1","_id":"@hal-wang/cloudbase-access@2.0.4","_nodeVersion":"16.15.0","_npmVersion":"8.5.5","dist":{"integrity":"sha512-hb5q4PvlCIKALKuVHmw7hG3PbS9qPg/ZYyQwd3rgMWS+arxRdY+PWxXx0mkhU5QaL4qNVVl6DBVmMbGmRiEzPQ==","shasum":"260ecc0202ea1f24a8893f3bc445c9214fd0b718","tarball":"https://registry.npmjs.org/@hal-wang/cloudbase-access/-/cloudbase-access-2.0.4.tgz","fileCount":149,"unpackedSize":126281,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEUCID6kqW8O2J0Z6MlMTFHa89bMTbv5Ge5rVS95SWiQJDRgAiEA1KVfT/7UpA2nMyAQJXfU2jHc317buv8Gy8zGMTNqeGc="}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJizn0VACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2VmqMdQ/+P4nnBNBYKqZnhy+etO1I0I9SssURLXO/Nmu0NCUXXJXM3Sji\r\nEsETbsDRDNEWKB280vC2aLpNmBYBn0ZPcyQ60h8Q2YvqgLAJhFX2FvoYSAGj\r\nRx6UYXkY2T02zvLiwa+Qozq4WJO4cH2mKGz3eb36QxhO7kOLJ5qc92qHsk7G\r\nbhEbVqfNxxC0bGMhxi1sQc3MtNP2AOC/2BUZoUsekoz8akAMyZfzuCT56PC6\r\nIazDADsW30H33U0eiOS6GoMsLyBXO+sFHvVK/8MinBk7uhZxYLvvPrfjmK+s\r\nlxFCWQPm5pWu1pvHTGpD/zpqlKguOWJer/wY9AZEfP+kR+brnkrlACqdcaPK\r\ncj6rpdsVNjGpGd92TFyOTM08D0i4DEBsGqUw2D+SYS60MBbvODRpene/d9CQ\r\nMWkVXOezFQkIO2hBL6tvoBmIFuECY0FRTmXRe4U/hM0bwhBLgVbMDzI5u4B4\r\nwcKZQ+KbZbxyNkRkcd0rIMCvjQoPoSinvxkPH5UNo/tjZI06n9QZFDvkwvxZ\r\nsyCtHgHC8jjZX+wRxotsMsQrCKbNuSWe+faP3gr47Z9Zt6ERwhOrVcRnQdCE\r\nO1sdkbniDAKDJnad9csAQ3yk9bYDP/EG8cps58aw8ZG7i61vs3Dfqm4gTtSb\r\nheuZ+j0GRDiFYHQZ0yOC3NGyZ1WsbQSH7Hg=\r\n=EJ3B\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"hal-wang","email":"hi@hal.wang"},"directories":{},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/cloudbase-access_2.0.4_1657699604857_0.43764322552002377"},"_hasShrinkwrap":false,"deprecated":"已更新为更轻更灵活的 Ipare, 详情见 https://ipare.org"}},"time":{"created":"2020-12-10T08:33:18.087Z","0.7.0":"2020-12-10T08:33:18.303Z","modified":"2022-07-13T08:08:06.100Z","0.7.1":"2020-12-10T08:47:13.036Z","0.7.2":"2020-12-21T03:08:45.042Z","0.8.0-beta.0":"2020-12-25T04:16:47.777Z","0.8.0-beta.1":"2020-12-25T05:49:17.828Z","0.8.0-beta.2":"2020-12-25T05:50:10.630Z","0.8.0":"2020-12-25T06:04:54.079Z","0.8.0-beta.3":"2020-12-25T06:06:53.083Z","0.8.1":"2020-12-25T06:49:43.650Z","0.8.2":"2020-12-25T08:39:48.139Z","0.8.3-beta":"2021-01-20T11:06:08.410Z","0.8.3-beta.1":"2021-01-20T11:16:58.189Z","0.8.3":"2021-01-20T11:47:22.403Z","0.9.0-beta.1":"2021-01-22T02:53:02.572Z","0.9.0-beta.2":"2021-02-02T08:50:28.744Z","0.9.0-beta.3":"2021-02-02T08:58:09.774Z","0.9.0-beta.4":"2021-02-02T11:39:53.157Z","0.9.0-beta.5":"2021-02-02T12:17:43.341Z","0.9.0-beta.6":"2021-02-02T12:25:30.883Z","0.9.0-beta.7":"2021-02-02T12:28:49.338Z","0.9.0-beta.8":"2021-02-03T01:59:26.231Z","0.9.0":"2021-02-03T08:59:44.577Z","0.9.1":"2021-02-04T06:18:56.313Z","0.9.2":"2021-02-04T06:31:44.023Z","0.9.3":"2021-02-04T06:52:58.566Z","0.9.4":"2021-02-04T06:56:28.778Z","0.9.5-beta.1":"2021-02-07T13:16:51.350Z","1.0.0-beta.2":"2021-02-11T07:56:04.937Z","1.0.0":"2021-02-11T07:58:46.928Z","1.0.1":"2021-02-11T08:13:14.581Z","1.0.2":"2021-02-12T10:52:05.298Z","1.0.3":"2021-03-01T09:58:44.305Z","1.1.0-beta.1":"2021-03-03T13:41:34.447Z","1.1.0-beta.2":"2021-03-04T02:22:33.368Z","1.1.0-beta.3":"2021-03-04T03:59:00.738Z","1.1.0-beta.4":"2021-03-04T05:14:40.692Z","1.1.0-beta.5":"2021-03-04T05:20:56.311Z","1.1.0-beta.6":"2021-03-04T07:37:43.882Z","1.1.0-beta.7":"2021-03-04T07:49:46.632Z","1.1.0-beta.8":"2021-03-04T08:11:49.883Z","1.1.0-beta.9":"2021-03-04T08:15:18.244Z","1.1.0":"2021-03-04T09:54:19.573Z","1.1.1":"2021-03-05T09:13:56.431Z","1.1.2":"2021-03-06T05:27:05.351Z","1.1.3":"2021-03-06T06:19:56.730Z","1.1.4":"2021-03-08T14:52:52.743Z","1.1.5":"2021-03-09T08:37:50.201Z","1.1.6":"2021-03-14T13:38:12.934Z","1.1.7":"2021-03-17T12:45:00.250Z","1.1.8":"2021-03-17T14:14:56.055Z","1.2.0-beta.1":"2021-04-04T06:54:01.834Z","1.2.0-beta.2":"2021-04-04T07:00:36.377Z","1.2.0":"2021-04-04T07:09:40.439Z","1.2.1":"2021-04-04T07:34:31.582Z","1.2.2":"2021-04-07T11:40:25.207Z","1.2.3-beta.1":"2021-04-09T07:06:34.137Z","1.2.3":"2021-04-09T11:57:41.198Z","1.2.4":"2021-04-11T08:20:38.150Z","1.2.5":"2021-04-22T09:27:09.022Z","1.2.6":"2021-04-22T09:36:01.478Z","1.2.7":"2021-04-22T09:44:24.229Z","1.2.8-beta.1":"2021-04-25T05:31:06.665Z","1.2.8-beta.2":"2021-04-25T05:32:01.800Z","1.2.8":"2021-04-25T05:59:33.462Z","1.2.9":"2021-05-09T03:55:06.919Z","1.2.10":"2021-05-12T12:20:54.914Z","2.0.0-beta.1":"2021-05-20T07:01:08.783Z","2.0.0-beta.2":"2021-05-20T07:13:35.511Z","2.0.0-beta.3":"2021-05-20T07:17:05.146Z","2.0.0-beta.4":"2021-05-20T07:25:20.855Z","2.0.0-beta.5":"2021-05-20T08:29:24.365Z","2.0.0-beta.6":"2021-05-20T14:15:11.631Z","2.0.0-beta.7":"2021-05-20T14:28:35.622Z","2.0.0-beta.8":"2021-05-20T14:51:02.738Z","2.0.0-beta.9":"2021-05-21T02:03:55.344Z","2.0.0":"2021-05-21T06:18:30.388Z","2.0.0-beta.11":"2021-05-22T15:53:30.416Z","2.0.1":"2021-05-24T12:27:30.935Z","2.0.2":"2022-03-25T09:45:21.082Z","2.0.3":"2022-03-25T09:49:31.729Z","2.0.4":"2022-07-13T08:06:45.045Z"},"maintainers":[{"name":"hal-wang","email":"hi@hal.wang"}],"description":"利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api","homepage":"https://github.com/hal-wang/cloudbase-access","keywords":["cloudbase","restful","nodejs-server","serverless","nodejs","typescript","javascript"],"repository":{"type":"git","url":"git+https://github.com/hal-wang/cloudbase-access.git"},"author":{"name":"hal-wang"},"bugs":{"url":"https://github.com/hal-wang/cloudbase-access/issues","email":"support@hal.wang"},"license":"MIT","readme":"> 已更新为更轻更灵活的 Ipare, 详情见 <https://github.com/ipare>\n\n> [@ipare/lambda](https://github.com/ipare/lambda) 为本项目升级版\n\n# cloudbase-access ( cba )\n\n利用 NodeJS 和 CloudBase 快速创建 Serverless RESTful Api\n\n## 安装\n\nnpm i @hal-wang/cloudbase-access\n\n## 示例\n\n### 简单 demo\n\n项目 demo 目录下包含 `ts 项目` 和 `js 项目` 的简单 demo\n\n### todo\n\n一个简易的 todo 项目，包含后端和前端，详情请查看 <https://todo.hal.wang/docs>\n\n线上示例：<https://todo.hal.wang>\n\n一键部署：[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Ftodo&branch=main)\n\n### short-url\n\n使用自己的域名简化链接，详情请查看 <https://github.com/hal-wang/short-url>\n\n线上示例：<https://s.hal.wang>\n\n一键部署：[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fshort-url&branch=main)\n\n### wedding-card\n\n网络喜帖，能够生成邀请二维码。详情请查看 <https://github.com/hal-wang/wedding-card>\n\n线上示例：<https://wedding.hal.wang>\n\n一键部署：[![](https://main.qcloudimg.com/raw/67f5a389f1ac6f3b4d04c7256438e44f.svg)](https://console.cloud.tencent.com/tcb/env/index?action=CreateAndDeployCloudBaseProject&appUrl=https%3A%2F%2Fgithub.com%2Fhal-wang%2Fwedding-card&branch=main)\n\n## 关于 CBA 的建议\n\n强烈建议使用 `ts` ，通过对 `cba` 的配置，能够生成云函数可用的 `js` 文件\n\n理论上 `js` 完全没问题，但作者更多的是对 `ts` 进行测试\n\n## Startup\n\n`Startup` 是 `cba` 的控制中心，构造函数传入环境 `event` 和 `context`。\n\n如在入口文件中编写（JS）：\n\n```js\nconst { Startup } = require(\"@hal-wang/cloudbase-access\");\nexports.main = async (event, context) => {\n  return await new Startup(event, context)\n    .use(async (ctx) => {\n      ctx.res.body = \"hello world\";\n    })\n    .invoke();\n};\n```\n\n以上几行代码即创建一个简单的 API\n\n## 构建\n\n在 package.json 文件的 scripts 节点下添加\n\n```JSON\n\"build\": \"cba-build\"\n```\n\n```JSON\n{\n  \"scripts\": {\n    \"build\": \"cba-build\"\n  },\n  \"dependencies\": {\n    \"@hal-wang/cloudbase-access\": \"^2.0.1\"\n  }\n}\n```\n\n构建时运行\n\n```\nnpm run build\n```\n\n## 配置文件\n\n在项目目录下定义 `cba.config.json` 文件，一个常规配置文件如下：\n\n```JSON\n{\n  \"router\": {  // 路由相关\n    \"dir\": \"controllers\", // 路由文件夹目录\n    \"strict\": false // 是否严格控制 httpMethod\n  },\n  \"ts\": { // ts编写代码的配置\n    \"static\": [ // 静态文件/文件夹。由于ts的生成目录一般在其他位置，如果有生产环境需要的非 .ts 文件，需要在此声明\n      {\n        \"source\": \"static\", // 原文件/文件夹相对路径\n        \"target\": \"assets\" // 目标文件/文件夹相对路径\n      },\n      {\n        \"source\": \"static.txt\",\n        \"target\": \"read.txt\"\n      }\n    ]\n  },\n  \"doc\": { // 使用 cba-map 命令生成文档时必须，详情参考后面的 “自动化文档”\n    \"output\": \"../docs/api/README.md\",\n    \"title\": \"cba-title\",\n    \"subtitle\": \"cba-subtitle\",\n    \"parts\": [\n      {\n        \"name\": \"part1\",\n        \"inputHeaders\": [\n          {\n            \"name\": \"base-input-header\",\n            \"desc\": \"this is a base input header\",\n            \"type\": \"string\"\n          }\n        ]\n      },\n      {\n        \"name\": \"part2\",\n        \"outputHeaders\": [\n          {\n            \"name\": \"base-output-header\",\n            \"desc\": \"this is a base output header\",\n            \"type\": \"string\"\n          }\n        ]\n      },\n      {\n        \"name\": \"part3\",\n        \"query\": [\n          {\n            \"name\": \"base-query\",\n            \"desc\": \"this is a base query\",\n            \"type\": \"string\"\n          }\n        ]\n      }\n    ],\n    \"partsFromAuth\": true\n  }\n}\n```\n\n## 路由（useRouter）\n\n调用 `startup.useRouter` 函数即可开启路由中间件，开启后能够支持路由功能，常规项目都需要使用。\n\n`useRouter` 接收一个可选配置参数 `config` ，该参数包含一个可选字段\n\n- authFunc: 函数类型，函数返回值为权限认证对象，详情后面 [权限](#权限) 部分有介绍。\n\n### 路由文件夹\n\n配置文件的 `router.dir` 值是路由文件夹路径，`cba` 能够将路由文件夹下的所有 `Action` 映射为 `http` 访问路径\n\n如果配置文件没有该值，默认为 `controllers`，并且在根目录下（ts 则是目标目录下）需要定义此文件夹\n\n所有 API Action 统一放在这个文件夹中，在 `controllers` 目录中，建立各文件或文件夹。文件是 API 的最小执行单元 Action，详情后面 [Action](##Action) 部分有介绍。\n\n### 路由匹配\n\n在`cba`中，路由与文件系统匹配。\n\n路由查询参数命名以 `^` 开头（文件系统中命名不允许出现字符 `:`），如果存在多个查询参数则后面的会覆盖前面的，如 `get user/^id/todo/^id`，则 `id` 值为 `todoId`。正确命名应如 `user/^userId/todo/^todoId`。\n\n如果限制 `httpMethod`, `action` 应以 `post.ts`、`get.ts`、`delete.ts`、`patch.ts`、`put.ts` （或其他自定义 method，扩展名为.js 效果相同 ）命名，否则任意 `httpMethod` 都可以访问。\n\n#### X-HTTP-Method-Override\n\n如果请求头部包含 `X-HTTP-Method-Override` 参数，则访问方法以 `X-HTTP-Method-Override` 值为准\n\n比如 Action 要求 `PATCH` 请求，但微信小程序不支持 `PATCH`，那么可以使用 `POST` 访问，并在头部加上此参数，值为 `PATCH`\n\n```JSON\n\"headers\":{\n  \"X-HTTP-Method-Override\":\"PATCH\"\n}\n```\n\n### strict\n\n配置文件的 `router.strict` 值决定是否开启严格模式\n\n如果设置 `router.strict: true`, 则所有 `Action` 必须严格使用 `httpMethod` 命名，与 RESTFul 规范相符。否则会找不到路由并返回 `404`。\n\n如果 `strict` 为 `false` 或不设置，则 RESTFul 规范的 API 可能会以非 RESTFul 方式调用。如路由 `user/login`，本应是 `get user/login`，但 `post user/login/get` 也能调用。因此如果使用 RESTFul 或限制 method，建议设置 `strict` 为 `true`。\n\n#### 例 1\n\n获取 todo list\n\n##### 方式 1（推荐）\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- get.ts\n```\n\n访问地址为 `get /todo`，\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoList.ts\n```\n\n访问地址为 `get /todo/getTodoList` 、 `post /todo/getTodoList` 、 `put /todo/getTodoList` 等等，效果相同。\n\n#### 例 2\n\n获取单个 todo item\n\n##### 方式 1（推荐）\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- ^id\n|           +-- get.ts\n```\n\n访问地址为 `get /todo/66`\n\n##### 方式 2\n\n目录结构如下：\n\n```\n+-- controllers\n|   +-- todo\n|       +-- getTodoItem.ts\n```\n\n访问地址为 `get(post 等) /todo/getTodoItem`，需要在 `body` 、 `header` 或 `queryParams` 传入 `todoId` 参数\n\n#### 示例建议\n\n上述两个示例都给了两种定义方式。\n\ncloudbase 云函数没有限制 httpMethod，但建议使用方式 1 更符合规范，易读性也更好。\n\n因此建议设置 `strict` 为 true 。\n\n## 中间件\n\n中间件是 `cba` 最重要的部分之一，如记录日志，验证权限\n\n以下内容都继承自中间件：\n\n1. API 执行最小单元 `Action`\n2. 权限认证 `Authority`\n3. 其他派生自类 `Middleware`的中间件\n\n所有中间件应派生自类 `Middleware`，并实现 `invoke` 函数\n\n### 执行顺序\n\n中间件是以递归方式严格按声明顺序执行，每个中间件都可以修改正向或反向管道内容\n\n在中间件里如果需要调用下一个中间件，需执行 `await this.next()`，若不调用下一个中间件，中间件将反向递归执行，并最终返回当前管道内容\n\n```\n 中间件1   中间件2 ... 中间件n\n    _       _           _\n->-|-|-----|-|---------|-|-->   没有执行 next\n   | |     | |         | |   ↓  或是最后一个\n-<-|-|-----|-|---------|-|--<   反向递归\n    -       -           -\n```\n\n### 注册中间件\n\n你需要使用 `startup.use` 注册中间件，传参是一个创建中间件的回调函数，如（JS）\n\n```js\nconst { Startup } = require(\"@hal-wang/cloudbase-access\");\nexports.main = async (event, context) => {\n  const startup = new Startup(event, context);\n\n  // 简单中间件\n  startup.use(async (ctx) => {\n    ctx.res.body = \"hello world\";\n  });\n\n  // 类中间件\n  startup.use(() => new YourMiddleware());\n\n  return await startup.invoke();\n};\n```\n\n#### 简单中间件\n\n简单中间件不需要单独写一个中间件类，但其底层仍然会被转化为普通中间件来执行\n\n```TS\nstartup.use(async (ctx) => {\n  ctx.res.body = \"hello world\";\n});\n```\n\n或\n\n```TS\nstartup.use(async (ctx,next) => {\n  ctx.res.body = \"hello world\";\n  await next();\n  ctx.res.headers.h = \"h\";\n});\n```\n\n## 路由（`startup.useRouter()`）\n\n`startup.useRouter` 是一个特殊的注册中间件的方式，调用该方法能够使 `cba` 支持路由功能\n\n该方法可能会注册一个或两个中间件：\n\n- 根据路由找到的 Action\n- 权限验证 Authority（如果传参 auth）\n\n## HttpContext\n\n管道中的内容都在 `HttpContext` 对象之中，每个中间件都可以调用 `this.ctx` 来获取或修改管道内容\n\n该对象包含以下属性：\n\n- res: `Response` 对象，API 返回结果\n- req: `Request` 对象，API 请求内容\n- action: `Action` 对象，只有执行了 `Authority` 或 `Action` 的中间件后，此值才会有内容，因此可以在任意中间件中的 `await next()` 之后使用（如果没有执行 `Authority` 或 `Action` 中间件，`action` 值仍然为 `undefined`）\n\n### Response\n\n管道的返回内容，可以调用 `ctx.res.result` 来获取最终 HTTP 返回结构 `ResponseStruct`\n\n在每个中间件中都可以修改 `this.ctx.res` 内容\n\n### Request\n\n`ctx.req` 对象已经解析并封装了请求参数\n\n在中间件中，可通过 `this.ctx.req` 方式获取请求内容\n\n`req` 对象包含以下字段\n\n- event\n- context\n- path\n- headers\n- params\n- data\n- query\n\n#### event\n\n云函数环境 `event`\n\n#### context\n\n云函数环境 `context`\n\n#### path\n\n访问路径，如`POST https://domain.com/user/login`，path 值为`user/login`。\n\n_注意：在 event 中，path 实为 `/` 开头，上例为 `/user/login`。但在 `cba` 中移除了开头的 `/`_\n\n#### headers\n\n请求头部\n\n#### params\n\n查询参数\n\n#### data\n\n请求 body，如果是 JSON 字符串，则自动转为 JSON 对象。\n\n#### query\n\nRESTFul 规范的路径中查询参数。如 `user/:id` 调用时是 `user/66`，在 query 中即存在\n\n```ts\nquery.id == \"66\"; // true;\n```\n\n## Action\n\n`Action` 也是中间件，该类继承于中间件类 `Middleware`， 正常情况 Action 会终止管道继续向后执行\n\n每次调用 API，如果顺利进行，主要执行的是自定义 `Action` 对象中的 `invoke` 函数。\n\n所有自定义 `Action` 都应派生自 `Action` 类，并重写 `invoke` 函数。\n\n### 创建一个 Action\n\n1. 在云函数根目录（即与 `index.ts` 同级）创建名为 `controllers` （也可以为其他路径或名称，但需要在配置文件设置，此处为默认 `controllers`）\n1. 根据各业务，创建 `.ts/.js` 文件或文件夹，名称自定，但名称和路径会映射为访问路径，每个文件对应一个 `action`\n1. 在 `.ts/.js` 文件中创建继承 `Action` 的类，并重写 `invoke` 函数\n\n```\n+-- controllers\n|   +-- type1\n|       +-- action1.ts\n|       +-- action2.ts\n|       +-- ...\n|   +-- type2\n|       +-- action3.ts\n|       +-- action4.ts\n|       +-- ^id\n|           +-- action5.ts\n|           +-- ...\n```\n\n### Action 文件内容\n\n模块返回一个类，该类继承 `Action` 并实现 `invoke` 函数\n\n```ts\nimport { Action } from \"@hal-wang/cloudbase-access\";\nexport default class extends Action {\n  async invoke(): Promise<void> {}\n}\n```\n\n#### 权限参数\n\n构造函数有一个可选参数，传入字符串数组，值为允许的权限角色。\n\n如判断调用需要登录信息：\n\n```ts\n[\"login\"];\n```\n\n如判断调用者是管理员：\n\n```ts\n[\"admin\"];\n```\n\n具体判断方式，参考后面的 [权限](#权限) 部分。\n\n```ts\nimport { Action } from \"@hal-wang/cloudbase-access\";\n\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  async invoke(): Promise<void> {\n    const { account } = this.ctx.req.headers; // 在auth中已经验证 account 的正确性，因此可认为调用者身份无误。\n\n    const todoList = []; // 可放心从数据库读取用户数据，因为 account 已验证登录\n    this.ok(todoList);\n  }\n}\n```\n\n### Action 内置结果\n\n目前 `Action` 内置一些返回结果：\n\n- ok, 200\n- accepted, 202\n- created, 201\n- noContent, 204\n- partialContent, 206\n- redirect, 30\\*\n- badRequest, 400\n- badRequestMsg, 400\n- forbidden, 403\n- forbiddenMsg, 403\n- notFound, 404\n- notFoundMsg, 404\n- methodNotAllowed, 405\n- errRequest, 500\n- errRequestMsg, 500\n\n```ts\nthis.ok(\"success\");\n```\n\n```ts\nimport { Action } from \"@hal-wang/cloudbase-access\";\nexport default class extends Action {\n  async invoke(): Promise<void> {\n    this.noContent();\n    // or this.ok('success');\n  }\n}\n```\n\n```ts\nimport { Action } from \"@hal-wang/cloudbase-access\";\nexport default class extends Action {\n  async invoke(): Promise<void> {\n    const { account, password } = this.ctx.req.params\n\n    if(/*账号或密码错误*/) {\n      this.notFound('账号或密码错误')\n    }\n    else {\n      this.ok({/*返回信息*/})\n    }\n  }\n}\n```\n\n多数内置类型支持传入 `body` 可选参数，`body` 为返回的内容。\nAPI 返回错误时，可统一返回 `ErrorMessage`，命名以 `Msg` 结尾的内置类型接受 `ErrorMessage` 参数。\n\n## 权限\n\n默认的权限功能是用于判断用户能否使用 API，可以精确到控制每个 `Action`\n\n`startup.useRouter()` 参数接收一个 `authFunc` 字段，值为创建 `Authority` 派生类对象的回调\n\n`Authority` 类继承于中间件类 `Middleware`，因此该类对象也是中间件，但加载方式比较特殊\n\n因此你需要新写个类，继承 `Authority`，并实现 `invoke` 函数\n\n当然你也可以自己写个权限管理中间件，效果可以与 `Authority` 相同，但可能无法在 `Action` 执行前访问 `Action` 中的 `roles` 字段\n\n下例使用请求头部的账号信息验证调用者信息，用法如下：\n\n```TS\n// Authority 类，用于权限验证\nclass Auth extends Authority {\n  async invoke(): Promise<void> {\n    if (!this.roles || !this.roles.length) {\n      await this.next(); // 无需验证，执行下一个中间件\n      return;\n    }\n\n    if (this.roles.includes(\"login\") && !this.loginAuth()) {\n      this.forbidden(\"账号或密码错误\"); // 终止中间件的执行\n      return;\n    }\n\n    await this.next(); // 验证通过，执行下一个中间件\n  }\n\n  loginAuth() {\n    // 实际情况应该需要查表等复杂操作\n    const { account, password } = this.ctx.req.headers;\n    return account == \"abc\" && password == \"123456\";\n  }\n}\n```\n\n```TS\n// 云函数入口\nexport const main = async (\n  event: Record<string, unknown>,\n  context: Record<string, unknown>\n): Promise<unknown> => {\n  const startup = new Startup(event, context)\n  .useRouter(\n    authFunc: () => new Auth(),\n  );\n  return await startup.invoke();\n};\n```\n\n```TS\n// Action\nimport { Action } from \"@hal-wang/cloudbase-access\";\nexport default class extends Action {\n  constructor() {\n    super([\"login\"]);\n  }\n\n  // 只有 login 身份验证通过，才会执行此 invoke 函数\n  async invoke(): Promise<void> {\n    this.ok();\n  }\n}\n```\n\n## 自动化文档\n\n`cba` 支持自动化文档创建，目前已支持输出 `md` 格式文档。\n\n文档的编写支持两种方式：\n\n1. 字段赋值：给 `Action` 类实例对象的 `docs` 属性赋值\n2. 注释解析：按特定格式注释 `Action` 定义文件 （建议）\n\n### 使用方式\n\n使用此功能需要预先配置，后面 [自动化文档配置文件](###自动化文档配置文件) 部分有详细介绍。\n\n在 package.json 文件中的 scripts 中添加\n\n```json\n  \"scripts\": {\n    \"doc\": \"cba-doc\",\n  },\n```\n\n执行 `npm run doc`\n\n### `action` 注释\n\n参考如下格式在文件任意处注释（建议在 Action 类声明之前）：\n\n```\n/**\n * @action delete docs\n *\n * a docs test named delete\n *\n * @parts test1 test2 custom\n * @input\n * @@headers\n * @@@test-header1 {string} a test header of deleting docs NO.1\n * @@@test-header2 {number}\n * @@@test-header3 {object} a test header of deleting docs NO.3\n * @@@@test-header31 {string} a test header of deleting docs NO.3.1\n * @@@@test-header32 {number} a test header of deleting docs NO.3.2\n * @@@test-header4 a test header of deleting docs NO.4\n * @@@test-header5 {number} a test header of deleting docs NO.5\n * @@body {object} ok result\n * @@@method {string} http method\n * @@params\n * @@query\n * @output\n * @@codes\n * @@@200 success\n * @@@404\n * @@body\n * @@@method {string} http method\n */\n```\n\n`@` 的数量可对比 JSON 对象的深度，其中一级和二级是固定的，如 `@action`、`@parts`、`@input`、`@output`、`@@headers`、`@@query`、`@@body`、`@@params`、`@@code`，三级或以上不做限制\n\n只有 `@action` 是必须的，如果没有则不会生成文档，其他都是可选的\n\n#### @action\n\n作为自动化文档注释的标识，其后所带内容为该 `Action` 名称，新起一行的内容则为该 `Action` 介绍\n\n#### `@input`/`@output`\n\n输入/输出的参数\n\n`@input` 可选 `@@headers`、`@@query`、`@@body`、`@@params`\n\n`@output` 可选 `@@headers`、`@@body`、`@@code`\n\n1. `@@headers`: 头部参数\n\n2. `@@params`: 查询参数\n\n3. `@@query`: RESTFul 地址参数\n\n4. `@@body`: 内容参数\n\n`@@body` 与 `@@headers`、`@@query`、`@@params` 有些不同，其右侧内容可选，内容是对 body 做介绍的文档\n\n5. `@@code`: 返回状态码\n\n#### 参数\n\n参数格式统一为 `@*prop-name {type} desc`，`@`的数量表示深度，可无限递归\n\n#### parts\n\nparts 的内容较为复杂，参考 [parts](###parts) 部分\n\n### `docs` 属性赋值\n\n`docs` 是 `ApiDocs` 对象\n\n参考如下内容给 `Action` 实例对象的 `docs` 属性赋值：\n\n```TS\n    this.docs = {\n      name: \"get docs\",\n      desc: \"a docs test named get\",\n      input: {\n        headers: [\n          {\n            name: \"test-header1\",\n            desc: \"a test header of getting docs NO.1\",\n            type: \"string\",\n          },\n          {\n            name: \"test-header2\",\n            type: \"number\",\n          },\n          {\n            name: \"test-header3\",\n            desc: \"a test header of getting docs NO.3\",\n            type: \"object\",\n            children: [\n              {\n                name: \"test-header31\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"string\",\n              },\n              {\n                name: \"test-header32\",\n                desc: \"a test header of getting docs NO.3.1\",\n                type: \"number\",\n              },\n            ],\n          },\n          {\n            name: \"test-header4\",\n            desc: \"a test header of getting docs NO.4\",\n            type: \"number\",\n          },\n        ],\n        body: {\n          type: \"string\",\n          desc: \"http method\",\n        },\n      },\n      output: {\n        codes: [\n          {\n            code: 200,\n            desc: \"success\",\n          },\n          {\n            code: 404,\n          },\n        ],\n        body: [\n          {\n            name: \"method\",\n            type: \"string\",\n            desc: \"http method\",\n          },\n        ],\n      },\n      parts: [\"test1\", \"test2\", \"custom\"],\n    };\n```\n\n其实 [action 注释](###action注释) 的方式最终会编译为 `ApiDocs` 对象，如果编写内容相同，则二者最终生成的文档也相同。\n\n因此各属性的介绍与 [action 注释](###action注释) 的方式相同，此处不再赘述。\n\n### @auth\n\n为了简单化，`action` 注释或 `docs` 属性赋值的方式，字段 `parts` 值也可以为一个特殊值 `@auth`，此时这个 `Action` 的 `parts` 字段值将取自 `action.roles` 字段值。\n\n更进一步，如果配置文件中的 `partsFromAuth` 属性值为 `true`，那么所有 `parts` 如果未设置值，都将取自 `action.roles` 属性值。（没有 `@input` 将忽略输入参数，没有 `@output` 将忽略输出参数 ）。\n\n### 自动化文档配置文件\n\n在 `cba.config.json` 配置文件中，doc 字段即为自动化文档的相关配置，配置格式如下：\n\n```JSON\n{\n  \"doc\": {\n    \"output\": \"../docs/api/README.md\",\n    \"title\": \"cba-title\",\n    \"subtitle\": \"cba-subtitle\",\n    \"parts\": [\n      {\n        \"name\": \"part1\",\n        \"inputHeaders\": [\n          {\n            \"name\": \"base-input-header\",\n            \"desc\": \"this is a base input header\",\n            \"type\": \"string\"\n          }\n        ]\n      },\n      {\n        \"name\": \"part2\",\n        \"outputHeaders\": [\n          {\n            \"name\": \"base-output-header\",\n            \"desc\": \"this is a base output header\",\n            \"type\": \"string\"\n          }\n        ]\n      },\n      {\n        \"name\": \"part3\",\n        \"query\": [\n          {\n            \"name\": \"base-query\",\n            \"desc\": \"this is a base query\",\n            \"type\": \"string\"\n          }\n        ]\n      }\n    ],\n    \"partsFromAuth\": true\n  }\n}\n```\n\n1. output\n1. title\n1. subtitle\n1. parts\n1. partsFromAuth\n\n#### output\n\n生成目标文件的相对路径\n\n#### title\n\n生成文档的标题\n\n#### subtitle\n\n生成文档的简介\n\n#### parts\n\n有些参数可能会被多个 API 使用，对于一个网站，可能大多数 API 都需要在头部传入`cookie`、`account`等。\n\n利用 `parts` 功能可以重复使用某些参数。\n\n每个 `part` 为一个`可配置项`\n\n##### 配置\n\n前面配置文件的 `parts` 属性值为`可配置项`数组。\n\n每个`可配置项`格式如下：\n\n```JSON\n{\n  \"name\": \"custom\",\n  \"query\": [\n    {\n      \"name\": \"base-query\",\n      \"desc\": \"this is a base query\",\n      \"type\": \"string\"\n    }\n  ],\n  \"outputHeaders\":[],\n  \"inputHeaders\":[],\n  \"params\":[],\n  \"codes\":[]\n}\n```\n\n其中 `name` 值为该配置项的标识，如果设置不正确会找不到该配置项\n\n##### 注释中的格式\n\n在注释中，parts 格式如：\n\n```\n@parts part1 part2\n```\n\n或取自 `auth` 属性值：\n\n```\n@parts @auth\n```\n","readmeFilename":"README.md"}