nextjs-hasura-auth 0.1.2 → 0.1.3
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/APOLLO.md +101 -174
- package/dist/lib/apollo.d.ts +2 -0
- package/dist/lib/apollo.js +243 -0
- package/dist/lib/authDbUtils.d.ts +48 -0
- package/dist/lib/authDbUtils.js +183 -0
- package/dist/lib/client.d.ts +43 -44
- package/dist/lib/client.js +353 -0
- package/dist/lib/email.d.ts +7 -0
- package/dist/lib/email.js +90 -0
- package/dist/lib/graphql-proxy.d.ts +6 -0
- package/dist/lib/graphql-proxy.js +385 -0
- package/dist/lib/hasura-schema.js +0 -7
- package/dist/lib/hooks/useCheckConnection.d.ts +7 -0
- package/dist/lib/hooks/useCheckConnection.js +62 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +1 -0
- package/dist/lib/test-utils.d.ts +11 -0
- package/dist/lib/test-utils.js +59 -0
- package/dist/lib/tokenUtils.d.ts +14 -0
- package/dist/lib/tokenUtils.js +94 -0
- package/dist/package.json +8 -4
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +8 -4
- package/dist/lib/apollo.jsx +0 -181
- package/dist/lib/client.jsx +0 -237
- /package/dist/lib/{auth.jsx → auth.js} +0 -0
package/APOLLO.md
CHANGED
@@ -1,174 +1,101 @@
|
|
1
|
-
# Apollo Client Setup (`
|
2
|
-
|
3
|
-
This
|
4
|
-
|
5
|
-
##
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
function UserProfile() {
|
103
|
-
// Assume user ID is available, e.g., from session or props
|
104
|
-
const userId = '...';
|
105
|
-
|
106
|
-
const GET_USER = gql`
|
107
|
-
query GetUser($userId: uuid!) {
|
108
|
-
users_by_pk(id: $userId) {
|
109
|
-
id
|
110
|
-
name
|
111
|
-
email
|
112
|
-
}
|
113
|
-
}
|
114
|
-
`;
|
115
|
-
|
116
|
-
// The client from ApolloWrapper's context is used automatically
|
117
|
-
const { loading, error, data } = useQuery(GET_USER, {
|
118
|
-
variables: { userId }
|
119
|
-
});
|
120
|
-
|
121
|
-
// ... render logic ...
|
122
|
-
}
|
123
|
-
```
|
124
|
-
|
125
|
-
### Server-Side (SSR/SSG/Server Components/API Routes)
|
126
|
-
|
127
|
-
1. **Create Client Instance:** Use `createApolloClient` directly. You need to decide how to authenticate:
|
128
|
-
* **Admin Access:** Pass the admin secret (e.g., from environment variables) using the `secret` option if you need privileged access.
|
129
|
-
* **User Access:** If running in the context of a specific user request, obtain their Hasura JWT (e.g., from session data, request headers) and pass it using the `token` option.
|
130
|
-
|
131
|
-
```typescript
|
132
|
-
// Example in an API Route or Server Component
|
133
|
-
import { createApolloClient } from '@/lib/apollo'; // Adjust path
|
134
|
-
import { gql } from '@apollo/client';
|
135
|
-
// import { getToken } from "next-auth/jwt"
|
136
|
-
|
137
|
-
async function getUserDataOnServer(userId: string, request?: Request) {
|
138
|
-
// Option 1: Use Admin Secret for privileged access
|
139
|
-
// const client = createApolloClient({
|
140
|
-
// secret: process.env.HASURA_ADMIN_SECRET // Ensure secret is available server-side
|
141
|
-
// });
|
142
|
-
|
143
|
-
// Option 2: Use User Token (if available from request/session)
|
144
|
-
// Example: const sessionToken = await getToken({ req: request, secret: process.env.NEXTAUTH_SECRET });
|
145
|
-
// const hasuraToken = sessionToken?.accessToken;
|
146
|
-
const client = createApolloClient({
|
147
|
-
token: process.env.SOME_SERVICE_ACCOUNT_TOKEN_IF_NEEDED // Or fetch user token if applicable
|
148
|
-
// url: process.env.NEXT_PUBLIC_HASURA_GRAPHQL_URL // URL can also be passed explicitly
|
149
|
-
});
|
150
|
-
|
151
|
-
const GET_USER = gql`...`; // Your query
|
152
|
-
|
153
|
-
try {
|
154
|
-
const { data } = await client.query({
|
155
|
-
query: GET_USER,
|
156
|
-
variables: { userId },
|
157
|
-
// Important for server-side: Avoid using client-side cache
|
158
|
-
fetchPolicy: 'network-only',
|
159
|
-
});
|
160
|
-
return data.users_by_pk;
|
161
|
-
} catch (error) {
|
162
|
-
console.error('Error fetching user data:', error);
|
163
|
-
return null;
|
164
|
-
}
|
165
|
-
}
|
166
|
-
```
|
167
|
-
|
168
|
-
2. **Fetch Data:** Use `client.query(...)` or `client.mutate(...)`.
|
169
|
-
|
170
|
-
## Important Considerations
|
171
|
-
|
172
|
-
* **JWT Token:** Ensure your authentication system (like `next-auth`) generates a Hasura-compatible JWT containing the necessary `https://hasura.io/jwt/claims` and includes it in the session data (e.g., as `session.accessToken`) for the client-side integration to work.
|
173
|
-
* **Environment Variables:** Securely manage `HASURA_ADMIN_SECRET`, `NEXTAUTH_SECRET`, and potentially `HASURA_JWT_SECRET` using environment variable configuration in your hosting provider (e.g., Vercel). `NEXT_PUBLIC_HASURA_GRAPHQL_URL` needs to be accessible client-side.
|
174
|
-
* **WebSocket Security:** WebSocket connections initiated from the client include the token/secret directly in the `connectionParams`. Ensure your Hasura endpoint is properly secured (e.g., using HTTPS/WSS).
|
1
|
+
# Apollo Client Setup (`lib/apollo.tsx`)
|
2
|
+
|
3
|
+
This file provides the `useCreateApolloClient` hook, a crucial part of the library for interacting with your Hasura GraphQL backend.
|
4
|
+
|
5
|
+
## `useCreateApolloClient` Hook
|
6
|
+
|
7
|
+
A React hook to create and memoize an Apollo Client instance configured for the Hasura backend.
|
8
|
+
|
9
|
+
```tsx
|
10
|
+
import { useCreateApolloClient } from 'nextjs-hasura-auth';
|
11
|
+
|
12
|
+
function MyComponent() {
|
13
|
+
// Create client for HTTP only
|
14
|
+
const apolloClientHttp = useCreateApolloClient({ token: 'your-auth-token' });
|
15
|
+
|
16
|
+
// Create client for HTTP and WebSocket (subscriptions)
|
17
|
+
const apolloClientWs = useCreateApolloClient({ token: 'your-auth-token', ws: true });
|
18
|
+
|
19
|
+
// ... use apolloClient
|
20
|
+
}
|
21
|
+
```
|
22
|
+
|
23
|
+
### Purpose
|
24
|
+
|
25
|
+
This hook simplifies the setup of an Apollo Client tailored for Hasura environments, handling both HTTP and WebSocket connections, authentication headers, and role management.
|
26
|
+
|
27
|
+
### Arguments
|
28
|
+
|
29
|
+
- `options` (object):
|
30
|
+
- `token` (string | undefined): Optional authentication token (JWT) to be included in headers.
|
31
|
+
- `ws` (boolean): Optional flag (default: `false`) to enable WebSocket connection for subscriptions.
|
32
|
+
|
33
|
+
### Return Value
|
34
|
+
|
35
|
+
- `ApolloClient<NormalizedCacheObject>`: An initialized and memoized Apollo Client instance.
|
36
|
+
|
37
|
+
### Key Features
|
38
|
+
|
39
|
+
1. **HTTP Link (`httpLink`)**: Configured for standard GraphQL operations (queries, mutations) using `createHttpLink`.
|
40
|
+
2. **WebSocket Link (`wsLink`)**: Configured for GraphQL subscriptions using `graphql-ws`. Enabled only if `ws: true` is passed in the options. It uses `createClient` from `graphql-ws`.
|
41
|
+
3. **Role Link (`roleLink`)**: **New!** This is an `ApolloLink` middleware using `setContext` that intercepts outgoing **HTTP requests**. It checks the `context` object passed to the Apollo operation (e.g., in `useQuery`, `useMutation`). If a `role` property is found in the operation's context, it adds the `X-Hasura-Role` header to the HTTP request with the specified role.
|
42
|
+
* **Important Note:** This dynamic role setting via context currently **only works for HTTP requests** (queries and mutations). It **does not** dynamically set the role for WebSocket connections (subscriptions). For subscriptions, the role is determined by the `connectionParams` when the WebSocket connection is established, which typically uses the `token` provided to `useCreateApolloClient` to infer the role on the backend.
|
43
|
+
4. **Authentication Headers**:
|
44
|
+
* For HTTP requests, it automatically includes `Authorization: Bearer <token>` (if provided) and `X-Hasura-Admin-Secret` (if `process.env.HASURA_ADMIN_SECRET` is set). The `roleLink` adds the `X-Hasura-Role` header if a `role` is provided in the operation's context.
|
45
|
+
* For WebSocket connections, `connectionParams` are set with `headers` containing `Authorization` and `X-Hasura-Admin-Secret`.
|
46
|
+
5. **Request Splitting**: Uses `split` to direct operations to `httpLink` (via `roleLink` and `authLink`) or `wsLink` based on the operation type. Subscriptions go to `wsLink` (if `ws: true`), others go to `httpLink`.
|
47
|
+
6. **Error Handling (`errorLink`)**: Includes basic error logging for GraphQL and network errors using `onError`.
|
48
|
+
7. **Caching**: Uses `InMemoryCache` for client-side caching.
|
49
|
+
8. **Memoization**: The `useMemo` hook ensures the client instance is created only once per component lifecycle or when the `token` or `ws` options change, preventing unnecessary client recreations.
|
50
|
+
|
51
|
+
### How `roleLink` Works
|
52
|
+
|
53
|
+
The `roleLink` leverages Apollo Link's `setContext` middleware.
|
54
|
+
|
55
|
+
```typescript
|
56
|
+
// Simplified logic within useCreateApolloClient
|
57
|
+
import { setContext } from '@apollo/client/link/context';
|
58
|
+
|
59
|
+
const roleLink = setContext((_operation, context) => {
|
60
|
+
// context here is the *link* context, which includes headers etc.
|
61
|
+
// and importantly, the context passed from the hook/operation call.
|
62
|
+
const operationContext = context?.graphqlContext || {}; // Access context passed from useQuery/useMutation etc.
|
63
|
+
const role = operationContext.role; // Get the role from the operation's context
|
64
|
+
|
65
|
+
// If a role is provided in the operation's context, add it to the headers
|
66
|
+
if (role) {
|
67
|
+
return {
|
68
|
+
headers: {
|
69
|
+
...context.headers, // Preserve existing headers (like Authorization)
|
70
|
+
'X-Hasura-Role': role,
|
71
|
+
},
|
72
|
+
};
|
73
|
+
}
|
74
|
+
|
75
|
+
// Otherwise, return the existing headers unchanged
|
76
|
+
return {
|
77
|
+
headers: context.headers,
|
78
|
+
};
|
79
|
+
});
|
80
|
+
|
81
|
+
// This roleLink is then chained before the httpLink:
|
82
|
+
// link: from([errorLink, roleLink, authLink, httpLink]) // for HTTP
|
83
|
+
```
|
84
|
+
|
85
|
+
When you use the data fetching hooks from `lib/client.tsx` (like `useQuery`, `useMutation`) and pass a `role` in the `hookOptions`, that `role` becomes part of the operation's context (`graphqlContext`), which `roleLink` then reads to set the appropriate `X-Hasura-Role` header for that specific HTTP request.
|
86
|
+
|
87
|
+
```tsx
|
88
|
+
// Example using useQuery with a role
|
89
|
+
const { data } = useQuery(GET_POSTS, {
|
90
|
+
hookOptions: {
|
91
|
+
// These options are passed to Apollo's useQuery
|
92
|
+
variables: { limit: 10 },
|
93
|
+
// This context object is passed along the link chain
|
94
|
+
context: {
|
95
|
+
role: 'editor', // roleLink will pick this up
|
96
|
+
},
|
97
|
+
},
|
98
|
+
});
|
99
|
+
```
|
100
|
+
|
101
|
+
This allows for fine-grained role control on a per-operation basis for queries and mutations. Remember, WebSocket subscriptions rely on the role established during the initial connection based on the token.
|
package/dist/lib/apollo.d.ts
CHANGED
@@ -31,6 +31,8 @@ export declare function getClient(options?: {}): ApolloClient<any>;
|
|
31
31
|
* @returns Apollo client instance
|
32
32
|
*/
|
33
33
|
export declare function useCreateApolloClient(options: ApolloOptions): ApolloClientWithProvider;
|
34
|
+
export declare const CHECK_CONNECTION_SUBSCRIPTION: import("@apollo/client").DocumentNode;
|
35
|
+
export declare const CHECK_CONNECTION_QUERY: import("@apollo/client").DocumentNode;
|
34
36
|
/**
|
35
37
|
* Check connection to Hasura GraphQL endpoint
|
36
38
|
* @returns {Promise<boolean>} True if connection is successful
|
@@ -0,0 +1,243 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
9
|
+
});
|
10
|
+
};
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
13
|
+
};
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
15
|
+
exports.CHECK_CONNECTION_QUERY = exports.CHECK_CONNECTION_SUBSCRIPTION = void 0;
|
16
|
+
exports.createApolloClient = createApolloClient;
|
17
|
+
exports.getClient = getClient;
|
18
|
+
exports.useCreateApolloClient = useCreateApolloClient;
|
19
|
+
exports.checkConnection = checkConnection;
|
20
|
+
const jsx_runtime_1 = require("react/jsx-runtime");
|
21
|
+
const client_1 = require("@apollo/client");
|
22
|
+
const context_1 = require("@apollo/client/link/context");
|
23
|
+
const utilities_1 = require("@apollo/client/utilities");
|
24
|
+
// Restore GraphQLWsLink imports
|
25
|
+
const subscriptions_1 = require("@apollo/client/link/subscriptions");
|
26
|
+
const graphql_ws_1 = require("graphql-ws");
|
27
|
+
const cross_fetch_1 = __importDefault(require("cross-fetch"));
|
28
|
+
const debug_1 = __importDefault(require("./debug"));
|
29
|
+
const react_1 = require("react");
|
30
|
+
const jwt_1 = require("./jwt");
|
31
|
+
// Remove deprecated WebSocketLink import
|
32
|
+
// import { WebSocketLink } from '@apollo/client/link/ws';
|
33
|
+
const error_1 = require("@apollo/client/link/error");
|
34
|
+
// Create a debug logger for this module
|
35
|
+
const debug = (0, debug_1.default)('apollo');
|
36
|
+
// Determine if running on client
|
37
|
+
const isClient = typeof window !== 'undefined';
|
38
|
+
const createRoleLink = () => (0, context_1.setContext)((request, previousContext) => {
|
39
|
+
// Get the role from the operation's context passed in the hook options
|
40
|
+
const role = previousContext === null || previousContext === void 0 ? void 0 : previousContext.role; // Correctly access context via the second argument
|
41
|
+
debug(`roleLink: Role from context: ${role}`);
|
42
|
+
if (role) {
|
43
|
+
return {
|
44
|
+
headers: Object.assign(Object.assign({}, previousContext.headers), { 'X-Hasura-Role': role }),
|
45
|
+
};
|
46
|
+
}
|
47
|
+
// If no role is provided in the context, don't add the header
|
48
|
+
return {};
|
49
|
+
});
|
50
|
+
/**
|
51
|
+
* Create Apollo Client
|
52
|
+
*
|
53
|
+
* @param {Object} options - Options for creating the client
|
54
|
+
* @param {boolean} options.ws - Use WebSocket connection
|
55
|
+
* @param {string} options.token - JWT token for authorization
|
56
|
+
* @param {string} options.secret - Admin secret for Hasura
|
57
|
+
* @returns {ApolloClient} Apollo Client
|
58
|
+
*/
|
59
|
+
function createApolloClient(options = {}) {
|
60
|
+
// Default values
|
61
|
+
const { url = process.env.NEXT_PUBLIC_HASURA_GRAPHQL_URL, ws = false, token = undefined, secret = process.env.HASURA_ADMIN_SECRET } = options;
|
62
|
+
if (!url) {
|
63
|
+
throw new Error('❌ options.url or NEXT_PUBLIC_HASURA_GRAPHQL_URL not defined');
|
64
|
+
}
|
65
|
+
debug('apollo', '🔌 Creating Apollo client with endpoint:', url);
|
66
|
+
// --- NEW: Link to set Hasura Role Header ---
|
67
|
+
const roleLink = createRoleLink();
|
68
|
+
// --- END NEW ---
|
69
|
+
// --- Existing Links ---
|
70
|
+
// Create base HttpLink (no auth here initially)
|
71
|
+
const baseHttpLink = new client_1.HttpLink({
|
72
|
+
uri: url,
|
73
|
+
fetch: cross_fetch_1.default,
|
74
|
+
});
|
75
|
+
// Create link for adding auth (JWT or Admin Secret)
|
76
|
+
const authHeaderLink = (0, context_1.setContext)((_, { headers }) => {
|
77
|
+
// Return the headers to the context so httpLink can read them
|
78
|
+
if (token) {
|
79
|
+
debug('apollo', '🔒 Using JWT token for Authorization header');
|
80
|
+
return {
|
81
|
+
headers: Object.assign(Object.assign({}, headers), { Authorization: `Bearer ${token}` })
|
82
|
+
};
|
83
|
+
}
|
84
|
+
else if (secret) {
|
85
|
+
debug('apollo', '🔑 Using Admin Secret for x-hasura-admin-secret header');
|
86
|
+
return {
|
87
|
+
headers: Object.assign(Object.assign({}, headers), { 'x-hasura-admin-secret': secret })
|
88
|
+
};
|
89
|
+
}
|
90
|
+
debug('apollo', '🔓 Sending request without authentication headers');
|
91
|
+
return { headers };
|
92
|
+
});
|
93
|
+
// Chain the links: roleLink -> authHeaderLink -> baseHttpLink
|
94
|
+
const httpLink = client_1.ApolloLink.from([roleLink, authHeaderLink, baseHttpLink]);
|
95
|
+
// --- End Existing Links Modification ---
|
96
|
+
// --- WebSocket Link Setup (Remains largely the same) ---
|
97
|
+
let link = httpLink; // Start with the combined HTTP link
|
98
|
+
// --- Debugging WS Link Creation ---
|
99
|
+
debug('apollo', `🚀 Checking WS setup: ws=${ws}, isClient=${isClient}`);
|
100
|
+
if (ws && isClient) {
|
101
|
+
debug('apollo', '✅ Entering WS Link creation block.'); // Log entry
|
102
|
+
const wsEndpoint = url.replace('http', 'ws').replace('https://', 'wss');
|
103
|
+
debug('apollo', '🔌 Setting up GraphQLWsLink for:', wsEndpoint);
|
104
|
+
// --- Restore GraphQLWsLink ---
|
105
|
+
const wsLink = new subscriptions_1.GraphQLWsLink((0, graphql_ws_1.createClient)({
|
106
|
+
url: wsEndpoint,
|
107
|
+
connectionParams: () => __awaiter(this, void 0, void 0, function* () {
|
108
|
+
debug('apollo', '⚙️ Evaluating connectionParams function...');
|
109
|
+
const params = {};
|
110
|
+
if (token) {
|
111
|
+
debug('apollo', '🔒 Using JWT token for WS connectionParams (from function)');
|
112
|
+
params.headers = { Authorization: `Bearer ${token}` };
|
113
|
+
}
|
114
|
+
else if (secret) {
|
115
|
+
debug('apollo', '🔑 Using Admin Secret for WS connectionParams (from function)');
|
116
|
+
params.headers = { 'x-hasura-admin-secret': secret };
|
117
|
+
}
|
118
|
+
else {
|
119
|
+
debug('apollo', '🔓 WebSocket connection without specific auth params (from function)');
|
120
|
+
}
|
121
|
+
debug('apollo', '⚙️ connectionParams function returning:', params);
|
122
|
+
return params;
|
123
|
+
}),
|
124
|
+
// Note: Dynamically changing headers per subscription via context
|
125
|
+
// is not standard in GraphQLWsLink. The roleLink above won't affect this.
|
126
|
+
// --- Add event handlers for diagnostics ---
|
127
|
+
on: {
|
128
|
+
connected: (socket) => debug('apollo', '🔗 [graphql-ws] WebSocket connected:', socket),
|
129
|
+
ping: (received) => debug('apollo', `➡️ [graphql-ws] Ping ${received ? 'received' : 'sent'}`),
|
130
|
+
pong: (received) => debug('apollo', `⬅️ [graphql-ws] Pong ${received ? 'received' : 'sent'}`),
|
131
|
+
error: (err) => debug('apollo', '❌ [graphql-ws] WebSocket error:', err),
|
132
|
+
closed: (event) => debug('apollo', '🚪 [graphql-ws] WebSocket closed:', event),
|
133
|
+
}
|
134
|
+
// --- End event handlers ---
|
135
|
+
}));
|
136
|
+
/* --- Remove Deprecated WebSocketLink ---
|
137
|
+
const wsLink = new WebSocketLink({
|
138
|
+
uri: wsEndpoint,
|
139
|
+
options: {
|
140
|
+
reconnect: true,
|
141
|
+
connectionParams: connectionParams, // Pass prepared headers here
|
142
|
+
// Note: Timeout options might be needed depending on env
|
143
|
+
}
|
144
|
+
});
|
145
|
+
debug('apollo', '🔗 DEPRECATED WebSocketLink created.');
|
146
|
+
*/
|
147
|
+
// Split based on operation type
|
148
|
+
link = (0, client_1.split)(({ query }) => {
|
149
|
+
const definition = (0, utilities_1.getMainDefinition)(query);
|
150
|
+
const isSubscription = definition.kind === 'OperationDefinition' &&
|
151
|
+
definition.operation === 'subscription';
|
152
|
+
debug('apollo', `🔗 Split link decision: isSubscription=${isSubscription}`);
|
153
|
+
return (definition.kind === 'OperationDefinition' &&
|
154
|
+
definition.operation === 'subscription');
|
155
|
+
}, wsLink, // Use wsLink for subscriptions
|
156
|
+
httpLink // Use httpLink (with roleLink and authHeaderLink) for query/mutation
|
157
|
+
);
|
158
|
+
}
|
159
|
+
else {
|
160
|
+
debug('apollo', '❌ Skipping WS Link creation.', { ws, isClient });
|
161
|
+
}
|
162
|
+
// --- End WebSocket Setup ---
|
163
|
+
// Create Apollo Client with the final composed link
|
164
|
+
const apolloClient = new client_1.ApolloClient({
|
165
|
+
link: link, // Use the potentially split link
|
166
|
+
cache: new client_1.InMemoryCache(),
|
167
|
+
defaultOptions: {
|
168
|
+
watchQuery: {
|
169
|
+
fetchPolicy: 'network-only',
|
170
|
+
errorPolicy: 'all',
|
171
|
+
},
|
172
|
+
query: {
|
173
|
+
fetchPolicy: 'network-only',
|
174
|
+
errorPolicy: 'all',
|
175
|
+
},
|
176
|
+
mutate: {
|
177
|
+
errorPolicy: 'all',
|
178
|
+
},
|
179
|
+
}
|
180
|
+
});
|
181
|
+
apolloClient.Provider = function Provider({ children }) {
|
182
|
+
return (0, jsx_runtime_1.jsx)(client_1.ApolloProvider, { client: apolloClient, children: children });
|
183
|
+
};
|
184
|
+
return apolloClient;
|
185
|
+
}
|
186
|
+
// Default client instance
|
187
|
+
let clientInstance = null;
|
188
|
+
/**
|
189
|
+
* Get or create Apollo client instance
|
190
|
+
* @param options Client options
|
191
|
+
* @returns Apollo client instance
|
192
|
+
*/
|
193
|
+
function getClient(options = {}) {
|
194
|
+
if (!clientInstance) {
|
195
|
+
clientInstance = createApolloClient(options);
|
196
|
+
}
|
197
|
+
return clientInstance;
|
198
|
+
}
|
199
|
+
/**
|
200
|
+
* React hook to get Apollo client instance
|
201
|
+
* @returns Apollo client instance
|
202
|
+
*/
|
203
|
+
function useCreateApolloClient(options) {
|
204
|
+
return (0, react_1.useMemo)(() => createApolloClient(options), [options]);
|
205
|
+
}
|
206
|
+
exports.CHECK_CONNECTION_SUBSCRIPTION = (0, client_1.gql) `
|
207
|
+
subscription CheckConnection {
|
208
|
+
__schema {
|
209
|
+
queryType {
|
210
|
+
name
|
211
|
+
}
|
212
|
+
}
|
213
|
+
}
|
214
|
+
`;
|
215
|
+
exports.CHECK_CONNECTION_QUERY = (0, client_1.gql) `
|
216
|
+
query CheckConnection {
|
217
|
+
__schema {
|
218
|
+
queryType {
|
219
|
+
name
|
220
|
+
}
|
221
|
+
}
|
222
|
+
}
|
223
|
+
`;
|
224
|
+
/**
|
225
|
+
* Check connection to Hasura GraphQL endpoint
|
226
|
+
* @returns {Promise<boolean>} True if connection is successful
|
227
|
+
*/
|
228
|
+
function checkConnection() {
|
229
|
+
return __awaiter(this, arguments, void 0, function* (client = getClient()) {
|
230
|
+
var _a, _b, _c;
|
231
|
+
const result = yield client.query({ query: exports.CHECK_CONNECTION_QUERY });
|
232
|
+
return !!((_c = (_b = (_a = result.data) === null || _a === void 0 ? void 0 : _a.__schema) === null || _b === void 0 ? void 0 : _b.queryType) === null || _c === void 0 ? void 0 : _c.name);
|
233
|
+
});
|
234
|
+
}
|
235
|
+
const errorLink = (0, error_1.onError)(({ graphQLErrors, networkError, operation, forward }) => {
|
236
|
+
// Handle errors
|
237
|
+
});
|
238
|
+
exports.default = {
|
239
|
+
createApolloClient,
|
240
|
+
getClient,
|
241
|
+
getJwtSecret: jwt_1.getJwtSecret,
|
242
|
+
checkConnection
|
243
|
+
};
|
@@ -0,0 +1,48 @@
|
|
1
|
+
import { Client } from 'nextjs-hasura-auth';
|
2
|
+
/**
|
3
|
+
* Hashes a password using bcrypt.
|
4
|
+
* @param password The plain text password.
|
5
|
+
* @returns The hashed password.
|
6
|
+
*/
|
7
|
+
export declare function hashPassword(password: string): Promise<string>;
|
8
|
+
/**
|
9
|
+
* Compares a plain text password with a hash.
|
10
|
+
* @param password The plain text password.
|
11
|
+
* @param hash The hash to compare against.
|
12
|
+
* @returns True if the password matches the hash, false otherwise.
|
13
|
+
*/
|
14
|
+
export declare function comparePassword(password: string, hash: string): Promise<boolean>;
|
15
|
+
interface UserProfileFromProvider {
|
16
|
+
name?: string | null;
|
17
|
+
email?: string | null;
|
18
|
+
image?: string | null;
|
19
|
+
}
|
20
|
+
export interface HasuraUser {
|
21
|
+
id: string;
|
22
|
+
name?: string | null;
|
23
|
+
email?: string | null;
|
24
|
+
email_verified?: string | null;
|
25
|
+
image?: string | null;
|
26
|
+
password?: string | null;
|
27
|
+
created_at: string;
|
28
|
+
updated_at: string;
|
29
|
+
is_admin?: boolean | null;
|
30
|
+
hasura_role?: string | null;
|
31
|
+
accounts?: {
|
32
|
+
provider: string;
|
33
|
+
provider_account_id: string;
|
34
|
+
}[];
|
35
|
+
}
|
36
|
+
/**
|
37
|
+
* Finds or creates a user and their associated account based on provider information.
|
38
|
+
* This function handles the core logic of linking OAuth/Credentials logins to Hasura users.
|
39
|
+
*
|
40
|
+
* @param client The initialized NHA Client instance.
|
41
|
+
* @param provider The OAuth provider name (e.g., 'google', 'credentials').
|
42
|
+
* @param providerAccountId The user's unique ID from the provider.
|
43
|
+
* @param profile Optional profile information from the provider (name, email, image).
|
44
|
+
* @returns The Hasura user object associated with the account.
|
45
|
+
* @throws Error if user/account processing fails.
|
46
|
+
*/
|
47
|
+
export declare function getOrCreateUserAndAccount(client: Client, provider: string, providerAccountId: string, profile?: UserProfileFromProvider | null): Promise<HasuraUser>;
|
48
|
+
export {};
|