@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.
- package/CHANGELOG.md +1126 -0
- package/README.md +94 -0
- package/dist/auth/auth.d.ts +243 -0
- package/dist/auth/hosted.d.ts +40 -0
- package/dist/auth/index.d.ts +21 -0
- package/dist/auth/operations.d.ts +144 -0
- package/dist/auth/ops.d.ts +99 -0
- package/dist/auth/session-client.d.ts +76 -0
- package/dist/auth-session.js +137 -0
- package/dist/auth.js +973 -92
- package/dist/chunk-IGNLWT3H.js +35 -0
- package/dist/chunk-OHYVKTGB.js +45 -0
- package/dist/chunk-TAL5H6VA.js +39 -0
- package/dist/client/platform-client.d.ts +29 -0
- package/dist/client.js +275 -37
- package/dist/codegen/block-registry.d.ts +13 -23
- package/dist/codegen/block-registry.js +3 -31
- package/dist/codegen/block-scaffold.d.ts +12 -25
- package/dist/codegen/block-scaffold.js +3 -41
- package/dist/codegen/index.d.ts +12 -61
- package/dist/codegen/index.js +7 -11
- package/dist/codegen/item-registry.d.ts +28 -0
- package/dist/codegen/item-registry.js +7 -0
- package/dist/codegen/item-scaffold.d.ts +29 -0
- package/dist/codegen/item-scaffold.js +7 -0
- package/dist/codegen/preset.d.ts +67 -0
- package/dist/codegen/shared.d.ts +36 -0
- package/dist/components/EditorProvider.d.ts +36 -0
- package/dist/content/content-renderer.d.ts +113 -0
- package/dist/content/index.d.ts +18 -0
- package/dist/content/richtext.d.ts +118 -0
- package/dist/content.js +227 -80
- package/dist/data/builtins.d.ts +506 -0
- package/dist/data/client.d.ts +166 -0
- package/dist/data/document.d.ts +251 -0
- package/dist/data/index.d.ts +73 -0
- package/dist/data/manifest.d.ts +424 -0
- package/dist/data/schema.d.ts +313 -0
- package/dist/data/selection.d.ts +524 -0
- package/dist/data/subjects.d.ts +221 -0
- package/dist/data/subscription-document.d.ts +75 -0
- package/dist/data/subscriptions.d.ts +181 -0
- package/dist/data/transport.d.ts +325 -0
- package/dist/data/ws-transport.d.ts +197 -0
- package/dist/data.js +1683 -0
- package/dist/graphql/cdn-route.d.ts +26 -0
- package/dist/graphql/client.d.ts +30 -0
- package/dist/graphql/content-client.d.ts +66 -0
- package/dist/graphql/foir-request.d.ts +47 -0
- package/dist/hooks/useAutoResize.d.ts +22 -0
- package/dist/hooks/useEditor.d.ts +16 -0
- package/dist/index.d.ts +10 -394
- package/dist/media/BlurhashCanvas.d.ts +10 -0
- package/dist/media/ProgressiveMedia.d.ts +56 -0
- package/dist/media/index.d.ts +18 -0
- package/dist/media/media.d.ts +139 -0
- package/dist/media/screen-capture.d.ts +81 -0
- package/dist/media/useProgressiveLoad.d.ts +23 -0
- package/dist/media.js +102 -0
- package/dist/next/cookieAdapter.d.ts +26 -0
- package/dist/next/index.d.ts +15 -0
- package/dist/next/middleware.d.ts +49 -0
- package/dist/next/session.d.ts +53 -0
- package/dist/next.js +763 -78
- package/dist/protocol/constants.d.ts +6 -0
- package/dist/protocol/messages.d.ts +155 -0
- package/dist/protocol/validation.d.ts +8 -0
- package/dist/push/index.d.ts +14 -0
- package/dist/push/operations.d.ts +22 -0
- package/dist/push/web-push.d.ts +39 -0
- package/dist/push.js +892 -78
- package/dist/react/FoirFeedback.d.ts +62 -0
- package/dist/react/FoirProvider.d.ts +116 -0
- package/dist/react/OAuthButtons.d.ts +20 -0
- package/dist/react/SignIn.d.ts +22 -0
- package/dist/react/UserButton.d.ts +13 -0
- package/dist/react/feedback-notes.d.ts +101 -0
- package/dist/react/index.d.ts +25 -0
- package/dist/react/localStorageAdapter.d.ts +10 -0
- package/dist/react.js +1373 -91
- package/dist/{realtime.d.ts → realtime/index.d.ts} +35 -16
- package/dist/realtime.js +1 -1
- package/dist/server/callback-client.d.ts +92 -0
- package/dist/server/events-client.d.ts +279 -0
- package/dist/server/index.d.ts +12 -0
- package/dist/server/operation-types.d.ts +134 -0
- package/dist/server/require-scoped-token.d.ts +76 -0
- package/dist/server/server-client.d.ts +34 -0
- package/dist/server/types.d.ts +54 -0
- package/dist/server/verify-scoped-token.d.ts +100 -0
- package/dist/server/webhook-helpers.d.ts +36 -0
- package/dist/server.js +298 -0
- package/dist/transport/foir-http.d.ts +234 -0
- package/dist/transport/persisted-query.d.ts +68 -0
- package/dist/transport/retry.d.ts +61 -0
- package/dist/types/index.d.ts +124 -0
- package/package.json +35 -13
- package/dist/auth.d.ts +0 -382
- package/dist/chunk-ADO5FJNM.js +0 -30
- package/dist/client.d.ts +0 -135
- package/dist/content.d.ts +0 -96
- package/dist/media.d.ts +0 -234
- package/dist/next.d.ts +0 -178
- package/dist/push.d.ts +0 -109
- package/dist/react.d.ts +0 -319
- package/dist/server.d.ts +0 -534
- package/dist/shared-DkWlEd2Z.d.ts +0 -18
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
2
|
+
import { type FoirEnv } from '../transport/foir-http';
|
|
3
|
+
/**
|
|
4
|
+
* The shared read lane, for `@foir/sdk/client`.
|
|
5
|
+
*
|
|
6
|
+
* The mechanics — the URL, the hash, the handshake codes — moved to
|
|
7
|
+
* `../transport/persisted-query`, which has no `graphql` import, so
|
|
8
|
+
* `@foir/sdk/data` can build the same requests without dragging the parser into
|
|
9
|
+
* a storefront bundle. They are re-exported unchanged; this module's public
|
|
10
|
+
* surface is exactly what it always was. What stayed here is the part that
|
|
11
|
+
* needs a parsed document: `print`, and the eligibility rule that reads the
|
|
12
|
+
* printed text.
|
|
13
|
+
*/
|
|
14
|
+
export { buildCdnUrl, documentHash, hasFoirErrorCode, NOT_SHAREABLE, PERSISTED_QUERY_NOT_FOUND, persistedQueryExtension, } from '../transport/persisted-query';
|
|
15
|
+
/**
|
|
16
|
+
* Whether this read can be served by the shared endpoint.
|
|
17
|
+
*
|
|
18
|
+
* These mirror the conditions the server refuses on, so a request that would be
|
|
19
|
+
* turned away is not sent there in the first place. The server is still the
|
|
20
|
+
* authority — it refuses rather than falling back, and `foirRequest` retries on
|
|
21
|
+
* `/graphql` when it does — but every condition checked here is one round trip
|
|
22
|
+
* saved.
|
|
23
|
+
*/
|
|
24
|
+
export declare function isCdnEligible(env: FoirEnv, documentText: string, bearerToken?: string): boolean;
|
|
25
|
+
/** Print a document once, so eligibility and the URL agree on the same text. */
|
|
26
|
+
export declare function printDocument<TData, TVariables>(document: TypedDocumentNode<TData, TVariables>): string;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@foir/sdk/client` — client-agnostic GraphQL transport for SSR/edge loaders.
|
|
3
|
+
*
|
|
4
|
+
* A thin auth transport, not a GraphQL client: it carries the Foir-specific
|
|
5
|
+
* `x-api-key` + preview schema channel and runs typed documents via `fetch`.
|
|
6
|
+
* Consumers that bring their own GraphQL client (Apollo/urql/react-query) use
|
|
7
|
+
* the generated `TypedDocumentNode`s directly and replicate those two headers.
|
|
8
|
+
*/
|
|
9
|
+
export { foirRequest, isFoirPreview, absolutiseFoirMediaUrl, FOIR_CDN_BASE, FoirRequestError, } from './foir-request';
|
|
10
|
+
export type { FoirEnv, FoirRequestOptions } from './foir-request';
|
|
11
|
+
/**
|
|
12
|
+
* Failure classification. Branch on these rather than on `err.message`: the
|
|
13
|
+
* codes are a stable contract, the wording is not.
|
|
14
|
+
*
|
|
15
|
+
* The one worth knowing about is `isFoirRateLimited`. It is the only 4xx that
|
|
16
|
+
* clears on its own, and a client that lumps it in with the rest fails every
|
|
17
|
+
* read for as long as the key stays saturated — which looks, from the outside,
|
|
18
|
+
* exactly like a site with no content.
|
|
19
|
+
*/
|
|
20
|
+
export { isFoirRateLimited, isFoirUnauthenticated, isFoirForbidden, isFoirNotFound, readFoirRateLimit, } from './foir-request';
|
|
21
|
+
export type { FoirErrorCode, FoirErrorExtensions, FoirGraphQLErrorItem, FoirRateLimitSnapshot, } from './foir-request';
|
|
22
|
+
/**
|
|
23
|
+
* Retry. `createFoirContentClient` applies this for you; these are exported for
|
|
24
|
+
* a caller running its own loop, so both use one definition of "worth retrying"
|
|
25
|
+
* rather than two that disagree about the 429.
|
|
26
|
+
*/
|
|
27
|
+
export { withFoirRetry, foirRetryDelayMs } from './foir-request';
|
|
28
|
+
export type { FoirRetryPolicy } from './foir-request';
|
|
29
|
+
export { createFoirContentClient } from './content-client';
|
|
30
|
+
export type { FoirContentClient, FoirContentClientConfig, FoirTokenProvider, } from './content-client';
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session-bound content client — forwards the customer bearer on every read
|
|
3
|
+
* when one is available, so auth/segment-targeted variants and customer-scoped
|
|
4
|
+
* records resolve out of the box, with no per-query wiring to forget.
|
|
5
|
+
*
|
|
6
|
+
* Resolution keys off the request's principal (see the platform's two-gate
|
|
7
|
+
* model): the `x-api-key` alone resolves the *anonymous baseline*
|
|
8
|
+
* (`context.authStatus = ""`); adding the customer bearer resolves the request
|
|
9
|
+
* as that customer (`context.authStatus = "authenticated"`, `customer_id` set).
|
|
10
|
+
*
|
|
11
|
+
* Caching: an api-key-only read is identical for every anonymous visitor and is
|
|
12
|
+
* shared-cacheable; a bearer-bearing read resolves per-customer and is not.
|
|
13
|
+
* Because the bearer only exists once a customer signs in, anonymous traffic
|
|
14
|
+
* keeps hitting the shared-cacheable baseline — only signed-in reads become
|
|
15
|
+
* per-customer. Bind this client wherever content is personalized (for most
|
|
16
|
+
* apps, everywhere the customer may be signed in) and use plain `foirRequest`
|
|
17
|
+
* for reads that must stay anonymous regardless of session.
|
|
18
|
+
*/
|
|
19
|
+
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
20
|
+
import type { FoirEnv, FoirRequestOptions } from './foir-request';
|
|
21
|
+
import { type FoirRetryPolicy } from '../transport/retry';
|
|
22
|
+
import type { FoirRateLimitSnapshot } from '../transport/foir-http';
|
|
23
|
+
export type { FoirTokenProvider } from '../transport/foir-http';
|
|
24
|
+
import type { FoirTokenProvider } from '../transport/foir-http';
|
|
25
|
+
export interface FoirContentClientConfig {
|
|
26
|
+
env: FoirEnv;
|
|
27
|
+
/**
|
|
28
|
+
* Resolves the current customer bearer before every request. When it yields a
|
|
29
|
+
* token the token is forwarded, so `authStatus`/segment targeting and
|
|
30
|
+
* customer-scoped records resolve as that customer; when it yields
|
|
31
|
+
* null/undefined the read hits the anonymous baseline. Omit for a client that
|
|
32
|
+
* is always anonymous (equivalent to calling `foirRequest` directly).
|
|
33
|
+
*/
|
|
34
|
+
getToken?: FoirTokenProvider;
|
|
35
|
+
/**
|
|
36
|
+
* Retry policy for transient failures — no response, 5xx, and 429.
|
|
37
|
+
*
|
|
38
|
+
* ON BY DEFAULT, which is the point of it being here. Retry that has to be
|
|
39
|
+
* opted into is retry each integrator writes for themselves, and the one
|
|
40
|
+
* detail they get wrong is the 429: it looks like the permanent 4xx family it
|
|
41
|
+
* sits in, and it is the only failure in that family that clears on its own.
|
|
42
|
+
* Pass `{ attempts: 1 }` to turn it off.
|
|
43
|
+
*/
|
|
44
|
+
retry?: FoirRetryPolicy;
|
|
45
|
+
/**
|
|
46
|
+
* Called with the `X-RateLimit-*` headers of every response. Wire it to your
|
|
47
|
+
* logger and you will see a key approaching its ceiling instead of finding
|
|
48
|
+
* out when it hits one.
|
|
49
|
+
*/
|
|
50
|
+
onRateLimit?: (snapshot: FoirRateLimitSnapshot | undefined) => void;
|
|
51
|
+
}
|
|
52
|
+
export interface FoirContentClient {
|
|
53
|
+
/**
|
|
54
|
+
* Run a typed document, forwarding the bound customer bearer when available.
|
|
55
|
+
* An explicit `options.bearerToken` still wins, so a single call can override
|
|
56
|
+
* the bound token (or force anonymous by passing `undefined` — the bound
|
|
57
|
+
* token only fills in when `options.bearerToken` is not supplied).
|
|
58
|
+
*/
|
|
59
|
+
request<TData, TVariables>(document: TypedDocumentNode<TData, TVariables>, variables?: TVariables, options?: FoirRequestOptions): Promise<TData>;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Create a {@link FoirContentClient} bound to an env + token source. Every
|
|
63
|
+
* `request` forwards the customer bearer when `getToken` yields one, upgrading
|
|
64
|
+
* that read from the anonymous baseline to the signed-in customer.
|
|
65
|
+
*/
|
|
66
|
+
export declare function createFoirContentClient(config: FoirContentClientConfig): FoirContentClient;
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
* The transport concerns themselves now live in `../transport/foir-http`, which
|
|
20
|
+
* has no `graphql` import, so `@foir/sdk/data` can reuse them without dragging
|
|
21
|
+
* `graphql` into a storefront bundle. Only `print` stayed here. Everything that
|
|
22
|
+
* module owns is re-exported below, unchanged, so this file's public surface is
|
|
23
|
+
* exactly what it always was.
|
|
24
|
+
*/
|
|
25
|
+
import type { TypedDocumentNode } from '@graphql-typed-document-node/core';
|
|
26
|
+
import { type FoirEnv, type FoirRequestOptions } from '../transport/foir-http';
|
|
27
|
+
export { FoirRequestError, isFoirPreview, isFoirRateLimited, isFoirUnauthenticated, isFoirForbidden, isFoirNotFound, readFoirRateLimit, type FoirEnv, type FoirErrorCode, type FoirErrorExtensions, type FoirGraphQLErrorItem, type FoirRateLimitSnapshot, type FoirRequestOptions, } from '../transport/foir-http';
|
|
28
|
+
export { withFoirRetry, foirRetryDelayMs, type FoirRetryPolicy, } from '../transport/retry';
|
|
29
|
+
/** Default Foir CDN origin used to absolutise relative media URLs. */
|
|
30
|
+
export declare const FOIR_CDN_BASE = "https://cdn.foir.dev/";
|
|
31
|
+
/**
|
|
32
|
+
* Foir returns `hlsManifestUrl` as a relative path while every other media
|
|
33
|
+
* URL is absolute. Prefix relative paths with the CDN host so the browser
|
|
34
|
+
* doesn't request them from the consumer's own origin. Already-absolute URLs
|
|
35
|
+
* pass through untouched. `cdnBase` is overridable for non-default CDN hosts.
|
|
36
|
+
*/
|
|
37
|
+
export declare function absolutiseFoirMediaUrl(url: string | null | undefined, cdnBase?: string): string | undefined;
|
|
38
|
+
/**
|
|
39
|
+
* Execute a typed GraphQL document against the Foir platform.
|
|
40
|
+
*
|
|
41
|
+
* Throws `FoirRequestError` on HTTP failure or GraphQL errors so the caller
|
|
42
|
+
* can decide whether to rethrow or fall back to local defaults. GraphQL can
|
|
43
|
+
* return partial data alongside errors; when data is present the errors are
|
|
44
|
+
* logged and the data returned (callers handle nulls), and we only throw when
|
|
45
|
+
* there's no data at all.
|
|
46
|
+
*/
|
|
47
|
+
export declare function foirRequest<TData, TVariables>(env: FoirEnv, document: TypedDocumentNode<TData, TVariables>, variables?: TVariables, options?: FoirRequestOptions): Promise<TData>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface UseAutoResizeOptions {
|
|
2
|
+
/** Minimum height to report (prevents too-small iframes). @default 400 */
|
|
3
|
+
minHeight?: number;
|
|
4
|
+
/** Debounce delay in milliseconds. @default 100 */
|
|
5
|
+
debounce?: number;
|
|
6
|
+
/** Whether auto-resize is enabled. @default true */
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Automatically resize the host iframe based on content height.
|
|
11
|
+
*
|
|
12
|
+
* @returns A callback ref to attach to your root container element.
|
|
13
|
+
*
|
|
14
|
+
* @example
|
|
15
|
+
* ```tsx
|
|
16
|
+
* function MyEditor() {
|
|
17
|
+
* const containerRef = useAutoResize({ minHeight: 600 });
|
|
18
|
+
* return <div ref={containerRef}>...</div>;
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function useAutoResize(options?: UseAutoResizeOptions): (node: HTMLDivElement | null) => void;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { EditorContextValue } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Access the Foir editor context.
|
|
4
|
+
*
|
|
5
|
+
* Must be used inside an `<EditorProvider>`.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* function MyEditor() {
|
|
10
|
+
* const { isReady, init, client, updateField, setDirty } = useEditor();
|
|
11
|
+
* if (!isReady) return <p>Loading...</p>;
|
|
12
|
+
* return <form>...</form>;
|
|
13
|
+
* }
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
export declare function useEditor(): EditorContextValue;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,394 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
metadata?: Record<string, unknown>;
|
|
12
|
-
modelKey: string;
|
|
13
|
-
recordId: string;
|
|
14
|
-
naturalKey?: string;
|
|
15
|
-
versionId: string | null;
|
|
16
|
-
variantKey: string | null;
|
|
17
|
-
locale: string | null;
|
|
18
|
-
schema: unknown;
|
|
19
|
-
mode: 'edit' | 'readonly';
|
|
20
|
-
theme: 'light' | 'dark';
|
|
21
|
-
/** Secret API key for public API access. */
|
|
22
|
-
apiKey: string;
|
|
23
|
-
/** Public API GraphQL endpoint URL (provided by host). */
|
|
24
|
-
apiUrl: string;
|
|
25
|
-
/** Config connection domain (e.g. my-store.myshopify.com) */
|
|
26
|
-
connectionDomain?: string;
|
|
27
|
-
/** How this editor is rendered in the admin UI. */
|
|
28
|
-
configMode?: 'editor' | 'sidebar';
|
|
29
|
-
/** Currently selected field keys (sidebar mode). */
|
|
30
|
-
selectedFieldKeys?: string[];
|
|
31
|
-
/** Available fields for selection (sidebar mode). */
|
|
32
|
-
selectableFields?: Array<{
|
|
33
|
-
key: string;
|
|
34
|
-
label: string;
|
|
35
|
-
type: string;
|
|
36
|
-
}>;
|
|
37
|
-
/** Locale context (sidebar mode). */
|
|
38
|
-
localeContext?: LocaleContext | null;
|
|
39
|
-
}
|
|
40
|
-
/** Locale context passed by the host for sidebar editors. */
|
|
41
|
-
interface LocaleContext {
|
|
42
|
-
currentLocale: string;
|
|
43
|
-
sourceLocale: string;
|
|
44
|
-
isTranslating: boolean;
|
|
45
|
-
locales: Array<{
|
|
46
|
-
code: string;
|
|
47
|
-
displayName: string;
|
|
48
|
-
isDefault: boolean;
|
|
49
|
-
}>;
|
|
50
|
-
}
|
|
51
|
-
/** Value exposed by the EditorProvider context. */
|
|
52
|
-
interface EditorContextValue {
|
|
53
|
-
/** Whether the editor has received init data from the host. */
|
|
54
|
-
isReady: boolean;
|
|
55
|
-
/** Initial data from the host (available after init). */
|
|
56
|
-
init: EditorInit | null;
|
|
57
|
-
/** Current host theme. */
|
|
58
|
-
theme: 'light' | 'dark';
|
|
59
|
-
/** Platform GraphQL client (available after init). */
|
|
60
|
-
client: PlatformClient;
|
|
61
|
-
/** Send complete form values to the host (full replacement). */
|
|
62
|
-
updateValues: (values: Record<string, unknown>) => void;
|
|
63
|
-
/** Send a single field update to the host. */
|
|
64
|
-
updateField: (path: string, value: unknown) => void;
|
|
65
|
-
/** Request the host to save the current values. */
|
|
66
|
-
requestSave: () => void;
|
|
67
|
-
/** Request the host to publish the current version. */
|
|
68
|
-
requestPublish: () => void;
|
|
69
|
-
/** Report iframe height for auto-resize. */
|
|
70
|
-
resize: (height: number) => void;
|
|
71
|
-
/** Report dirty state (unsaved changes). */
|
|
72
|
-
setDirty: (isDirty: boolean) => void;
|
|
73
|
-
/** Request the host to navigate to an admin path. */
|
|
74
|
-
requestNavigate: (path: string) => void;
|
|
75
|
-
/** Request the host to execute a platform operation. Returns the result.
|
|
76
|
-
* `mode` controls whether the platform waits for the operation to complete
|
|
77
|
-
* ('sync') or returns immediately after queueing ('async'). Defaults to 'sync'. */
|
|
78
|
-
requestOperation: (operationKey: string, input?: Record<string, unknown>, options?: {
|
|
79
|
-
mode?: 'sync' | 'async';
|
|
80
|
-
}) => Promise<{
|
|
81
|
-
success: boolean;
|
|
82
|
-
result?: unknown;
|
|
83
|
-
error?: {
|
|
84
|
-
code: string;
|
|
85
|
-
message: string;
|
|
86
|
-
};
|
|
87
|
-
}>;
|
|
88
|
-
/** Editor mode ('editor' or 'sidebar'). */
|
|
89
|
-
configMode: 'editor' | 'sidebar';
|
|
90
|
-
/** Currently selected field keys (sidebar mode). */
|
|
91
|
-
selectedFieldKeys: string[];
|
|
92
|
-
/** Available fields for selection (sidebar mode). */
|
|
93
|
-
selectableFields: Array<{
|
|
94
|
-
key: string;
|
|
95
|
-
label: string;
|
|
96
|
-
type: string;
|
|
97
|
-
}>;
|
|
98
|
-
/** Locale context (sidebar mode). */
|
|
99
|
-
localeContext: LocaleContext | null;
|
|
100
|
-
}
|
|
101
|
-
/** Options for creating a PlatformClient. */
|
|
102
|
-
interface PlatformClientOptions {
|
|
103
|
-
/** GraphQL endpoint URL. */
|
|
104
|
-
apiUrl: string;
|
|
105
|
-
/** API key for authentication. */
|
|
106
|
-
apiKey: string;
|
|
107
|
-
}
|
|
108
|
-
/** A minimal GraphQL error shape. */
|
|
109
|
-
interface GraphQLError {
|
|
110
|
-
message: string;
|
|
111
|
-
locations?: Array<{
|
|
112
|
-
line: number;
|
|
113
|
-
column: number;
|
|
114
|
-
}>;
|
|
115
|
-
path?: Array<string | number>;
|
|
116
|
-
extensions?: Record<string, unknown>;
|
|
117
|
-
}
|
|
118
|
-
/** Response shape from a GraphQL query/mutation. */
|
|
119
|
-
interface GraphQLResponse<T = Record<string, unknown>> {
|
|
120
|
-
data: T | null;
|
|
121
|
-
errors?: GraphQLError[];
|
|
122
|
-
}
|
|
123
|
-
/** Fetch-based GraphQL client for platform API calls. */
|
|
124
|
-
interface PlatformClient {
|
|
125
|
-
/** Execute a GraphQL query or mutation. */
|
|
126
|
-
query<T = Record<string, unknown>>(query: string, variables?: Record<string, unknown>): Promise<GraphQLResponse<T>>;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
interface EditorProviderProps {
|
|
130
|
-
children: ReactNode;
|
|
131
|
-
/**
|
|
132
|
-
* Parent window origin for postMessage validation.
|
|
133
|
-
* Must be an explicit origin (e.g., 'https://admin.example.com').
|
|
134
|
-
* Falls back to VITE_PARENT_ORIGIN or NEXT_PUBLIC_PARENT_ORIGIN env var.
|
|
135
|
-
*/
|
|
136
|
-
parentOrigin?: string;
|
|
137
|
-
/**
|
|
138
|
-
* Platform API URL for GraphQL requests.
|
|
139
|
-
* Falls back to VITE_API_URL or NEXT_PUBLIC_API_URL env var.
|
|
140
|
-
*/
|
|
141
|
-
apiUrl?: string;
|
|
142
|
-
onInit?: (init: EditorInit) => void;
|
|
143
|
-
onValuesChanged?: (values: Record<string, unknown>) => void;
|
|
144
|
-
onVariantChanged?: (variantKey: string, values: Record<string, unknown>) => void;
|
|
145
|
-
onSaveResult?: (success: boolean, error?: string, versionId?: string) => void;
|
|
146
|
-
onPublishResult?: (success: boolean, error?: string) => void;
|
|
147
|
-
onThemeChanged?: (theme: 'light' | 'dark') => void;
|
|
148
|
-
onSelectionChanged?: (keys: string[], fields: Array<{
|
|
149
|
-
key: string;
|
|
150
|
-
label: string;
|
|
151
|
-
type: string;
|
|
152
|
-
}>) => void;
|
|
153
|
-
onLocaleChanged?: (locale: LocaleContext) => void;
|
|
154
|
-
}
|
|
155
|
-
declare function EditorProvider({ children, parentOrigin: parentOriginProp, apiUrl: apiUrlProp, onInit, onValuesChanged, onVariantChanged, onSaveResult, onPublishResult, onThemeChanged, onSelectionChanged, onLocaleChanged, }: EditorProviderProps): react_jsx_runtime.JSX.Element;
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Access the Foir editor context.
|
|
159
|
-
*
|
|
160
|
-
* Must be used inside an `<EditorProvider>`.
|
|
161
|
-
*
|
|
162
|
-
* @example
|
|
163
|
-
* ```tsx
|
|
164
|
-
* function MyEditor() {
|
|
165
|
-
* const { isReady, init, client, updateField, setDirty } = useEditor();
|
|
166
|
-
* if (!isReady) return <p>Loading...</p>;
|
|
167
|
-
* return <form>...</form>;
|
|
168
|
-
* }
|
|
169
|
-
* ```
|
|
170
|
-
*/
|
|
171
|
-
declare function useEditor(): EditorContextValue;
|
|
172
|
-
|
|
173
|
-
interface UseAutoResizeOptions {
|
|
174
|
-
/** Minimum height to report (prevents too-small iframes). @default 400 */
|
|
175
|
-
minHeight?: number;
|
|
176
|
-
/** Debounce delay in milliseconds. @default 100 */
|
|
177
|
-
debounce?: number;
|
|
178
|
-
/** Whether auto-resize is enabled. @default true */
|
|
179
|
-
enabled?: boolean;
|
|
180
|
-
}
|
|
181
|
-
/**
|
|
182
|
-
* Automatically resize the host iframe based on content height.
|
|
183
|
-
*
|
|
184
|
-
* @returns A callback ref to attach to your root container element.
|
|
185
|
-
*
|
|
186
|
-
* @example
|
|
187
|
-
* ```tsx
|
|
188
|
-
* function MyEditor() {
|
|
189
|
-
* const containerRef = useAutoResize({ minHeight: 600 });
|
|
190
|
-
* return <div ref={containerRef}>...</div>;
|
|
191
|
-
* }
|
|
192
|
-
* ```
|
|
193
|
-
*/
|
|
194
|
-
declare function useAutoResize(options?: UseAutoResizeOptions): (node: HTMLDivElement | null) => void;
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Fetch-based GraphQL client for the EIDE platform API.
|
|
198
|
-
*
|
|
199
|
-
* Zero dependencies — uses the native Fetch API.
|
|
200
|
-
*/
|
|
201
|
-
|
|
202
|
-
/** Error thrown when a platform API request fails. */
|
|
203
|
-
declare class PlatformClientError extends Error {
|
|
204
|
-
status?: number | undefined;
|
|
205
|
-
response?: unknown | undefined;
|
|
206
|
-
constructor(message: string, status?: number | undefined, response?: unknown | undefined);
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Create a PlatformClient instance.
|
|
210
|
-
*
|
|
211
|
-
* @example
|
|
212
|
-
* ```ts
|
|
213
|
-
* const client = createPlatformClient({
|
|
214
|
-
* apiUrl: 'https://api.example.com/graphql',
|
|
215
|
-
* apiKey: 'sk_test_...',
|
|
216
|
-
* });
|
|
217
|
-
*
|
|
218
|
-
* const { data } = await client.query(
|
|
219
|
-
* `query GetProduct($id: ID!) { product(id: $id) { title } }`,
|
|
220
|
-
* { id: '123' }
|
|
221
|
-
* );
|
|
222
|
-
* ```
|
|
223
|
-
*/
|
|
224
|
-
declare function createPlatformClient(options: PlatformClientOptions): PlatformClient;
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* PostMessage protocol types between EIDE platform host and extension iframes.
|
|
228
|
-
*
|
|
229
|
-
* Inlined from the platform protocol to keep the SDK zero-dep.
|
|
230
|
-
*/
|
|
231
|
-
/**
|
|
232
|
-
* Messages sent FROM the platform host TO the iframe extension.
|
|
233
|
-
*/
|
|
234
|
-
type HostToEditorMessage = {
|
|
235
|
-
type: 'init';
|
|
236
|
-
payload: {
|
|
237
|
-
values: Record<string, unknown>;
|
|
238
|
-
metadata?: Record<string, unknown>;
|
|
239
|
-
modelKey: string;
|
|
240
|
-
recordId: string;
|
|
241
|
-
naturalKey?: string;
|
|
242
|
-
versionId: string | null;
|
|
243
|
-
variantKey: string | null;
|
|
244
|
-
locale: string | null;
|
|
245
|
-
schema: unknown;
|
|
246
|
-
mode: 'edit' | 'readonly';
|
|
247
|
-
theme: 'light' | 'dark';
|
|
248
|
-
apiKey: string;
|
|
249
|
-
apiUrl: string;
|
|
250
|
-
connectionDomain?: string;
|
|
251
|
-
configMode?: 'editor' | 'sidebar';
|
|
252
|
-
selectedFieldKeys?: string[];
|
|
253
|
-
selectableFields?: Array<{
|
|
254
|
-
key: string;
|
|
255
|
-
label: string;
|
|
256
|
-
type: string;
|
|
257
|
-
}>;
|
|
258
|
-
localeContext?: {
|
|
259
|
-
currentLocale: string;
|
|
260
|
-
sourceLocale: string;
|
|
261
|
-
isTranslating: boolean;
|
|
262
|
-
locales: Array<{
|
|
263
|
-
code: string;
|
|
264
|
-
displayName: string;
|
|
265
|
-
isDefault: boolean;
|
|
266
|
-
}>;
|
|
267
|
-
};
|
|
268
|
-
};
|
|
269
|
-
} | {
|
|
270
|
-
type: 'values-changed';
|
|
271
|
-
payload: {
|
|
272
|
-
values: Record<string, unknown>;
|
|
273
|
-
source: 'remote';
|
|
274
|
-
};
|
|
275
|
-
} | {
|
|
276
|
-
type: 'variant-changed';
|
|
277
|
-
payload: {
|
|
278
|
-
variantKey: string;
|
|
279
|
-
values: Record<string, unknown>;
|
|
280
|
-
};
|
|
281
|
-
} | {
|
|
282
|
-
type: 'save-result';
|
|
283
|
-
payload: {
|
|
284
|
-
success: boolean;
|
|
285
|
-
error?: string;
|
|
286
|
-
versionId?: string;
|
|
287
|
-
};
|
|
288
|
-
} | {
|
|
289
|
-
type: 'publish-result';
|
|
290
|
-
payload: {
|
|
291
|
-
success: boolean;
|
|
292
|
-
error?: string;
|
|
293
|
-
};
|
|
294
|
-
} | {
|
|
295
|
-
type: 'theme-changed';
|
|
296
|
-
payload: {
|
|
297
|
-
theme: 'light' | 'dark';
|
|
298
|
-
};
|
|
299
|
-
} | {
|
|
300
|
-
type: 'selection-changed';
|
|
301
|
-
payload: {
|
|
302
|
-
selectedFieldKeys: string[];
|
|
303
|
-
fields: Array<{
|
|
304
|
-
key: string;
|
|
305
|
-
label: string;
|
|
306
|
-
type: string;
|
|
307
|
-
}>;
|
|
308
|
-
};
|
|
309
|
-
} | {
|
|
310
|
-
type: 'locale-changed';
|
|
311
|
-
payload: {
|
|
312
|
-
currentLocale: string;
|
|
313
|
-
sourceLocale: string;
|
|
314
|
-
isTranslating: boolean;
|
|
315
|
-
locales: Array<{
|
|
316
|
-
code: string;
|
|
317
|
-
displayName: string;
|
|
318
|
-
isDefault: boolean;
|
|
319
|
-
}>;
|
|
320
|
-
};
|
|
321
|
-
} | {
|
|
322
|
-
type: 'operation-result';
|
|
323
|
-
payload: {
|
|
324
|
-
requestId: string;
|
|
325
|
-
success: boolean;
|
|
326
|
-
result?: unknown;
|
|
327
|
-
error?: {
|
|
328
|
-
code: string;
|
|
329
|
-
message: string;
|
|
330
|
-
};
|
|
331
|
-
};
|
|
332
|
-
};
|
|
333
|
-
/**
|
|
334
|
-
* Messages sent FROM the iframe extension TO the platform host.
|
|
335
|
-
*/
|
|
336
|
-
type EditorToHostMessage = {
|
|
337
|
-
type: 'ready';
|
|
338
|
-
payload: Record<string, never>;
|
|
339
|
-
} | {
|
|
340
|
-
type: 'update-values';
|
|
341
|
-
payload: {
|
|
342
|
-
values: Record<string, unknown>;
|
|
343
|
-
};
|
|
344
|
-
} | {
|
|
345
|
-
type: 'update-field';
|
|
346
|
-
payload: {
|
|
347
|
-
path: string;
|
|
348
|
-
value: unknown;
|
|
349
|
-
};
|
|
350
|
-
} | {
|
|
351
|
-
type: 'request-save';
|
|
352
|
-
payload: Record<string, never>;
|
|
353
|
-
} | {
|
|
354
|
-
type: 'request-publish';
|
|
355
|
-
payload: Record<string, never>;
|
|
356
|
-
} | {
|
|
357
|
-
type: 'resize';
|
|
358
|
-
payload: {
|
|
359
|
-
height: number;
|
|
360
|
-
};
|
|
361
|
-
} | {
|
|
362
|
-
type: 'dirty';
|
|
363
|
-
payload: {
|
|
364
|
-
isDirty: boolean;
|
|
365
|
-
};
|
|
366
|
-
} | {
|
|
367
|
-
type: 'request-navigate';
|
|
368
|
-
payload: {
|
|
369
|
-
path: string;
|
|
370
|
-
};
|
|
371
|
-
} | {
|
|
372
|
-
type: 'request-operation';
|
|
373
|
-
payload: {
|
|
374
|
-
operationKey: string;
|
|
375
|
-
input?: Record<string, unknown>;
|
|
376
|
-
requestId: string;
|
|
377
|
-
/** Execution mode: 'sync' waits for completion, 'async' queues and returns. */
|
|
378
|
-
mode?: 'sync' | 'async';
|
|
379
|
-
};
|
|
380
|
-
};
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Runtime validation for postMessage payloads.
|
|
384
|
-
*/
|
|
385
|
-
|
|
386
|
-
/** Validate an incoming message from a custom editor iframe (editor -> host). */
|
|
387
|
-
declare function isValidEditorMessage(data: unknown): data is EditorToHostMessage;
|
|
388
|
-
/** Validate an incoming message from the platform host (host -> editor). */
|
|
389
|
-
declare function isValidHostMessage(data: unknown): data is HostToEditorMessage;
|
|
390
|
-
|
|
391
|
-
/** Protocol version for compatibility checks. */
|
|
392
|
-
declare const PROTOCOL_VERSION = "1.0";
|
|
393
|
-
|
|
394
|
-
export { type EditorContextValue, type EditorInit, EditorProvider, type EditorProviderProps, type EditorToHostMessage, type GraphQLError, type GraphQLResponse, type HostToEditorMessage, type LocaleContext, PROTOCOL_VERSION, type PlatformClient, PlatformClientError, type PlatformClientOptions, type UseAutoResizeOptions, createPlatformClient, isValidEditorMessage, isValidHostMessage, useAutoResize, useEditor };
|
|
1
|
+
export { EditorProvider } from './components/EditorProvider';
|
|
2
|
+
export type { EditorProviderProps } from './components/EditorProvider';
|
|
3
|
+
export { useEditor } from './hooks/useEditor';
|
|
4
|
+
export { useAutoResize } from './hooks/useAutoResize';
|
|
5
|
+
export type { UseAutoResizeOptions } from './hooks/useAutoResize';
|
|
6
|
+
export { createPlatformClient, PlatformClientError, } from './client/platform-client';
|
|
7
|
+
export type { EditorInit, EditorContextValue, LocaleContext, PlatformClient, PlatformClientOptions, GraphQLResponse, GraphQLError, } from './types';
|
|
8
|
+
export type { HostToEditorMessage, EditorToHostMessage, } from './protocol/messages';
|
|
9
|
+
export { isValidEditorMessage, isValidHostMessage, } from './protocol/validation';
|
|
10
|
+
export { PROTOCOL_VERSION } from './protocol/constants';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface BlurhashCanvasProps {
|
|
2
|
+
hash: string;
|
|
3
|
+
className?: string;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Decodes a BlurHash string to a 32×32 canvas. `blurhash` is an optional peer
|
|
7
|
+
* dependency loaded via dynamic import — if it isn't installed the canvas
|
|
8
|
+
* stays blank rather than throwing.
|
|
9
|
+
*/
|
|
10
|
+
export declare function BlurhashCanvas({ hash, className }: BlurhashCanvasProps): import("react/jsx-runtime").JSX.Element;
|