@solvapay/react-supabase 1.0.8-preview.1 → 1.0.8-preview.11

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
@@ -14,69 +14,49 @@ yarn add @solvapay/react-supabase @supabase/supabase-js
14
14
 
15
15
  ## Usage
16
16
 
17
- Use the Supabase adapter with `SolvaPayProvider`:
17
+ Pass your existing Supabase client to `createSupabaseAuthAdapter`:
18
18
 
19
19
  ```tsx
20
+ import { createClient } from '@supabase/supabase-js'
20
21
  import { SolvaPayProvider } from '@solvapay/react'
21
22
  import { createSupabaseAuthAdapter } from '@solvapay/react-supabase'
22
23
 
23
- const adapter = createSupabaseAuthAdapter({
24
- supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
25
- supabaseAnonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
26
- })
24
+ const supabase = createClient(
25
+ process.env.NEXT_PUBLIC_SUPABASE_URL!,
26
+ process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
27
+ )
28
+
29
+ const adapter = createSupabaseAuthAdapter({ client: supabase })
27
30
 
28
31
  export default function RootLayout({ children }) {
29
32
  return <SolvaPayProvider config={{ auth: { adapter } }}>{children}</SolvaPayProvider>
30
33
  }
31
34
  ```
32
35
 
36
+ Reusing the host app's client avoids spawning a second `GoTrue` instance and is the only reliable form with `@supabase/ssr`, custom `auth.storageKey`, or `persistSession: false`.
37
+
33
38
  ## API
34
39
 
35
40
  ### `createSupabaseAuthAdapter(config)`
36
41
 
37
- Creates a Supabase auth adapter instance.
42
+ Creates a Supabase auth adapter instance. Accepts one of two config shapes:
38
43
 
39
- **Parameters:**
44
+ **`{ client }`** (recommended)
40
45
 
41
- - `config.supabaseUrl` (string, required) - Your Supabase project URL
42
- - `config.supabaseAnonKey` (string, required) - Your Supabase anonymous/public key
46
+ - `config.client` (`SupabaseClient`, required) - Your existing Supabase client.
43
47
 
44
- **Returns:** `AuthAdapter` instance
45
-
46
- ## How It Works
48
+ **`{ supabaseUrl, supabaseAnonKey }`** (deprecated)
47
49
 
48
- The adapter:
50
+ - `config.supabaseUrl` (string) - Your Supabase project URL.
51
+ - `config.supabaseAnonKey` (string) - Your Supabase anonymous/public key.
49
52
 
50
- 1. Creates a Supabase client using your credentials
51
- 2. Gets the current session using `supabase.auth.getSession()`
52
- 3. Extracts the access token and user ID from the session
53
- 4. Returns `null` if no session is available (unauthenticated)
53
+ The URL/key form dynamically imports `@supabase/supabase-js` and creates a second client. It emits a one-time `console.warn` recommending migration to the `{ client }` form.
54
54
 
55
- The adapter handles errors gracefully and never throws - it returns `null` when authentication is not available.
56
-
57
- ## Example: Full Setup
58
-
59
- ```tsx
60
- 'use client'
55
+ **Returns:** `AuthAdapter` instance.
61
56
 
62
- import { SolvaPayProvider } from '@solvapay/react'
63
- import { createSupabaseAuthAdapter } from '@solvapay/react-supabase'
57
+ ## How It Works
64
58
 
65
- export default function RootLayout({ children }) {
66
- const adapter = createSupabaseAuthAdapter({
67
- supabaseUrl: process.env.NEXT_PUBLIC_SUPABASE_URL!,
68
- supabaseAnonKey: process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!,
69
- })
70
-
71
- return (
72
- <html>
73
- <body>
74
- <SolvaPayProvider config={{ auth: { adapter } }}>{children}</SolvaPayProvider>
75
- </body>
76
- </html>
77
- )
78
- }
79
- ```
59
+ The adapter calls `supabase.auth.getSession()` and returns the access token + user ID. Returns `null` when there is no active session. Never throws.
80
60
 
81
61
  ## Custom Adapters
82
62
 
package/dist/index.cjs CHANGED
@@ -35,23 +35,35 @@ __export(index_exports, {
35
35
  module.exports = __toCommonJS(index_exports);
36
36
 
37
37
  // src/supabase-adapter.ts
38
+ var urlKeyDeprecationWarned = false;
39
+ function isClientConfig(config) {
40
+ return "client" in config && config.client !== void 0 && config.client !== null;
41
+ }
38
42
  function createSupabaseAuthAdapter(config) {
39
- if (!config.supabaseUrl || !config.supabaseAnonKey) {
40
- throw new Error("SupabaseAuthAdapter requires both supabaseUrl and supabaseAnonKey");
43
+ if (isClientConfig(config)) {
44
+ return adapterFromClient(() => Promise.resolve(config.client));
45
+ }
46
+ const { supabaseUrl, supabaseAnonKey } = config;
47
+ if (!supabaseUrl || !supabaseAnonKey) {
48
+ throw new Error(
49
+ "createSupabaseAuthAdapter: pass { client } with your existing Supabase client, or { supabaseUrl, supabaseAnonKey } to have the adapter create one."
50
+ );
51
+ }
52
+ if (!urlKeyDeprecationWarned) {
53
+ urlKeyDeprecationWarned = true;
54
+ console.warn(
55
+ "[SupabaseAuthAdapter] The { supabaseUrl, supabaseAnonKey } form is deprecated and creates a second GoTrueClient that can miss sessions with @supabase/ssr or custom auth.storageKey. Pass { client: yourExistingSupabaseClient } instead."
56
+ );
41
57
  }
42
58
  let supabaseClient = null;
43
59
  let clientPromise = null;
44
- const getSupabaseClient = async () => {
45
- if (supabaseClient) {
46
- return supabaseClient;
47
- }
48
- if (clientPromise) {
49
- return clientPromise;
50
- }
60
+ const getClient = () => {
61
+ if (supabaseClient) return Promise.resolve(supabaseClient);
62
+ if (clientPromise) return clientPromise;
51
63
  clientPromise = (async () => {
52
64
  try {
53
65
  const { createClient } = await import("@supabase/supabase-js");
54
- const client = createClient(config.supabaseUrl, config.supabaseAnonKey);
66
+ const client = createClient(supabaseUrl, supabaseAnonKey);
55
67
  supabaseClient = client;
56
68
  return client;
57
69
  } catch {
@@ -63,11 +75,14 @@ function createSupabaseAuthAdapter(config) {
63
75
  })();
64
76
  return clientPromise;
65
77
  };
78
+ return adapterFromClient(getClient);
79
+ }
80
+ function adapterFromClient(getClient) {
66
81
  return {
67
82
  async getToken() {
68
83
  if (typeof window === "undefined") return null;
69
84
  try {
70
- const supabase = await getSupabaseClient();
85
+ const supabase = await getClient();
71
86
  const {
72
87
  data: { session }
73
88
  } = await supabase.auth.getSession();
@@ -80,7 +95,7 @@ function createSupabaseAuthAdapter(config) {
80
95
  async getUserId() {
81
96
  if (typeof window === "undefined") return null;
82
97
  try {
83
- const supabase = await getSupabaseClient();
98
+ const supabase = await getClient();
84
99
  const {
85
100
  data: { session }
86
101
  } = await supabase.auth.getSession();
package/dist/index.d.cts CHANGED
@@ -7,16 +7,80 @@ import { AuthAdapter } from '@solvapay/react';
7
7
  * This adapter integrates with Supabase Auth to get tokens and user IDs.
8
8
  */
9
9
 
10
- interface SupabaseAuthAdapterConfig {
11
- /**
12
- * Supabase project URL
13
- */
10
+ /**
11
+ * Structural shape of a Supabase client as used by the adapter.
12
+ *
13
+ * Matches `SupabaseClient` from `@supabase/supabase-js` without importing
14
+ * the type, so consumers pass the real client without a cast and this
15
+ * package stays dependency-light.
16
+ */
17
+ type SupabaseClientLike = {
18
+ auth: {
19
+ getSession: () => Promise<{
20
+ data: {
21
+ session: {
22
+ access_token?: string;
23
+ user?: {
24
+ id?: string;
25
+ };
26
+ } | null;
27
+ };
28
+ }>;
29
+ };
30
+ };
31
+ /**
32
+ * Configuration for `createSupabaseAuthAdapter`.
33
+ *
34
+ * Prefer the `{ client }` form: pass your app's existing Supabase client so
35
+ * only one `GoTrue` instance is ever in the page. The URL/key form is kept
36
+ * for backwards compatibility but creates a second client that can miss
37
+ * sessions when the host app uses custom storage keys, `@supabase/ssr`, or
38
+ * iframe-isolated storage.
39
+ */
40
+ type SupabaseAuthAdapterConfig = {
41
+ /** The host app's existing Supabase client. Recommended. */
42
+ client: SupabaseClientLike;
43
+ } | {
44
+ /** @deprecated Prefer `{ client }` — pass your existing Supabase client instead. */
14
45
  supabaseUrl: string;
15
- /**
16
- * Supabase anonymous/public key
17
- */
46
+ /** @deprecated Prefer `{ client }` — pass your existing Supabase client instead. */
18
47
  supabaseAnonKey: string;
19
- }
48
+ };
49
+ /**
50
+ * Create a Supabase authentication adapter for SolvaPayProvider.
51
+ *
52
+ * Two configuration forms are supported:
53
+ *
54
+ * 1. **`{ client }` (recommended)** — reuse the host app's existing Supabase
55
+ * client. No dynamic import, no second `GoTrue` instance, works with
56
+ * `@supabase/ssr` and custom storage configurations.
57
+ * 2. **`{ supabaseUrl, supabaseAnonKey }` (deprecated)** — the adapter
58
+ * dynamically imports `@supabase/supabase-js` and creates its own client.
59
+ * Emits a one-time `console.warn` recommending migration to `{ client }`.
60
+ *
61
+ * @example
62
+ * ```tsx
63
+ * // Recommended: reuse the host app's client
64
+ * import { createClient } from '@supabase/supabase-js'
65
+ * import { createSupabaseAuthAdapter } from '@solvapay/react-supabase'
66
+ * import { SolvaPayProvider } from '@solvapay/react'
67
+ *
68
+ * const supabase = createClient(url, anonKey)
69
+ * const adapter = createSupabaseAuthAdapter({ client: supabase })
70
+ *
71
+ * export function App() {
72
+ * return (
73
+ * <SolvaPayProvider config={{ auth: { adapter } }}>
74
+ * <YourApp />
75
+ * </SolvaPayProvider>
76
+ * )
77
+ * }
78
+ * ```
79
+ *
80
+ * @see SolvaPayProvider (from `@solvapay/react`) for using the adapter
81
+ * @see {@link AuthAdapter} for the adapter interface
82
+ * @since 1.0.0
83
+ */
20
84
  declare function createSupabaseAuthAdapter(config: SupabaseAuthAdapterConfig): AuthAdapter;
21
85
 
22
- export { type SupabaseAuthAdapterConfig, createSupabaseAuthAdapter };
86
+ export { type SupabaseAuthAdapterConfig, type SupabaseClientLike, createSupabaseAuthAdapter };
package/dist/index.d.ts CHANGED
@@ -7,16 +7,80 @@ import { AuthAdapter } from '@solvapay/react';
7
7
  * This adapter integrates with Supabase Auth to get tokens and user IDs.
8
8
  */
9
9
 
10
- interface SupabaseAuthAdapterConfig {
11
- /**
12
- * Supabase project URL
13
- */
10
+ /**
11
+ * Structural shape of a Supabase client as used by the adapter.
12
+ *
13
+ * Matches `SupabaseClient` from `@supabase/supabase-js` without importing
14
+ * the type, so consumers pass the real client without a cast and this
15
+ * package stays dependency-light.
16
+ */
17
+ type SupabaseClientLike = {
18
+ auth: {
19
+ getSession: () => Promise<{
20
+ data: {
21
+ session: {
22
+ access_token?: string;
23
+ user?: {
24
+ id?: string;
25
+ };
26
+ } | null;
27
+ };
28
+ }>;
29
+ };
30
+ };
31
+ /**
32
+ * Configuration for `createSupabaseAuthAdapter`.
33
+ *
34
+ * Prefer the `{ client }` form: pass your app's existing Supabase client so
35
+ * only one `GoTrue` instance is ever in the page. The URL/key form is kept
36
+ * for backwards compatibility but creates a second client that can miss
37
+ * sessions when the host app uses custom storage keys, `@supabase/ssr`, or
38
+ * iframe-isolated storage.
39
+ */
40
+ type SupabaseAuthAdapterConfig = {
41
+ /** The host app's existing Supabase client. Recommended. */
42
+ client: SupabaseClientLike;
43
+ } | {
44
+ /** @deprecated Prefer `{ client }` — pass your existing Supabase client instead. */
14
45
  supabaseUrl: string;
15
- /**
16
- * Supabase anonymous/public key
17
- */
46
+ /** @deprecated Prefer `{ client }` — pass your existing Supabase client instead. */
18
47
  supabaseAnonKey: string;
19
- }
48
+ };
49
+ /**
50
+ * Create a Supabase authentication adapter for SolvaPayProvider.
51
+ *
52
+ * Two configuration forms are supported:
53
+ *
54
+ * 1. **`{ client }` (recommended)** — reuse the host app's existing Supabase
55
+ * client. No dynamic import, no second `GoTrue` instance, works with
56
+ * `@supabase/ssr` and custom storage configurations.
57
+ * 2. **`{ supabaseUrl, supabaseAnonKey }` (deprecated)** — the adapter
58
+ * dynamically imports `@supabase/supabase-js` and creates its own client.
59
+ * Emits a one-time `console.warn` recommending migration to `{ client }`.
60
+ *
61
+ * @example
62
+ * ```tsx
63
+ * // Recommended: reuse the host app's client
64
+ * import { createClient } from '@supabase/supabase-js'
65
+ * import { createSupabaseAuthAdapter } from '@solvapay/react-supabase'
66
+ * import { SolvaPayProvider } from '@solvapay/react'
67
+ *
68
+ * const supabase = createClient(url, anonKey)
69
+ * const adapter = createSupabaseAuthAdapter({ client: supabase })
70
+ *
71
+ * export function App() {
72
+ * return (
73
+ * <SolvaPayProvider config={{ auth: { adapter } }}>
74
+ * <YourApp />
75
+ * </SolvaPayProvider>
76
+ * )
77
+ * }
78
+ * ```
79
+ *
80
+ * @see SolvaPayProvider (from `@solvapay/react`) for using the adapter
81
+ * @see {@link AuthAdapter} for the adapter interface
82
+ * @since 1.0.0
83
+ */
20
84
  declare function createSupabaseAuthAdapter(config: SupabaseAuthAdapterConfig): AuthAdapter;
21
85
 
22
- export { type SupabaseAuthAdapterConfig, createSupabaseAuthAdapter };
86
+ export { type SupabaseAuthAdapterConfig, type SupabaseClientLike, createSupabaseAuthAdapter };
package/dist/index.js CHANGED
@@ -1,21 +1,33 @@
1
1
  // src/supabase-adapter.ts
2
+ var urlKeyDeprecationWarned = false;
3
+ function isClientConfig(config) {
4
+ return "client" in config && config.client !== void 0 && config.client !== null;
5
+ }
2
6
  function createSupabaseAuthAdapter(config) {
3
- if (!config.supabaseUrl || !config.supabaseAnonKey) {
4
- throw new Error("SupabaseAuthAdapter requires both supabaseUrl and supabaseAnonKey");
7
+ if (isClientConfig(config)) {
8
+ return adapterFromClient(() => Promise.resolve(config.client));
9
+ }
10
+ const { supabaseUrl, supabaseAnonKey } = config;
11
+ if (!supabaseUrl || !supabaseAnonKey) {
12
+ throw new Error(
13
+ "createSupabaseAuthAdapter: pass { client } with your existing Supabase client, or { supabaseUrl, supabaseAnonKey } to have the adapter create one."
14
+ );
15
+ }
16
+ if (!urlKeyDeprecationWarned) {
17
+ urlKeyDeprecationWarned = true;
18
+ console.warn(
19
+ "[SupabaseAuthAdapter] The { supabaseUrl, supabaseAnonKey } form is deprecated and creates a second GoTrueClient that can miss sessions with @supabase/ssr or custom auth.storageKey. Pass { client: yourExistingSupabaseClient } instead."
20
+ );
5
21
  }
6
22
  let supabaseClient = null;
7
23
  let clientPromise = null;
8
- const getSupabaseClient = async () => {
9
- if (supabaseClient) {
10
- return supabaseClient;
11
- }
12
- if (clientPromise) {
13
- return clientPromise;
14
- }
24
+ const getClient = () => {
25
+ if (supabaseClient) return Promise.resolve(supabaseClient);
26
+ if (clientPromise) return clientPromise;
15
27
  clientPromise = (async () => {
16
28
  try {
17
29
  const { createClient } = await import("@supabase/supabase-js");
18
- const client = createClient(config.supabaseUrl, config.supabaseAnonKey);
30
+ const client = createClient(supabaseUrl, supabaseAnonKey);
19
31
  supabaseClient = client;
20
32
  return client;
21
33
  } catch {
@@ -27,11 +39,14 @@ function createSupabaseAuthAdapter(config) {
27
39
  })();
28
40
  return clientPromise;
29
41
  };
42
+ return adapterFromClient(getClient);
43
+ }
44
+ function adapterFromClient(getClient) {
30
45
  return {
31
46
  async getToken() {
32
47
  if (typeof window === "undefined") return null;
33
48
  try {
34
- const supabase = await getSupabaseClient();
49
+ const supabase = await getClient();
35
50
  const {
36
51
  data: { session }
37
52
  } = await supabase.auth.getSession();
@@ -44,7 +59,7 @@ function createSupabaseAuthAdapter(config) {
44
59
  async getUserId() {
45
60
  if (typeof window === "undefined") return null;
46
61
  try {
47
- const supabase = await getSupabaseClient();
62
+ const supabase = await getClient();
48
63
  const {
49
64
  data: { session }
50
65
  } = await supabase.auth.getSession();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solvapay/react-supabase",
3
- "version": "1.0.8-preview.1",
3
+ "version": "1.0.8-preview.11",
4
4
  "type": "module",
5
5
  "main": "./dist/index.cjs",
6
6
  "module": "./dist/index.js",
@@ -18,20 +18,20 @@
18
18
  "directory": "packages/react-supabase"
19
19
  },
20
20
  "peerDependencies": {
21
- "@solvapay/react": "^1.0.1",
22
- "@supabase/supabase-js": "^2.0.0"
21
+ "@supabase/supabase-js": "^2.0.0",
22
+ "@solvapay/react": "^1.0.8-preview.11"
23
23
  },
24
24
  "devDependencies": {
25
25
  "@types/react": "^19.2.14",
26
26
  "tsup": "^8.5.1",
27
27
  "typescript": "^5.9.3",
28
28
  "vitest": "^4.1.2",
29
- "@solvapay/react": "1.0.8-preview.1"
29
+ "@solvapay/react": "1.0.8-preview.11"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "tsup src/index.ts --format esm,cjs --dts --tsconfig tsconfig.build.json",
33
- "test": "vitest run || exit 0",
34
- "test:unit": "vitest run || exit 0",
33
+ "test": "vitest run",
34
+ "test:unit": "vitest run",
35
35
  "test:watch": "vitest",
36
36
  "lint": "eslint src --config ../../eslint.config.react.mjs",
37
37
  "lint:fix": "eslint src --config ../../eslint.config.react.mjs --fix"