oauth2-cli 1.2.8 → 2.0.1
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/CHANGELOG.md +18 -0
- package/README.md +7 -9
- package/dist/Client.d.ts +25 -10
- package/dist/Client.js +45 -14
- package/dist/PaginatedCollection.d.ts +18 -0
- package/dist/PaginatedCollection.js +34 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.
|
|
4
4
|
|
|
5
|
+
## [2.0.1](https://github.com/battis/oauth2-cli/compare/oauth2-cli/2.0.0...oauth2-cli/2.0.1) (2026-03-27)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* more detail on bad response ([8a38bd5](https://github.com/battis/oauth2-cli/commit/8a38bd5b86802e0640592117a21d69323a265d8f))
|
|
11
|
+
|
|
12
|
+
## [2.0.0](https://github.com/battis/oauth2-cli/compare/oauth2-cli/1.2.8...oauth2-cli/2.0.0) (2026-03-22)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### ⚠ BREAKING CHANGES
|
|
16
|
+
|
|
17
|
+
* detect and automate traversing paginated collections
|
|
18
|
+
|
|
19
|
+
### Features
|
|
20
|
+
|
|
21
|
+
* detect and automate traversing paginated collections ([28d6c6a](https://github.com/battis/oauth2-cli/commit/28d6c6ad90deb01059804d11ee692ec413a03345))
|
|
22
|
+
|
|
5
23
|
## [1.2.8](https://github.com/battis/oauth2-cli/compare/oauth2-cli/1.2.7...oauth2-cli/1.2.8) (2026-03-17)
|
|
6
24
|
|
|
7
25
|
### Bug Fixes
|
package/README.md
CHANGED
|
@@ -33,7 +33,7 @@ const client = new Client({
|
|
|
33
33
|
storage: new FileStorage('/path/to/token/file.json');
|
|
34
34
|
});
|
|
35
35
|
console.log(
|
|
36
|
-
client.
|
|
36
|
+
client.fetch<ExpectedResponse>('https://example.com/path/to/api/endpoint')
|
|
37
37
|
);
|
|
38
38
|
```
|
|
39
39
|
|
|
@@ -69,7 +69,7 @@ If you would prefer an `https` connection to localhost, you have to roll your ow
|
|
|
69
69
|
|
|
70
70
|
### Request an endpoint
|
|
71
71
|
|
|
72
|
-
#### `
|
|
72
|
+
#### `requestRaw()`
|
|
73
73
|
|
|
74
74
|
As noted above, `oauth2-cli` is built on top of [openid-client](https://www.npmjs.com/package/openid-client). The `request()` method is a pass-through to the `openid-client` [fetchProtectedResource()](https://github.com/panva/openid-client/blob/b77d87c1e2f5fef6fab501de615fb83a74a0251f/docs/functions/fetchProtectedResource.md) function, with the configuration and accessToken managed by the Client.
|
|
75
75
|
|
|
@@ -77,7 +77,7 @@ As noted above, `oauth2-cli` is built on top of [openid-client](https://www.npmj
|
|
|
77
77
|
class Client {
|
|
78
78
|
// ...
|
|
79
79
|
|
|
80
|
-
public async
|
|
80
|
+
public async requestRaw(
|
|
81
81
|
url: requestish.URL.ish,
|
|
82
82
|
method = 'GET',
|
|
83
83
|
body?: requestish.Body.ish,
|
|
@@ -95,7 +95,7 @@ class Client {
|
|
|
95
95
|
|
|
96
96
|
If you would prefer to make requests to relative paths, rather than absolute paths, either configure a `base_url` or include an `issuer` in the `credentials` when instantiating the client. A `base_url` will preempt an `issuer`, if both are defined (handy for when the `issuer` is a different subdomain than the API endpoints).
|
|
97
97
|
|
|
98
|
-
### `
|
|
98
|
+
### `request<T>()`
|
|
99
99
|
|
|
100
100
|
Given that many APIs return JSON-formatted responses, it is convenient to just get that JSON (optionally pre-typed based on what you expect to receive) rather than having to process the response yourself.
|
|
101
101
|
|
|
@@ -103,9 +103,7 @@ Given that many APIs return JSON-formatted responses, it is convenient to just g
|
|
|
103
103
|
class Client {
|
|
104
104
|
// ...
|
|
105
105
|
|
|
106
|
-
public async
|
|
107
|
-
J extends OpenIDClient.JsonValue = OpenIDClient.JsonValue
|
|
108
|
-
>(
|
|
106
|
+
public async request<T extends JSONValue = JSONValue>(
|
|
109
107
|
url: requestish.URL.ish,
|
|
110
108
|
method = 'GET',
|
|
111
109
|
body?: requestish.Body.ish,
|
|
@@ -117,9 +115,9 @@ class Client {
|
|
|
117
115
|
}
|
|
118
116
|
```
|
|
119
117
|
|
|
120
|
-
### `
|
|
118
|
+
### `fetchRaw()` and `fetch<T>()`
|
|
121
119
|
|
|
122
|
-
Aliases for `
|
|
120
|
+
Aliases for `requestRaw()` and `request<T>()` that use [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)-style arguments.
|
|
123
121
|
|
|
124
122
|
## Examples
|
|
125
123
|
|
package/dist/Client.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { Credentials } from './Credentials.js';
|
|
|
7
7
|
import { Injection } from './Injection.js';
|
|
8
8
|
import * as Localhost from './Localhost/index.js';
|
|
9
9
|
import * as Options from './Options.js';
|
|
10
|
+
import { PaginatedCollection } from './PaginatedCollection.js';
|
|
10
11
|
import * as Token from './Token/index.js';
|
|
11
12
|
export type PreparedRequest = Parameters<(typeof OpenIDClient)['fetchProtectedResource']>;
|
|
12
13
|
/**
|
|
@@ -117,7 +118,7 @@ export declare class Client<C extends Credentials = Credentials> extends EventEm
|
|
|
117
118
|
* @param body Optional
|
|
118
119
|
* @param dPoPOptions Optional, see {@link OpenIDClient.DPoPOptions}
|
|
119
120
|
*/
|
|
120
|
-
|
|
121
|
+
requestRaw(url: requestish.URL.ish, method?: string, body?: requestish.Body.ish, headers?: requestish.Headers.ish, dPoPOptions?: OpenIDClient.DPoPOptions): Promise<Response>;
|
|
121
122
|
/**
|
|
122
123
|
* Available hook to manipulate a fully-prepared request before sending to the
|
|
123
124
|
* server
|
|
@@ -128,13 +129,27 @@ export declare class Client<C extends Credentials = Credentials> extends EventEm
|
|
|
128
129
|
* processing it
|
|
129
130
|
*/
|
|
130
131
|
protected prepareResponse(response: Response): Promise<Response>;
|
|
131
|
-
/** Parse a fetch response as JSON, typing it as J */
|
|
132
|
-
private toJSON;
|
|
133
132
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
133
|
+
* Available hook to check for a paginated response and return an interable
|
|
134
|
+
* PaginatedCollection
|
|
136
135
|
*/
|
|
137
|
-
|
|
136
|
+
protected checkForPagination<T extends JSONValue = JSONValue>(_response: Response, _data: JSONValue): PaginatedCollection<T> | undefined;
|
|
137
|
+
/**
|
|
138
|
+
* Process a raw response int JSON, typing it as `T` or as a
|
|
139
|
+
* `PaginatedCollection<T>`
|
|
140
|
+
*
|
|
141
|
+
* @param response Raw response
|
|
142
|
+
*/
|
|
143
|
+
processResponse<T extends JSONValue = JSONValue>(response: Response, paginationCheck: false): Promise<T>;
|
|
144
|
+
processResponse<T extends JSONValue = JSONValue>(response: Response, paginationCheck?: true): Promise<T | PaginatedCollection<T>>;
|
|
145
|
+
/**
|
|
146
|
+
* Returns the result of {@link requestRaw} as a parsed JSON object, optionally
|
|
147
|
+
* typed as `T`
|
|
148
|
+
*
|
|
149
|
+
* @param pagination Optional function to test conversion of response into a
|
|
150
|
+
* `PaginatedCollection<T>`
|
|
151
|
+
*/
|
|
152
|
+
request<T extends JSONValue = JSONValue>(url: requestish.URL.ish, method?: string, body?: requestish.Body.ish, headers?: requestish.Headers.ish, dPoPOptions?: OpenIDClient.DPoPOptions): Promise<T | PaginatedCollection<T>>;
|
|
138
153
|
/**
|
|
139
154
|
* Request a protected resource using the client's access token.
|
|
140
155
|
*
|
|
@@ -145,12 +160,12 @@ export declare class Client<C extends Credentials = Credentials> extends EventEm
|
|
|
145
160
|
* paths relative to the `issuer` URL as well as absolute URLs
|
|
146
161
|
* @param init Optional
|
|
147
162
|
* @param dPoPOptions Optional, see {@link OpenIDClient.DPoPOptions}
|
|
148
|
-
* @see {@link
|
|
163
|
+
* @see {@link requestRaw} for which this is an alias for {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API Fetch API}-style requests
|
|
149
164
|
*/
|
|
150
|
-
|
|
165
|
+
fetchRaw(input: requestish.URL.ish, init?: RequestInit, dPoPOptions?: OpenIDClient.DPoPOptions): Promise<Response>;
|
|
151
166
|
/**
|
|
152
167
|
* Returns the result of {@link fetch} as a parsed JSON object, optionally
|
|
153
|
-
* typed as `
|
|
168
|
+
* typed as `T`
|
|
154
169
|
*/
|
|
155
|
-
|
|
170
|
+
fetch<T extends JSONValue = JSONValue>(input: requestish.URL.ish, init?: RequestInit, dPoPOptions?: OpenIDClient.DPoPOptions): Promise<T | PaginatedCollection<T>>;
|
|
156
171
|
}
|
package/dist/Client.js
CHANGED
|
@@ -253,7 +253,7 @@ export class Client extends EventEmitter {
|
|
|
253
253
|
* @param body Optional
|
|
254
254
|
* @param dPoPOptions Optional, see {@link OpenIDClient.DPoPOptions}
|
|
255
255
|
*/
|
|
256
|
-
async
|
|
256
|
+
async requestRaw(url, method = 'GET', body, headers = {}, dPoPOptions) {
|
|
257
257
|
url = new URL(url, this.base_url || this.credentials.issuer);
|
|
258
258
|
url = requestish.URL.from(requestish.URLSearchParams.appendTo(url, requestish.URLSearchParams.merge(this.inject?.search, url.searchParams)));
|
|
259
259
|
const request = async () => await OpenIDClient.fetchProtectedResource(...(await this.prepareRequest(await this.getConfiguration(), (await this.getToken()).access_token, url, method, await requestish.Body.from(body), requestish.Headers.merge(this.inject?.headers, headers), dPoPOptions)));
|
|
@@ -284,12 +284,24 @@ export class Client extends EventEmitter {
|
|
|
284
284
|
async prepareResponse(response) {
|
|
285
285
|
return response;
|
|
286
286
|
}
|
|
287
|
-
/**
|
|
288
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Available hook to check for a paginated response and return an interable
|
|
289
|
+
* PaginatedCollection
|
|
290
|
+
*/
|
|
291
|
+
checkForPagination(_response, _data) {
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
async processResponse(response, paginationCheck = true) {
|
|
289
295
|
if (response.ok) {
|
|
290
296
|
const body = await response.text();
|
|
291
297
|
try {
|
|
292
|
-
|
|
298
|
+
const data = JSON.parse(body);
|
|
299
|
+
let paginatedCollection;
|
|
300
|
+
if (paginationCheck &&
|
|
301
|
+
(paginatedCollection = this.checkForPagination(response, data))) {
|
|
302
|
+
return paginatedCollection;
|
|
303
|
+
}
|
|
304
|
+
return data;
|
|
293
305
|
}
|
|
294
306
|
catch (error) {
|
|
295
307
|
throw new Error(`${this.name} response could not be parsed as JSON`, {
|
|
@@ -312,11 +324,30 @@ export class Client extends EventEmitter {
|
|
|
312
324
|
}
|
|
313
325
|
}
|
|
314
326
|
/**
|
|
315
|
-
* Returns the result of {@link
|
|
316
|
-
* typed as `
|
|
327
|
+
* Returns the result of {@link requestRaw} as a parsed JSON object, optionally
|
|
328
|
+
* typed as `T`
|
|
329
|
+
*
|
|
330
|
+
* @param pagination Optional function to test conversion of response into a
|
|
331
|
+
* `PaginatedCollection<T>`
|
|
317
332
|
*/
|
|
318
|
-
async
|
|
319
|
-
|
|
333
|
+
async request(url, method = 'GET', body, headers = {}, dPoPOptions) {
|
|
334
|
+
try {
|
|
335
|
+
const response = await this.requestRaw(url, method, body, headers, dPoPOptions);
|
|
336
|
+
return await this.processResponse(response);
|
|
337
|
+
}
|
|
338
|
+
catch (error) {
|
|
339
|
+
throw new Error(`Bad response from ${this.name}`, {
|
|
340
|
+
cause: {
|
|
341
|
+
request: {
|
|
342
|
+
method,
|
|
343
|
+
url: requestish.URL.toString(url),
|
|
344
|
+
headers: Object.fromEntries(requestish.Headers.from(headers).entries()),
|
|
345
|
+
body
|
|
346
|
+
},
|
|
347
|
+
error
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
}
|
|
320
351
|
}
|
|
321
352
|
/**
|
|
322
353
|
* Request a protected resource using the client's access token.
|
|
@@ -328,16 +359,16 @@ export class Client extends EventEmitter {
|
|
|
328
359
|
* paths relative to the `issuer` URL as well as absolute URLs
|
|
329
360
|
* @param init Optional
|
|
330
361
|
* @param dPoPOptions Optional, see {@link OpenIDClient.DPoPOptions}
|
|
331
|
-
* @see {@link
|
|
362
|
+
* @see {@link requestRaw} for which this is an alias for {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API Fetch API}-style requests
|
|
332
363
|
*/
|
|
333
|
-
async
|
|
334
|
-
return await this.
|
|
364
|
+
async fetchRaw(input, init, dPoPOptions) {
|
|
365
|
+
return await this.requestRaw(input, init?.method, await requestish.Body.from(init?.body), requestish.Headers.from(init?.headers), dPoPOptions);
|
|
335
366
|
}
|
|
336
367
|
/**
|
|
337
368
|
* Returns the result of {@link fetch} as a parsed JSON object, optionally
|
|
338
|
-
* typed as `
|
|
369
|
+
* typed as `T`
|
|
339
370
|
*/
|
|
340
|
-
async
|
|
341
|
-
return await this.
|
|
371
|
+
async fetch(input, init, dPoPOptions) {
|
|
372
|
+
return await this.request(input, init?.method, await requestish.Body.from(init?.body), requestish.Headers.from(init?.headers), dPoPOptions);
|
|
342
373
|
}
|
|
343
374
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { JSONValue } from '@battis/typescript-tricks';
|
|
2
|
+
import { Client } from './Client.js';
|
|
3
|
+
type Options<T extends JSONValue = JSONValue> = {
|
|
4
|
+
page: T[];
|
|
5
|
+
response: Response;
|
|
6
|
+
client: Client;
|
|
7
|
+
};
|
|
8
|
+
export declare abstract class PaginatedCollection<T extends JSONValue> implements AsyncIterable<T>, AsyncIterableIterator<T> {
|
|
9
|
+
protected currentResponse: Response;
|
|
10
|
+
protected currentElt: number;
|
|
11
|
+
protected currentPage: T[];
|
|
12
|
+
protected client: Client;
|
|
13
|
+
constructor({ page, response, client }: Options<T>);
|
|
14
|
+
[Symbol.asyncIterator](): this;
|
|
15
|
+
protected abstract nextPage(): Promise<T[] | undefined>;
|
|
16
|
+
next(): Promise<IteratorResult<T>>;
|
|
17
|
+
}
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export class PaginatedCollection {
|
|
2
|
+
currentResponse;
|
|
3
|
+
currentElt = 0;
|
|
4
|
+
currentPage;
|
|
5
|
+
client;
|
|
6
|
+
constructor({ page, response, client }) {
|
|
7
|
+
this.currentResponse = response;
|
|
8
|
+
this.currentPage = page;
|
|
9
|
+
this.client = client;
|
|
10
|
+
}
|
|
11
|
+
[Symbol.asyncIterator]() {
|
|
12
|
+
return this;
|
|
13
|
+
}
|
|
14
|
+
async next() {
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
const value = this.currentPage[this.currentElt++];
|
|
17
|
+
if (this.currentElt === this.currentPage.length) {
|
|
18
|
+
this.nextPage().then((page) => {
|
|
19
|
+
if (page) {
|
|
20
|
+
this.currentPage = page;
|
|
21
|
+
this.currentElt = 0;
|
|
22
|
+
resolve({ value, done: this.currentPage.length === 0 });
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
resolve({ value, done: true });
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
resolve({ value, done: false });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oauth2-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
4
4
|
"description": "Acquire API access tokens via OAuth 2.0 / OpenID Connect within CLI tools",
|
|
5
5
|
"homepage": "https://github.com/battis/oauth2-cli/tree/main/packages/oauth2-cli#readme",
|
|
6
6
|
"repository": {
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"open": "^11.0.0",
|
|
24
24
|
"openid-client": "^6.8.2",
|
|
25
25
|
"ora": "^9.3.0",
|
|
26
|
-
"
|
|
27
|
-
"
|
|
26
|
+
"gcrtl": "0.1.12",
|
|
27
|
+
"requestish": "0.1.12"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@battis/typescript-tricks": "^0.8.1",
|