@foir/sdk 0.2.0 → 0.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/README.md CHANGED
@@ -25,6 +25,8 @@ pnpm add yjs y-websocket # for @foir/sdk/realtime
25
25
  | `@foir/sdk` | Editor iframe client — `EditorProvider`, `useEditor`, `useAutoResize`, `createPlatformClient`, host↔editor message protocol | `react` |
26
26
  | `@foir/sdk/client` | Client-agnostic GraphQL transport for SSR/edge loaders — `foirRequest`, `isFoirPreview`, `absolutiseFoirMediaUrl` | `graphql` |
27
27
  | `@foir/sdk/auth` | Framework-agnostic customer auth — login/register/OTP/provider flows, token lifecycle (`SessionAdapter`), `authedRequest`, guards | `graphql` |
28
+ | `@foir/sdk/react` | Drop-in React auth — `<FoirProvider>`, `useFoirSession`/`useFoirUser`/`useFoirAuth`, `<SignIn>`, `<OAuthButtons>`, `<UserButton>` | `react`, `graphql` |
29
+ | `@foir/sdk/next` | Next.js App Router BFF auth — `createFoirCookieAdapter`, `getFoirSession`, `foirSignIn*`, `completeFoirProviderLogin`, `createFoirMiddleware` | `graphql` |
28
30
  | `@foir/sdk/server` | Server-side helpers for extension/config API backends — `createServerClient`, `verifyWebhookSignature`, `verifyScopedToken`, callback client | — |
29
31
  | `@foir/sdk/media` | Progressive media — `ProgressiveMedia`, `BlurhashCanvas`, `useProgressiveLoad`, variant-tier adapters | `react` (`hls.js`, `blurhash` optional) |
30
32
  | `@foir/sdk/content` | Content-rendering primitives — `createContentRenderer` block dispatch + Lexical `RichTextRenderer` | `react` |
@@ -72,6 +74,76 @@ const customer = await loginWithPassword(adapter, env, { email, password });
72
74
  const { myProfile } = await authedRequest(adapter, env, MyProfileDocument);
73
75
  ```
74
76
 
77
+ ### React
78
+
79
+ `@foir/sdk/react` builds the reactive layer on top of `@foir/sdk/auth`. Wrap
80
+ your app once, then read the session with hooks or drop in the components. The
81
+ default session store is `localStorage`; pass your own `adapter` for cookies.
82
+
83
+ ```tsx
84
+ 'use client';
85
+ import { FoirProvider, SignIn, UserButton, useFoirSession } from '@foir/sdk/react';
86
+
87
+ const env = {
88
+ PLATFORM_API_URL: process.env.NEXT_PUBLIC_PLATFORM_API_URL,
89
+ PLATFORM_API_KEY: process.env.NEXT_PUBLIC_PLATFORM_API_KEY, // a publishable pk_ key
90
+ };
91
+
92
+ export function App() {
93
+ return (
94
+ <FoirProvider env={env}>
95
+ <Header />
96
+ <SignIn afterSignInUrl="/dashboard" />
97
+ </FoirProvider>
98
+ );
99
+ }
100
+
101
+ function Header() {
102
+ const { isAuthenticated, isLoading } = useFoirSession();
103
+ if (isLoading) return null;
104
+ return isAuthenticated ? <UserButton afterSignOutUrl="/" /> : null;
105
+ }
106
+ ```
107
+
108
+ For a custom form, use `useFoirAuth()` (`signIn`, `register`, `signInWithOtp`,
109
+ `requestOtp`, `signInWithProvider`, `signOut`, `getToken`) and `useFoirUser()`.
110
+
111
+ ### Next.js (App Router, BFF)
112
+
113
+ `@foir/sdk/next` keeps the tokens in HttpOnly cookies server-side. Protect
114
+ routes with the middleware, read the session in a server component, and sign in
115
+ from a route handler.
116
+
117
+ ```ts
118
+ // middleware.ts
119
+ import { createFoirMiddleware } from '@foir/sdk/next';
120
+ export const middleware = createFoirMiddleware({ signInUrl: '/sign-in' });
121
+ export const config = { matcher: ['/dashboard/:path*'] };
122
+ ```
123
+
124
+ ```ts
125
+ // app/dashboard/page.tsx (Server Component)
126
+ import { cookies } from 'next/headers';
127
+ import { getFoirSession } from '@foir/sdk/next';
128
+
129
+ export default async function Dashboard() {
130
+ const customer = await getFoirSession(await cookies());
131
+ return <p>Signed in as {customer?.email}</p>;
132
+ }
133
+ ```
134
+
135
+ ```ts
136
+ // app/sign-in/route.ts (Route Handler)
137
+ import { cookies } from 'next/headers';
138
+ import { foirSignInWithPassword } from '@foir/sdk/next';
139
+
140
+ export async function POST(req: Request) {
141
+ const { email, password } = await req.json();
142
+ await foirSignInWithPassword({ env, store: await cookies(), email, password });
143
+ return Response.json({ ok: true });
144
+ }
145
+ ```
146
+
75
147
  ### Codegen
76
148
 
77
149
  ```ts
package/dist/next.d.ts ADDED
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Foir GraphQL client — a single typed fetch wrapper for SSR/edge loaders.
3
+ *
4
+ * No GraphQL client (Apollo/urql) required: the Foir public API is a plain
5
+ * `POST` with an `x-api-key` header, and the dominant consumers (Hydrogen on
6
+ * Oxygen, React Router loaders, TanStack Start on CF Workers) fetch in
7
+ * server-only loaders and render — so Apollo's `InMemoryCache`/`useQuery`
8
+ * reactivity is dead weight, and a shared cache on a stateless multi-tenant
9
+ * edge worker is a cross-tenant hazard. This helper carries only the
10
+ * Foir-specific transport concerns (auth header, preview schema channel,
11
+ * error shape). Consumers on a GraphQL client (Apollo / urql / react-query /
12
+ * graphql-request) use the generated `TypedDocumentNode`s directly with their
13
+ * own client and replicate the two Foir-specific headers below — the
14
+ * `x-api-key` and, in preview, `X-Foir-Schema-Channel: draft`.
15
+ *
16
+ * Deduplicates the hand-copied `lib/foir/client.ts` that shipped identically
17
+ * across the Foir storefronts.
18
+ */
19
+
20
+ interface FoirEnv {
21
+ PLATFORM_API_URL?: string;
22
+ PLATFORM_API_KEY?: string;
23
+ PLATFORM_PREVIEW_API_KEY?: string;
24
+ FOIR_PREVIEW?: string;
25
+ }
26
+
27
+ /**
28
+ * Foir customer auth — framework-agnostic flows, token lifecycle, and guards.
29
+ *
30
+ * Session I/O is injected via {@link SessionAdapter} (no Hydrogen/React-Router
31
+ * coupling). Pre-login flows authenticate with the project `x-api-key`;
32
+ * post-login reads add the customer bearer. The project-specific profile (e.g.
33
+ * `isAdmin`) is resolved by a consumer-supplied `resolveUser` — the SDK never
34
+ * hardcodes the per-project customer profile shape.
35
+ */
36
+
37
+ /** The customer identity carried by an auth result. */
38
+ interface FoirCustomer {
39
+ id: string;
40
+ email: string;
41
+ }
42
+ /**
43
+ * Injected session store. Methods may be sync or async so consumers can plug
44
+ * in a cookie session (Hydrogen/Remix), a KV store, etc.
45
+ */
46
+ interface SessionAdapter {
47
+ get(key: string): string | null | undefined | Promise<string | null | undefined>;
48
+ set(key: string, value: string): void | Promise<void>;
49
+ unset(key: string): void | Promise<void>;
50
+ }
51
+
52
+ /**
53
+ * The minimal cookie-store shape this adapter needs. It's satisfied by Next's
54
+ * `cookies()` (route handlers / server actions — `await cookies()` on Next 15),
55
+ * and by `NextResponse.cookies` in middleware. Kept structural on purpose so the
56
+ * SDK doesn't import (or pin a version of) `next/headers`.
57
+ */
58
+ interface FoirCookieStore {
59
+ get(name: string): {
60
+ value: string;
61
+ } | undefined;
62
+ set(name: string, value: string, options?: Record<string, unknown>): void;
63
+ delete(name: string): void;
64
+ }
65
+ interface CookieAdapterOptions {
66
+ /** Cookie attributes for writes, merged over the secure defaults. */
67
+ cookieOptions?: Record<string, unknown>;
68
+ }
69
+ declare function foirCookieName(key: string): string;
70
+ /**
71
+ * A {@link SessionAdapter} backed by an HttpOnly cookie store — the seam for
72
+ * server-side (BFF) Foir sessions in Next.js. Pass the cookie store from a route
73
+ * handler / server action (`await cookies()`) for reads and writes; a Server
74
+ * Component's `cookies()` is read-only, so use it only for reads there.
75
+ */
76
+ declare function createFoirCookieAdapter(store: FoirCookieStore, opts?: CookieAdapterOptions): SessionAdapter;
77
+
78
+ /**
79
+ * Server-side session helpers for the Next.js BFF pattern. Each takes the Next
80
+ * cookie store (`await cookies()` in a route handler / server action, or the
81
+ * read-only `cookies()` in a Server Component for reads).
82
+ *
83
+ * Note on "verification": the customer access token is opaque to your app and
84
+ * validated by the Foir API on use, so `getFoirSession` returns the identity
85
+ * stored in the cookies rather than locally verifying a JWT. A rejected/expired
86
+ * bearer surfaces when you call the API (and `@foir/sdk/auth`'s `authedRequest`
87
+ * transparently refreshes it).
88
+ */
89
+ /** The signed-in customer from the session cookies, or null. */
90
+ declare function getFoirSession(store: FoirCookieStore): Promise<FoirCustomer | null>;
91
+ /** The current access token from the session cookies, or null. */
92
+ declare function getFoirToken(store: FoirCookieStore): Promise<string | null>;
93
+ /** Clear the session cookies (sign out). */
94
+ declare function foirSignOut(store: FoirCookieStore, opts?: CookieAdapterOptions): Promise<void>;
95
+ interface PasswordArgs {
96
+ env: FoirEnv;
97
+ store: FoirCookieStore;
98
+ email: string;
99
+ password: string;
100
+ cookieOptions?: CookieAdapterOptions['cookieOptions'];
101
+ }
102
+ /** Password sign-in in a route handler; persists the session to cookies. */
103
+ declare function foirSignInWithPassword({ env, store, email, password, cookieOptions, }: PasswordArgs): Promise<FoirCustomer>;
104
+ /** Register a customer in a route handler; persists the session to cookies. */
105
+ declare function foirRegisterWithPassword({ env, store, email, password, cookieOptions, }: PasswordArgs): Promise<FoirCustomer>;
106
+ /** Complete an OTP sign-in in a route handler; persists the session to cookies. */
107
+ declare function foirSignInWithOtp({ env, store, email, otp, cookieOptions, }: {
108
+ env: FoirEnv;
109
+ store: FoirCookieStore;
110
+ email: string;
111
+ otp: string;
112
+ cookieOptions?: CookieAdapterOptions['cookieOptions'];
113
+ }): Promise<FoirCustomer>;
114
+ /**
115
+ * Complete a provider (OAuth/OIDC) login in your callback route handler:
116
+ * exchange the `code` + `state` for tokens and persist them to the session
117
+ * cookies. Returns the customer.
118
+ */
119
+ declare function completeFoirProviderLogin(opts: {
120
+ env: FoirEnv;
121
+ store: FoirCookieStore;
122
+ providerKey: string;
123
+ code?: string;
124
+ state?: string;
125
+ cookieOptions?: CookieAdapterOptions['cookieOptions'];
126
+ }): Promise<FoirCustomer>;
127
+
128
+ /**
129
+ * The slice of `NextRequest` the middleware reads. Typed structurally so the SDK
130
+ * doesn't need `next` installed to build — a real `NextRequest` satisfies it, so
131
+ * the returned function drops straight into `export const middleware`.
132
+ */
133
+ interface FoirMiddlewareRequest {
134
+ cookies: {
135
+ get(name: string): {
136
+ value: string;
137
+ } | undefined;
138
+ };
139
+ nextUrl: {
140
+ pathname: string;
141
+ search: string;
142
+ };
143
+ url: string;
144
+ }
145
+ interface FoirMiddlewareConfig {
146
+ /** Where to send unauthenticated requests (path or absolute URL). */
147
+ signInUrl: string;
148
+ /**
149
+ * The session cookie whose presence means "signed in". Defaults to the
150
+ * access-token cookie the cookie adapter writes (`foir_token`).
151
+ */
152
+ cookieName?: string;
153
+ /**
154
+ * Return true for requests that require auth. Omit to protect every request
155
+ * the middleware `matcher` passes through.
156
+ */
157
+ isProtected?(request: FoirMiddlewareRequest): boolean;
158
+ /** Query param carrying the original path on the sign-in URL. Default `returnTo`. */
159
+ returnParam?: string;
160
+ }
161
+ /**
162
+ * Build a Next.js middleware that redirects unauthenticated requests to your
163
+ * sign-in URL. Edge-safe: it checks for the presence of the session cookie only
164
+ * — the bearer itself is validated server-side when you call the Foir API — so
165
+ * pair it with a real `getFoirSession` check in protected route handlers /
166
+ * server components. Returns a standard `Response` (redirect) or `undefined`
167
+ * (continue), both of which Next.js middleware accepts.
168
+ *
169
+ * ```ts
170
+ * // middleware.ts
171
+ * import { createFoirMiddleware } from '@foir/sdk/next';
172
+ * export const middleware = createFoirMiddleware({ signInUrl: '/sign-in' });
173
+ * export const config = { matcher: ['/dashboard/:path*'] };
174
+ * ```
175
+ */
176
+ declare function createFoirMiddleware(config: FoirMiddlewareConfig): (request: FoirMiddlewareRequest) => Response | undefined;
177
+
178
+ export { type CookieAdapterOptions, type FoirCookieStore, type FoirCustomer, type FoirEnv, type FoirMiddlewareConfig, type FoirMiddlewareRequest, type SessionAdapter, completeFoirProviderLogin, createFoirCookieAdapter, createFoirMiddleware, foirCookieName, foirRegisterWithPassword, foirSignInWithOtp, foirSignInWithPassword, foirSignOut, getFoirSession, getFoirToken };
package/dist/next.js ADDED
@@ -0,0 +1,275 @@
1
+ // src/next/cookieAdapter.ts
2
+ var DEFAULT_COOKIE_OPTIONS = {
3
+ httpOnly: true,
4
+ secure: true,
5
+ sameSite: "lax",
6
+ path: "/"
7
+ };
8
+ function foirCookieName(key) {
9
+ return key.replace(/[^a-zA-Z0-9_-]/g, "_");
10
+ }
11
+ function createFoirCookieAdapter(store, opts = {}) {
12
+ const options = { ...DEFAULT_COOKIE_OPTIONS, ...opts.cookieOptions };
13
+ return {
14
+ get: (key) => store.get(foirCookieName(key))?.value ?? null,
15
+ set: (key, value) => store.set(foirCookieName(key), value, options),
16
+ unset: (key) => store.delete(foirCookieName(key))
17
+ };
18
+ }
19
+
20
+ // src/graphql/foir-request.ts
21
+ import { print } from "graphql";
22
+ function isFoirPreview(env) {
23
+ return env.FOIR_PREVIEW === "true";
24
+ }
25
+ var FoirRequestError = class extends Error {
26
+ /** HTTP status code, when the request failed at the HTTP layer. */
27
+ status;
28
+ /** GraphQL errors, when the request failed with a no-data error envelope. */
29
+ graphQLErrors;
30
+ cause;
31
+ constructor(message, options) {
32
+ super(message);
33
+ this.name = "FoirRequestError";
34
+ this.cause = options?.cause;
35
+ this.status = options?.status;
36
+ this.graphQLErrors = options?.graphQLErrors;
37
+ }
38
+ };
39
+ async function foirRequest(env, document, variables, options) {
40
+ const endpoint = env.PLATFORM_API_URL;
41
+ const apiKey = isFoirPreview(env) ? env.PLATFORM_PREVIEW_API_KEY ?? env.PLATFORM_API_KEY : env.PLATFORM_API_KEY;
42
+ if (!endpoint || !apiKey) {
43
+ throw new FoirRequestError(
44
+ "[foir] PLATFORM_API_URL or PLATFORM_API_KEY is not set \u2014 add them to .env"
45
+ );
46
+ }
47
+ const headers = {
48
+ "Content-Type": "application/json",
49
+ "x-api-key": apiKey
50
+ };
51
+ if (isFoirPreview(env)) {
52
+ headers["X-Foir-Schema-Channel"] = "draft";
53
+ }
54
+ if (options?.bearerToken) {
55
+ headers["Authorization"] = `Bearer ${options.bearerToken}`;
56
+ }
57
+ let res;
58
+ try {
59
+ res = await fetch(endpoint, {
60
+ method: "POST",
61
+ headers,
62
+ body: JSON.stringify({ query: print(document), variables })
63
+ });
64
+ } catch (err) {
65
+ throw new FoirRequestError("[foir] network error", { cause: err });
66
+ }
67
+ if (!res.ok) {
68
+ throw new FoirRequestError(`[foir] HTTP ${res.status} ${res.statusText}`, {
69
+ status: res.status
70
+ });
71
+ }
72
+ const json = await res.json();
73
+ if (json.errors?.length) {
74
+ const msg = json.errors.map((e) => e.message).join("; ");
75
+ if (json.data) {
76
+ console.warn(`[foir] GraphQL partial errors (data returned): ${msg}`);
77
+ } else {
78
+ throw new FoirRequestError(`[foir] GraphQL errors: ${msg}`, {
79
+ graphQLErrors: json.errors
80
+ });
81
+ }
82
+ }
83
+ if (!json.data) {
84
+ throw new FoirRequestError("[foir] empty GraphQL response");
85
+ }
86
+ return json.data;
87
+ }
88
+
89
+ // src/auth/operations.ts
90
+ import { parse } from "graphql";
91
+ var AUTH_RESULT_FIELDS = "token refreshToken customerId email";
92
+ var CustomerLoginDocument = parse(
93
+ `mutation CustomerLogin($email: String!, $password: String!) {
94
+ customerLogin(email: $email, password: $password) { ${AUTH_RESULT_FIELDS} }
95
+ }`
96
+ );
97
+ var CustomerRegisterDocument = parse(
98
+ `mutation CustomerRegister($email: String!, $password: String!) {
99
+ customerRegister(email: $email, password: $password) { ${AUTH_RESULT_FIELDS} }
100
+ }`
101
+ );
102
+ var CustomerRefreshTokenDocument = parse(
103
+ `mutation CustomerRefreshToken($refreshToken: String!) {
104
+ customerRefreshToken(refreshToken: $refreshToken) { ${AUTH_RESULT_FIELDS} }
105
+ }`
106
+ );
107
+ var CustomerRequestOTPDocument = parse(
108
+ `mutation CustomerRequestOTP($email: String!) {
109
+ customerRequestOTP(email: $email)
110
+ }`
111
+ );
112
+ var CustomerLoginOTPDocument = parse(
113
+ `mutation CustomerLoginOTP($email: String!, $otp: String!) {
114
+ customerLoginOTP(email: $email, otp: $otp) { ${AUTH_RESULT_FIELDS} }
115
+ }`
116
+ );
117
+ var CustomerLoginWithProviderDocument = parse(
118
+ `mutation CustomerLoginWithProvider($input: ProviderLoginInput!) {
119
+ customerLoginWithProvider(input: $input) { redirectUrl token }
120
+ }`
121
+ );
122
+ var CustomerProviderCallbackDocument = parse(
123
+ `mutation CustomerProviderCallback($input: ProviderCallbackInput!) {
124
+ customerProviderCallback(input: $input) { ${AUTH_RESULT_FIELDS} }
125
+ }`
126
+ );
127
+ var CustomerProviderVerifyOTPDocument = parse(
128
+ `mutation CustomerProviderVerifyOTP($input: ProviderOTPVerifyInput!) {
129
+ customerProviderVerifyOTP(input: $input) { ${AUTH_RESULT_FIELDS} }
130
+ }`
131
+ );
132
+ var AuthProvidersDocument = parse(
133
+ `query AuthProviders {
134
+ authProviders { key name type isDefault }
135
+ }`
136
+ );
137
+
138
+ // src/auth/auth.ts
139
+ var TOKEN_KEY = "foir:token";
140
+ var REFRESH_KEY = "foir:refreshToken";
141
+ var CUSTOMER_ID_KEY = "foir:customerId";
142
+ var EMAIL_KEY = "foir:email";
143
+ async function customerLogin(env, vars) {
144
+ return (await foirRequest(env, CustomerLoginDocument, vars)).customerLogin;
145
+ }
146
+ async function customerRegister(env, vars) {
147
+ return (await foirRequest(env, CustomerRegisterDocument, vars)).customerRegister;
148
+ }
149
+ async function customerLoginOTP(env, vars) {
150
+ return (await foirRequest(env, CustomerLoginOTPDocument, vars)).customerLoginOTP;
151
+ }
152
+ async function customerProviderCallback(env, input) {
153
+ return (await foirRequest(env, CustomerProviderCallbackDocument, { input })).customerProviderCallback;
154
+ }
155
+ async function saveSession(adapter, result) {
156
+ await adapter.set(TOKEN_KEY, result.token);
157
+ await adapter.set(REFRESH_KEY, result.refreshToken);
158
+ await adapter.set(CUSTOMER_ID_KEY, result.customerId);
159
+ await adapter.set(EMAIL_KEY, result.email);
160
+ return { id: result.customerId, email: result.email };
161
+ }
162
+ async function clearSession(adapter) {
163
+ await adapter.unset(TOKEN_KEY);
164
+ await adapter.unset(REFRESH_KEY);
165
+ await adapter.unset(CUSTOMER_ID_KEY);
166
+ await adapter.unset(EMAIL_KEY);
167
+ }
168
+ async function getSessionToken(adapter) {
169
+ return await adapter.get(TOKEN_KEY) ?? null;
170
+ }
171
+ async function getSessionCustomer(adapter) {
172
+ const id = await adapter.get(CUSTOMER_ID_KEY) ?? null;
173
+ const email = await adapter.get(EMAIL_KEY) ?? null;
174
+ if (!id) return null;
175
+ return { id, email: email ?? "" };
176
+ }
177
+ async function loginWithPassword(adapter, env, vars) {
178
+ return saveSession(adapter, await customerLogin(env, vars));
179
+ }
180
+ async function registerWithPassword(adapter, env, vars) {
181
+ return saveSession(adapter, await customerRegister(env, vars));
182
+ }
183
+ async function loginWithOTP(adapter, env, vars) {
184
+ return saveSession(adapter, await customerLoginOTP(env, vars));
185
+ }
186
+
187
+ // src/next/session.ts
188
+ async function getFoirSession(store) {
189
+ return getSessionCustomer(createFoirCookieAdapter(store));
190
+ }
191
+ async function getFoirToken(store) {
192
+ return getSessionToken(createFoirCookieAdapter(store));
193
+ }
194
+ async function foirSignOut(store, opts) {
195
+ return clearSession(createFoirCookieAdapter(store, opts));
196
+ }
197
+ function foirSignInWithPassword({
198
+ env,
199
+ store,
200
+ email,
201
+ password,
202
+ cookieOptions
203
+ }) {
204
+ return loginWithPassword(createFoirCookieAdapter(store, { cookieOptions }), env, {
205
+ email,
206
+ password
207
+ });
208
+ }
209
+ function foirRegisterWithPassword({
210
+ env,
211
+ store,
212
+ email,
213
+ password,
214
+ cookieOptions
215
+ }) {
216
+ return registerWithPassword(createFoirCookieAdapter(store, { cookieOptions }), env, {
217
+ email,
218
+ password
219
+ });
220
+ }
221
+ function foirSignInWithOtp({
222
+ env,
223
+ store,
224
+ email,
225
+ otp,
226
+ cookieOptions
227
+ }) {
228
+ return loginWithOTP(createFoirCookieAdapter(store, { cookieOptions }), env, {
229
+ email,
230
+ otp
231
+ });
232
+ }
233
+ async function completeFoirProviderLogin(opts) {
234
+ const result = await customerProviderCallback(opts.env, {
235
+ providerKey: opts.providerKey,
236
+ code: opts.code,
237
+ state: opts.state
238
+ });
239
+ return saveSession(
240
+ createFoirCookieAdapter(opts.store, { cookieOptions: opts.cookieOptions }),
241
+ result
242
+ );
243
+ }
244
+
245
+ // src/next/middleware.ts
246
+ function createFoirMiddleware(config) {
247
+ const cookieName = config.cookieName ?? foirCookieName("foir:token");
248
+ const returnParam = config.returnParam ?? "returnTo";
249
+ return function foirMiddleware(request) {
250
+ if (config.isProtected && !config.isProtected(request)) {
251
+ return void 0;
252
+ }
253
+ if (request.cookies.get(cookieName)?.value) {
254
+ return void 0;
255
+ }
256
+ const url = new URL(config.signInUrl, request.url);
257
+ url.searchParams.set(
258
+ returnParam,
259
+ request.nextUrl.pathname + request.nextUrl.search
260
+ );
261
+ return Response.redirect(url.toString(), 307);
262
+ };
263
+ }
264
+ export {
265
+ completeFoirProviderLogin,
266
+ createFoirCookieAdapter,
267
+ createFoirMiddleware,
268
+ foirCookieName,
269
+ foirRegisterWithPassword,
270
+ foirSignInWithOtp,
271
+ foirSignInWithPassword,
272
+ foirSignOut,
273
+ getFoirSession,
274
+ getFoirToken
275
+ };