@poe-platform/safe-js 0.1.803 → 0.1.804

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.
Files changed (56) hide show
  1. package/README.md +4 -4
  2. package/dist/safe-js/bundled-yaml/LICENSE +13 -0
  3. package/dist/safe-js/bundled-yaml/index.js +6601 -0
  4. package/dist/safe-js/chunks/{chunk-FUXGXSZC.js → chunk-36PBWSDR.js} +8 -8
  5. package/dist/safe-js/chunks/{chunk-SN4G557J.js → chunk-6AO2T2VZ.js} +1 -1
  6. package/dist/safe-js/chunks/{chunk-ZXDUALDQ.js → chunk-BKNQTNHP.js} +33 -23
  7. package/dist/safe-js/chunks/{chunk-WEPHHJMR.js → chunk-BYDDUKS3.js} +3 -3
  8. package/dist/safe-js/chunks/{chunk-6H5VC5W5.js → chunk-CKOGIOB3.js} +470 -464
  9. package/dist/safe-js/chunks/{chunk-D36FRVNN.js → chunk-CVPZFRCC.js} +3 -3
  10. package/dist/safe-js/chunks/{chunk-4KMUWNZD.js → chunk-ECMGBHAB.js} +13 -137
  11. package/dist/safe-js/chunks/{chunk-A3LXCGMJ.js → chunk-EQUBWQJN.js} +57 -34
  12. package/dist/safe-js/chunks/{chunk-ZAOSXSKI.js → chunk-JMDWLOJV.js} +26 -3
  13. package/dist/safe-js/chunks/{chunk-3NFTBEZR.js → chunk-JQ5QJV5Q.js} +2 -2
  14. package/dist/safe-js/chunks/{chunk-MMN3IESA.js → chunk-KMBCLXER.js} +1 -1
  15. package/dist/safe-js/chunks/{chunk-WRGATIKL.js → chunk-MJH73KJI.js} +2 -2
  16. package/dist/safe-js/chunks/{chunk-UQYM4GXB.js → chunk-P66QKVQC.js} +3 -3
  17. package/dist/safe-js/chunks/{chunk-HPHCQNFV.js → chunk-RPGCF4KE.js} +130 -3
  18. package/dist/safe-js/chunks/{chunk-J565YTXP.js → chunk-SIR35W6T.js} +5 -5
  19. package/dist/safe-js/chunks/{chunk-LVTYTUF5.js → chunk-SMGNJNDU.js} +1 -1
  20. package/dist/safe-js/chunks/{chunk-6NCYOKZQ.js → chunk-VLRTLEDI.js} +2 -2
  21. package/dist/safe-js/chunks/{chunk-JCHJGIQA.js → chunk-VVOPJZRG.js} +2 -0
  22. package/dist/safe-js/chunks/{cli-runtime-QIA3QMTP.js → cli-runtime-A353G7DR.js} +15 -15
  23. package/dist/safe-js/chunks/{dump-TGI6PZKL.js → dump-KQZFULX2.js} +4 -4
  24. package/dist/safe-js/chunks/harness-XT6K6X67.js +10 -0
  25. package/dist/safe-js/chunks/mcp-VWE444VD.js +11 -0
  26. package/dist/safe-js/chunks/migration-file-NSKXOMAO.js +14 -0
  27. package/dist/safe-js/chunks/restore-SHPORPY4.js +13 -0
  28. package/dist/safe-js/chunks/run-FQOSICOT.js +19 -0
  29. package/dist/safe-js/chunks/{runtime-modules-HWTUIY5J.js → runtime-modules-DBRXXRND.js} +4 -4
  30. package/dist/safe-js/chunks/{source-files-BSDM22Y2.js → source-files-A2WSOO6G.js} +3 -3
  31. package/dist/safe-js/cli.js +2 -2
  32. package/dist/safe-js/core.d.ts +19 -0
  33. package/dist/safe-js/core.js +39 -15
  34. package/dist/safe-js/error/format.d.ts +3 -0
  35. package/dist/safe-js/index.d.ts +1 -12
  36. package/dist/safe-js/index.js +30 -39
  37. package/dist/safe-js/interp/interpreter.d.ts +1 -3
  38. package/dist/safe-js/modules/fs.js +5 -5
  39. package/dist/safe-js/platform/node.d.ts +1 -0
  40. package/dist/safe-js/platform/node.js +1 -0
  41. package/dist/safe-js/platform/workerd.d.ts +1 -0
  42. package/dist/safe-js/platform/workerd.js +2 -0
  43. package/dist/safe-js/portable/chunks/{chunk-XCTU25SU.js → chunk-NLGXLZCK.js} +1 -1
  44. package/dist/safe-js/portable/chunks/{chunk-BIHLWVUU.js → chunk-SRMMDXD3.js} +124 -91
  45. package/dist/safe-js/portable/chunks/{chunk-H5X3T5VP.js → chunk-W6MZOTYR.js} +2 -0
  46. package/dist/safe-js/portable/chunks/{source-files-CVU252FB.js → source-files-AEDWESAJ.js} +2 -2
  47. package/dist/safe-js/portable/core.js +452 -246
  48. package/dist/safe-js/portable/modules/fs.js +2 -2
  49. package/dist/safe-js/workerd.js +57970 -57736
  50. package/package.json +6 -5
  51. package/dist/safe-js/chunks/harness-EE3ISLJP.js +0 -10
  52. package/dist/safe-js/chunks/mcp-F5MMOZNP.js +0 -11
  53. package/dist/safe-js/chunks/migration-file-W3HZOGXV.js +0 -14
  54. package/dist/safe-js/chunks/restore-MMM4A46M.js +0 -13
  55. package/dist/safe-js/chunks/run-TKX3IFNH.js +0 -19
  56. package/dist/safe-js/node-unavailable.d.ts +0 -1
@@ -1459,7 +1459,11 @@ var JSON_RPC_ERROR_CODES = Object.freeze({
1459
1459
  // packages/tiny-stdio-mcp-server/src/base64.ts
1460
1460
  function isBase64(value) {
1461
1461
  if (value.length % 4 !== 0) return false;
1462
- return Buffer.from(value, "base64").toString("base64") === value;
1462
+ try {
1463
+ return btoa(atob(value)) === value;
1464
+ } catch {
1465
+ return false;
1466
+ }
1463
1467
  }
1464
1468
 
1465
1469
  // packages/tiny-stdio-mcp-server/src/uri.ts
@@ -3682,137 +3686,8 @@ function copyBoundedOAuthJson(value, message) {
3682
3686
  }
3683
3687
  }
3684
3688
 
3685
- // packages/mcp-oauth/src/client/loopback-authorization.ts
3686
- import http from "node:http";
3687
-
3688
- // packages/mcp-oauth/src/client/authorization-state.ts
3689
- import crypto2 from "node:crypto";
3690
- function createAuthorizationState(input) {
3691
- const payload = {
3692
- v: 1,
3693
- n: crypto2.randomBytes(16).toString("base64url"),
3694
- i: input.issuer,
3695
- r: input.requireIssuer
3696
- };
3697
- return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
3698
- }
3699
- function parseAuthorizationState(value) {
3700
- if (value === null || value.length === 0) {
3701
- return null;
3702
- }
3703
- try {
3704
- const decoded = Buffer.from(value, "base64url").toString("utf8");
3705
- const parsed = JSON.parse(decoded);
3706
- if (!isObjectRecord(parsed)) {
3707
- return null;
3708
- }
3709
- const version = getOwnEntry(parsed, "v");
3710
- const nonce = getOwnEntry(parsed, "n");
3711
- const issuer = getOwnEntry(parsed, "i");
3712
- const requireIssuer = getOwnEntry(parsed, "r");
3713
- if (version !== 1 || typeof nonce !== "string" || nonce.length === 0 || typeof issuer !== "string" || issuer.length === 0 || typeof requireIssuer !== "boolean") {
3714
- return null;
3715
- }
3716
- return {
3717
- issuer,
3718
- requireIssuer
3719
- };
3720
- } catch {
3721
- return null;
3722
- }
3723
- }
3724
- function isObjectRecord(value) {
3725
- return typeof value === "object" && value !== null && !Array.isArray(value);
3726
- }
3727
- function getOwnEntry(record2, key2) {
3728
- return Object.prototype.hasOwnProperty.call(record2, key2) ? record2[key2] : void 0;
3729
- }
3730
-
3731
- // packages/mcp-oauth/src/client/authorization-error.ts
3732
- var authorizationErrorBrand = /* @__PURE__ */ Symbol.for("poe-platform.mcp-oauth.OAuthAuthorizationError");
3733
- var OAuthAuthorizationError = class extends Error {
3734
- constructor(error, errorDescription) {
3735
- super(`OAuth authorization failed: ${error} \u2014 ${errorDescription}`);
3736
- this.error = error;
3737
- this.errorDescription = errorDescription;
3738
- this.name = "OAuthAuthorizationError";
3739
- Object.defineProperty(this, authorizationErrorBrand, { value: true });
3740
- }
3741
- error;
3742
- errorDescription;
3743
- /** Recognize errors from separately bundled copies of this package. */
3744
- static is(value) {
3745
- return value instanceof Error && Object.getOwnPropertyDescriptor(value, authorizationErrorBrand)?.value === true;
3746
- }
3747
- };
3748
-
3749
- // packages/mcp-oauth/src/client/loopback-authorization.ts
3689
+ // packages/mcp-oauth/src/client/redirect-target.ts
3750
3690
  var oauthCallbackParameters = ["code", "state", "iss", "error", "error_description", "error_uri"];
3751
- function snapshotLoopbackAuthorizationOptions(options) {
3752
- return {
3753
- ...options,
3754
- openBrowser: options.openBrowser?.bind(options),
3755
- readLine: options.readLine?.bind(options),
3756
- waitForCallback: options.waitForCallback?.bind(options),
3757
- createServer: options.createServer?.bind(options),
3758
- callbackPath: options.callbackPath,
3759
- redirectUri: options.redirectUri,
3760
- signal: options.signal,
3761
- timeoutMs: options.timeoutMs,
3762
- landingPage: options.landingPage === void 0 ? void 0 : { ...options.landingPage, title: options.landingPage.title, body: options.landingPage.body }
3763
- };
3764
- }
3765
- async function createLoopbackAuthorizationSession(options = {}) {
3766
- options = snapshotLoopbackAuthorizationOptions(options);
3767
- options.signal?.throwIfAborted();
3768
- const timeoutMs = options.timeoutMs ?? 12e4;
3769
- if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647)
3770
- throw new Error("OAuth authorization timeoutMs must be a positive supported timer interval");
3771
- if (options.waitForCallback !== void 0) return createHostedAuthorizationSession(options, timeoutMs);
3772
- const target = loopbackTarget(options);
3773
- const server = options.createServer ? options.createServer() : http.createServer();
3774
- const controller = new AbortController();
3775
- let closed = false;
3776
- let used = false;
3777
- const callerAbort = () => controller.abort(options.signal?.reason);
3778
- const teardown = () => {
3779
- if (closed) return;
3780
- closed = true;
3781
- clearTimeout(timer);
3782
- options.signal?.removeEventListener("abort", callerAbort);
3783
- server.closeAllConnections?.();
3784
- server.close();
3785
- };
3786
- const timer = setTimeout(() => controller.abort(new Error("OAuth authorization timed out")), timeoutMs);
3787
- timer.unref?.();
3788
- controller.signal.addEventListener("abort", teardown, { once: true });
3789
- options.signal?.addEventListener("abort", callerAbort, { once: true });
3790
- if (options.signal?.aborted) callerAbort();
3791
- let port;
3792
- try {
3793
- port = await startServer(server, target.port, target.host, controller.signal);
3794
- } catch (error) {
3795
- controller.abort(error);
3796
- throw error;
3797
- }
3798
- const redirectUri = options.redirectUri ?? `http://127.0.0.1:${port}${target.callbackPath}`;
3799
- return {
3800
- redirectUri,
3801
- async waitForCode(authorizationUrl) {
3802
- controller.signal.throwIfAborted();
3803
- if (used) throw new Error("OAuth authorization session has already been used");
3804
- used = true;
3805
- try {
3806
- return await waitForAuthorizationCode(server, authorizationUrl, options, target.callbackPath, controller.signal);
3807
- } finally {
3808
- clearTimeout(timer);
3809
- }
3810
- },
3811
- close() {
3812
- controller.abort(new Error("OAuth authorization session closed"));
3813
- }
3814
- };
3815
- }
3816
3691
  function loopbackTarget(options) {
3817
3692
  if (options.redirectUri !== void 0) {
3818
3693
  let url;
@@ -3845,303 +3720,69 @@ function validateHostedOAuthRedirect(redirectUri, callbackPath) {
3845
3720
  if (url.protocol !== "https:" || url.username || url.password || url.href.includes("#") || url.port === "0" || oauthCallbackParameters.some((name) => url.searchParams.has(name)) || [...redirectUri].some((char) => char.codePointAt(0) <= 32) || callbackPath !== void 0 && callbackPath !== url.pathname)
3846
3721
  throw new Error("Invalid hosted OAuth redirect URI");
3847
3722
  }
3848
- function createHostedAuthorizationSession(options, timeoutMs) {
3849
- validateAuthorizationRedirect(options);
3850
- const redirectUri = options.redirectUri, controller = new AbortController();
3851
- let used = false;
3852
- const aborted = () => controller.abort(options.signal?.reason);
3853
- const timer = setTimeout(() => controller.abort(new Error("OAuth authorization timed out")), timeoutMs);
3854
- timer.unref?.();
3855
- const cleanup = () => {
3856
- clearTimeout(timer);
3857
- options.signal?.removeEventListener("abort", aborted);
3858
- };
3859
- controller.signal.addEventListener("abort", cleanup, { once: true });
3860
- options.signal?.addEventListener("abort", aborted, { once: true });
3861
- if (options.signal?.aborted) aborted();
3862
- return {
3863
- redirectUri,
3864
- async waitForCode(authorizationUrl) {
3865
- controller.signal.throwIfAborted();
3866
- if (used) throw new Error("OAuth authorization session has already been used");
3867
- used = true;
3868
- try {
3869
- const authorization = new URL(authorizationUrl);
3870
- if (authorization.searchParams.getAll("redirect_uri").length !== 1 || authorization.searchParams.get("redirect_uri") !== redirectUri)
3871
- throw new Error("OAuth authorization redirect mismatch");
3872
- const callback = await new Promise((resolve, reject) => {
3873
- const onAbort = () => reject(controller.signal.reason);
3874
- controller.signal.addEventListener("abort", onAbort, { once: true });
3875
- void Promise.resolve().then(() => {
3876
- controller.signal.throwIfAborted();
3877
- return options.waitForCallback({ authorizationUrl, redirectUri, signal: controller.signal });
3878
- }).then(resolve, reject).finally(() => controller.signal.removeEventListener("abort", onAbort));
3879
- });
3880
- controller.signal.throwIfAborted();
3881
- const url = new URL(callback), base = new URL(redirectUri);
3882
- if (url.origin !== base.origin || url.pathname !== base.pathname || url.username || url.password || url.href.includes("#") || [...callback].some((char) => char.codePointAt(0) <= 32)) throw new Error("OAuth callback redirect mismatch");
3883
- const params = readAuthorizationCallbackParameters(url);
3884
- for (const name of oauthCallbackParameters) url.searchParams.delete(name);
3885
- if (url.searchParams.toString() !== base.searchParams.toString()) throw new Error("OAuth callback redirect mismatch");
3886
- const expected = readExpectedAuthorizationCallback(authorizationUrl);
3887
- if (expected.state === null) throw new Error("OAuth authorization missing state");
3888
- validateAuthorizationCallbackBinding(params, expected);
3889
- if (params.error !== null) throw new OAuthAuthorizationError(params.error, params.errorDescription ?? params.error);
3890
- return validateAuthorizationCallbackParameters(params, expected);
3891
- } finally {
3892
- controller.abort(new Error("OAuth authorization session closed"));
3893
- }
3894
- },
3895
- close() {
3896
- controller.abort(new Error("OAuth authorization session closed"));
3897
- }
3898
- };
3723
+
3724
+ // packages/mcp-oauth/src/client/token-auth-method.ts
3725
+ function normalizeOAuthTokenEndpointAuthMethod(value) {
3726
+ if (value === void 0 || value === null) return void 0;
3727
+ if (value !== "none" && value !== "client_secret_post" && value !== "client_secret_basic")
3728
+ throw new Error("Unsupported OAuth token endpoint authentication method");
3729
+ return value;
3899
3730
  }
3900
- async function startServer(server, port, host, signal) {
3901
- signal.throwIfAborted();
3902
- return new Promise((resolve, reject) => {
3903
- const cleanup = () => {
3904
- server.off("error", handleError);
3905
- signal.removeEventListener("abort", aborted);
3906
- };
3907
- const handleError = (error) => {
3908
- cleanup();
3909
- reject(error);
3910
- };
3911
- const aborted = () => {
3912
- cleanup();
3913
- reject(signal.reason);
3914
- };
3915
- server.once("error", handleError);
3916
- signal.addEventListener("abort", aborted, { once: true });
3917
- try {
3918
- server.listen(port, host, () => {
3919
- cleanup();
3920
- if (signal.aborted) {
3921
- server.close();
3922
- reject(signal.reason);
3923
- return;
3924
- }
3925
- const address = server.address();
3926
- if (address === null || typeof address === "string") {
3927
- reject(new Error("OAuth listener has no TCP address"));
3928
- return;
3929
- }
3930
- resolve(address.port);
3931
- });
3932
- } catch (error) {
3933
- cleanup();
3934
- reject(error);
3935
- }
3936
- });
3937
- }
3938
- function waitForAuthorizationCode(server, authorizationUrl, options, callbackPath, signal) {
3939
- signal.throwIfAborted();
3940
- const expectedAuthorization = readExpectedAuthorizationCallback(authorizationUrl);
3941
- return new Promise((resolve, reject) => {
3942
- let settled = false;
3943
- const settle = (fn) => {
3944
- if (settled) return;
3945
- settled = true;
3946
- server.off("request", request);
3947
- signal.removeEventListener("abort", aborted);
3948
- fn();
3949
- };
3950
- const aborted = () => settle(() => reject(signal.reason));
3951
- const request = (req, res) => {
3952
- let url;
3953
- try {
3954
- url = new URL(req.url ?? "/", "http://127.0.0.1");
3955
- } catch {
3956
- res.writeHead(400);
3957
- res.end("Invalid callback URL");
3958
- return;
3959
- }
3960
- if (url.pathname !== callbackPath) {
3961
- res.writeHead(404);
3962
- res.end("Not found");
3963
- return;
3964
- }
3965
- try {
3966
- const callbackParameters = readAuthorizationCallbackParameters(url);
3967
- validateAuthorizationCallbackBinding(callbackParameters, expectedAuthorization);
3968
- if (callbackParameters.error !== null)
3969
- throw new OAuthAuthorizationError(callbackParameters.error, callbackParameters.errorDescription ?? callbackParameters.error);
3970
- const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
3971
- res.writeHead(200, { "Content-Type": "text/html" });
3972
- res.end(buildSuccessPage(options.landingPage));
3973
- settle(() => resolve(code));
3974
- } catch (error) {
3975
- res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8", "X-Content-Type-Options": "nosniff" });
3976
- res.end(error instanceof Error ? error.message : "Invalid OAuth callback");
3977
- settle(() => reject(error));
3978
- }
3979
- };
3980
- server.on("request", request);
3981
- signal.addEventListener("abort", aborted, { once: true });
3982
- if (options.readLine !== void 0) {
3983
- void Promise.resolve().then(() => settled ? void 0 : options.readLine()).then((input) => {
3984
- if (settled) return;
3985
- const callbackParameters = extractCallbackParametersFromInput(input);
3986
- if (callbackParameters === null) throw new Error("OAuth callback missing authorization code");
3987
- validateAuthorizationCallbackBinding(callbackParameters, expectedAuthorization);
3988
- if (callbackParameters.error !== null)
3989
- throw new OAuthAuthorizationError(callbackParameters.error, callbackParameters.errorDescription ?? callbackParameters.error);
3990
- const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
3991
- settle(() => resolve(code));
3992
- }).catch((error) => settle(() => reject(error)));
3993
- }
3994
- if (options.openBrowser !== void 0) {
3995
- void Promise.resolve().then(() => settled ? void 0 : options.openBrowser(authorizationUrl)).catch((error) => settle(() => reject(error)));
3996
- }
3997
- });
3998
- }
3999
- function extractCallbackParametersFromInput(input) {
4000
- const trimmed = input.replaceAll("\r", "").replaceAll("\n", "").trim();
4001
- if (trimmed.length === 0) {
4002
- return null;
4003
- }
4004
- let url;
4005
- try {
4006
- url = new URL(trimmed);
4007
- } catch {
4008
- return {
4009
- code: trimmed,
4010
- error: null,
4011
- errorDescription: null,
4012
- state: null,
4013
- iss: null
4014
- };
4015
- }
4016
- return readAuthorizationCallbackParameters(url);
4017
- }
4018
- function readAuthorizationCallbackParameters(url) {
4019
- for (const parameter of oauthCallbackParameters) {
4020
- if (url.searchParams.getAll(parameter).length > 1)
4021
- throw new Error(`OAuth callback parameter '${parameter}' must occur only once`);
4022
- }
4023
- return {
4024
- code: url.searchParams.get("code"),
4025
- error: url.searchParams.get("error"),
4026
- errorDescription: url.searchParams.get("error_description"),
4027
- state: url.searchParams.get("state"),
4028
- iss: url.searchParams.get("iss")
4029
- };
4030
- }
4031
- function readExpectedAuthorizationCallback(authorizationUrl) {
4032
- const url = new URL(authorizationUrl);
4033
- const state = url.searchParams.get("state");
4034
- const parsedState = parseAuthorizationState(state);
4035
- return {
4036
- state,
4037
- issuer: parsedState?.issuer ?? null,
4038
- requireIssuer: parsedState?.requireIssuer ?? false
4039
- };
4040
- }
4041
- function validateAuthorizationCallbackParameters(callback, expected) {
4042
- validateAuthorizationCallbackBinding(callback, expected);
4043
- if (callback.code === null || callback.code.length === 0) {
4044
- throw new Error("OAuth callback missing authorization code");
4045
- }
4046
- return callback.code;
4047
- }
4048
- function validateAuthorizationCallbackBinding(callback, expected) {
4049
- if (expected.state !== null) {
4050
- if (callback.state === null || callback.state.length === 0) {
4051
- throw new Error("OAuth callback missing state");
4052
- }
4053
- if (callback.state !== expected.state) {
4054
- throw new Error("OAuth callback state mismatch");
4055
- }
4056
- }
4057
- if (expected.requireIssuer) {
4058
- if (callback.iss === null || callback.iss.length === 0) {
4059
- throw new Error("OAuth callback missing issuer");
4060
- }
4061
- }
4062
- if (callback.iss !== null && callback.iss.length > 0 && expected.issuer !== null && callback.iss !== expected.issuer) {
4063
- throw new Error("OAuth callback issuer mismatch");
4064
- }
4065
- }
4066
- function escapeHtml(text) {
4067
- return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
4068
- }
4069
- function buildSuccessPage(landingPage) {
4070
- const title = landingPage?.title ?? "Connected";
4071
- const body = landingPage?.body ?? "You can close this tab and return to your terminal.";
4072
- return [
4073
- "<!DOCTYPE html>",
4074
- `<html><head><meta charset=utf-8><title>${escapeHtml(title)}</title></head>`,
4075
- '<body style="font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0">',
4076
- '<div style="text-align:center">',
4077
- `<h1>${escapeHtml(title)}</h1>`,
4078
- `<p style="color:#666">${escapeHtml(body)}</p>`,
4079
- "</div></body></html>"
4080
- ].join("");
4081
- }
4082
-
4083
- // packages/mcp-oauth/src/client/token-auth-method.ts
4084
- function normalizeOAuthTokenEndpointAuthMethod(value) {
4085
- if (value === void 0 || value === null) return void 0;
4086
- if (value !== "none" && value !== "client_secret_post" && value !== "client_secret_basic")
4087
- throw new Error("Unsupported OAuth token endpoint authentication method");
4088
- return value;
4089
- }
4090
-
4091
- // packages/mcp-oauth/src/client/client-registration.ts
4092
- function parseOAuthClientRegistration(value) {
4093
- const invalid = () => new Error("Invalid OAuth client registration metadata");
4094
- const result = copyBoundedOAuthJson(value, "Invalid OAuth client registration metadata");
4095
- if (typeof result !== "object" || result === null || Array.isArray(result)) throw invalid();
4096
- const record2 = result;
4097
- if (!Object.hasOwn(record2, "client_id") || typeof record2.client_id !== "string" || record2.client_id.trim() === "")
4098
- throw new Error("OAuth client registration response missing client_id");
4099
- for (const key2 of [
4100
- "client_id",
4101
- "client_secret",
4102
- "token_endpoint_auth_method",
4103
- "application_type",
4104
- "client_name",
4105
- "client_uri",
4106
- "logo_uri",
4107
- "scope",
4108
- "tos_uri",
4109
- "policy_uri",
4110
- "jwks_uri",
4111
- "software_id",
4112
- "software_version",
4113
- "software_statement",
4114
- "registration_access_token",
4115
- "registration_client_uri",
4116
- "issuer"
4117
- ]) {
4118
- if (Object.hasOwn(record2, key2) && record2[key2] !== null && typeof record2[key2] !== "string") throw invalid();
4119
- }
4120
- if (typeof record2.client_secret === "string" && record2.client_secret.trim() === "") throw invalid();
4121
- for (const key2 of ["redirect_uris", "grant_types", "response_types", "contacts"]) {
4122
- const entry = record2[key2];
4123
- if (Object.hasOwn(record2, key2) && entry !== null && (!Array.isArray(entry) || entry.some((item) => typeof item !== "string"))) throw invalid();
4124
- }
4125
- for (const key2 of ["client_id_issued_at", "client_secret_expires_at"]) {
4126
- const entry = record2[key2];
4127
- if (Object.hasOwn(record2, key2) && entry !== null && (typeof entry !== "number" || !Number.isSafeInteger(entry) || entry < 0)) throw invalid();
4128
- }
4129
- try {
4130
- normalizeOAuthScope(Object.hasOwn(record2, "scope") && record2.scope !== null ? record2.scope : void 0);
4131
- } catch {
4132
- throw invalid();
4133
- }
4134
- return record2;
4135
- }
4136
- function normalizeStoredOAuthClient(value) {
4137
- if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
4138
- const record2 = value;
4139
- const clientId = Object.hasOwn(record2, "clientId") ? record2.clientId : void 0;
4140
- const clientSecret = Object.hasOwn(record2, "clientSecret") ? record2.clientSecret : void 0;
4141
- if (typeof clientId !== "string" || clientId.trim() === "" || clientSecret !== void 0 && (typeof clientSecret !== "string" || clientSecret.trim() === "")) return null;
4142
- const client = { clientId: clientId.trim(), ...clientSecret === void 0 ? {} : { clientSecret: clientSecret.trim() } };
4143
- const requestedRedirectUri = Object.hasOwn(record2, "requestedRedirectUri") ? record2.requestedRedirectUri : void 0;
4144
- if (requestedRedirectUri !== void 0) {
3731
+
3732
+ // packages/mcp-oauth/src/client/client-registration.ts
3733
+ function parseOAuthClientRegistration(value) {
3734
+ const invalid = () => new Error("Invalid OAuth client registration metadata");
3735
+ const result = copyBoundedOAuthJson(value, "Invalid OAuth client registration metadata");
3736
+ if (typeof result !== "object" || result === null || Array.isArray(result)) throw invalid();
3737
+ const record2 = result;
3738
+ if (!Object.hasOwn(record2, "client_id") || typeof record2.client_id !== "string" || record2.client_id.trim() === "")
3739
+ throw new Error("OAuth client registration response missing client_id");
3740
+ for (const key2 of [
3741
+ "client_id",
3742
+ "client_secret",
3743
+ "token_endpoint_auth_method",
3744
+ "application_type",
3745
+ "client_name",
3746
+ "client_uri",
3747
+ "logo_uri",
3748
+ "scope",
3749
+ "tos_uri",
3750
+ "policy_uri",
3751
+ "jwks_uri",
3752
+ "software_id",
3753
+ "software_version",
3754
+ "software_statement",
3755
+ "registration_access_token",
3756
+ "registration_client_uri",
3757
+ "issuer"
3758
+ ]) {
3759
+ if (Object.hasOwn(record2, key2) && record2[key2] !== null && typeof record2[key2] !== "string") throw invalid();
3760
+ }
3761
+ if (typeof record2.client_secret === "string" && record2.client_secret.trim() === "") throw invalid();
3762
+ for (const key2 of ["redirect_uris", "grant_types", "response_types", "contacts"]) {
3763
+ const entry = record2[key2];
3764
+ if (Object.hasOwn(record2, key2) && entry !== null && (!Array.isArray(entry) || entry.some((item) => typeof item !== "string"))) throw invalid();
3765
+ }
3766
+ for (const key2 of ["client_id_issued_at", "client_secret_expires_at"]) {
3767
+ const entry = record2[key2];
3768
+ if (Object.hasOwn(record2, key2) && entry !== null && (typeof entry !== "number" || !Number.isSafeInteger(entry) || entry < 0)) throw invalid();
3769
+ }
3770
+ try {
3771
+ normalizeOAuthScope(Object.hasOwn(record2, "scope") && record2.scope !== null ? record2.scope : void 0);
3772
+ } catch {
3773
+ throw invalid();
3774
+ }
3775
+ return record2;
3776
+ }
3777
+ function normalizeStoredOAuthClient(value) {
3778
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return null;
3779
+ const record2 = value;
3780
+ const clientId = Object.hasOwn(record2, "clientId") ? record2.clientId : void 0;
3781
+ const clientSecret = Object.hasOwn(record2, "clientSecret") ? record2.clientSecret : void 0;
3782
+ if (typeof clientId !== "string" || clientId.trim() === "" || clientSecret !== void 0 && (typeof clientSecret !== "string" || clientSecret.trim() === "")) return null;
3783
+ const client = { clientId: clientId.trim(), ...clientSecret === void 0 ? {} : { clientSecret: clientSecret.trim() } };
3784
+ const requestedRedirectUri = Object.hasOwn(record2, "requestedRedirectUri") ? record2.requestedRedirectUri : void 0;
3785
+ if (requestedRedirectUri !== void 0) {
4145
3786
  try {
4146
3787
  if (typeof requestedRedirectUri !== "string") throw new Error("Invalid redirect identity");
4147
3788
  if (new URL(requestedRedirectUri).protocol === "https:")
@@ -4198,7 +3839,7 @@ function registrationMatchesRedirect(client, requestedUri, fresh = false) {
4198
3839
  }
4199
3840
 
4200
3841
  // packages/mcp-oauth/src/client/auth-store-session-store.ts
4201
- import crypto3 from "node:crypto";
3842
+ import crypto2 from "node:crypto";
4202
3843
  import path4 from "node:path";
4203
3844
 
4204
3845
  // packages/auth-store/src/encrypted-file-store.ts
@@ -4217,8 +3858,8 @@ import { randomUUID } from "node:crypto";
4217
3858
  import path from "node:path";
4218
3859
  async function withSecretStoreFileLock(fs2, lockDirectory, operation, options = {}) {
4219
3860
  options = { ...options, signal: options.signal, timeoutMs: options.timeoutMs };
4220
- const timeoutMs = options.timeoutMs ?? 3e4;
4221
- if (!Number.isFinite(timeoutMs) || timeoutMs < 0 || timeoutMs > 2147483647)
3861
+ const timeoutMs = options.timeoutMs ?? Infinity;
3862
+ if (timeoutMs !== Infinity && (!Number.isFinite(timeoutMs) || timeoutMs < 0 || timeoutMs > 2147483647))
4222
3863
  throw new Error("Invalid secret-store transaction lock timeout");
4223
3864
  options.signal?.throwIfAborted();
4224
3865
  const deadline = performance.now() + timeoutMs;
@@ -4613,10 +4254,10 @@ function parseEncryptedDocument(raw) {
4613
4254
  if (!isRecord2(parsed)) {
4614
4255
  return null;
4615
4256
  }
4616
- const version = getOwnEntry2(parsed, "version");
4617
- const iv = getOwnEntry2(parsed, "iv");
4618
- const authTag = getOwnEntry2(parsed, "authTag");
4619
- const ciphertext = getOwnEntry2(parsed, "ciphertext");
4257
+ const version = getOwnEntry(parsed, "version");
4258
+ const iv = getOwnEntry(parsed, "iv");
4259
+ const authTag = getOwnEntry(parsed, "authTag");
4260
+ const ciphertext = getOwnEntry(parsed, "ciphertext");
4620
4261
  if (version !== ENCRYPTION_VERSION) {
4621
4262
  return null;
4622
4263
  }
@@ -4636,7 +4277,7 @@ function parseEncryptedDocument(raw) {
4636
4277
  function isRecord2(value) {
4637
4278
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
4638
4279
  }
4639
- function getOwnEntry2(record2, key2) {
4280
+ function getOwnEntry(record2, key2) {
4640
4281
  return Object.prototype.hasOwnProperty.call(record2, key2) ? record2[key2] : void 0;
4641
4282
  }
4642
4283
  function isNotFoundError(error) {
@@ -4808,14 +4449,14 @@ function createSecurityCliFailure(operation, result) {
4808
4449
  return new Error(`Failed to ${operation}: security exited with code ${exitCode}`);
4809
4450
  }
4810
4451
  function getCommandExitCode(result) {
4811
- const value = getOwnEntry3(result, "exitCode");
4452
+ const value = getOwnEntry2(result, "exitCode");
4812
4453
  return typeof value === "number" && Number.isInteger(value) ? value : 1;
4813
4454
  }
4814
4455
  function getCommandOutput(result, key2) {
4815
- const value = getOwnEntry3(result, key2);
4456
+ const value = getOwnEntry2(result, key2);
4816
4457
  return typeof value === "string" ? value : "";
4817
4458
  }
4818
- function getOwnEntry3(record2, key2) {
4459
+ function getOwnEntry2(record2, key2) {
4819
4460
  return Object.prototype.hasOwnProperty.call(record2, key2) ? record2[key2] : void 0;
4820
4461
  }
4821
4462
 
@@ -4935,7 +4576,7 @@ function createAuthStoreClientStore(options, namespace) {
4935
4576
  } catch {
4936
4577
  throw new Error("Stored OAuth client must be valid JSON; reset the store explicitly to recover");
4937
4578
  }
4938
- if (isObjectRecord2(parsed) && typeof getOwnEntry4(parsed, "clientId") === "string")
4579
+ if (isObjectRecord(parsed) && typeof getOwnEntry3(parsed, "clientId") === "string")
4939
4580
  return parsed;
4940
4581
  throw new Error("Stored OAuth client must be a JSON object with clientId");
4941
4582
  },
@@ -4956,7 +4597,7 @@ function snapshotPersistenceOptions(options) {
4956
4597
  }
4957
4598
  function createNamedSecretStore(key2, options, defaults, namespace) {
4958
4599
  options = snapshotOAuthPersistenceOptions(options);
4959
- const hash = crypto3.createHash("sha256").update(namespace === void 0 ? key2 : JSON.stringify([namespace, key2])).digest("hex");
4600
+ const hash = crypto2.createHash("sha256").update(namespace === void 0 ? key2 : JSON.stringify([namespace, key2])).digest("hex");
4960
4601
  const configuredFilePath = options.fileStore?.filePath;
4961
4602
  const parsedFilePath = configuredFilePath === void 0 ? null : path4.parse(configuredFilePath);
4962
4603
  const fileStore = {
@@ -4997,47 +4638,47 @@ function assertPersistenceNamespace(namespace) {
4997
4638
  if (namespace !== void 0 && (typeof namespace !== "string" || namespace.trim() === "" || Buffer.byteLength(namespace, "utf8") > 1024))
4998
4639
  throw new Error("OAuth persistence namespace must be a nonempty string within 1024 bytes");
4999
4640
  }
5000
- function isObjectRecord2(value) {
4641
+ function isObjectRecord(value) {
5001
4642
  return typeof value === "object" && value !== null && !Array.isArray(value);
5002
4643
  }
5003
- function getOwnEntry4(record2, key2) {
4644
+ function getOwnEntry3(record2, key2) {
5004
4645
  return Object.prototype.hasOwnProperty.call(record2, key2) ? record2[key2] : void 0;
5005
4646
  }
5006
4647
  function getOwnString(record2, key2) {
5007
- const value = getOwnEntry4(record2, key2);
4648
+ const value = getOwnEntry3(record2, key2);
5008
4649
  return typeof value === "string" ? value : void 0;
5009
4650
  }
5010
4651
  function isStoredOAuthSession(value) {
5011
- if (!isObjectRecord2(value)) {
4652
+ if (!isObjectRecord(value)) {
5012
4653
  return false;
5013
4654
  }
5014
- return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && normalizeStoredOAuthClient(getOwnEntry4(value, "client")) !== null && isStoredOAuthDiscovery(getOwnEntry4(value, "discovery")) && (getOwnEntry4(value, "requestedScope") === void 0 || isNonBlankOwnString(value, "requestedScope")) && (getOwnEntry4(value, "refreshState") === void 0 || getOwnEntry4(value, "refreshState") === "pending" && getOwnEntry4(value, "tokens") === void 0) && isStoredOAuthTokensOrMissing(getOwnEntry4(value, "tokens"));
4655
+ return isNonBlankOwnString(value, "resource") && isNonBlankOwnString(value, "authorizationServer") && normalizeStoredOAuthClient(getOwnEntry3(value, "client")) !== null && isStoredOAuthDiscovery(getOwnEntry3(value, "discovery")) && (getOwnEntry3(value, "requestedScope") === void 0 || isNonBlankOwnString(value, "requestedScope")) && (getOwnEntry3(value, "refreshState") === void 0 || getOwnEntry3(value, "refreshState") === "pending" && getOwnEntry3(value, "tokens") === void 0) && isStoredOAuthTokensOrMissing(getOwnEntry3(value, "tokens"));
5015
4656
  }
5016
4657
  function isStoredOAuthDiscovery(value) {
5017
- if (!isObjectRecord2(value)) {
4658
+ if (!isObjectRecord(value)) {
5018
4659
  return false;
5019
4660
  }
5020
- return isNonBlankOwnString(value, "resourceMetadataUrl") && isObjectRecord2(getOwnEntry4(value, "resourceMetadata")) && isObjectRecord2(getOwnEntry4(value, "authorizationServerMetadata"));
4661
+ return isNonBlankOwnString(value, "resourceMetadataUrl") && isObjectRecord(getOwnEntry3(value, "resourceMetadata")) && isObjectRecord(getOwnEntry3(value, "authorizationServerMetadata"));
5021
4662
  }
5022
4663
  function isStoredOAuthTokensOrMissing(value) {
5023
4664
  if (value === void 0) {
5024
4665
  return true;
5025
4666
  }
5026
- if (!isObjectRecord2(value)) {
4667
+ if (!isObjectRecord(value)) {
5027
4668
  return false;
5028
4669
  }
5029
4670
  if (!isNonBlankOwnString(value, "accessToken") || getOwnString(value, "tokenType") !== "Bearer") {
5030
4671
  return false;
5031
4672
  }
5032
- const expiresAt = getOwnEntry4(value, "expiresAt");
4673
+ const expiresAt = getOwnEntry3(value, "expiresAt");
5033
4674
  if (expiresAt !== null && (typeof expiresAt !== "number" || !Number.isSafeInteger(expiresAt) || expiresAt > MAX_JS_DATE_MS || !Number.isFinite(new Date(expiresAt).getTime()))) {
5034
4675
  return false;
5035
4676
  }
5036
- const refreshToken = getOwnEntry4(value, "refreshToken");
4677
+ const refreshToken = getOwnEntry3(value, "refreshToken");
5037
4678
  if (refreshToken !== void 0 && (typeof refreshToken !== "string" || refreshToken.trim().length === 0)) {
5038
4679
  return false;
5039
4680
  }
5040
- const scope = getOwnEntry4(value, "scope");
4681
+ const scope = getOwnEntry3(value, "scope");
5041
4682
  return scope === void 0 || scope === "" || typeof scope === "string" && scope.trim().length > 0;
5042
4683
  }
5043
4684
  function isNonBlankOwnString(record2, key2) {
@@ -5101,8 +4742,8 @@ function createResourceBoundOAuthStores(options, namespace, identity) {
5101
4742
  async function replace(record2, options2) {
5102
4743
  options2 = { ...options2, signal: options2.signal, timeoutMs: options2.timeoutMs };
5103
4744
  options2.signal?.throwIfAborted();
5104
- const timeoutMs = options2.timeoutMs ?? 3e4;
5105
- if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647)
4745
+ const timeoutMs = options2.timeoutMs ?? Infinity;
4746
+ if (timeoutMs !== Infinity && (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647))
5106
4747
  throw new Error("OAuth replacement timeoutMs must be a positive supported timer interval");
5107
4748
  if (store.withLock === void 0) throw new Error("OAuth resource identity backend must support transaction locks");
5108
4749
  await store.withLock(async () => {
@@ -5255,6 +4896,371 @@ async function fetchMcpResponse(fetchImplementation, input, init = {}) {
5255
4896
  // packages/mcp-oauth/src/client/default-oauth-client-provider.ts
5256
4897
  import { URL as URL2 } from "node:url";
5257
4898
 
4899
+ // packages/mcp-oauth/src/client/loopback-authorization.ts
4900
+ import http from "node:http";
4901
+
4902
+ // packages/mcp-oauth/src/client/authorization-state.ts
4903
+ import crypto3 from "node:crypto";
4904
+ function createAuthorizationState(input) {
4905
+ const payload = {
4906
+ v: 1,
4907
+ n: crypto3.randomBytes(16).toString("base64url"),
4908
+ i: input.issuer,
4909
+ r: input.requireIssuer
4910
+ };
4911
+ return Buffer.from(JSON.stringify(payload), "utf8").toString("base64url");
4912
+ }
4913
+ function parseAuthorizationState(value) {
4914
+ if (value === null || value.length === 0) {
4915
+ return null;
4916
+ }
4917
+ try {
4918
+ const decoded = Buffer.from(value, "base64url").toString("utf8");
4919
+ const parsed = JSON.parse(decoded);
4920
+ if (!isObjectRecord2(parsed)) {
4921
+ return null;
4922
+ }
4923
+ const version = getOwnEntry4(parsed, "v");
4924
+ const nonce = getOwnEntry4(parsed, "n");
4925
+ const issuer = getOwnEntry4(parsed, "i");
4926
+ const requireIssuer = getOwnEntry4(parsed, "r");
4927
+ if (version !== 1 || typeof nonce !== "string" || nonce.length === 0 || typeof issuer !== "string" || issuer.length === 0 || typeof requireIssuer !== "boolean") {
4928
+ return null;
4929
+ }
4930
+ return {
4931
+ issuer,
4932
+ requireIssuer
4933
+ };
4934
+ } catch {
4935
+ return null;
4936
+ }
4937
+ }
4938
+ function isObjectRecord2(value) {
4939
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4940
+ }
4941
+ function getOwnEntry4(record2, key2) {
4942
+ return Object.prototype.hasOwnProperty.call(record2, key2) ? record2[key2] : void 0;
4943
+ }
4944
+
4945
+ // packages/mcp-oauth/src/client/authorization-error.ts
4946
+ var authorizationErrorBrand = /* @__PURE__ */ Symbol.for("poe-platform.mcp-oauth.OAuthAuthorizationError");
4947
+ var OAuthAuthorizationError = class extends Error {
4948
+ constructor(error, errorDescription) {
4949
+ super(`OAuth authorization failed: ${error} \u2014 ${errorDescription}`);
4950
+ this.error = error;
4951
+ this.errorDescription = errorDescription;
4952
+ this.name = "OAuthAuthorizationError";
4953
+ Object.defineProperty(this, authorizationErrorBrand, { value: true });
4954
+ }
4955
+ error;
4956
+ errorDescription;
4957
+ /** Recognize errors from separately bundled copies of this package. */
4958
+ static is(value) {
4959
+ return value instanceof Error && Object.getOwnPropertyDescriptor(value, authorizationErrorBrand)?.value === true;
4960
+ }
4961
+ };
4962
+
4963
+ // packages/mcp-oauth/src/client/loopback-authorization.ts
4964
+ function snapshotLoopbackAuthorizationOptions(options) {
4965
+ return {
4966
+ ...options,
4967
+ openBrowser: options.openBrowser?.bind(options),
4968
+ readLine: options.readLine?.bind(options),
4969
+ waitForCallback: options.waitForCallback?.bind(options),
4970
+ createServer: options.createServer?.bind(options),
4971
+ callbackPath: options.callbackPath,
4972
+ redirectUri: options.redirectUri,
4973
+ signal: options.signal,
4974
+ timeoutMs: options.timeoutMs,
4975
+ landingPage: options.landingPage === void 0 ? void 0 : { ...options.landingPage, title: options.landingPage.title, body: options.landingPage.body }
4976
+ };
4977
+ }
4978
+ async function createLoopbackAuthorizationSession(options = {}) {
4979
+ options = snapshotLoopbackAuthorizationOptions(options);
4980
+ options.signal?.throwIfAborted();
4981
+ const timeoutMs = options.timeoutMs ?? Infinity;
4982
+ if (timeoutMs !== Infinity && (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647))
4983
+ throw new Error("OAuth authorization timeoutMs must be a positive supported timer interval");
4984
+ if (options.waitForCallback !== void 0) return createHostedAuthorizationSession(options, timeoutMs);
4985
+ const target = loopbackTarget(options);
4986
+ const server = options.createServer ? options.createServer() : http.createServer();
4987
+ const controller = new AbortController();
4988
+ let closed = false;
4989
+ let used = false;
4990
+ const callerAbort = () => controller.abort(options.signal?.reason);
4991
+ const teardown = () => {
4992
+ if (closed) return;
4993
+ closed = true;
4994
+ clearTimeout(timer);
4995
+ options.signal?.removeEventListener("abort", callerAbort);
4996
+ server.closeAllConnections?.();
4997
+ server.close();
4998
+ };
4999
+ const timer = timeoutMs === Infinity ? void 0 : setTimeout(() => controller.abort(new Error("OAuth authorization timed out")), timeoutMs);
5000
+ timer?.unref?.();
5001
+ controller.signal.addEventListener("abort", teardown, { once: true });
5002
+ options.signal?.addEventListener("abort", callerAbort, { once: true });
5003
+ if (options.signal?.aborted) callerAbort();
5004
+ let port;
5005
+ try {
5006
+ port = await startServer(server, target.port, target.host, controller.signal);
5007
+ } catch (error) {
5008
+ controller.abort(error);
5009
+ throw error;
5010
+ }
5011
+ const redirectUri = options.redirectUri ?? `http://127.0.0.1:${port}${target.callbackPath}`;
5012
+ return {
5013
+ redirectUri,
5014
+ async waitForCode(authorizationUrl) {
5015
+ controller.signal.throwIfAborted();
5016
+ if (used) throw new Error("OAuth authorization session has already been used");
5017
+ used = true;
5018
+ try {
5019
+ return await waitForAuthorizationCode(server, authorizationUrl, options, target.callbackPath, controller.signal);
5020
+ } finally {
5021
+ clearTimeout(timer);
5022
+ }
5023
+ },
5024
+ close() {
5025
+ controller.abort(new Error("OAuth authorization session closed"));
5026
+ }
5027
+ };
5028
+ }
5029
+ function createHostedAuthorizationSession(options, timeoutMs) {
5030
+ validateAuthorizationRedirect(options);
5031
+ const redirectUri = options.redirectUri, controller = new AbortController();
5032
+ let used = false;
5033
+ const aborted = () => controller.abort(options.signal?.reason);
5034
+ const timer = timeoutMs === Infinity ? void 0 : setTimeout(() => controller.abort(new Error("OAuth authorization timed out")), timeoutMs);
5035
+ timer?.unref?.();
5036
+ const cleanup = () => {
5037
+ clearTimeout(timer);
5038
+ options.signal?.removeEventListener("abort", aborted);
5039
+ };
5040
+ controller.signal.addEventListener("abort", cleanup, { once: true });
5041
+ options.signal?.addEventListener("abort", aborted, { once: true });
5042
+ if (options.signal?.aborted) aborted();
5043
+ return {
5044
+ redirectUri,
5045
+ async waitForCode(authorizationUrl) {
5046
+ controller.signal.throwIfAborted();
5047
+ if (used) throw new Error("OAuth authorization session has already been used");
5048
+ used = true;
5049
+ try {
5050
+ const authorization = new URL(authorizationUrl);
5051
+ if (authorization.searchParams.getAll("redirect_uri").length !== 1 || authorization.searchParams.get("redirect_uri") !== redirectUri)
5052
+ throw new Error("OAuth authorization redirect mismatch");
5053
+ const callback = await new Promise((resolve, reject) => {
5054
+ const onAbort = () => reject(controller.signal.reason);
5055
+ controller.signal.addEventListener("abort", onAbort, { once: true });
5056
+ void Promise.resolve().then(() => {
5057
+ controller.signal.throwIfAborted();
5058
+ return options.waitForCallback({ authorizationUrl, redirectUri, signal: controller.signal });
5059
+ }).then(resolve, reject).finally(() => controller.signal.removeEventListener("abort", onAbort));
5060
+ });
5061
+ controller.signal.throwIfAborted();
5062
+ const url = new URL(callback), base = new URL(redirectUri);
5063
+ if (url.origin !== base.origin || url.pathname !== base.pathname || url.username || url.password || url.href.includes("#") || [...callback].some((char) => char.codePointAt(0) <= 32)) throw new Error("OAuth callback redirect mismatch");
5064
+ const params = readAuthorizationCallbackParameters(url);
5065
+ for (const name of oauthCallbackParameters) url.searchParams.delete(name);
5066
+ if (url.searchParams.toString() !== base.searchParams.toString()) throw new Error("OAuth callback redirect mismatch");
5067
+ const expected = readExpectedAuthorizationCallback(authorizationUrl);
5068
+ if (expected.state === null) throw new Error("OAuth authorization missing state");
5069
+ validateAuthorizationCallbackBinding(params, expected);
5070
+ if (params.error !== null) throw new OAuthAuthorizationError(params.error, params.errorDescription ?? params.error);
5071
+ return validateAuthorizationCallbackParameters(params, expected);
5072
+ } finally {
5073
+ controller.abort(new Error("OAuth authorization session closed"));
5074
+ }
5075
+ },
5076
+ close() {
5077
+ controller.abort(new Error("OAuth authorization session closed"));
5078
+ }
5079
+ };
5080
+ }
5081
+ async function startServer(server, port, host, signal) {
5082
+ signal.throwIfAborted();
5083
+ return new Promise((resolve, reject) => {
5084
+ const cleanup = () => {
5085
+ server.off("error", handleError);
5086
+ signal.removeEventListener("abort", aborted);
5087
+ };
5088
+ const handleError = (error) => {
5089
+ cleanup();
5090
+ reject(error);
5091
+ };
5092
+ const aborted = () => {
5093
+ cleanup();
5094
+ reject(signal.reason);
5095
+ };
5096
+ server.once("error", handleError);
5097
+ signal.addEventListener("abort", aborted, { once: true });
5098
+ try {
5099
+ server.listen(port, host, () => {
5100
+ cleanup();
5101
+ if (signal.aborted) {
5102
+ server.close();
5103
+ reject(signal.reason);
5104
+ return;
5105
+ }
5106
+ const address = server.address();
5107
+ if (address === null || typeof address === "string") {
5108
+ reject(new Error("OAuth listener has no TCP address"));
5109
+ return;
5110
+ }
5111
+ resolve(address.port);
5112
+ });
5113
+ } catch (error) {
5114
+ cleanup();
5115
+ reject(error);
5116
+ }
5117
+ });
5118
+ }
5119
+ function waitForAuthorizationCode(server, authorizationUrl, options, callbackPath, signal) {
5120
+ signal.throwIfAborted();
5121
+ const expectedAuthorization = readExpectedAuthorizationCallback(authorizationUrl);
5122
+ return new Promise((resolve, reject) => {
5123
+ let settled = false;
5124
+ const settle = (fn) => {
5125
+ if (settled) return;
5126
+ settled = true;
5127
+ server.off("request", request);
5128
+ signal.removeEventListener("abort", aborted);
5129
+ fn();
5130
+ };
5131
+ const aborted = () => settle(() => reject(signal.reason));
5132
+ const request = (req, res) => {
5133
+ let url;
5134
+ try {
5135
+ url = new URL(req.url ?? "/", "http://127.0.0.1");
5136
+ } catch {
5137
+ res.writeHead(400);
5138
+ res.end("Invalid callback URL");
5139
+ return;
5140
+ }
5141
+ if (url.pathname !== callbackPath) {
5142
+ res.writeHead(404);
5143
+ res.end("Not found");
5144
+ return;
5145
+ }
5146
+ try {
5147
+ const callbackParameters = readAuthorizationCallbackParameters(url);
5148
+ validateAuthorizationCallbackBinding(callbackParameters, expectedAuthorization);
5149
+ if (callbackParameters.error !== null)
5150
+ throw new OAuthAuthorizationError(callbackParameters.error, callbackParameters.errorDescription ?? callbackParameters.error);
5151
+ const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
5152
+ res.writeHead(200, { "Content-Type": "text/html" });
5153
+ res.end(buildSuccessPage(options.landingPage));
5154
+ settle(() => resolve(code));
5155
+ } catch (error) {
5156
+ res.writeHead(400, { "Content-Type": "text/plain; charset=utf-8", "X-Content-Type-Options": "nosniff" });
5157
+ res.end(error instanceof Error ? error.message : "Invalid OAuth callback");
5158
+ settle(() => reject(error));
5159
+ }
5160
+ };
5161
+ server.on("request", request);
5162
+ signal.addEventListener("abort", aborted, { once: true });
5163
+ if (options.readLine !== void 0) {
5164
+ void Promise.resolve().then(() => settled ? void 0 : options.readLine()).then((input) => {
5165
+ if (settled) return;
5166
+ const callbackParameters = extractCallbackParametersFromInput(input);
5167
+ if (callbackParameters === null) throw new Error("OAuth callback missing authorization code");
5168
+ validateAuthorizationCallbackBinding(callbackParameters, expectedAuthorization);
5169
+ if (callbackParameters.error !== null)
5170
+ throw new OAuthAuthorizationError(callbackParameters.error, callbackParameters.errorDescription ?? callbackParameters.error);
5171
+ const code = validateAuthorizationCallbackParameters(callbackParameters, expectedAuthorization);
5172
+ settle(() => resolve(code));
5173
+ }).catch((error) => settle(() => reject(error)));
5174
+ }
5175
+ if (options.openBrowser !== void 0) {
5176
+ void Promise.resolve().then(() => settled ? void 0 : options.openBrowser(authorizationUrl)).catch((error) => settle(() => reject(error)));
5177
+ }
5178
+ });
5179
+ }
5180
+ function extractCallbackParametersFromInput(input) {
5181
+ const trimmed = input.replaceAll("\r", "").replaceAll("\n", "").trim();
5182
+ if (trimmed.length === 0) {
5183
+ return null;
5184
+ }
5185
+ let url;
5186
+ try {
5187
+ url = new URL(trimmed);
5188
+ } catch {
5189
+ return {
5190
+ code: trimmed,
5191
+ error: null,
5192
+ errorDescription: null,
5193
+ state: null,
5194
+ iss: null
5195
+ };
5196
+ }
5197
+ return readAuthorizationCallbackParameters(url);
5198
+ }
5199
+ function readAuthorizationCallbackParameters(url) {
5200
+ for (const parameter of oauthCallbackParameters) {
5201
+ if (url.searchParams.getAll(parameter).length > 1)
5202
+ throw new Error(`OAuth callback parameter '${parameter}' must occur only once`);
5203
+ }
5204
+ return {
5205
+ code: url.searchParams.get("code"),
5206
+ error: url.searchParams.get("error"),
5207
+ errorDescription: url.searchParams.get("error_description"),
5208
+ state: url.searchParams.get("state"),
5209
+ iss: url.searchParams.get("iss")
5210
+ };
5211
+ }
5212
+ function readExpectedAuthorizationCallback(authorizationUrl) {
5213
+ const url = new URL(authorizationUrl);
5214
+ const state = url.searchParams.get("state");
5215
+ const parsedState = parseAuthorizationState(state);
5216
+ return {
5217
+ state,
5218
+ issuer: parsedState?.issuer ?? null,
5219
+ requireIssuer: parsedState?.requireIssuer ?? false
5220
+ };
5221
+ }
5222
+ function validateAuthorizationCallbackParameters(callback, expected) {
5223
+ validateAuthorizationCallbackBinding(callback, expected);
5224
+ if (callback.code === null || callback.code.length === 0) {
5225
+ throw new Error("OAuth callback missing authorization code");
5226
+ }
5227
+ return callback.code;
5228
+ }
5229
+ function validateAuthorizationCallbackBinding(callback, expected) {
5230
+ if (expected.state !== null) {
5231
+ if (callback.state === null || callback.state.length === 0) {
5232
+ throw new Error("OAuth callback missing state");
5233
+ }
5234
+ if (callback.state !== expected.state) {
5235
+ throw new Error("OAuth callback state mismatch");
5236
+ }
5237
+ }
5238
+ if (expected.requireIssuer) {
5239
+ if (callback.iss === null || callback.iss.length === 0) {
5240
+ throw new Error("OAuth callback missing issuer");
5241
+ }
5242
+ }
5243
+ if (callback.iss !== null && callback.iss.length > 0 && expected.issuer !== null && callback.iss !== expected.issuer) {
5244
+ throw new Error("OAuth callback issuer mismatch");
5245
+ }
5246
+ }
5247
+ function escapeHtml(text) {
5248
+ return text.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;");
5249
+ }
5250
+ function buildSuccessPage(landingPage) {
5251
+ const title = landingPage?.title ?? "Connected";
5252
+ const body = landingPage?.body ?? "You can close this tab and return to your terminal.";
5253
+ return [
5254
+ "<!DOCTYPE html>",
5255
+ `<html><head><meta charset=utf-8><title>${escapeHtml(title)}</title></head>`,
5256
+ '<body style="font-family:system-ui,sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0">',
5257
+ '<div style="text-align:center">',
5258
+ `<h1>${escapeHtml(title)}</h1>`,
5259
+ `<p style="color:#666">${escapeHtml(body)}</p>`,
5260
+ "</div></body></html>"
5261
+ ].join("");
5262
+ }
5263
+
5258
5264
  // packages/mcp-oauth/src/client/pkce.ts
5259
5265
  import crypto4 from "node:crypto";
5260
5266
  function generateCodeVerifier() {
@@ -5503,8 +5509,8 @@ function normalizeBearerTokenType(value) {
5503
5509
  // packages/mcp-oauth/src/client/session-transaction.ts
5504
5510
  var queues = /* @__PURE__ */ new WeakMap();
5505
5511
  async function withOAuthSessionTransaction(store, resource, operation, options = {}) {
5506
- const timeoutMs = options.timeoutMs ?? 3e4;
5507
- if (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647)
5512
+ const timeoutMs = options.timeoutMs ?? Infinity;
5513
+ if (timeoutMs !== Infinity && (!Number.isSafeInteger(timeoutMs) || timeoutMs < 1 || timeoutMs > 2147483647))
5508
5514
  throw new Error("sessionLockTimeoutMs must be an integer from 1 to 2147483647 milliseconds");
5509
5515
  options.signal?.throwIfAborted();
5510
5516
  const started = performance.now();
@@ -5527,7 +5533,7 @@ async function withOAuthSessionTransaction(store, resource, operation, options =
5527
5533
  });
5528
5534
  const abort = () => rejectWait(options.signal?.reason);
5529
5535
  try {
5530
- timer = setTimeout(() => rejectWait(new Error("Timed out waiting for OAuth session transaction lock")), timeoutMs);
5536
+ if (timeoutMs !== Infinity) timer = setTimeout(() => rejectWait(new Error("Timed out waiting for OAuth session transaction lock")), timeoutMs);
5531
5537
  options.signal?.addEventListener("abort", abort, { once: true });
5532
5538
  if (options.signal?.aborted) abort();
5533
5539
  await waiting;
@@ -6418,15 +6424,15 @@ import {
6418
6424
 
6419
6425
  // packages/tiny-stdio-mcp-server/src/headers.ts
6420
6426
  function encodeHeaderValue(value) {
6421
- const bytes = Buffer.from(value, "utf8");
6422
- if (bytes.toString("utf8") !== value)
6427
+ const bytes = new TextEncoder().encode(value);
6428
+ if (new TextDecoder("utf-8", { ignoreBOM: true }).decode(bytes) !== value)
6423
6429
  throw new Error("MCP header value must contain valid Unicode");
6424
6430
  const sentinel = value.startsWith("=?base64?") && value.endsWith("?=");
6425
6431
  const unsafe = value.trim() !== value || [...value].some((character) => {
6426
6432
  const code = character.charCodeAt(0);
6427
6433
  return code !== 9 && (code < 32 || code > 126);
6428
6434
  });
6429
- return sentinel || unsafe ? `=?base64?${bytes.toString("base64")}?=` : value;
6435
+ return sentinel || unsafe ? `=?base64?${btoa(Array.from(bytes, (byte) => String.fromCharCode(byte)).join(""))}?=` : value;
6430
6436
  }
6431
6437
  var schemaMaps = /* @__PURE__ */ new Set([
6432
6438
  "properties",
@@ -8154,7 +8160,7 @@ var HttpTransport = class {
8154
8160
  if (this.legacyProtocolVersion !== void 0) headers.set("MCP-Protocol-Version", this.legacyProtocolVersion);
8155
8161
  if (this.lastEventId !== void 0) {
8156
8162
  if (this.lastEventId === "") headers.delete("Last-Event-ID");
8157
- else headers.set("Last-Event-ID", Buffer.from(this.lastEventId, "utf8").toString("latin1"));
8163
+ else headers.set("Last-Event-ID", Array.from(new TextEncoder().encode(this.lastEventId), (byte) => String.fromCharCode(byte)).join(""));
8158
8164
  }
8159
8165
  return this.authorizeRequestHeaders(headers, signal);
8160
8166
  }
@@ -8583,7 +8589,7 @@ async function* readLines(stream, maxLineBytes = 16 * 1024 * 1024) {
8583
8589
  let bytes = 0;
8584
8590
  const decoder = new TextDecoder("utf-8", { fatal: true });
8585
8591
  const append = (part) => {
8586
- bytes += Buffer.byteLength(part, "utf8");
8592
+ bytes += new TextEncoder().encode(part).byteLength;
8587
8593
  if (bytes > maxLineBytes) throw new Error(`Stdio input line byte limit exceeded (${maxLineBytes} bytes)`);
8588
8594
  if (part.length > 0) parts.push(part);
8589
8595
  };
@@ -8644,7 +8650,7 @@ var SseParser = class {
8644
8650
  else if (index === this.buffer.length - 1) this.skipLf = true;
8645
8651
  }
8646
8652
  start = index + 1;
8647
- if (Buffer.byteLength(line, "utf8") > this.maxEventBytes)
8653
+ if (new TextEncoder().encode(line).byteLength > this.maxEventBytes)
8648
8654
  throw new Error(`SSE event exceeds ${this.maxEventBytes} bytes`);
8649
8655
  this.consumeLine(line, messages);
8650
8656
  this.assertEventSize("");
@@ -8676,7 +8682,7 @@ var SseParser = class {
8676
8682
  return;
8677
8683
  }
8678
8684
  if (field === "data") {
8679
- this.dataBytes += Buffer.byteLength(value, "utf8") + (this.dataLines.length > 0 ? 1 : 0);
8685
+ this.dataBytes += new TextEncoder().encode(value).byteLength + (this.dataLines.length > 0 ? 1 : 0);
8680
8686
  this.dataLines.push(value);
8681
8687
  return;
8682
8688
  }
@@ -8715,7 +8721,7 @@ var SseParser = class {
8715
8721
  this.dataBytes = 0;
8716
8722
  }
8717
8723
  assertEventSize(partialLine) {
8718
- if (this.dataBytes + Buffer.byteLength(this.eventType ?? "", "utf8") + Buffer.byteLength(this.eventId, "utf8") + Buffer.byteLength(partialLine, "utf8") > this.maxEventBytes)
8724
+ if (this.dataBytes + new TextEncoder().encode(this.eventType ?? "").byteLength + new TextEncoder().encode(this.eventId).byteLength + new TextEncoder().encode(partialLine).byteLength > this.maxEventBytes)
8719
8725
  throw new Error(`SSE event exceeds ${this.maxEventBytes} bytes`);
8720
8726
  }
8721
8727
  };