@hfunlabs/hypurr-connect 0.1.23 → 0.1.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -49,7 +49,6 @@ const config = {
49
49
  grpcUrl: "https://grpc.hypurr.fun",
50
50
  telegram: {
51
51
  authHubUrl: "https://auth.hypurr.fun/login",
52
- // tokenUrl defaults to https://auth.hypurr.fun/token
53
52
  scope: [
54
53
  "telegram:user:read",
55
54
  "telegram:wallet:read",
@@ -127,7 +126,6 @@ interface HypurrConnectConfig {
127
126
  isTestnet?: boolean; // Use testnet endpoints (default: false)
128
127
  telegram: {
129
128
  authHubUrl?: string; // Auth hub URL (default: https://auth.hypurr.fun/login)
130
- tokenUrl?: string; // Token exchange URL (default: auth hub /token)
131
129
  returnTo?: string | (() => string); // Callback URL (default: current page)
132
130
  scope?: string | string[]; // Requested JWT scopes
133
131
  };
@@ -157,7 +155,8 @@ for generated protobuf service clients.
157
155
  4. The popup callback page posts `{ token, state }` or `{ code, state }` to the
158
156
  opener with `postMessage` and closes.
159
157
  5. The opener validates `state`. Legacy tokens are stored directly; auth codes
160
- are exchanged at the configured token URL with the stored PKCE verifier.
158
+ are exchanged at the OAuth metadata `token_endpoint` with the stored PKCE
159
+ verifier.
161
160
  6. The SDK calls the Hypurr gRPC backend with `Authorization: Bearer <jwt>`
162
161
  metadata.
163
162
  7. An `ExchangeClient` is created with `GrpcExchangeTransport`; exchange
package/dist/index.d.ts CHANGED
@@ -27,8 +27,6 @@ interface HypurrConnectConfig {
27
27
  telegram?: {
28
28
  /** Auth hub login URL. Defaults to https://auth.hypurr.fun/login. */
29
29
  authHubUrl?: string;
30
- /** Auth hub token exchange URL. Defaults to the auth hub login URL with `/login` replaced by `/token`. */
31
- tokenUrl?: string;
32
30
  /** Optional callback URL. Defaults to the current page without auth query params. */
33
31
  returnTo?: string | (() => string);
34
32
  /** Requested hub scopes. Defaults to the scopes required by this SDK. */
package/dist/index.js CHANGED
@@ -542,17 +542,51 @@ function takeTelegramAuthSession(state) {
542
542
  sessionStorage.removeItem(returnToKey);
543
543
  return { codeVerifier, returnTo };
544
544
  }
545
- function resolveAuthTokenUrl(authHubUrl, tokenUrl) {
546
- const configuredTokenUrl = tokenUrl?.trim();
547
- if (configuredTokenUrl) return configuredTokenUrl;
545
+ function fallbackAuthTokenUrl(authHubUrl) {
548
546
  const url = new URL(authHubUrl || DEFAULT_AUTH_HUB_URL);
549
- const pathWithoutTrailingSlash = url.pathname.replace(/\/+$/, "");
550
- const basePath = pathWithoutTrailingSlash.replace(/\/[^/]*$/, "");
551
- url.pathname = `${basePath}/token`;
547
+ url.pathname = "/oauth/token";
552
548
  url.search = "";
553
549
  url.hash = "";
554
550
  return url.toString();
555
551
  }
552
+ function authMetadataUrls(authHubUrl) {
553
+ const authUrl = new URL(authHubUrl || DEFAULT_AUTH_HUB_URL);
554
+ const urls = [
555
+ new URL("/.well-known/oauth-authorization-server", authUrl).toString(),
556
+ new URL("/.well-known/openid-configuration", authUrl).toString()
557
+ ];
558
+ const authPath = authUrl.pathname.replace(/\/+$/, "");
559
+ const basePath = authPath.replace(/\/[^/]*$/, "");
560
+ if (basePath) {
561
+ urls.push(
562
+ new URL(
563
+ `/.well-known/oauth-authorization-server${basePath}`,
564
+ authUrl
565
+ ).toString()
566
+ );
567
+ }
568
+ return Array.from(new Set(urls));
569
+ }
570
+ async function tokenUrlFromMetadata(authHubUrl) {
571
+ for (const metadataUrl of authMetadataUrls(authHubUrl)) {
572
+ try {
573
+ const response = await fetch(metadataUrl, {
574
+ headers: { accept: "application/json" }
575
+ });
576
+ if (!response.ok) continue;
577
+ const metadata = await response.json();
578
+ const tokenEndpoint = metadata.token_endpoint;
579
+ if (typeof tokenEndpoint === "string" && tokenEndpoint.trim()) {
580
+ return tokenEndpoint.trim();
581
+ }
582
+ } catch {
583
+ }
584
+ }
585
+ return void 0;
586
+ }
587
+ async function resolveAuthTokenUrl(authHubUrl) {
588
+ return await tokenUrlFromMetadata(authHubUrl) || fallbackAuthTokenUrl(authHubUrl);
589
+ }
556
590
  function getTokenFromExchangeResponse(data) {
557
591
  if (typeof data === "string") {
558
592
  const token = data.trim();
@@ -570,8 +604,7 @@ async function exchangeTelegramAuthCode({
570
604
  clientId,
571
605
  code,
572
606
  codeVerifier,
573
- returnTo,
574
- tokenUrl
607
+ returnTo
575
608
  }) {
576
609
  const body = new URLSearchParams({
577
610
  client_id: clientId,
@@ -580,7 +613,7 @@ async function exchangeTelegramAuthCode({
580
613
  grant_type: "authorization_code",
581
614
  return_to: returnTo
582
615
  });
583
- const response = await fetch(resolveAuthTokenUrl(authHubUrl, tokenUrl), {
616
+ const response = await fetch(await resolveAuthTokenUrl(authHubUrl), {
584
617
  method: "POST",
585
618
  headers: {
586
619
  accept: "application/json",
@@ -697,8 +730,7 @@ function HypurrConnectProvider({
697
730
  clientId: normalizeClientId(config.clientId),
698
731
  code: callback.code,
699
732
  codeVerifier: authSession.codeVerifier,
700
- returnTo: authSession.returnTo || currentReturnTo(),
701
- tokenUrl: config.telegram?.tokenUrl
733
+ returnTo: authSession.returnTo || currentReturnTo()
702
734
  }).then(acceptTelegramToken).catch(
703
735
  (err) => setTgError(err instanceof Error ? err.message : String(err))
704
736
  ).finally(() => setTgLoading(false));
@@ -713,8 +745,7 @@ function HypurrConnectProvider({
713
745
  [
714
746
  acceptTelegramToken,
715
747
  config.clientId,
716
- config.telegram?.authHubUrl,
717
- config.telegram?.tokenUrl
748
+ config.telegram?.authHubUrl
718
749
  ]
719
750
  );
720
751
  useEffect(() => {