@foir/sdk 0.5.0 → 0.8.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.
Files changed (107) hide show
  1. package/CHANGELOG.md +1126 -0
  2. package/README.md +94 -0
  3. package/dist/auth/auth.d.ts +243 -0
  4. package/dist/auth/hosted.d.ts +40 -0
  5. package/dist/auth/index.d.ts +21 -0
  6. package/dist/auth/operations.d.ts +144 -0
  7. package/dist/auth/ops.d.ts +99 -0
  8. package/dist/auth/session-client.d.ts +76 -0
  9. package/dist/auth-session.js +137 -0
  10. package/dist/auth.js +973 -92
  11. package/dist/chunk-IGNLWT3H.js +35 -0
  12. package/dist/chunk-OHYVKTGB.js +45 -0
  13. package/dist/chunk-TAL5H6VA.js +39 -0
  14. package/dist/client/platform-client.d.ts +29 -0
  15. package/dist/client.js +275 -37
  16. package/dist/codegen/block-registry.d.ts +13 -23
  17. package/dist/codegen/block-registry.js +3 -31
  18. package/dist/codegen/block-scaffold.d.ts +12 -25
  19. package/dist/codegen/block-scaffold.js +3 -41
  20. package/dist/codegen/index.d.ts +12 -61
  21. package/dist/codegen/index.js +7 -11
  22. package/dist/codegen/item-registry.d.ts +28 -0
  23. package/dist/codegen/item-registry.js +7 -0
  24. package/dist/codegen/item-scaffold.d.ts +29 -0
  25. package/dist/codegen/item-scaffold.js +7 -0
  26. package/dist/codegen/preset.d.ts +67 -0
  27. package/dist/codegen/shared.d.ts +36 -0
  28. package/dist/components/EditorProvider.d.ts +36 -0
  29. package/dist/content/content-renderer.d.ts +113 -0
  30. package/dist/content/index.d.ts +18 -0
  31. package/dist/content/richtext.d.ts +118 -0
  32. package/dist/content.js +227 -80
  33. package/dist/data/builtins.d.ts +506 -0
  34. package/dist/data/client.d.ts +166 -0
  35. package/dist/data/document.d.ts +251 -0
  36. package/dist/data/index.d.ts +73 -0
  37. package/dist/data/manifest.d.ts +424 -0
  38. package/dist/data/schema.d.ts +313 -0
  39. package/dist/data/selection.d.ts +524 -0
  40. package/dist/data/subjects.d.ts +221 -0
  41. package/dist/data/subscription-document.d.ts +75 -0
  42. package/dist/data/subscriptions.d.ts +181 -0
  43. package/dist/data/transport.d.ts +325 -0
  44. package/dist/data/ws-transport.d.ts +197 -0
  45. package/dist/data.js +1683 -0
  46. package/dist/graphql/cdn-route.d.ts +26 -0
  47. package/dist/graphql/client.d.ts +30 -0
  48. package/dist/graphql/content-client.d.ts +66 -0
  49. package/dist/graphql/foir-request.d.ts +47 -0
  50. package/dist/hooks/useAutoResize.d.ts +22 -0
  51. package/dist/hooks/useEditor.d.ts +16 -0
  52. package/dist/index.d.ts +10 -394
  53. package/dist/media/BlurhashCanvas.d.ts +10 -0
  54. package/dist/media/ProgressiveMedia.d.ts +56 -0
  55. package/dist/media/index.d.ts +18 -0
  56. package/dist/media/media.d.ts +139 -0
  57. package/dist/media/screen-capture.d.ts +81 -0
  58. package/dist/media/useProgressiveLoad.d.ts +23 -0
  59. package/dist/media.js +102 -0
  60. package/dist/next/cookieAdapter.d.ts +26 -0
  61. package/dist/next/index.d.ts +15 -0
  62. package/dist/next/middleware.d.ts +49 -0
  63. package/dist/next/session.d.ts +53 -0
  64. package/dist/next.js +763 -78
  65. package/dist/protocol/constants.d.ts +6 -0
  66. package/dist/protocol/messages.d.ts +155 -0
  67. package/dist/protocol/validation.d.ts +8 -0
  68. package/dist/push/index.d.ts +14 -0
  69. package/dist/push/operations.d.ts +22 -0
  70. package/dist/push/web-push.d.ts +39 -0
  71. package/dist/push.js +892 -78
  72. package/dist/react/FoirFeedback.d.ts +62 -0
  73. package/dist/react/FoirProvider.d.ts +116 -0
  74. package/dist/react/OAuthButtons.d.ts +20 -0
  75. package/dist/react/SignIn.d.ts +22 -0
  76. package/dist/react/UserButton.d.ts +13 -0
  77. package/dist/react/feedback-notes.d.ts +101 -0
  78. package/dist/react/index.d.ts +25 -0
  79. package/dist/react/localStorageAdapter.d.ts +10 -0
  80. package/dist/react.js +1373 -91
  81. package/dist/{realtime.d.ts → realtime/index.d.ts} +35 -16
  82. package/dist/realtime.js +1 -1
  83. package/dist/server/callback-client.d.ts +92 -0
  84. package/dist/server/events-client.d.ts +279 -0
  85. package/dist/server/index.d.ts +12 -0
  86. package/dist/server/operation-types.d.ts +134 -0
  87. package/dist/server/require-scoped-token.d.ts +76 -0
  88. package/dist/server/server-client.d.ts +34 -0
  89. package/dist/server/types.d.ts +54 -0
  90. package/dist/server/verify-scoped-token.d.ts +100 -0
  91. package/dist/server/webhook-helpers.d.ts +36 -0
  92. package/dist/server.js +298 -0
  93. package/dist/transport/foir-http.d.ts +234 -0
  94. package/dist/transport/persisted-query.d.ts +68 -0
  95. package/dist/transport/retry.d.ts +61 -0
  96. package/dist/types/index.d.ts +124 -0
  97. package/package.json +35 -13
  98. package/dist/auth.d.ts +0 -382
  99. package/dist/chunk-ADO5FJNM.js +0 -30
  100. package/dist/client.d.ts +0 -135
  101. package/dist/content.d.ts +0 -96
  102. package/dist/media.d.ts +0 -234
  103. package/dist/next.d.ts +0 -178
  104. package/dist/push.d.ts +0 -109
  105. package/dist/react.d.ts +0 -319
  106. package/dist/server.d.ts +0 -534
  107. package/dist/shared-DkWlEd2Z.d.ts +0 -18
package/dist/auth.d.ts DELETED
@@ -1,382 +0,0 @@
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
- /**
306
- * Foir-hosted first-party sessions, from the browser — the model for a
307
- * backend-less SPA (Vite, CRA, a static site) that wants no tokens in JS.
308
- *
309
- * The sibling `fetchHostedSession` in ./hosted does the same exchange from a
310
- * SERVER: it reads the cookie off an incoming request and forwards it by hand.
311
- * A browser cannot set a `Cookie` header, so that function is unusable from an
312
- * SPA by construction. This one lets the browser send the cookie the only way it
313
- * can — `credentials: 'include'` — and keeps the resulting bearer in memory.
314
- *
315
- * How the pieces divide:
316
- *
317
- * cookie — long-lived (30d), HttpOnly, first-party on your registrable
318
- * domain, set by Foir when hosted login finalizes. JS cannot read
319
- * it, so XSS cannot exfiltrate it.
320
- * bearer — 15 minutes, held in a closure here. Never written to
321
- * localStorage/sessionStorage/IndexedDB, never in a cookie of ours.
322
- *
323
- * There is no refresh token in this flow. Re-exchanging the cookie IS the
324
- * refresh, which is why nothing here needs rotation or reuse-detection: the
325
- * durable credential is an opaque server-side session handle, revocable at any
326
- * time from the admin panel or `signOut()`.
327
- *
328
- * REQUIRES a verified custom login domain that shares a registrable domain with
329
- * your app (app.acme.com + login.acme.com). That is what makes the cookie
330
- * first-party and lets `SameSite=Lax` send it. The same endpoints exist on
331
- * api.foir.dev but a browser cannot reach them there — the cookie would be
332
- * cross-site, and that CORS surface deliberately refuses credentials.
333
- */
334
- interface FoirSessionConfig {
335
- /**
336
- * Your verified custom login domain, e.g. `https://login.acme.com`. Must share
337
- * a registrable domain with the app calling it.
338
- */
339
- loginOrigin: string;
340
- /** Session-exchange path. Default `/session/token`. */
341
- sessionPath?: string;
342
- /** Logout path. Default `/session/logout`. */
343
- logoutPath?: string;
344
- /** Seconds before expiry to re-exchange. Default 60. */
345
- refreshSkewSeconds?: number;
346
- /**
347
- * Called when the session goes away — the cookie expired, was revoked, or
348
- * `signOut()` ran. Use it to redirect to `signInUrl()`.
349
- */
350
- onSignOut?: () => void;
351
- }
352
- /** The identity behind the current session. */
353
- interface FoirSessionUser {
354
- customerId: string;
355
- email: string;
356
- }
357
- interface FoirSessionClient {
358
- /**
359
- * The current access token, exchanging or re-exchanging the cookie as needed.
360
- * Null when there is no session. Concurrent callers share one in-flight
361
- * exchange. Call this before each API request — do not cache the result.
362
- */
363
- getToken(): Promise<string | null>;
364
- /** The signed-in customer, or null. Exchanges if the session isn't loaded yet. */
365
- getUser(): Promise<FoirSessionUser | null>;
366
- /** Revoke the session server-side and clear the cookie. Idempotent. */
367
- signOut(): Promise<void>;
368
- /** Where to send the browser to sign in. */
369
- signInUrl(returnTo?: string): string;
370
- /** Observe session changes. Returns an unsubscribe function. */
371
- subscribe(listener: (user: FoirSessionUser | null) => void): () => void;
372
- /** Cancel the refresh timer. Call on unmount. */
373
- destroy(): void;
374
- }
375
- /**
376
- * Create a session client. Safe to call during SSR — it does nothing until a
377
- * method is invoked, and `getToken()` on the server returns null rather than
378
- * throwing (there is no cookie jar to draw on).
379
- */
380
- declare function createFoirSessionClient(config: FoirSessionConfig): FoirSessionClient;
381
-
382
- export { type AuthProviderPublic, AuthProvidersDocument, type CustomerAuthResult, CustomerLoginDocument, CustomerLoginOTPDocument, CustomerLoginWithProviderDocument, CustomerProviderCallbackDocument, CustomerProviderVerifyOTPDocument, CustomerRefreshTokenDocument, CustomerRegisterDocument, CustomerRequestOTPDocument, type FoirAuthTokens, type FoirCustomer, type FoirSessionClient, type FoirSessionConfig, type FoirSessionUser, type FoirUser, type HostedLoginConfig, type HostedSession, type ProviderCallbackInput, type ProviderLoginInput, type ProviderLoginResult, type ProviderOTPVerifyInput, type RequireAdminOptions, type RequireAuthOptions, type SessionAdapter, authedRequest, clearSession, createFoirSessionClient, customerLogin, customerLoginOTP, customerLoginWithProvider, customerProviderCallback, customerProviderVerifyOTP, customerRefreshToken, customerRegister, customerRequestOTP, fetchHostedSession, getAuthProviders, getSessionCustomer, getSessionToken, hostedLoginUrl, loginWithOTP, loginWithPassword, refreshSession, registerWithPassword, requireAdmin, requireAuth, saveSession };
@@ -1,30 +0,0 @@
1
- // src/codegen/shared.ts
2
- import { isUnionType } from "graphql";
3
- var DEFAULT_UNIONS = ["Block"];
4
- var DEFAULT_GRAPHQL_IMPORT = "./graphql";
5
- var DEFAULT_SDK_IMPORT = "@foir/sdk/content";
6
- function collectBlockMembers(schema, unionNames) {
7
- const members = /* @__PURE__ */ new Set();
8
- const missing = [];
9
- for (const name of unionNames) {
10
- const type = schema.getType(name);
11
- if (!type || !isUnionType(type)) {
12
- missing.push(name);
13
- continue;
14
- }
15
- for (const member of type.getTypes()) members.add(member.name);
16
- }
17
- if (members.size === 0) {
18
- throw new Error(
19
- `[foir codegen] no union members found. Looked for union(s): ${unionNames.join(", ")}` + (missing.length ? ` (not found or not a union: ${missing.join(", ")})` : "") + `. Run \`foir push\` and confirm the block union name.`
20
- );
21
- }
22
- return [...members].sort();
23
- }
24
-
25
- export {
26
- DEFAULT_UNIONS,
27
- DEFAULT_GRAPHQL_IMPORT,
28
- DEFAULT_SDK_IMPORT,
29
- collectBlockMembers
30
- };
package/dist/client.d.ts DELETED
@@ -1,135 +0,0 @@
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
- * Returns true when `FOIR_PREVIEW=true` is set in the environment.
30
- *
31
- * Preview is selected at the environment level, not per-request: load a
32
- * preview env file that sets `FOIR_PREVIEW=true` + a `sk_…`
33
- * `PLATFORM_PREVIEW_API_KEY` with `drafts:read` instead of the default env.
34
- * The site-wide mode keeps draft semantics consistent — every loader sees
35
- * the same preview/published view of the world. Intended for non-production
36
- * surfaces only.
37
- */
38
- declare function isFoirPreview(env: FoirEnv): boolean;
39
- /** Default Foir CDN origin used to absolutise relative media URLs. */
40
- declare const FOIR_CDN_BASE = "https://cdn.foir.dev/";
41
- /**
42
- * Foir returns `hlsManifestUrl` as a relative path while every other media
43
- * URL is absolute. Prefix relative paths with the CDN host so the browser
44
- * doesn't request them from the consumer's own origin. Already-absolute URLs
45
- * pass through untouched. `cdnBase` is overridable for non-default CDN hosts.
46
- */
47
- declare function absolutiseFoirMediaUrl(url: string | null | undefined, cdnBase?: string): string | undefined;
48
- interface FoirGraphQLErrorItem {
49
- message: string;
50
- path?: Array<string | number>;
51
- }
52
- declare class FoirRequestError extends Error {
53
- /** HTTP status code, when the request failed at the HTTP layer. */
54
- readonly status?: number;
55
- /** GraphQL errors, when the request failed with a no-data error envelope. */
56
- readonly graphQLErrors?: ReadonlyArray<FoirGraphQLErrorItem>;
57
- readonly cause?: unknown;
58
- constructor(message: string, options?: {
59
- cause?: unknown;
60
- status?: number;
61
- graphQLErrors?: ReadonlyArray<FoirGraphQLErrorItem>;
62
- });
63
- }
64
- /**
65
- * Execute a typed GraphQL document against the Foir platform.
66
- *
67
- * Throws `FoirRequestError` on HTTP failure or GraphQL errors so the caller
68
- * can decide whether to rethrow or fall back to local defaults. GraphQL can
69
- * return partial data alongside errors; when data is present the errors are
70
- * logged and the data returned (callers handle nulls), and we only throw when
71
- * there's no data at all.
72
- */
73
- interface FoirRequestOptions {
74
- /**
75
- * Customer bearer token. api-public still needs the `x-api-key` to resolve
76
- * the project; the bearer adds the customer identity for self-scoped reads
77
- * (e.g. `myProfile`). Used by `@foir/sdk/auth`'s post-login profile fetch.
78
- */
79
- bearerToken?: string;
80
- }
81
- declare function foirRequest<TData, TVariables>(env: FoirEnv, document: TypedDocumentNode<TData, TVariables>, variables?: TVariables, options?: FoirRequestOptions): Promise<TData>;
82
-
83
- /**
84
- * Session-bound content client — forwards the customer bearer on every read
85
- * when one is available, so auth/segment-targeted variants and customer-scoped
86
- * records resolve out of the box, with no per-query wiring to forget.
87
- *
88
- * Resolution keys off the request's principal (see the platform's two-gate
89
- * model): the `x-api-key` alone resolves the *anonymous baseline*
90
- * (`context.authStatus = ""`); adding the customer bearer resolves the request
91
- * as that customer (`context.authStatus = "authenticated"`, `customer_id` set).
92
- *
93
- * Caching: an api-key-only read is identical for every anonymous visitor and is
94
- * shared-cacheable; a bearer-bearing read resolves per-customer and is not.
95
- * Because the bearer only exists once a customer signs in, anonymous traffic
96
- * keeps hitting the shared-cacheable baseline — only signed-in reads become
97
- * per-customer. Bind this client wherever content is personalized (for most
98
- * apps, everywhere the customer may be signed in) and use plain `foirRequest`
99
- * for reads that must stay anonymous regardless of session.
100
- */
101
-
102
- /**
103
- * Supplies the current customer bearer. Sync or async so consumers can read a
104
- * cookie session (Hydrogen/Remix), a KV store, an in-memory value, etc. Returns
105
- * the token when signed in, or `null`/`undefined` when signed out.
106
- */
107
- type FoirTokenProvider = () => string | null | undefined | Promise<string | null | undefined>;
108
- interface FoirContentClientConfig {
109
- env: FoirEnv;
110
- /**
111
- * Resolves the current customer bearer before every request. When it yields a
112
- * token the token is forwarded, so `authStatus`/segment targeting and
113
- * customer-scoped records resolve as that customer; when it yields
114
- * null/undefined the read hits the anonymous baseline. Omit for a client that
115
- * is always anonymous (equivalent to calling `foirRequest` directly).
116
- */
117
- getToken?: FoirTokenProvider;
118
- }
119
- interface FoirContentClient {
120
- /**
121
- * Run a typed document, forwarding the bound customer bearer when available.
122
- * An explicit `options.bearerToken` still wins, so a single call can override
123
- * the bound token (or force anonymous by passing `undefined` — the bound
124
- * token only fills in when `options.bearerToken` is not supplied).
125
- */
126
- request<TData, TVariables>(document: TypedDocumentNode<TData, TVariables>, variables?: TVariables, options?: FoirRequestOptions): Promise<TData>;
127
- }
128
- /**
129
- * Create a {@link FoirContentClient} bound to an env + token source. Every
130
- * `request` forwards the customer bearer when `getToken` yields one, upgrading
131
- * that read from the anonymous baseline to the signed-in customer.
132
- */
133
- declare function createFoirContentClient(config: FoirContentClientConfig): FoirContentClient;
134
-
135
- export { FOIR_CDN_BASE, type FoirContentClient, type FoirContentClientConfig, type FoirEnv, FoirRequestError, type FoirRequestOptions, type FoirTokenProvider, absolutiseFoirMediaUrl, createFoirContentClient, foirRequest, isFoirPreview };
package/dist/content.d.ts DELETED
@@ -1,96 +0,0 @@
1
- import { ReactNode, JSX } from 'react';
2
- import * as react_jsx_runtime from 'react/jsx-runtime';
3
-
4
- /**
5
- * createContentRenderer — the generic content-dispatch primitive.
6
- *
7
- * It does NOT know any concrete block types. Given a registry that maps each
8
- * block `__typename` to a component, it renders a `flexible` field's block
9
- * array: looks each block up by `__typename`, renders unknown types as null,
10
- * keys by the block `_id`, assigns LCP `priority` to the first block that
11
- * actually renders, and threads a consumer-defined `Ctx` to every component.
12
- *
13
- * The "switch" is a typed object lookup. Exhaustiveness is enforced where the
14
- * registry is BUILT — against the exhaustive `BlockRegistry` type the codegen
15
- * plugin (EID-92) generates per project, so omitting a block type is a compile
16
- * error there, not a runtime surprise here. The consumer can supply different
17
- * registries per surface (e.g. web vs email).
18
- */
19
-
20
- /** Minimal shape every block in a `flexible` field carries. */
21
- interface BlockLike {
22
- __typename: string;
23
- _id?: string | null;
24
- }
25
- /** Props a block component receives from the content renderer. */
26
- interface BlockComponentProps<TBlock, TCtx = unknown> {
27
- block: TBlock;
28
- /** Consumer-defined render context (host product, locale, etc.). */
29
- ctx: TCtx;
30
- /** True only for the first block that renders — the LCP candidate. */
31
- priority: boolean;
32
- }
33
- /** A component that renders one block type. */
34
- type BlockComponent<TBlock, TCtx = unknown> = (props: BlockComponentProps<TBlock, TCtx>) => ReactNode;
35
- /**
36
- * A registry mapping `__typename` → block component. In practice this is the
37
- * exhaustive `BlockRegistry` type the codegen plugin emits for the project;
38
- * here it's the structural lower bound the renderer needs.
39
- */
40
- type BlockRegistry<TCtx = unknown> = Record<string, BlockComponent<any, TCtx>>;
41
- interface ContentRendererProps<TCtx> {
42
- blocks: readonly BlockLike[] | null | undefined;
43
- /** Consumer-defined context passed to every block component. */
44
- ctx: TCtx;
45
- }
46
- /**
47
- * Build a `<ContentRenderer>` bound to a block registry. Returns a component
48
- * that takes the `flexible` field's `blocks` array plus a `ctx`.
49
- */
50
- declare function createContentRenderer<TCtx = unknown>(registry: BlockRegistry<TCtx>): (props: ContentRendererProps<TCtx>) => ReactNode;
51
-
52
- /** A resolved typography token from the project's design tokens. */
53
- interface TypographyToken {
54
- /** Token key referenced by a Lexical node's `style`. */
55
- name: string;
56
- /** Rendered HTML element (paragraph / h1–h6 / blockquote). */
57
- tag?: string;
58
- value: {
59
- fontFamily: string[];
60
- fontSize: string | number;
61
- fontWeight: string | number;
62
- lineHeight: string | number;
63
- letterSpacing: string | number;
64
- textTransform?: string;
65
- };
66
- }
67
- /**
68
- * Provide the project's resolved typography tokens to every nested
69
- * `<RichTextRenderer>` so callers don't thread them through each usage. A
70
- * `tokens` prop on the renderer still takes precedence.
71
- */
72
- declare function RichTextTypographyProvider({ tokens, children, }: {
73
- tokens: TypographyToken[];
74
- children: ReactNode;
75
- }): react_jsx_runtime.JSX.Element;
76
- /** Read the injected typography tokens (null when no provider is mounted). */
77
- declare function useRichTextTypography(): TypographyToken[] | null;
78
- interface RichtextValueLike {
79
- html?: string | null;
80
- json?: unknown;
81
- }
82
- interface RichTextRendererProps {
83
- value: RichtextValueLike | null | undefined;
84
- className?: string;
85
- /**
86
- * Resolved typography tokens. Overrides any provided via
87
- * `<RichTextTypographyProvider>`. When neither is set, paragraphs render
88
- * with `fallbackTag` and no inline typography.
89
- */
90
- tokens?: TypographyToken[];
91
- /** Tag used for any paragraph with no token style and no Lexical tag. */
92
- fallbackTag?: keyof JSX.IntrinsicElements;
93
- }
94
- declare function RichTextRenderer({ value, className, tokens, fallbackTag, }: RichTextRendererProps): react_jsx_runtime.JSX.Element | null;
95
-
96
- export { type BlockComponent, type BlockComponentProps, type BlockLike, type BlockRegistry, type ContentRendererProps, RichTextRenderer, type RichTextRendererProps, RichTextTypographyProvider, type TypographyToken, createContentRenderer, useRichTextTypography };