@foir/sdk 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,394 @@
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 };