@bagelink/auth 1.15.112 → 1.15.114

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/dist/index.cjs CHANGED
@@ -892,6 +892,26 @@ function getAllSSOProviders() {
892
892
  function isSupportedProvider(provider) {
893
893
  return provider in ssoProviders;
894
894
  }
895
+ function handleSsoPopup() {
896
+ if (typeof window === "undefined" || !window.opener || window.opener === window) {
897
+ return false;
898
+ }
899
+ const { code, state, error } = queryParams();
900
+ if (!code && !error) return false;
901
+ const provider = state && typeof sessionStorage !== "undefined" ? sessionStorage.getItem(`oauth_provider:${state}`) ?? void 0 : void 0;
902
+ try {
903
+ window.opener.postMessage(
904
+ { type: "auth:complete", provider, code: code || void 0, state, error: error || void 0 },
905
+ window.location.origin
906
+ );
907
+ } catch {
908
+ }
909
+ try {
910
+ window.close();
911
+ } catch {
912
+ }
913
+ return true;
914
+ }
895
915
  function handleOAuthCallback() {
896
916
  const { code, state } = queryParams();
897
917
  if (!code || !state) {
@@ -1618,6 +1638,7 @@ exports.getAllSSOProviders = getAllSSOProviders;
1618
1638
  exports.getRedirectConfig = getRedirectConfig;
1619
1639
  exports.getRedirectUrl = getRedirectUrl;
1620
1640
  exports.getSSOProvider = getSSOProvider;
1641
+ exports.handleSsoPopup = handleSsoPopup;
1621
1642
  exports.isSupportedProvider = isSupportedProvider;
1622
1643
  exports.isValidRedirect = isValidRedirect;
1623
1644
  exports.normalizeRedirectConfig = normalizeRedirectConfig;
package/dist/index.mjs CHANGED
@@ -890,6 +890,26 @@ function getAllSSOProviders() {
890
890
  function isSupportedProvider(provider) {
891
891
  return provider in ssoProviders;
892
892
  }
893
+ function handleSsoPopup() {
894
+ if (typeof window === "undefined" || !window.opener || window.opener === window) {
895
+ return false;
896
+ }
897
+ const { code, state, error } = queryParams();
898
+ if (!code && !error) return false;
899
+ const provider = state && typeof sessionStorage !== "undefined" ? sessionStorage.getItem(`oauth_provider:${state}`) ?? void 0 : void 0;
900
+ try {
901
+ window.opener.postMessage(
902
+ { type: "auth:complete", provider, code: code || void 0, state, error: error || void 0 },
903
+ window.location.origin
904
+ );
905
+ } catch {
906
+ }
907
+ try {
908
+ window.close();
909
+ } catch {
910
+ }
911
+ return true;
912
+ }
893
913
  function handleOAuthCallback() {
894
914
  const { code, state } = queryParams();
895
915
  if (!code || !state) {
@@ -1617,6 +1637,7 @@ export {
1617
1637
  getRedirectConfig,
1618
1638
  getRedirectUrl,
1619
1639
  getSSOProvider,
1640
+ handleSsoPopup,
1620
1641
  isSupportedProvider,
1621
1642
  isValidRedirect,
1622
1643
  normalizeRedirectConfig,
package/dist/sso.d.ts CHANGED
@@ -143,3 +143,27 @@ export declare function getAllSSOProviders(): readonly SSOProviderInstance[];
143
143
  * Check if a provider is supported
144
144
  */
145
145
  export declare function isSupportedProvider(provider: string): provider is SSOProvider;
146
+ /**
147
+ * Popup-mode OAuth landing handler.
148
+ *
149
+ * Call this **once at app startup, before the router mounts**. When the current
150
+ * page was opened as an OAuth popup (it has `?code`/`?state` — or `?error` — and
151
+ * a `window.opener`), it posts an `auth:complete` message back to the opener
152
+ * (which `sso.<provider>.popup()` is waiting for) and closes the popup.
153
+ *
154
+ * This lets a host app support popup SSO **without** a dedicated `/auth/callback`
155
+ * route or component — the whole flow stays on the original page.
156
+ *
157
+ * @returns `true` if it handled a popup callback (caller should stop bootstrapping
158
+ * the app — the window is closing), otherwise `false`.
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * import { handleSsoPopup } from '@bagelink/auth'
163
+ * if (handleSsoPopup()) { // we're the popup; do nothing else
164
+ * } else {
165
+ * app.mount('#app')
166
+ * }
167
+ * ```
168
+ */
169
+ export declare function handleSsoPopup(): boolean;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/auth",
3
3
  "type": "module",
4
- "version": "1.15.112",
4
+ "version": "1.15.114",
5
5
  "description": "Bagelink auth package",
6
6
  "author": {
7
7
  "name": "Bagel Studio",
package/src/sso.ts CHANGED
@@ -623,6 +623,59 @@ export function isSupportedProvider(provider: string): provider is SSOProvider {
623
623
  return provider in ssoProviders
624
624
  }
625
625
 
626
+ /**
627
+ * Popup-mode OAuth landing handler.
628
+ *
629
+ * Call this **once at app startup, before the router mounts**. When the current
630
+ * page was opened as an OAuth popup (it has `?code`/`?state` — or `?error` — and
631
+ * a `window.opener`), it posts an `auth:complete` message back to the opener
632
+ * (which `sso.<provider>.popup()` is waiting for) and closes the popup.
633
+ *
634
+ * This lets a host app support popup SSO **without** a dedicated `/auth/callback`
635
+ * route or component — the whole flow stays on the original page.
636
+ *
637
+ * @returns `true` if it handled a popup callback (caller should stop bootstrapping
638
+ * the app — the window is closing), otherwise `false`.
639
+ *
640
+ * @example
641
+ * ```ts
642
+ * import { handleSsoPopup } from '@bagelink/auth'
643
+ * if (handleSsoPopup()) { // we're the popup; do nothing else
644
+ * } else {
645
+ * app.mount('#app')
646
+ * }
647
+ * ```
648
+ */
649
+ export function handleSsoPopup(): boolean {
650
+ if (typeof window === 'undefined' || !window.opener || window.opener === window) {
651
+ return false
652
+ }
653
+
654
+ const { code, state, error } = queryParams()
655
+ if (!code && !error) return false
656
+
657
+ const provider = state && typeof sessionStorage !== 'undefined'
658
+ ? sessionStorage.getItem(`oauth_provider:${state}`) ?? undefined
659
+ : undefined
660
+
661
+ try {
662
+ window.opener.postMessage(
663
+ { type: 'auth:complete', provider, code: code || undefined, state, error: error || undefined },
664
+ window.location.origin,
665
+ )
666
+ } catch {
667
+ // Opener gone or cross-origin — the opener's polling fallback still works.
668
+ }
669
+
670
+ // Close the popup; the opener resolves via the message (or its poll).
671
+ try {
672
+ window.close()
673
+ } catch {
674
+ /* ignore */
675
+ }
676
+ return true
677
+ }
678
+
626
679
  /**
627
680
  * Handle OAuth callback from URL
628
681
  * Internal helper - use sso.handleCallback() instead