toolcraft 0.0.341 → 0.0.343
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/composition.json +3 -3
- package/dist/composition.json +3 -3
- package/node_modules/tiny-http-mcp-server/dist/composition.json +1 -1
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/README.md +19 -2
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/default-oauth-client-provider.js +25 -10
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/resource-bound-store.js +2 -0
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.js +6 -0
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.d.ts +1 -0
- package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/index.js +1 -0
- package/node_modules/tiny-http-mcp-server/package.json +1 -1
- package/node_modules/tiny-mcp-client/README.md +1 -1
- package/node_modules/tiny-mcp-client/dist/index.js +71 -33
- package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
- package/node_modules/toolcraft-schema/package.json +1 -1
- package/package.json +2 -2
package/composition.json
CHANGED
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"name": "tiny-http-mcp-server",
|
|
101
|
-
"version": "0.1.
|
|
101
|
+
"version": "0.1.68",
|
|
102
102
|
"license": "MIT"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
"name": "toolcraft",
|
|
116
|
-
"version": "0.0.
|
|
116
|
+
"version": "0.0.343",
|
|
117
117
|
"license": "MIT"
|
|
118
118
|
},
|
|
119
119
|
{
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
125
|
"name": "toolcraft-schema",
|
|
126
|
-
"version": "0.0.
|
|
126
|
+
"version": "0.0.343",
|
|
127
127
|
"license": "MIT"
|
|
128
128
|
},
|
|
129
129
|
{
|
package/dist/composition.json
CHANGED
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"name": "tiny-http-mcp-server",
|
|
101
|
-
"version": "0.1.
|
|
101
|
+
"version": "0.1.68",
|
|
102
102
|
"license": "MIT"
|
|
103
103
|
},
|
|
104
104
|
{
|
|
@@ -113,7 +113,7 @@
|
|
|
113
113
|
},
|
|
114
114
|
{
|
|
115
115
|
"name": "toolcraft",
|
|
116
|
-
"version": "0.0.
|
|
116
|
+
"version": "0.0.343",
|
|
117
117
|
"license": "MIT"
|
|
118
118
|
},
|
|
119
119
|
{
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
},
|
|
124
124
|
{
|
|
125
125
|
"name": "toolcraft-schema",
|
|
126
|
-
"version": "0.0.
|
|
126
|
+
"version": "0.0.343",
|
|
127
127
|
"license": "MIT"
|
|
128
128
|
},
|
|
129
129
|
{
|
|
@@ -31,6 +31,7 @@ const verifier = createJwksTokenVerifier({
|
|
|
31
31
|
- `generateCodeVerifier()` and `generateCodeChallenge(...)`: PKCE helpers.
|
|
32
32
|
- `normalizeStoredOAuthClient(value)`: normalize a saved client identity, full registration and ownership marker.
|
|
33
33
|
- `normalizeOAuthScope(value)`: validate scope syntax and normalize its case-sensitive set.
|
|
34
|
+
- `waitForOAuthOperation(promise, signal?)`: settle the caller on cancellation while continuing to observe host completion.
|
|
34
35
|
- `canonicalizeResourceIndicator(value)`: resource indicator canonicalization.
|
|
35
36
|
- `createJwksTokenVerifier(options)`: JWKS-backed access-token verifier for MCP servers.
|
|
36
37
|
- `OAuthError`: OAuth HTTP error type with status, retryability and known-outcome fields.
|
|
@@ -94,6 +95,14 @@ accept the same `redirectUri`, `signal` and `timeoutMs` options. Cancellation,
|
|
|
94
95
|
timeout and explicit close settle pending code waits and release listeners.
|
|
95
96
|
Always close a successful standalone session in `finally`.
|
|
96
97
|
|
|
98
|
+
Native provider calls capture request option handles before host work. Unauthorized
|
|
99
|
+
handling also owns complete discovery metadata, presented grant values, rejected
|
|
100
|
+
request headers and the selected challenge error before reading persistence.
|
|
101
|
+
A browser callback cannot redirect a later code exchange by changing caller
|
|
102
|
+
metadata. Metadata loaded from a host session store is copied before clock or
|
|
103
|
+
fetch callbacks, retaining the original refresh endpoint and persisted extensions. Explicit authentication owns metadata when lazy discovery returns;
|
|
104
|
+
the selected discovery method retains its original receiver and live host state.
|
|
105
|
+
|
|
97
106
|
Provider request inputs accept an optional `signal`. It reaches callback waits,
|
|
98
107
|
registration, token requests and bounded token-body reads. Cancellation retains
|
|
99
108
|
its original reason and does not retry authorization. Native provider calls
|
|
@@ -126,7 +135,11 @@ timeoutMs })`. Reset acquires the raw identity backend lock, so it can recover
|
|
|
126
135
|
corrupt or undecryptable records without reading their old contents. It atomically
|
|
127
136
|
retires the identity's grant and registrations and writes a marker that suppresses
|
|
128
137
|
stale initial grants. The default lock wait is 30 seconds. Other names/profiles
|
|
129
|
-
are untouched, and symlink paths are still refused.
|
|
138
|
+
are untouched, and symlink paths are still refused. Native reset, import and
|
|
139
|
+
transaction callbacks retain their original signal while locks or reconciliation
|
|
140
|
+
wait; replacing a caller handle cannot change subsequent cancellation checks.
|
|
141
|
+
Cancellation after a completed identity write prevents the transaction callback
|
|
142
|
+
from running and retains that already persisted identity.
|
|
130
143
|
|
|
131
144
|
Configure `client.metadata.scope` to request a precise scope set; broader
|
|
132
145
|
discovery metadata does not override it. Explicit scopes must match the cached
|
|
@@ -256,7 +269,11 @@ transient retry or restoration of the original grant. Gateway error pages do not
|
|
|
256
269
|
Native persisted OAuth reads always reject corrupt encrypted documents and
|
|
257
270
|
invalid stored JSON, with diagnostics that omit decrypted contents. They retain
|
|
258
271
|
the existing record for explicit reset rather than interpreting corruption as
|
|
259
|
-
an absent session and reviving an initial grant.
|
|
272
|
+
an absent session and reviving an initial grant. Persisted access tokens that
|
|
273
|
+
cannot be sent as HTTP headers fail with diagnostics that omit token contents;
|
|
274
|
+
the original record remains available for explicit recovery. Token responses are
|
|
275
|
+
checked before activation or persistence. An unusable rotated access token keeps
|
|
276
|
+
refresh intent pending, preventing rotating-token replay. Caller file-backend settings
|
|
260
277
|
cannot disable this policy.
|
|
261
278
|
|
|
262
279
|
## Environment Variables
|
|
@@ -73,6 +73,7 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
73
73
|
let initialGrantConsumed = false;
|
|
74
74
|
return {
|
|
75
75
|
async authenticate(input) {
|
|
76
|
+
input = { ...input, ...(input.discover === undefined ? {} : { discover: input.discover.bind(input) }) };
|
|
76
77
|
input.signal?.throwIfAborted();
|
|
77
78
|
assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
|
|
78
79
|
const resource = canonicalizeResourceIndicator(input.requestUrl);
|
|
@@ -84,7 +85,7 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
84
85
|
return { ...initialGrant.tokens };
|
|
85
86
|
if (input.discover === undefined)
|
|
86
87
|
return;
|
|
87
|
-
const discovery = await waitForOAuthOperation(input.discover(), input.signal);
|
|
88
|
+
const discovery = structuredClone(await waitForOAuthOperation(input.discover(), input.signal));
|
|
88
89
|
input.signal?.throwIfAborted();
|
|
89
90
|
assertRequestMatchesResource(resource, canonicalizeResourceIndicator(discovery.resource));
|
|
90
91
|
session = await ensureAuthorizedSession(resource, discovery, input.fetch, true, false, input.signal);
|
|
@@ -93,6 +94,7 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
93
94
|
return { ...session.tokens };
|
|
94
95
|
},
|
|
95
96
|
async authorizeRequest(input) {
|
|
97
|
+
input = { ...input };
|
|
96
98
|
assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
|
|
97
99
|
const requestUrl = canonicalizeResourceIndicator(input.requestUrl);
|
|
98
100
|
const session = await ensureAuthorizedSession(requestUrl, undefined, input.fetch, false, false, input.signal);
|
|
@@ -113,8 +115,16 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
113
115
|
return { ...session.tokens };
|
|
114
116
|
},
|
|
115
117
|
async handleUnauthorized(input) {
|
|
118
|
+
input = { ...input };
|
|
116
119
|
try {
|
|
117
120
|
input.signal?.throwIfAborted();
|
|
121
|
+
const presented = input.presentedTokens == null ? input.presentedTokens : normalizeStoredTokens(input.presentedTokens);
|
|
122
|
+
if (input.presentedTokens != null && presented === undefined)
|
|
123
|
+
throw new Error("OAuth rejected-request provenance does not match its authorization header");
|
|
124
|
+
const challengeError = input.challenge?.params.error;
|
|
125
|
+
input = { ...input, discovery: structuredClone(input.discovery),
|
|
126
|
+
...(input.requestHeaders === undefined ? {} : { requestHeaders: new Headers(input.requestHeaders) }),
|
|
127
|
+
...(presented === undefined ? {} : { presentedTokens: presented }) };
|
|
118
128
|
assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
|
|
119
129
|
const requestUrl = canonicalizeResourceIndicator(input.requestUrl);
|
|
120
130
|
const resource = canonicalizeResourceIndicator(input.discovery.resource);
|
|
@@ -126,16 +136,15 @@ export function createDefaultOAuthClientProvider(options) {
|
|
|
126
136
|
if (input.presentedTokens !== undefined) {
|
|
127
137
|
rejectedCurrentGrant = false;
|
|
128
138
|
if (input.presentedTokens !== null) {
|
|
129
|
-
const presented =
|
|
139
|
+
const presented = input.presentedTokens;
|
|
130
140
|
const header = input.requestHeaders?.get("Authorization") ?? "";
|
|
131
141
|
const separator = header.indexOf(" ");
|
|
132
|
-
if (
|
|
142
|
+
if (header.slice(0, separator).toLowerCase() !== "bearer" || header.slice(separator + 1).trim() !== presented.accessToken)
|
|
133
143
|
throw new Error("OAuth rejected-request provenance does not match its authorization header");
|
|
134
144
|
presentedTokens = presented;
|
|
135
145
|
rejectedCurrentGrant = currentTokens !== undefined && sameTokenGrant(currentTokens, presented);
|
|
136
146
|
}
|
|
137
147
|
}
|
|
138
|
-
const challengeError = input.challenge?.params.error;
|
|
139
148
|
const forceRefresh = rejectedCurrentGrant && (challengeError === "invalid_token" || (input.presentedTokens !== undefined && challengeError === undefined));
|
|
140
149
|
const session = await ensureAuthorizedSession(resource, {
|
|
141
150
|
...input.discovery,
|
|
@@ -584,18 +593,24 @@ function normalizeLoadedSession(session) {
|
|
|
584
593
|
if (session === null) {
|
|
585
594
|
return null;
|
|
586
595
|
}
|
|
596
|
+
const discovery = structuredClone(session.discovery);
|
|
587
597
|
const refreshState = getOwnEntry(session, "refreshState");
|
|
588
598
|
if (refreshState !== undefined && (refreshState !== "pending" || getOwnEntry(session, "tokens") !== undefined))
|
|
589
599
|
throw new Error("Stored OAuth refresh state is invalid");
|
|
590
600
|
const client = normalizeStoredOAuthClient(getOwnEntry(session, "client"));
|
|
591
601
|
if (client === null) {
|
|
592
|
-
return { ...session, client: { clientId: "" }, tokens: undefined };
|
|
602
|
+
return { ...session, discovery, client: { clientId: "" }, tokens: undefined };
|
|
593
603
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
604
|
+
const tokens = normalizeStoredTokens(getOwnEntry(session, "tokens"));
|
|
605
|
+
if (tokens !== undefined) {
|
|
606
|
+
try {
|
|
607
|
+
new Headers({ Authorization: `Bearer ${tokens.accessToken}` });
|
|
608
|
+
}
|
|
609
|
+
catch {
|
|
610
|
+
throw new Error("Stored OAuth access token is not a valid HTTP header value");
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return { ...session, discovery, client, tokens };
|
|
599
614
|
}
|
|
600
615
|
function normalizeImportedTokens(value, now) {
|
|
601
616
|
if (!isObjectRecord(value))
|
package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/resource-bound-store.js
CHANGED
|
@@ -51,6 +51,7 @@ export function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
51
51
|
}
|
|
52
52
|
};
|
|
53
53
|
async function replace(record, options) {
|
|
54
|
+
options = { ...options };
|
|
54
55
|
options.signal?.throwIfAborted();
|
|
55
56
|
const timeoutMs = options.timeoutMs ?? 30_000;
|
|
56
57
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2_147_483_647)
|
|
@@ -124,6 +125,7 @@ export function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
124
125
|
}
|
|
125
126
|
result.sessionStore = {
|
|
126
127
|
async withLock(resource, operation, options) {
|
|
128
|
+
options = { ...options };
|
|
127
129
|
if (store.withLock === undefined)
|
|
128
130
|
throw new Error("OAuth resource identity backend must support transaction locks");
|
|
129
131
|
return store.withLock(async () => {
|
package/node_modules/tiny-http-mcp-server/node_modules/mcp-oauth/dist/client/token-endpoint.js
CHANGED
|
@@ -105,6 +105,12 @@ async function requestTokens(input) {
|
|
|
105
105
|
throw new Error("OAuth token response missing access_token");
|
|
106
106
|
}
|
|
107
107
|
const normalizedAccessToken = accessToken.trim();
|
|
108
|
+
try {
|
|
109
|
+
new Headers({ Authorization: `Bearer ${normalizedAccessToken}` });
|
|
110
|
+
}
|
|
111
|
+
catch {
|
|
112
|
+
throw new Error("OAuth token response access_token is not a valid HTTP header value");
|
|
113
|
+
}
|
|
108
114
|
const tokenType = normalizeBearerTokenType(getOwnEntry(payload, "token_type"));
|
|
109
115
|
if (tokenType === null) {
|
|
110
116
|
throw new Error("OAuth token response missing token_type=Bearer");
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { normalizeOAuthScope } from "./client/scope.js";
|
|
2
|
+
export { waitForOAuthOperation } from "./client/cancellable-operation.js";
|
|
2
3
|
export { parseOAuthTokenGrant } from "./client/token-grant.js";
|
|
3
4
|
export type { OAuthTokenGrantImportOptions } from "./client/token-grant.js";
|
|
4
5
|
export { createAuthStoreSessionStore, } from "./client/auth-store-session-store.js";
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { normalizeOAuthScope } from "./client/scope.js";
|
|
2
|
+
export { waitForOAuthOperation } from "./client/cancellable-operation.js";
|
|
2
3
|
export { parseOAuthTokenGrant } from "./client/token-grant.js";
|
|
3
4
|
export { createAuthStoreSessionStore, } from "./client/auth-store-session-store.js";
|
|
4
5
|
export { createResourceBoundOAuthStores } from "./client/resource-bound-store.js";
|
|
@@ -101,7 +101,7 @@ const transport = new HttpTransport({
|
|
|
101
101
|
});
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
-
You can also call `discoverOAuthMetadata(resourceUrl, options)` directly, or instantiate `OAuthMetadataDiscovery` with a custom `fetch` implementation and shared cache. Lookup options accept `signal`; cancellation stops metadata fetches and body reads without trying another discovery candidate.
|
|
104
|
+
You can also call `discoverOAuthMetadata(resourceUrl, options)` directly, or instantiate `OAuthMetadataDiscovery` with a custom `fetch` implementation and shared cache. An explicit `resourceMetadataUrl` requires fresh network discovery without reading either cache; validated results still populate both caches. Lookup options accept `signal`; cancellation stops metadata fetches and body reads without trying another discovery candidate. It also settles while shared-cache reads, writes or eviction wait. Host cache work may finish afterward; its late rejection remains observed, and canceled discovery does not start another candidate.
|
|
105
105
|
|
|
106
106
|
OAuth provider inputs receive the originating request's `signal`, covering header authorization and unauthorized handling. Modern request cancellation stops its OAuth work while leaving other requests usable; transport disposal cancels all pending OAuth operations. The default provider propagates this signal to callback, registration and token work. Custom providers must observe it for their own operations.
|
|
107
107
|
|
|
@@ -3405,6 +3405,24 @@ function normalizeOAuthScope(scope) {
|
|
|
3405
3405
|
return normalized || void 0;
|
|
3406
3406
|
}
|
|
3407
3407
|
|
|
3408
|
+
// ../mcp-oauth/dist/client/cancellable-operation.js
|
|
3409
|
+
async function waitForOAuthOperation(operation, signal) {
|
|
3410
|
+
if (signal === void 0)
|
|
3411
|
+
return operation;
|
|
3412
|
+
let abort;
|
|
3413
|
+
try {
|
|
3414
|
+
return await new Promise((resolve, reject) => {
|
|
3415
|
+
abort = () => reject(signal.reason);
|
|
3416
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
3417
|
+
operation.then(resolve, reject);
|
|
3418
|
+
if (signal.aborted)
|
|
3419
|
+
abort();
|
|
3420
|
+
});
|
|
3421
|
+
} finally {
|
|
3422
|
+
signal.removeEventListener("abort", abort);
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
|
|
3408
3426
|
// ../mcp-oauth/dist/client/bounded-json.js
|
|
3409
3427
|
function copyBoundedOAuthJson(value, message) {
|
|
3410
3428
|
const invalid = () => new Error(message);
|
|
@@ -4793,6 +4811,7 @@ function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
4793
4811
|
}
|
|
4794
4812
|
};
|
|
4795
4813
|
async function replace(record2, options2) {
|
|
4814
|
+
options2 = { ...options2 };
|
|
4796
4815
|
options2.signal?.throwIfAborted();
|
|
4797
4816
|
const timeoutMs = options2.timeoutMs ?? 3e4;
|
|
4798
4817
|
if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647)
|
|
@@ -4858,6 +4877,7 @@ function createResourceBoundOAuthStores(options, namespace, identity) {
|
|
|
4858
4877
|
}
|
|
4859
4878
|
result.sessionStore = {
|
|
4860
4879
|
async withLock(resource, operation, options2) {
|
|
4880
|
+
options2 = { ...options2 };
|
|
4861
4881
|
if (store.withLock === void 0)
|
|
4862
4882
|
throw new Error("OAuth resource identity backend must support transaction locks");
|
|
4863
4883
|
return store.withLock(async () => {
|
|
@@ -5114,6 +5134,11 @@ async function requestTokens(input) {
|
|
|
5114
5134
|
throw new Error("OAuth token response missing access_token");
|
|
5115
5135
|
}
|
|
5116
5136
|
const normalizedAccessToken = accessToken.trim();
|
|
5137
|
+
try {
|
|
5138
|
+
new Headers({ Authorization: `Bearer ${normalizedAccessToken}` });
|
|
5139
|
+
} catch {
|
|
5140
|
+
throw new Error("OAuth token response access_token is not a valid HTTP header value");
|
|
5141
|
+
}
|
|
5117
5142
|
const tokenType = normalizeBearerTokenType(getOwnEntry5(payload, "token_type"));
|
|
5118
5143
|
if (tokenType === null) {
|
|
5119
5144
|
throw new Error("OAuth token response missing token_type=Bearer");
|
|
@@ -5197,24 +5222,6 @@ function normalizeBearerTokenType(value) {
|
|
|
5197
5222
|
return value.toLowerCase() === "bearer" ? "Bearer" : null;
|
|
5198
5223
|
}
|
|
5199
5224
|
|
|
5200
|
-
// ../mcp-oauth/dist/client/cancellable-operation.js
|
|
5201
|
-
async function waitForOAuthOperation(operation, signal) {
|
|
5202
|
-
if (signal === void 0)
|
|
5203
|
-
return operation;
|
|
5204
|
-
let abort;
|
|
5205
|
-
try {
|
|
5206
|
-
return await new Promise((resolve, reject) => {
|
|
5207
|
-
abort = () => reject(signal.reason);
|
|
5208
|
-
signal.addEventListener("abort", abort, { once: true });
|
|
5209
|
-
operation.then(resolve, reject);
|
|
5210
|
-
if (signal.aborted)
|
|
5211
|
-
abort();
|
|
5212
|
-
});
|
|
5213
|
-
} finally {
|
|
5214
|
-
signal.removeEventListener("abort", abort);
|
|
5215
|
-
}
|
|
5216
|
-
}
|
|
5217
|
-
|
|
5218
5225
|
// ../mcp-oauth/dist/client/session-transaction.js
|
|
5219
5226
|
var queues = /* @__PURE__ */ new WeakMap();
|
|
5220
5227
|
async function withOAuthSessionTransaction(store, resource, operation, options = {}) {
|
|
@@ -5328,6 +5335,7 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
5328
5335
|
let initialGrantConsumed = false;
|
|
5329
5336
|
return {
|
|
5330
5337
|
async authenticate(input) {
|
|
5338
|
+
input = { ...input, ...input.discover === void 0 ? {} : { discover: input.discover.bind(input) } };
|
|
5331
5339
|
input.signal?.throwIfAborted();
|
|
5332
5340
|
assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
|
|
5333
5341
|
const resource = canonicalizeResourceIndicator(input.requestUrl);
|
|
@@ -5338,7 +5346,7 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
5338
5346
|
return { ...initialGrant.tokens };
|
|
5339
5347
|
if (input.discover === void 0)
|
|
5340
5348
|
return;
|
|
5341
|
-
const discovery = await waitForOAuthOperation(input.discover(), input.signal);
|
|
5349
|
+
const discovery = structuredClone(await waitForOAuthOperation(input.discover(), input.signal));
|
|
5342
5350
|
input.signal?.throwIfAborted();
|
|
5343
5351
|
assertRequestMatchesResource(resource, canonicalizeResourceIndicator(discovery.resource));
|
|
5344
5352
|
session = await ensureAuthorizedSession(resource, discovery, input.fetch, true, false, input.signal);
|
|
@@ -5347,6 +5355,7 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
5347
5355
|
return { ...session.tokens };
|
|
5348
5356
|
},
|
|
5349
5357
|
async authorizeRequest(input) {
|
|
5358
|
+
input = { ...input };
|
|
5350
5359
|
assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
|
|
5351
5360
|
const requestUrl = canonicalizeResourceIndicator(input.requestUrl);
|
|
5352
5361
|
const session = await ensureAuthorizedSession(requestUrl, void 0, input.fetch, false, false, input.signal);
|
|
@@ -5363,8 +5372,19 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
5363
5372
|
return { ...session.tokens };
|
|
5364
5373
|
},
|
|
5365
5374
|
async handleUnauthorized(input) {
|
|
5375
|
+
input = { ...input };
|
|
5366
5376
|
try {
|
|
5367
5377
|
input.signal?.throwIfAborted();
|
|
5378
|
+
const presented = input.presentedTokens == null ? input.presentedTokens : normalizeStoredTokens(input.presentedTokens);
|
|
5379
|
+
if (input.presentedTokens != null && presented === void 0)
|
|
5380
|
+
throw new Error("OAuth rejected-request provenance does not match its authorization header");
|
|
5381
|
+
const challengeError = input.challenge?.params.error;
|
|
5382
|
+
input = {
|
|
5383
|
+
...input,
|
|
5384
|
+
discovery: structuredClone(input.discovery),
|
|
5385
|
+
...input.requestHeaders === void 0 ? {} : { requestHeaders: new Headers(input.requestHeaders) },
|
|
5386
|
+
...presented === void 0 ? {} : { presentedTokens: presented }
|
|
5387
|
+
};
|
|
5368
5388
|
assertNoAccessTokenInUrl(input.requestUrl, "Protected resource request URL");
|
|
5369
5389
|
const requestUrl = canonicalizeResourceIndicator(input.requestUrl);
|
|
5370
5390
|
const resource = canonicalizeResourceIndicator(input.discovery.resource);
|
|
@@ -5376,16 +5396,15 @@ function createDefaultOAuthClientProvider(options) {
|
|
|
5376
5396
|
if (input.presentedTokens !== void 0) {
|
|
5377
5397
|
rejectedCurrentGrant = false;
|
|
5378
5398
|
if (input.presentedTokens !== null) {
|
|
5379
|
-
const
|
|
5399
|
+
const presented2 = input.presentedTokens;
|
|
5380
5400
|
const header = input.requestHeaders?.get("Authorization") ?? "";
|
|
5381
5401
|
const separator = header.indexOf(" ");
|
|
5382
|
-
if (
|
|
5402
|
+
if (header.slice(0, separator).toLowerCase() !== "bearer" || header.slice(separator + 1).trim() !== presented2.accessToken)
|
|
5383
5403
|
throw new Error("OAuth rejected-request provenance does not match its authorization header");
|
|
5384
|
-
presentedTokens =
|
|
5385
|
-
rejectedCurrentGrant = currentTokens !== void 0 && sameTokenGrant(currentTokens,
|
|
5404
|
+
presentedTokens = presented2;
|
|
5405
|
+
rejectedCurrentGrant = currentTokens !== void 0 && sameTokenGrant(currentTokens, presented2);
|
|
5386
5406
|
}
|
|
5387
5407
|
}
|
|
5388
|
-
const challengeError = input.challenge?.params.error;
|
|
5389
5408
|
const forceRefresh = rejectedCurrentGrant && (challengeError === "invalid_token" || input.presentedTokens !== void 0 && challengeError === void 0);
|
|
5390
5409
|
const session = await ensureAuthorizedSession(resource, {
|
|
5391
5410
|
...input.discovery,
|
|
@@ -5818,18 +5837,23 @@ function normalizeLoadedSession(session) {
|
|
|
5818
5837
|
if (session === null) {
|
|
5819
5838
|
return null;
|
|
5820
5839
|
}
|
|
5840
|
+
const discovery = structuredClone(session.discovery);
|
|
5821
5841
|
const refreshState = getOwnEntry6(session, "refreshState");
|
|
5822
5842
|
if (refreshState !== void 0 && (refreshState !== "pending" || getOwnEntry6(session, "tokens") !== void 0))
|
|
5823
5843
|
throw new Error("Stored OAuth refresh state is invalid");
|
|
5824
5844
|
const client = normalizeStoredOAuthClient(getOwnEntry6(session, "client"));
|
|
5825
5845
|
if (client === null) {
|
|
5826
|
-
return { ...session, client: { clientId: "" }, tokens: void 0 };
|
|
5846
|
+
return { ...session, discovery, client: { clientId: "" }, tokens: void 0 };
|
|
5827
5847
|
}
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
|
|
5831
|
-
|
|
5832
|
-
|
|
5848
|
+
const tokens = normalizeStoredTokens(getOwnEntry6(session, "tokens"));
|
|
5849
|
+
if (tokens !== void 0) {
|
|
5850
|
+
try {
|
|
5851
|
+
new Headers({ Authorization: `Bearer ${tokens.accessToken}` });
|
|
5852
|
+
} catch {
|
|
5853
|
+
throw new Error("Stored OAuth access token is not a valid HTTP header value");
|
|
5854
|
+
}
|
|
5855
|
+
}
|
|
5856
|
+
return { ...session, discovery, client, tokens };
|
|
5833
5857
|
}
|
|
5834
5858
|
function normalizeImportedTokens(value, now) {
|
|
5835
5859
|
if (!isObjectRecord3(value))
|
|
@@ -6400,6 +6424,20 @@ function validateCachedDiscovery(value, resource) {
|
|
|
6400
6424
|
authorizationServerMetadata
|
|
6401
6425
|
});
|
|
6402
6426
|
}
|
|
6427
|
+
async function waitForCache(operation, signal) {
|
|
6428
|
+
if (signal === void 0) return operation;
|
|
6429
|
+
let abort;
|
|
6430
|
+
try {
|
|
6431
|
+
return await new Promise((resolve, reject) => {
|
|
6432
|
+
abort = () => reject(signal.reason);
|
|
6433
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
6434
|
+
Promise.resolve(operation).then(resolve, reject);
|
|
6435
|
+
if (signal.aborted) abort();
|
|
6436
|
+
});
|
|
6437
|
+
} finally {
|
|
6438
|
+
signal.removeEventListener("abort", abort);
|
|
6439
|
+
}
|
|
6440
|
+
}
|
|
6403
6441
|
var OAuthMetadataDiscovery = class {
|
|
6404
6442
|
fetchImpl;
|
|
6405
6443
|
cache;
|
|
@@ -6436,7 +6474,7 @@ var OAuthMetadataDiscovery = class {
|
|
|
6436
6474
|
if (memoryCachedResult !== void 0 && resourceMetadataUrl === void 0) {
|
|
6437
6475
|
return structuredClone(memoryCachedResult);
|
|
6438
6476
|
}
|
|
6439
|
-
const sharedCachedResult = await this.cache?.get(cacheKey);
|
|
6477
|
+
const sharedCachedResult = resourceMetadataUrl === void 0 ? await waitForCache(this.cache?.get(cacheKey), signal) : void 0;
|
|
6440
6478
|
signal?.throwIfAborted();
|
|
6441
6479
|
if (sharedCachedResult !== null && sharedCachedResult !== void 0 && resourceMetadataUrl === void 0) {
|
|
6442
6480
|
try {
|
|
@@ -6444,7 +6482,7 @@ var OAuthMetadataDiscovery = class {
|
|
|
6444
6482
|
this.memoryCache.set(cacheKey, structuredClone(result));
|
|
6445
6483
|
return result;
|
|
6446
6484
|
} catch {
|
|
6447
|
-
await this.cache?.delete?.(cacheKey);
|
|
6485
|
+
await waitForCache(this.cache?.delete?.(cacheKey), signal);
|
|
6448
6486
|
}
|
|
6449
6487
|
}
|
|
6450
6488
|
const { location: resourceMetadataLocation, metadata: resourceMetadata } = await this.discoverProtectedResource(cacheKey, resourceMetadataUrl, signal);
|
|
@@ -6467,7 +6505,7 @@ var OAuthMetadataDiscovery = class {
|
|
|
6467
6505
|
authorizationServerMetadata
|
|
6468
6506
|
};
|
|
6469
6507
|
this.memoryCache.set(cacheKey, structuredClone(result));
|
|
6470
|
-
await this.cache?.set(cacheKey, structuredClone(result));
|
|
6508
|
+
await waitForCache(this.cache?.set(cacheKey, structuredClone(result)), signal);
|
|
6471
6509
|
return result;
|
|
6472
6510
|
} catch (error) {
|
|
6473
6511
|
signal?.throwIfAborted();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.343",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -158,7 +158,7 @@
|
|
|
158
158
|
"yaml"
|
|
159
159
|
],
|
|
160
160
|
"optionalDependencies": {
|
|
161
|
-
"toolcraft-schema": "0.0.
|
|
161
|
+
"toolcraft-schema": "0.0.343",
|
|
162
162
|
"toolcraft-design": "*",
|
|
163
163
|
"@poe-code/frontmatter": "*",
|
|
164
164
|
"@poe-code/agent-mcp-config": "*",
|