naystack 1.8.3 → 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.
Files changed (47) hide show
  1. package/dist/auth/client.cjs.js +51 -8
  2. package/dist/auth/client.d.mts +1 -0
  3. package/dist/auth/client.d.ts +1 -0
  4. package/dist/auth/client.esm.js +48 -8
  5. package/dist/auth/email/client.cjs.js +51 -8
  6. package/dist/auth/email/client.d.mts +1 -0
  7. package/dist/auth/email/client.d.ts +1 -0
  8. package/dist/auth/email/client.esm.js +48 -8
  9. package/dist/auth/email/index.cjs.js +4 -2
  10. package/dist/auth/email/index.d.mts +1 -0
  11. package/dist/auth/email/index.d.ts +1 -0
  12. package/dist/auth/email/index.esm.js +4 -2
  13. package/dist/auth/email/next.d.mts +1 -0
  14. package/dist/auth/email/next.d.ts +1 -0
  15. package/dist/auth/email/routes/delete.cjs.js +4 -2
  16. package/dist/auth/email/routes/delete.esm.js +4 -2
  17. package/dist/auth/email/routes/get.cjs.js +4 -2
  18. package/dist/auth/email/routes/get.esm.js +4 -2
  19. package/dist/auth/email/routes/post.cjs.js +4 -2
  20. package/dist/auth/email/routes/post.esm.js +4 -2
  21. package/dist/auth/email/routes/put.cjs.js +4 -2
  22. package/dist/auth/email/routes/put.esm.js +4 -2
  23. package/dist/auth/email/token.cjs.js +4 -2
  24. package/dist/auth/email/token.d.mts +2 -2
  25. package/dist/auth/email/token.d.ts +2 -2
  26. package/dist/auth/email/token.esm.js +4 -2
  27. package/dist/auth/google/get.cjs.js +3 -1
  28. package/dist/auth/google/get.esm.js +3 -1
  29. package/dist/auth/google/index.cjs.js +3 -1
  30. package/dist/auth/google/index.esm.js +3 -1
  31. package/dist/auth/index.cjs.js +4 -2
  32. package/dist/auth/index.d.mts +1 -0
  33. package/dist/auth/index.d.ts +1 -0
  34. package/dist/auth/index.esm.js +4 -2
  35. package/dist/auth/token-store.cjs.js +120 -0
  36. package/dist/auth/token-store.d.mts +42 -0
  37. package/dist/auth/token-store.d.ts +42 -0
  38. package/dist/auth/token-store.esm.js +90 -0
  39. package/dist/graphql/client.cjs.js +109 -35
  40. package/dist/graphql/client.esm.js +102 -29
  41. package/dist/graphql/links.cjs.js +154 -0
  42. package/dist/graphql/links.d.mts +14 -0
  43. package/dist/graphql/links.d.ts +14 -0
  44. package/dist/graphql/links.esm.js +129 -0
  45. package/dist/graphql/next.cjs.js +95 -21
  46. package/dist/graphql/next.esm.js +95 -21
  47. package/package.json +1 -1
@@ -1,7 +1,6 @@
1
1
  "use client";
2
2
 
3
3
  // src/graphql/next.tsx
4
- import { HttpLink } from "@apollo/client";
5
4
  import {
6
5
  ApolloClient,
7
6
  ApolloNextAppProvider,
@@ -9,6 +8,30 @@ import {
9
8
  } from "@apollo/client-integration-nextjs";
10
9
  import React from "react";
11
10
 
11
+ // src/graphql/clear-store.tsx
12
+ import { useApolloClient } from "@apollo/client";
13
+ import { useToken } from "naystack/auth/client";
14
+ import { useEffect, useRef } from "react";
15
+ function ClearStoreOnLogout() {
16
+ const client = useApolloClient();
17
+ const token = useToken();
18
+ const hadToken = useRef(false);
19
+ useEffect(() => {
20
+ if (token) {
21
+ hadToken.current = true;
22
+ } else if (token === null && hadToken.current) {
23
+ hadToken.current = false;
24
+ void client.clearStore();
25
+ }
26
+ }, [client, token]);
27
+ return null;
28
+ }
29
+
30
+ // src/graphql/links.ts
31
+ import { ApolloLink, fromPromise, HttpLink } from "@apollo/client";
32
+ import { setContext } from "@apollo/client/link/context";
33
+ import { onError } from "@apollo/client/link/error";
34
+
12
35
  // src/env.ts
13
36
  var EXTRA_ENV = globalThis.__NAYSTACK_ENV__ || (globalThis.__NAYSTACK_ENV__ = {});
14
37
  var getEnvValue = (key) => {
@@ -59,32 +82,83 @@ function getEnv(key, skipCheck) {
59
82
  return value;
60
83
  }
61
84
 
62
- // src/graphql/clear-store.tsx
63
- import { useApolloClient } from "@apollo/client";
64
- import { useToken } from "naystack/auth/client";
65
- import { useEffect, useRef } from "react";
66
- function ClearStoreOnLogout() {
67
- const client = useApolloClient();
68
- const token = useToken();
69
- const hadToken = useRef(false);
70
- useEffect(() => {
71
- if (token) {
72
- hadToken.current = true;
73
- } else if (token === null && hadToken.current) {
74
- hadToken.current = false;
75
- void client.clearStore();
76
- }
77
- }, [client, token]);
78
- return null;
85
+ // src/auth/token-store.ts
86
+ var currentToken;
87
+ var listeners = /* @__PURE__ */ new Set();
88
+ var inFlightRefresh = null;
89
+ function getAccessToken() {
90
+ return currentToken;
91
+ }
92
+ function setAccessToken(token) {
93
+ if (token === currentToken) return;
94
+ currentToken = token;
95
+ listeners.forEach((listener) => listener(token));
96
+ }
97
+ function refreshAccessToken() {
98
+ if (inFlightRefresh) return inFlightRefresh;
99
+ inFlightRefresh = (async () => {
100
+ const res = await fetch(
101
+ getEnv("NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT" /* NEXT_PUBLIC_EMAIL_AUTH_ENDPOINT */),
102
+ { credentials: "include" }
103
+ );
104
+ if (!res.ok) throw new Error(`Token refresh failed: ${res.status}`);
105
+ const token = await res.text() || null;
106
+ setAccessToken(token);
107
+ return token;
108
+ })().finally(() => {
109
+ inFlightRefresh = null;
110
+ });
111
+ return inFlightRefresh;
112
+ }
113
+
114
+ // src/graphql/links.ts
115
+ var RETRY_CONTEXT_KEY = "__naystackRetried";
116
+ function isExpiredTokenError(error) {
117
+ return error.extensions?.code === "UNAUTHENTICATED";
118
+ }
119
+ var authLink = setContext((_, previousContext) => {
120
+ const token = getAccessToken();
121
+ if (!token || previousContext.credentials === "include")
122
+ return previousContext;
123
+ return {
124
+ ...previousContext,
125
+ headers: {
126
+ ...previousContext.headers,
127
+ authorization: `Bearer ${token}`
128
+ },
129
+ credentials: "omit"
130
+ };
131
+ });
132
+ var refreshLink = onError(({ graphQLErrors, operation, forward }) => {
133
+ if (!graphQLErrors?.some(isExpiredTokenError)) return;
134
+ if (operation.getContext()[RETRY_CONTEXT_KEY]) return;
135
+ return fromPromise(
136
+ // A failed refresh still replays once: the retry reproduces the original
137
+ // error for the caller instead of surfacing the refresh's error in its place.
138
+ refreshAccessToken().catch(() => null)
139
+ ).flatMap(() => {
140
+ operation.setContext((previousContext) => ({
141
+ ...previousContext,
142
+ [RETRY_CONTEXT_KEY]: true
143
+ }));
144
+ return forward(operation);
145
+ });
146
+ });
147
+ function makeAuthLink() {
148
+ return ApolloLink.from([
149
+ refreshLink,
150
+ authLink,
151
+ new HttpLink({
152
+ uri: getEnv("NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */)
153
+ })
154
+ ]);
79
155
  }
80
156
 
81
157
  // src/graphql/next.tsx
82
158
  function makeClient(cacheConfig) {
83
159
  return new ApolloClient({
84
160
  cache: new InMemoryCache(cacheConfig),
85
- link: new HttpLink({
86
- uri: getEnv("NEXT_PUBLIC_GRAPHQL_ENDPOINT" /* NEXT_PUBLIC_GRAPHQL_ENDPOINT */)
87
- })
161
+ link: makeAuthLink()
88
162
  });
89
163
  }
90
164
  var ApolloWrapper = ({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "naystack",
3
- "version": "1.8.3",
3
+ "version": "1.8.4",
4
4
  "description": "A stack built with Next + GraphQL + S3 + Auth",
5
5
  "main": "dist/index.cjs.js",
6
6
  "module": "dist/index.esm.js",