naystack 1.8.2 → 1.8.4
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/auth/client.cjs.js +51 -8
- package/dist/auth/client.d.mts +1 -0
- package/dist/auth/client.d.ts +1 -0
- package/dist/auth/client.esm.js +48 -8
- package/dist/auth/email/client.cjs.js +51 -8
- package/dist/auth/email/client.d.mts +1 -0
- package/dist/auth/email/client.d.ts +1 -0
- package/dist/auth/email/client.esm.js +48 -8
- package/dist/auth/email/index.cjs.js +4 -2
- package/dist/auth/email/index.d.mts +1 -0
- package/dist/auth/email/index.d.ts +1 -0
- package/dist/auth/email/index.esm.js +4 -2
- package/dist/auth/email/next.d.mts +1 -0
- package/dist/auth/email/next.d.ts +1 -0
- package/dist/auth/email/routes/delete.cjs.js +4 -2
- package/dist/auth/email/routes/delete.esm.js +4 -2
- package/dist/auth/email/routes/get.cjs.js +4 -2
- package/dist/auth/email/routes/get.esm.js +4 -2
- package/dist/auth/email/routes/post.cjs.js +4 -2
- package/dist/auth/email/routes/post.esm.js +4 -2
- package/dist/auth/email/routes/put.cjs.js +4 -2
- package/dist/auth/email/routes/put.esm.js +4 -2
- package/dist/auth/email/token.cjs.js +4 -2
- package/dist/auth/email/token.d.mts +2 -2
- package/dist/auth/email/token.d.ts +2 -2
- package/dist/auth/email/token.esm.js +4 -2
- package/dist/auth/google/get.cjs.js +3 -1
- package/dist/auth/google/get.esm.js +3 -1
- package/dist/auth/google/index.cjs.js +3 -1
- package/dist/auth/google/index.esm.js +3 -1
- package/dist/auth/index.cjs.js +4 -2
- package/dist/auth/index.d.mts +1 -0
- package/dist/auth/index.d.ts +1 -0
- package/dist/auth/index.esm.js +4 -2
- package/dist/auth/token-store.cjs.js +120 -0
- package/dist/auth/token-store.d.mts +42 -0
- package/dist/auth/token-store.d.ts +42 -0
- package/dist/auth/token-store.esm.js +90 -0
- package/dist/graphql/clear-store.cjs.js +47 -0
- package/dist/graphql/clear-store.d.mts +16 -0
- package/dist/graphql/clear-store.d.ts +16 -0
- package/dist/graphql/clear-store.esm.js +23 -0
- package/dist/graphql/client.cjs.js +116 -21
- package/dist/graphql/client.d.mts +4 -4
- package/dist/graphql/client.d.ts +4 -4
- package/dist/graphql/client.esm.js +113 -19
- package/dist/graphql/links.cjs.js +154 -0
- package/dist/graphql/links.d.mts +14 -0
- package/dist/graphql/links.d.ts +14 -0
- package/dist/graphql/links.esm.js +129 -0
- package/dist/graphql/next.cjs.js +99 -6
- package/dist/graphql/next.esm.js +98 -5
- package/package.json +1 -1
|
@@ -37,9 +37,33 @@ __export(client_exports, {
|
|
|
37
37
|
useAuthQuery: () => useAuthQuery
|
|
38
38
|
});
|
|
39
39
|
module.exports = __toCommonJS(client_exports);
|
|
40
|
+
var import_client4 = require("@apollo/client");
|
|
41
|
+
var import_client5 = require("naystack/auth/client");
|
|
42
|
+
var import_react2 = __toESM(require("react"));
|
|
43
|
+
|
|
44
|
+
// src/graphql/clear-store.tsx
|
|
40
45
|
var import_client = require("@apollo/client");
|
|
41
46
|
var import_client2 = require("naystack/auth/client");
|
|
42
|
-
var import_react =
|
|
47
|
+
var import_react = require("react");
|
|
48
|
+
function ClearStoreOnLogout() {
|
|
49
|
+
const client = (0, import_client.useApolloClient)();
|
|
50
|
+
const token = (0, import_client2.useToken)();
|
|
51
|
+
const hadToken = (0, import_react.useRef)(false);
|
|
52
|
+
(0, import_react.useEffect)(() => {
|
|
53
|
+
if (token) {
|
|
54
|
+
hadToken.current = true;
|
|
55
|
+
} else if (token === null && hadToken.current) {
|
|
56
|
+
hadToken.current = false;
|
|
57
|
+
void client.clearStore();
|
|
58
|
+
}
|
|
59
|
+
}, [client, token]);
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// src/graphql/links.ts
|
|
64
|
+
var import_client3 = require("@apollo/client");
|
|
65
|
+
var import_context = require("@apollo/client/link/context");
|
|
66
|
+
var import_error = require("@apollo/client/link/error");
|
|
43
67
|
|
|
44
68
|
// src/env.ts
|
|
45
69
|
var EXTRA_ENV = globalThis.__NAYSTACK_ENV__ || (globalThis.__NAYSTACK_ENV__ = {});
|
|
@@ -91,20 +115,92 @@ function getEnv(key, skipCheck) {
|
|
|
91
115
|
return value;
|
|
92
116
|
}
|
|
93
117
|
|
|
94
|
-
// src/
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
118
|
+
// src/auth/token-store.ts
|
|
119
|
+
var currentToken;
|
|
120
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
121
|
+
var inFlightRefresh = null;
|
|
122
|
+
function getAccessToken() {
|
|
123
|
+
return currentToken;
|
|
124
|
+
}
|
|
125
|
+
function setAccessToken(token) {
|
|
126
|
+
if (token === currentToken) return;
|
|
127
|
+
currentToken = token;
|
|
128
|
+
listeners.forEach((listener) => listener(token));
|
|
129
|
+
}
|
|
130
|
+
function refreshAccessToken() {
|
|
131
|
+
if (inFlightRefresh) return inFlightRefresh;
|
|
132
|
+
inFlightRefresh = (async () => {
|
|
133
|
+
const res = await fetch(
|
|
134
|
+
getEnv("NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT" /* NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT */),
|
|
135
|
+
{ credentials: "include" }
|
|
136
|
+
);
|
|
137
|
+
if (!res.ok) throw new Error(`Token refresh failed: ${res.status}`);
|
|
138
|
+
const token = await res.text() || null;
|
|
139
|
+
setAccessToken(token);
|
|
140
|
+
return token;
|
|
141
|
+
})().finally(() => {
|
|
142
|
+
inFlightRefresh = null;
|
|
143
|
+
});
|
|
144
|
+
return inFlightRefresh;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/graphql/links.ts
|
|
148
|
+
var RETRY_CONTEXT_KEY = "__naystackRetried";
|
|
149
|
+
function isExpiredTokenError(error) {
|
|
150
|
+
return error.extensions?.code === "UNAUTHENTICATED";
|
|
151
|
+
}
|
|
152
|
+
var authLink = (0, import_context.setContext)((_, previousContext) => {
|
|
153
|
+
const token = getAccessToken();
|
|
154
|
+
if (!token || previousContext.credentials === "include")
|
|
155
|
+
return previousContext;
|
|
156
|
+
return {
|
|
157
|
+
...previousContext,
|
|
158
|
+
headers: {
|
|
159
|
+
...previousContext.headers,
|
|
160
|
+
authorization: `Bearer ${token}`
|
|
161
|
+
},
|
|
162
|
+
credentials: "omit"
|
|
163
|
+
};
|
|
164
|
+
});
|
|
165
|
+
var refreshLink = (0, import_error.onError)(({ graphQLErrors, operation, forward }) => {
|
|
166
|
+
if (!graphQLErrors?.some(isExpiredTokenError)) return;
|
|
167
|
+
if (operation.getContext()[RETRY_CONTEXT_KEY]) return;
|
|
168
|
+
return (0, import_client3.fromPromise)(
|
|
169
|
+
// A failed refresh still replays once: the retry reproduces the original
|
|
170
|
+
// error for the caller instead of surfacing the refresh's error in its place.
|
|
171
|
+
refreshAccessToken().catch(() => null)
|
|
172
|
+
).flatMap(() => {
|
|
173
|
+
operation.setContext((previousContext) => ({
|
|
174
|
+
...previousContext,
|
|
175
|
+
[RETRY_CONTEXT_KEY]: true
|
|
176
|
+
}));
|
|
177
|
+
return forward(operation);
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
function makeAuthLink() {
|
|
181
|
+
return import_client3.ApolloLink.from([
|
|
182
|
+
refreshLink,
|
|
183
|
+
authLink,
|
|
184
|
+
new import_client3.HttpLink({
|
|
99
185
|
uri: getEnv("NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */)
|
|
100
186
|
})
|
|
187
|
+
]);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/graphql/client.tsx
|
|
191
|
+
function makeClient(cacheConfig) {
|
|
192
|
+
return new import_client4.ApolloClient({
|
|
193
|
+
cache: new import_client4.InMemoryCache(cacheConfig),
|
|
194
|
+
link: makeAuthLink()
|
|
101
195
|
});
|
|
102
196
|
}
|
|
103
197
|
var ApolloWrapper = ({
|
|
104
198
|
children,
|
|
105
199
|
cacheConfig
|
|
106
200
|
}) => {
|
|
107
|
-
|
|
201
|
+
const clientRef = (0, import_react2.useRef)(null);
|
|
202
|
+
if (!clientRef.current) clientRef.current = makeClient(cacheConfig);
|
|
203
|
+
return /* @__PURE__ */ import_react2.default.createElement(import_client4.ApolloProvider, { client: clientRef.current }, /* @__PURE__ */ import_react2.default.createElement(ClearStoreOnLogout, null), children);
|
|
108
204
|
};
|
|
109
205
|
var tokenContext = (token) => {
|
|
110
206
|
if (!token) return void 0;
|
|
@@ -116,16 +212,16 @@ var tokenContext = (token) => {
|
|
|
116
212
|
};
|
|
117
213
|
};
|
|
118
214
|
function useAuthQuery(query, variables, options) {
|
|
119
|
-
const [
|
|
215
|
+
const [fetch2, result] = (0, import_client4.useLazyQuery)(query, {
|
|
120
216
|
fetchPolicy: "no-cache",
|
|
121
217
|
...options
|
|
122
218
|
});
|
|
123
|
-
const prevVarsRef = (0,
|
|
124
|
-
(0,
|
|
219
|
+
const prevVarsRef = (0, import_react2.useRef)(null);
|
|
220
|
+
(0, import_react2.useEffect)(() => {
|
|
125
221
|
const serialized = JSON.stringify(variables);
|
|
126
222
|
if (variables && prevVarsRef.current !== serialized) {
|
|
127
223
|
prevVarsRef.current = serialized;
|
|
128
|
-
void
|
|
224
|
+
void fetch2({
|
|
129
225
|
// @ts-expect-error -- to allow dynamic props
|
|
130
226
|
variables: { input: variables },
|
|
131
227
|
context: {
|
|
@@ -133,29 +229,28 @@ function useAuthQuery(query, variables, options) {
|
|
|
133
229
|
}
|
|
134
230
|
});
|
|
135
231
|
}
|
|
136
|
-
}, [
|
|
137
|
-
const reFetch = (0,
|
|
138
|
-
(input) =>
|
|
232
|
+
}, [fetch2, variables]);
|
|
233
|
+
const reFetch = (0, import_react2.useCallback)(
|
|
234
|
+
(input) => fetch2({
|
|
139
235
|
// @ts-expect-error -- to allow dynamic props
|
|
140
236
|
variables: { input },
|
|
141
237
|
context: {
|
|
142
238
|
credentials: `include`
|
|
143
239
|
}
|
|
144
240
|
}),
|
|
145
|
-
[
|
|
241
|
+
[fetch2]
|
|
146
242
|
);
|
|
147
243
|
return [reFetch, result];
|
|
148
244
|
}
|
|
149
245
|
function useAuthMutation(mutation, options) {
|
|
150
|
-
const token = (0,
|
|
151
|
-
const [mutate, result] = (0,
|
|
152
|
-
const method = (0,
|
|
246
|
+
const token = (0, import_client5.useToken)();
|
|
247
|
+
const [mutate, result] = (0, import_client4.useMutation)(mutation, options);
|
|
248
|
+
const method = (0, import_react2.useCallback)(
|
|
153
249
|
(input) => mutate({
|
|
154
250
|
// @ts-expect-error -- to allow dynamic props
|
|
155
|
-
variables: { input }
|
|
156
|
-
context: tokenContext(token)
|
|
251
|
+
variables: { input }
|
|
157
252
|
}),
|
|
158
|
-
[
|
|
253
|
+
[mutate]
|
|
159
254
|
);
|
|
160
255
|
return [method, { ...result, hasAuth: !!token }];
|
|
161
256
|
}
|
|
@@ -25,10 +25,10 @@ declare const tokenContext: (token?: string | null) => {
|
|
|
25
25
|
* Hook to run a GraphQL query with the current user's token. The query auto-fires when both the token
|
|
26
26
|
* and variables are available. Returns a refetch function and the Apollo query result.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
* `options
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* Defaults to `fetchPolicy: "no-cache"` (always fresh, safe for viewer-keyed data).
|
|
29
|
+
* Override per-query via `options` — e.g. `{ fetchPolicy: "cache-first" }` for static
|
|
30
|
+
* reference data, or `{ fetchPolicy: "cache-and-network" }` to show cached data
|
|
31
|
+
* instantly while refetching.
|
|
32
32
|
*
|
|
33
33
|
* @param query - A `TypedDocumentNode` for the query (e.g. from codegen or a `gql` template).
|
|
34
34
|
* @param variables - Optional initial variables (the `input` value). Automatically wrapped as `{ input: variables }` before sending. Query fires automatically when this and token are set; change to refetch.
|
package/dist/graphql/client.d.ts
CHANGED
|
@@ -25,10 +25,10 @@ declare const tokenContext: (token?: string | null) => {
|
|
|
25
25
|
* Hook to run a GraphQL query with the current user's token. The query auto-fires when both the token
|
|
26
26
|
* and variables are available. Returns a refetch function and the Apollo query result.
|
|
27
27
|
*
|
|
28
|
-
*
|
|
29
|
-
* `options
|
|
30
|
-
*
|
|
31
|
-
*
|
|
28
|
+
* Defaults to `fetchPolicy: "no-cache"` (always fresh, safe for viewer-keyed data).
|
|
29
|
+
* Override per-query via `options` — e.g. `{ fetchPolicy: "cache-first" }` for static
|
|
30
|
+
* reference data, or `{ fetchPolicy: "cache-and-network" }` to show cached data
|
|
31
|
+
* instantly while refetching.
|
|
32
32
|
*
|
|
33
33
|
* @param query - A `TypedDocumentNode` for the query (e.g. from codegen or a `gql` template).
|
|
34
34
|
* @param variables - Optional initial variables (the `input` value). Automatically wrapped as `{ input: variables }` before sending. Query fires automatically when this and token are set; change to refetch.
|
|
@@ -4,18 +4,41 @@
|
|
|
4
4
|
import {
|
|
5
5
|
ApolloClient,
|
|
6
6
|
ApolloProvider,
|
|
7
|
-
HttpLink,
|
|
8
7
|
InMemoryCache,
|
|
9
8
|
useLazyQuery,
|
|
10
9
|
useMutation
|
|
11
10
|
} from "@apollo/client";
|
|
12
|
-
import { useToken } from "naystack/auth/client";
|
|
11
|
+
import { useToken as useToken2 } from "naystack/auth/client";
|
|
13
12
|
import React, {
|
|
14
13
|
useCallback,
|
|
15
|
-
useEffect,
|
|
16
|
-
useRef
|
|
14
|
+
useEffect as useEffect2,
|
|
15
|
+
useRef as useRef2
|
|
17
16
|
} from "react";
|
|
18
17
|
|
|
18
|
+
// src/graphql/clear-store.tsx
|
|
19
|
+
import { useApolloClient } from "@apollo/client";
|
|
20
|
+
import { useToken } from "naystack/auth/client";
|
|
21
|
+
import { useEffect, useRef } from "react";
|
|
22
|
+
function ClearStoreOnLogout() {
|
|
23
|
+
const client = useApolloClient();
|
|
24
|
+
const token = useToken();
|
|
25
|
+
const hadToken = useRef(false);
|
|
26
|
+
useEffect(() => {
|
|
27
|
+
if (token) {
|
|
28
|
+
hadToken.current = true;
|
|
29
|
+
} else if (token === null && hadToken.current) {
|
|
30
|
+
hadToken.current = false;
|
|
31
|
+
void client.clearStore();
|
|
32
|
+
}
|
|
33
|
+
}, [client, token]);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/graphql/links.ts
|
|
38
|
+
import { ApolloLink, fromPromise, HttpLink } from "@apollo/client";
|
|
39
|
+
import { setContext } from "@apollo/client/link/context";
|
|
40
|
+
import { onError } from "@apollo/client/link/error";
|
|
41
|
+
|
|
19
42
|
// src/env.ts
|
|
20
43
|
var EXTRA_ENV = globalThis.__NAYSTACK_ENV__ || (globalThis.__NAYSTACK_ENV__ = {});
|
|
21
44
|
var getEnvValue = (key) => {
|
|
@@ -66,20 +89,92 @@ function getEnv(key, skipCheck) {
|
|
|
66
89
|
return value;
|
|
67
90
|
}
|
|
68
91
|
|
|
92
|
+
// src/auth/token-store.ts
|
|
93
|
+
var currentToken;
|
|
94
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
95
|
+
var inFlightRefresh = null;
|
|
96
|
+
function getAccessToken() {
|
|
97
|
+
return currentToken;
|
|
98
|
+
}
|
|
99
|
+
function setAccessToken(token) {
|
|
100
|
+
if (token === currentToken) return;
|
|
101
|
+
currentToken = token;
|
|
102
|
+
listeners.forEach((listener) => listener(token));
|
|
103
|
+
}
|
|
104
|
+
function refreshAccessToken() {
|
|
105
|
+
if (inFlightRefresh) return inFlightRefresh;
|
|
106
|
+
inFlightRefresh = (async () => {
|
|
107
|
+
const res = await fetch(
|
|
108
|
+
getEnv("NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT" /* NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT */),
|
|
109
|
+
{ credentials: "include" }
|
|
110
|
+
);
|
|
111
|
+
if (!res.ok) throw new Error(`Token refresh failed: ${res.status}`);
|
|
112
|
+
const token = await res.text() || null;
|
|
113
|
+
setAccessToken(token);
|
|
114
|
+
return token;
|
|
115
|
+
})().finally(() => {
|
|
116
|
+
inFlightRefresh = null;
|
|
117
|
+
});
|
|
118
|
+
return inFlightRefresh;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/graphql/links.ts
|
|
122
|
+
var RETRY_CONTEXT_KEY = "__naystackRetried";
|
|
123
|
+
function isExpiredTokenError(error) {
|
|
124
|
+
return error.extensions?.code === "UNAUTHENTICATED";
|
|
125
|
+
}
|
|
126
|
+
var authLink = setContext((_, previousContext) => {
|
|
127
|
+
const token = getAccessToken();
|
|
128
|
+
if (!token || previousContext.credentials === "include")
|
|
129
|
+
return previousContext;
|
|
130
|
+
return {
|
|
131
|
+
...previousContext,
|
|
132
|
+
headers: {
|
|
133
|
+
...previousContext.headers,
|
|
134
|
+
authorization: `Bearer ${token}`
|
|
135
|
+
},
|
|
136
|
+
credentials: "omit"
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
var refreshLink = onError(({ graphQLErrors, operation, forward }) => {
|
|
140
|
+
if (!graphQLErrors?.some(isExpiredTokenError)) return;
|
|
141
|
+
if (operation.getContext()[RETRY_CONTEXT_KEY]) return;
|
|
142
|
+
return fromPromise(
|
|
143
|
+
// A failed refresh still replays once: the retry reproduces the original
|
|
144
|
+
// error for the caller instead of surfacing the refresh's error in its place.
|
|
145
|
+
refreshAccessToken().catch(() => null)
|
|
146
|
+
).flatMap(() => {
|
|
147
|
+
operation.setContext((previousContext) => ({
|
|
148
|
+
...previousContext,
|
|
149
|
+
[RETRY_CONTEXT_KEY]: true
|
|
150
|
+
}));
|
|
151
|
+
return forward(operation);
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
function makeAuthLink() {
|
|
155
|
+
return ApolloLink.from([
|
|
156
|
+
refreshLink,
|
|
157
|
+
authLink,
|
|
158
|
+
new HttpLink({
|
|
159
|
+
uri: getEnv("NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */)
|
|
160
|
+
})
|
|
161
|
+
]);
|
|
162
|
+
}
|
|
163
|
+
|
|
69
164
|
// src/graphql/client.tsx
|
|
70
165
|
function makeClient(cacheConfig) {
|
|
71
166
|
return new ApolloClient({
|
|
72
167
|
cache: new InMemoryCache(cacheConfig),
|
|
73
|
-
link:
|
|
74
|
-
uri: getEnv("NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */)
|
|
75
|
-
})
|
|
168
|
+
link: makeAuthLink()
|
|
76
169
|
});
|
|
77
170
|
}
|
|
78
171
|
var ApolloWrapper = ({
|
|
79
172
|
children,
|
|
80
173
|
cacheConfig
|
|
81
174
|
}) => {
|
|
82
|
-
|
|
175
|
+
const clientRef = useRef2(null);
|
|
176
|
+
if (!clientRef.current) clientRef.current = makeClient(cacheConfig);
|
|
177
|
+
return /* @__PURE__ */ React.createElement(ApolloProvider, { client: clientRef.current }, /* @__PURE__ */ React.createElement(ClearStoreOnLogout, null), children);
|
|
83
178
|
};
|
|
84
179
|
var tokenContext = (token) => {
|
|
85
180
|
if (!token) return void 0;
|
|
@@ -91,16 +186,16 @@ var tokenContext = (token) => {
|
|
|
91
186
|
};
|
|
92
187
|
};
|
|
93
188
|
function useAuthQuery(query, variables, options) {
|
|
94
|
-
const [
|
|
189
|
+
const [fetch2, result] = useLazyQuery(query, {
|
|
95
190
|
fetchPolicy: "no-cache",
|
|
96
191
|
...options
|
|
97
192
|
});
|
|
98
|
-
const prevVarsRef =
|
|
99
|
-
|
|
193
|
+
const prevVarsRef = useRef2(null);
|
|
194
|
+
useEffect2(() => {
|
|
100
195
|
const serialized = JSON.stringify(variables);
|
|
101
196
|
if (variables && prevVarsRef.current !== serialized) {
|
|
102
197
|
prevVarsRef.current = serialized;
|
|
103
|
-
void
|
|
198
|
+
void fetch2({
|
|
104
199
|
// @ts-expect-error -- to allow dynamic props
|
|
105
200
|
variables: { input: variables },
|
|
106
201
|
context: {
|
|
@@ -108,29 +203,28 @@ function useAuthQuery(query, variables, options) {
|
|
|
108
203
|
}
|
|
109
204
|
});
|
|
110
205
|
}
|
|
111
|
-
}, [
|
|
206
|
+
}, [fetch2, variables]);
|
|
112
207
|
const reFetch = useCallback(
|
|
113
|
-
(input) =>
|
|
208
|
+
(input) => fetch2({
|
|
114
209
|
// @ts-expect-error -- to allow dynamic props
|
|
115
210
|
variables: { input },
|
|
116
211
|
context: {
|
|
117
212
|
credentials: `include`
|
|
118
213
|
}
|
|
119
214
|
}),
|
|
120
|
-
[
|
|
215
|
+
[fetch2]
|
|
121
216
|
);
|
|
122
217
|
return [reFetch, result];
|
|
123
218
|
}
|
|
124
219
|
function useAuthMutation(mutation, options) {
|
|
125
|
-
const token =
|
|
220
|
+
const token = useToken2();
|
|
126
221
|
const [mutate, result] = useMutation(mutation, options);
|
|
127
222
|
const method = useCallback(
|
|
128
223
|
(input) => mutate({
|
|
129
224
|
// @ts-expect-error -- to allow dynamic props
|
|
130
|
-
variables: { input }
|
|
131
|
-
context: tokenContext(token)
|
|
225
|
+
variables: { input }
|
|
132
226
|
}),
|
|
133
|
-
[
|
|
227
|
+
[mutate]
|
|
134
228
|
);
|
|
135
229
|
return [method, { ...result, hasAuth: !!token }];
|
|
136
230
|
}
|
|
@@ -0,0 +1,154 @@
|
|
|
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
|
+
|
|
20
|
+
// src/graphql/links.ts
|
|
21
|
+
var links_exports = {};
|
|
22
|
+
__export(links_exports, {
|
|
23
|
+
makeAuthLink: () => makeAuthLink
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(links_exports);
|
|
26
|
+
var import_client = require("@apollo/client");
|
|
27
|
+
var import_context = require("@apollo/client/link/context");
|
|
28
|
+
var import_error = require("@apollo/client/link/error");
|
|
29
|
+
|
|
30
|
+
// src/env.ts
|
|
31
|
+
var EXTRA_ENV = globalThis.__NAYSTACK_ENV__ || (globalThis.__NAYSTACK_ENV__ = {});
|
|
32
|
+
var getEnvValue = (key) => {
|
|
33
|
+
switch (key) {
|
|
34
|
+
case "NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */:
|
|
35
|
+
return process.env.NEXT_PUBLIC_GRAPHQL_ENDPOINT || EXTRA_ENV.GRAPHQL_ENDPOINT;
|
|
36
|
+
case "NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT" /* NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT */:
|
|
37
|
+
return process.env.NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT || EXTRA_ENV.EMAIL_AUTH_ENDPOINT;
|
|
38
|
+
case "NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT" /* NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT */:
|
|
39
|
+
return process.env.NEXT_PUBLIC_GOOGLE_AUTH_ENDPOINT || EXTRA_ENV.GOOGLE_AUTH_ENDPOINT;
|
|
40
|
+
case "NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT" /* NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT */:
|
|
41
|
+
return process.env.NEXT_PUBLIC_INSTAGRAM_AUTH_ENDPOINT || EXTRA_ENV.INSTAGRAM_AUTH_ENDPOINT;
|
|
42
|
+
case "NEXT_PUBLIC_FILE_ENDPOINT" /* NEXT_PUBLIC_FILE_ENDPOINT */:
|
|
43
|
+
return process.env.NEXT_PUBLIC_FILE_ENDPOINT || EXTRA_ENV.FILE_ENDPOINT;
|
|
44
|
+
case "NEXT_PUBLIC_BASE_URL" /* NEXT_PUBLIC_BASE_URL */:
|
|
45
|
+
return process.env.NEXT_PUBLIC_BASE_URL || EXTRA_ENV.BASE_URL;
|
|
46
|
+
case "REFRESH_KEY" /* REFRESH_KEY */:
|
|
47
|
+
return process.env.REFRESH_KEY;
|
|
48
|
+
case "SIGNING_KEY" /* SIGNING_KEY */:
|
|
49
|
+
return process.env.SIGNING_KEY;
|
|
50
|
+
case "INSTAGRAM_CLIENT_SECRET" /* INSTAGRAM_CLIENT_SECRET */:
|
|
51
|
+
return process.env.INSTAGRAM_CLIENT_SECRET;
|
|
52
|
+
case "INSTAGRAM_CLIENT_ID" /* INSTAGRAM_CLIENT_ID */:
|
|
53
|
+
return process.env.INSTAGRAM_CLIENT_ID;
|
|
54
|
+
case "GOOGLE_CLIENT_SECRET" /* GOOGLE_CLIENT_SECRET */:
|
|
55
|
+
return process.env.GOOGLE_CLIENT_SECRET;
|
|
56
|
+
case "GOOGLE_CLIENT_ID" /* GOOGLE_CLIENT_ID */:
|
|
57
|
+
return process.env.GOOGLE_CLIENT_ID;
|
|
58
|
+
case "TURNSTILE_KEY" /* TURNSTILE_KEY */:
|
|
59
|
+
return process.env.TURNSTILE_KEY;
|
|
60
|
+
case "S3_ACCESS_KEY_ID" /* S3_ACCESS_KEY_ID */:
|
|
61
|
+
return process.env.S3_ACCESS_KEY_ID;
|
|
62
|
+
case "S3_ACCESS_KEY_SECRET" /* S3_ACCESS_KEY_SECRET */:
|
|
63
|
+
return process.env.S3_ACCESS_KEY_SECRET;
|
|
64
|
+
case "S3_REGION" /* S3_REGION */:
|
|
65
|
+
return process.env.S3_REGION;
|
|
66
|
+
case "S3_BUCKET" /* S3_BUCKET */:
|
|
67
|
+
return process.env.S3_BUCKET;
|
|
68
|
+
case "NODE_ENV" /* NODE_ENV */:
|
|
69
|
+
return process.env.NODE_ENV;
|
|
70
|
+
default:
|
|
71
|
+
return process.env[key];
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
function getEnv(key, skipCheck) {
|
|
75
|
+
const value = getEnvValue(key);
|
|
76
|
+
if (!skipCheck && !value) throw new Error(`${key} is not defined`);
|
|
77
|
+
return value;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/auth/token-store.ts
|
|
81
|
+
var currentToken;
|
|
82
|
+
var listeners = /* @__PURE__ */ new Set();
|
|
83
|
+
var inFlightRefresh = null;
|
|
84
|
+
function getAccessToken() {
|
|
85
|
+
return currentToken;
|
|
86
|
+
}
|
|
87
|
+
function setAccessToken(token) {
|
|
88
|
+
if (token === currentToken) return;
|
|
89
|
+
currentToken = token;
|
|
90
|
+
listeners.forEach((listener) => listener(token));
|
|
91
|
+
}
|
|
92
|
+
function refreshAccessToken() {
|
|
93
|
+
if (inFlightRefresh) return inFlightRefresh;
|
|
94
|
+
inFlightRefresh = (async () => {
|
|
95
|
+
const res = await fetch(
|
|
96
|
+
getEnv("NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT" /* NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT */),
|
|
97
|
+
{ credentials: "include" }
|
|
98
|
+
);
|
|
99
|
+
if (!res.ok) throw new Error(`Token refresh failed: ${res.status}`);
|
|
100
|
+
const token = await res.text() || null;
|
|
101
|
+
setAccessToken(token);
|
|
102
|
+
return token;
|
|
103
|
+
})().finally(() => {
|
|
104
|
+
inFlightRefresh = null;
|
|
105
|
+
});
|
|
106
|
+
return inFlightRefresh;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// src/graphql/links.ts
|
|
110
|
+
var RETRY_CONTEXT_KEY = "__naystackRetried";
|
|
111
|
+
function isExpiredTokenError(error) {
|
|
112
|
+
return error.extensions?.code === "UNAUTHENTICATED";
|
|
113
|
+
}
|
|
114
|
+
var authLink = (0, import_context.setContext)((_, previousContext) => {
|
|
115
|
+
const token = getAccessToken();
|
|
116
|
+
if (!token || previousContext.credentials === "include")
|
|
117
|
+
return previousContext;
|
|
118
|
+
return {
|
|
119
|
+
...previousContext,
|
|
120
|
+
headers: {
|
|
121
|
+
...previousContext.headers,
|
|
122
|
+
authorization: `Bearer ${token}`
|
|
123
|
+
},
|
|
124
|
+
credentials: "omit"
|
|
125
|
+
};
|
|
126
|
+
});
|
|
127
|
+
var refreshLink = (0, import_error.onError)(({ graphQLErrors, operation, forward }) => {
|
|
128
|
+
if (!graphQLErrors?.some(isExpiredTokenError)) return;
|
|
129
|
+
if (operation.getContext()[RETRY_CONTEXT_KEY]) return;
|
|
130
|
+
return (0, import_client.fromPromise)(
|
|
131
|
+
// A failed refresh still replays once: the retry reproduces the original
|
|
132
|
+
// error for the caller instead of surfacing the refresh's error in its place.
|
|
133
|
+
refreshAccessToken().catch(() => null)
|
|
134
|
+
).flatMap(() => {
|
|
135
|
+
operation.setContext((previousContext) => ({
|
|
136
|
+
...previousContext,
|
|
137
|
+
[RETRY_CONTEXT_KEY]: true
|
|
138
|
+
}));
|
|
139
|
+
return forward(operation);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
function makeAuthLink() {
|
|
143
|
+
return import_client.ApolloLink.from([
|
|
144
|
+
refreshLink,
|
|
145
|
+
authLink,
|
|
146
|
+
new import_client.HttpLink({
|
|
147
|
+
uri: getEnv("NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */)
|
|
148
|
+
})
|
|
149
|
+
]);
|
|
150
|
+
}
|
|
151
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
152
|
+
0 && (module.exports = {
|
|
153
|
+
makeAuthLink
|
|
154
|
+
});
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ApolloLink } from '@apollo/client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Builds the client link chain: refresh-and-retry → auth header → HTTP.
|
|
5
|
+
*
|
|
6
|
+
* `refreshLink` sits outermost so its replayed operation passes back through
|
|
7
|
+
* `authLink` and picks up the refreshed token.
|
|
8
|
+
*
|
|
9
|
+
* @returns An `ApolloLink` for the `link` option of `ApolloClient`.
|
|
10
|
+
* @category GraphQL
|
|
11
|
+
*/
|
|
12
|
+
declare function makeAuthLink(): ApolloLink;
|
|
13
|
+
|
|
14
|
+
export { makeAuthLink };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ApolloLink } from '@apollo/client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Builds the client link chain: refresh-and-retry → auth header → HTTP.
|
|
5
|
+
*
|
|
6
|
+
* `refreshLink` sits outermost so its replayed operation passes back through
|
|
7
|
+
* `authLink` and picks up the refreshed token.
|
|
8
|
+
*
|
|
9
|
+
* @returns An `ApolloLink` for the `link` option of `ApolloClient`.
|
|
10
|
+
* @category GraphQL
|
|
11
|
+
*/
|
|
12
|
+
declare function makeAuthLink(): ApolloLink;
|
|
13
|
+
|
|
14
|
+
export { makeAuthLink };
|