@unofficialbox/box-open-sdk 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/client.js +11 -2
- package/dist/cjs/errors.js +3 -2
- package/dist/cjs/managers/authorization.js +15 -0
- package/dist/cjs/runtime.js +14 -0
- package/dist/esm/client.js +11 -2
- package/dist/esm/errors.js +3 -2
- package/dist/esm/managers/authorization.js +15 -0
- package/dist/esm/runtime.js +14 -0
- package/dist/types/client.d.ts +9 -3
- package/dist/types/managers/authorization.d.ts +6 -0
- package/dist/types/runtime.d.ts +6 -0
- package/docs/auth.md +35 -8
- package/docs/pagination.md +1 -1
- package/package.json +1 -1
package/dist/cjs/client.js
CHANGED
|
@@ -181,10 +181,13 @@ class Client {
|
|
|
181
181
|
webhooks;
|
|
182
182
|
workflows;
|
|
183
183
|
zipDownloads;
|
|
184
|
+
#session;
|
|
184
185
|
/** Build a client for an authentication flow; `options` configures the
|
|
185
|
-
* runtime session (retries, `fetch`, default headers, base URLs).
|
|
186
|
+
* runtime session (retries, `fetch`, default headers, base URLs). An
|
|
187
|
+
* already configured runtime session is used as is. */
|
|
186
188
|
constructor(auth, options = {}) {
|
|
187
|
-
const session = new runtime_js_1.Client(auth, options);
|
|
189
|
+
const session = auth instanceof runtime_js_1.Client ? auth : new runtime_js_1.Client(auth, options);
|
|
190
|
+
this.#session = session;
|
|
188
191
|
this.ai = new ai_js_1.AiManager(session);
|
|
189
192
|
this.aiStudio = new ai_studio_js_1.AiStudioManager(session);
|
|
190
193
|
this.appItemAssociations = new app_item_associations_js_1.AppItemAssociationsManager(session);
|
|
@@ -274,5 +277,11 @@ class Client {
|
|
|
274
277
|
this.workflows = new workflows_js_1.WorkflowsManager(session);
|
|
275
278
|
this.zipDownloads = new zip_downloads_js_1.ZipDownloadsManager(session);
|
|
276
279
|
}
|
|
280
|
+
/** A new client whose every API call acts as the user `userId` (Box's
|
|
281
|
+
* `As-User` header). It shares this client's auth and configuration;
|
|
282
|
+
* this client is unchanged. */
|
|
283
|
+
withAsUserHeader(userId) {
|
|
284
|
+
return new Client(this.#session.withAsUserHeader(userId));
|
|
285
|
+
}
|
|
277
286
|
}
|
|
278
287
|
exports.Client = Client;
|
package/dist/cjs/errors.js
CHANGED
|
@@ -57,8 +57,9 @@ function apiErrorFromResponse(status, body) {
|
|
|
57
57
|
const value = payload[key];
|
|
58
58
|
return typeof value === 'string' ? value : undefined;
|
|
59
59
|
};
|
|
60
|
-
|
|
61
|
-
const
|
|
60
|
+
// A Box error object, or from the token endpoint an OAuth 2.0 error.
|
|
61
|
+
const code = field('code') ?? field('error');
|
|
62
|
+
const boxMessage = field('message') ?? field('error_description');
|
|
62
63
|
const requestId = field('request_id');
|
|
63
64
|
let message = `box: status ${status}`;
|
|
64
65
|
if (code !== undefined) {
|
|
@@ -145,5 +145,20 @@ class AuthorizationManager {
|
|
|
145
145
|
req = runtime.withFormBody(req, new TextEncoder().encode((0, internal_js_1.formEncode)(form)));
|
|
146
146
|
await this.session.fetch(req);
|
|
147
147
|
}
|
|
148
|
+
/** Exchange the session's current access token for one limited to `scopes`
|
|
149
|
+
* and, when given, to one item (`resource`: its API URL, e.g.
|
|
150
|
+
* `https://api.box.com/2.0/files/123`) or a shared link. The result is a plain
|
|
151
|
+
* access token with no refresh token: build a client from it with
|
|
152
|
+
* `auth.developerToken`. */
|
|
153
|
+
async downscopeToken(scopes, resource, sharedLink) {
|
|
154
|
+
return this.createOauth2Token({
|
|
155
|
+
grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
|
|
156
|
+
subject_token: await this.session.accessToken(),
|
|
157
|
+
subject_token_type: "urn:ietf:params:oauth:token-type:access_token",
|
|
158
|
+
scope: scopes.join(' '),
|
|
159
|
+
...(resource === undefined ? {} : { resource: resource }),
|
|
160
|
+
...(sharedLink === undefined ? {} : { box_shared_link: sharedLink }),
|
|
161
|
+
});
|
|
162
|
+
}
|
|
148
163
|
}
|
|
149
164
|
exports.AuthorizationManager = AuthorizationManager;
|
package/dist/cjs/runtime.js
CHANGED
|
@@ -104,6 +104,20 @@ class Client {
|
|
|
104
104
|
this.fetchImpl = options.fetch ?? fetch;
|
|
105
105
|
this.defaultHeaders = { ...(options.headers ?? {}) };
|
|
106
106
|
}
|
|
107
|
+
/** A new client that sends `As-User: userId` with every API request, so Box
|
|
108
|
+
* acts as that user (an admin, or a service account whose app may "make API
|
|
109
|
+
* calls using the as-user header"). It shares this client's auth flow and
|
|
110
|
+
* token cache, `fetch`, base URLs, and retry policy; this client is
|
|
111
|
+
* unchanged. Token requests never carry the header. */
|
|
112
|
+
withAsUserHeader(userId) {
|
|
113
|
+
const headers = Object.fromEntries(Object.entries(this.defaultHeaders).filter(([name]) => name.toLowerCase() !== 'as-user'));
|
|
114
|
+
return new Client(this.auth, {
|
|
115
|
+
maxRetries: this.maxRetries,
|
|
116
|
+
baseUrls: this.baseUrls,
|
|
117
|
+
fetch: this.fetchImpl,
|
|
118
|
+
headers: { ...headers, 'As-User': userId },
|
|
119
|
+
});
|
|
120
|
+
}
|
|
107
121
|
/** The configured base URL for a D-106 class, without a trailing slash. */
|
|
108
122
|
baseUrl(name) {
|
|
109
123
|
return this.baseUrls[name] ?? '';
|
package/dist/esm/client.js
CHANGED
|
@@ -178,10 +178,13 @@ export class Client {
|
|
|
178
178
|
webhooks;
|
|
179
179
|
workflows;
|
|
180
180
|
zipDownloads;
|
|
181
|
+
#session;
|
|
181
182
|
/** Build a client for an authentication flow; `options` configures the
|
|
182
|
-
* runtime session (retries, `fetch`, default headers, base URLs).
|
|
183
|
+
* runtime session (retries, `fetch`, default headers, base URLs). An
|
|
184
|
+
* already configured runtime session is used as is. */
|
|
183
185
|
constructor(auth, options = {}) {
|
|
184
|
-
const session = new Session(auth, options);
|
|
186
|
+
const session = auth instanceof Session ? auth : new Session(auth, options);
|
|
187
|
+
this.#session = session;
|
|
185
188
|
this.ai = new AiManager(session);
|
|
186
189
|
this.aiStudio = new AiStudioManager(session);
|
|
187
190
|
this.appItemAssociations = new AppItemAssociationsManager(session);
|
|
@@ -271,4 +274,10 @@ export class Client {
|
|
|
271
274
|
this.workflows = new WorkflowsManager(session);
|
|
272
275
|
this.zipDownloads = new ZipDownloadsManager(session);
|
|
273
276
|
}
|
|
277
|
+
/** A new client whose every API call acts as the user `userId` (Box's
|
|
278
|
+
* `As-User` header). It shares this client's auth and configuration;
|
|
279
|
+
* this client is unchanged. */
|
|
280
|
+
withAsUserHeader(userId) {
|
|
281
|
+
return new Client(this.#session.withAsUserHeader(userId));
|
|
282
|
+
}
|
|
274
283
|
}
|
package/dist/esm/errors.js
CHANGED
|
@@ -51,8 +51,9 @@ export function apiErrorFromResponse(status, body) {
|
|
|
51
51
|
const value = payload[key];
|
|
52
52
|
return typeof value === 'string' ? value : undefined;
|
|
53
53
|
};
|
|
54
|
-
|
|
55
|
-
const
|
|
54
|
+
// A Box error object, or from the token endpoint an OAuth 2.0 error.
|
|
55
|
+
const code = field('code') ?? field('error');
|
|
56
|
+
const boxMessage = field('message') ?? field('error_description');
|
|
56
57
|
const requestId = field('request_id');
|
|
57
58
|
let message = `box: status ${status}`;
|
|
58
59
|
if (code !== undefined) {
|
|
@@ -109,4 +109,19 @@ export class AuthorizationManager {
|
|
|
109
109
|
req = runtime.withFormBody(req, new TextEncoder().encode(formEncode(form)));
|
|
110
110
|
await this.session.fetch(req);
|
|
111
111
|
}
|
|
112
|
+
/** Exchange the session's current access token for one limited to `scopes`
|
|
113
|
+
* and, when given, to one item (`resource`: its API URL, e.g.
|
|
114
|
+
* `https://api.box.com/2.0/files/123`) or a shared link. The result is a plain
|
|
115
|
+
* access token with no refresh token: build a client from it with
|
|
116
|
+
* `auth.developerToken`. */
|
|
117
|
+
async downscopeToken(scopes, resource, sharedLink) {
|
|
118
|
+
return this.createOauth2Token({
|
|
119
|
+
grant_type: "urn:ietf:params:oauth:grant-type:token-exchange",
|
|
120
|
+
subject_token: await this.session.accessToken(),
|
|
121
|
+
subject_token_type: "urn:ietf:params:oauth:token-type:access_token",
|
|
122
|
+
scope: scopes.join(' '),
|
|
123
|
+
...(resource === undefined ? {} : { resource: resource }),
|
|
124
|
+
...(sharedLink === undefined ? {} : { box_shared_link: sharedLink }),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
112
127
|
}
|
package/dist/esm/runtime.js
CHANGED
|
@@ -69,6 +69,20 @@ export class Client {
|
|
|
69
69
|
this.fetchImpl = options.fetch ?? fetch;
|
|
70
70
|
this.defaultHeaders = { ...(options.headers ?? {}) };
|
|
71
71
|
}
|
|
72
|
+
/** A new client that sends `As-User: userId` with every API request, so Box
|
|
73
|
+
* acts as that user (an admin, or a service account whose app may "make API
|
|
74
|
+
* calls using the as-user header"). It shares this client's auth flow and
|
|
75
|
+
* token cache, `fetch`, base URLs, and retry policy; this client is
|
|
76
|
+
* unchanged. Token requests never carry the header. */
|
|
77
|
+
withAsUserHeader(userId) {
|
|
78
|
+
const headers = Object.fromEntries(Object.entries(this.defaultHeaders).filter(([name]) => name.toLowerCase() !== 'as-user'));
|
|
79
|
+
return new Client(this.auth, {
|
|
80
|
+
maxRetries: this.maxRetries,
|
|
81
|
+
baseUrls: this.baseUrls,
|
|
82
|
+
fetch: this.fetchImpl,
|
|
83
|
+
headers: { ...headers, 'As-User': userId },
|
|
84
|
+
});
|
|
85
|
+
}
|
|
72
86
|
/** The configured base URL for a D-106 class, without a trailing slash. */
|
|
73
87
|
baseUrl(name) {
|
|
74
88
|
return this.baseUrls[name] ?? '';
|
package/dist/types/client.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Auth, ClientOptions } from './runtime.js';
|
|
1
|
+
import { Auth, Client as Session, ClientOptions } from './runtime.js';
|
|
2
2
|
import { AiManager } from './managers/ai.js';
|
|
3
3
|
import { AiStudioManager } from './managers/ai_studio.js';
|
|
4
4
|
import { AppItemAssociationsManager } from './managers/app_item_associations.js';
|
|
@@ -89,6 +89,7 @@ import { WorkflowsManager } from './managers/workflows.js';
|
|
|
89
89
|
import { ZipDownloadsManager } from './managers/zip_downloads.js';
|
|
90
90
|
/** The Box SDK client: one manager per API area over a shared session. */
|
|
91
91
|
export declare class Client {
|
|
92
|
+
#private;
|
|
92
93
|
readonly ai: AiManager;
|
|
93
94
|
readonly aiStudio: AiStudioManager;
|
|
94
95
|
readonly appItemAssociations: AppItemAssociationsManager;
|
|
@@ -178,6 +179,11 @@ export declare class Client {
|
|
|
178
179
|
readonly workflows: WorkflowsManager;
|
|
179
180
|
readonly zipDownloads: ZipDownloadsManager;
|
|
180
181
|
/** Build a client for an authentication flow; `options` configures the
|
|
181
|
-
* runtime session (retries, `fetch`, default headers, base URLs).
|
|
182
|
-
|
|
182
|
+
* runtime session (retries, `fetch`, default headers, base URLs). An
|
|
183
|
+
* already configured runtime session is used as is. */
|
|
184
|
+
constructor(auth: Auth | Session, options?: ClientOptions);
|
|
185
|
+
/** A new client whose every API call acts as the user `userId` (Box's
|
|
186
|
+
* `As-User` header). It shares this client's auth and configuration;
|
|
187
|
+
* this client is unchanged. */
|
|
188
|
+
withAsUserHeader(userId: string): Client;
|
|
183
189
|
}
|
|
@@ -14,4 +14,10 @@ export declare class AuthorizationManager {
|
|
|
14
14
|
createOauth2Token(body: models.schemas.PostOAuth2Token): Promise<models.schemas.AccessToken>;
|
|
15
15
|
createOauth2TokenRefresh(body: models.schemas.PostOAuth2TokenRefreshAccessToken): Promise<models.schemas.AccessToken>;
|
|
16
16
|
revokeOauth2(body: models.schemas.PostOAuth2Revoke): Promise<void>;
|
|
17
|
+
/** Exchange the session's current access token for one limited to `scopes`
|
|
18
|
+
* and, when given, to one item (`resource`: its API URL, e.g.
|
|
19
|
+
* `https://api.box.com/2.0/files/123`) or a shared link. The result is a plain
|
|
20
|
+
* access token with no refresh token: build a client from it with
|
|
21
|
+
* `auth.developerToken`. */
|
|
22
|
+
downscopeToken(scopes: readonly string[], resource?: string, sharedLink?: string): Promise<models.schemas.AccessToken>;
|
|
17
23
|
}
|
package/dist/types/runtime.d.ts
CHANGED
|
@@ -53,6 +53,12 @@ export declare class Client {
|
|
|
53
53
|
private readonly fetchImpl;
|
|
54
54
|
private readonly defaultHeaders;
|
|
55
55
|
constructor(auth: Auth, options?: ClientOptions);
|
|
56
|
+
/** A new client that sends `As-User: userId` with every API request, so Box
|
|
57
|
+
* acts as that user (an admin, or a service account whose app may "make API
|
|
58
|
+
* calls using the as-user header"). It shares this client's auth flow and
|
|
59
|
+
* token cache, `fetch`, base URLs, and retry policy; this client is
|
|
60
|
+
* unchanged. Token requests never carry the header. */
|
|
61
|
+
withAsUserHeader(userId: string): Client;
|
|
56
62
|
/** The configured base URL for a D-106 class, without a trailing slash. */
|
|
57
63
|
baseUrl(name: string): string;
|
|
58
64
|
/** A valid access token for the configured auth flow. The `signal` is
|
package/docs/auth.md
CHANGED
|
@@ -23,9 +23,9 @@ to act as a managed user:
|
|
|
23
23
|
```ts
|
|
24
24
|
import { auth } from '@unofficialbox/box-open-sdk';
|
|
25
25
|
const client = new Client(auth.clientCredentials({
|
|
26
|
-
clientId: 'CLIENT_ID',
|
|
27
|
-
clientSecret: 'CLIENT_SECRET',
|
|
28
|
-
enterpriseId: 'ENTERPRISE_ID',
|
|
26
|
+
clientId: 'CLIENT_ID',
|
|
27
|
+
clientSecret: 'CLIENT_SECRET',
|
|
28
|
+
enterpriseId: 'ENTERPRISE_ID',
|
|
29
29
|
}));
|
|
30
30
|
```
|
|
31
31
|
|
|
@@ -38,11 +38,11 @@ imported from the runtime's `./jwt` entry point and returns a promise:
|
|
|
38
38
|
```ts
|
|
39
39
|
import { jwtAuth } from '@unofficialbox/box-open-sdk/jwt';
|
|
40
40
|
const auth = await jwtAuth({
|
|
41
|
-
clientId: 'CLIENT_ID',
|
|
42
|
-
clientSecret: 'CLIENT_SECRET',
|
|
43
|
-
publicKeyId: 'PUBLIC_KEY_ID',
|
|
44
|
-
privateKeyPem: privateKeyPem, // optionally encrypted; set passphrase
|
|
45
|
-
enterpriseId: 'ENTERPRISE_ID',
|
|
41
|
+
clientId: 'CLIENT_ID',
|
|
42
|
+
clientSecret: 'CLIENT_SECRET',
|
|
43
|
+
publicKeyId: 'PUBLIC_KEY_ID',
|
|
44
|
+
privateKeyPem: privateKeyPem, // optionally encrypted; set passphrase
|
|
45
|
+
enterpriseId: 'ENTERPRISE_ID',
|
|
46
46
|
});
|
|
47
47
|
const client = new Client(auth);
|
|
48
48
|
```
|
|
@@ -58,3 +58,30 @@ import { auth } from '@unofficialbox/box-open-sdk';
|
|
|
58
58
|
const source = auth.oauth({ clientId: 'CLIENT_ID', clientSecret: 'CLIENT_SECRET' }, storedRefreshToken);
|
|
59
59
|
const client = new Client(source);
|
|
60
60
|
```
|
|
61
|
+
|
|
62
|
+
## Acting as another user
|
|
63
|
+
|
|
64
|
+
An admin, or a service account whose app may *make API calls using the as-user
|
|
65
|
+
header*, can act as another user. `withAsUserHeader` returns a new client whose
|
|
66
|
+
every call sends Box's `As-User` header; it shares the original's auth (and
|
|
67
|
+
token cache) and configuration, and the original is unchanged:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const userClient = client.withAsUserHeader('USER_ID');
|
|
71
|
+
const me = await userClient.users.getMe(); // the user USER_ID
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Downscoping a token
|
|
75
|
+
|
|
76
|
+
Exchange the session's access token for one limited to `scopes` and,
|
|
77
|
+
optionally, to one item (its API URL) or shared link — e.g. to hand a
|
|
78
|
+
browser-side preview a narrow token. The result has no refresh token; build
|
|
79
|
+
a client from it as a developer token:
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
const down = await client.authorization.downscopeToken(
|
|
83
|
+
['item_preview'],
|
|
84
|
+
'https://api.box.com/2.0/files/123',
|
|
85
|
+
);
|
|
86
|
+
const preview = new Client(auth.developerToken(down.access_token!));
|
|
87
|
+
```
|
package/docs/pagination.md
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unofficialbox/box-open-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Box API client for TypeScript (open source, community, punk rock) — typed models, async managers, and a fetch runtime with retry, backoff, and token refresh.",
|
|
5
5
|
"keywords": ["box", "box-api", "sdk", "api-client", "typescript", "unofficial"],
|
|
6
6
|
"license": "MIT",
|