@clevercloud/client
Advanced tools
Comparing version 1.0.1 to 2.0.0-beta.0
# Clever Client changelog | ||
## 2.0.0-beta.0 (2019-08-01) | ||
- (HEAD -> 200) Expose user.getSummary() | ||
- Remove legacy getAuthorization() | ||
- Replace request with superagent | ||
- Provide error id on response.id (lecagy reasons) | ||
- Make sure /cjs is cleared when invoking task "generate-cjs-modules" | ||
- Expose helpers for WebSockets and ServerSentEvents endpoints | ||
- Move some function in "product" service | ||
- Add possibility to merge live OpenAPI doc with custom definitions (temporary lol) | ||
- Use 'oauth-1.0a' for timestamps and nonce for anonymous requests | ||
- Improve request support and error handling (browser & node) | ||
## 1.0.1 (2019-07-25) | ||
@@ -4,0 +17,0 @@ |
@@ -16,2 +16,8 @@ "use strict"; | ||
var log = _interopRequireWildcard(require("./log.js")); | ||
var metrics = _interopRequireWildcard(require("./metrics.js")); | ||
var notification = _interopRequireWildcard(require("./notification.js")); | ||
var oauth = _interopRequireWildcard(require("./oauth.js")); | ||
@@ -23,2 +29,4 @@ | ||
var product = _interopRequireWildcard(require("./product.js")); | ||
var unknown = _interopRequireWildcard(require("./unknown.js")); | ||
@@ -88,2 +96,24 @@ | ||
}, | ||
logs: { | ||
_: { | ||
get: prepareRequest(log.getOldLogs, ['appId']), | ||
drains: { | ||
get: prepareRequest(log.getDrains, ['appId']), | ||
post: prepareRequest(log.createDrain, ['appId']), | ||
_: { | ||
delete: prepareRequest(log.deleteDrain, ['appId', 'drainId']), | ||
state: { | ||
put: prepareRequest(log.updateDrainState, ['appId', 'drainId']) | ||
} | ||
} | ||
} | ||
} | ||
}, | ||
metrics: { | ||
read: { | ||
_: { | ||
get: prepareRequest(metrics.getToken, ['orgaId']) | ||
} | ||
} | ||
}, | ||
newsfeeds: { | ||
@@ -97,2 +127,32 @@ blog: { | ||
}, | ||
notifications: { | ||
emailhooks: { | ||
_: { | ||
get: prepareRequest(notification.getEmailhooks, ['ownerId']), | ||
post: prepareRequest(notification.createEmailhook, ['ownerId']), | ||
_: { | ||
delete: prepareRequest(notification.deleteEmailhook, ['ownerId', 'id']), | ||
put: prepareRequest(notification.editEmailhook, ['ownerId', 'id']) | ||
} | ||
} | ||
}, | ||
info: { | ||
events: { | ||
get: prepareRequest(notification.getAvailableEvents) | ||
}, | ||
webhookformats: { | ||
get: prepareRequest(notification.getWebhookFormats) | ||
} | ||
}, | ||
webhooks: { | ||
_: { | ||
get: prepareRequest(notification.getWebhooks, ['ownerId']), | ||
post: prepareRequest(notification.createWebhook, ['ownerId']), | ||
_: { | ||
delete: prepareRequest(notification.deleteWebhook, ['ownerId', 'id']), | ||
put: prepareRequest(notification.editWebhook, ['ownerId', 'id']) | ||
} | ||
} | ||
} | ||
}, | ||
oauth: { | ||
@@ -429,3 +489,3 @@ access_token: { | ||
_: { | ||
get: prepareRequest(unknown.todo_getAddonProvider, ['provider_id']), | ||
get: prepareRequest(product.getAddonProvider, ['provider_id']), | ||
versions: { | ||
@@ -443,3 +503,3 @@ get: prepareRequest(unknown.todo_getAddonProviderVersions, ['provider_id']) | ||
instances: { | ||
get: prepareRequest(unknown.todo_getAvailableInstances), | ||
get: prepareRequest(product.getAvailableInstances), | ||
'_-_': { | ||
@@ -733,6 +793,6 @@ get: prepareRequest(unknown.todo_getInstance, ['type', 'version']) | ||
summary: { | ||
get: prepareRequest(user.todo_getSummary) | ||
get: prepareRequest(user.getSummary) | ||
}, | ||
users: { | ||
post: prepareRequest(unknown.todo_createUser), | ||
post: prepareRequest(user.create), | ||
_: { | ||
@@ -739,0 +799,0 @@ get: prepareRequest(unknown.todo_getUser, ['id']), |
@@ -29,7 +29,5 @@ "use strict"; | ||
exports.todo_getAddonProviders = todo_getAddonProviders; | ||
exports.todo_getAddonProvider = todo_getAddonProvider; | ||
exports.todo_getAddonProviderVersions = todo_getAddonProviderVersions; | ||
exports.todo_getCountries = todo_getCountries; | ||
exports.todo_getCountryCodes = todo_getCountryCodes; | ||
exports.todo_getAvailableInstances = todo_getAvailableInstances; | ||
exports.todo_getInstance = todo_getInstance; | ||
@@ -46,3 +44,2 @@ exports.todo_getMFAKinds = todo_getMFAKinds; | ||
exports.todo_getSignupForm_1 = todo_getSignupForm_1; | ||
exports.todo_createUser = todo_createUser; | ||
exports.todo_getUser = todo_getUser; | ||
@@ -288,3 +285,3 @@ exports.todo_getApplications = todo_getApplications; | ||
headers: { | ||
Accept: 'application/x-www-form-urlencoded', | ||
Accept: 'text/html, application/json', | ||
'Content-Type': 'application/x-www-form-urlencoded' | ||
@@ -535,21 +532,2 @@ }, | ||
/** | ||
* GET /products/addonproviders/{provider_id} | ||
* @param {Object} params | ||
* @param {String} params.provider_id | ||
*/ | ||
function todo_getAddonProvider(params) { | ||
// no multipath for /self or /organisations/{id} | ||
return Promise.resolve({ | ||
method: 'get', | ||
url: `/products/addonproviders/${params.provider_id}`, | ||
headers: { | ||
Accept: 'application/json' | ||
} // no query params | ||
// no body | ||
}); | ||
} | ||
/** | ||
* GET /products/addonproviders/{provider_id}/versions | ||
@@ -610,21 +588,2 @@ * @param {Object} params | ||
/** | ||
* GET /products/instances | ||
* @param {Object} params | ||
* @param {String} params.for | ||
*/ | ||
function todo_getAvailableInstances(params) { | ||
// no multipath for /self or /organisations/{id} | ||
return Promise.resolve({ | ||
method: 'get', | ||
url: `/products/instances`, | ||
headers: { | ||
Accept: 'application/json' | ||
}, | ||
queryParams: (0, _pickNonNull.pickNonNull)(params, ['for']) // no body | ||
}); | ||
} | ||
/** | ||
* GET /products/instances/{type}-{version} | ||
@@ -851,24 +810,2 @@ * @param {Object} params | ||
/** | ||
* POST /users | ||
* @param {Object} params | ||
* @param {String} params.invitationKey | ||
* @param {String} params.addonBetaInvitationKey | ||
* @param {Object} body | ||
*/ | ||
function todo_createUser(params, body) { | ||
// no multipath for /self or /organisations/{id} | ||
return Promise.resolve({ | ||
method: 'post', | ||
url: `/users`, | ||
headers: { | ||
Accept: 'application/json', | ||
'Content-Type': 'application/json' | ||
}, | ||
queryParams: (0, _pickNonNull.pickNonNull)(params, ['invitationKey', 'addonBetaInvitationKey']), | ||
body | ||
}); | ||
} | ||
/** | ||
* GET /users/{id} | ||
@@ -875,0 +812,0 @@ * @param {Object} params |
@@ -25,3 +25,4 @@ "use strict"; | ||
exports.todo_validateEmail = todo_validateEmail; | ||
exports.todo_getSummary = todo_getSummary; | ||
exports.getSummary = getSummary; | ||
exports.create = create; | ||
@@ -395,3 +396,3 @@ var _pickNonNull = require("../pick-non-null.js"); | ||
function todo_getSummary(params) { | ||
function getSummary(params) { | ||
// no multipath for /self or /organisations/{id} | ||
@@ -407,2 +408,21 @@ return Promise.resolve({ | ||
}); | ||
} | ||
/** | ||
* POST /users | ||
* @param {Object} params | ||
* @param {Object} body | ||
*/ | ||
function create(params, body) { | ||
// no multipath for /self or /organisations/{id} | ||
return Promise.resolve({ | ||
method: 'post', | ||
url: `/users`, | ||
headers: { | ||
'Content-Type': 'application/x-www-form-urlencoded' | ||
}, | ||
// no query params | ||
body | ||
}); | ||
} |
@@ -18,3 +18,3 @@ "use strict"; | ||
var _requestRequest = require("./request.request.js"); | ||
var _requestSuperagent = require("./request.superagent.js"); | ||
@@ -31,3 +31,3 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
}); | ||
const restCallPromise = clientFn(params, body).then((0, _prefixUrl.prefixUrl)(config.API_HOST)).then((0, _oauthNode.addOauthHeader)(config)).then(_requestRequest.request); | ||
const restCallPromise = clientFn(params, body).then((0, _prefixUrl.prefixUrl)(config.API_HOST)).then((0, _oauthNode.addOauthHeader)(config)).then(_requestSuperagent.request); | ||
return _baconjs.default.fromPromise(restCallPromise); | ||
@@ -39,25 +39,5 @@ }); | ||
return ownerId != null && ownerId.includes('orga_') ? legacyClient.organisations._ : legacyClient.self; | ||
}; // add session.getHMACAuthorization(httpMethod, url, params, tokens) | ||
// so CLI can use that to sign calls to WS (events, logs, notifs...) | ||
}; | ||
legacyClient.session = { | ||
getHMACAuthorization(method, url, queryParams, tokens) { | ||
if (!tokens.user_oauth_token || !tokens.user_oauth_token_secret) { | ||
return ''; | ||
} | ||
const requestParams = { | ||
method, | ||
url, | ||
queryParams | ||
}; | ||
const { | ||
headers | ||
} = (0, _oauthNode.addOauthHeader)(config)(requestParams); | ||
return headers.Authorization; | ||
} | ||
}; | ||
return legacyClient; | ||
} |
@@ -14,4 +14,5 @@ "use strict"; | ||
return JSON.stringify(requestParams.body); | ||
} | ||
} // for now we support the fact that users sometimes already stringified the body | ||
if (requestParams.headers['Content-Type'] === FORM_TYPE && typeof requestParams.body !== 'string') { | ||
@@ -26,12 +27,14 @@ const qs = new URLSearchParams(); | ||
function formatResponse(requestParams, response) { | ||
if (requestParams.headers['Accept'] === JSON_TYPE && response.headers.get('Content-Type') === JSON_TYPE) { | ||
function parseResponseBody(response) { | ||
// We should rely on the request 'Accept' header but it's not always well defined | ||
if (response.headers.get('Content-Type') === JSON_TYPE) { | ||
return response.json(); | ||
} | ||
} // We should rely on the request 'Accept' header but it's not always well defined | ||
if (requestParams.headers['Accept'] === FORM_TYPE && response.headers.get('Content-Type') === FORM_TYPE) { | ||
if (response.headers.get('Content-Type') === FORM_TYPE) { | ||
return response.text().then(text => { | ||
const objectResponse = {}; | ||
Array.from(new URLSearchParams(text).entries()).forEach(([name, value]) => objectResponse[name] = value); | ||
return objectResponse; | ||
const responseObject = {}; | ||
Array.from(new URLSearchParams(text).entries()).forEach(([name, value]) => responseObject[name] = value); | ||
return responseObject; // TODO: return Object.fromEntries(new URLSearchParams(text).entries()) | ||
}); | ||
@@ -45,4 +48,3 @@ } | ||
const url = new URL(requestParams.url); | ||
Object.entries(requestParams.queryParams || {}).forEach(([k, v]) => url.searchParams.set(k, v)); // for now we support the fact that users sometimes already stringified the body | ||
Object.entries(requestParams.queryParams || {}).forEach(([k, v]) => url.searchParams.set(k, v)); | ||
const body = formatBody(requestParams); | ||
@@ -55,4 +57,12 @@ const response = await window.fetch(url.toString(), { ...requestParams, | ||
if (response.status >= 400) { | ||
const responseError = await response.json(); | ||
throw new Error(responseError.message); | ||
const responseBody = await parseResponseBody(response); | ||
const errorMessage = responseBody.message != null ? responseBody.message : responseBody; | ||
const error = new Error(errorMessage); // NOTE: This is only for legacy | ||
if (responseBody.id != null) { | ||
error.id = responseBody.id; | ||
} | ||
error.response = response; | ||
throw error; | ||
} | ||
@@ -64,3 +74,3 @@ | ||
return formatResponse(requestParams, response); | ||
return parseResponseBody(response); | ||
} |
@@ -5,5 +5,9 @@ import * as addon from './addon.js'; | ||
import * as github from './github.js'; | ||
import * as log from './log.js'; | ||
import * as metrics from './metrics.js'; | ||
import * as notification from './notification.js'; | ||
import * as oauth from './oauth.js'; | ||
import * as oauthConsumer from './oauth-consumer.js'; | ||
import * as organisation from './organisation.js'; | ||
import * as product from './product.js'; | ||
import * as unknown from './unknown.js'; | ||
@@ -70,2 +74,24 @@ import * as user from './user.js'; | ||
}, | ||
logs: { | ||
_: { | ||
get: prepareRequest(log.getOldLogs, ['appId']), | ||
drains: { | ||
get: prepareRequest(log.getDrains, ['appId']), | ||
post: prepareRequest(log.createDrain, ['appId']), | ||
_: { | ||
delete: prepareRequest(log.deleteDrain, ['appId', 'drainId']), | ||
state: { | ||
put: prepareRequest(log.updateDrainState, ['appId', 'drainId']), | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
metrics: { | ||
read: { | ||
_: { | ||
get: prepareRequest(metrics.getToken, ['orgaId']), | ||
}, | ||
}, | ||
}, | ||
newsfeeds: { | ||
@@ -79,2 +105,32 @@ blog: { | ||
}, | ||
notifications: { | ||
emailhooks: { | ||
_: { | ||
get: prepareRequest(notification.getEmailhooks, ['ownerId']), | ||
post: prepareRequest(notification.createEmailhook, ['ownerId']), | ||
_: { | ||
delete: prepareRequest(notification.deleteEmailhook, ['ownerId', 'id']), | ||
put: prepareRequest(notification.editEmailhook, ['ownerId', 'id']), | ||
}, | ||
}, | ||
}, | ||
info: { | ||
events: { | ||
get: prepareRequest(notification.getAvailableEvents), | ||
}, | ||
webhookformats: { | ||
get: prepareRequest(notification.getWebhookFormats), | ||
}, | ||
}, | ||
webhooks: { | ||
_: { | ||
get: prepareRequest(notification.getWebhooks, ['ownerId']), | ||
post: prepareRequest(notification.createWebhook, ['ownerId']), | ||
_: { | ||
delete: prepareRequest(notification.deleteWebhook, ['ownerId', 'id']), | ||
put: prepareRequest(notification.editWebhook, ['ownerId', 'id']), | ||
}, | ||
}, | ||
}, | ||
}, | ||
oauth: { | ||
@@ -411,3 +467,3 @@ access_token: { | ||
_: { | ||
get: prepareRequest(unknown.todo_getAddonProvider, ['provider_id']), | ||
get: prepareRequest(product.getAddonProvider, ['provider_id']), | ||
versions: { | ||
@@ -425,3 +481,3 @@ get: prepareRequest(unknown.todo_getAddonProviderVersions, ['provider_id']), | ||
instances: { | ||
get: prepareRequest(unknown.todo_getAvailableInstances), | ||
get: prepareRequest(product.getAvailableInstances), | ||
'_-_': { | ||
@@ -715,6 +771,6 @@ get: prepareRequest(unknown.todo_getInstance, ['type', 'version']), | ||
summary: { | ||
get: prepareRequest(user.todo_getSummary), | ||
get: prepareRequest(user.getSummary), | ||
}, | ||
users: { | ||
post: prepareRequest(unknown.todo_createUser), | ||
post: prepareRequest(user.create), | ||
_: { | ||
@@ -721,0 +777,0 @@ get: prepareRequest(unknown.todo_getUser, ['id']), |
@@ -205,3 +205,3 @@ import { pickNonNull } from '../pick-non-null.js'; | ||
url: `/oauth/authorize`, | ||
headers: { Accept: 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded' }, | ||
headers: { Accept: 'text/html, application/json', 'Content-Type': 'application/x-www-form-urlencoded' }, | ||
// no query params | ||
@@ -424,18 +424,2 @@ body, | ||
/** | ||
* GET /products/addonproviders/{provider_id} | ||
* @param {Object} params | ||
* @param {String} params.provider_id | ||
*/ | ||
export function todo_getAddonProvider(params) { | ||
// no multipath for /self or /organisations/{id} | ||
return Promise.resolve({ | ||
method: 'get', | ||
url: `/products/addonproviders/${params.provider_id}`, | ||
headers: { Accept: 'application/json' }, | ||
// no query params | ||
// no body | ||
}); | ||
} | ||
/** | ||
* GET /products/addonproviders/{provider_id}/versions | ||
@@ -487,18 +471,2 @@ * @param {Object} params | ||
/** | ||
* GET /products/instances | ||
* @param {Object} params | ||
* @param {String} params.for | ||
*/ | ||
export function todo_getAvailableInstances(params) { | ||
// no multipath for /self or /organisations/{id} | ||
return Promise.resolve({ | ||
method: 'get', | ||
url: `/products/instances`, | ||
headers: { Accept: 'application/json' }, | ||
queryParams: pickNonNull(params, ['for']), | ||
// no body | ||
}); | ||
} | ||
/** | ||
* GET /products/instances/{type}-{version} | ||
@@ -690,20 +658,2 @@ * @param {Object} params | ||
/** | ||
* POST /users | ||
* @param {Object} params | ||
* @param {String} params.invitationKey | ||
* @param {String} params.addonBetaInvitationKey | ||
* @param {Object} body | ||
*/ | ||
export function todo_createUser(params, body) { | ||
// no multipath for /self or /organisations/{id} | ||
return Promise.resolve({ | ||
method: 'post', | ||
url: `/users`, | ||
headers: { Accept: 'application/json', 'Content-Type': 'application/json' }, | ||
queryParams: pickNonNull(params, ['invitationKey', 'addonBetaInvitationKey']), | ||
body, | ||
}); | ||
} | ||
/** | ||
* GET /users/{id} | ||
@@ -710,0 +660,0 @@ * @param {Object} params |
@@ -308,3 +308,3 @@ import { pickNonNull } from '../pick-non-null.js'; | ||
*/ | ||
export function todo_getSummary(params) { | ||
export function getSummary(params) { | ||
// no multipath for /self or /organisations/{id} | ||
@@ -319,1 +319,17 @@ return Promise.resolve({ | ||
} | ||
/** | ||
* POST /users | ||
* @param {Object} params | ||
* @param {Object} body | ||
*/ | ||
export function create(params, body) { | ||
// no multipath for /self or /organisations/{id} | ||
return Promise.resolve({ | ||
method: 'post', | ||
url: `/users`, | ||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, | ||
// no query params | ||
body, | ||
}); | ||
} |
@@ -6,3 +6,3 @@ import Bacon from 'baconjs'; | ||
import { prefixUrl } from './prefix-url.js'; | ||
import { request } from './request.request.js'; | ||
import { request } from './request.superagent.js'; | ||
@@ -34,19 +34,3 @@ export function initCleverClient (config) { | ||
// add session.getHMACAuthorization(httpMethod, url, params, tokens) | ||
// so CLI can use that to sign calls to WS (events, logs, notifs...) | ||
legacyClient.session = { | ||
getHMACAuthorization (method, url, queryParams, tokens) { | ||
if (!tokens.user_oauth_token || !tokens.user_oauth_token_secret) { | ||
return ''; | ||
} | ||
const requestParams = { method, url, queryParams }; | ||
const { headers } = addOauthHeader(config)(requestParams); | ||
return headers.Authorization; | ||
}, | ||
}; | ||
return legacyClient; | ||
} |
@@ -11,2 +11,3 @@ const JSON_TYPE = 'application/json'; | ||
// for now we support the fact that users sometimes already stringified the body | ||
if (requestParams.headers['Content-Type'] === FORM_TYPE && typeof requestParams.body !== 'string') { | ||
@@ -23,16 +24,19 @@ const qs = new URLSearchParams(); | ||
function formatResponse (requestParams, response) { | ||
function parseResponseBody (response) { | ||
if (requestParams.headers['Accept'] === JSON_TYPE && response.headers.get('Content-Type') === JSON_TYPE) { | ||
// We should rely on the request 'Accept' header but it's not always well defined | ||
if (response.headers.get('Content-Type') === JSON_TYPE) { | ||
return response.json(); | ||
} | ||
if (requestParams.headers['Accept'] === FORM_TYPE && response.headers.get('Content-Type') === FORM_TYPE) { | ||
// We should rely on the request 'Accept' header but it's not always well defined | ||
if (response.headers.get('Content-Type') === FORM_TYPE) { | ||
return response.text() | ||
.then((text) => { | ||
const objectResponse = {}; | ||
const responseObject = {}; | ||
Array | ||
.from(new URLSearchParams(text).entries()) | ||
.forEach(([name, value]) => (objectResponse[name] = value)); | ||
return objectResponse; | ||
.forEach(([name, value]) => (responseObject[name] = value)); | ||
return responseObject; | ||
// TODO: return Object.fromEntries(new URLSearchParams(text).entries()) | ||
}); | ||
@@ -47,6 +51,6 @@ } | ||
const url = new URL(requestParams.url); | ||
Object.entries(requestParams.queryParams || {}) | ||
Object | ||
.entries(requestParams.queryParams || {}) | ||
.forEach(([k, v]) => url.searchParams.set(k, v)); | ||
// for now we support the fact that users sometimes already stringified the body | ||
const body = formatBody(requestParams); | ||
@@ -61,4 +65,13 @@ | ||
if (response.status >= 400) { | ||
const responseError = await response.json(); | ||
throw new Error(responseError.message); | ||
const responseBody = await parseResponseBody(response); | ||
const errorMessage = (responseBody.message != null) | ||
? responseBody.message | ||
: responseBody; | ||
const error = new Error(errorMessage); | ||
// NOTE: This is only for legacy | ||
if (responseBody.id != null) { | ||
error.id = responseBody.id; | ||
} | ||
error.response = response; | ||
throw error; | ||
} | ||
@@ -70,3 +83,3 @@ | ||
return formatResponse(requestParams, response); | ||
return parseResponseBody(response); | ||
} |
{ | ||
"name": "@clevercloud/client", | ||
"version": "1.0.1", | ||
"version": "2.0.0-beta.0", | ||
"description": "JavaScript REST client and utils for Clever Cloud's API", | ||
@@ -20,3 +20,3 @@ "homepage": "https://github.com/CleverCloud/clever-client.js", | ||
"generate-client-from-openapi": "node tasks/generate-client.js", | ||
"generate-cjs-modules": "babel esm --out-dir cjs", | ||
"generate-cjs-modules": "rm -rf cjs && babel esm --out-dir cjs", | ||
"lint": "eslint esm tasks tests", | ||
@@ -33,3 +33,3 @@ "lint:fix": "eslint --fix esm tasks tests", | ||
"baconjs": "^0.7.83", | ||
"request": "^2.88.0" | ||
"superagent": "^5.1.0" | ||
}, | ||
@@ -51,4 +51,4 @@ "devDependencies": { | ||
"prettier": "^1.18.2", | ||
"request": "^2.88.0" | ||
"superagent": "^5.1.0" | ||
} | ||
} |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
343576
57
11258
1