@nhost/nhost-js 4.2.2 → 4.3.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.
- package/dist/fetch-2PHmQBIJ.js.map +1 -1
- package/dist/fetch-DWXwEnoe.cjs.map +1 -1
- package/dist/{middlewareWithAdminSession-DLqDQUbW.js → middlewareWithAdminSession-BeIk-9HO.js} +2 -2
- package/dist/middlewareWithAdminSession-BeIk-9HO.js.map +1 -0
- package/dist/middlewareWithAdminSession-DDApoLkL.cjs.map +1 -1
- package/dist/nhost-js/auth.cjs.map +1 -1
- package/dist/nhost-js/auth.js.map +1 -1
- package/dist/nhost-js/fetch.cjs.map +1 -1
- package/dist/nhost-js/fetch.js +1 -1
- package/dist/nhost-js/fetch.js.map +1 -1
- package/dist/nhost-js/functions.cjs.map +1 -1
- package/dist/nhost-js/functions.js.map +1 -1
- package/dist/nhost-js/graphql.cjs.map +1 -1
- package/dist/nhost-js/graphql.js.map +1 -1
- package/dist/nhost-js/session.cjs.map +1 -1
- package/dist/nhost-js/session.js +1 -1
- package/dist/nhost-js/session.js.map +1 -1
- package/dist/nhost-js/storage.cjs.map +1 -1
- package/dist/nhost-js/storage.js.map +1 -1
- package/dist/nhost-js.cjs.map +1 -1
- package/dist/nhost-js.js +2 -2
- package/dist/nhost-js.js.map +1 -1
- package/dist/nhost-js.umd.js.map +1 -1
- package/dist/refreshSession-Bw715ZmX.cjs.map +1 -1
- package/dist/{refreshSession-CG8GIEun.js → refreshSession-WwGlzgtM.js} +2 -5
- package/dist/refreshSession-WwGlzgtM.js.map +1 -0
- package/dist/src/auth/client.d.ts +28 -28
- package/dist/src/auth/client.js +76 -76
- package/dist/src/auth/index.d.ts +1 -1
- package/dist/src/auth/index.js +1 -1
- package/dist/src/fetch/fetch.js +20 -20
- package/dist/src/fetch/index.d.ts +7 -7
- package/dist/src/fetch/index.js +7 -7
- package/dist/src/fetch/middlewareAttachAccessToken.d.ts +2 -2
- package/dist/src/fetch/middlewareAttachAccessToken.js +2 -2
- package/dist/src/fetch/middlewareSessionRefresh.d.ts +3 -3
- package/dist/src/fetch/middlewareSessionRefresh.js +3 -3
- package/dist/src/fetch/middlewareUpdateSessionFromResponse.d.ts +2 -2
- package/dist/src/fetch/middlewareUpdateSessionFromResponse.js +8 -8
- package/dist/src/fetch/middlewareWithAdminSession.d.ts +1 -1
- package/dist/src/fetch/middlewareWithAdminSession.js +5 -5
- package/dist/src/fetch/middlewareWithHeaders.d.ts +1 -1
- package/dist/src/fetch/middlewareWithRole.d.ts +1 -1
- package/dist/src/fetch/middlewareWithRole.js +2 -2
- package/dist/src/functions/client.d.ts +1 -1
- package/dist/src/functions/client.js +6 -6
- package/dist/src/functions/index.d.ts +1 -1
- package/dist/src/functions/index.js +1 -1
- package/dist/src/graphql/client.d.ts +2 -2
- package/dist/src/graphql/client.js +6 -6
- package/dist/src/graphql/index.d.ts +1 -1
- package/dist/src/graphql/index.js +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/nhost.d.ts +6 -6
- package/dist/src/nhost.js +11 -11
- package/dist/src/session/index.d.ts +4 -4
- package/dist/src/session/index.js +3 -3
- package/dist/src/session/refreshSession.d.ts +3 -3
- package/dist/src/session/refreshSession.d.ts.map +1 -1
- package/dist/src/session/refreshSession.js +5 -7
- package/dist/src/session/refreshSession.js.map +1 -1
- package/dist/src/session/session.d.ts +2 -2
- package/dist/src/session/session.js +15 -15
- package/dist/src/session/storage.d.ts +3 -3
- package/dist/src/session/storage.js +4 -4
- package/dist/src/session/storageBackend.d.ts +2 -2
- package/dist/src/session/storageBackend.js +7 -7
- package/dist/src/storage/client.d.ts +5 -5
- package/dist/src/storage/client.js +44 -44
- package/dist/src/storage/index.d.ts +1 -1
- package/dist/src/storage/index.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -2
- package/dist/middlewareWithAdminSession-DLqDQUbW.js.map +0 -1
- package/dist/refreshSession-CG8GIEun.js.map +0 -1
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* authorization tokens to outgoing API requests, ensuring the client
|
|
6
6
|
* is properly authenticated.
|
|
7
7
|
*/
|
|
8
|
-
import type { SessionStorage } from
|
|
9
|
-
import type { ChainFunction } from
|
|
8
|
+
import type { SessionStorage } from '../session/storage';
|
|
9
|
+
import type { ChainFunction } from './fetch';
|
|
10
10
|
/**
|
|
11
11
|
* Creates a fetch middleware that adds the Authorization header with the current access token.
|
|
12
12
|
*
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
export const attachAccessTokenMiddleware = (storage) => (next) => async (url, options = {}) => {
|
|
22
22
|
const headers = new Headers(options.headers || {});
|
|
23
23
|
// Skip if Authorization header is already set
|
|
24
|
-
if (headers.has(
|
|
24
|
+
if (headers.has('Authorization')) {
|
|
25
25
|
return next(url, options);
|
|
26
26
|
}
|
|
27
27
|
// Get current session from storage
|
|
@@ -47,7 +47,7 @@ export const attachAccessTokenMiddleware = (storage) => (next) => async (url, op
|
|
|
47
47
|
*/
|
|
48
48
|
function addAuthorizationHeader(headers, session) {
|
|
49
49
|
if (session.accessToken) {
|
|
50
|
-
headers.set(
|
|
50
|
+
headers.set('Authorization', `Bearer ${session.accessToken}`);
|
|
51
51
|
}
|
|
52
52
|
return headers;
|
|
53
53
|
}
|
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
* authentication tokens before they expire, ensuring seamless API access
|
|
6
6
|
* without requiring manual token refresh by the application.
|
|
7
7
|
*/
|
|
8
|
-
import type { Client } from
|
|
9
|
-
import type { SessionStorage } from
|
|
10
|
-
import type { ChainFunction } from
|
|
8
|
+
import type { Client } from '../auth';
|
|
9
|
+
import type { SessionStorage } from '../session/storage';
|
|
10
|
+
import type { ChainFunction } from './fetch';
|
|
11
11
|
/**
|
|
12
12
|
* Creates a fetch middleware that automatically refreshes authentication tokens.
|
|
13
13
|
*
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* authentication tokens before they expire, ensuring seamless API access
|
|
6
6
|
* without requiring manual token refresh by the application.
|
|
7
7
|
*/
|
|
8
|
-
import { refreshSession } from
|
|
8
|
+
import { refreshSession } from '../session/refreshSession';
|
|
9
9
|
/**
|
|
10
10
|
* Creates a fetch middleware that automatically refreshes authentication tokens.
|
|
11
11
|
*
|
|
@@ -49,11 +49,11 @@ export const sessionRefreshMiddleware = (auth, storage, options) => {
|
|
|
49
49
|
function shouldSkipTokenHandling(url, options) {
|
|
50
50
|
const headers = new Headers(options.headers || {});
|
|
51
51
|
// If Authorization header is explicitly set, skip token handling
|
|
52
|
-
if (headers.has(
|
|
52
|
+
if (headers.has('Authorization')) {
|
|
53
53
|
return true;
|
|
54
54
|
}
|
|
55
55
|
// If calling the token endpoint, skip to avoid infinite loops
|
|
56
|
-
if (url.endsWith(
|
|
56
|
+
if (url.endsWith('/v1/token')) {
|
|
57
57
|
return true;
|
|
58
58
|
}
|
|
59
59
|
return false;
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* and persist session information from authentication responses, ensuring
|
|
6
6
|
* that new sessions are properly stored after sign-in operations.
|
|
7
7
|
*/
|
|
8
|
-
import type { SessionStorage } from
|
|
9
|
-
import type { ChainFunction } from
|
|
8
|
+
import type { SessionStorage } from '../session/storage';
|
|
9
|
+
import type { ChainFunction } from './fetch';
|
|
10
10
|
/**
|
|
11
11
|
* Creates a fetch middleware that automatically extracts and stores session data from API responses.
|
|
12
12
|
*
|
|
@@ -28,14 +28,14 @@ export const updateSessionFromResponseMiddleware = (storage) => {
|
|
|
28
28
|
* @returns Session object if found, null otherwise
|
|
29
29
|
*/
|
|
30
30
|
const sessionExtractor = (body) => {
|
|
31
|
-
if (typeof body ===
|
|
31
|
+
if (typeof body === 'string') {
|
|
32
32
|
return null;
|
|
33
33
|
}
|
|
34
|
-
if (
|
|
34
|
+
if ('session' in body) {
|
|
35
35
|
// SessionPayload
|
|
36
36
|
return body.session || null;
|
|
37
37
|
}
|
|
38
|
-
if (
|
|
38
|
+
if ('accessToken' in body && 'refreshToken' in body && 'user' in body) {
|
|
39
39
|
// Session
|
|
40
40
|
return body;
|
|
41
41
|
}
|
|
@@ -46,15 +46,15 @@ export const updateSessionFromResponseMiddleware = (storage) => {
|
|
|
46
46
|
const response = await next(url, options);
|
|
47
47
|
try {
|
|
48
48
|
// Check if this is a logout request
|
|
49
|
-
if (url.endsWith(
|
|
49
|
+
if (url.endsWith('/signout')) {
|
|
50
50
|
// Remove session on sign-out
|
|
51
51
|
storage.remove();
|
|
52
52
|
return response;
|
|
53
53
|
}
|
|
54
54
|
// Check if this is an auth-related endpoint that might return session data
|
|
55
|
-
if (url.endsWith(
|
|
56
|
-
url.includes(
|
|
57
|
-
url.includes(
|
|
55
|
+
if (url.endsWith('/token') ||
|
|
56
|
+
url.includes('/signin/') ||
|
|
57
|
+
url.includes('/signup/')) {
|
|
58
58
|
// Clone the response to avoid consuming it
|
|
59
59
|
const clonedResponse = response.clone();
|
|
60
60
|
// Parse the JSON data
|
|
@@ -70,7 +70,7 @@ export const updateSessionFromResponseMiddleware = (storage) => {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
catch (error) {
|
|
73
|
-
console.warn(
|
|
73
|
+
console.warn('Error in session response middleware:', error);
|
|
74
74
|
}
|
|
75
75
|
// Return the original response
|
|
76
76
|
return response;
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This module provides middleware functionality to automatically attach
|
|
5
5
|
* Hasura admin secret for admin permissions in requests.
|
|
6
6
|
*/
|
|
7
|
-
import type { ChainFunction } from
|
|
7
|
+
import type { ChainFunction } from './fetch';
|
|
8
8
|
/**
|
|
9
9
|
* Configuration options for admin session middleware
|
|
10
10
|
*/
|
|
@@ -56,18 +56,18 @@
|
|
|
56
56
|
export const withAdminSessionMiddleware = (options) => (next) => async (url, requestOptions = {}) => {
|
|
57
57
|
const headers = new Headers(requestOptions.headers || {});
|
|
58
58
|
// Set x-hasura-admin-secret if not already present
|
|
59
|
-
if (!headers.has(
|
|
60
|
-
headers.set(
|
|
59
|
+
if (!headers.has('x-hasura-admin-secret')) {
|
|
60
|
+
headers.set('x-hasura-admin-secret', options.adminSecret);
|
|
61
61
|
}
|
|
62
62
|
// Set x-hasura-role if provided and not already present
|
|
63
|
-
if (options.role && !headers.has(
|
|
64
|
-
headers.set(
|
|
63
|
+
if (options.role && !headers.has('x-hasura-role')) {
|
|
64
|
+
headers.set('x-hasura-role', options.role);
|
|
65
65
|
}
|
|
66
66
|
// Set custom session variables
|
|
67
67
|
if (options.sessionVariables) {
|
|
68
68
|
for (const [key, value] of Object.entries(options.sessionVariables)) {
|
|
69
69
|
// Ensure the key has the x-hasura- prefix
|
|
70
|
-
const headerKey = key.startsWith(
|
|
70
|
+
const headerKey = key.startsWith('x-hasura-') ? key : `x-hasura-${key}`;
|
|
71
71
|
// Only set if not already present in the request
|
|
72
72
|
if (!headers.has(headerKey)) {
|
|
73
73
|
headers.set(headerKey, value);
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* default headers to all outgoing requests, while allowing request-specific
|
|
6
6
|
* headers to take precedence.
|
|
7
7
|
*/
|
|
8
|
-
import type { ChainFunction } from
|
|
8
|
+
import type { ChainFunction } from './fetch';
|
|
9
9
|
/**
|
|
10
10
|
* Creates a fetch middleware that attaches default headers to requests.
|
|
11
11
|
*
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* the Hasura role for all requests. This is useful when you want to
|
|
6
6
|
* make requests as a specific role without using the admin secret.
|
|
7
7
|
*/
|
|
8
|
-
import type { ChainFunction } from
|
|
8
|
+
import type { ChainFunction } from './fetch';
|
|
9
9
|
/**
|
|
10
10
|
* Creates a fetch middleware that sets the Hasura role header.
|
|
11
11
|
*
|
|
@@ -42,8 +42,8 @@
|
|
|
42
42
|
export const withRoleMiddleware = (role) => (next) => async (url, requestOptions = {}) => {
|
|
43
43
|
const headers = new Headers(requestOptions.headers || {});
|
|
44
44
|
// Set x-hasura-role if not already present
|
|
45
|
-
if (!headers.has(
|
|
46
|
-
headers.set(
|
|
45
|
+
if (!headers.has('x-hasura-role')) {
|
|
46
|
+
headers.set('x-hasura-role', role);
|
|
47
47
|
}
|
|
48
48
|
return next(url, { ...requestOptions, headers });
|
|
49
49
|
};
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This module provides functionality for executing serverless function calls
|
|
5
5
|
* against Nhost serverless functions.
|
|
6
6
|
*/
|
|
7
|
-
import { type ChainFunction, type FetchResponse } from
|
|
7
|
+
import { type ChainFunction, type FetchResponse } from '../fetch';
|
|
8
8
|
/**
|
|
9
9
|
* Functions client interface providing methods for executing serverless function calls
|
|
10
10
|
*/
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This module provides functionality for executing serverless function calls
|
|
5
5
|
* against Nhost serverless functions.
|
|
6
6
|
*/
|
|
7
|
-
import { createEnhancedFetch, FetchError, } from
|
|
7
|
+
import { createEnhancedFetch, FetchError, } from '../fetch';
|
|
8
8
|
/**
|
|
9
9
|
* Creates a Functions API client for interacting with serverless functions.
|
|
10
10
|
*
|
|
@@ -36,10 +36,10 @@ export const createAPIClient = (baseURL, chainFunctions = []) => {
|
|
|
36
36
|
const resp = await enhancedFetch(`${baseURL}${path}`, options);
|
|
37
37
|
let body;
|
|
38
38
|
// Process response based on content type
|
|
39
|
-
if (resp.headers.get(
|
|
39
|
+
if (resp.headers.get('content-type')?.includes('application/json')) {
|
|
40
40
|
body = (await resp.json());
|
|
41
41
|
}
|
|
42
|
-
else if (resp.headers.get(
|
|
42
|
+
else if (resp.headers.get('content-type')?.startsWith('text/')) {
|
|
43
43
|
body = await resp.text();
|
|
44
44
|
}
|
|
45
45
|
else {
|
|
@@ -73,10 +73,10 @@ export const createAPIClient = (baseURL, chainFunctions = []) => {
|
|
|
73
73
|
// Ensure the method is POST and set the body
|
|
74
74
|
const requestOptions = {
|
|
75
75
|
...options,
|
|
76
|
-
method:
|
|
76
|
+
method: 'POST',
|
|
77
77
|
headers: {
|
|
78
|
-
Accept:
|
|
79
|
-
|
|
78
|
+
Accept: 'application/json',
|
|
79
|
+
'Content-Type': 'application/json',
|
|
80
80
|
...options.headers,
|
|
81
81
|
},
|
|
82
82
|
body: body ? JSON.stringify(body) : undefined,
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* This module provides functionality for executing GraphQL operations against
|
|
5
5
|
* a Hasura GraphQL API.
|
|
6
6
|
*/
|
|
7
|
-
import type { TypedDocumentNode } from
|
|
8
|
-
import { type ChainFunction, type FetchResponse } from
|
|
7
|
+
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
8
|
+
import { type ChainFunction, type FetchResponse } from '../fetch';
|
|
9
9
|
/**
|
|
10
10
|
* Variables object for GraphQL operations.
|
|
11
11
|
* Key-value pairs of variable names and their values.
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* This module provides functionality for executing GraphQL operations against
|
|
5
5
|
* a Hasura GraphQL API.
|
|
6
6
|
*/
|
|
7
|
-
import { createEnhancedFetch, FetchError, } from
|
|
7
|
+
import { createEnhancedFetch, FetchError, } from '../fetch';
|
|
8
8
|
/**
|
|
9
9
|
* Creates a GraphQL API client for interacting with a GraphQL endpoint.
|
|
10
10
|
*
|
|
@@ -24,9 +24,9 @@ export const createAPIClient = (url, chainFunctions = []) => {
|
|
|
24
24
|
};
|
|
25
25
|
const executeOperation = async (request, options) => {
|
|
26
26
|
const response = await enhancedFetch(`${url}`, {
|
|
27
|
-
method:
|
|
27
|
+
method: 'POST',
|
|
28
28
|
headers: {
|
|
29
|
-
|
|
29
|
+
'Content-Type': 'application/json',
|
|
30
30
|
},
|
|
31
31
|
body: JSON.stringify(request),
|
|
32
32
|
...options,
|
|
@@ -44,12 +44,12 @@ export const createAPIClient = (url, chainFunctions = []) => {
|
|
|
44
44
|
return resp;
|
|
45
45
|
};
|
|
46
46
|
function request(requestOrDocument, variablesOrOptions, options) {
|
|
47
|
-
if (typeof requestOrDocument ===
|
|
47
|
+
if (typeof requestOrDocument === 'object' && 'kind' in requestOrDocument) {
|
|
48
48
|
const definition = requestOrDocument.definitions[0];
|
|
49
49
|
const request = {
|
|
50
|
-
query: requestOrDocument.loc?.source.body ||
|
|
50
|
+
query: requestOrDocument.loc?.source.body || '',
|
|
51
51
|
variables: variablesOrOptions,
|
|
52
|
-
operationName: definition &&
|
|
52
|
+
operationName: definition && 'name' in definition
|
|
53
53
|
? definition.name?.value
|
|
54
54
|
: undefined,
|
|
55
55
|
};
|
package/dist/src/index.d.ts
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
*
|
|
32
32
|
* @packageDocumentation
|
|
33
33
|
*/
|
|
34
|
-
export { type ClientConfigurationFn, createClient, createNhostClient, createServerClient, type NhostClient, type NhostClientOptions, type NhostServerClientOptions, withAdminSession, withClientSideSessionMiddleware, withServerSideSessionMiddleware, } from
|
|
34
|
+
export { type ClientConfigurationFn, createClient, createNhostClient, createServerClient, type NhostClient, type NhostClientOptions, type NhostServerClientOptions, withAdminSession, withClientSideSessionMiddleware, withServerSideSessionMiddleware, } from './nhost';
|
|
35
35
|
/**
|
|
36
36
|
* Generates a base URL for a Nhost service based on configuration
|
|
37
37
|
*
|
package/dist/src/index.js
CHANGED
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
*
|
|
32
32
|
* @packageDocumentation
|
|
33
33
|
*/
|
|
34
|
-
export { createClient, createNhostClient, createServerClient, withAdminSession, withClientSideSessionMiddleware, withServerSideSessionMiddleware, } from
|
|
34
|
+
export { createClient, createNhostClient, createServerClient, withAdminSession, withClientSideSessionMiddleware, withServerSideSessionMiddleware, } from './nhost';
|
|
35
35
|
/**
|
|
36
36
|
* Generates a base URL for a Nhost service based on configuration
|
|
37
37
|
*
|
package/dist/src/nhost.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { type Client as AuthClient } from
|
|
2
|
-
import { type AdminSessionOptions, type ChainFunction } from
|
|
3
|
-
import { type Client as FunctionsClient } from
|
|
4
|
-
import { type Client as GraphQLClient } from
|
|
5
|
-
import { type Session, SessionStorage, type SessionStorageBackend } from
|
|
6
|
-
import { type Client as StorageClient } from
|
|
1
|
+
import { type Client as AuthClient } from './auth';
|
|
2
|
+
import { type AdminSessionOptions, type ChainFunction } from './fetch';
|
|
3
|
+
import { type Client as FunctionsClient } from './functions';
|
|
4
|
+
import { type Client as GraphQLClient } from './graphql';
|
|
5
|
+
import { type Session, SessionStorage, type SessionStorageBackend } from './session/';
|
|
6
|
+
import { type Client as StorageClient } from './storage';
|
|
7
7
|
/**
|
|
8
8
|
* Configuration function that receives all clients and can configure them
|
|
9
9
|
* (e.g., by attaching middleware, setting up interceptors, etc.)
|
package/dist/src/nhost.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { generateServiceUrl } from
|
|
2
|
-
import { createAPIClient as createAuthClient, } from
|
|
3
|
-
import { attachAccessTokenMiddleware, sessionRefreshMiddleware, updateSessionFromResponseMiddleware, withAdminSessionMiddleware, } from
|
|
4
|
-
import { createAPIClient as createFunctionsClient, } from
|
|
5
|
-
import { createAPIClient as createGraphQLClient, } from
|
|
6
|
-
import { detectStorage, refreshSession, SessionStorage, } from
|
|
7
|
-
import { createAPIClient as createStorageClient, } from
|
|
1
|
+
import { generateServiceUrl } from './';
|
|
2
|
+
import { createAPIClient as createAuthClient, } from './auth';
|
|
3
|
+
import { attachAccessTokenMiddleware, sessionRefreshMiddleware, updateSessionFromResponseMiddleware, withAdminSessionMiddleware, } from './fetch';
|
|
4
|
+
import { createAPIClient as createFunctionsClient, } from './functions';
|
|
5
|
+
import { createAPIClient as createGraphQLClient, } from './graphql';
|
|
6
|
+
import { detectStorage, refreshSession, SessionStorage, } from './session/';
|
|
7
|
+
import { createAPIClient as createStorageClient, } from './storage';
|
|
8
8
|
/**
|
|
9
9
|
* Built-in configuration for client-side applications.
|
|
10
10
|
* Includes automatic session refresh, token attachment, and session updates.
|
|
@@ -233,10 +233,10 @@ export function createNhostClient(options = {}) {
|
|
|
233
233
|
const { subdomain, region, authUrl, storageUrl, graphqlUrl, functionsUrl, storage = detectStorage(), configure = [], } = options;
|
|
234
234
|
const sessionStorage = new SessionStorage(storage);
|
|
235
235
|
// Determine base URLs for each service
|
|
236
|
-
const authBaseUrl = generateServiceUrl(
|
|
237
|
-
const storageBaseUrl = generateServiceUrl(
|
|
238
|
-
const graphqlBaseUrl = generateServiceUrl(
|
|
239
|
-
const functionsBaseUrl = generateServiceUrl(
|
|
236
|
+
const authBaseUrl = generateServiceUrl('auth', subdomain, region, authUrl);
|
|
237
|
+
const storageBaseUrl = generateServiceUrl('storage', subdomain, region, storageUrl);
|
|
238
|
+
const graphqlBaseUrl = generateServiceUrl('graphql', subdomain, region, graphqlUrl);
|
|
239
|
+
const functionsBaseUrl = generateServiceUrl('functions', subdomain, region, functionsUrl);
|
|
240
240
|
// Create all clients
|
|
241
241
|
const auth = createAuthClient(authBaseUrl);
|
|
242
242
|
const storageClient = createStorageClient(storageBaseUrl, []);
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
*
|
|
14
14
|
* @packageDocumentation
|
|
15
15
|
*/
|
|
16
|
-
export { refreshSession } from
|
|
17
|
-
export type { DecodedToken, Session } from
|
|
18
|
-
export { detectStorage, type SessionChangeCallback, SessionStorage, } from
|
|
19
|
-
export { CookieStorage, DEFAULT_SESSION_KEY, LocalStorage, MemoryStorage, type SessionStorageBackend, } from
|
|
16
|
+
export { refreshSession } from './refreshSession';
|
|
17
|
+
export type { DecodedToken, Session } from './session';
|
|
18
|
+
export { detectStorage, type SessionChangeCallback, SessionStorage, } from './storage';
|
|
19
|
+
export { CookieStorage, DEFAULT_SESSION_KEY, LocalStorage, MemoryStorage, type SessionStorageBackend, } from './storageBackend';
|
|
20
20
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* @packageDocumentation
|
|
15
15
|
*/
|
|
16
|
-
export { refreshSession } from
|
|
17
|
-
export { detectStorage, SessionStorage, } from
|
|
18
|
-
export { CookieStorage, DEFAULT_SESSION_KEY, LocalStorage, MemoryStorage, } from
|
|
16
|
+
export { refreshSession } from './refreshSession';
|
|
17
|
+
export { detectStorage, SessionStorage, } from './storage';
|
|
18
|
+
export { CookieStorage, DEFAULT_SESSION_KEY, LocalStorage, MemoryStorage, } from './storageBackend';
|
|
19
19
|
//# sourceMappingURL=index.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Client as AuthClient } from
|
|
2
|
-
import type { Session } from
|
|
3
|
-
import type { SessionStorage } from
|
|
1
|
+
import type { Client as AuthClient } from '../auth';
|
|
2
|
+
import type { Session } from './session';
|
|
3
|
+
import type { SessionStorage } from './storage';
|
|
4
4
|
/**
|
|
5
5
|
* Refreshes the authentication session if needed
|
|
6
6
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refreshSession.d.ts","sourceRoot":"","sources":["../../../src/session/refreshSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAiB,MAAM,SAAS,CAAC;AAEnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"refreshSession.d.ts","sourceRoot":"","sources":["../../../src/session/refreshSession.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAiB,MAAM,SAAS,CAAC;AAEnE,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AA4BhD;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,GACzB,MAAM,UAAU,EAChB,SAAS,cAAc,EACvB,sBAAkB,KACjB,OAAO,CAAC,OAAO,GAAG,IAAI,CAmBxB,CAAC"}
|
|
@@ -5,9 +5,7 @@ class DummyLock {
|
|
|
5
5
|
return callback();
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
-
const lock =
|
|
9
|
-
// biome-ignore lint/complexity/useOptionalChain: this check breaks non-browser environments
|
|
10
|
-
typeof navigator !== "undefined" && navigator.locks
|
|
8
|
+
const lock = typeof navigator !== 'undefined' && navigator.locks
|
|
11
9
|
? navigator.locks
|
|
12
10
|
: new DummyLock();
|
|
13
11
|
/**
|
|
@@ -30,14 +28,14 @@ export const refreshSession = async (auth, storage, marginSeconds = 60) => {
|
|
|
30
28
|
try {
|
|
31
29
|
// we retry the refresh token in case of transient error
|
|
32
30
|
// or race conditions
|
|
33
|
-
console.warn(
|
|
31
|
+
console.warn('error refreshing session, retrying:', error);
|
|
34
32
|
return await _refreshSession(auth, storage, marginSeconds);
|
|
35
33
|
}
|
|
36
34
|
catch (error) {
|
|
37
35
|
const errResponse = error;
|
|
38
36
|
if (errResponse?.status === 401) {
|
|
39
37
|
// this probably means the refresh token is invalid
|
|
40
|
-
console.error(
|
|
38
|
+
console.error('session probably expired');
|
|
41
39
|
storage.remove();
|
|
42
40
|
}
|
|
43
41
|
return null;
|
|
@@ -54,7 +52,7 @@ export const refreshSession = async (auth, storage, marginSeconds = 60) => {
|
|
|
54
52
|
* @private
|
|
55
53
|
*/
|
|
56
54
|
const _refreshSession = async (auth, storage, marginSeconds = 60) => {
|
|
57
|
-
const { session, needsRefresh, } = await lock.request(
|
|
55
|
+
const { session, needsRefresh, } = await lock.request('nhostSessionLock', { mode: 'shared' }, async () => {
|
|
58
56
|
return _needsRefresh(storage, marginSeconds);
|
|
59
57
|
});
|
|
60
58
|
if (!session) {
|
|
@@ -63,7 +61,7 @@ const _refreshSession = async (auth, storage, marginSeconds = 60) => {
|
|
|
63
61
|
if (!needsRefresh) {
|
|
64
62
|
return session; // No need to refresh
|
|
65
63
|
}
|
|
66
|
-
const refreshedSession = await lock.request(
|
|
64
|
+
const refreshedSession = await lock.request('nhostSessionLock', { mode: 'exclusive' }, async () => {
|
|
67
65
|
const { session, needsRefresh, sessionExpired } = _needsRefresh(storage, marginSeconds);
|
|
68
66
|
if (!session) {
|
|
69
67
|
return null; // No session found
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"refreshSession.js","sourceRoot":"","sources":["../../../src/session/refreshSession.ts"],"names":[],"mappings":"AAKA,MAAM,SAAS;IACb,KAAK,CAAC,OAAO,CACX,KAAa,EACb,QAA0C;IAC1C,kDAAkD;IAClD,QAA4B;QAE5B,OAAO,QAAQ,EAAE,CAAC;IACpB,CAAC;CACF;AAYD,MAAM,IAAI
|
|
1
|
+
{"version":3,"file":"refreshSession.js","sourceRoot":"","sources":["../../../src/session/refreshSession.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Session as AuthSession } from
|
|
1
|
+
import type { Session as AuthSession } from '../auth';
|
|
2
2
|
/**
|
|
3
3
|
* Decoded JWT token payload with processed timestamps and Hasura claims
|
|
4
4
|
*/
|
|
@@ -12,7 +12,7 @@ export interface DecodedToken {
|
|
|
12
12
|
/** Token subject (user ID) */
|
|
13
13
|
sub?: string;
|
|
14
14
|
/** Hasura JWT claims with PostgreSQL arrays converted to JavaScript arrays */
|
|
15
|
-
|
|
15
|
+
'https://hasura.io/jwt/claims'?: Record<string, unknown>;
|
|
16
16
|
/** Any other JWT claims */
|
|
17
17
|
[key: string]: unknown;
|
|
18
18
|
}
|
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
export const decodeUserSession = (accessToken) => {
|
|
2
|
-
const s = accessToken.split(
|
|
2
|
+
const s = accessToken.split('.');
|
|
3
3
|
if (s.length !== 3 || !s[1]) {
|
|
4
|
-
throw new Error(
|
|
4
|
+
throw new Error('Invalid access token format');
|
|
5
5
|
}
|
|
6
|
-
const decodedToken = JSON.parse(typeof atob !==
|
|
6
|
+
const decodedToken = JSON.parse(typeof atob !== 'undefined'
|
|
7
7
|
? atob(s[1])
|
|
8
|
-
: Buffer.from(s[1],
|
|
8
|
+
: Buffer.from(s[1], 'base64').toString('utf-8'));
|
|
9
9
|
// Convert iat and exp to Date objects
|
|
10
|
-
const iat = typeof decodedToken[
|
|
11
|
-
? decodedToken[
|
|
10
|
+
const iat = typeof decodedToken['iat'] === 'number'
|
|
11
|
+
? decodedToken['iat'] * 1000 // Convert seconds to milliseconds
|
|
12
12
|
: undefined;
|
|
13
|
-
const exp = typeof decodedToken[
|
|
14
|
-
? decodedToken[
|
|
13
|
+
const exp = typeof decodedToken['exp'] === 'number'
|
|
14
|
+
? decodedToken['exp'] * 1000 // Convert seconds to milliseconds
|
|
15
15
|
: undefined;
|
|
16
16
|
// Process Hasura claims - dynamically convert PostgreSQL array notation to arrays
|
|
17
|
-
const hasuraClaims = decodedToken[
|
|
17
|
+
const hasuraClaims = decodedToken['https://hasura.io/jwt/claims'];
|
|
18
18
|
const processedClaims = hasuraClaims
|
|
19
19
|
? Object.entries(hasuraClaims).reduce((acc, [key, value]) => {
|
|
20
|
-
if (typeof value ===
|
|
20
|
+
if (typeof value === 'string' && isPostgresArray(value)) {
|
|
21
21
|
acc[key] = parsePostgresArray(value);
|
|
22
22
|
}
|
|
23
23
|
else {
|
|
@@ -30,19 +30,19 @@ export const decodeUserSession = (accessToken) => {
|
|
|
30
30
|
...decodedToken,
|
|
31
31
|
iat,
|
|
32
32
|
exp,
|
|
33
|
-
|
|
33
|
+
'https://hasura.io/jwt/claims': processedClaims,
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
36
|
const isPostgresArray = (value) => {
|
|
37
|
-
return value.startsWith(
|
|
37
|
+
return value.startsWith('{') && value.endsWith('}');
|
|
38
38
|
};
|
|
39
39
|
const parsePostgresArray = (value) => {
|
|
40
|
-
if (!value || value ===
|
|
40
|
+
if (!value || value === '{}')
|
|
41
41
|
return [];
|
|
42
42
|
// Remove curly braces and split by comma, handling quoted values
|
|
43
43
|
return value
|
|
44
44
|
.slice(1, -1)
|
|
45
|
-
.split(
|
|
46
|
-
.map((item) => item.trim().replace(/^"(.*)"$/,
|
|
45
|
+
.split(',')
|
|
46
|
+
.map((item) => item.trim().replace(/^"(.*)"$/, '$1'));
|
|
47
47
|
};
|
|
48
48
|
//# sourceMappingURL=session.js.map
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* This module provides different storage adapters for persisting authentication sessions
|
|
5
5
|
* across page reloads and browser sessions.
|
|
6
6
|
*/
|
|
7
|
-
import type { Session as AuthSession } from
|
|
8
|
-
import { type Session } from
|
|
9
|
-
import { type SessionStorageBackend } from
|
|
7
|
+
import type { Session as AuthSession } from '../auth';
|
|
8
|
+
import { type Session } from './session';
|
|
9
|
+
import { type SessionStorageBackend } from './storageBackend';
|
|
10
10
|
/**
|
|
11
11
|
* Callback function type for session change subscriptions
|
|
12
12
|
*/
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* This module provides different storage adapters for persisting authentication sessions
|
|
5
5
|
* across page reloads and browser sessions.
|
|
6
6
|
*/
|
|
7
|
-
import { decodeUserSession } from
|
|
8
|
-
import { LocalStorage, MemoryStorage, } from
|
|
7
|
+
import { decodeUserSession } from './session';
|
|
8
|
+
import { LocalStorage, MemoryStorage, } from './storageBackend';
|
|
9
9
|
/**
|
|
10
10
|
* A wrapper around any SessionStorageInterface implementation that adds
|
|
11
11
|
* the ability to subscribe to session changes.
|
|
@@ -68,7 +68,7 @@ export class SessionStorage {
|
|
|
68
68
|
subscriber(session);
|
|
69
69
|
}
|
|
70
70
|
catch (error) {
|
|
71
|
-
console.error(
|
|
71
|
+
console.error('Error notifying subscriber:', error);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
}
|
|
@@ -83,7 +83,7 @@ export class SessionStorage {
|
|
|
83
83
|
* @returns The best available storage implementation as a SessionStorageBackend
|
|
84
84
|
*/
|
|
85
85
|
export const detectStorage = () => {
|
|
86
|
-
if (typeof window !==
|
|
86
|
+
if (typeof window !== 'undefined') {
|
|
87
87
|
return new LocalStorage();
|
|
88
88
|
}
|
|
89
89
|
return new MemoryStorage();
|