@outfoxx/sunday 2.0.0-beta.2 → 2.0.0-beta.21
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/README.md +346 -4
- package/build/authentication-adapter.d.ts +21 -0
- package/build/authentication-adapter.js +74 -0
- package/build/authentication-adapter.js.map +1 -0
- package/build/bearer-token-rejection-adapter.d.ts +6 -0
- package/build/bearer-token-rejection-adapter.js +25 -0
- package/build/bearer-token-rejection-adapter.js.map +1 -0
- package/build/client-settings.d.ts +22 -0
- package/build/client-settings.js +180 -0
- package/build/client-settings.js.map +1 -0
- package/build/credentials.d.ts +58 -0
- package/build/credentials.js +51 -0
- package/build/credentials.js.map +1 -0
- package/build/event-parser.d.ts +23 -8
- package/build/event-parser.js +93 -121
- package/build/event-parser.js.map +1 -1
- package/build/fetch-copy.d.ts +15 -0
- package/build/fetch-copy.js +71 -0
- package/build/fetch-copy.js.map +1 -0
- package/build/fetch-event-source.d.ts +18 -8
- package/build/fetch-event-source.js +241 -144
- package/build/fetch-event-source.js.map +1 -1
- package/build/fetch-oauth-token-provider.d.ts +28 -0
- package/build/fetch-oauth-token-provider.js +213 -0
- package/build/fetch-oauth-token-provider.js.map +1 -0
- package/build/fetch-transport.d.ts +15 -1
- package/build/fetch-transport.js +142 -132
- package/build/fetch-transport.js.map +1 -1
- package/build/fetch.js +24 -10
- package/build/fetch.js.map +1 -1
- package/build/header-token-adapters.d.ts +28 -0
- package/build/header-token-adapters.js +121 -0
- package/build/header-token-adapters.js.map +1 -0
- package/build/index.d.ts +23 -1
- package/build/index.js +22 -1
- package/build/index.js.map +1 -1
- package/build/media-type-codecs/binary-decoder.d.ts +1 -0
- package/build/media-type-codecs/binary-decoder.js +4 -11
- package/build/media-type-codecs/binary-decoder.js.map +1 -1
- package/build/media-type-codecs/cbor-encoder.d.ts +2 -2
- package/build/media-type-codecs/cbor-encoder.js +2 -2
- package/build/media-type-codecs/cbor-encoder.js.map +1 -1
- package/build/media-type-codecs/json-encoder.d.ts +3 -3
- package/build/media-type-codecs/json-encoder.js +4 -4
- package/build/media-type-codecs/json-encoder.js.map +1 -1
- package/build/media-type-codecs/media-type-encoder.d.ts +3 -3
- package/build/media-type-codecs/media-type-encoder.js.map +1 -1
- package/build/media-type-codecs/www-form-url-encoder.d.ts +2 -2
- package/build/media-type-codecs/www-form-url-encoder.js +2 -2
- package/build/media-type-codecs/www-form-url-encoder.js.map +1 -1
- package/build/model-construction.d.ts +5 -0
- package/build/model-construction.js +40 -0
- package/build/model-construction.js.map +1 -0
- package/build/model-schema.d.ts +9 -0
- package/build/model-schema.js +131 -0
- package/build/model-schema.js.map +1 -0
- package/build/oauth-wire.d.ts +33 -0
- package/build/oauth-wire.js +143 -0
- package/build/oauth-wire.js.map +1 -0
- package/build/operation.d.ts +3 -1
- package/build/problem.d.ts +39 -16
- package/build/problem.js +88 -32
- package/build/problem.js.map +1 -1
- package/build/request-adapter.d.ts +8 -0
- package/build/request-adapter.js +15 -0
- package/build/request-adapter.js.map +1 -0
- package/build/request-adapters-compat.d.ts +6 -0
- package/build/request-adapters-compat.js +19 -0
- package/build/request-adapters-compat.js.map +1 -0
- package/build/request-adapters.d.ts +13 -23
- package/build/request-adapters.js +40 -31
- package/build/request-adapters.js.map +1 -1
- package/build/request-body.d.ts +24 -0
- package/build/request-body.js +104 -0
- package/build/request-body.js.map +1 -0
- package/build/request-cancellation-error.d.ts +13 -0
- package/build/request-cancellation-error.js +43 -0
- package/build/request-cancellation-error.js.map +1 -0
- package/build/request-context.d.ts +4 -0
- package/build/request-context.js +29 -0
- package/build/request-context.js.map +1 -0
- package/build/request-execution.d.ts +13 -0
- package/build/request-execution.js +80 -0
- package/build/request-execution.js.map +1 -0
- package/build/request-security-bindings.d.ts +5 -0
- package/build/request-security-bindings.js +30 -0
- package/build/request-security-bindings.js.map +1 -0
- package/build/request-security.d.ts +20 -0
- package/build/request-security.js +223 -0
- package/build/request-security.js.map +1 -0
- package/build/request-validation-error.d.ts +4 -0
- package/build/request-validation-error.js +21 -0
- package/build/request-validation-error.js.map +1 -0
- package/build/response-adapter.d.ts +10 -0
- package/build/response-adapter.js +15 -0
- package/build/response-adapter.js.map +1 -0
- package/build/response-adapters.d.ts +13 -0
- package/build/response-adapters.js +75 -0
- package/build/response-adapters.js.map +1 -0
- package/build/schema-builtins.js +11 -21
- package/build/schema-builtins.js.map +1 -1
- package/build/schema-runtime.d.ts +8 -1
- package/build/schema-runtime.js +12 -3
- package/build/schema-runtime.js.map +1 -1
- package/build/security-binding.d.ts +22 -0
- package/build/security-binding.js +15 -0
- package/build/security-binding.js.map +1 -0
- package/build/standard-authentication-adapter.d.ts +18 -0
- package/build/standard-authentication-adapter.js +58 -0
- package/build/standard-authentication-adapter.js.map +1 -0
- package/build/token-manager.d.ts +42 -0
- package/build/token-manager.js +276 -0
- package/build/token-manager.js.map +1 -0
- package/build/token-provider.d.ts +52 -0
- package/build/token-provider.js +102 -0
- package/build/token-provider.js.map +1 -0
- package/build/transport.d.ts +10 -3
- package/build/unknown-variant.d.ts +12 -0
- package/build/unknown-variant.js +45 -0
- package/build/unknown-variant.js.map +1 -0
- package/build/url-template.d.ts +3 -0
- package/build/url-template.js +30 -2
- package/build/url-template.js.map +1 -1
- package/build/util/abort.d.ts +3 -0
- package/build/util/abort.js +42 -0
- package/build/util/abort.js.map +1 -0
- package/build/util/base64.d.ts +4 -0
- package/build/util/base64.js +46 -0
- package/build/util/base64.js.map +1 -0
- package/build/util/native-fetch.d.ts +2 -0
- package/build/util/native-fetch.js +39 -0
- package/build/util/native-fetch.js.map +1 -0
- package/build/util/nullify.js +12 -5
- package/build/util/nullify.js.map +1 -1
- package/build/util/owned-body.d.ts +12 -0
- package/build/util/owned-body.js +243 -0
- package/build/util/owned-body.js.map +1 -0
- package/build/util/status-title.d.ts +2 -0
- package/build/util/status-title.js +83 -0
- package/build/util/status-title.js.map +1 -0
- package/package.json +18 -6
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
// Copyright 2020 Outfox, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
import { validateCredentials } from './credentials.js';
|
|
15
|
+
/** Resolved, transport-independent inputs supplied to an application's transport factory. */
|
|
16
|
+
export class ClientSettings {
|
|
17
|
+
baseUrl;
|
|
18
|
+
/** Providers shared by this configuration's operations; caching requires an explicit TokenManager. */
|
|
19
|
+
tokenProviders;
|
|
20
|
+
bindings;
|
|
21
|
+
#credentials;
|
|
22
|
+
/** Snapshots operation bindings and credentials without acquiring tokens or making requests. */
|
|
23
|
+
constructor(baseUrl, bindings = {}, credentials = {}) {
|
|
24
|
+
const url = new URL(baseUrl);
|
|
25
|
+
if (!['https:', 'http:'].includes(url.protocol) ||
|
|
26
|
+
url.username ||
|
|
27
|
+
url.password ||
|
|
28
|
+
url.href.includes('?') ||
|
|
29
|
+
url.href.includes('#'))
|
|
30
|
+
throw new TypeError('Client endpoint must be HTTP or HTTPS');
|
|
31
|
+
this.baseUrl = url.href;
|
|
32
|
+
this.bindings = Object.freeze(Object.fromEntries(Object.entries(bindings).map(([operation, values]) => [
|
|
33
|
+
operation,
|
|
34
|
+
Object.freeze(values.map((value) => Object.freeze({
|
|
35
|
+
...value,
|
|
36
|
+
...Object.fromEntries([
|
|
37
|
+
'discoveryUrl',
|
|
38
|
+
'authorizationUrl',
|
|
39
|
+
'tokenUrl',
|
|
40
|
+
'refreshUrl',
|
|
41
|
+
].flatMap((key) => {
|
|
42
|
+
const endpoint = value[key];
|
|
43
|
+
if (typeof endpoint !== 'string')
|
|
44
|
+
return [];
|
|
45
|
+
if (/[{}]/.test(endpoint))
|
|
46
|
+
throw new TypeError('Security endpoint URLs do not support server variables');
|
|
47
|
+
return [[key, new URL(endpoint, baseUrl).href]];
|
|
48
|
+
})),
|
|
49
|
+
scopes: Object.freeze([...value.scopes]),
|
|
50
|
+
transport: Object.freeze({ ...value.transport }),
|
|
51
|
+
}))),
|
|
52
|
+
])));
|
|
53
|
+
this.#credentials = new Map(Object.entries(credentials).map(([scheme, value]) => [
|
|
54
|
+
scheme,
|
|
55
|
+
Object.freeze({
|
|
56
|
+
...value,
|
|
57
|
+
...(value.kind === 'oauth' && value.endpoints
|
|
58
|
+
? {
|
|
59
|
+
endpoints: Object.freeze(Object.fromEntries(Object.entries(value.endpoints).map(([key, endpoint]) => {
|
|
60
|
+
if (endpoint === undefined)
|
|
61
|
+
return [key, undefined];
|
|
62
|
+
if (/[{}]/.test(endpoint))
|
|
63
|
+
throw new TypeError('Security endpoint URLs do not support server variables');
|
|
64
|
+
return [key, new URL(endpoint, baseUrl).href];
|
|
65
|
+
}))),
|
|
66
|
+
}
|
|
67
|
+
: {}),
|
|
68
|
+
}),
|
|
69
|
+
]));
|
|
70
|
+
for (const binding of Object.values(this.bindings).flat()) {
|
|
71
|
+
const credential = this.#credentials.get(binding.scheme);
|
|
72
|
+
if (!credential)
|
|
73
|
+
throw new TypeError(`Missing credentials for scheme '${binding.scheme}'`);
|
|
74
|
+
validateCredentials(credential, binding);
|
|
75
|
+
}
|
|
76
|
+
this.tokenProviders = this.prepareTokenProviders();
|
|
77
|
+
Object.freeze(this);
|
|
78
|
+
}
|
|
79
|
+
/** Expands server variables once and resolves relative servers against their document location. */
|
|
80
|
+
static serverUrl(template, variables, documentBaseUrl) {
|
|
81
|
+
const expanded = template.replace(/\{([^{}]+)\}/g, (_match, name) => {
|
|
82
|
+
if (!Object.hasOwn(variables, name))
|
|
83
|
+
throw new TypeError(`Missing server variable '${name}'`);
|
|
84
|
+
return variables[name];
|
|
85
|
+
});
|
|
86
|
+
const url = new URL(expanded, documentBaseUrl);
|
|
87
|
+
if (!['http:', 'https:'].includes(url.protocol) ||
|
|
88
|
+
url.username ||
|
|
89
|
+
url.password ||
|
|
90
|
+
url.search ||
|
|
91
|
+
url.hash) {
|
|
92
|
+
throw new TypeError('Invalid HTTP server endpoint');
|
|
93
|
+
}
|
|
94
|
+
return url.href;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Chooses one complete alternative per operation using credentials and optional explicit scheme sets.
|
|
98
|
+
* `alternativeSelection` selects a zero-based candidate index, including its scopes and endpoint metadata.
|
|
99
|
+
*/
|
|
100
|
+
static resolve(baseUrl, alternatives, credentials, selection = {}, alternativeSelection = {}) {
|
|
101
|
+
if ([...Object.keys(selection), ...Object.keys(alternativeSelection)].some((operation) => !Object.hasOwn(alternatives, operation))) {
|
|
102
|
+
throw new TypeError('Unknown operation selection');
|
|
103
|
+
}
|
|
104
|
+
const bindings = Object.create(null);
|
|
105
|
+
for (const [operation, candidates] of Object.entries(alternatives)) {
|
|
106
|
+
const selected = Object.hasOwn(selection, operation)
|
|
107
|
+
? selection[operation]
|
|
108
|
+
: undefined;
|
|
109
|
+
const selectedIndex = Object.hasOwn(alternativeSelection, operation)
|
|
110
|
+
? alternativeSelection[operation]
|
|
111
|
+
: undefined;
|
|
112
|
+
const usable = candidates.filter((candidate, index) => {
|
|
113
|
+
if (selectedIndex !== undefined && selectedIndex !== index)
|
|
114
|
+
return false;
|
|
115
|
+
if (selected &&
|
|
116
|
+
(selected.length !== candidate.length ||
|
|
117
|
+
candidate.some((binding) => !selected.includes(binding.scheme))))
|
|
118
|
+
return false;
|
|
119
|
+
return candidate.every((binding) => {
|
|
120
|
+
const credential = Object.hasOwn(credentials, binding.scheme)
|
|
121
|
+
? credentials[binding.scheme]
|
|
122
|
+
: undefined;
|
|
123
|
+
if (!credential)
|
|
124
|
+
return false;
|
|
125
|
+
try {
|
|
126
|
+
validateCredentials(credential, binding);
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
if (usable.length !== 1)
|
|
135
|
+
throw new TypeError(`Operation '${operation}' requires one complete security alternative`);
|
|
136
|
+
bindings[operation] = usable[0];
|
|
137
|
+
}
|
|
138
|
+
return new ClientSettings(baseUrl, bindings, credentials);
|
|
139
|
+
}
|
|
140
|
+
prepareTokenProviders() {
|
|
141
|
+
const providers = new Map();
|
|
142
|
+
const owners = new Map();
|
|
143
|
+
for (const binding of Object.values(this.bindings).flat()) {
|
|
144
|
+
const previous = owners.get(binding.provider);
|
|
145
|
+
if (previous !== undefined && previous !== binding.scheme) {
|
|
146
|
+
throw new TypeError('Distinct credential schemes require distinct provider bindings');
|
|
147
|
+
}
|
|
148
|
+
if (previous !== undefined)
|
|
149
|
+
continue;
|
|
150
|
+
owners.set(binding.provider, binding.scheme);
|
|
151
|
+
providers.set(binding.provider, this.prepareProvider(this.#credentials.get(binding.scheme)));
|
|
152
|
+
}
|
|
153
|
+
return Object.freeze(Object.fromEntries(providers));
|
|
154
|
+
}
|
|
155
|
+
prepareProvider(credentials) {
|
|
156
|
+
if (credentials.kind === 'provider')
|
|
157
|
+
return credentials.provider;
|
|
158
|
+
if (credentials.kind === 'oauth')
|
|
159
|
+
return credentials.providerFactory(credentials);
|
|
160
|
+
const identity = crypto.randomUUID();
|
|
161
|
+
let token;
|
|
162
|
+
switch (credentials.kind) {
|
|
163
|
+
case 'bearer':
|
|
164
|
+
token = credentials.token;
|
|
165
|
+
break;
|
|
166
|
+
case 'apiKey':
|
|
167
|
+
token = credentials.key;
|
|
168
|
+
break;
|
|
169
|
+
case 'basic':
|
|
170
|
+
token = btoa(Array.from(new TextEncoder().encode(`${credentials.username}:${credentials.password}`), (byte) => String.fromCodePoint(byte)).join(''));
|
|
171
|
+
break;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
identity,
|
|
175
|
+
configure: () => ({ clientIdentity: identity }),
|
|
176
|
+
acquire: () => Promise.resolve({ accessToken: token }),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=client-settings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client-settings.js","sourceRoot":"","sources":["../src/client-settings.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import type { SecurityBinding, SecurityEndpoints } from './security-binding.js';
|
|
2
|
+
import type { TokenProvider, TokenRequest } from './token-provider.js';
|
|
3
|
+
/** Fresh application-authorized PKCE result; interactive authorization remains application-owned. */
|
|
4
|
+
export interface AuthorizationGrant {
|
|
5
|
+
readonly code: string;
|
|
6
|
+
readonly redirectUri: string;
|
|
7
|
+
readonly codeVerifier: string;
|
|
8
|
+
}
|
|
9
|
+
/** Transport-independent OAuth client configuration. */
|
|
10
|
+
export interface OAuthCredentialOptions {
|
|
11
|
+
readonly identity: string;
|
|
12
|
+
readonly clientId: string;
|
|
13
|
+
readonly clientSecret?: string;
|
|
14
|
+
readonly authentication?: 'none' | 'client_secret_basic' | 'client_secret_post';
|
|
15
|
+
readonly grantIdentity?: string;
|
|
16
|
+
readonly authorization?: (request: TokenRequest, signal: AbortSignal) => Promise<AuthorizationGrant>;
|
|
17
|
+
readonly endpoints?: SecurityEndpoints;
|
|
18
|
+
readonly issuer?: string;
|
|
19
|
+
}
|
|
20
|
+
/** Application-supplied bearer token, without its wire prefix. */
|
|
21
|
+
export interface BearerCredentials {
|
|
22
|
+
readonly kind: 'bearer';
|
|
23
|
+
readonly token: string;
|
|
24
|
+
}
|
|
25
|
+
/** Application-supplied API key; the contract determines its wire location. */
|
|
26
|
+
export interface ApiKeyCredentials {
|
|
27
|
+
readonly kind: 'apiKey';
|
|
28
|
+
readonly key: string;
|
|
29
|
+
}
|
|
30
|
+
/** Basic authentication inputs; the runtime supplies the wire encoding. */
|
|
31
|
+
export interface BasicCredentials {
|
|
32
|
+
readonly kind: 'basic';
|
|
33
|
+
readonly username: string;
|
|
34
|
+
readonly password: string;
|
|
35
|
+
}
|
|
36
|
+
/** OAuth inputs narrowed to the selected acquisition flow. */
|
|
37
|
+
export type OAuthCredentials = {
|
|
38
|
+
/** Builds the installed module's provider without acquiring tokens. */
|
|
39
|
+
readonly providerFactory: (credentials: OAuthCredentials) => TokenProvider;
|
|
40
|
+
} & ((OAuthCredentialOptions & {
|
|
41
|
+
readonly kind: 'oauth';
|
|
42
|
+
readonly flow: 'clientCredentials';
|
|
43
|
+
}) | (OAuthCredentialOptions & {
|
|
44
|
+
readonly kind: 'oauth';
|
|
45
|
+
readonly flow: 'authorizationCode';
|
|
46
|
+
readonly grantIdentity: string;
|
|
47
|
+
readonly authorization: NonNullable<OAuthCredentialOptions['authorization']>;
|
|
48
|
+
}));
|
|
49
|
+
/** Escape hatch for application-owned acquisition and unsupported OAuth flows. */
|
|
50
|
+
export interface ProviderCredentials {
|
|
51
|
+
readonly kind: 'provider';
|
|
52
|
+
readonly provider: TokenProvider;
|
|
53
|
+
readonly flow?: SecurityBinding['flow'];
|
|
54
|
+
}
|
|
55
|
+
/** Shared credential family; generated code narrows this union for each declared scheme. */
|
|
56
|
+
export type Credentials = BearerCredentials | ApiKeyCredentials | BasicCredentials | OAuthCredentials | ProviderCredentials;
|
|
57
|
+
/** Reject incompatible inputs before constructing a transport or acquiring a token. */
|
|
58
|
+
export declare function validateCredentials(credentials: Credentials, binding: SecurityBinding): void;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// Copyright 2020 Outfox, Inc.
|
|
2
|
+
//
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
/** Reject incompatible inputs before constructing a transport or acquiring a token. */
|
|
15
|
+
export function validateCredentials(credentials, binding) {
|
|
16
|
+
if (credentials.kind === 'provider') {
|
|
17
|
+
if (credentials.flow !== undefined && credentials.flow !== binding.flow)
|
|
18
|
+
throw new TypeError('Provider flow does not match');
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const prefix = binding.transport.prefix?.toLowerCase();
|
|
22
|
+
if (credentials.kind === 'oauth') {
|
|
23
|
+
validateOAuthCredentials(credentials, binding);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (binding.flow !== 'static' && binding.flow !== 'external') {
|
|
27
|
+
throw new TypeError('Static credentials cannot satisfy an OAuth acquisition binding');
|
|
28
|
+
}
|
|
29
|
+
if (credentials.kind === 'bearer' && (prefix !== 'bearer' || !credentials.token)) {
|
|
30
|
+
throw new TypeError('Bearer credentials do not match the selected security binding');
|
|
31
|
+
}
|
|
32
|
+
if (credentials.kind === 'apiKey' && (prefix !== undefined || !credentials.key)) {
|
|
33
|
+
throw new TypeError('API key credentials do not match the selected security binding');
|
|
34
|
+
}
|
|
35
|
+
if (credentials.kind === 'basic' && (prefix !== 'basic' || credentials.username.includes(':'))) {
|
|
36
|
+
throw new TypeError('Basic credentials do not match the selected security binding');
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function validateOAuthCredentials(credentials, binding) {
|
|
40
|
+
const prefix = binding.transport.prefix?.toLowerCase();
|
|
41
|
+
if (prefix !== 'bearer' || credentials.flow !== binding.flow || !credentials.identity.trim() || !credentials.clientId.trim()) {
|
|
42
|
+
throw new TypeError('OAuth credentials do not match the selected security binding');
|
|
43
|
+
}
|
|
44
|
+
const authentication = credentials.authentication ?? 'none';
|
|
45
|
+
if (!['none', 'client_secret_basic', 'client_secret_post'].includes(authentication) || (authentication === 'none') !== (credentials.clientSecret === undefined) || credentials.clientSecret === '' ||
|
|
46
|
+
(credentials.flow === 'clientCredentials' && authentication === 'none') ||
|
|
47
|
+
(credentials.flow === 'authorizationCode' && (!credentials.grantIdentity.trim() || !credentials.authorization))) {
|
|
48
|
+
throw new TypeError('Invalid OAuth credential configuration');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,gDAAgD;AAChD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAiEjC,uFAAuF;AACvF,MAAM,UAAU,mBAAmB,CAAC,WAAwB,EAAE,OAAwB;IACpF,IAAI,WAAW,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QACpC,IAAI,WAAW,CAAC,IAAI,KAAK,SAAS,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI;YAAE,MAAM,IAAI,SAAS,CAAC,8BAA8B,CAAC,CAAC;QAC7H,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;IACvD,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACjC,wBAAwB,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;QAC/C,OAAO;IACT,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC7D,MAAM,IAAI,SAAS,CAAC,gEAAgE,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,SAAS,CAAC,+DAA+D,CAAC,CAAC;IACvF,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,EAAE,CAAC;QAChF,MAAM,IAAI,SAAS,CAAC,gEAAgE,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,MAAM,KAAK,OAAO,IAAI,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;QAC/F,MAAM,IAAI,SAAS,CAAC,8DAA8D,CAAC,CAAC;IACtF,CAAC;AACH,CAAC;AAGD,SAAS,wBAAwB,CAAC,WAA6B,EAAE,OAAwB;IACvF,MAAM,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,CAAC;IACvD,IAAI,MAAM,KAAK,QAAQ,IAAI,WAAW,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,IAAI,EAAE,EAAE,CAAC;QAC7H,MAAM,IAAI,SAAS,CAAC,8DAA8D,CAAC,CAAC;IACtF,CAAC;IACD,MAAM,cAAc,GAAG,WAAW,CAAC,cAAc,IAAI,MAAM,CAAC;IAC5D,IAAI,CAAC,CAAC,MAAM,EAAE,qBAAqB,EAAE,oBAAoB,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,cAAc,KAAK,MAAM,CAAC,KAAK,CAAC,WAAW,CAAC,YAAY,KAAK,SAAS,CAAC,IAAI,WAAW,CAAC,YAAY,KAAK,EAAE;QAChM,CAAC,WAAW,CAAC,IAAI,KAAK,mBAAmB,IAAI,cAAc,KAAK,MAAM,CAAC;QACvE,CAAC,WAAW,CAAC,IAAI,KAAK,mBAAmB,IAAI,CAAC,CAAC,WAAW,CAAC,aAAa,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC,EAAE,CAAC;QAClH,MAAM,IAAI,SAAS,CAAC,wCAAwC,CAAC,CAAC;IAChE,CAAC;AACH,CAAC"}
|
package/build/event-parser.d.ts
CHANGED
|
@@ -1,17 +1,32 @@
|
|
|
1
|
+
/** Message fields dispatched at a blank line; ID-only frames update the reconnect cursor. */
|
|
1
2
|
export interface EventInfo {
|
|
3
|
+
/** Last valid ID in this frame; NUL-containing fields are ignored. */
|
|
2
4
|
id?: string;
|
|
3
5
|
event?: string;
|
|
4
6
|
data?: string;
|
|
7
|
+
}
|
|
8
|
+
/** Connection controls reported immediately, independently of message boundaries. */
|
|
9
|
+
export interface EventControl {
|
|
10
|
+
/** A valid non-negative safe integer, retaining its wire representation. */
|
|
5
11
|
retry?: string;
|
|
12
|
+
keepalive?: string;
|
|
13
|
+
'retry-max'?: string;
|
|
6
14
|
}
|
|
15
|
+
/** Incremental UTF-8 SSE parser. Create one instance per connection; incomplete events end with it. */
|
|
7
16
|
export declare class EventParser {
|
|
17
|
+
private readonly control;
|
|
8
18
|
private readonly decoder;
|
|
9
|
-
private
|
|
10
|
-
|
|
11
|
-
private
|
|
12
|
-
private
|
|
13
|
-
private
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
private atStart;
|
|
20
|
+
private readonly lineParts;
|
|
21
|
+
private event;
|
|
22
|
+
private readonly data;
|
|
23
|
+
private skipLF;
|
|
24
|
+
/** Receives each completed control line, even when EOF discards the unfinished message. */
|
|
25
|
+
constructor(control?: (control: EventControl) => void);
|
|
26
|
+
/** Parses complete lines and events, discarding the rest of a chunk when the signal aborts. */
|
|
27
|
+
process(buffer: ArrayBuffer | ArrayBufferView, dispatcher: (eventInfo: EventInfo) => void, signal?: AbortSignal): void;
|
|
28
|
+
private discard;
|
|
29
|
+
private processLine;
|
|
17
30
|
}
|
|
31
|
+
/** @internal Parses bounded SSE millisecond values without accepting partial numbers. */
|
|
32
|
+
export declare function parseEventMilliseconds(value: string): number | undefined;
|
package/build/event-parser.js
CHANGED
|
@@ -11,141 +11,113 @@
|
|
|
11
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
|
+
/** Incremental UTF-8 SSE parser. Create one instance per connection; incomplete events end with it. */
|
|
14
15
|
export class EventParser {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
EventParser.parseAndDispatchEvents(eventStrings, dispatcher);
|
|
16
|
+
control;
|
|
17
|
+
// Node can strip two consecutive BOMs when the first spans chunks; remove exactly one here.
|
|
18
|
+
decoder = new TextDecoder('utf-8', { ignoreBOM: true });
|
|
19
|
+
atStart = true;
|
|
20
|
+
lineParts = [];
|
|
21
|
+
event = {};
|
|
22
|
+
data = [];
|
|
23
|
+
skipLF = false;
|
|
24
|
+
/** Receives each completed control line, even when EOF discards the unfinished message. */
|
|
25
|
+
constructor(control = () => { }) {
|
|
26
|
+
this.control = control;
|
|
27
27
|
}
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
return
|
|
33
|
-
}
|
|
34
|
-
else if (!unprocessedBuffer?.byteLength) {
|
|
35
|
-
return buffer;
|
|
28
|
+
/** Parses complete lines and events, discarding the rest of a chunk when the signal aborts. */
|
|
29
|
+
process(buffer, dispatcher, signal) {
|
|
30
|
+
if (signal?.aborted) {
|
|
31
|
+
this.discard();
|
|
32
|
+
return;
|
|
36
33
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
extractEventStringsFromBuffer(buffer) {
|
|
43
|
-
const eventStrings = [];
|
|
44
|
-
while (buffer.byteLength) {
|
|
45
|
-
// Find end of next event separator in buffer, exiting if none found.
|
|
46
|
-
const eventSeparator = EventParser.findEventSeparator(buffer);
|
|
47
|
-
if (!eventSeparator) {
|
|
48
|
-
// Save unprocessed data
|
|
49
|
-
this.unprocessedBuffer = buffer;
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
const [endOfCurrentEventIdx, startOfNextEventIdx] = eventSeparator;
|
|
53
|
-
const eventBuffer = buffer.slice(0, endOfCurrentEventIdx);
|
|
54
|
-
buffer = buffer.slice(startOfNextEventIdx);
|
|
55
|
-
const eventString = this.decoder.decode(eventBuffer, {
|
|
56
|
-
stream: true,
|
|
57
|
-
});
|
|
58
|
-
eventStrings.push(eventString);
|
|
34
|
+
let text = this.decoder.decode(buffer, { stream: true });
|
|
35
|
+
if (this.atStart && text.length) {
|
|
36
|
+
this.atStart = false;
|
|
37
|
+
if (text[0] === '\ufeff')
|
|
38
|
+
text = text.slice(1);
|
|
59
39
|
}
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
// if the next byte is the
|
|
70
|
-
// same, we found a separator
|
|
71
|
-
if (bytes[idx + 1] == 0xa) {
|
|
72
|
-
return [idx, idx + 2];
|
|
73
|
-
}
|
|
74
|
-
break;
|
|
75
|
-
}
|
|
76
|
-
// carriage-return
|
|
77
|
-
case 0xd: {
|
|
78
|
-
// if the next byte is the
|
|
79
|
-
// same, we found a separator
|
|
80
|
-
if (bytes[idx + 1] == 0xd) {
|
|
81
|
-
return [idx, idx + 2];
|
|
82
|
-
}
|
|
83
|
-
// if next is line-feed, and pattern
|
|
84
|
-
// repeats, we found a separator.
|
|
85
|
-
if (bytes[idx + 1] == 0xa &&
|
|
86
|
-
bytes[idx + 2] == 0xd &&
|
|
87
|
-
bytes[idx + 3] == 0xa) {
|
|
88
|
-
return [idx, idx + 4];
|
|
89
|
-
}
|
|
90
|
-
break;
|
|
40
|
+
let start = 0;
|
|
41
|
+
for (let index = 0; index < text.length; index++) {
|
|
42
|
+
const character = text[index];
|
|
43
|
+
// A CR completes its line immediately; only its optional following LF is skipped.
|
|
44
|
+
if (this.skipLF) {
|
|
45
|
+
this.skipLF = false;
|
|
46
|
+
if (character === '\n') {
|
|
47
|
+
start = index + 1;
|
|
48
|
+
continue;
|
|
91
49
|
}
|
|
92
|
-
default:
|
|
93
50
|
}
|
|
94
|
-
|
|
95
|
-
return undefined;
|
|
96
|
-
}
|
|
97
|
-
static parseAndDispatchEvents(eventStrings, dispatcher) {
|
|
98
|
-
for (const eventString of eventStrings) {
|
|
99
|
-
if (!eventString.length) {
|
|
51
|
+
if (character !== '\r' && character !== '\n')
|
|
100
52
|
continue;
|
|
101
|
-
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
for (const line of eventString.split(lineSeparatorsRegEx)) {
|
|
109
|
-
const keyValueSeparatorIdx = line.indexOf(':');
|
|
110
|
-
let key;
|
|
111
|
-
let value;
|
|
112
|
-
if (keyValueSeparatorIdx != -1) {
|
|
113
|
-
key = line.slice(0, keyValueSeparatorIdx);
|
|
114
|
-
value = line.slice(keyValueSeparatorIdx + 1);
|
|
53
|
+
this.lineParts.push(text.slice(start, index));
|
|
54
|
+
const line = this.lineParts.join('');
|
|
55
|
+
this.lineParts.length = 0;
|
|
56
|
+
this.skipLF = character === '\r';
|
|
57
|
+
start = index + 1;
|
|
58
|
+
if (line) {
|
|
59
|
+
this.processLine(line);
|
|
115
60
|
}
|
|
116
61
|
else {
|
|
117
|
-
|
|
118
|
-
|
|
62
|
+
const event = this.event;
|
|
63
|
+
if (this.data.length)
|
|
64
|
+
event.data = this.data.join('\n');
|
|
65
|
+
this.event = {};
|
|
66
|
+
this.data.length = 0;
|
|
67
|
+
if (event.data !== undefined || event.id !== undefined)
|
|
68
|
+
dispatcher(event);
|
|
119
69
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
break;
|
|
124
|
-
case 'data': {
|
|
125
|
-
const data = event.data ?? '';
|
|
126
|
-
event.data = `${data}${EventParser.trimFieldValue(value)}\n`;
|
|
127
|
-
break;
|
|
128
|
-
}
|
|
129
|
-
case '':
|
|
130
|
-
// comment do nothing
|
|
131
|
-
break;
|
|
132
|
-
default: {
|
|
133
|
-
event[key] =
|
|
134
|
-
EventParser.trimFieldValue(value);
|
|
135
|
-
}
|
|
70
|
+
if (signal?.aborted) {
|
|
71
|
+
this.discard();
|
|
72
|
+
return;
|
|
136
73
|
}
|
|
137
74
|
}
|
|
138
|
-
if (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
75
|
+
if (start < text.length)
|
|
76
|
+
this.lineParts.push(text.slice(start));
|
|
77
|
+
}
|
|
78
|
+
discard() {
|
|
79
|
+
// decode() without stream resets UTF-8/BOM state, including a partial character in the
|
|
80
|
+
// discarded tail. It must not contaminate a later call after cancellation.
|
|
81
|
+
this.decoder.decode();
|
|
82
|
+
this.atStart = true;
|
|
83
|
+
this.lineParts.length = 0;
|
|
84
|
+
this.event = {};
|
|
85
|
+
this.data.length = 0;
|
|
86
|
+
this.skipLF = false;
|
|
142
87
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
88
|
+
processLine(line) {
|
|
89
|
+
const colon = line.indexOf(':');
|
|
90
|
+
const key = colon < 0 ? line : line.slice(0, colon);
|
|
91
|
+
let value = colon < 0 ? '' : line.slice(colon + 1);
|
|
92
|
+
if (value.startsWith(' '))
|
|
93
|
+
value = value.slice(1);
|
|
94
|
+
switch (key) {
|
|
95
|
+
case 'data':
|
|
96
|
+
this.data.push(value);
|
|
97
|
+
break;
|
|
98
|
+
case 'id':
|
|
99
|
+
if (!value.includes('\0'))
|
|
100
|
+
this.event.id = value;
|
|
101
|
+
break;
|
|
102
|
+
case 'retry':
|
|
103
|
+
if (parseEventMilliseconds(value) !== undefined)
|
|
104
|
+
this.control({ retry: value });
|
|
105
|
+
break;
|
|
106
|
+
case 'event':
|
|
107
|
+
this.event.event = value;
|
|
108
|
+
break;
|
|
109
|
+
case 'keepalive':
|
|
110
|
+
case 'retry-max':
|
|
111
|
+
this.control({ [key]: value });
|
|
112
|
+
break;
|
|
146
113
|
}
|
|
147
|
-
return value.slice(1);
|
|
148
114
|
}
|
|
149
115
|
}
|
|
150
|
-
|
|
116
|
+
/** @internal Parses bounded SSE millisecond values without accepting partial numbers. */
|
|
117
|
+
export function parseEventMilliseconds(value) {
|
|
118
|
+
if (!/^\d+$/.test(value))
|
|
119
|
+
return undefined;
|
|
120
|
+
const milliseconds = Number(value);
|
|
121
|
+
return Number.isSafeInteger(milliseconds) ? milliseconds : undefined;
|
|
122
|
+
}
|
|
151
123
|
//# sourceMappingURL=event-parser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"event-parser.js","sourceRoot":"","sources":["../src/event-parser.ts"],"names":[],"mappings":"AAAA,8BAA8B;AAC9B,EAAE;AACF,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,gDAAgD;AAChD,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;
|
|
1
|
+
{"version":3,"file":"event-parser.js","sourceRoot":"","sources":["../src/event-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copies native Fetch request settings and transfers responsibility for its body. The old request
|
|
3
|
+
* must not subsequently consume the body. Supply a replacement after consuming a body.
|
|
4
|
+
*/
|
|
5
|
+
export declare function copyRequest(request: Request, changes?: RequestInit & {
|
|
6
|
+
url?: string | URL;
|
|
7
|
+
duplex?: 'half';
|
|
8
|
+
}): Request;
|
|
9
|
+
/**
|
|
10
|
+
* Copies an inspectable response without teeing its body, retaining Fetch metadata.
|
|
11
|
+
* Opaque/error responses cannot be reconstructed with the platform Response constructor.
|
|
12
|
+
*/
|
|
13
|
+
export declare function copyResponse(response: Response, changes?: ResponseInit & {
|
|
14
|
+
body?: BodyInit | null;
|
|
15
|
+
}): Response;
|