oauth2-cli 0.6.0 → 0.7.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/CHANGELOG.md +11 -0
- package/dist/Client.d.ts +17 -27
- package/dist/Client.js +19 -19
- package/dist/Credentials.d.ts +13 -12
- package/dist/Request/Injection.d.ts +4 -6
- package/dist/Request/index.d.ts +0 -4
- package/dist/Request/index.js +0 -4
- package/dist/Session.d.ts +1 -1
- package/dist/WebServer.js +2 -2
- package/package.json +3 -2
- package/dist/Request/Body.d.ts +0 -3
- package/dist/Request/Body.js +0 -19
- package/dist/Request/Headers.d.ts +0 -3
- package/dist/Request/Headers.js +0 -20
- package/dist/Request/URL.d.ts +0 -4
- package/dist/Request/URL.js +0 -12
- package/dist/Request/URLSearchParams.d.ts +0 -6
- package/dist/Request/URLSearchParams.js +0 -37
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
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
|
+
## [0.7.0](https://github.com/battis/oauth2-cli/compare/oauth2-cli/0.6.0...oauth2-cli/0.7.0) (2026-02-16)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### ⚠ BREAKING CHANGES
|
|
9
|
+
|
|
10
|
+
* make more properties of Client accessible to subclasses
|
|
11
|
+
|
|
12
|
+
### Features
|
|
13
|
+
|
|
14
|
+
* make more properties of Client accessible to subclasses ([74ef874](https://github.com/battis/oauth2-cli/commit/74ef874804323a9c3c496ddf7b0e24bac9e671e1))
|
|
15
|
+
|
|
5
16
|
## [0.6.0](https://github.com/battis/oauth2-cli/compare/oauth2-cli/0.5.1...oauth2-cli/0.6.0) (2026-02-15)
|
|
6
17
|
|
|
7
18
|
|
package/dist/Client.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { PathString } from '@battis/descriptive-types';
|
|
|
2
2
|
import { Request } from 'express';
|
|
3
3
|
import { EventEmitter } from 'node:events';
|
|
4
4
|
import * as OpenIDClient from 'openid-client';
|
|
5
|
+
import * as requestish from 'requestish';
|
|
5
6
|
import * as Credentials from './Credentials.js';
|
|
6
7
|
import * as Req from './Request/index.js';
|
|
7
8
|
import { Session, SessionOptions } from './Session.js';
|
|
@@ -14,6 +15,12 @@ export declare const DEFAULT_REDIRECT_URI = "http://localhost:3000/oauth2-cli/re
|
|
|
14
15
|
export type ClientOptions = {
|
|
15
16
|
/** Credentials for server access */
|
|
16
17
|
credentials: Credentials.Combined;
|
|
18
|
+
/** Optional request components to inject */
|
|
19
|
+
inject?: {
|
|
20
|
+
search?: requestish.URLSearchParams.ish;
|
|
21
|
+
headers?: requestish.Headers.ish;
|
|
22
|
+
body?: requestish.Body.ish;
|
|
23
|
+
};
|
|
17
24
|
/**
|
|
18
25
|
* Optional absolute path to EJS view templates directory, see
|
|
19
26
|
* [WebServer.setViews()](./Webserver.ts)
|
|
@@ -21,21 +28,6 @@ export type ClientOptions = {
|
|
|
21
28
|
views?: PathString;
|
|
22
29
|
/** Optional {@link TokenStorage} implementation to manage tokens */
|
|
23
30
|
storage?: Token.TokenStorage;
|
|
24
|
-
/**
|
|
25
|
-
* Optional search query parameters to include in all server requests (see
|
|
26
|
-
* {@link RequestAddons.search})
|
|
27
|
-
*/
|
|
28
|
-
search?: Req.URLSearchParams.ish;
|
|
29
|
-
/**
|
|
30
|
-
* Optional headers to include in all server requests (see
|
|
31
|
-
* {@link RequestAddons.headers})
|
|
32
|
-
*/
|
|
33
|
-
headers?: Req.Headers.ish;
|
|
34
|
-
/**
|
|
35
|
-
* Optional body parameters to include in applicable server requests (see
|
|
36
|
-
* {@link RequestAddons.body})
|
|
37
|
-
*/
|
|
38
|
-
body?: Req.Body.ish;
|
|
39
31
|
};
|
|
40
32
|
type RefreshOptions = {
|
|
41
33
|
/**
|
|
@@ -71,17 +63,15 @@ type GetTokenOptions = {
|
|
|
71
63
|
*/
|
|
72
64
|
export declare class Client extends EventEmitter {
|
|
73
65
|
static readonly TokenEvent = "token";
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
66
|
+
protected credentials: Credentials.Combined;
|
|
67
|
+
protected config?: OpenIDClient.Configuration;
|
|
68
|
+
protected views?: PathString;
|
|
69
|
+
protected inject?: Req.Injection;
|
|
77
70
|
private token?;
|
|
78
71
|
private tokenLock;
|
|
79
|
-
private search?;
|
|
80
|
-
private headers?;
|
|
81
|
-
private body?;
|
|
82
72
|
private storage?;
|
|
83
|
-
constructor({ credentials, views,
|
|
84
|
-
get redirect_uri():
|
|
73
|
+
constructor({ credentials, views, inject, storage }: ClientOptions);
|
|
74
|
+
get redirect_uri(): requestish.URL.ish;
|
|
85
75
|
/**
|
|
86
76
|
* @throws IndeterminateConfiguration if provided credentials combined with
|
|
87
77
|
* OpenID discovery fail to generate a complete configuration
|
|
@@ -110,14 +100,14 @@ export declare class Client extends EventEmitter {
|
|
|
110
100
|
* @param headers Optional
|
|
111
101
|
* @param dPoPOptions Optional
|
|
112
102
|
*/
|
|
113
|
-
request(url:
|
|
103
|
+
request(url: requestish.URL.ish, method?: string, body?: OpenIDClient.FetchBody, headers?: requestish.Headers.ish, dPoPOptions?: OpenIDClient.DPoPOptions): Promise<Response>;
|
|
114
104
|
private toJSON;
|
|
115
105
|
/**
|
|
116
106
|
* Returns the result of {@link request} as a parsed JSON object, optionally
|
|
117
107
|
* typed as `T`
|
|
118
108
|
*/
|
|
119
|
-
requestJSON<T extends OpenIDClient.JsonValue = OpenIDClient.JsonValue>(url:
|
|
120
|
-
fetch(input:
|
|
121
|
-
fetchJSON<T extends OpenIDClient.JsonValue = OpenIDClient.JsonValue>(input:
|
|
109
|
+
requestJSON<T extends OpenIDClient.JsonValue = OpenIDClient.JsonValue>(url: requestish.URL.ish, method?: string, body?: OpenIDClient.FetchBody, headers?: requestish.Headers.ish, dPoPOptions?: OpenIDClient.DPoPOptions): Promise<T>;
|
|
110
|
+
fetch(input: requestish.URL.ish, init?: RequestInit, dPoPOptions?: OpenIDClient.DPoPOptions): Promise<Response>;
|
|
111
|
+
fetchJSON<T extends OpenIDClient.JsonValue = OpenIDClient.JsonValue>(input: requestish.URL.ish, init?: RequestInit, dPoPOptions?: OpenIDClient.DPoPOptions): Promise<T>;
|
|
122
112
|
}
|
|
123
113
|
export {};
|
package/dist/Client.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Mutex } from 'async-mutex';
|
|
2
2
|
import { EventEmitter } from 'node:events';
|
|
3
3
|
import * as OpenIDClient from 'openid-client';
|
|
4
|
+
import * as requestish from 'requestish';
|
|
4
5
|
import * as Errors from './Errors/index.js';
|
|
5
6
|
import * as Req from './Request/index.js';
|
|
6
7
|
import { Session } from './Session.js';
|
|
@@ -21,19 +22,15 @@ export class Client extends EventEmitter {
|
|
|
21
22
|
credentials;
|
|
22
23
|
config;
|
|
23
24
|
views;
|
|
25
|
+
inject;
|
|
24
26
|
token;
|
|
25
27
|
tokenLock = new Mutex();
|
|
26
|
-
search;
|
|
27
|
-
headers;
|
|
28
|
-
body;
|
|
29
28
|
storage;
|
|
30
|
-
constructor({ credentials, views,
|
|
29
|
+
constructor({ credentials, views, inject, storage }) {
|
|
31
30
|
super();
|
|
32
31
|
this.credentials = credentials;
|
|
33
32
|
this.views = views;
|
|
34
|
-
this.
|
|
35
|
-
this.headers = headers;
|
|
36
|
-
this.body = body;
|
|
33
|
+
this.inject = inject;
|
|
37
34
|
this.storage = storage;
|
|
38
35
|
}
|
|
39
36
|
get redirect_uri() {
|
|
@@ -45,13 +42,13 @@ export class Client extends EventEmitter {
|
|
|
45
42
|
*/
|
|
46
43
|
async getConfiguration() {
|
|
47
44
|
if (!this.config && this.credentials.issuer) {
|
|
48
|
-
this.config = await OpenIDClient.discovery(
|
|
45
|
+
this.config = await OpenIDClient.discovery(requestish.URL.from(this.credentials.issuer), this.credentials.client_id, { client_secret: this.credentials.client_secret });
|
|
49
46
|
}
|
|
50
47
|
if (!this.config && this.credentials?.authorization_endpoint) {
|
|
51
48
|
this.config = new OpenIDClient.Configuration({
|
|
52
|
-
issuer: `https://${
|
|
53
|
-
authorization_endpoint:
|
|
54
|
-
token_endpoint:
|
|
49
|
+
issuer: `https://${requestish.URL.from(this.credentials.authorization_endpoint).hostname}`,
|
|
50
|
+
authorization_endpoint: requestish.URL.toString(this.credentials.authorization_endpoint),
|
|
51
|
+
token_endpoint: requestish.URL.toString(this.credentials.token_endpoint ||
|
|
55
52
|
this.credentials.authorization_endpoint)
|
|
56
53
|
}, this.credentials.client_id, { client_secret: this.credentials.client_secret });
|
|
57
54
|
}
|
|
@@ -61,9 +58,8 @@ export class Client extends EventEmitter {
|
|
|
61
58
|
return this.config;
|
|
62
59
|
}
|
|
63
60
|
async getParameters(session) {
|
|
64
|
-
const params =
|
|
65
|
-
|
|
66
|
-
params.set('redirect_uri', Req.URL.toString(this.credentials.redirect_uri));
|
|
61
|
+
const params = requestish.URLSearchParams.merge(this.inject?.search, session.inject?.search) || new URLSearchParams();
|
|
62
|
+
params.set('redirect_uri', requestish.URL.toString(this.credentials.redirect_uri));
|
|
67
63
|
params.set('code_challenge', await OpenIDClient.calculatePKCECodeChallenge(session.code_verifier));
|
|
68
64
|
params.set('code_challenge_method', 'S256');
|
|
69
65
|
params.set('state', session.state);
|
|
@@ -92,7 +88,9 @@ export class Client extends EventEmitter {
|
|
|
92
88
|
const response = await OpenIDClient.authorizationCodeGrant(await this.getConfiguration(), new URL(req.url, this.redirect_uri), {
|
|
93
89
|
pkceCodeVerifier: session.code_verifier,
|
|
94
90
|
expectedState: session.state
|
|
95
|
-
}, this.search
|
|
91
|
+
}, this.inject?.search
|
|
92
|
+
? requestish.URLSearchParams.from(this.inject.search)
|
|
93
|
+
: undefined);
|
|
96
94
|
await session.resolve(response);
|
|
97
95
|
}
|
|
98
96
|
catch (error) {
|
|
@@ -106,7 +104,9 @@ export class Client extends EventEmitter {
|
|
|
106
104
|
if (!refresh_token || refresh_token === '') {
|
|
107
105
|
return undefined;
|
|
108
106
|
}
|
|
109
|
-
const token = await OpenIDClient.refreshTokenGrant(await this.getConfiguration(), refresh_token, this.search
|
|
107
|
+
const token = await OpenIDClient.refreshTokenGrant(await this.getConfiguration(), refresh_token, this.inject?.search
|
|
108
|
+
? requestish.URLSearchParams.from(this.inject.search)
|
|
109
|
+
: undefined, {
|
|
110
110
|
// @ts-expect-error 2322 undocumented arg pass-through to oauth4webapi
|
|
111
111
|
headers: Req.Headers.merge(this.headers, request?.headers)
|
|
112
112
|
});
|
|
@@ -152,7 +152,7 @@ export class Client extends EventEmitter {
|
|
|
152
152
|
*/
|
|
153
153
|
async request(url, method = 'GET', body, headers = {}, dPoPOptions) {
|
|
154
154
|
try {
|
|
155
|
-
url =
|
|
155
|
+
url = requestish.URL.from(url);
|
|
156
156
|
}
|
|
157
157
|
catch (error) {
|
|
158
158
|
if (this.credentials.issuer) {
|
|
@@ -162,7 +162,7 @@ export class Client extends EventEmitter {
|
|
|
162
162
|
throw error;
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
|
-
const request = async () => await OpenIDClient.fetchProtectedResource(await this.getConfiguration(), (await this.getToken()).access_token,
|
|
165
|
+
const request = async () => await OpenIDClient.fetchProtectedResource(await this.getConfiguration(), (await this.getToken()).access_token, requestish.URL.from(requestish.URLSearchParams.appendTo(url, this.inject?.search || {})), method, body, requestish.Headers.merge(this.inject?.headers, headers), dPoPOptions);
|
|
166
166
|
try {
|
|
167
167
|
return await request();
|
|
168
168
|
}
|
|
@@ -195,7 +195,7 @@ export class Client extends EventEmitter {
|
|
|
195
195
|
return await this.toJSON(await this.request(url, method, body, headers, dPoPOptions));
|
|
196
196
|
}
|
|
197
197
|
async fetch(input, init, dPoPOptions) {
|
|
198
|
-
return await this.request(input, init?.method, await
|
|
198
|
+
return await this.request(input, init?.method, await requestish.Body.from(init?.body), requestish.Headers.from(init?.headers), dPoPOptions);
|
|
199
199
|
}
|
|
200
200
|
async fetchJSON(input, init, dPoPOptions) {
|
|
201
201
|
return await this.toJSON(await this.fetch(input, init, dPoPOptions));
|
package/dist/Credentials.d.ts
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
|
+
import * as requestish from 'requestish';
|
|
1
2
|
import * as Req from './Request/index.js';
|
|
2
3
|
export type OAuth2 = {
|
|
3
4
|
client_id: string;
|
|
4
5
|
client_secret: string;
|
|
5
|
-
redirect_uri:
|
|
6
|
-
authorization_endpoint:
|
|
7
|
-
token_endpoint:
|
|
6
|
+
redirect_uri: requestish.URL.ish;
|
|
7
|
+
authorization_endpoint: requestish.URL.ish;
|
|
8
|
+
token_endpoint: requestish.URL.ish;
|
|
8
9
|
scope?: Req.Scope.ish;
|
|
9
10
|
};
|
|
10
11
|
export type OpenID = {
|
|
11
|
-
issuer:
|
|
12
|
+
issuer: requestish.URL.ish;
|
|
12
13
|
client_id: string;
|
|
13
14
|
client_secret: string;
|
|
14
|
-
redirect_uri:
|
|
15
|
+
redirect_uri: requestish.URL.ish;
|
|
15
16
|
};
|
|
16
17
|
export type Combined = {
|
|
17
18
|
client_id: string;
|
|
18
19
|
client_secret: string;
|
|
19
|
-
redirect_uri:
|
|
20
|
+
redirect_uri: requestish.URL.ish;
|
|
20
21
|
scope?: Req.Scope.ish;
|
|
21
22
|
} & ({
|
|
22
|
-
issuer?:
|
|
23
|
-
authorization_endpoint:
|
|
24
|
-
token_endpoint:
|
|
23
|
+
issuer?: requestish.URL.ish;
|
|
24
|
+
authorization_endpoint: requestish.URL.ish;
|
|
25
|
+
token_endpoint: requestish.URL.ish;
|
|
25
26
|
} | {
|
|
26
|
-
issuer:
|
|
27
|
-
authorization_endpoint?:
|
|
28
|
-
token_endpoint?:
|
|
27
|
+
issuer: requestish.URL.ish;
|
|
28
|
+
authorization_endpoint?: requestish.URL.ish;
|
|
29
|
+
token_endpoint?: requestish.URL.ish;
|
|
29
30
|
});
|
|
@@ -1,23 +1,21 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import * as Headers from './Headers.js';
|
|
1
|
+
import * as requestish from 'requestish';
|
|
3
2
|
import * as Scope from './Scope.js';
|
|
4
|
-
import * as URLSearchParams from './URLSearchParams.js';
|
|
5
3
|
export type Injection = {
|
|
6
4
|
/**
|
|
7
5
|
* Search query parameters to include in server request (may be ovewritten by
|
|
8
6
|
* computed values such as `state` or `challenge_code`)
|
|
9
7
|
*/
|
|
10
|
-
search?: URLSearchParams.ish;
|
|
8
|
+
search?: requestish.URLSearchParams.ish;
|
|
11
9
|
/**
|
|
12
10
|
* HTTP headers to include in server request (may be overwritten by computed
|
|
13
11
|
* values such as `Authorization: Bearer <token>`)
|
|
14
12
|
*/
|
|
15
|
-
headers?: Headers.ish;
|
|
13
|
+
headers?: requestish.Headers.ish;
|
|
16
14
|
/**
|
|
17
15
|
* HTTP request body parameters to include in server request (if request
|
|
18
16
|
* method allows)
|
|
19
17
|
*/
|
|
20
|
-
body?: Body.ish;
|
|
18
|
+
body?: requestish.Body.ish;
|
|
21
19
|
/** Specific scope or scopes */
|
|
22
20
|
scope?: Scope.ish;
|
|
23
21
|
};
|
package/dist/Request/index.d.ts
CHANGED
package/dist/Request/index.js
CHANGED
package/dist/Session.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export declare class Session {
|
|
|
37
37
|
*/
|
|
38
38
|
authorizationCodeGrant(): Promise<Token.Response>;
|
|
39
39
|
/** OAuth 2.0 redirect_uri that this session is handling */
|
|
40
|
-
get redirect_uri():
|
|
40
|
+
get redirect_uri(): import("requestish/dist/URL.js").ish;
|
|
41
41
|
getAuthorizationUrl(): Promise<string>;
|
|
42
42
|
/**
|
|
43
43
|
* Express RequestHandler for the out-of-band redirect in the Authorization
|
package/dist/WebServer.js
CHANGED
|
@@ -2,8 +2,8 @@ import express from 'express';
|
|
|
2
2
|
import * as gcrtl from 'gcrtl';
|
|
3
3
|
import fs from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
|
+
import * as requestish from 'requestish';
|
|
5
6
|
import * as Errors from './Errors/index.js';
|
|
6
|
-
import * as Req from './Request/index.js';
|
|
7
7
|
let ejs = undefined;
|
|
8
8
|
try {
|
|
9
9
|
ejs = (await import('ejs')).default;
|
|
@@ -28,7 +28,7 @@ export class WebServer {
|
|
|
28
28
|
this.session = session;
|
|
29
29
|
this.authorization_endpoint = authorize_endpoint;
|
|
30
30
|
this.views = views;
|
|
31
|
-
const url =
|
|
31
|
+
const url = requestish.URL.from(this.session.redirect_uri);
|
|
32
32
|
this.port = url.port;
|
|
33
33
|
if (WebServer.activePorts.includes(this.port)) {
|
|
34
34
|
throw new Errors.PortCollision(url.port);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oauth2-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "Acquire API access tokens via OAuth 2.0 within CLI tools",
|
|
5
5
|
"homepage": "https://github.com/battis/oauth2-cli/tree/main/packages/oauth2-cli#readme",
|
|
6
6
|
"repository": {
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
"oauth4webapi": "^3.8.4",
|
|
24
24
|
"open": "^11.0.0",
|
|
25
25
|
"openid-client": "^6.8.2",
|
|
26
|
-
"ora": "^9.3.0"
|
|
26
|
+
"ora": "^9.3.0",
|
|
27
|
+
"requestish": "0.1.0"
|
|
27
28
|
},
|
|
28
29
|
"devDependencies": {
|
|
29
30
|
"@battis/descriptive-types": "^0.2.6",
|
package/dist/Request/Body.d.ts
DELETED
package/dist/Request/Body.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { isRecord } from '@battis/typescript-tricks';
|
|
2
|
-
function isString(obj) {
|
|
3
|
-
return typeof obj === 'string';
|
|
4
|
-
}
|
|
5
|
-
export async function from(body) {
|
|
6
|
-
if (body === undefined ||
|
|
7
|
-
body === null ||
|
|
8
|
-
typeof body === 'string' ||
|
|
9
|
-
body instanceof ArrayBuffer ||
|
|
10
|
-
body instanceof ReadableStream ||
|
|
11
|
-
body instanceof Uint8Array ||
|
|
12
|
-
body instanceof URLSearchParams) {
|
|
13
|
-
return body;
|
|
14
|
-
}
|
|
15
|
-
else if (isRecord(body, isString, isString)) {
|
|
16
|
-
return new URLSearchParams(body);
|
|
17
|
-
}
|
|
18
|
-
return new Response(body).arrayBuffer();
|
|
19
|
-
}
|
package/dist/Request/Headers.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
export function from(headers) {
|
|
2
|
-
if (headers instanceof Headers) {
|
|
3
|
-
return headers;
|
|
4
|
-
}
|
|
5
|
-
return new Headers(headers);
|
|
6
|
-
}
|
|
7
|
-
export function merge(a, b) {
|
|
8
|
-
if (a && !b) {
|
|
9
|
-
return from(a);
|
|
10
|
-
}
|
|
11
|
-
else if (!a && b) {
|
|
12
|
-
return from(b);
|
|
13
|
-
}
|
|
14
|
-
else if (a && b) {
|
|
15
|
-
const headers = from(a);
|
|
16
|
-
from(b).forEach((value, key) => headers.set(key, value));
|
|
17
|
-
return headers;
|
|
18
|
-
}
|
|
19
|
-
return undefined;
|
|
20
|
-
}
|
package/dist/Request/URL.d.ts
DELETED
package/dist/Request/URL.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { ish as URLish } from './URL.js';
|
|
2
|
-
export type ish = URLSearchParams | Record<string, string>;
|
|
3
|
-
export declare function from(search: ish): URLSearchParams;
|
|
4
|
-
export declare function toString(search: ish): string;
|
|
5
|
-
export declare function merge(a?: ish, b?: ish): URLSearchParams | undefined;
|
|
6
|
-
export declare function appendTo(url: URLish, search: ish): URLish;
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
export function from(search) {
|
|
2
|
-
if (search instanceof URLSearchParams) {
|
|
3
|
-
return search;
|
|
4
|
-
}
|
|
5
|
-
return new URLSearchParams(search);
|
|
6
|
-
}
|
|
7
|
-
export function toString(search) {
|
|
8
|
-
const query = from(search).toString();
|
|
9
|
-
if (query.length) {
|
|
10
|
-
return `?${query}`;
|
|
11
|
-
}
|
|
12
|
-
return '';
|
|
13
|
-
}
|
|
14
|
-
export function merge(a, b) {
|
|
15
|
-
if (a && !b) {
|
|
16
|
-
return from(a);
|
|
17
|
-
}
|
|
18
|
-
else if (!a && b) {
|
|
19
|
-
return from(b);
|
|
20
|
-
}
|
|
21
|
-
else if (a && b) {
|
|
22
|
-
const search = from(a);
|
|
23
|
-
from(b).forEach((value, key) => search.set(key, value));
|
|
24
|
-
return search;
|
|
25
|
-
}
|
|
26
|
-
return undefined;
|
|
27
|
-
}
|
|
28
|
-
export function appendTo(url, search) {
|
|
29
|
-
if (url instanceof URL) {
|
|
30
|
-
const result = new URL(url);
|
|
31
|
-
result.search = toString(search);
|
|
32
|
-
return result;
|
|
33
|
-
}
|
|
34
|
-
else {
|
|
35
|
-
return url.replace(/(.+)(\?.*)?$/, `$1${toString(search)}`);
|
|
36
|
-
}
|
|
37
|
-
}
|