├── .autod.conf.js ├── .eslintrc ├── .github └── main.workflow ├── .gitignore ├── .travis.yml ├── History.md ├── README.md ├── appveyor.yml ├── lib ├── client.js ├── doc.js ├── group.js ├── index.js ├── repo.js └── user.js ├── logo.png ├── package.json └── test ├── client.test.js ├── docs.test.js ├── group.test.js ├── respos.test.js ├── user.test.js └── utils.js /.autod.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | module.exports = { 4 | write: true, 5 | prefix: '^', 6 | test: [ 7 | 'test', 8 | ], 9 | dep: [ 10 | ], 11 | devdep: [ 12 | 'egg-ci', 13 | 'egg-bin', 14 | 'autod', 15 | 'eslint', 16 | 'eslint-config-egg', 17 | ], 18 | exclude: [ 19 | './test/fixtures', 20 | ], 21 | }; 22 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint-config-egg" 3 | } 4 | -------------------------------------------------------------------------------- /.github/main.workflow: -------------------------------------------------------------------------------- 1 | workflow "Unit Test" { 2 | on = "push" 3 | resolves = ["Test"] 4 | } 5 | 6 | action "Install" { 7 | uses = "actions/npm@master" 8 | args = "install" 9 | } 10 | 11 | action "Test" { 12 | uses = "actions/npm@master" 13 | args = "run cov" 14 | secrets = ["GITHUB_TOKEN"] 15 | needs = ["Install"] 16 | } 17 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | logs/ 2 | npm-debug.log 3 | node_modules/ 4 | coverage/ 5 | .idea/ 6 | run/ 7 | .DS_Store 8 | *.swp 9 | .vscode 10 | 11 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | node_js: 4 | - '8' 5 | - '10' 6 | install: 7 | - npm i npminstall && npminstall 8 | script: 9 | - npm run ci 10 | after_script: 11 | - npminstall codecov && codecov 12 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | 1.1.1 / 2019-04-16 3 | ================== 4 | 5 | **fixes** 6 | * [[`3414384`](http://github.com/yuque/sdk/commit/34143840cce2024f7d51c5cf5c2bd7ae8e6bb760)] - fix: remove user interface (#9) (TZ | 天猪 <>) 7 | 8 | **others** 9 | * [[`e904464`](http://github.com/yuque/sdk/commit/e90446425aabaaa190ff8bb809ce79d4217a3084)] - chore: fix jsdoc lint (#8) (TZ | 天猪 <>) 10 | 11 | 1.1.0 / 2019-04-11 12 | ================== 13 | 14 | **features** 15 | * [[`42fc9fd`](http://github.com/yuque/sdk/commit/42fc9fd9fb8062a2d40adff337bbd1903a48dfa8)] - feat: rename to @yuque/sdk (#7) (TZ | 天猪 <>) 16 | 17 | 1.0.2 / 2019-04-11 18 | ================== 19 | 20 | **others** 21 | * [[`e1a7446`](http://github.com/yuque/sdk/commit/e1a74463af59d524261e36f90a0fca57dc94f402)] - chore: move to yuque group (#6) (TZ | 天猪 <>) 22 | 23 | 1.0.1 / 2019-04-11 24 | ================== 25 | 26 | **fixes** 27 | * [[`abef061`](http://github.com/yuque/sdk/commit/abef061a6d0cc37d25851fbf11cb8a362e0ade9e)] - fix: remove search repo api (#3) (Yiyu He <>) 28 | * [[`432dc23`](http://github.com/yuque/sdk/commit/432dc23adcb1e236aa28dcc33caeab14d19594cf)] - fix: jsdocs (TZ <>) 29 | 30 | **others** 31 | * [[`b1cabf9`](http://github.com/yuque/sdk/commit/b1cabf9f11ec6fc1b9d8ca18342b8056c2599b0c)] - test: fix ci (#1) (TZ | 天猪 <>) 32 | * [[`1108cdd`](http://github.com/yuque/sdk/commit/1108cddb917364914e31d6fd0be8754db833e2f4)] - chore: fix action workflow (TZ <>) 33 | * [[`2cb55a5`](http://github.com/yuque/sdk/commit/2cb55a5982caba574daa32df4e5beb86729058c7)] - chore: trigger action (TZ <>) 34 | * [[`66d65f9`](http://github.com/yuque/sdk/commit/66d65f9d09b3db5b405478e3509c332b2434c4b1)] - chore: GitHub Action (TZ | 天猪 <>) 35 | 36 | 1.0.0 / 2019-03-25 37 | ================== 38 | 39 | **features** 40 | * [[`864893e`](http://github.com/yuque/sdk/commit/864893efbb499d6b19a6184b8241a922f9180eac)] - feat: first impl (TZ <>),fatal: No names found, cannot describe anything. 41 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ![](./logo.png) 2 | 3 | Node SDK for [yuque](https://www.yuque.com/yuque/developer/api) 4 | 5 | [![NPM version][npm-image]][npm-url] 6 | [![build status][travis-image]][travis-url] 7 | [![Test coverage][codecov-image]][codecov-url] 8 | [![David deps][david-image]][david-url] 9 | [![Known Vulnerabilities][snyk-image]][snyk-url] 10 | [![NPM download][download-image]][download-url] 11 | 12 | [npm-image]: https://img.shields.io/npm/v/@yuque/sdk.svg?style=flat-square 13 | [npm-url]: https://npmjs.org/package/@yuque/sdk 14 | [travis-image]: https://img.shields.io/travis/yuque/sdk.svg?style=flat-square 15 | [travis-url]: https://travis-ci.org/yuque/sdk 16 | [codecov-image]: https://codecov.io/gh/yuque/sdk/branch/master/graph/badge.svg 17 | [codecov-url]: https://codecov.io/gh/yuque/sdk 18 | [david-image]: https://img.shields.io/david/yuque/sdk.svg?style=flat-square 19 | [david-url]: https://david-dm.org/yuque/sdk 20 | [snyk-image]: https://snyk.io/test/npm/@yuque/sdk/badge.svg?style=flat-square 21 | [snyk-url]: https://snyk.io/test/npm/@yuque/sdk 22 | [download-image]: https://img.shields.io/npm/dm/@yuque/sdk.svg?style=flat-square 23 | [download-url]: https://npmjs.org/package/@yuque/sdk 24 | 25 | ## Install 26 | 27 | ```bash 28 | npm i @yuque/sdk --save 29 | ``` 30 | 31 | ## Usage 32 | 33 | ```js 34 | const SDK = require('@yuque/sdk'); 35 | const client = new SDK({ 36 | token: '', 37 | // other options 38 | }); 39 | 40 | const result = await client.users.get(); 41 | console.log(result); 42 | 43 | // apis 44 | const { users, groups, repos, docs } = client; 45 | ``` 46 | 47 | ## Options 48 | 49 | ```js 50 | /** 51 | * @param {Object} options - opts 52 | * @param {String} options.token - yuque token, https://www.yuque.com/settings/tokens 53 | * @param {String} [options.endpoint] - yuque endpoint 54 | * @param {String} [options.userAgent] - request user-agent 55 | * @param {Object} [options.requestOpts] - default request options of [urllib](https://www.npmjs.com/package/urllib) 56 | * @param {Function} [options.handler] - special how to handler response 57 | */ 58 | ``` 59 | 60 | by default, will return `response.data.data`, you can custom it by `handler`: 61 | 62 | ```js 63 | new SDK({ 64 | handler(res) { 65 | // should handler error yourself 66 | if (res.status !== 200) { 67 | const err = new Error(res.data.message); 68 | /* istanbul ignore next */ 69 | err.status = res.data.status || res.status; 70 | err.code = res.data.code; 71 | err.data = res; 72 | throw err; 73 | } 74 | // return whatever you want 75 | const { data, abilities } = res.data; 76 | return data; 77 | }, 78 | }); 79 | ``` 80 | 81 | ## Debug 82 | 83 | ```js 84 | $ http_proxy=http://127.0.0.1:8888 TOKEN= npm test 85 | ``` 86 | 87 | ## API 88 | 89 | see [Yuque API Docs](https://www.yuque.com/yuque/developer/api) for more details. 90 | 91 | ### users 92 | 93 | see the source. 94 | 95 | ### groups 96 | 97 | see the source. 98 | 99 | ### repos 100 | 101 | see the source. 102 | 103 | ### docs 104 | 105 | see the source. 106 | 107 | ## TODO 108 | 109 | - [ ] API docs 110 | - [ ] JSDocs definition for result info 111 | - [ ] add `d.ts` or refactor to TypeScript 112 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | matrix: 3 | - nodejs_version: '8' 4 | - nodejs_version: '10' 5 | 6 | install: 7 | - ps: Install-Product node $env:nodejs_version 8 | - npm i npminstall && node_modules\.bin\npminstall 9 | 10 | test_script: 11 | - node --version 12 | - npm --version 13 | - npm run test 14 | 15 | build: off 16 | -------------------------------------------------------------------------------- /lib/client.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const httpclient = require('urllib'); 5 | const extend = require('extend2'); 6 | const debug = require('debug')('yuque'); 7 | 8 | class Client { 9 | constructor(options) { 10 | // endpoint, token, userAgent 11 | this.options = Object.assign({ 12 | endpoint: 'https://www.yuque.com/api/v2/', 13 | userAgent: '@yuque/sdk', 14 | }, options); 15 | 16 | assert(this.options.token, 'token is required'); 17 | } 18 | 19 | /** 20 | * send api request to yuque 21 | * @param {String} api - API url, DO NOT startWiths `/` 22 | * @param {Object} opts - request options 23 | * @return {Promise} response 24 | */ 25 | async request(api, opts) { 26 | const { endpoint, token, userAgent, requestOpts, handler } = this.options; 27 | 28 | const url = `${endpoint}${api}`; 29 | opts = extend(true, { 30 | method: 'GET', 31 | contentType: 'json', 32 | dataType: 'json', 33 | headers: { 34 | 'User-Agent': userAgent, 35 | 'X-Auth-Token': token, 36 | }, 37 | gzip: true, 38 | 39 | // proxy 40 | rejectUnauthorized: !process.env.http_proxy, 41 | enableProxy: !!process.env.http_proxy, 42 | proxy: process.env.http_proxy, 43 | }, requestOpts, opts); 44 | 45 | debug(`${opts.method} ${url}`); 46 | 47 | const res = await httpclient.request(url, opts); 48 | debug('response', res.data); 49 | 50 | // custom response 51 | if (handler) return handler(res); 52 | 53 | // default handler 54 | if (res.status !== 200) { 55 | const err = new Error(res.data.message); 56 | /* istanbul ignore next */ 57 | err.status = res.data.status || res.status; 58 | err.code = res.data.code; 59 | err.data = res; 60 | throw err; 61 | } 62 | 63 | return res.data.data; 64 | } 65 | } 66 | 67 | module.exports = Client; 68 | -------------------------------------------------------------------------------- /lib/doc.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | 5 | class Doc { 6 | constructor({ client }) { 7 | this.client = client; 8 | } 9 | /** 10 | * list docs of a repo 11 | * @param {Object} args - params 12 | * @param {String} args.namespace - repos namespace or id 13 | * @return {Promise} return docs 14 | */ 15 | async list({ namespace }) { 16 | assert(namespace, 'repo namespace or id is required'); 17 | return this.client.request(`repos/${namespace}/docs`, { method: 'GET' }); 18 | } 19 | 20 | /** 21 | * get detail info of a doc 22 | * @param {Object} args - params 23 | * @param {String} args.namespace - repos namespace or id 24 | * @param {String} args.slug - doc slug or id 25 | * @param {Object} [args.data] - query 26 | * @param {Number} [args.data.raw] - pass `1` will return markdown body 27 | * @return {Promise} - return specified doc 28 | */ 29 | async get({ namespace, slug, data }) { 30 | assert(namespace, 'repo namespace or id is required'); 31 | assert(slug, 'doc slug or id is required'); 32 | return this.client.request(`repos/${namespace}/docs/${slug}`, { method: 'GET', data }); 33 | } 34 | 35 | /** 36 | * create doc 37 | * @param {Object} args - params 38 | * @param {String} args.namespace - repos namespace or id 39 | * @param {Object} args.data - doc info 40 | * @param {String} args.data.title - doc title 41 | * @param {String} args.data.slug - doc slug 42 | * @param {Number} [args.data.public] - `0` as private doc, `1` as public doc 43 | * @param {String} [args.data.format] - doc type, support `markdown`(default) and `lake` 44 | * @param {String} [args.data.body] - doc content, max size is 5MB 45 | * @return {Promise} - return specified doc 46 | */ 47 | async create({ namespace, data }) { 48 | assert(namespace, 'repo namespace or id is required'); 49 | return this.client.request(`repos/${namespace}/docs`, { method: 'POST', data }); 50 | } 51 | 52 | /** 53 | * update doc 54 | * @param {Object} args - params 55 | * @param {String} args.namespace - repos namespace or id 56 | * @param {String} args.id - doc id, NOT `slug` 57 | * @param {Object} args.data - doc info 58 | * @param {String} [args.data.title] - doc title 59 | * @param {String} [args.data.slug] - doc slug 60 | * @param {Number} [args.data.public] - `0` as private doc, `1` as public doc 61 | * @param {String} [args.data.body] - doc content, markdown, max size is 5MB 62 | * @return {Promise} - return specified doc 63 | */ 64 | async update({ namespace, id, data }) { 65 | assert(namespace, 'repo namespace or id is required'); 66 | assert(id, 'doc id is required'); 67 | return this.client.request(`repos/${namespace}/docs/${id}`, { method: 'PUT', data }); 68 | } 69 | 70 | /** 71 | * delete doc 72 | * @param {Object} args - params 73 | * @param {String} args.namespace - repos namespace or id 74 | * @param {String} args.id - doc id, NOT `slug` 75 | * @return {Promise} - return specified doc 76 | */ 77 | async delete({ namespace, id }) { 78 | assert(namespace, 'repo namespace or id is required'); 79 | assert(id, 'doc id is required'); 80 | return this.client.request(`repos/${namespace}/docs/${id}`, { method: 'DELETE' }); 81 | } 82 | } 83 | 84 | module.exports = Doc; 85 | -------------------------------------------------------------------------------- /lib/group.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | 5 | class Group { 6 | constructor({ client }) { 7 | this.client = client; 8 | } 9 | /** 10 | * list groups 11 | * @param {Object} args - params 12 | * @param {String} [args.login] - user login or id 13 | * @return {Promise} return groups 14 | */ 15 | async list({ login } = {}) { 16 | const api = login ? `users/${login}/groups` : 'groups'; 17 | return this.client.request(api, { method: 'GET' }); 18 | } 19 | 20 | /** 21 | * create group 22 | * @param {Object} args - params 23 | * @param {Object} args.data - group info 24 | * @param {String} args.data.name - group name 25 | * @param {String} args.data.login - group login 26 | * @param {String} [args.data.description] - group description 27 | * @return {Promise} return group info 28 | */ 29 | async create({ data }) { 30 | assert(data, 'data is required'); 31 | assert(data.name, 'data.name is required'); 32 | assert(data.login, 'data.login is required'); 33 | return this.client.request('groups', { method: 'POST', data }); 34 | } 35 | 36 | /** 37 | * get group detail info 38 | * @param {Object} args - params 39 | * @param {String} args.login - group login or id 40 | * @return {Promise} return group info 41 | */ 42 | async get({ login }) { 43 | assert(login, 'group login or id is required'); 44 | return this.client.request(`groups/${login}`, { method: 'GET' }); 45 | } 46 | 47 | /** 48 | * update group info 49 | * @param {Object} args - params 50 | * @param {Object} args.login - group login or id 51 | * @param {Object} args.data - group info 52 | * @param {String} [args.data.name] - group name 53 | * @param {String} [args.data.login] - group login 54 | * @param {String} [args.data.description] - group description 55 | * @return {Promise} return group info 56 | */ 57 | async update({ login, data }) { 58 | assert(login, 'group login or id is required'); 59 | return this.client.request(`groups/${login}`, { method: 'PUT', data }); 60 | } 61 | 62 | /** 63 | * delete group 64 | * @param {Object} args - params 65 | * @param {Object} args.login - group login or id 66 | * @return {Promise} return group info 67 | */ 68 | async delete({ login }) { 69 | assert(login, 'group login or id is required'); 70 | return this.client.request(`groups/${login}`, { method: 'DELETE' }); 71 | } 72 | 73 | /** 74 | * list users of group 75 | * @param {Object} args - params 76 | * @param {Object} args.login - group login or id 77 | * @return {Promise} return group users 78 | */ 79 | async listUser({ login }) { 80 | assert(login, 'group login or id is required'); 81 | return this.client.request(`groups/${login}/users`, { method: 'GET' }); 82 | } 83 | 84 | /** 85 | * add or update user to group 86 | * @param {Object} args - params 87 | * @param {Object} args.group - group login or id 88 | * @param {Object} args.user - user login or id 89 | * @param {Object} [args.data] - options 90 | * @param {Object} [args.data.role] - `0` as admin, `1` as normal 91 | * @return {Promise} return group user info 92 | */ 93 | async addUser({ group, user, data }) { 94 | assert(group, 'group login or id is required'); 95 | assert(user, 'user login or id is required'); 96 | return this.client.request(`groups/${group}/users/${user}`, { method: 'PUT', data }); 97 | } 98 | 99 | /** 100 | * remove user of group 101 | * @param {Object} args - params 102 | * @param {Object} args.group - group login or id 103 | * @param {Object} args.user - user login or id 104 | * @return {Promise} return group user info 105 | */ 106 | async removeUser({ group, user }) { 107 | assert(group, 'group login or id is required'); 108 | assert(user, 'user login or id is required'); 109 | return this.client.request(`groups/${group}/users/${user}`, { method: 'DELETE' }); 110 | } 111 | } 112 | 113 | module.exports = Group; 114 | -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Client = require('./client'); 4 | const User = require('./user'); 5 | const Group = require('./group'); 6 | const Repo = require('./repo'); 7 | const Doc = require('./doc'); 8 | 9 | /** 10 | * Yuque SDK 11 | * @class 12 | */ 13 | class Yuque { 14 | /** 15 | * @param {Object} options - opts 16 | * @param {String} options.token - yuque token, https://www.yuque.com/settings/tokens 17 | * @param {String} [options.endpoint] - yuque endpoint 18 | * @param {String} [options.userAgent] - request user-agent 19 | * @param {Object} [options.requestOpts] - default request options of [urllib](https://www.npmjs.com/package/urllib) 20 | * @param {Function} [options.handler] - special how to handler response 21 | */ 22 | constructor(options) { 23 | this.options = options; 24 | 25 | const client = new Client(this.options); 26 | this._client = client; 27 | 28 | /** 29 | * @member users 30 | */ 31 | this.users = new User({ client }); 32 | 33 | /** 34 | * @member groups 35 | */ 36 | this.groups = new Group({ client }); 37 | 38 | /** 39 | * @member repos 40 | */ 41 | this.repos = new Repo({ client }); 42 | 43 | /** 44 | * @member docs 45 | */ 46 | this.docs = new Doc({ client }); 47 | } 48 | } 49 | 50 | module.exports = Yuque; 51 | -------------------------------------------------------------------------------- /lib/repo.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | 5 | class Repo { 6 | constructor({ client }) { 7 | this.client = client; 8 | } 9 | 10 | /** 11 | * list repos of user or group 12 | * @param {Object} args - params 13 | * @param {String} [args.user] - user login or id 14 | * @param {String} [args.group] - group login or id 15 | * @param {Object} [args.data] - query obj 16 | * @param {String} [args.data.type] - repo type, `Book` / `Design` / `Column` / `all` 17 | * @param {Boolean} [args.data.include_membered] - whether include your group member created 18 | * @param {Number} [args.data.offset] - limit offset, each page is 20. 19 | * @return {Promise} return repos 20 | */ 21 | async list({ user, group, data }) { 22 | assert(user || group, 'user or group is required'); 23 | const api = user ? `users/${user}/repos` : `groups/${group}/repos`; 24 | return this.client.request(api, { method: 'GET', data }); 25 | } 26 | 27 | /** 28 | * create repo 29 | * @param {Object} args - params 30 | * @param {String} [args.user] - user login or id 31 | * @param {String} [args.group] - group login or id 32 | * @param {Object} args.data - repo info 33 | * @param {String} args.data.name - repo name 34 | * @param {String} args.data.slug - repo slug 35 | * @param {String} args.data.type - repo type, `Book` / `Design` / `Column` 36 | * @param {String} [args.data.description] - repo description 37 | * @param {Number} [args.data.public] - `0` as private, `1` as bussiness public, `2` as global public 38 | * @return {Promise} return repo info 39 | */ 40 | async create({ user, group, data }) { 41 | assert(user || group, 'user or group is required'); 42 | const api = user ? `users/${user}/repos` : `groups/${group}/repos`; 43 | return this.client.request(api, { method: 'POST', data }); 44 | } 45 | 46 | /** 47 | * get repo info 48 | * @param {Object} args - params 49 | * @param {String|Number} args.namespace - repo namespace or id 50 | * @param {Object} args.data - query info 51 | * @param {String} [args.data.type] - repo type, `Book` / `Design` / `Column` 52 | * @return {Promise} return repo info 53 | */ 54 | async get({ namespace, data }) { 55 | assert(namespace, 'namespace is required'); 56 | return this.client.request(`repos/${namespace}`, { method: 'GET', data }); 57 | } 58 | 59 | /** 60 | * update repo 61 | * @param {Object} args - params 62 | * @param {String|Number} args.namespace - repo namespace or id 63 | * @param {Object} args.data - repo info 64 | * @param {String} [args.data.name] - repo name 65 | * @param {String} [args.data.slug] - repo slug 66 | * @param {String} [args.data.toc] - resp toc, as a markdown list 67 | * @param {String} [args.data.description] - repo description 68 | * @param {Number} [args.data.public] - `0` as private, `1` as bussiness public, `2` as global public 69 | * @return {Promise} return repo info 70 | */ 71 | async update({ namespace, data }) { 72 | assert(namespace, 'namespace is required'); 73 | return this.client.request(`repos/${namespace}`, { method: 'PUT', data }); 74 | } 75 | 76 | /** 77 | * delete repo 78 | * @param {Object} args - params 79 | * @param {String|Number} args.namespace - repo namespace or id 80 | * @return {Promise} return repo info 81 | */ 82 | async delete({ namespace }) { 83 | assert(namespace, 'namespace is required'); 84 | return this.client.request(`repos/${namespace}`, { method: 'DELETE' }); 85 | } 86 | 87 | /** 88 | * get repo toc 89 | * @param {Object} args - params 90 | * @param {String|Number} args.namespace - repo namespace or id 91 | * @return {Promise} return toc info, `[{ title, slug, depth }, ...]` 92 | */ 93 | async getTOC({ namespace }) { 94 | assert(namespace, 'namespace is required'); 95 | return this.client.request(`repos/${namespace}/toc`, { method: 'GET' }); 96 | } 97 | } 98 | 99 | module.exports = Repo; 100 | -------------------------------------------------------------------------------- /lib/user.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | class User { 4 | constructor({ client }) { 5 | this.client = client; 6 | } 7 | /** 8 | * get user info of special login, or get current user info of token 9 | * @param {Object} args - params 10 | * @param {String} [args.login] - user login or id 11 | * @return {Promise} return user info 12 | */ 13 | async get({ login } = {}) { 14 | const api = login ? `users/${login}` : 'user'; 15 | return this.client.request(api, { method: 'GET' }); 16 | } 17 | } 18 | 19 | module.exports = User; 20 | -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuque/sdk/57b84b56575e0858e6d0642830225adc815c16d0/logo.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@yuque/sdk", 3 | "version": "1.1.1", 4 | "description": "Node SDK for yuque", 5 | "main": "lib/index.js", 6 | "dependencies": { 7 | "debug": "^4.1.1", 8 | "extend2": "^1.0.0", 9 | "urllib": "^2.33.1" 10 | }, 11 | "devDependencies": { 12 | "autod": "^3.0.1", 13 | "egg-bin": "^4.3.7", 14 | "egg-ci": "^1.8.0", 15 | "eslint": "^4.18.1", 16 | "eslint-config-egg": "^7.0.0" 17 | }, 18 | "engines": { 19 | "node": ">=8.0.0" 20 | }, 21 | "scripts": { 22 | "autod": "autod", 23 | "lint": "eslint .", 24 | "test": "npm run lint -- --fix && egg-bin pkgfiles && npm run test-local", 25 | "test-local": "egg-bin test", 26 | "cov": "egg-bin cov", 27 | "ci": "npm run lint && egg-bin pkgfiles --check && npm run cov", 28 | "pkgfiles": "egg-bin pkgfiles" 29 | }, 30 | "ci": { 31 | "version": "8, 10" 32 | }, 33 | "eslintIgnore": [ 34 | "coverage", 35 | "dist" 36 | ], 37 | "homepage": "https://github.com/yuque/sdk", 38 | "repository": { 39 | "type": "git", 40 | "url": "git@github.com:yuque/sdk.git" 41 | }, 42 | "files": [ 43 | "lib" 44 | ], 45 | "publishConfig": { 46 | "access": "public" 47 | }, 48 | "author": "TZ ", 49 | "license": "MIT" 50 | } 51 | -------------------------------------------------------------------------------- /test/client.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const utils = require('./utils'); 5 | 6 | describe('test/client.test.js', () => { 7 | let client; 8 | 9 | it('should options.handler', async () => { 10 | client = utils.getInstance({ 11 | handler(res) { 12 | return res.data; 13 | }, 14 | }); 15 | const { data } = await client.users.get(); 16 | assert(data.id === 201213); 17 | }); 18 | 19 | it('should 404', async () => { 20 | client = utils.getInstance(); 21 | try { 22 | await client.users.get({ login: Date.now() }); 23 | throw new Error('should not run here'); 24 | } catch (err) { 25 | assert(err.message === 'Not Found'); 26 | assert(err.status === 404); 27 | } 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/docs.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const utils = require('./utils'); 5 | 6 | describe('test/docs.test.js', () => { 7 | let client; 8 | let namespace; 9 | 10 | before(() => { 11 | namespace = 'node-yuque/book'; 12 | client = utils.getInstance(); 13 | }); 14 | 15 | it('should list docs', async () => { 16 | const data = await client.docs.list({ namespace }); 17 | assert(data.length >= 1); 18 | const list = data.map(x => x.slug); 19 | assert(list.includes('quickstart')); 20 | }); 21 | 22 | it('should get doc detail', async () => { 23 | const data = await client.docs.get({ namespace, slug: 'quickstart', data: { raw: 1 } }); 24 | assert(data.title.includes('QuickStart')); 25 | assert(data.body.includes('auto created by unittest')); 26 | 27 | const doc = await client.docs.get({ namespace, slug: data.id, data: { raw: 1 } }); 28 | assert(doc.title.includes('QuickStart')); 29 | assert(doc.body.includes('auto created by unittest')); 30 | }); 31 | 32 | it('should create and delete', async () => { 33 | const slug = `unittest_create_${Date.now()}`; 34 | const title = `a doc auto created by unittest(${Date.now()})`; 35 | const data = await client.docs.create({ 36 | namespace, 37 | data: { 38 | title, 39 | slug, 40 | public: 1, 41 | body: '**auto created by unittest, this is body**', 42 | }, 43 | }); 44 | assert(data.title === title); 45 | assert(data.slug === slug); 46 | assert(data.body.includes('auto created by unittest')); 47 | 48 | const deleteData = await client.docs.delete({ namespace, id: data.id }); 49 | assert(deleteData.slug === slug); 50 | assert(deleteData.title === title); 51 | }); 52 | 53 | it('should update', async () => { 54 | const doc = await client.docs.get({ namespace, slug: 'quickstart' }); 55 | const body = `**auto created by unittest, this is body(${Date.now()})**`; 56 | const data = await client.docs.update({ 57 | namespace, 58 | id: doc.id, 59 | data: { 60 | body, 61 | }, 62 | }); 63 | assert(data.body === body); 64 | }); 65 | }); 66 | -------------------------------------------------------------------------------- /test/group.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const utils = require('./utils'); 5 | 6 | describe('test/group.test.js', () => { 7 | let client; 8 | let user; 9 | let id; 10 | 11 | before(() => { 12 | id = '201213'; 13 | user = 'globaltest'; 14 | client = utils.getInstance(); 15 | }); 16 | 17 | it('should list groups', async () => { 18 | const data = await client.groups.list(); 19 | assert(data.length >= 1); 20 | }); 21 | 22 | it('should list groups by user', async () => { 23 | const data = await client.groups.list({ login: user }); 24 | assert(data.length >= 1); 25 | const list = data.map(x => x.login); 26 | assert(list.includes('node-yuque')); 27 | }); 28 | 29 | it('should list groups by user id', async () => { 30 | const data = await client.groups.list({ login: id }); 31 | assert(data.length >= 1); 32 | const list = data.map(x => x.name); 33 | assert(list.includes('node-yuque-unittest')); 34 | }); 35 | 36 | it('should get', async () => { 37 | const data = await client.groups.get({ login: 'node-yuque' }); 38 | assert(data.name === 'node-yuque-unittest'); 39 | }); 40 | 41 | it('should get by group id', async () => { 42 | const data = await client.groups.get({ login: 298127 }); 43 | assert(data.login === 'node-yuque'); 44 | assert(data.name === 'node-yuque-unittest'); 45 | }); 46 | 47 | it('should create and delete', async () => { 48 | const name = `a group auto created by unittest(${Date.now()})`; 49 | const data = await client.groups.create({ 50 | data: { 51 | name, 52 | login: 'unittest_group', 53 | description: 'auto created by unittest', 54 | }, 55 | }); 56 | assert(data.name === name); 57 | 58 | const deleteData = await client.groups.delete({ login: 'unittest_group' }); 59 | assert(deleteData.name === name); 60 | }); 61 | 62 | it('should update', async () => { 63 | const description = `单元测试,请勿删除(${Date.now()})`; 64 | const data = await client.groups.update({ 65 | login: 'node-yuque', 66 | data: { 67 | description, 68 | }, 69 | }); 70 | assert(data.description === description); 71 | }); 72 | 73 | it('should list users', async () => { 74 | const data = await client.groups.listUser({ login: 'node-yuque' }); 75 | assert(data.length >= 1); 76 | const list = data.map(x => x.user.login); 77 | assert(list.includes(user)); 78 | }); 79 | 80 | it('should add and remove user', async () => { 81 | const data = await client.groups.addUser({ group: 'node-yuque', user: 'globaltest1', data: { role: 1 } }); 82 | assert(data.user_id === 298555); 83 | const removeData = await client.groups.removeUser({ group: 'node-yuque', user: 'globaltest1' }); 84 | assert(removeData.user_id === 298555); 85 | }); 86 | }); 87 | -------------------------------------------------------------------------------- /test/respos.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const utils = require('./utils'); 5 | 6 | describe('test/repos.test.js', () => { 7 | let client; 8 | let user; 9 | let group; 10 | 11 | before(() => { 12 | user = 'globaltest'; 13 | group = 'node-yuque'; 14 | client = utils.getInstance(); 15 | }); 16 | 17 | it('should list by user', async () => { 18 | const data = await client.repos.list({ 19 | user: 'yuque', 20 | data: { type: 'Book', include_membered: true, offset: 0 }, 21 | }); 22 | assert(data.length >= 1); 23 | }); 24 | 25 | it('should list by group', async () => { 26 | const data = await client.repos.list({ 27 | group, 28 | data: { type: 'Book', include_membered: true, offset: 0 }, 29 | }); 30 | assert(data.length === 1); 31 | const list = data.map(x => x.namespace); 32 | assert(list.includes('node-yuque/book')); 33 | }); 34 | 35 | it('should create in user and delete', async () => { 36 | const data = await client.repos.create({ 37 | user, 38 | data: { 39 | name: 'unittest for sdk', 40 | slug: 'unittest', 41 | description: 'auto created by unittest', 42 | public: 2, 43 | type: 'Book', 44 | }, 45 | }); 46 | assert(data.slug === 'unittest'); 47 | 48 | const deleteData = await client.repos.delete({ namespace: `${user}/unittest` }); 49 | assert(deleteData.slug === 'unittest'); 50 | }); 51 | 52 | it('should create in group and delete', async () => { 53 | const description = `auto created by unittest(${Date.now()})`; 54 | const data = await client.repos.create({ 55 | group, 56 | data: { 57 | name: 'unittest for sdk', 58 | slug: 'unittest', 59 | description, 60 | public: 2, 61 | type: 'Book', 62 | }, 63 | }); 64 | assert(data.slug === 'unittest'); 65 | assert(data.description === description); 66 | 67 | const deleteData = await client.repos.delete({ namespace: `${group}/unittest` }); 68 | assert(deleteData.slug === 'unittest'); 69 | assert(deleteData.description === description); 70 | }); 71 | 72 | it('should get()', async () => { 73 | const data = await client.repos.get({ namespace: 'yuque/developer' }); 74 | assert(data.slug === 'developer'); 75 | assert(data.type === 'Book'); 76 | assert(data.toc); 77 | }); 78 | 79 | it('should update()', async () => { 80 | const description = `单元测试,请勿删除(${Date.now()})`; 81 | 82 | const data = await client.repos.update({ 83 | namespace: `${group}/book`, 84 | data: { description }, 85 | }); 86 | assert(data.description === description); 87 | 88 | const info = await client.repos.get({ namespace: `${group}/book` }); 89 | assert(info.description === description); 90 | }); 91 | 92 | it('should get toc', async () => { 93 | const title = `QuickStart(${Date.now()})`; 94 | await client.repos.update({ 95 | namespace: `${group}/book`, 96 | data: { toc: `- [${title}](quickstart)` }, 97 | }); 98 | const data = await client.repos.getTOC({ namespace: `${group}/book` }); 99 | assert(data[0].title === title); 100 | assert(data[0].slug === 'quickstart'); 101 | assert(data[0].depth === 1); 102 | }); 103 | }); 104 | -------------------------------------------------------------------------------- /test/user.test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const assert = require('assert'); 4 | const utils = require('./utils'); 5 | 6 | describe('test/user.test.js', () => { 7 | let client; 8 | 9 | before(() => { 10 | client = utils.getInstance(); 11 | }); 12 | 13 | it('should get user info', async () => { 14 | const data = await client.users.get({ login: 'globaltest1' }); 15 | assert(data.id === 298555); 16 | }); 17 | 18 | it('should get self info', async () => { 19 | const data = await client.users.get(); 20 | assert(data.id === 201213); 21 | }); 22 | }); 23 | -------------------------------------------------------------------------------- /test/utils.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const Yuque = require('..'); 4 | 5 | /** 6 | * @param {Object} [options] - init options 7 | * @return {Yuque} instance 8 | */ 9 | exports.getInstance = options => { 10 | return new Yuque(Object.assign({ 11 | token: process.env.TOKEN, 12 | }, options)); 13 | }; 14 | 15 | --------------------------------------------------------------------------------