@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
@@ -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
- import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { ReactNode } from 'react';
3
-
4
- /**
5
- * Public type definitions for the Editor SDK.
6
- */
7
-
8
- /** Data provided by the host when the editor initializes. */
9
- interface EditorInit {
10
- values: Record<string, unknown>;
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;