@foir/sdk 0.1.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 +110 -0
- package/dist/auth.d.ts +305 -0
- package/dist/auth.js +309 -0
- package/dist/chunk-ADO5FJNM.js +30 -0
- package/dist/client.d.ts +83 -0
- package/dist/client.js +81 -0
- package/dist/codegen/block-registry.d.ts +27 -0
- package/dist/codegen/block-registry.js +35 -0
- package/dist/codegen/block-scaffold.d.ts +28 -0
- package/dist/codegen/block-scaffold.js +45 -0
- package/dist/codegen/index.d.ts +65 -0
- package/dist/codegen/index.js +80 -0
- package/dist/content.d.ts +96 -0
- package/dist/content.js +161 -0
- package/dist/index.d.ts +394 -0
- package/dist/index.js +476 -0
- package/dist/media.d.ts +234 -0
- package/dist/media.js +399 -0
- package/dist/realtime.d.ts +111 -0
- package/dist/realtime.js +168 -0
- package/dist/server.d.ts +457 -0
- package/dist/server.js +296 -0
- package/dist/shared-DkWlEd2Z.d.ts +18 -0
- package/package.json +136 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# @foir/sdk
|
|
2
|
+
|
|
3
|
+
Official Foir SDK — client-agnostic typed GraphQL transport, customer auth,
|
|
4
|
+
progressive media, content rendering, realtime collaboration, and editor/server
|
|
5
|
+
helpers for building apps on the [Foir](https://foir.dev) platform.
|
|
6
|
+
|
|
7
|
+
The SDK is split into independent subpath exports so consumers only pull what
|
|
8
|
+
they use. Everything heavy (`react`, `graphql`, `yjs`, `hls.js`, …) is an
|
|
9
|
+
optional peer dependency gated to the subpath that needs it.
|
|
10
|
+
|
|
11
|
+
## Install
|
|
12
|
+
|
|
13
|
+
```sh
|
|
14
|
+
pnpm add @foir/sdk
|
|
15
|
+
# plus the peers for the subpaths you use, e.g.:
|
|
16
|
+
pnpm add graphql # for @foir/sdk/client + @foir/sdk/auth
|
|
17
|
+
pnpm add react # for @foir/sdk (editor), /media, /content
|
|
18
|
+
pnpm add yjs y-websocket # for @foir/sdk/realtime
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Subpath exports
|
|
22
|
+
|
|
23
|
+
| Import | What it is | Peers |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| `@foir/sdk` | Editor iframe client — `EditorProvider`, `useEditor`, `useAutoResize`, `createPlatformClient`, host↔editor message protocol | `react` |
|
|
26
|
+
| `@foir/sdk/client` | Client-agnostic GraphQL transport for SSR/edge loaders — `foirRequest`, `isFoirPreview`, `absolutiseFoirMediaUrl` | `graphql` |
|
|
27
|
+
| `@foir/sdk/auth` | Framework-agnostic customer auth — login/register/OTP/provider flows, token lifecycle (`SessionAdapter`), `authedRequest`, guards | `graphql` |
|
|
28
|
+
| `@foir/sdk/server` | Server-side helpers for extension/config API backends — `createServerClient`, `verifyWebhookSignature`, `verifyScopedToken`, callback client | — |
|
|
29
|
+
| `@foir/sdk/media` | Progressive media — `ProgressiveMedia`, `BlurhashCanvas`, `useProgressiveLoad`, variant-tier adapters | `react` (`hls.js`, `blurhash` optional) |
|
|
30
|
+
| `@foir/sdk/content` | Content-rendering primitives — `createContentRenderer` block dispatch + Lexical `RichTextRenderer` | `react` |
|
|
31
|
+
| `@foir/sdk/realtime` | Thin collaboration helper over `y-websocket` — canonical room addressing, presence, token refresh | `yjs`, `y-websocket` |
|
|
32
|
+
| `@foir/sdk/codegen` | Build-time graphql-codegen preset (`foirCodegen`) + exhaustive block-registry plugin | `@graphql-codegen/cli`, `@graphql-codegen/client-preset` (devDeps) |
|
|
33
|
+
|
|
34
|
+
## Usage
|
|
35
|
+
|
|
36
|
+
### Typed GraphQL from a server loader
|
|
37
|
+
|
|
38
|
+
`foirRequest` is a typed `fetch` wrapper, not a GraphQL client: it carries the
|
|
39
|
+
Foir-specific transport concerns (`x-api-key`, preview schema channel, error
|
|
40
|
+
shape) and runs generated `TypedDocumentNode`s. Bring-your-own-client consumers
|
|
41
|
+
(Apollo/urql/react-query) use the generated documents directly and replicate
|
|
42
|
+
those headers.
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { foirRequest, type FoirEnv } from '@foir/sdk/client';
|
|
46
|
+
import { HomePageDocument } from './generated/graphql';
|
|
47
|
+
|
|
48
|
+
export async function loader({ context }: LoaderArgs) {
|
|
49
|
+
const env: FoirEnv = {
|
|
50
|
+
PLATFORM_API_URL: context.env.PLATFORM_API_URL,
|
|
51
|
+
PLATFORM_API_KEY: context.env.PLATFORM_API_KEY,
|
|
52
|
+
};
|
|
53
|
+
const data = await foirRequest(env, HomePageDocument, { slug: 'home' });
|
|
54
|
+
return data.homePage;
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Customer auth
|
|
59
|
+
|
|
60
|
+
```ts
|
|
61
|
+
import {
|
|
62
|
+
loginWithPassword,
|
|
63
|
+
authedRequest,
|
|
64
|
+
type SessionAdapter,
|
|
65
|
+
} from '@foir/sdk/auth';
|
|
66
|
+
import { MyProfileDocument } from './generated/graphql';
|
|
67
|
+
|
|
68
|
+
// SessionAdapter = { get, set, delete } over your session store (cookie, KV…).
|
|
69
|
+
const customer = await loginWithPassword(adapter, env, { email, password });
|
|
70
|
+
|
|
71
|
+
// Bearer-authed request with automatic refresh-and-retry on expired sessions.
|
|
72
|
+
const { myProfile } = await authedRequest(adapter, env, MyProfileDocument);
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Codegen
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
// codegen.ts
|
|
79
|
+
import { foirCodegen } from '@foir/sdk/codegen';
|
|
80
|
+
|
|
81
|
+
export default foirCodegen({
|
|
82
|
+
apiUrl: process.env.PLATFORM_API_URL!,
|
|
83
|
+
apiKey: process.env.PLATFORM_API_KEY!,
|
|
84
|
+
// documents: 'app/graphql/foir/**/*.graphql' (default)
|
|
85
|
+
// outputDir: './app/gql/foir/' (default)
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Editor extensions
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
import { EditorProvider, useEditor } from '@foir/sdk';
|
|
93
|
+
|
|
94
|
+
function App() {
|
|
95
|
+
return (
|
|
96
|
+
<EditorProvider>
|
|
97
|
+
<MyEditor />
|
|
98
|
+
</EditorProvider>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function MyEditor() {
|
|
103
|
+
const { init, client } = useEditor(); // record context + platform GraphQL client
|
|
104
|
+
// ...
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
MIT
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
import { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Foir GraphQL client — a single typed fetch wrapper for SSR/edge loaders.
|
|
5
|
+
*
|
|
6
|
+
* No GraphQL client (Apollo/urql) required: the Foir public API is a plain
|
|
7
|
+
* `POST` with an `x-api-key` header, and the dominant consumers (Hydrogen on
|
|
8
|
+
* Oxygen, React Router loaders, TanStack Start on CF Workers) fetch in
|
|
9
|
+
* server-only loaders and render — so Apollo's `InMemoryCache`/`useQuery`
|
|
10
|
+
* reactivity is dead weight, and a shared cache on a stateless multi-tenant
|
|
11
|
+
* edge worker is a cross-tenant hazard. This helper carries only the
|
|
12
|
+
* Foir-specific transport concerns (auth header, preview schema channel,
|
|
13
|
+
* error shape). Consumers on a GraphQL client (Apollo / urql / react-query /
|
|
14
|
+
* graphql-request) use the generated `TypedDocumentNode`s directly with their
|
|
15
|
+
* own client and replicate the two Foir-specific headers below — the
|
|
16
|
+
* `x-api-key` and, in preview, `X-Foir-Schema-Channel: draft`.
|
|
17
|
+
*
|
|
18
|
+
* Deduplicates the hand-copied `lib/foir/client.ts` that shipped identically
|
|
19
|
+
* across the Foir storefronts.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
interface FoirEnv {
|
|
23
|
+
PLATFORM_API_URL?: string;
|
|
24
|
+
PLATFORM_API_KEY?: string;
|
|
25
|
+
PLATFORM_PREVIEW_API_KEY?: string;
|
|
26
|
+
FOIR_PREVIEW?: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Foir customer-auth GraphQL operations + result types.
|
|
31
|
+
*
|
|
32
|
+
* These are PLATFORM-STABLE primitives — `customerLogin`/`customerRegister`/
|
|
33
|
+
* `customerRefreshToken`/OTP/provider login are fixed-shape operations served
|
|
34
|
+
* by api-public for every project (gated per-project by the password/OTP/
|
|
35
|
+
* provider flags, but identical in shape when present). Unlike per-project
|
|
36
|
+
* model types, they don't vary by configured models, so the SDK owns the
|
|
37
|
+
* documents directly rather than relying on the consumer's codegen.
|
|
38
|
+
*
|
|
39
|
+
* The project-specific customer PROFILE (e.g. `myProfile.isAdmin`) is NOT here
|
|
40
|
+
* — that shape varies per project, so it stays consumer-injected (see
|
|
41
|
+
* `requireAuth`'s `resolveUser`).
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
/** The common auth result every login/register/refresh mutation returns. */
|
|
45
|
+
interface CustomerAuthResult {
|
|
46
|
+
token: string;
|
|
47
|
+
refreshToken: string;
|
|
48
|
+
customerId: string;
|
|
49
|
+
email: string;
|
|
50
|
+
}
|
|
51
|
+
/** Result of initiating a provider login — a redirect URL or an inline token. */
|
|
52
|
+
interface ProviderLoginResult {
|
|
53
|
+
/** OAuth/OIDC authorization URL to redirect the user to (redirect flows). */
|
|
54
|
+
redirectUrl: string | null;
|
|
55
|
+
/** Inline access token (non-redirect provider flows). */
|
|
56
|
+
token: string | null;
|
|
57
|
+
}
|
|
58
|
+
/** A configured auth provider, as exposed to unauthenticated callers. */
|
|
59
|
+
interface AuthProviderPublic {
|
|
60
|
+
key: string;
|
|
61
|
+
name: string;
|
|
62
|
+
/** OAUTH2 | TOKEN_SSO | SAML | OIDC | EXTERNAL */
|
|
63
|
+
type: string;
|
|
64
|
+
isDefault: boolean | null;
|
|
65
|
+
}
|
|
66
|
+
interface ProviderLoginInput {
|
|
67
|
+
providerKey: string;
|
|
68
|
+
email?: string;
|
|
69
|
+
returnTo?: string;
|
|
70
|
+
/** Override the provider's default redirect_uri (must be allow-listed). */
|
|
71
|
+
redirectUri?: string;
|
|
72
|
+
}
|
|
73
|
+
interface ProviderCallbackInput {
|
|
74
|
+
providerKey: string;
|
|
75
|
+
code?: string;
|
|
76
|
+
state?: string;
|
|
77
|
+
email?: string;
|
|
78
|
+
idToken?: string;
|
|
79
|
+
}
|
|
80
|
+
interface ProviderOTPVerifyInput {
|
|
81
|
+
providerKey: string;
|
|
82
|
+
email: string;
|
|
83
|
+
otp: string;
|
|
84
|
+
}
|
|
85
|
+
declare const CustomerLoginDocument: TypedDocumentNode<{
|
|
86
|
+
customerLogin: CustomerAuthResult;
|
|
87
|
+
}, {
|
|
88
|
+
email: string;
|
|
89
|
+
password: string;
|
|
90
|
+
}>;
|
|
91
|
+
declare const CustomerRegisterDocument: TypedDocumentNode<{
|
|
92
|
+
customerRegister: CustomerAuthResult;
|
|
93
|
+
}, {
|
|
94
|
+
email: string;
|
|
95
|
+
password: string;
|
|
96
|
+
}>;
|
|
97
|
+
declare const CustomerRefreshTokenDocument: TypedDocumentNode<{
|
|
98
|
+
customerRefreshToken: CustomerAuthResult;
|
|
99
|
+
}, {
|
|
100
|
+
refreshToken: string;
|
|
101
|
+
}>;
|
|
102
|
+
declare const CustomerRequestOTPDocument: TypedDocumentNode<{
|
|
103
|
+
customerRequestOTP: boolean;
|
|
104
|
+
}, {
|
|
105
|
+
email: string;
|
|
106
|
+
}>;
|
|
107
|
+
declare const CustomerLoginOTPDocument: TypedDocumentNode<{
|
|
108
|
+
customerLoginOTP: CustomerAuthResult;
|
|
109
|
+
}, {
|
|
110
|
+
email: string;
|
|
111
|
+
otp: string;
|
|
112
|
+
}>;
|
|
113
|
+
declare const CustomerLoginWithProviderDocument: TypedDocumentNode<{
|
|
114
|
+
customerLoginWithProvider: ProviderLoginResult;
|
|
115
|
+
}, {
|
|
116
|
+
input: ProviderLoginInput;
|
|
117
|
+
}>;
|
|
118
|
+
declare const CustomerProviderCallbackDocument: TypedDocumentNode<{
|
|
119
|
+
customerProviderCallback: CustomerAuthResult;
|
|
120
|
+
}, {
|
|
121
|
+
input: ProviderCallbackInput;
|
|
122
|
+
}>;
|
|
123
|
+
declare const CustomerProviderVerifyOTPDocument: TypedDocumentNode<{
|
|
124
|
+
customerProviderVerifyOTP: CustomerAuthResult;
|
|
125
|
+
}, {
|
|
126
|
+
input: ProviderOTPVerifyInput;
|
|
127
|
+
}>;
|
|
128
|
+
declare const AuthProvidersDocument: TypedDocumentNode<{
|
|
129
|
+
authProviders: AuthProviderPublic[];
|
|
130
|
+
}, Record<string, never>>;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Foir customer auth — framework-agnostic flows, token lifecycle, and guards.
|
|
134
|
+
*
|
|
135
|
+
* Session I/O is injected via {@link SessionAdapter} (no Hydrogen/React-Router
|
|
136
|
+
* coupling). Pre-login flows authenticate with the project `x-api-key`;
|
|
137
|
+
* post-login reads add the customer bearer. The project-specific profile (e.g.
|
|
138
|
+
* `isAdmin`) is resolved by a consumer-supplied `resolveUser` — the SDK never
|
|
139
|
+
* hardcodes the per-project customer profile shape.
|
|
140
|
+
*/
|
|
141
|
+
|
|
142
|
+
/** An access token + its rotating refresh token. */
|
|
143
|
+
interface FoirAuthTokens {
|
|
144
|
+
token: string;
|
|
145
|
+
refreshToken: string;
|
|
146
|
+
}
|
|
147
|
+
/** The customer identity carried by an auth result. */
|
|
148
|
+
interface FoirCustomer {
|
|
149
|
+
id: string;
|
|
150
|
+
email: string;
|
|
151
|
+
}
|
|
152
|
+
/** The resolved customer for a guarded surface. */
|
|
153
|
+
interface FoirUser {
|
|
154
|
+
id: string;
|
|
155
|
+
email: string;
|
|
156
|
+
isAdmin: boolean;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Injected session store. Methods may be sync or async so consumers can plug
|
|
160
|
+
* in a cookie session (Hydrogen/Remix), a KV store, etc.
|
|
161
|
+
*/
|
|
162
|
+
interface SessionAdapter {
|
|
163
|
+
get(key: string): string | null | undefined | Promise<string | null | undefined>;
|
|
164
|
+
set(key: string, value: string): void | Promise<void>;
|
|
165
|
+
unset(key: string): void | Promise<void>;
|
|
166
|
+
}
|
|
167
|
+
/** Login with email + password. Requires the project to have passwords enabled. */
|
|
168
|
+
declare function customerLogin(env: FoirEnv, vars: {
|
|
169
|
+
email: string;
|
|
170
|
+
password: string;
|
|
171
|
+
}): Promise<CustomerAuthResult>;
|
|
172
|
+
/** Register a new customer with email + password. */
|
|
173
|
+
declare function customerRegister(env: FoirEnv, vars: {
|
|
174
|
+
email: string;
|
|
175
|
+
password: string;
|
|
176
|
+
}): Promise<CustomerAuthResult>;
|
|
177
|
+
/** Request a one-time password be emailed to the customer. */
|
|
178
|
+
declare function customerRequestOTP(env: FoirEnv, email: string): Promise<boolean>;
|
|
179
|
+
/** Complete an OTP login. */
|
|
180
|
+
declare function customerLoginOTP(env: FoirEnv, vars: {
|
|
181
|
+
email: string;
|
|
182
|
+
otp: string;
|
|
183
|
+
}): Promise<CustomerAuthResult>;
|
|
184
|
+
/** Rotate an access token using a refresh token. */
|
|
185
|
+
declare function customerRefreshToken(env: FoirEnv, refreshToken: string): Promise<CustomerAuthResult>;
|
|
186
|
+
/**
|
|
187
|
+
* Initiate provider (OAuth/OIDC) login — returns a `redirectUrl` to send the
|
|
188
|
+
* user to, or an inline `token` for non-redirect providers.
|
|
189
|
+
*/
|
|
190
|
+
declare function customerLoginWithProvider(env: FoirEnv, input: ProviderLoginInput): Promise<ProviderLoginResult>;
|
|
191
|
+
/** Complete a provider login from the OAuth callback (`code`/`state`). */
|
|
192
|
+
declare function customerProviderCallback(env: FoirEnv, input: ProviderCallbackInput): Promise<CustomerAuthResult>;
|
|
193
|
+
/** Verify an OTP issued by an external provider. */
|
|
194
|
+
declare function customerProviderVerifyOTP(env: FoirEnv, input: ProviderOTPVerifyInput): Promise<CustomerAuthResult>;
|
|
195
|
+
/** List the project's configured auth providers (for a login UI). */
|
|
196
|
+
declare function getAuthProviders(env: FoirEnv): Promise<AuthProviderPublic[]>;
|
|
197
|
+
/** Persist an auth result to the session; returns the customer identity. */
|
|
198
|
+
declare function saveSession(adapter: SessionAdapter, result: CustomerAuthResult): Promise<FoirCustomer>;
|
|
199
|
+
/** Clear all Foir auth keys from the session. */
|
|
200
|
+
declare function clearSession(adapter: SessionAdapter): Promise<void>;
|
|
201
|
+
/** Read the stored access token (null when signed out). */
|
|
202
|
+
declare function getSessionToken(adapter: SessionAdapter): Promise<string | null>;
|
|
203
|
+
/** Read the stored customer identity (null when signed out). */
|
|
204
|
+
declare function getSessionCustomer(adapter: SessionAdapter): Promise<FoirCustomer | null>;
|
|
205
|
+
/** Login with email + password and persist the session. */
|
|
206
|
+
declare function loginWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
|
|
207
|
+
email: string;
|
|
208
|
+
password: string;
|
|
209
|
+
}): Promise<FoirCustomer>;
|
|
210
|
+
/** Register with email + password and persist the session. */
|
|
211
|
+
declare function registerWithPassword(adapter: SessionAdapter, env: FoirEnv, vars: {
|
|
212
|
+
email: string;
|
|
213
|
+
password: string;
|
|
214
|
+
}): Promise<FoirCustomer>;
|
|
215
|
+
/** Complete an OTP login and persist the session. */
|
|
216
|
+
declare function loginWithOTP(adapter: SessionAdapter, env: FoirEnv, vars: {
|
|
217
|
+
email: string;
|
|
218
|
+
otp: string;
|
|
219
|
+
}): Promise<FoirCustomer>;
|
|
220
|
+
/**
|
|
221
|
+
* Refresh the access token from the stored refresh token, persisting the
|
|
222
|
+
* rotated pair. Returns the new tokens, or null when there's no refresh token
|
|
223
|
+
* or the refresh fails (the session is cleared in that case).
|
|
224
|
+
*/
|
|
225
|
+
declare function refreshSession(adapter: SessionAdapter, env: FoirEnv): Promise<FoirAuthTokens | null>;
|
|
226
|
+
/**
|
|
227
|
+
* Run a bearer-authed GraphQL operation with refresh-with-retry: uses the
|
|
228
|
+
* stored access token, and on a 401-shaped failure (rejected/expired bearer)
|
|
229
|
+
* attempts a single token refresh and retries once. Any other error — network
|
|
230
|
+
* blips, server errors, validation — propagates without a retry so transient
|
|
231
|
+
* mutation failures can't be duplicated. Throws the original error if there's
|
|
232
|
+
* no refresh path.
|
|
233
|
+
*/
|
|
234
|
+
declare function authedRequest<TData, TVariables>(adapter: SessionAdapter, env: FoirEnv, document: TypedDocumentNode<TData, TVariables>, variables?: TVariables): Promise<TData>;
|
|
235
|
+
interface RequireAuthOptions {
|
|
236
|
+
/**
|
|
237
|
+
* Resolve the full {@link FoirUser} (including the project-specific
|
|
238
|
+
* `isAdmin`) from the session identity. Typically runs the project's
|
|
239
|
+
* `myProfile` query via {@link authedRequest}. Defaults to `isAdmin: false`.
|
|
240
|
+
*/
|
|
241
|
+
resolveUser?: (ctx: {
|
|
242
|
+
token: string;
|
|
243
|
+
customer: FoirCustomer;
|
|
244
|
+
}) => FoirUser | Promise<FoirUser>;
|
|
245
|
+
/**
|
|
246
|
+
* Called when there's no valid session — throw your framework's redirect
|
|
247
|
+
* (e.g. `throw redirect(loginUrl)`). Must not return.
|
|
248
|
+
*/
|
|
249
|
+
onUnauthenticated: () => never | Promise<never>;
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Require a signed-in customer. Resolves the {@link FoirUser} via
|
|
253
|
+
* `resolveUser` (or a minimal identity), or invokes `onUnauthenticated` when
|
|
254
|
+
* there's no session.
|
|
255
|
+
*/
|
|
256
|
+
declare function requireAuth(adapter: SessionAdapter, options: RequireAuthOptions): Promise<FoirUser>;
|
|
257
|
+
interface RequireAdminOptions extends RequireAuthOptions {
|
|
258
|
+
/** Called when the user is authenticated but not an admin. Must not return. */
|
|
259
|
+
onForbidden: () => never | Promise<never>;
|
|
260
|
+
}
|
|
261
|
+
/** Require a signed-in customer who is also an admin. */
|
|
262
|
+
declare function requireAdmin(adapter: SessionAdapter, options: RequireAdminOptions): Promise<FoirUser>;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Hosted-login bridge — for storefronts that delegate sign-in to a Foir
|
|
266
|
+
* white-label front door (the `customerLoginWithFoir` flow) instead of
|
|
267
|
+
* rendering their own login UI.
|
|
268
|
+
*
|
|
269
|
+
* The front door sets a first-party session cookie on the registrable domain;
|
|
270
|
+
* because that domain is shared, the cookie reaches the storefront, which
|
|
271
|
+
* exchanges it server-side for a short-lived customer bearer + identity. The
|
|
272
|
+
* cookie is the durable credential (re-exchanged on bearer expiry) — there's
|
|
273
|
+
* no separate refresh token in this flow.
|
|
274
|
+
*
|
|
275
|
+
* Every URL/cookie/path is CONFIG, not a constant, so a domain restructure
|
|
276
|
+
* is a config change, not a code change.
|
|
277
|
+
*/
|
|
278
|
+
interface HostedLoginConfig {
|
|
279
|
+
/** White-label front-door origin, e.g. `https://login.example.com`. */
|
|
280
|
+
loginOrigin: string;
|
|
281
|
+
/** Session cookie name set on the registrable domain. Default `foir_customer_session`. */
|
|
282
|
+
cookieName?: string;
|
|
283
|
+
/** Session-exchange path on the front door. Default `/session/token`. */
|
|
284
|
+
sessionPath?: string;
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Build the redirect URL to the hosted front door, forwarding a best-effort
|
|
288
|
+
* absolute `returnTo` (honoured if the front door supports it).
|
|
289
|
+
*/
|
|
290
|
+
declare function hostedLoginUrl(config: HostedLoginConfig, returnTo?: string): string;
|
|
291
|
+
/** The identity + bearer returned by a successful hosted-session exchange. */
|
|
292
|
+
interface HostedSession {
|
|
293
|
+
token: string;
|
|
294
|
+
customerId: string;
|
|
295
|
+
email: string;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Exchange the hosted-login cookie on an incoming request for a customer
|
|
299
|
+
* bearer + identity (server-to-server: forwards the cookie to the front
|
|
300
|
+
* door's session endpoint with the CSRF header). Returns null when there's no
|
|
301
|
+
* cookie or it's expired/revoked.
|
|
302
|
+
*/
|
|
303
|
+
declare function fetchHostedSession(request: Request, config: HostedLoginConfig): Promise<HostedSession | null>;
|
|
304
|
+
|
|
305
|
+
export { type AuthProviderPublic, AuthProvidersDocument, type CustomerAuthResult, CustomerLoginDocument, CustomerLoginOTPDocument, CustomerLoginWithProviderDocument, CustomerProviderCallbackDocument, CustomerProviderVerifyOTPDocument, CustomerRefreshTokenDocument, CustomerRegisterDocument, CustomerRequestOTPDocument, type FoirAuthTokens, type FoirCustomer, type FoirUser, type HostedLoginConfig, type HostedSession, type ProviderCallbackInput, type ProviderLoginInput, type ProviderLoginResult, type ProviderOTPVerifyInput, type RequireAdminOptions, type RequireAuthOptions, type SessionAdapter, authedRequest, clearSession, customerLogin, customerLoginOTP, customerLoginWithProvider, customerProviderCallback, customerProviderVerifyOTP, customerRefreshToken, customerRegister, customerRequestOTP, fetchHostedSession, getAuthProviders, getSessionCustomer, getSessionToken, hostedLoginUrl, loginWithOTP, loginWithPassword, refreshSession, registerWithPassword, requireAdmin, requireAuth, saveSession };
|