Skip to content

Commit d20b8cf

Browse files
committed
Merge branch 'release/v0.1.0'
2 parents 886393c + 6c43cd7 commit d20b8cf

10 files changed

Lines changed: 72 additions & 40 deletions

File tree

.jsdoc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"encoding": "utf8",
2121
"private": true,
2222
"recurse": true,
23-
"template": "./node_modules/jsdoc-template"
23+
"template": "./node_modules/jsdoc-template",
24+
"tutorials": "docs/tutorials"
2425
}
2526
}

.travis.yml

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,3 @@ deploy:
88
api_key: $NPM_AUTH_TOKEN
99
on:
1010
tags: true
11-
12-
notifications:
13-
email:
14-
recipients:
15-
- ipetrbroz@gmail.com
16-
on_success: change
17-
on_failure: always

README.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,26 +10,24 @@ or [generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Referenc
1010
### Authentication
1111

1212
```js
13+
const { AuthenticationClient } = require('autodesk-forge-tools');
1314
const auth = new AuthenticationClient(); // If no params, gets credentials from env. vars FORGE_CLIENT_ID and FORGE_CLIENT_SECRET
14-
const token = await auth.authenticate(['bucket:read', 'data:read']);
15-
console.log('2-legged Token', token);
15+
const authentication = await auth.authenticate(['bucket:read', 'data:read']);
16+
console.log('2-legged Token', authentication.access_token);
1617
```
1718

1819
### Data Management
1920

2021
```js
22+
const { DataManagementClient, AuthenticationClient } = require('autodesk-forge-tools');
2123
const data = new DataManagementClient(new AuthenticationClient());
2224
// List buckets
2325
for await (const buckets of await data.buckets()) {
24-
for (const bucket of buckets) {
25-
console.log('Bucket', bucket.bucketKey);
26-
}
26+
console.log('Buckets', buckets.map(bucket => bucket.bucketKey).join(','));
2727
}
2828
// List objects in bucket
2929
for await (const objects of data.objects("foo-bucket")) {
30-
for (const object of objects) {
31-
console.log('Object', object.objectId);
32-
}
30+
console.log('Objects', objects.map(object => object.objectId).join(','));
3331
}
3432
```
3533

docs/tutorials/auth-basic.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# Basic usage of authentication APIs
2+
3+
```js
4+
const { AuthenticationClient } = require('autodesk-forge-tools');
5+
const auth = new AuthenticationClient(); // If no params, gets credentials from env. vars FORGE_CLIENT_ID and FORGE_CLIENT_SECRET
6+
const authentication = await auth.authenticate(['bucket:read', 'data:read']);
7+
console.log('2-legged Token', authentication.access_token);
8+
```

docs/tutorials/data-basic.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Basic usage of data APIs
2+
3+
```js
4+
const { DataManagementClient, AuthenticationClient } = require('autodesk-forge-tools');
5+
const data = new DataManagementClient(new AuthenticationClient());
6+
// List buckets
7+
for await (const buckets of await data.buckets()) {
8+
console.log('Buckets', buckets.map(bucket => bucket.bucketKey).join(','));
9+
}
10+
// List objects in bucket
11+
for await (const objects of data.objects("foo-bucket")) {
12+
console.log('Objects', objects.map(object => object.objectId).join(','));
13+
}
14+
```

docs/tutorials/index.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"auth-basic": {
3+
"title": "Basic Authentication"
4+
},
5+
"data-basic": {
6+
"title": "Basic Data Management"
7+
}
8+
}

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "autodesk-forge-tools",
3-
"version": "0.0.6",
3+
"version": "0.1.0",
44
"description": "Tools for accessing Autodesk Forge APIs from Node.js apps.",
55
"main": "src/index.js",
66
"scripts": {

src/auth.js

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const RootPath = '/authentication/v1';
44

55
/**
66
* Client providing access to Autodesk Forge {@link https://forge.autodesk.com/en/docs/oauth/v2|authentication APIs}.
7+
* @tutorial auth-basic
78
*/
89
class AuthenticationClient {
910
/**
@@ -26,15 +27,19 @@ class AuthenticationClient {
2627
* based on their scopes and the 'expires_in' field in the response.
2728
* @param {string[]} scopes List of requested {@link https://forge.autodesk.com/en/docs/oauth/v2/developers_guide/scopes|scopes}.
2829
* @param {boolean} [force] Skip cache, if there is any, and retrieve a new token.
29-
* @returns {Promise<string>} 2-legged auth access token.
30+
* @returns {Promise<object>} Promise of 2-legged authentication object containing two fields,
31+
* 'access_token' with the actual token, and 'expires_in' with expiration time (in seconds).
3032
*/
3133
authenticate(scopes, force = false) {
3234
// Check if there's a cached token, unexpired, and with the same scopes
3335
const key = 'two-legged/' + scopes.join('/');
3436
if (!force && key in this._cached) {
3537
const cache = this._cached[key];
3638
if (cache.expires_at > Date.now()) {
37-
return cache.promise;
39+
return cache.promise.then((token) => ({
40+
access_token: token,
41+
expires_in: Math.floor((cache.expires_at - Date.now()) / 1000)
42+
}));
3843
}
3944
}
4045

@@ -45,14 +50,17 @@ class AuthenticationClient {
4550
'grant_type': 'client_credentials',
4651
'scope': scopes.join(' ')
4752
};
48-
this._cached[key] = {
53+
const cache = this._cached[key] = {
4954
expires_at: Number.MAX_VALUE,
5055
promise: post(`${RootPath}/authenticate`, { urlencoded: params }).then((resp) => {
5156
this._cached[key].expires_at = Date.now() + resp.expires_in * 1000;
5257
return resp.access_token;
5358
})
5459
};
55-
return this._cached[key].promise;
60+
return cache.promise.then((token) => ({
61+
access_token: token,
62+
expires_in: Math.floor((cache.expires_at - Date.now()) / 1000)
63+
}));
5664
}
5765
}
5866

src/data.js

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ class DataManagementClient {
3232
* @throws Error when the request fails, for example, due to insufficient rights, or incorrect scopes.
3333
*/
3434
async *buckets(page = 16) {
35-
let access_token = await this.auth.authenticate(ReadTokenScopes);
36-
let response = await get(`${RootPath}/buckets?limit=${page}`, { 'Authorization': 'Bearer ' + access_token });
35+
let authentication = await this.auth.authenticate(ReadTokenScopes);
36+
let response = await get(`${RootPath}/buckets?limit=${page}`, { 'Authorization': 'Bearer ' + authentication.access_token });
3737
yield response.items;
3838

3939
while (response.next) {
4040
const next = new URL(response.next);
4141
const startAt = querystring.escape(next.searchParams.get('startAt'));
42-
access_token = await this.auth.authenticate(ReadTokenScopes);
43-
response = await get(`${RootPath}/buckets?startAt=${startAt}&limit=${page}`, { 'Authorization': 'Bearer ' + access_token });
42+
authentication = await this.auth.authenticate(ReadTokenScopes);
43+
response = await get(`${RootPath}/buckets?startAt=${startAt}&limit=${page}`, { 'Authorization': 'Bearer ' + authentication.access_token });
4444
yield response.items;
4545
}
4646
}
@@ -56,8 +56,8 @@ class DataManagementClient {
5656
* with this name does not exist.
5757
*/
5858
async bucketDetails(bucket) {
59-
const access_token = await this.auth.authenticate(ReadTokenScopes);
60-
const response = await get(`${RootPath}/buckets/${bucket}/details`, { 'Authorization': 'Bearer ' + access_token });
59+
const authentication = await this.auth.authenticate(ReadTokenScopes);
60+
const response = await get(`${RootPath}/buckets/${bucket}/details`, { 'Authorization': 'Bearer ' + authentication.access_token });
6161
return response;
6262
}
6363

@@ -73,12 +73,12 @@ class DataManagementClient {
7373
* or when a bucket with this name already exists.
7474
*/
7575
async createBucket(bucket, dataRetention) {
76-
const access_token = await this.auth.authenticate(WriteTokenScopes);
76+
const authentication = await this.auth.authenticate(WriteTokenScopes);
7777
const params = {
7878
bucketKey: bucket,
7979
policyKey: dataRetention
8080
};
81-
const response = await post(`${RootPath}/buckets`, { json: params }, { 'Authorization': 'Bearer ' + access_token });
81+
const response = await post(`${RootPath}/buckets`, { json: params }, { 'Authorization': 'Bearer ' + authentication.access_token });
8282
return response;
8383
}
8484

@@ -95,14 +95,15 @@ class DataManagementClient {
9595
* @throws Error when the request fails, for example, due to insufficient rights, or incorrect scopes.
9696
*/
9797
async *objects(bucket, page = 16) {
98-
const access_token = await this.auth.authenticate(ReadTokenScopes);
99-
let response = await get(`${RootPath}/buckets/${bucket}/objects?limit=${page}`, { 'Authorization': 'Bearer ' + access_token });
98+
let authentication = await this.auth.authenticate(ReadTokenScopes);
99+
let response = await get(`${RootPath}/buckets/${bucket}/objects?limit=${page}`, { 'Authorization': 'Bearer ' + authentication.access_token });
100100
yield response.items;
101101

102102
while (response.next) {
103103
const next = new URL(response.next);
104104
const startAt = querystring.escape(next.searchParams.get('startAt'));
105-
response = await get(`${RootPath}/buckets/${bucket}/objects?startAt=${startAt}&limit=${page}`, { 'Authorization': 'Bearer ' + access_token });
105+
authentication = await this.auth.authenticate(ReadTokenScopes);
106+
response = await get(`${RootPath}/buckets/${bucket}/objects?startAt=${startAt}&limit=${page}`, { 'Authorization': 'Bearer ' + authentication.access_token });
106107
yield response.items;
107108
}
108109
}
@@ -121,9 +122,9 @@ class DataManagementClient {
121122
*/
122123
async uploadObject(bucket, name, contentType, data) {
123124
// TODO: add support for large file uploads using "PUT buckets/:bucketKey/objects/:objectName/resumable"
124-
const access_token = await this.auth.authenticate(WriteTokenScopes);
125+
const authentication = await this.auth.authenticate(WriteTokenScopes);
125126
const response = await put(`${RootPath}/buckets/${bucket}/objects/${name}`, data, {
126-
'Authorization': 'Bearer ' + access_token,
127+
'Authorization': 'Bearer ' + authentication.access_token,
127128
'Content-Type': contentType
128129
});
129130
return response;
@@ -139,9 +140,9 @@ class DataManagementClient {
139140
* @throws Error when the request fails, for example, due to insufficient rights, or incorrect scopes.
140141
*/
141142
async downloadObject(bucket, object) {
142-
const access_token = await this.auth.authenticate(ReadTokenScopes);
143+
const authentication = await this.auth.authenticate(ReadTokenScopes);
143144
const response = await get(`${RootPath}/buckets/${bucket}/objects/${object}`, {
144-
'Authorization': 'Bearer ' + access_token,
145+
'Authorization': 'Bearer ' + authentication.access_token,
145146
}, false);
146147
return response;
147148
}
@@ -158,8 +159,8 @@ class DataManagementClient {
158159
* with this name does not exist.
159160
*/
160161
async objectDetails(bucket, object) {
161-
const access_token = await this.auth.authenticate(ReadTokenScopes);
162-
const response = await get(`${RootPath}/buckets/${bucket}/objects/${object}/details`, { 'Authorization': 'Bearer ' + access_token });
162+
const authentication = await this.auth.authenticate(ReadTokenScopes);
163+
const response = await get(`${RootPath}/buckets/${bucket}/objects/${object}/details`, { 'Authorization': 'Bearer ' + authentication.access_token });
163164
return response;
164165
}
165166
}

test/auth.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ describe('AuthenticationClient', function() {
1212

1313
describe('authenticate()', function() {
1414
it('should return a token for valid scopes', async function() {
15-
const token = await this.client.authenticate(['viewables:read']);
16-
assert(token.length > 0);
15+
const authentication = await this.client.authenticate(['viewables:read']);
16+
assert(authentication.access_token);
17+
assert(authentication.expires_in > 0);
1718
});
1819

1920
it('should reject promise for invalid scopes', function(done) {

0 commit comments

Comments
 (0)