@poe-platform/safe-js 0.1.807 → 0.1.809

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.
@@ -5145,11 +5145,25 @@ function normalizeBearerTokenType(value) {
5145
5145
 
5146
5146
  // packages/mcp-oauth/src/client/register-client.ts
5147
5147
  async function registerOAuthClient(input) {
5148
- if (new URL(input.redirectUri).protocol === "https:") validateHostedOAuthRedirect(input.redirectUri);
5149
- else loopbackTarget({ redirectUri: input.redirectUri });
5148
+ if (input.redirectUri !== void 0 && input.redirectUris !== void 0)
5149
+ throw new Error("Specify either redirectUri or redirectUris, not both");
5150
+ const redirects = input.redirectUris === void 0 ? [input.redirectUri] : input.redirectUris;
5151
+ if (!Array.isArray(redirects) || redirects.length === 0 || redirects.length > 32)
5152
+ throw new Error("OAuth registration requires one to 32 redirect URIs");
5153
+ const redirectUris = [];
5154
+ const seen = /* @__PURE__ */ new Set();
5155
+ for (const redirectUri of redirects) {
5156
+ if (typeof redirectUri !== "string" || redirectUri.length === 0)
5157
+ throw new Error("Invalid OAuth registration redirect URI");
5158
+ if (seen.has(redirectUri)) throw new Error("Duplicate OAuth registration redirect URI");
5159
+ if (new URL(redirectUri).protocol === "https:") validateHostedOAuthRedirect(redirectUri);
5160
+ else loopbackTarget({ redirectUri });
5161
+ seen.add(redirectUri);
5162
+ redirectUris.push(redirectUri);
5163
+ }
5150
5164
  const body = JSON.stringify(buildClientRegistrationBody(
5151
5165
  input.metadata,
5152
- input.redirectUri,
5166
+ redirectUris,
5153
5167
  normalizeOAuthTokenEndpointAuthMethod(input.tokenEndpointAuthMethod) ?? "none"
5154
5168
  ));
5155
5169
  if (new TextEncoder().encode(body).byteLength > 65536) throw new Error("OAuth registration request is too large");
@@ -5168,9 +5182,9 @@ function getOwnString2(input, key2) {
5168
5182
  const descriptor = Object.getOwnPropertyDescriptor(input, key2);
5169
5183
  return descriptor !== void 0 && "value" in descriptor && typeof descriptor.value === "string" ? descriptor.value : void 0;
5170
5184
  }
5171
- function buildClientRegistrationBody(metadata, redirectUri, tokenEndpointAuthMethod) {
5185
+ function buildClientRegistrationBody(metadata, redirectUris, tokenEndpointAuthMethod) {
5172
5186
  const body = {
5173
- redirect_uris: [redirectUri],
5187
+ redirect_uris: redirectUris,
5174
5188
  grant_types: ["authorization_code", "refresh_token"],
5175
5189
  response_types: ["code"],
5176
5190
  token_endpoint_auth_method: tokenEndpointAuthMethod
@@ -6576,19 +6590,38 @@ function createParameterHeaders(definitions, argumentsValue) {
6576
6590
  // packages/tiny-mcp-client/src/oauth-discovery.ts
6577
6591
  var metadataErrorBrand = /* @__PURE__ */ Symbol.for("poe-platform.tiny-mcp-client.OAuthMetadataError");
6578
6592
  var OAuthMetadataError = class extends Error {
6579
- constructor(phase, message, status) {
6593
+ constructor(phase, message, status, reason = status === void 0 ? "invalid-metadata" : "http-error", failures = []) {
6580
6594
  super(message);
6581
6595
  this.phase = phase;
6582
6596
  this.status = status;
6597
+ this.reason = reason;
6598
+ this.failures = failures;
6583
6599
  this.name = "OAuthMetadataError";
6600
+ this.category = reason === "invalid-json" ? "json" : reason === "http-error" ? "http" : reason === "network-error" ? "network" : "validation";
6584
6601
  Object.defineProperty(this, metadataErrorBrand, { value: true });
6585
6602
  }
6586
6603
  phase;
6587
6604
  status;
6605
+ reason;
6606
+ failures;
6588
6607
  static is(value) {
6589
6608
  return value instanceof Error && Object.getOwnPropertyDescriptor(value, metadataErrorBrand)?.value === true;
6590
6609
  }
6610
+ category;
6591
6611
  };
6612
+ function metadataFailure(error, phase, reason) {
6613
+ return OAuthMetadataError.is(error) ? error : new OAuthMetadataError(
6614
+ phase,
6615
+ error instanceof Error ? error.message : String(error),
6616
+ void 0,
6617
+ reason
6618
+ );
6619
+ }
6620
+ function aggregateMetadataFailures(phase, errors2, message) {
6621
+ const primary = errors2.find((error) => error.category === "validation") ?? errors2[0];
6622
+ const failures = errors2.map(({ phase: phase2, category, reason, status }) => Object.freeze({ phase: phase2, category, reason, status }));
6623
+ return new OAuthMetadataError(phase, message, primary.status, primary.reason, Object.freeze(failures));
6624
+ }
6592
6625
  function defaultOAuthMetadataFetch(input, init) {
6593
6626
  return fetch(input, init);
6594
6627
  }
@@ -6654,14 +6687,16 @@ function validateAuthorizationServerMetadata(value, issuer) {
6654
6687
  if (value.issuer !== issuer) {
6655
6688
  throw new OAuthMetadataError(
6656
6689
  "authorization-server",
6657
- `Authorization server metadata issuer mismatch: expected ${issuer}, received ${value.issuer}`
6690
+ `Authorization server metadata issuer mismatch: expected ${issuer}, received ${value.issuer}`,
6691
+ void 0,
6692
+ "issuer-mismatch"
6658
6693
  );
6659
6694
  }
6660
6695
  if (typeof value.authorization_endpoint !== "string" || value.authorization_endpoint.length === 0) {
6661
- throw new Error("Authorization server metadata must include authorization_endpoint");
6696
+ throw new OAuthMetadataError("authorization-server", "Authorization server metadata must include authorization_endpoint", void 0, "invalid-endpoint");
6662
6697
  }
6663
6698
  if (typeof value.token_endpoint !== "string" || value.token_endpoint.length === 0) {
6664
- throw new Error("Authorization server metadata must include token_endpoint");
6699
+ throw new OAuthMetadataError("authorization-server", "Authorization server metadata must include token_endpoint", void 0, "invalid-endpoint");
6665
6700
  }
6666
6701
  for (const field of ["authorization_endpoint", "token_endpoint", "registration_endpoint"]) {
6667
6702
  if (field === "registration_endpoint" && value[field] === void 0) {
@@ -6673,19 +6708,25 @@ function validateAuthorizationServerMetadata(value, issuer) {
6673
6708
  throw new Error();
6674
6709
  }
6675
6710
  endpoint = new URL(value[field]);
6676
- } catch {
6677
- throw new Error(`Authorization server metadata ${field} must be an absolute URL`);
6711
+ assertSecureUrl2(endpoint, `Authorization server metadata ${field}`);
6712
+ } catch (error) {
6713
+ throw new OAuthMetadataError("authorization-server", `Authorization server metadata ${field} must be an absolute URL: ${error instanceof Error ? error.message : "invalid URL"}`, void 0, "invalid-endpoint");
6678
6714
  }
6679
- assertSecureUrl2(endpoint, `Authorization server metadata ${field}`);
6680
6715
  }
6681
6716
  if (!isStringArray(value.response_types_supported) || !value.response_types_supported.includes("code")) {
6682
- throw new Error(
6683
- "Authorization server metadata must include response_types_supported containing code"
6717
+ throw new OAuthMetadataError(
6718
+ "authorization-server",
6719
+ "Authorization server metadata must include response_types_supported containing code",
6720
+ void 0,
6721
+ "response-type-unsupported"
6684
6722
  );
6685
6723
  }
6686
6724
  if (!isStringArray(value.code_challenge_methods_supported) || !value.code_challenge_methods_supported.includes("S256")) {
6687
- throw new Error(
6688
- "Authorization server metadata must include code_challenge_methods_supported containing S256"
6725
+ throw new OAuthMetadataError(
6726
+ "authorization-server",
6727
+ "Authorization server metadata must include code_challenge_methods_supported containing S256",
6728
+ void 0,
6729
+ "pkce-unsupported"
6689
6730
  );
6690
6731
  }
6691
6732
  return value;
@@ -6701,19 +6742,24 @@ async function readJsonResponse(response, phase, signal) {
6701
6742
  try {
6702
6743
  return JSON.parse(text);
6703
6744
  } catch {
6704
- throw new Error(`${label} response must be valid JSON`);
6745
+ throw new OAuthMetadataError(phase, `${label} response must be valid JSON`, void 0, "invalid-json");
6705
6746
  }
6706
6747
  }
6707
6748
  async function fetchMetadata(fetch2, location, phase, parentSignal) {
6708
6749
  parentSignal?.throwIfAborted();
6709
6750
  const deadline = AbortSignal.timeout(1e4);
6710
6751
  const signal = parentSignal === void 0 ? deadline : AbortSignal.any([deadline, parentSignal]);
6711
- const response = await fetchMcpResponse(fetch2, location, {
6712
- method: "GET",
6713
- headers: { Accept: "application/json" },
6714
- signal
6715
- });
6716
- return readJsonResponse(response, phase, signal);
6752
+ try {
6753
+ const response = await fetchMcpResponse(fetch2, location, {
6754
+ method: "GET",
6755
+ headers: { Accept: "application/json" },
6756
+ signal
6757
+ });
6758
+ return await readJsonResponse(response, phase, signal);
6759
+ } catch (error) {
6760
+ parentSignal?.throwIfAborted();
6761
+ throw metadataFailure(error, phase, "network-error");
6762
+ }
6717
6763
  }
6718
6764
  function resolveWellKnownMetadataUrl(inputUrl, suffix) {
6719
6765
  const url = new URL(typeof inputUrl === "string" ? inputUrl : inputUrl.toString());
@@ -6823,7 +6869,7 @@ var OAuthMetadataDiscovery = class {
6823
6869
  if (resourceMetadataUrl === void 0) {
6824
6870
  locations.add(new URL("/.well-known/oauth-protected-resource", resource).toString());
6825
6871
  }
6826
- let lastError;
6872
+ const errors2 = [];
6827
6873
  for (const location of locations) {
6828
6874
  try {
6829
6875
  const metadata = validateProtectedResourceMetadata(
@@ -6833,17 +6879,18 @@ var OAuthMetadataDiscovery = class {
6833
6879
  return { location, metadata };
6834
6880
  } catch (error) {
6835
6881
  signal?.throwIfAborted();
6836
- lastError = error;
6882
+ errors2.push(metadataFailure(error, "protected-resource", "invalid-metadata"));
6837
6883
  }
6838
6884
  }
6839
- throw lastError;
6885
+ throw aggregateMetadataFailures("protected-resource", errors2, errors2.at(-1).message);
6840
6886
  }
6841
- async discover(resourceUrl, { resourceMetadataUrl, signal } = {}) {
6887
+ async discover(resourceUrl, { resourceMetadataUrl, signal, expectedIssuer } = {}) {
6842
6888
  signal?.throwIfAborted();
6889
+ if (expectedIssuer !== void 0) validateAuthorizationServerIssuer(expectedIssuer);
6843
6890
  const cacheKey = canonicalizeResourceIndicator(resourceUrl);
6844
6891
  resolveProtectedResourceMetadataUrl(resourceUrl, resourceMetadataUrl);
6845
6892
  const memoryCachedResult = this.memoryCache.get(cacheKey);
6846
- if (memoryCachedResult !== void 0 && resourceMetadataUrl === void 0) {
6893
+ if (memoryCachedResult !== void 0 && resourceMetadataUrl === void 0 && (expectedIssuer === void 0 || memoryCachedResult.authorizationServer === expectedIssuer)) {
6847
6894
  return structuredClone(memoryCachedResult);
6848
6895
  }
6849
6896
  const sharedCachedResult = resourceMetadataUrl === void 0 ? await waitForCache(this.cache?.get(cacheKey), signal) : void 0;
@@ -6851,44 +6898,63 @@ var OAuthMetadataDiscovery = class {
6851
6898
  if (sharedCachedResult !== null && sharedCachedResult !== void 0 && resourceMetadataUrl === void 0) {
6852
6899
  try {
6853
6900
  const result = validateCachedDiscovery(sharedCachedResult, cacheKey);
6854
- this.memoryCache.set(cacheKey, structuredClone(result));
6855
- return result;
6901
+ if (expectedIssuer === void 0 || result.authorizationServer === expectedIssuer) {
6902
+ this.memoryCache.set(cacheKey, structuredClone(result));
6903
+ return result;
6904
+ }
6856
6905
  } catch {
6857
6906
  await waitForCache(this.cache?.delete?.(cacheKey), signal);
6858
6907
  }
6859
6908
  }
6860
6909
  const { location: resourceMetadataLocation, metadata: resourceMetadata } = await this.discoverProtectedResource(cacheKey, resourceMetadataUrl, signal);
6861
6910
  const authorizationServerErrors = [];
6862
- for (const authorizationServer of resourceMetadata.authorization_servers) {
6863
- const normalizedAuthorizationServer = validateAuthorizationServerIssuer(authorizationServer);
6911
+ const failures = [];
6912
+ if (expectedIssuer !== void 0 && !resourceMetadata.authorization_servers.includes(expectedIssuer)) {
6913
+ throw new OAuthMetadataError("authorization-server", "Expected issuer was not advertised by the protected resource", void 0, "issuer-mismatch");
6914
+ }
6915
+ const authorizationServers = expectedIssuer === void 0 ? resourceMetadata.authorization_servers : [expectedIssuer];
6916
+ for (const authorizationServer of authorizationServers) {
6917
+ let normalizedAuthorizationServer;
6918
+ try {
6919
+ normalizedAuthorizationServer = validateAuthorizationServerIssuer(authorizationServer);
6920
+ } catch (error) {
6921
+ const failure = metadataFailure(error, "authorization-server", "invalid-metadata");
6922
+ failures.push(failure);
6923
+ authorizationServerErrors.push(failure.message);
6924
+ continue;
6925
+ }
6864
6926
  const metadataLocations = authorizationServerMetadataLocations(normalizedAuthorizationServer);
6865
6927
  for (const authorizationServerMetadataUrl of metadataLocations) {
6928
+ let authorizationServerMetadata;
6866
6929
  try {
6867
- const authorizationServerMetadata = validateAuthorizationServerMetadata(
6930
+ authorizationServerMetadata = validateAuthorizationServerMetadata(
6868
6931
  await fetchMetadata(this.fetchImpl, authorizationServerMetadataUrl, "authorization-server", signal),
6869
6932
  normalizedAuthorizationServer
6870
6933
  );
6871
- const result = {
6872
- resource: resourceMetadata.resource,
6873
- resourceMetadataUrl: resourceMetadataLocation,
6874
- resourceMetadata,
6875
- authorizationServer: normalizedAuthorizationServer,
6876
- authorizationServerMetadataUrl,
6877
- authorizationServerMetadata
6878
- };
6879
- this.memoryCache.set(cacheKey, structuredClone(result));
6880
- await waitForCache(this.cache?.set(cacheKey, structuredClone(result)), signal);
6881
- return result;
6882
6934
  } catch (error) {
6883
6935
  signal?.throwIfAborted();
6936
+ failures.push(metadataFailure(error, "authorization-server", "invalid-metadata"));
6884
6937
  authorizationServerErrors.push(
6885
6938
  `${authorizationServerMetadataUrl}: ${error instanceof Error ? error.message : String(error)}`
6886
6939
  );
6940
+ continue;
6887
6941
  }
6942
+ const result = {
6943
+ resource: resourceMetadata.resource,
6944
+ resourceMetadataUrl: resourceMetadataLocation,
6945
+ resourceMetadata,
6946
+ authorizationServer: normalizedAuthorizationServer,
6947
+ authorizationServerMetadataUrl,
6948
+ authorizationServerMetadata
6949
+ };
6950
+ await waitForCache(this.cache?.set(cacheKey, structuredClone(result)), signal);
6951
+ this.memoryCache.set(cacheKey, structuredClone(result));
6952
+ return result;
6888
6953
  }
6889
6954
  }
6890
- throw new OAuthMetadataError(
6955
+ throw aggregateMetadataFailures(
6891
6956
  "authorization-server",
6957
+ failures,
6892
6958
  `Unable to load authorization server metadata for ${cacheKey}: ${authorizationServerErrors.join(
6893
6959
  "; "
6894
6960
  )}`
@@ -2,7 +2,7 @@ import {
2
2
  McpError,
3
3
  connectMcpTransport,
4
4
  normalizeMcpOptions
5
- } from "./chunk-E7V44LSN.js";
5
+ } from "./chunk-5KAVJF3R.js";
6
6
  import {
7
7
  declareHostOperation,
8
8
  runResources
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunk-XQOJJA4C.js";
9
9
  import {
10
10
  parseMcpConfig
11
- } from "./chunk-E7V44LSN.js";
11
+ } from "./chunk-5KAVJF3R.js";
12
12
  import {
13
13
  lint,
14
14
  makeEnvModule,
@@ -296,7 +296,7 @@ async function runScriptFile(filepath, parsed, options) {
296
296
  import("./dump-OX7M4C56.js"),
297
297
  import("./runtime-modules-UOVJSSD7.js"),
298
298
  import("../modules/fs.js"),
299
- import("./mcp-DSJET2K4.js")
299
+ import("./mcp-IOBUSD2E.js")
300
300
  ]);
301
301
  const loaded = loadExecutableSource(filepath, await options.readFile(filepath, "utf8"));
302
302
  const meta = {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  makeMcpModule
3
- } from "./chunk-7RGEML7S.js";
4
- import "./chunk-E7V44LSN.js";
3
+ } from "./chunk-EUKAVPB5.js";
4
+ import "./chunk-5KAVJF3R.js";
5
5
  import "./chunk-ROIZEQTS.js";
6
6
  import "./chunk-EQUBWQJN.js";
7
7
  import "./chunk-2IYZK337.js";
@@ -13,7 +13,7 @@ import { createHostFileSystem } from "@poe-platform/safe-fs/node";
13
13
  import { fileURLToPath } from "node:url";
14
14
  async function runCli(argv, options = {}) {
15
15
  if (!argv.includes("--help") && !argv.includes("-h")) {
16
- const runtime = await import("./chunks/cli-runtime-EV4DQ7UW.js");
16
+ const runtime = await import("./chunks/cli-runtime-UC3OADSS.js");
17
17
  return runtime.runCli(argv, options, createUsage());
18
18
  }
19
19
  const brokenPipe = createBrokenPipeState();
@@ -32,7 +32,7 @@ async function runCli(argv, options = {}) {
32
32
  stderr.write(`${error instanceof Error ? error.message : String(error)}
33
33
  `);
34
34
  if (brokenPipe.closed) return 0;
35
- const { exitCodeForError } = await import("./chunks/cli-runtime-EV4DQ7UW.js");
35
+ const { exitCodeForError } = await import("./chunks/cli-runtime-UC3OADSS.js");
36
36
  return exitCodeForError(error);
37
37
  }
38
38
  }
@@ -8,7 +8,7 @@ import {
8
8
  } from "./chunks/chunk-425IYA26.js";
9
9
  import {
10
10
  makeMcpModule
11
- } from "./chunks/chunk-7RGEML7S.js";
11
+ } from "./chunks/chunk-EUKAVPB5.js";
12
12
  import {
13
13
  AgentSpawnError,
14
14
  SPAWN_MODES,
@@ -24,7 +24,7 @@ import {
24
24
  } from "./chunks/chunk-XQOJJA4C.js";
25
25
  import {
26
26
  parseMcpConfig
27
- } from "./chunks/chunk-E7V44LSN.js";
27
+ } from "./chunks/chunk-5KAVJF3R.js";
28
28
  import {
29
29
  captureHostContext,
30
30
  deepCopyFromSandbox,
@@ -81716,19 +81716,38 @@ function createParameterHeaders(definitions2, argumentsValue) {
81716
81716
  // packages/tiny-mcp-client/src/oauth-discovery.ts
81717
81717
  var metadataErrorBrand = /* @__PURE__ */ Symbol.for("poe-platform.tiny-mcp-client.OAuthMetadataError");
81718
81718
  var OAuthMetadataError = class extends Error {
81719
- constructor(phase, message, status) {
81719
+ constructor(phase, message, status, reason = status === void 0 ? "invalid-metadata" : "http-error", failures = []) {
81720
81720
  super(message);
81721
81721
  this.phase = phase;
81722
81722
  this.status = status;
81723
+ this.reason = reason;
81724
+ this.failures = failures;
81723
81725
  this.name = "OAuthMetadataError";
81726
+ this.category = reason === "invalid-json" ? "json" : reason === "http-error" ? "http" : reason === "network-error" ? "network" : "validation";
81724
81727
  Object.defineProperty(this, metadataErrorBrand, { value: true });
81725
81728
  }
81726
81729
  phase;
81727
81730
  status;
81731
+ reason;
81732
+ failures;
81728
81733
  static is(value) {
81729
81734
  return value instanceof Error && Object.getOwnPropertyDescriptor(value, metadataErrorBrand)?.value === true;
81730
81735
  }
81736
+ category;
81731
81737
  };
81738
+ function metadataFailure(error, phase, reason) {
81739
+ return OAuthMetadataError.is(error) ? error : new OAuthMetadataError(
81740
+ phase,
81741
+ error instanceof Error ? error.message : String(error),
81742
+ void 0,
81743
+ reason
81744
+ );
81745
+ }
81746
+ function aggregateMetadataFailures(phase, errors, message) {
81747
+ const primary = errors.find((error) => error.category === "validation") ?? errors[0];
81748
+ const failures = errors.map(({ phase: phase2, category, reason, status }) => Object.freeze({ phase: phase2, category, reason, status }));
81749
+ return new OAuthMetadataError(phase, message, primary.status, primary.reason, Object.freeze(failures));
81750
+ }
81732
81751
  function defaultOAuthMetadataFetch(input, init) {
81733
81752
  return fetch(input, init);
81734
81753
  }
@@ -81794,14 +81813,16 @@ function validateAuthorizationServerMetadata(value, issuer) {
81794
81813
  if (value.issuer !== issuer) {
81795
81814
  throw new OAuthMetadataError(
81796
81815
  "authorization-server",
81797
- `Authorization server metadata issuer mismatch: expected ${issuer}, received ${value.issuer}`
81816
+ `Authorization server metadata issuer mismatch: expected ${issuer}, received ${value.issuer}`,
81817
+ void 0,
81818
+ "issuer-mismatch"
81798
81819
  );
81799
81820
  }
81800
81821
  if (typeof value.authorization_endpoint !== "string" || value.authorization_endpoint.length === 0) {
81801
- throw new Error("Authorization server metadata must include authorization_endpoint");
81822
+ throw new OAuthMetadataError("authorization-server", "Authorization server metadata must include authorization_endpoint", void 0, "invalid-endpoint");
81802
81823
  }
81803
81824
  if (typeof value.token_endpoint !== "string" || value.token_endpoint.length === 0) {
81804
- throw new Error("Authorization server metadata must include token_endpoint");
81825
+ throw new OAuthMetadataError("authorization-server", "Authorization server metadata must include token_endpoint", void 0, "invalid-endpoint");
81805
81826
  }
81806
81827
  for (const field of ["authorization_endpoint", "token_endpoint", "registration_endpoint"]) {
81807
81828
  if (field === "registration_endpoint" && value[field] === void 0) {
@@ -81813,19 +81834,25 @@ function validateAuthorizationServerMetadata(value, issuer) {
81813
81834
  throw new Error();
81814
81835
  }
81815
81836
  endpoint = new URL(value[field]);
81816
- } catch {
81817
- throw new Error(`Authorization server metadata ${field} must be an absolute URL`);
81837
+ assertSecureUrl(endpoint, `Authorization server metadata ${field}`);
81838
+ } catch (error) {
81839
+ throw new OAuthMetadataError("authorization-server", `Authorization server metadata ${field} must be an absolute URL: ${error instanceof Error ? error.message : "invalid URL"}`, void 0, "invalid-endpoint");
81818
81840
  }
81819
- assertSecureUrl(endpoint, `Authorization server metadata ${field}`);
81820
81841
  }
81821
81842
  if (!isStringArray(value.response_types_supported) || !value.response_types_supported.includes("code")) {
81822
- throw new Error(
81823
- "Authorization server metadata must include response_types_supported containing code"
81843
+ throw new OAuthMetadataError(
81844
+ "authorization-server",
81845
+ "Authorization server metadata must include response_types_supported containing code",
81846
+ void 0,
81847
+ "response-type-unsupported"
81824
81848
  );
81825
81849
  }
81826
81850
  if (!isStringArray(value.code_challenge_methods_supported) || !value.code_challenge_methods_supported.includes("S256")) {
81827
- throw new Error(
81828
- "Authorization server metadata must include code_challenge_methods_supported containing S256"
81851
+ throw new OAuthMetadataError(
81852
+ "authorization-server",
81853
+ "Authorization server metadata must include code_challenge_methods_supported containing S256",
81854
+ void 0,
81855
+ "pkce-unsupported"
81829
81856
  );
81830
81857
  }
81831
81858
  return value;
@@ -81841,19 +81868,24 @@ async function readJsonResponse(response, phase, signal) {
81841
81868
  try {
81842
81869
  return JSON.parse(text);
81843
81870
  } catch {
81844
- throw new Error(`${label} response must be valid JSON`);
81871
+ throw new OAuthMetadataError(phase, `${label} response must be valid JSON`, void 0, "invalid-json");
81845
81872
  }
81846
81873
  }
81847
81874
  async function fetchMetadata(fetch2, location, phase, parentSignal) {
81848
81875
  parentSignal?.throwIfAborted();
81849
81876
  const deadline = AbortSignal.timeout(1e4);
81850
81877
  const signal = parentSignal === void 0 ? deadline : AbortSignal.any([deadline, parentSignal]);
81851
- const response = await fetchMcpResponse(fetch2, location, {
81852
- method: "GET",
81853
- headers: { Accept: "application/json" },
81854
- signal
81855
- });
81856
- return readJsonResponse(response, phase, signal);
81878
+ try {
81879
+ const response = await fetchMcpResponse(fetch2, location, {
81880
+ method: "GET",
81881
+ headers: { Accept: "application/json" },
81882
+ signal
81883
+ });
81884
+ return await readJsonResponse(response, phase, signal);
81885
+ } catch (error) {
81886
+ parentSignal?.throwIfAborted();
81887
+ throw metadataFailure(error, phase, "network-error");
81888
+ }
81857
81889
  }
81858
81890
  function resolveWellKnownMetadataUrl(inputUrl, suffix) {
81859
81891
  const url = new URL(typeof inputUrl === "string" ? inputUrl : inputUrl.toString());
@@ -81963,7 +81995,7 @@ var OAuthMetadataDiscovery = class {
81963
81995
  if (resourceMetadataUrl === void 0) {
81964
81996
  locations.add(new URL("/.well-known/oauth-protected-resource", resource).toString());
81965
81997
  }
81966
- let lastError;
81998
+ const errors = [];
81967
81999
  for (const location of locations) {
81968
82000
  try {
81969
82001
  const metadata = validateProtectedResourceMetadata(
@@ -81973,17 +82005,18 @@ var OAuthMetadataDiscovery = class {
81973
82005
  return { location, metadata };
81974
82006
  } catch (error) {
81975
82007
  signal?.throwIfAborted();
81976
- lastError = error;
82008
+ errors.push(metadataFailure(error, "protected-resource", "invalid-metadata"));
81977
82009
  }
81978
82010
  }
81979
- throw lastError;
82011
+ throw aggregateMetadataFailures("protected-resource", errors, errors.at(-1).message);
81980
82012
  }
81981
- async discover(resourceUrl, { resourceMetadataUrl, signal } = {}) {
82013
+ async discover(resourceUrl, { resourceMetadataUrl, signal, expectedIssuer } = {}) {
81982
82014
  signal?.throwIfAborted();
82015
+ if (expectedIssuer !== void 0) validateAuthorizationServerIssuer(expectedIssuer);
81983
82016
  const cacheKey = canonicalizeResourceIndicator(resourceUrl);
81984
82017
  resolveProtectedResourceMetadataUrl(resourceUrl, resourceMetadataUrl);
81985
82018
  const memoryCachedResult = this.memoryCache.get(cacheKey);
81986
- if (memoryCachedResult !== void 0 && resourceMetadataUrl === void 0) {
82019
+ if (memoryCachedResult !== void 0 && resourceMetadataUrl === void 0 && (expectedIssuer === void 0 || memoryCachedResult.authorizationServer === expectedIssuer)) {
81987
82020
  return structuredClone(memoryCachedResult);
81988
82021
  }
81989
82022
  const sharedCachedResult = resourceMetadataUrl === void 0 ? await waitForCache(this.cache?.get(cacheKey), signal) : void 0;
@@ -81991,44 +82024,63 @@ var OAuthMetadataDiscovery = class {
81991
82024
  if (sharedCachedResult !== null && sharedCachedResult !== void 0 && resourceMetadataUrl === void 0) {
81992
82025
  try {
81993
82026
  const result = validateCachedDiscovery(sharedCachedResult, cacheKey);
81994
- this.memoryCache.set(cacheKey, structuredClone(result));
81995
- return result;
82027
+ if (expectedIssuer === void 0 || result.authorizationServer === expectedIssuer) {
82028
+ this.memoryCache.set(cacheKey, structuredClone(result));
82029
+ return result;
82030
+ }
81996
82031
  } catch {
81997
82032
  await waitForCache(this.cache?.delete?.(cacheKey), signal);
81998
82033
  }
81999
82034
  }
82000
82035
  const { location: resourceMetadataLocation, metadata: resourceMetadata } = await this.discoverProtectedResource(cacheKey, resourceMetadataUrl, signal);
82001
82036
  const authorizationServerErrors = [];
82002
- for (const authorizationServer of resourceMetadata.authorization_servers) {
82003
- const normalizedAuthorizationServer = validateAuthorizationServerIssuer(authorizationServer);
82037
+ const failures = [];
82038
+ if (expectedIssuer !== void 0 && !resourceMetadata.authorization_servers.includes(expectedIssuer)) {
82039
+ throw new OAuthMetadataError("authorization-server", "Expected issuer was not advertised by the protected resource", void 0, "issuer-mismatch");
82040
+ }
82041
+ const authorizationServers = expectedIssuer === void 0 ? resourceMetadata.authorization_servers : [expectedIssuer];
82042
+ for (const authorizationServer of authorizationServers) {
82043
+ let normalizedAuthorizationServer;
82044
+ try {
82045
+ normalizedAuthorizationServer = validateAuthorizationServerIssuer(authorizationServer);
82046
+ } catch (error) {
82047
+ const failure = metadataFailure(error, "authorization-server", "invalid-metadata");
82048
+ failures.push(failure);
82049
+ authorizationServerErrors.push(failure.message);
82050
+ continue;
82051
+ }
82004
82052
  const metadataLocations = authorizationServerMetadataLocations(normalizedAuthorizationServer);
82005
82053
  for (const authorizationServerMetadataUrl of metadataLocations) {
82054
+ let authorizationServerMetadata;
82006
82055
  try {
82007
- const authorizationServerMetadata = validateAuthorizationServerMetadata(
82056
+ authorizationServerMetadata = validateAuthorizationServerMetadata(
82008
82057
  await fetchMetadata(this.fetchImpl, authorizationServerMetadataUrl, "authorization-server", signal),
82009
82058
  normalizedAuthorizationServer
82010
82059
  );
82011
- const result = {
82012
- resource: resourceMetadata.resource,
82013
- resourceMetadataUrl: resourceMetadataLocation,
82014
- resourceMetadata,
82015
- authorizationServer: normalizedAuthorizationServer,
82016
- authorizationServerMetadataUrl,
82017
- authorizationServerMetadata
82018
- };
82019
- this.memoryCache.set(cacheKey, structuredClone(result));
82020
- await waitForCache(this.cache?.set(cacheKey, structuredClone(result)), signal);
82021
- return result;
82022
82060
  } catch (error) {
82023
82061
  signal?.throwIfAborted();
82062
+ failures.push(metadataFailure(error, "authorization-server", "invalid-metadata"));
82024
82063
  authorizationServerErrors.push(
82025
82064
  `${authorizationServerMetadataUrl}: ${error instanceof Error ? error.message : String(error)}`
82026
82065
  );
82066
+ continue;
82027
82067
  }
82068
+ const result = {
82069
+ resource: resourceMetadata.resource,
82070
+ resourceMetadataUrl: resourceMetadataLocation,
82071
+ resourceMetadata,
82072
+ authorizationServer: normalizedAuthorizationServer,
82073
+ authorizationServerMetadataUrl,
82074
+ authorizationServerMetadata
82075
+ };
82076
+ await waitForCache(this.cache?.set(cacheKey, structuredClone(result)), signal);
82077
+ this.memoryCache.set(cacheKey, structuredClone(result));
82078
+ return result;
82028
82079
  }
82029
82080
  }
82030
- throw new OAuthMetadataError(
82081
+ throw aggregateMetadataFailures(
82031
82082
  "authorization-server",
82083
+ failures,
82032
82084
  `Unable to load authorization server metadata for ${cacheKey}: ${authorizationServerErrors.join(
82033
82085
  "; "
82034
82086
  )}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@poe-platform/safe-js",
3
- "version": "0.1.807",
3
+ "version": "0.1.809",
4
4
  "description": "Budgeted JavaScript interpreter with explicit host capabilities and resumable execution",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -82,7 +82,7 @@
82
82
  "access": "public"
83
83
  },
84
84
  "dependencies": {
85
- "@poe-platform/safe-fs": "0.1.807",
85
+ "@poe-platform/safe-fs": "0.1.809",
86
86
  "@petamoriken/float16": "^3.9.3",
87
87
  "@noble/hashes": "2.4.0",
88
88
  "@formatjs/intl-localematcher": "0.8.13",