@cabin-id/nextjs 1.1.0 → 1.2.0

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.
@@ -35,6 +35,7 @@ module.exports = __toCommonJS(SignOutButton_exports);
35
35
  var import_react = __toESM(require("react"));
36
36
  var import_useUser = require("../hooks/useUser");
37
37
  var import_constants = require("../constants");
38
+ var import_subdomain = require("../utils/subdomain");
38
39
  const SignOutButton = ({
39
40
  children = "Sign Out",
40
41
  className = "px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50",
@@ -44,7 +45,9 @@ const SignOutButton = ({
44
45
  onSignOutError,
45
46
  showLoading = true,
46
47
  loadingText = "Signing out...",
47
- callBackend = true
48
+ callBackend = true,
49
+ cabinIdSubdomain,
50
+ useCrossDomainLogout = true
48
51
  }) => {
49
52
  const { signOut, isSignedIn, user } = (0, import_useUser.useUser)();
50
53
  const [isLoading, setIsLoading] = (0, import_react.useState)(false);
@@ -53,6 +56,33 @@ const SignOutButton = ({
53
56
  try {
54
57
  setIsLoading(true);
55
58
  onSignOutStart == null ? void 0 : onSignOutStart();
59
+ const subdomain = cabinIdSubdomain || (0, import_subdomain.detectCabinIdSubdomain)();
60
+ if (useCrossDomainLogout && subdomain) {
61
+ if (callBackend && user) {
62
+ try {
63
+ const token = getCookieValue("__client") || getCookieValue("__user");
64
+ if (token) {
65
+ await fetch(`${import_constants.baseApiUrl}/auth/sign-out`, {
66
+ method: "POST",
67
+ headers: {
68
+ "Content-Type": "application/json",
69
+ "Authorization": `Bearer ${token}`,
70
+ "Origin": typeof window !== "undefined" ? window.location.origin : ""
71
+ }
72
+ });
73
+ }
74
+ } catch (backendError) {
75
+ console.warn("Backend sign-out failed, proceeding with logout:", backendError);
76
+ }
77
+ }
78
+ await signOut(() => {
79
+ });
80
+ const currentDomain = typeof window !== "undefined" ? window.location.hostname : "";
81
+ const logoutUrl = `https://${subdomain}.cabinid.dev/${subdomain}/logout?redirect_url=${encodeURIComponent(currentDomain)}`;
82
+ onSignOutSuccess == null ? void 0 : onSignOutSuccess();
83
+ window.location.href = logoutUrl;
84
+ return;
85
+ }
56
86
  if (callBackend && user) {
57
87
  try {
58
88
  const token = getCookieValue("__client") || getCookieValue("__user");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/SignOutButton.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState } from 'react';\nimport { useUser, SignOutOptions } from '../hooks/useUser';\nimport { baseApiUrl } from '../constants';\n\nexport interface SignOutButtonProps {\n /**\n * Custom text to display on the button\n * @default \"Sign Out\"\n */\n children?: React.ReactNode;\n /**\n * Custom CSS class name\n */\n className?: string;\n /**\n * Sign out options\n */\n signOutOptions?: SignOutOptions;\n /**\n * Callback function called before sign out\n */\n onSignOutStart?: () => void;\n /**\n * Callback function called after successful sign out\n */\n onSignOutSuccess?: () => void;\n /**\n * Callback function called when sign out fails\n */\n onSignOutError?: (error: Error) => void;\n /**\n * Whether to show loading state\n * @default true\n */\n showLoading?: boolean;\n /**\n * Custom loading text\n * @default \"Signing out...\"\n */\n loadingText?: string;\n /**\n * Whether to call the backend sign-out endpoint\n * @default true\n */\n callBackend?: boolean;\n}\n\n/**\n * SignOutButton component that handles user logout with CabinID backend integration\n */\nexport const SignOutButton: React.FC<SignOutButtonProps> = ({\n children = 'Sign Out',\n className = 'px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50',\n signOutOptions,\n onSignOutStart,\n onSignOutSuccess,\n onSignOutError,\n showLoading = true,\n loadingText = 'Signing out...',\n callBackend = true,\n}) => {\n const { signOut, isSignedIn, user } = useUser();\n const [isLoading, setIsLoading] = useState(false);\n\n const handleSignOut = async () => {\n if (isLoading || !isSignedIn) return;\n\n try {\n setIsLoading(true);\n onSignOutStart?.();\n\n if (callBackend && user) {\n // Call the backend sign-out endpoint\n try {\n const token = getCookieValue('__client') || getCookieValue('__user');\n if (token) {\n await fetch(`${baseApiUrl}/auth/sign-out`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : '',\n },\n });\n }\n } catch (backendError) {\n console.warn('Backend sign-out failed, proceeding with client-side cleanup:', backendError);\n // Continue with client-side logout even if backend fails\n }\n }\n\n // Perform client-side sign out\n await signOut(signOutOptions);\n onSignOutSuccess?.();\n } catch (error) {\n console.error('Sign out error:', error);\n onSignOutError?.(error as Error);\n } finally {\n setIsLoading(false);\n }\n };\n\n // Helper function to get cookie value\n const getCookieValue = (name: string): string | null => {\n if (typeof window === 'undefined') return null;\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || null;\n }\n return null;\n };\n\n // Don't render if user is not signed in\n if (!isSignedIn) {\n return null;\n }\n\n return (\n <button\n onClick={handleSignOut}\n disabled={isLoading}\n className={className}\n type=\"button\"\n >\n {isLoading && showLoading ? loadingText : children}\n </button>\n );\n};"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,mBAAgC;AAChC,qBAAwC;AACxC,uBAA2B;AAgDpB,MAAM,gBAA8C,CAAC;AAAA,EAC1D,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAChB,MAAM;AACJ,QAAM,EAAE,SAAS,YAAY,KAAK,QAAI,wBAAQ;AAC9C,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAEhD,QAAM,gBAAgB,YAAY;AAChC,QAAI,aAAa,CAAC,WAAY;AAE9B,QAAI;AACF,mBAAa,IAAI;AACjB;AAEA,UAAI,eAAe,MAAM;AAEvB,YAAI;AACF,gBAAM,QAAQ,eAAe,UAAU,KAAK,eAAe,QAAQ;AACnE,cAAI,OAAO;AACT,kBAAM,MAAM,GAAG,2BAAU,kBAAkB;AAAA,cACzC,QAAQ;AAAA,cACR,SAAS;AAAA,gBACP,gBAAgB;AAAA,gBAChB,iBAAiB,UAAU,KAAK;AAAA,gBAChC,UAAU,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS;AAAA,cACrE;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,SAAS,cAAc;AACrB,kBAAQ,KAAK,iEAAiE,YAAY;AAAA,QAE5F;AAAA,MACF;AAGA,YAAM,QAAQ,cAAc;AAC5B;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,mBAAmB,KAAK;AACtC,uDAAiB;AAAA,IACnB,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAGA,QAAM,iBAAiB,CAAC,SAAgC;AAzG1D;AA0GI,QAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,UAAM,QAAQ,KAAK,SAAS,MAAM;AAClC,UAAM,QAAQ,MAAM,MAAM,KAAK,IAAI,GAAG;AACtC,QAAI,MAAM,WAAW,GAAG;AACtB,eAAO,WAAM,IAAI,MAAV,mBAAa,MAAM,KAAK,YAAW;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AAGA,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,SACE,6BAAAA,QAAA;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA,MAAK;AAAA;AAAA,IAEJ,aAAa,cAAc,cAAc;AAAA,EAC5C;AAEJ;","names":["React"]}
1
+ {"version":3,"sources":["../../../src/components/SignOutButton.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState } from 'react';\nimport { useUser, SignOutOptions } from '../hooks/useUser';\nimport { baseApiUrl } from '../constants';\nimport { detectCabinIdSubdomain } from '../utils/subdomain';\n\nexport interface SignOutButtonProps {\n /**\n * Custom text to display on the button\n * @default \"Sign Out\"\n */\n children?: React.ReactNode;\n /**\n * Custom CSS class name\n */\n className?: string;\n /**\n * Sign out options\n */\n signOutOptions?: SignOutOptions;\n /**\n * Callback function called before sign out\n */\n onSignOutStart?: () => void;\n /**\n * Callback function called after successful sign out\n */\n onSignOutSuccess?: () => void;\n /**\n * Callback function called when sign out fails\n */\n onSignOutError?: (error: Error) => void;\n /**\n * Whether to show loading state\n * @default true\n */\n showLoading?: boolean;\n /**\n * Custom loading text\n * @default \"Signing out...\"\n */\n loadingText?: string;\n /**\n * Whether to call the backend sign-out endpoint\n * @default true\n */\n callBackend?: boolean;\n /**\n * CabinID subdomain for cross-domain logout\n * @example \"myapp\" for myapp.cabinid.dev\n */\n cabinIdSubdomain?: string;\n /**\n * Whether to use cross-domain logout flow\n * @default true\n */\n useCrossDomainLogout?: boolean;\n}\n\n/**\n * SignOutButton component that handles user logout with CabinID backend integration\n */\nexport const SignOutButton: React.FC<SignOutButtonProps> = ({\n children = 'Sign Out',\n className = 'px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50',\n signOutOptions,\n onSignOutStart,\n onSignOutSuccess,\n onSignOutError,\n showLoading = true,\n loadingText = 'Signing out...',\n callBackend = true,\n cabinIdSubdomain,\n useCrossDomainLogout = true,\n}) => {\n const { signOut, isSignedIn, user } = useUser();\n const [isLoading, setIsLoading] = useState(false);\n\n const handleSignOut = async () => {\n if (isLoading || !isSignedIn) return;\n\n try {\n setIsLoading(true);\n onSignOutStart?.();\n\n // Cross-domain logout flow\n const subdomain = cabinIdSubdomain || detectCabinIdSubdomain();\n if (useCrossDomainLogout && subdomain) {\n // Call backend sign-out endpoint first\n if (callBackend && user) {\n try {\n const token = getCookieValue('__client') || getCookieValue('__user');\n if (token) {\n await fetch(`${baseApiUrl}/auth/sign-out`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : '',\n },\n });\n }\n } catch (backendError) {\n console.warn('Backend sign-out failed, proceeding with logout:', backendError);\n }\n }\n\n // Clear local cookies and storage\n await signOut(() => {\n // Don't redirect yet, we'll handle it manually\n });\n\n // Redirect to CabinID logout page for complete cleanup\n const currentDomain = typeof window !== 'undefined' ? window.location.hostname : '';\n const logoutUrl = `https://${subdomain}.cabinid.dev/${subdomain}/logout?redirect_url=${encodeURIComponent(currentDomain)}`;\n \n onSignOutSuccess?.();\n window.location.href = logoutUrl;\n return;\n }\n\n // Standard logout flow (backward compatibility)\n if (callBackend && user) {\n try {\n const token = getCookieValue('__client') || getCookieValue('__user');\n if (token) {\n await fetch(`${baseApiUrl}/auth/sign-out`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : '',\n },\n });\n }\n } catch (backendError) {\n console.warn('Backend sign-out failed, proceeding with client-side cleanup:', backendError);\n }\n }\n\n await signOut(signOutOptions);\n onSignOutSuccess?.();\n } catch (error) {\n console.error('Sign out error:', error);\n onSignOutError?.(error as Error);\n } finally {\n setIsLoading(false);\n }\n };\n\n // Helper function to get cookie value\n const getCookieValue = (name: string): string | null => {\n if (typeof window === 'undefined') return null;\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || null;\n }\n return null;\n };\n\n // Don't render if user is not signed in\n if (!isSignedIn) {\n return null;\n }\n\n return (\n <button\n onClick={handleSignOut}\n disabled={isLoading}\n className={className}\n type=\"button\"\n >\n {isLoading && showLoading ? loadingText : children}\n </button>\n );\n};"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,mBAAgC;AAChC,qBAAwC;AACxC,uBAA2B;AAC3B,uBAAuC;AA0DhC,MAAM,gBAA8C,CAAC;AAAA,EAC1D,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA,EACd;AAAA,EACA,uBAAuB;AACzB,MAAM;AACJ,QAAM,EAAE,SAAS,YAAY,KAAK,QAAI,wBAAQ;AAC9C,QAAM,CAAC,WAAW,YAAY,QAAI,uBAAS,KAAK;AAEhD,QAAM,gBAAgB,YAAY;AAChC,QAAI,aAAa,CAAC,WAAY;AAE9B,QAAI;AACF,mBAAa,IAAI;AACjB;AAGA,YAAM,YAAY,wBAAoB,yCAAuB;AAC7D,UAAI,wBAAwB,WAAW;AAErC,YAAI,eAAe,MAAM;AACvB,cAAI;AACF,kBAAM,QAAQ,eAAe,UAAU,KAAK,eAAe,QAAQ;AACnE,gBAAI,OAAO;AACT,oBAAM,MAAM,GAAG,2BAAU,kBAAkB;AAAA,gBACzC,QAAQ;AAAA,gBACR,SAAS;AAAA,kBACP,gBAAgB;AAAA,kBAChB,iBAAiB,UAAU,KAAK;AAAA,kBAChC,UAAU,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS;AAAA,gBACrE;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF,SAAS,cAAc;AACrB,oBAAQ,KAAK,oDAAoD,YAAY;AAAA,UAC/E;AAAA,QACF;AAGA,cAAM,QAAQ,MAAM;AAAA,QAEpB,CAAC;AAGD,cAAM,gBAAgB,OAAO,WAAW,cAAc,OAAO,SAAS,WAAW;AACjF,cAAM,YAAY,WAAW,SAAS,gBAAgB,SAAS,wBAAwB,mBAAmB,aAAa,CAAC;AAExH;AACA,eAAO,SAAS,OAAO;AACvB;AAAA,MACF;AAGA,UAAI,eAAe,MAAM;AACvB,YAAI;AACF,gBAAM,QAAQ,eAAe,UAAU,KAAK,eAAe,QAAQ;AACnE,cAAI,OAAO;AACT,kBAAM,MAAM,GAAG,2BAAU,kBAAkB;AAAA,cACzC,QAAQ;AAAA,cACR,SAAS;AAAA,gBACP,gBAAgB;AAAA,gBAChB,iBAAiB,UAAU,KAAK;AAAA,gBAChC,UAAU,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS;AAAA,cACrE;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,SAAS,cAAc;AACrB,kBAAQ,KAAK,iEAAiE,YAAY;AAAA,QAC5F;AAAA,MACF;AAEA,YAAM,QAAQ,cAAc;AAC5B;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,mBAAmB,KAAK;AACtC,uDAAiB;AAAA,IACnB,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAGA,QAAM,iBAAiB,CAAC,SAAgC;AAxJ1D;AAyJI,QAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,UAAM,QAAQ,KAAK,SAAS,MAAM;AAClC,UAAM,QAAQ,MAAM,MAAM,KAAK,IAAI,GAAG;AACtC,QAAI,MAAM,WAAW,GAAG;AACtB,eAAO,WAAM,IAAI,MAAV,mBAAa,MAAM,KAAK,YAAW;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AAGA,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,SACE,6BAAAA,QAAA;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA,MAAK;AAAA;AAAA,IAEJ,aAAa,cAAc,cAAc;AAAA,EAC5C;AAEJ;","names":["React"]}
package/dist/cjs/index.js CHANGED
@@ -23,7 +23,10 @@ __export(index_exports, {
23
23
  SignOutButton: () => import_components.SignOutButton,
24
24
  auth: () => import_auth.auth,
25
25
  authMiddleware: () => import_middleware.authMiddleware,
26
+ clearCabinIdSubdomain: () => import_subdomain.clearCabinIdSubdomain,
26
27
  currentUser: () => import_getCurrentUser.currentUser,
28
+ detectCabinIdSubdomain: () => import_subdomain.detectCabinIdSubdomain,
29
+ storeCabinIdSubdomain: () => import_subdomain.storeCabinIdSubdomain,
27
30
  useUser: () => import_hooks.useUser
28
31
  });
29
32
  module.exports = __toCommonJS(index_exports);
@@ -34,6 +37,7 @@ var import_main = require("./provider/main.provider");
34
37
  var import_hooks = require("./hooks");
35
38
  var import_middleware = require("./server/middleware");
36
39
  var import_components = require("./components");
40
+ var import_subdomain = require("./utils/subdomain");
37
41
  // Annotate the CommonJS export names for ESM import in node:
38
42
  0 && (module.exports = {
39
43
  CabinIDProvider,
@@ -41,7 +45,10 @@ var import_components = require("./components");
41
45
  SignOutButton,
42
46
  auth,
43
47
  authMiddleware,
48
+ clearCabinIdSubdomain,
44
49
  currentUser,
50
+ detectCabinIdSubdomain,
51
+ storeCabinIdSubdomain,
45
52
  useUser
46
53
  });
47
54
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import './styles/global.css';\n\nexport { auth } from './server/auth';\nexport { currentUser } from './server/getCurrentUser';\nexport { CabinIDProvider } from './provider/main.provider';\nexport { useUser } from './hooks';\nexport { authMiddleware } from './server/middleware';\nexport { SignInButton, SignOutButton } from './components';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAO;AAEP,kBAAqB;AACrB,4BAA4B;AAC5B,kBAAgC;AAChC,mBAAwB;AACxB,wBAA+B;AAC/B,wBAA4C;","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import './styles/global.css';\n\nexport { auth } from './server/auth';\nexport { currentUser } from './server/getCurrentUser';\nexport { CabinIDProvider } from './provider/main.provider';\nexport { useUser } from './hooks';\nexport { authMiddleware } from './server/middleware';\nexport { SignInButton, SignOutButton } from './components';\nexport { detectCabinIdSubdomain, storeCabinIdSubdomain, clearCabinIdSubdomain } from './utils/subdomain';\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAO;AAEP,kBAAqB;AACrB,4BAA4B;AAC5B,kBAAgC;AAChC,mBAAwB;AACxB,wBAA+B;AAC/B,wBAA4C;AAC5C,uBAAqF;","names":[]}
@@ -0,0 +1,62 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var subdomain_exports = {};
20
+ __export(subdomain_exports, {
21
+ clearCabinIdSubdomain: () => clearCabinIdSubdomain,
22
+ detectCabinIdSubdomain: () => detectCabinIdSubdomain,
23
+ storeCabinIdSubdomain: () => storeCabinIdSubdomain
24
+ });
25
+ module.exports = __toCommonJS(subdomain_exports);
26
+ const detectCabinIdSubdomain = () => {
27
+ if (typeof window === "undefined") return null;
28
+ const referrer = document.referrer;
29
+ if (referrer) {
30
+ const referrerMatch = referrer.match(/https?:\/\/([^.]+)\.cabinid\.dev/);
31
+ if (referrerMatch) {
32
+ return referrerMatch[1];
33
+ }
34
+ }
35
+ const storedSubdomain = localStorage.getItem("cabinid_subdomain");
36
+ if (storedSubdomain) {
37
+ return storedSubdomain;
38
+ }
39
+ const urlParams = new URLSearchParams(window.location.search);
40
+ const subdomainParam = urlParams.get("cabinid_subdomain");
41
+ if (subdomainParam) {
42
+ return subdomainParam;
43
+ }
44
+ return null;
45
+ };
46
+ const storeCabinIdSubdomain = (subdomain) => {
47
+ if (typeof window !== "undefined") {
48
+ localStorage.setItem("cabinid_subdomain", subdomain);
49
+ }
50
+ };
51
+ const clearCabinIdSubdomain = () => {
52
+ if (typeof window !== "undefined") {
53
+ localStorage.removeItem("cabinid_subdomain");
54
+ }
55
+ };
56
+ // Annotate the CommonJS export names for ESM import in node:
57
+ 0 && (module.exports = {
58
+ clearCabinIdSubdomain,
59
+ detectCabinIdSubdomain,
60
+ storeCabinIdSubdomain
61
+ });
62
+ //# sourceMappingURL=subdomain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/utils/subdomain.ts"],"sourcesContent":["/**\n * Utility functions for handling CabinID subdomain detection\n */\n\n/**\n * Extracts the CabinID subdomain from referrer or current URL\n * @returns The subdomain if detected, null otherwise\n */\nexport const detectCabinIdSubdomain = (): string | null => {\n if (typeof window === 'undefined') return null;\n\n // Check referrer first (where user came from during authentication flow)\n const referrer = document.referrer;\n if (referrer) {\n const referrerMatch = referrer.match(/https?:\\/\\/([^.]+)\\.cabinid\\.dev/);\n if (referrerMatch) {\n return referrerMatch[1];\n }\n }\n\n // Check if there's a stored subdomain from authentication flow\n const storedSubdomain = localStorage.getItem('cabinid_subdomain');\n if (storedSubdomain) {\n return storedSubdomain;\n }\n\n // Check URL parameters for subdomain hint\n const urlParams = new URLSearchParams(window.location.search);\n const subdomainParam = urlParams.get('cabinid_subdomain');\n if (subdomainParam) {\n return subdomainParam;\n }\n\n return null;\n};\n\n/**\n * Stores the CabinID subdomain for later use\n * @param subdomain The subdomain to store\n */\nexport const storeCabinIdSubdomain = (subdomain: string): void => {\n if (typeof window !== 'undefined') {\n localStorage.setItem('cabinid_subdomain', subdomain);\n }\n};\n\n/**\n * Clears the stored CabinID subdomain\n */\nexport const clearCabinIdSubdomain = (): void => {\n if (typeof window !== 'undefined') {\n localStorage.removeItem('cabinid_subdomain');\n }\n};"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAQO,MAAM,yBAAyB,MAAqB;AACzD,MAAI,OAAO,WAAW,YAAa,QAAO;AAG1C,QAAM,WAAW,SAAS;AAC1B,MAAI,UAAU;AACZ,UAAM,gBAAgB,SAAS,MAAM,kCAAkC;AACvE,QAAI,eAAe;AACjB,aAAO,cAAc,CAAC;AAAA,IACxB;AAAA,EACF;AAGA,QAAM,kBAAkB,aAAa,QAAQ,mBAAmB;AAChE,MAAI,iBAAiB;AACnB,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,IAAI,gBAAgB,OAAO,SAAS,MAAM;AAC5D,QAAM,iBAAiB,UAAU,IAAI,mBAAmB;AACxD,MAAI,gBAAgB;AAClB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMO,MAAM,wBAAwB,CAAC,cAA4B;AAChE,MAAI,OAAO,WAAW,aAAa;AACjC,iBAAa,QAAQ,qBAAqB,SAAS;AAAA,EACrD;AACF;AAKO,MAAM,wBAAwB,MAAY;AAC/C,MAAI,OAAO,WAAW,aAAa;AACjC,iBAAa,WAAW,mBAAmB;AAAA,EAC7C;AACF;","names":[]}
@@ -2,6 +2,7 @@
2
2
  import React, { useState } from "react";
3
3
  import { useUser } from "../hooks/useUser";
4
4
  import { baseApiUrl } from "../constants";
5
+ import { detectCabinIdSubdomain } from "../utils/subdomain";
5
6
  const SignOutButton = ({
6
7
  children = "Sign Out",
7
8
  className = "px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50",
@@ -11,7 +12,9 @@ const SignOutButton = ({
11
12
  onSignOutError,
12
13
  showLoading = true,
13
14
  loadingText = "Signing out...",
14
- callBackend = true
15
+ callBackend = true,
16
+ cabinIdSubdomain,
17
+ useCrossDomainLogout = true
15
18
  }) => {
16
19
  const { signOut, isSignedIn, user } = useUser();
17
20
  const [isLoading, setIsLoading] = useState(false);
@@ -20,6 +23,33 @@ const SignOutButton = ({
20
23
  try {
21
24
  setIsLoading(true);
22
25
  onSignOutStart == null ? void 0 : onSignOutStart();
26
+ const subdomain = cabinIdSubdomain || detectCabinIdSubdomain();
27
+ if (useCrossDomainLogout && subdomain) {
28
+ if (callBackend && user) {
29
+ try {
30
+ const token = getCookieValue("__client") || getCookieValue("__user");
31
+ if (token) {
32
+ await fetch(`${baseApiUrl}/auth/sign-out`, {
33
+ method: "POST",
34
+ headers: {
35
+ "Content-Type": "application/json",
36
+ "Authorization": `Bearer ${token}`,
37
+ "Origin": typeof window !== "undefined" ? window.location.origin : ""
38
+ }
39
+ });
40
+ }
41
+ } catch (backendError) {
42
+ console.warn("Backend sign-out failed, proceeding with logout:", backendError);
43
+ }
44
+ }
45
+ await signOut(() => {
46
+ });
47
+ const currentDomain = typeof window !== "undefined" ? window.location.hostname : "";
48
+ const logoutUrl = `https://${subdomain}.cabinid.dev/${subdomain}/logout?redirect_url=${encodeURIComponent(currentDomain)}`;
49
+ onSignOutSuccess == null ? void 0 : onSignOutSuccess();
50
+ window.location.href = logoutUrl;
51
+ return;
52
+ }
23
53
  if (callBackend && user) {
24
54
  try {
25
55
  const token = getCookieValue("__client") || getCookieValue("__user");
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/SignOutButton.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState } from 'react';\nimport { useUser, SignOutOptions } from '../hooks/useUser';\nimport { baseApiUrl } from '../constants';\n\nexport interface SignOutButtonProps {\n /**\n * Custom text to display on the button\n * @default \"Sign Out\"\n */\n children?: React.ReactNode;\n /**\n * Custom CSS class name\n */\n className?: string;\n /**\n * Sign out options\n */\n signOutOptions?: SignOutOptions;\n /**\n * Callback function called before sign out\n */\n onSignOutStart?: () => void;\n /**\n * Callback function called after successful sign out\n */\n onSignOutSuccess?: () => void;\n /**\n * Callback function called when sign out fails\n */\n onSignOutError?: (error: Error) => void;\n /**\n * Whether to show loading state\n * @default true\n */\n showLoading?: boolean;\n /**\n * Custom loading text\n * @default \"Signing out...\"\n */\n loadingText?: string;\n /**\n * Whether to call the backend sign-out endpoint\n * @default true\n */\n callBackend?: boolean;\n}\n\n/**\n * SignOutButton component that handles user logout with CabinID backend integration\n */\nexport const SignOutButton: React.FC<SignOutButtonProps> = ({\n children = 'Sign Out',\n className = 'px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50',\n signOutOptions,\n onSignOutStart,\n onSignOutSuccess,\n onSignOutError,\n showLoading = true,\n loadingText = 'Signing out...',\n callBackend = true,\n}) => {\n const { signOut, isSignedIn, user } = useUser();\n const [isLoading, setIsLoading] = useState(false);\n\n const handleSignOut = async () => {\n if (isLoading || !isSignedIn) return;\n\n try {\n setIsLoading(true);\n onSignOutStart?.();\n\n if (callBackend && user) {\n // Call the backend sign-out endpoint\n try {\n const token = getCookieValue('__client') || getCookieValue('__user');\n if (token) {\n await fetch(`${baseApiUrl}/auth/sign-out`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : '',\n },\n });\n }\n } catch (backendError) {\n console.warn('Backend sign-out failed, proceeding with client-side cleanup:', backendError);\n // Continue with client-side logout even if backend fails\n }\n }\n\n // Perform client-side sign out\n await signOut(signOutOptions);\n onSignOutSuccess?.();\n } catch (error) {\n console.error('Sign out error:', error);\n onSignOutError?.(error as Error);\n } finally {\n setIsLoading(false);\n }\n };\n\n // Helper function to get cookie value\n const getCookieValue = (name: string): string | null => {\n if (typeof window === 'undefined') return null;\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || null;\n }\n return null;\n };\n\n // Don't render if user is not signed in\n if (!isSignedIn) {\n return null;\n }\n\n return (\n <button\n onClick={handleSignOut}\n disabled={isLoading}\n className={className}\n type=\"button\"\n >\n {isLoading && showLoading ? loadingText : children}\n </button>\n );\n};"],"mappings":";AAEA,OAAO,SAAS,gBAAgB;AAChC,SAAS,eAA+B;AACxC,SAAS,kBAAkB;AAgDpB,MAAM,gBAA8C,CAAC;AAAA,EAC1D,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAChB,MAAM;AACJ,QAAM,EAAE,SAAS,YAAY,KAAK,IAAI,QAAQ;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,QAAM,gBAAgB,YAAY;AAChC,QAAI,aAAa,CAAC,WAAY;AAE9B,QAAI;AACF,mBAAa,IAAI;AACjB;AAEA,UAAI,eAAe,MAAM;AAEvB,YAAI;AACF,gBAAM,QAAQ,eAAe,UAAU,KAAK,eAAe,QAAQ;AACnE,cAAI,OAAO;AACT,kBAAM,MAAM,GAAG,UAAU,kBAAkB;AAAA,cACzC,QAAQ;AAAA,cACR,SAAS;AAAA,gBACP,gBAAgB;AAAA,gBAChB,iBAAiB,UAAU,KAAK;AAAA,gBAChC,UAAU,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS;AAAA,cACrE;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,SAAS,cAAc;AACrB,kBAAQ,KAAK,iEAAiE,YAAY;AAAA,QAE5F;AAAA,MACF;AAGA,YAAM,QAAQ,cAAc;AAC5B;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,mBAAmB,KAAK;AACtC,uDAAiB;AAAA,IACnB,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAGA,QAAM,iBAAiB,CAAC,SAAgC;AAzG1D;AA0GI,QAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,UAAM,QAAQ,KAAK,SAAS,MAAM;AAClC,UAAM,QAAQ,MAAM,MAAM,KAAK,IAAI,GAAG;AACtC,QAAI,MAAM,WAAW,GAAG;AACtB,eAAO,WAAM,IAAI,MAAV,mBAAa,MAAM,KAAK,YAAW;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AAGA,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA,MAAK;AAAA;AAAA,IAEJ,aAAa,cAAc,cAAc;AAAA,EAC5C;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../src/components/SignOutButton.tsx"],"sourcesContent":["'use client';\n\nimport React, { useState } from 'react';\nimport { useUser, SignOutOptions } from '../hooks/useUser';\nimport { baseApiUrl } from '../constants';\nimport { detectCabinIdSubdomain } from '../utils/subdomain';\n\nexport interface SignOutButtonProps {\n /**\n * Custom text to display on the button\n * @default \"Sign Out\"\n */\n children?: React.ReactNode;\n /**\n * Custom CSS class name\n */\n className?: string;\n /**\n * Sign out options\n */\n signOutOptions?: SignOutOptions;\n /**\n * Callback function called before sign out\n */\n onSignOutStart?: () => void;\n /**\n * Callback function called after successful sign out\n */\n onSignOutSuccess?: () => void;\n /**\n * Callback function called when sign out fails\n */\n onSignOutError?: (error: Error) => void;\n /**\n * Whether to show loading state\n * @default true\n */\n showLoading?: boolean;\n /**\n * Custom loading text\n * @default \"Signing out...\"\n */\n loadingText?: string;\n /**\n * Whether to call the backend sign-out endpoint\n * @default true\n */\n callBackend?: boolean;\n /**\n * CabinID subdomain for cross-domain logout\n * @example \"myapp\" for myapp.cabinid.dev\n */\n cabinIdSubdomain?: string;\n /**\n * Whether to use cross-domain logout flow\n * @default true\n */\n useCrossDomainLogout?: boolean;\n}\n\n/**\n * SignOutButton component that handles user logout with CabinID backend integration\n */\nexport const SignOutButton: React.FC<SignOutButtonProps> = ({\n children = 'Sign Out',\n className = 'px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700 disabled:opacity-50',\n signOutOptions,\n onSignOutStart,\n onSignOutSuccess,\n onSignOutError,\n showLoading = true,\n loadingText = 'Signing out...',\n callBackend = true,\n cabinIdSubdomain,\n useCrossDomainLogout = true,\n}) => {\n const { signOut, isSignedIn, user } = useUser();\n const [isLoading, setIsLoading] = useState(false);\n\n const handleSignOut = async () => {\n if (isLoading || !isSignedIn) return;\n\n try {\n setIsLoading(true);\n onSignOutStart?.();\n\n // Cross-domain logout flow\n const subdomain = cabinIdSubdomain || detectCabinIdSubdomain();\n if (useCrossDomainLogout && subdomain) {\n // Call backend sign-out endpoint first\n if (callBackend && user) {\n try {\n const token = getCookieValue('__client') || getCookieValue('__user');\n if (token) {\n await fetch(`${baseApiUrl}/auth/sign-out`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : '',\n },\n });\n }\n } catch (backendError) {\n console.warn('Backend sign-out failed, proceeding with logout:', backendError);\n }\n }\n\n // Clear local cookies and storage\n await signOut(() => {\n // Don't redirect yet, we'll handle it manually\n });\n\n // Redirect to CabinID logout page for complete cleanup\n const currentDomain = typeof window !== 'undefined' ? window.location.hostname : '';\n const logoutUrl = `https://${subdomain}.cabinid.dev/${subdomain}/logout?redirect_url=${encodeURIComponent(currentDomain)}`;\n \n onSignOutSuccess?.();\n window.location.href = logoutUrl;\n return;\n }\n\n // Standard logout flow (backward compatibility)\n if (callBackend && user) {\n try {\n const token = getCookieValue('__client') || getCookieValue('__user');\n if (token) {\n await fetch(`${baseApiUrl}/auth/sign-out`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${token}`,\n 'Origin': typeof window !== 'undefined' ? window.location.origin : '',\n },\n });\n }\n } catch (backendError) {\n console.warn('Backend sign-out failed, proceeding with client-side cleanup:', backendError);\n }\n }\n\n await signOut(signOutOptions);\n onSignOutSuccess?.();\n } catch (error) {\n console.error('Sign out error:', error);\n onSignOutError?.(error as Error);\n } finally {\n setIsLoading(false);\n }\n };\n\n // Helper function to get cookie value\n const getCookieValue = (name: string): string | null => {\n if (typeof window === 'undefined') return null;\n const value = `; ${document.cookie}`;\n const parts = value.split(`; ${name}=`);\n if (parts.length === 2) {\n return parts.pop()?.split(';').shift() || null;\n }\n return null;\n };\n\n // Don't render if user is not signed in\n if (!isSignedIn) {\n return null;\n }\n\n return (\n <button\n onClick={handleSignOut}\n disabled={isLoading}\n className={className}\n type=\"button\"\n >\n {isLoading && showLoading ? loadingText : children}\n </button>\n );\n};"],"mappings":";AAEA,OAAO,SAAS,gBAAgB;AAChC,SAAS,eAA+B;AACxC,SAAS,kBAAkB;AAC3B,SAAS,8BAA8B;AA0DhC,MAAM,gBAA8C,CAAC;AAAA,EAC1D,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA,EACd;AAAA,EACA,uBAAuB;AACzB,MAAM;AACJ,QAAM,EAAE,SAAS,YAAY,KAAK,IAAI,QAAQ;AAC9C,QAAM,CAAC,WAAW,YAAY,IAAI,SAAS,KAAK;AAEhD,QAAM,gBAAgB,YAAY;AAChC,QAAI,aAAa,CAAC,WAAY;AAE9B,QAAI;AACF,mBAAa,IAAI;AACjB;AAGA,YAAM,YAAY,oBAAoB,uBAAuB;AAC7D,UAAI,wBAAwB,WAAW;AAErC,YAAI,eAAe,MAAM;AACvB,cAAI;AACF,kBAAM,QAAQ,eAAe,UAAU,KAAK,eAAe,QAAQ;AACnE,gBAAI,OAAO;AACT,oBAAM,MAAM,GAAG,UAAU,kBAAkB;AAAA,gBACzC,QAAQ;AAAA,gBACR,SAAS;AAAA,kBACP,gBAAgB;AAAA,kBAChB,iBAAiB,UAAU,KAAK;AAAA,kBAChC,UAAU,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS;AAAA,gBACrE;AAAA,cACF,CAAC;AAAA,YACH;AAAA,UACF,SAAS,cAAc;AACrB,oBAAQ,KAAK,oDAAoD,YAAY;AAAA,UAC/E;AAAA,QACF;AAGA,cAAM,QAAQ,MAAM;AAAA,QAEpB,CAAC;AAGD,cAAM,gBAAgB,OAAO,WAAW,cAAc,OAAO,SAAS,WAAW;AACjF,cAAM,YAAY,WAAW,SAAS,gBAAgB,SAAS,wBAAwB,mBAAmB,aAAa,CAAC;AAExH;AACA,eAAO,SAAS,OAAO;AACvB;AAAA,MACF;AAGA,UAAI,eAAe,MAAM;AACvB,YAAI;AACF,gBAAM,QAAQ,eAAe,UAAU,KAAK,eAAe,QAAQ;AACnE,cAAI,OAAO;AACT,kBAAM,MAAM,GAAG,UAAU,kBAAkB;AAAA,cACzC,QAAQ;AAAA,cACR,SAAS;AAAA,gBACP,gBAAgB;AAAA,gBAChB,iBAAiB,UAAU,KAAK;AAAA,gBAChC,UAAU,OAAO,WAAW,cAAc,OAAO,SAAS,SAAS;AAAA,cACrE;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF,SAAS,cAAc;AACrB,kBAAQ,KAAK,iEAAiE,YAAY;AAAA,QAC5F;AAAA,MACF;AAEA,YAAM,QAAQ,cAAc;AAC5B;AAAA,IACF,SAAS,OAAO;AACd,cAAQ,MAAM,mBAAmB,KAAK;AACtC,uDAAiB;AAAA,IACnB,UAAE;AACA,mBAAa,KAAK;AAAA,IACpB;AAAA,EACF;AAGA,QAAM,iBAAiB,CAAC,SAAgC;AAxJ1D;AAyJI,QAAI,OAAO,WAAW,YAAa,QAAO;AAC1C,UAAM,QAAQ,KAAK,SAAS,MAAM;AAClC,UAAM,QAAQ,MAAM,MAAM,KAAK,IAAI,GAAG;AACtC,QAAI,MAAM,WAAW,GAAG;AACtB,eAAO,WAAM,IAAI,MAAV,mBAAa,MAAM,KAAK,YAAW;AAAA,IAC5C;AACA,WAAO;AAAA,EACT;AAGA,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,SACE;AAAA,IAAC;AAAA;AAAA,MACC,SAAS;AAAA,MACT,UAAU;AAAA,MACV;AAAA,MACA,MAAK;AAAA;AAAA,IAEJ,aAAa,cAAc,cAAc;AAAA,EAC5C;AAEJ;","names":[]}
package/dist/esm/index.js CHANGED
@@ -5,13 +5,17 @@ import { CabinIDProvider } from "./provider/main.provider";
5
5
  import { useUser } from "./hooks";
6
6
  import { authMiddleware } from "./server/middleware";
7
7
  import { SignInButton, SignOutButton } from "./components";
8
+ import { detectCabinIdSubdomain, storeCabinIdSubdomain, clearCabinIdSubdomain } from "./utils/subdomain";
8
9
  export {
9
10
  CabinIDProvider,
10
11
  SignInButton,
11
12
  SignOutButton,
12
13
  auth,
13
14
  authMiddleware,
15
+ clearCabinIdSubdomain,
14
16
  currentUser,
17
+ detectCabinIdSubdomain,
18
+ storeCabinIdSubdomain,
15
19
  useUser
16
20
  };
17
21
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import './styles/global.css';\n\nexport { auth } from './server/auth';\nexport { currentUser } from './server/getCurrentUser';\nexport { CabinIDProvider } from './provider/main.provider';\nexport { useUser } from './hooks';\nexport { authMiddleware } from './server/middleware';\nexport { SignInButton, SignOutButton } from './components';\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,YAAY;AACrB,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAC/B,SAAS,cAAc,qBAAqB;","names":[]}
1
+ {"version":3,"sources":["../../src/index.ts"],"sourcesContent":["import './styles/global.css';\n\nexport { auth } from './server/auth';\nexport { currentUser } from './server/getCurrentUser';\nexport { CabinIDProvider } from './provider/main.provider';\nexport { useUser } from './hooks';\nexport { authMiddleware } from './server/middleware';\nexport { SignInButton, SignOutButton } from './components';\nexport { detectCabinIdSubdomain, storeCabinIdSubdomain, clearCabinIdSubdomain } from './utils/subdomain';\n"],"mappings":"AAAA,OAAO;AAEP,SAAS,YAAY;AACrB,SAAS,mBAAmB;AAC5B,SAAS,uBAAuB;AAChC,SAAS,eAAe;AACxB,SAAS,sBAAsB;AAC/B,SAAS,cAAc,qBAAqB;AAC5C,SAAS,wBAAwB,uBAAuB,6BAA6B;","names":[]}
@@ -0,0 +1,36 @@
1
+ const detectCabinIdSubdomain = () => {
2
+ if (typeof window === "undefined") return null;
3
+ const referrer = document.referrer;
4
+ if (referrer) {
5
+ const referrerMatch = referrer.match(/https?:\/\/([^.]+)\.cabinid\.dev/);
6
+ if (referrerMatch) {
7
+ return referrerMatch[1];
8
+ }
9
+ }
10
+ const storedSubdomain = localStorage.getItem("cabinid_subdomain");
11
+ if (storedSubdomain) {
12
+ return storedSubdomain;
13
+ }
14
+ const urlParams = new URLSearchParams(window.location.search);
15
+ const subdomainParam = urlParams.get("cabinid_subdomain");
16
+ if (subdomainParam) {
17
+ return subdomainParam;
18
+ }
19
+ return null;
20
+ };
21
+ const storeCabinIdSubdomain = (subdomain) => {
22
+ if (typeof window !== "undefined") {
23
+ localStorage.setItem("cabinid_subdomain", subdomain);
24
+ }
25
+ };
26
+ const clearCabinIdSubdomain = () => {
27
+ if (typeof window !== "undefined") {
28
+ localStorage.removeItem("cabinid_subdomain");
29
+ }
30
+ };
31
+ export {
32
+ clearCabinIdSubdomain,
33
+ detectCabinIdSubdomain,
34
+ storeCabinIdSubdomain
35
+ };
36
+ //# sourceMappingURL=subdomain.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/utils/subdomain.ts"],"sourcesContent":["/**\n * Utility functions for handling CabinID subdomain detection\n */\n\n/**\n * Extracts the CabinID subdomain from referrer or current URL\n * @returns The subdomain if detected, null otherwise\n */\nexport const detectCabinIdSubdomain = (): string | null => {\n if (typeof window === 'undefined') return null;\n\n // Check referrer first (where user came from during authentication flow)\n const referrer = document.referrer;\n if (referrer) {\n const referrerMatch = referrer.match(/https?:\\/\\/([^.]+)\\.cabinid\\.dev/);\n if (referrerMatch) {\n return referrerMatch[1];\n }\n }\n\n // Check if there's a stored subdomain from authentication flow\n const storedSubdomain = localStorage.getItem('cabinid_subdomain');\n if (storedSubdomain) {\n return storedSubdomain;\n }\n\n // Check URL parameters for subdomain hint\n const urlParams = new URLSearchParams(window.location.search);\n const subdomainParam = urlParams.get('cabinid_subdomain');\n if (subdomainParam) {\n return subdomainParam;\n }\n\n return null;\n};\n\n/**\n * Stores the CabinID subdomain for later use\n * @param subdomain The subdomain to store\n */\nexport const storeCabinIdSubdomain = (subdomain: string): void => {\n if (typeof window !== 'undefined') {\n localStorage.setItem('cabinid_subdomain', subdomain);\n }\n};\n\n/**\n * Clears the stored CabinID subdomain\n */\nexport const clearCabinIdSubdomain = (): void => {\n if (typeof window !== 'undefined') {\n localStorage.removeItem('cabinid_subdomain');\n }\n};"],"mappings":"AAQO,MAAM,yBAAyB,MAAqB;AACzD,MAAI,OAAO,WAAW,YAAa,QAAO;AAG1C,QAAM,WAAW,SAAS;AAC1B,MAAI,UAAU;AACZ,UAAM,gBAAgB,SAAS,MAAM,kCAAkC;AACvE,QAAI,eAAe;AACjB,aAAO,cAAc,CAAC;AAAA,IACxB;AAAA,EACF;AAGA,QAAM,kBAAkB,aAAa,QAAQ,mBAAmB;AAChE,MAAI,iBAAiB;AACnB,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,IAAI,gBAAgB,OAAO,SAAS,MAAM;AAC5D,QAAM,iBAAiB,UAAU,IAAI,mBAAmB;AACxD,MAAI,gBAAgB;AAClB,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAMO,MAAM,wBAAwB,CAAC,cAA4B;AAChE,MAAI,OAAO,WAAW,aAAa;AACjC,iBAAa,QAAQ,qBAAqB,SAAS;AAAA,EACrD;AACF;AAKO,MAAM,wBAAwB,MAAY;AAC/C,MAAI,OAAO,WAAW,aAAa;AACjC,iBAAa,WAAW,mBAAmB;AAAA,EAC7C;AACF;","names":[]}
@@ -41,6 +41,16 @@ export interface SignOutButtonProps {
41
41
  * @default true
42
42
  */
43
43
  callBackend?: boolean;
44
+ /**
45
+ * CabinID subdomain for cross-domain logout
46
+ * @example "myapp" for myapp.cabinid.dev
47
+ */
48
+ cabinIdSubdomain?: string;
49
+ /**
50
+ * Whether to use cross-domain logout flow
51
+ * @default true
52
+ */
53
+ useCrossDomainLogout?: boolean;
44
54
  }
45
55
  /**
46
56
  * SignOutButton component that handles user logout with CabinID backend integration
@@ -1 +1 @@
1
- {"version":3,"file":"SignOutButton.d.ts","sourceRoot":"","sources":["../../../src/components/SignOutButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,EAAW,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAG3D,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CA8EtD,CAAC"}
1
+ {"version":3,"file":"SignOutButton.d.ts","sourceRoot":"","sources":["../../../src/components/SignOutButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAmB,MAAM,OAAO,CAAC;AACxC,OAAO,EAAW,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAI3D,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B;;OAEG;IACH,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B;;OAEG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACxC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,kBAAkB,CAkHtD,CAAC"}
@@ -5,4 +5,5 @@ export { CabinIDProvider } from './provider/main.provider';
5
5
  export { useUser } from './hooks';
6
6
  export { authMiddleware } from './server/middleware';
7
7
  export { SignInButton, SignOutButton } from './components';
8
+ export { detectCabinIdSubdomain, storeCabinIdSubdomain, clearCabinIdSubdomain } from './utils/subdomain';
8
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,qBAAqB,CAAC;AAE7B,OAAO,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACrC,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAC3D,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Utility functions for handling CabinID subdomain detection
3
+ */
4
+ /**
5
+ * Extracts the CabinID subdomain from referrer or current URL
6
+ * @returns The subdomain if detected, null otherwise
7
+ */
8
+ export declare const detectCabinIdSubdomain: () => string | null;
9
+ /**
10
+ * Stores the CabinID subdomain for later use
11
+ * @param subdomain The subdomain to store
12
+ */
13
+ export declare const storeCabinIdSubdomain: (subdomain: string) => void;
14
+ /**
15
+ * Clears the stored CabinID subdomain
16
+ */
17
+ export declare const clearCabinIdSubdomain: () => void;
18
+ //# sourceMappingURL=subdomain.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subdomain.d.ts","sourceRoot":"","sources":["../../../src/utils/subdomain.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH;;;GAGG;AACH,eAAO,MAAM,sBAAsB,QAAO,MAAM,GAAG,IA0BlD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,GAAI,WAAW,MAAM,KAAG,IAIzD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,QAAO,IAIxC,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@cabin-id/nextjs",
3
3
  "description": "NextJS SDK for CabinID",
4
- "version": "1.1.0",
4
+ "version": "1.2.0",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
7
7
  "author": "CabinVN",