@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,58 @@
|
|
|
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 { AuthenticationAdapter } from './authentication-adapter.js';
|
|
15
|
+
import { BearerTokenRejectionAdapter } from './bearer-token-rejection-adapter.js';
|
|
16
|
+
import { isRequestStopped } from './request-cancellation-error.js';
|
|
17
|
+
import { FetchTransport } from './fetch-transport.js';
|
|
18
|
+
import { RequestAdapters } from './request-adapters.js';
|
|
19
|
+
import { ResponseAdapters } from './response-adapters.js';
|
|
20
|
+
import { requestSecurityBindings } from './request-security-bindings.js';
|
|
21
|
+
/** Opt-in attachment, rejection feedback, and terminal cancellation. Supplied providers are never cached or wrapped. */
|
|
22
|
+
export class StandardAuthenticationAdapter {
|
|
23
|
+
authentication;
|
|
24
|
+
responses;
|
|
25
|
+
/** Uses caller-owned providers; supply TokenManager explicitly for Sunday-managed caching and refresh. */
|
|
26
|
+
constructor(providers, options) {
|
|
27
|
+
this.authentication = new AuthenticationAdapter(providers, options);
|
|
28
|
+
this.responses = new ResponseAdapters(this.authentication, new BearerTokenRejectionAdapter());
|
|
29
|
+
}
|
|
30
|
+
async adapt(value, request) {
|
|
31
|
+
if (!request)
|
|
32
|
+
return this.authentication.adapt(value);
|
|
33
|
+
if (!requestSecurityBindings(request).length)
|
|
34
|
+
return value;
|
|
35
|
+
try {
|
|
36
|
+
return await this.responses.adapt(value, request);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
if (request.signal.aborted || isRequestStopped(error))
|
|
40
|
+
throw error;
|
|
41
|
+
// Feedback failure must not bypass the explicitly selected stop policy.
|
|
42
|
+
await new BearerTokenRejectionAdapter().adapt(value, request);
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** Explicit standard factory for generated clients. Additional adapters run after standard authentication. */
|
|
48
|
+
export function standardTransportFromSettings(settings, options) {
|
|
49
|
+
const authentication = new StandardAuthenticationAdapter(settings.tokenProviders, options);
|
|
50
|
+
const request = options?.requestAdapter ?? options?.adapter;
|
|
51
|
+
const response = options?.responseAdapter;
|
|
52
|
+
return new FetchTransport(settings.baseUrl, {
|
|
53
|
+
...options,
|
|
54
|
+
requestAdapter: new RequestAdapters(authentication, ...(request ? [request] : [])),
|
|
55
|
+
responseAdapter: new ResponseAdapters(authentication, ...(response ? [response] : [])),
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=standard-authentication-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"standard-authentication-adapter.js","sourceRoot":"","sources":["../src/standard-authentication-adapter.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;AAEjC,OAAO,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AAEnE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAGzE,wHAAwH;AACxH,MAAM,OAAO,6BAA6B;IAGvB,cAAc,CAAwB;IACtC,SAAS,CAAmB;IAE7C,0GAA0G;IAC1G,YACE,SAAkD,EAClD,OAAgE;QAEhE,IAAI,CAAC,cAAc,GAAG,IAAI,qBAAqB,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;QACpE,IAAI,CAAC,SAAS,GAAG,IAAI,gBAAgB,CACnC,IAAI,CAAC,cAAc,EACnB,IAAI,2BAA2B,EAAE,CAClC,CAAC;IACJ,CAAC;IAKD,KAAK,CAAC,KAAK,CACT,KAAyB,EACzB,OAAiB;QAEjB,IAAI,CAAC,OAAO;YAAE,OAAO,IAAI,CAAC,cAAc,CAAC,KAAK,CAAC,KAAgB,CAAC,CAAC;QACjE,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC,MAAM;YAAE,OAAO,KAAK,CAAC;QAC3D,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,KAAiB,EAAE,OAAO,CAAC,CAAC;QAChE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,IAAI,gBAAgB,CAAC,KAAK,CAAC;gBAAE,MAAM,KAAK,CAAC;YACnE,wEAAwE;YACxE,MAAM,IAAI,2BAA2B,EAAE,CAAC,KAAK,CAAC,KAAiB,EAAE,OAAO,CAAC,CAAC;YAC1E,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;CACF;AAED,8GAA8G;AAC9G,MAAM,UAAU,6BAA6B,CAC3C,QAAwB,EACxB,OAAyD;IAEzD,MAAM,cAAc,GAAG,IAAI,6BAA6B,CACtD,QAAQ,CAAC,cAAc,EACvB,OAAO,CACR,CAAC;IACF,MAAM,OAAO,GAAG,OAAO,EAAE,cAAc,IAAI,OAAO,EAAE,OAAO,CAAC;IAC5D,MAAM,QAAQ,GAAG,OAAO,EAAE,eAAe,CAAC;IAC1C,OAAO,IAAI,cAAc,CAAC,QAAQ,CAAC,OAAO,EAAE;QAC1C,GAAG,OAAO;QACV,cAAc,EAAE,IAAI,eAAe,CACjC,cAAc,EACd,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAC9B;QACD,eAAe,EAAE,IAAI,gBAAgB,CACnC,cAAc,EACd,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAChC;KACF,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { SecurityBinding } from './security-binding.js';
|
|
2
|
+
import { TokenConfiguration, TokenProvider, TokenRequest, TokenSet, TokenStore } from './token-provider.js';
|
|
3
|
+
/** A credential receipt used for conditional invalidation after an invalid-token response. */
|
|
4
|
+
export interface TokenLease {
|
|
5
|
+
readonly key: string;
|
|
6
|
+
readonly tokens: TokenSet;
|
|
7
|
+
/** Rejects the original credential without invalidating a concurrent replacement. */
|
|
8
|
+
readonly invalidate?: () => Promise<boolean>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Shared token lifecycle with one renewal per cache key. Canceling one caller leaves other waiters
|
|
12
|
+
* running; canceling the last waiter stops waiting for the provider without abandoning storage commits.
|
|
13
|
+
* A failed or cancelled acquisition is never cached.
|
|
14
|
+
*/
|
|
15
|
+
export declare class TokenManager implements TokenProvider {
|
|
16
|
+
readonly identity: string;
|
|
17
|
+
private readonly provider?;
|
|
18
|
+
private readonly providers;
|
|
19
|
+
private readonly store;
|
|
20
|
+
private readonly renewals;
|
|
21
|
+
private readonly authorizationAttempts;
|
|
22
|
+
private readonly locks;
|
|
23
|
+
private readonly now;
|
|
24
|
+
private readonly skew;
|
|
25
|
+
constructor(providers: TokenProvider | Readonly<Record<string, TokenProvider>>, options?: {
|
|
26
|
+
store?: TokenStore;
|
|
27
|
+
expirySkewMs?: number;
|
|
28
|
+
now?: () => number;
|
|
29
|
+
});
|
|
30
|
+
/** Forwards application configuration to the explicitly managed provider. */
|
|
31
|
+
configure(binding: SecurityBinding): TokenConfiguration;
|
|
32
|
+
/** Obtains managed credentials; receipt acquisition preserves rejection context. */
|
|
33
|
+
acquire(request: TokenRequest, signal: AbortSignal): Promise<TokenSet>;
|
|
34
|
+
/** Acquires current credentials without invoking authorization twice for an expired interactive session. */
|
|
35
|
+
credentials(binding: SecurityBinding, signal?: AbortSignal): Promise<TokenLease>;
|
|
36
|
+
/** Invalidates only the credential that failed, preserving a token already renewed by another caller. */
|
|
37
|
+
invalidate(lease: TokenLease): Promise<void>;
|
|
38
|
+
private exclusive;
|
|
39
|
+
private renew;
|
|
40
|
+
private acquireOrRefresh;
|
|
41
|
+
private join;
|
|
42
|
+
}
|
|
@@ -0,0 +1,276 @@
|
|
|
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 { withAbort } from './util/abort.js';
|
|
15
|
+
import { isRequestStopped } from './request-cancellation-error.js';
|
|
16
|
+
import { AuthorizationRequiredError, TokenProviderError, } from './token-provider.js';
|
|
17
|
+
/**
|
|
18
|
+
* Shared token lifecycle with one renewal per cache key. Canceling one caller leaves other waiters
|
|
19
|
+
* running; canceling the last waiter stops waiting for the provider without abandoning storage commits.
|
|
20
|
+
* A failed or cancelled acquisition is never cached.
|
|
21
|
+
*/
|
|
22
|
+
export class TokenManager {
|
|
23
|
+
identity;
|
|
24
|
+
provider;
|
|
25
|
+
providers;
|
|
26
|
+
store;
|
|
27
|
+
renewals = new Map();
|
|
28
|
+
authorizationAttempts = new Set();
|
|
29
|
+
locks = new Map();
|
|
30
|
+
now;
|
|
31
|
+
skew;
|
|
32
|
+
constructor(providers, options = {}) {
|
|
33
|
+
this.provider =
|
|
34
|
+
typeof providers.acquire === 'function'
|
|
35
|
+
? providers
|
|
36
|
+
: undefined;
|
|
37
|
+
this.providers = new Map(this.provider
|
|
38
|
+
? []
|
|
39
|
+
: Object.entries(providers));
|
|
40
|
+
this.identity = this.provider?.identity ?? crypto.randomUUID();
|
|
41
|
+
this.store = options.store ?? new MemoryTokenStore();
|
|
42
|
+
this.now = options.now ?? Date.now;
|
|
43
|
+
this.skew = options.expirySkewMs ?? 30_000;
|
|
44
|
+
if (!Number.isFinite(this.skew) || this.skew < 0)
|
|
45
|
+
throw new RangeError('Invalid token expiry skew');
|
|
46
|
+
}
|
|
47
|
+
/** Forwards application configuration to the explicitly managed provider. */
|
|
48
|
+
configure(binding) {
|
|
49
|
+
const provider = this.provider ?? this.providers.get(binding.provider);
|
|
50
|
+
if (!provider)
|
|
51
|
+
throw new TokenProviderError();
|
|
52
|
+
return provider.configure(binding);
|
|
53
|
+
}
|
|
54
|
+
/** Obtains managed credentials; receipt acquisition preserves rejection context. */
|
|
55
|
+
async acquire(request, signal) {
|
|
56
|
+
return (await this.credentials(request, signal)).tokens;
|
|
57
|
+
}
|
|
58
|
+
/** Acquires current credentials without invoking authorization twice for an expired interactive session. */
|
|
59
|
+
async credentials(binding, signal) {
|
|
60
|
+
signal?.throwIfAborted();
|
|
61
|
+
const provider = this.provider ?? this.providers.get(binding.provider);
|
|
62
|
+
if (!provider)
|
|
63
|
+
throw new TokenProviderError();
|
|
64
|
+
let configuration;
|
|
65
|
+
try {
|
|
66
|
+
configuration = provider.configure(binding);
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
if (isRequestStopped(error))
|
|
70
|
+
throw error;
|
|
71
|
+
throw new TokenProviderError();
|
|
72
|
+
}
|
|
73
|
+
if (!provider.identity.trim() ||
|
|
74
|
+
!configuration.clientIdentity.trim() ||
|
|
75
|
+
(binding.flow === 'authorizationCode' &&
|
|
76
|
+
!configuration.grantIdentity?.trim()))
|
|
77
|
+
throw new TokenProviderError();
|
|
78
|
+
const request = Object.freeze({
|
|
79
|
+
...binding,
|
|
80
|
+
discoveryUrl: configuration.endpoints?.discoveryUrl ?? binding.discoveryUrl,
|
|
81
|
+
authorizationUrl: configuration.endpoints?.authorizationUrl ?? binding.authorizationUrl,
|
|
82
|
+
tokenUrl: configuration.endpoints?.tokenUrl ?? binding.tokenUrl,
|
|
83
|
+
refreshUrl: configuration.endpoints?.refreshUrl ?? binding.refreshUrl,
|
|
84
|
+
clientIdentity: configuration.clientIdentity,
|
|
85
|
+
grantIdentity: configuration.grantIdentity,
|
|
86
|
+
scopes: Object.freeze([...new Set(binding.scopes)].sort(compareScopes)),
|
|
87
|
+
transport: Object.freeze({ ...binding.transport }),
|
|
88
|
+
});
|
|
89
|
+
const key = JSON.stringify([
|
|
90
|
+
request.scheme,
|
|
91
|
+
binding.provider,
|
|
92
|
+
provider.identity,
|
|
93
|
+
request.clientIdentity,
|
|
94
|
+
request.grantIdentity,
|
|
95
|
+
request.profile,
|
|
96
|
+
request.flow,
|
|
97
|
+
request.discoveryUrl,
|
|
98
|
+
request.authorizationUrl,
|
|
99
|
+
request.tokenUrl,
|
|
100
|
+
request.refreshUrl,
|
|
101
|
+
request.scopes,
|
|
102
|
+
request.audience,
|
|
103
|
+
request.resource,
|
|
104
|
+
]);
|
|
105
|
+
let renewal = this.renewals.get(key);
|
|
106
|
+
if (!renewal || renewal.controller.signal.aborted) {
|
|
107
|
+
const controller = new AbortController();
|
|
108
|
+
const created = {
|
|
109
|
+
controller,
|
|
110
|
+
waiters: 0,
|
|
111
|
+
settled: false,
|
|
112
|
+
committing: false,
|
|
113
|
+
promise: this.exclusive(key, () => this.renew(key, provider, request, controller.signal)),
|
|
114
|
+
};
|
|
115
|
+
this.renewals.set(key, created);
|
|
116
|
+
void created.promise
|
|
117
|
+
.finally(() => {
|
|
118
|
+
created.settled = true;
|
|
119
|
+
if (this.renewals.get(key) === created)
|
|
120
|
+
this.renewals.delete(key);
|
|
121
|
+
})
|
|
122
|
+
.catch(() => undefined);
|
|
123
|
+
renewal = created;
|
|
124
|
+
}
|
|
125
|
+
const lease = await this.join(renewal, signal);
|
|
126
|
+
return {
|
|
127
|
+
...lease,
|
|
128
|
+
invalidate: async () => {
|
|
129
|
+
await this.invalidate(lease);
|
|
130
|
+
return true;
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** Invalidates only the credential that failed, preserving a token already renewed by another caller. */
|
|
135
|
+
async invalidate(lease) {
|
|
136
|
+
try {
|
|
137
|
+
await this.exclusive(lease.key, async () => {
|
|
138
|
+
const current = await this.store.load(lease.key);
|
|
139
|
+
if (current?.accessToken === lease.tokens.accessToken) {
|
|
140
|
+
await this.store.save(lease.key, Object.freeze({ ...current, expiresAt: 0 }));
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
if (isRequestStopped(error))
|
|
146
|
+
throw error;
|
|
147
|
+
throw new TokenProviderError();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
exclusive(key, action) {
|
|
151
|
+
const prior = this.locks.get(key) ?? Promise.resolve();
|
|
152
|
+
const next = prior.catch(() => undefined).then(action);
|
|
153
|
+
this.locks.set(key, next);
|
|
154
|
+
void next
|
|
155
|
+
.finally(() => {
|
|
156
|
+
if (this.locks.get(key) === next)
|
|
157
|
+
this.locks.delete(key);
|
|
158
|
+
})
|
|
159
|
+
.catch(() => undefined);
|
|
160
|
+
return next;
|
|
161
|
+
}
|
|
162
|
+
async renew(key, provider, request, signal) {
|
|
163
|
+
try {
|
|
164
|
+
signal.throwIfAborted();
|
|
165
|
+
const stored = await this.store.load(key);
|
|
166
|
+
signal.throwIfAborted();
|
|
167
|
+
if (stored &&
|
|
168
|
+
(stored.expiresAt === undefined ||
|
|
169
|
+
stored.expiresAt > this.now() + this.skew)) {
|
|
170
|
+
return { key, tokens: Object.freeze({ ...stored }) };
|
|
171
|
+
}
|
|
172
|
+
const tokens = await this.acquireOrRefresh(key, stored, provider, request, signal);
|
|
173
|
+
if (!tokens.accessToken ||
|
|
174
|
+
(tokens.expiresAt !== undefined &&
|
|
175
|
+
(!Number.isFinite(tokens.expiresAt) ||
|
|
176
|
+
tokens.expiresAt <= this.now())))
|
|
177
|
+
throw new TokenProviderError();
|
|
178
|
+
const snapshot = Object.freeze({ ...tokens });
|
|
179
|
+
signal.throwIfAborted();
|
|
180
|
+
const renewal = this.renewals.get(key);
|
|
181
|
+
if (renewal?.controller.signal !== signal)
|
|
182
|
+
throw new DOMException('Renewal expired', 'AbortError');
|
|
183
|
+
// Once persistence begins, cancellation must not discard a rotated refresh token.
|
|
184
|
+
renewal.committing = true;
|
|
185
|
+
await this.store.save(key, snapshot);
|
|
186
|
+
return { key, tokens: snapshot };
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
if (signal.aborted)
|
|
190
|
+
throw signal.reason;
|
|
191
|
+
if (isRequestStopped(error))
|
|
192
|
+
throw error;
|
|
193
|
+
if (error instanceof AuthorizationRequiredError ||
|
|
194
|
+
error instanceof TokenProviderError)
|
|
195
|
+
throw error;
|
|
196
|
+
throw new TokenProviderError();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
async acquireOrRefresh(key, stored, provider, request, signal) {
|
|
200
|
+
const refreshToken = stored?.refreshToken;
|
|
201
|
+
if (refreshToken && provider.refresh) {
|
|
202
|
+
try {
|
|
203
|
+
const refreshed = await withAbort(() => provider.refresh(request, refreshToken, signal), signal);
|
|
204
|
+
return {
|
|
205
|
+
...refreshed,
|
|
206
|
+
refreshToken: refreshed.refreshToken ?? refreshToken,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
catch (error) {
|
|
210
|
+
if (!(error instanceof TokenProviderError) ||
|
|
211
|
+
error.reason !== 'invalidGrant' ||
|
|
212
|
+
request.flow !== 'clientCredentials')
|
|
213
|
+
throw error;
|
|
214
|
+
signal.throwIfAborted();
|
|
215
|
+
await this.store.remove(key);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
else if (request.flow === 'authorizationCode' &&
|
|
219
|
+
(stored || this.authorizationAttempts.has(key))) {
|
|
220
|
+
throw new AuthorizationRequiredError();
|
|
221
|
+
}
|
|
222
|
+
// Only provider work is cancellable: storage mutations must finish before releasing the
|
|
223
|
+
// key's lock. Late provider completion is observed by withAbort but cannot reach persistence.
|
|
224
|
+
return withAbort(() => {
|
|
225
|
+
if (request.flow === 'authorizationCode')
|
|
226
|
+
this.authorizationAttempts.add(key);
|
|
227
|
+
return provider.acquire(request, signal);
|
|
228
|
+
}, signal);
|
|
229
|
+
}
|
|
230
|
+
join(renewal, signal) {
|
|
231
|
+
renewal.waiters++;
|
|
232
|
+
return new Promise((resolve, reject) => {
|
|
233
|
+
let completed = false;
|
|
234
|
+
const finish = (value, error) => {
|
|
235
|
+
if (completed)
|
|
236
|
+
return;
|
|
237
|
+
completed = true;
|
|
238
|
+
signal?.removeEventListener('abort', abort);
|
|
239
|
+
renewal.waiters--;
|
|
240
|
+
if (renewal.waiters === 0 && !renewal.settled && !renewal.committing)
|
|
241
|
+
renewal.controller.abort(error);
|
|
242
|
+
if (value)
|
|
243
|
+
resolve(value);
|
|
244
|
+
else
|
|
245
|
+
reject(error);
|
|
246
|
+
};
|
|
247
|
+
const abort = () => finish(undefined, signal?.reason);
|
|
248
|
+
signal?.addEventListener('abort', abort, { once: true });
|
|
249
|
+
if (signal?.aborted)
|
|
250
|
+
abort();
|
|
251
|
+
renewal.promise.then((value) => finish(value), (error) => finish(undefined, error));
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
class MemoryTokenStore {
|
|
256
|
+
tokens = new Map();
|
|
257
|
+
load(key) {
|
|
258
|
+
return Promise.resolve(this.tokens.get(key));
|
|
259
|
+
}
|
|
260
|
+
save(key, tokens) {
|
|
261
|
+
this.tokens.set(key, tokens);
|
|
262
|
+
return Promise.resolve();
|
|
263
|
+
}
|
|
264
|
+
remove(key) {
|
|
265
|
+
this.tokens.delete(key);
|
|
266
|
+
return Promise.resolve();
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
function compareScopes(left, right) {
|
|
270
|
+
if (left < right)
|
|
271
|
+
return -1;
|
|
272
|
+
if (left > right)
|
|
273
|
+
return 1;
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
//# sourceMappingURL=token-manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../src/token-manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { RequestCancellationError } from './request-cancellation-error.js';
|
|
2
|
+
import { SecurityBinding, SecurityEndpoints } from './security-binding.js';
|
|
3
|
+
import type { TokenLease } from './token-manager.js';
|
|
4
|
+
/** Credentials returned by an application provider; values are never included in runtime diagnostics. */
|
|
5
|
+
export interface TokenSet {
|
|
6
|
+
readonly accessToken: string;
|
|
7
|
+
readonly expiresAt?: number;
|
|
8
|
+
readonly refreshToken?: string;
|
|
9
|
+
}
|
|
10
|
+
/** Non-secret identities isolate cache entries; grantIdentity must change with session or grant inputs. */
|
|
11
|
+
export interface TokenConfiguration {
|
|
12
|
+
readonly clientIdentity: string;
|
|
13
|
+
readonly grantIdentity?: string;
|
|
14
|
+
readonly endpoints?: SecurityEndpoints;
|
|
15
|
+
}
|
|
16
|
+
/** Fully selected acquisition parameters; this contains neither client secrets nor authorization codes. */
|
|
17
|
+
export interface TokenRequest extends SecurityBinding {
|
|
18
|
+
readonly clientIdentity: string;
|
|
19
|
+
readonly grantIdentity?: string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Application credential binding. OAuth providers exchange fresh authorization and refresh tokens;
|
|
23
|
+
* providers own their lifecycle; TokenManager adds caching only when explicitly supplied.
|
|
24
|
+
*/
|
|
25
|
+
export interface TokenProvider {
|
|
26
|
+
readonly identity: string;
|
|
27
|
+
configure(binding: SecurityBinding): TokenConfiguration;
|
|
28
|
+
acquire(request: TokenRequest, signal: AbortSignal): Promise<TokenSet>;
|
|
29
|
+
/** Optional receipt acquisition, used by caching decorators to retain their original cache identity. */
|
|
30
|
+
credentials?(binding: SecurityBinding, signal?: AbortSignal): Promise<TokenLease>;
|
|
31
|
+
/** Rejects only this token in its original session. False leaves recovery to the caller. */
|
|
32
|
+
reject?(request: TokenRequest, rejectedToken: string): Promise<boolean>;
|
|
33
|
+
refresh?(request: TokenRequest, refreshToken: string, signal: AbortSignal): Promise<TokenSet>;
|
|
34
|
+
}
|
|
35
|
+
/** Application-owned storage. Implementations must serialize writes and keep credentials private. */
|
|
36
|
+
export interface TokenStore {
|
|
37
|
+
load(key: string): Promise<TokenSet | undefined>;
|
|
38
|
+
save(key: string, tokens: TokenSet): Promise<void>;
|
|
39
|
+
remove(key: string): Promise<void>;
|
|
40
|
+
}
|
|
41
|
+
/** Signals that an interactive application must supply a fresh authorization session. */
|
|
42
|
+
export declare class AuthorizationRequiredError extends RequestCancellationError {
|
|
43
|
+
constructor();
|
|
44
|
+
}
|
|
45
|
+
/** Safe provider failure without a provider's potentially credential-bearing error message. */
|
|
46
|
+
export declare class TokenProviderError extends Error {
|
|
47
|
+
readonly reason: 'unavailable' | 'temporary' | 'invalidGrant';
|
|
48
|
+
/** Safe recovery classification; provider messages and credentials are never retained. */
|
|
49
|
+
constructor(reason?: 'unavailable' | 'temporary' | 'invalidGrant');
|
|
50
|
+
}
|
|
51
|
+
/** Acquires once from an application provider without adding storage or refresh policy. */
|
|
52
|
+
export declare function providerCredentials(provider: TokenProvider, binding: SecurityBinding, signal: AbortSignal): Promise<TokenLease>;
|
|
@@ -0,0 +1,102 @@
|
|
|
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 { RequestCancellationError, isRequestStopped, } from './request-cancellation-error.js';
|
|
15
|
+
/** Signals that an interactive application must supply a fresh authorization session. */
|
|
16
|
+
export class AuthorizationRequiredError extends RequestCancellationError {
|
|
17
|
+
constructor() {
|
|
18
|
+
super('Fresh application authorization is required');
|
|
19
|
+
this.name = 'AuthorizationRequiredError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
/** Safe provider failure without a provider's potentially credential-bearing error message. */
|
|
23
|
+
export class TokenProviderError extends Error {
|
|
24
|
+
reason;
|
|
25
|
+
/** Safe recovery classification; provider messages and credentials are never retained. */
|
|
26
|
+
constructor(reason = 'unavailable') {
|
|
27
|
+
super('The credential provider could not supply usable credentials');
|
|
28
|
+
this.reason = reason;
|
|
29
|
+
this.name = 'TokenProviderError';
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/** Acquires once from an application provider without adding storage or refresh policy. */
|
|
33
|
+
export async function providerCredentials(provider, binding, signal) {
|
|
34
|
+
signal.throwIfAborted();
|
|
35
|
+
try {
|
|
36
|
+
if (provider.credentials) {
|
|
37
|
+
const lease = await provider.credentials(binding, signal);
|
|
38
|
+
signal.throwIfAborted();
|
|
39
|
+
return {
|
|
40
|
+
...lease,
|
|
41
|
+
invalidate: lease.invalidate
|
|
42
|
+
? async () => {
|
|
43
|
+
try {
|
|
44
|
+
return await lease.invalidate();
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
throw safeProviderError(error);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
: undefined,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const configuration = provider.configure(binding);
|
|
54
|
+
if (!provider.identity.trim() || !configuration.clientIdentity.trim())
|
|
55
|
+
throw new TokenProviderError();
|
|
56
|
+
const request = Object.freeze({
|
|
57
|
+
...binding,
|
|
58
|
+
...Object.fromEntries(Object.entries(configuration.endpoints ?? {}).filter(([, value]) => value !== undefined)),
|
|
59
|
+
clientIdentity: configuration.clientIdentity,
|
|
60
|
+
grantIdentity: configuration.grantIdentity,
|
|
61
|
+
scopes: Object.freeze([...new Set(binding.scopes)].sort((left, right) => {
|
|
62
|
+
// Credential scope order must not depend on the host locale.
|
|
63
|
+
if (left === right)
|
|
64
|
+
return 0;
|
|
65
|
+
return left < right ? -1 : 1;
|
|
66
|
+
})),
|
|
67
|
+
transport: Object.freeze({ ...binding.transport }),
|
|
68
|
+
});
|
|
69
|
+
const tokens = Object.freeze({
|
|
70
|
+
...(await provider.acquire(request, signal)),
|
|
71
|
+
});
|
|
72
|
+
signal.throwIfAborted();
|
|
73
|
+
if (!tokens.accessToken ||
|
|
74
|
+
(tokens.expiresAt !== undefined &&
|
|
75
|
+
(!Number.isFinite(tokens.expiresAt) || tokens.expiresAt <= Date.now())))
|
|
76
|
+
throw new TokenProviderError();
|
|
77
|
+
return {
|
|
78
|
+
key: '',
|
|
79
|
+
tokens,
|
|
80
|
+
invalidate: async () => {
|
|
81
|
+
try {
|
|
82
|
+
return ((await provider.reject?.(request, tokens.accessToken)) ?? false);
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
throw safeProviderError(error);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
signal.throwIfAborted();
|
|
92
|
+
throw safeProviderError(error);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
function safeProviderError(error) {
|
|
96
|
+
return isRequestStopped(error) ||
|
|
97
|
+
error instanceof AuthorizationRequiredError ||
|
|
98
|
+
error instanceof TokenProviderError
|
|
99
|
+
? error
|
|
100
|
+
: new TokenProviderError();
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=token-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-provider.js","sourceRoot":"","sources":["../src/token-provider.ts"],"names":[],"mappings":"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"}
|
package/build/transport.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SecurityBinding } from './security-binding.js';
|
|
1
2
|
import { MediaType } from './media-type.js';
|
|
2
3
|
import { TextMediaTypeDecoder } from './media-type-codecs/media-type-decoder.js';
|
|
3
4
|
import { Problem } from './problem.js';
|
|
@@ -20,6 +21,8 @@ export interface Transport<NativeRequest = Request> {
|
|
|
20
21
|
}
|
|
21
22
|
export interface ExtEventSource extends EventSource {
|
|
22
23
|
connect(): void;
|
|
24
|
+
/** Stops the subscription and forwards an optional failure to upstream cleanup. */
|
|
25
|
+
close(reason?: unknown): void;
|
|
23
26
|
}
|
|
24
27
|
export type RequestMethod = 'GET' | 'PUT' | 'POST' | 'PATCH' | 'DELETE' | 'HEAD' | 'OPTIONS';
|
|
25
28
|
export interface RequestSpec<B> {
|
|
@@ -29,11 +32,15 @@ export interface RequestSpec<B> {
|
|
|
29
32
|
queryParameters?: Record<string, unknown>;
|
|
30
33
|
body?: B;
|
|
31
34
|
bodyType?: SchemaLike<B>;
|
|
35
|
+
/** Revalidates typed parameters on every request build, before wire conversion. */
|
|
36
|
+
parameterValidation?: () => void;
|
|
32
37
|
contentTypes?: MediaType[];
|
|
33
38
|
acceptTypes?: MediaType[];
|
|
39
|
+
/** Decode a successful response as raw bytes, independent of its media type. */
|
|
40
|
+
binaryResponse?: boolean;
|
|
34
41
|
headers?: Record<string, unknown>;
|
|
35
42
|
signal?: AbortSignal;
|
|
43
|
+
/** Complete, explicitly selected credential bindings for this operation. */
|
|
44
|
+
security?: readonly SecurityBinding[];
|
|
36
45
|
}
|
|
37
|
-
export
|
|
38
|
-
adapt(transport: Transport, request: Request): Promise<Request>;
|
|
39
|
-
}
|
|
46
|
+
export type { RequestAdapter } from './request-adapter.js';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
/** Marks a fallback independently of its discriminator or structural fields. */
|
|
3
|
+
export declare const UnknownVariantTag: unique symbol;
|
|
4
|
+
/** An unknown discriminated payload whose original wire fields are preserved. */
|
|
5
|
+
export interface UnknownVariant {
|
|
6
|
+
readonly [UnknownVariantTag]: true;
|
|
7
|
+
readonly rawBody: Readonly<Record<string, unknown>>;
|
|
8
|
+
}
|
|
9
|
+
/** Identifies fallback instances even when their discriminator resembles a known branch. */
|
|
10
|
+
export declare function isUnknownVariant(value: unknown): value is UnknownVariant;
|
|
11
|
+
/** Dispatches encoding by fallback identity while retaining native schema validation. */
|
|
12
|
+
export declare function unionWithUnknown<K extends z.ZodType, U extends z.ZodType<UnknownVariant>>(known: K, unknown: U): z.ZodType<z.output<K> | z.output<U>>;
|
|
@@ -0,0 +1,45 @@
|
|
|
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 { z } from 'zod';
|
|
15
|
+
/** Marks a fallback independently of its discriminator or structural fields. */
|
|
16
|
+
export const UnknownVariantTag = Symbol.for('@outfoxx/sunday/UnknownVariant');
|
|
17
|
+
/** Identifies fallback instances even when their discriminator resembles a known branch. */
|
|
18
|
+
export function isUnknownVariant(value) {
|
|
19
|
+
return typeof value === 'object' && value !== null
|
|
20
|
+
&& UnknownVariantTag in value && value[UnknownVariantTag] === true;
|
|
21
|
+
}
|
|
22
|
+
/** Dispatches encoding by fallback identity while retaining native schema validation. */
|
|
23
|
+
export function unionWithUnknown(known, unknown) {
|
|
24
|
+
const wire = z.union([known, unknown]);
|
|
25
|
+
return z.codec(z.unknown(), z.custom(), {
|
|
26
|
+
decode(value, context) {
|
|
27
|
+
const result = wire.safeParse(value);
|
|
28
|
+
if (!result.success) {
|
|
29
|
+
context.issues.push(...result.error.issues.map(issue => ({ ...issue, input: undefined })));
|
|
30
|
+
return z.NEVER;
|
|
31
|
+
}
|
|
32
|
+
return result.data;
|
|
33
|
+
},
|
|
34
|
+
encode(value, context) {
|
|
35
|
+
const schema = isUnknownVariant(value) ? unknown : known;
|
|
36
|
+
const result = schema.safeEncode(value);
|
|
37
|
+
if (!result.success) {
|
|
38
|
+
context.issues.push(...result.error.issues.map(issue => ({ ...issue, input: undefined })));
|
|
39
|
+
return z.NEVER;
|
|
40
|
+
}
|
|
41
|
+
return result.data;
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=unknown-variant.js.map
|