@weaverse/hydrogen 5.17.0 → 5.18.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 (70) hide show
  1. package/dist/index.js +83 -1
  2. package/dist/index.js.map +1 -1
  3. package/dist/index.mjs +83 -1
  4. package/dist/index.mjs.map +1 -1
  5. package/dist/types/WeaverseHydrogenRoot.d.ts +218 -0
  6. package/dist/types/WeaverseHydrogenRoot.d.ts.map +1 -0
  7. package/dist/types/components/index.d.ts +4 -0
  8. package/dist/types/components/index.d.ts.map +1 -0
  9. package/dist/types/components/main.d.ts +7 -0
  10. package/dist/types/components/main.d.ts.map +1 -0
  11. package/dist/types/hooks/theme-text-context.d.ts +2 -0
  12. package/dist/types/hooks/theme-text-context.d.ts.map +1 -0
  13. package/dist/types/hooks/translation-context.d.ts +138 -0
  14. package/dist/types/hooks/translation-context.d.ts.map +1 -0
  15. package/dist/types/hooks/use-weaverse-data-context.d.ts +29 -0
  16. package/dist/types/hooks/use-weaverse-data-context.d.ts.map +1 -0
  17. package/dist/types/index.d.ts +99 -0
  18. package/dist/types/index.d.ts.map +1 -0
  19. package/dist/types/seo.d.ts +43 -0
  20. package/dist/types/seo.d.ts.map +1 -0
  21. package/dist/types/types.d.ts +826 -0
  22. package/dist/types/types.d.ts.map +1 -0
  23. package/dist/types/utils/index.d.ts +44 -0
  24. package/dist/types/utils/index.d.ts.map +1 -0
  25. package/dist/types/utils/normalize-page-url.d.ts +16 -0
  26. package/dist/types/utils/normalize-page-url.d.ts.map +1 -0
  27. package/dist/types/utils/pick-weaverse-data.d.ts +44 -0
  28. package/dist/types/utils/pick-weaverse-data.d.ts.map +1 -0
  29. package/dist/types/utils/pixel.d.ts +16 -0
  30. package/dist/types/utils/pixel.d.ts.map +1 -0
  31. package/dist/types/utils/studio-request-info.d.ts +17 -0
  32. package/dist/types/utils/studio-request-info.d.ts.map +1 -0
  33. package/dist/types/utils/studio-script-src.d.ts +78 -0
  34. package/dist/types/utils/studio-script-src.d.ts.map +1 -0
  35. package/dist/types/utils/sync-reused-instance.d.ts +21 -0
  36. package/dist/types/utils/sync-reused-instance.d.ts.map +1 -0
  37. package/dist/types/utils/theme-text-store.d.ts +2 -0
  38. package/dist/types/utils/theme-text-store.d.ts.map +1 -0
  39. package/dist/types/utils/translation-store.d.ts +40 -0
  40. package/dist/types/utils/translation-store.d.ts.map +1 -0
  41. package/dist/types/utils/use-studio.d.ts +33 -0
  42. package/dist/types/utils/use-studio.d.ts.map +1 -0
  43. package/dist/types/utils/use-theme-settings-store.d.ts +39 -0
  44. package/dist/types/utils/use-theme-settings-store.d.ts.map +1 -0
  45. package/dist/types/weaverse-client.d.ts +227 -0
  46. package/dist/types/weaverse-client.d.ts.map +1 -0
  47. package/package.json +7 -6
  48. package/src/WeaverseHydrogenRoot.tsx +649 -0
  49. package/src/components/index.ts +10 -0
  50. package/src/components/main.tsx +28 -0
  51. package/src/hooks/theme-text-context.tsx +14 -0
  52. package/src/hooks/translation-context.tsx +275 -0
  53. package/src/hooks/use-weaverse-data-context.ts +69 -0
  54. package/src/index.ts +179 -0
  55. package/src/seo.ts +125 -0
  56. package/src/types.ts +1020 -0
  57. package/src/utils/index.ts +351 -0
  58. package/src/utils/normalize-page-url.ts +44 -0
  59. package/src/utils/pick-weaverse-data.ts +89 -0
  60. package/src/utils/pixel.ts +71 -0
  61. package/src/utils/studio-request-info.ts +66 -0
  62. package/src/utils/studio-script-src.ts +162 -0
  63. package/src/utils/sync-reused-instance.ts +57 -0
  64. package/src/utils/theme-text-store.ts +1 -0
  65. package/src/utils/translation-store.ts +65 -0
  66. package/src/utils/use-studio.ts +168 -0
  67. package/src/utils/use-theme-settings-store.ts +160 -0
  68. package/src/weaverse-client.ts +1179 -0
  69. package/dist/index.d.mts +0 -1269
  70. package/dist/index.d.ts +0 -1269
package/src/types.ts ADDED
@@ -0,0 +1,1020 @@
1
+ import type {
2
+ CachingStrategy,
3
+ HydrogenContext,
4
+ I18nBase,
5
+ } from '@shopify/hydrogen'
6
+ import type {
7
+ AppLoadContext,
8
+ LoaderFunctionArgs as RemixOxygenLoaderArgs,
9
+ } from '@shopify/remix-oxygen'
10
+ import type {
11
+ ElementData,
12
+ PositionInputValue,
13
+ WeaverseCoreParams,
14
+ WeaverseElement,
15
+ WeaverseImage,
16
+ WeaverseProjectDataType,
17
+ WeaverseResourcePickerData,
18
+ WeaverseVideo,
19
+ } from '@weaverse/react'
20
+ import type {
21
+ // Enhanced type exports from schema package
22
+ BasicInput,
23
+ ComponentAvailabilityContext,
24
+ ComponentGroup,
25
+ HeadingInput,
26
+ InputType,
27
+ InspectorGroup,
28
+ PageSEOData,
29
+ PageType,
30
+ Resolvable,
31
+ ComponentPresets as SchemaComponentPresets,
32
+ SchemaType,
33
+ SchemaValidationIssue,
34
+ SchemaValidationResult,
35
+ } from '@weaverse/schema'
36
+ import { isValidSchema } from '@weaverse/schema'
37
+ import type * as React from 'react'
38
+ import type { ForwardRefExoticComponent } from 'react'
39
+ import type { NavigateFunction } from 'react-router'
40
+ import type { TranslationStore } from './utils/translation-store'
41
+ import type { ThemeSettingsStore } from './utils/use-theme-settings-store'
42
+ import type { WeaverseHydrogen } from './WeaverseHydrogenRoot'
43
+ import type { WeaverseClient } from './weaverse-client'
44
+
45
+ // Re-export CachingStrategy from Hydrogen for convenience
46
+ export type { CachingStrategy } from '@shopify/hydrogen'
47
+ // Re-export types from schema for backward compatibility and convenience
48
+ export type {
49
+ // Enhanced type exports
50
+ BasicInput,
51
+ ComponentAvailabilityContext,
52
+ ComponentGroup,
53
+ HeadingInput,
54
+ InputType,
55
+ InspectorGroup,
56
+ PageType,
57
+ PositionInputValue,
58
+ Resolvable,
59
+ SchemaValidationIssue,
60
+ SchemaValidationResult,
61
+ WeaverseImage,
62
+ WeaverseVideo,
63
+ }
64
+
65
+ /** Arguments passed to a component's server-side loader. */
66
+ export type ComponentLoaderArgs<T = any, _E = any> = {
67
+ /** Persisted component data merged with schema defaults. */
68
+ data: T
69
+ /** Request-scoped client available to the component loader. */
70
+ weaverse: WeaverseClient
71
+ }
72
+
73
+ /** Application load context initialized with a request-scoped Weaverse client. */
74
+ export interface WeaverseRouteAppLoadContext extends AppLoadContext {
75
+ /** Client used to load Weaverse content for the current request. */
76
+ weaverse: WeaverseClient
77
+ }
78
+
79
+ /** React Router loader arguments whose app context includes the Weaverse client. */
80
+ export interface RouteLoaderArgs extends RemixOxygenLoaderArgs {
81
+ /** Request-scoped application context with the initialized Weaverse client. */
82
+ context: WeaverseRouteAppLoadContext
83
+ }
84
+
85
+ /** Primitive value accepted in a component's persisted data. */
86
+ export type ComponentDataValue = string | number | boolean | undefined | null
87
+
88
+ /** Reference to a direct child component instance. */
89
+ export interface HydrogenChildComponentReference {
90
+ /** Unique identifier of the child component instance. */
91
+ id: string
92
+ }
93
+
94
+ /** Serialized component instance returned in a Weaverse page. */
95
+ export interface HydrogenComponentData extends ElementData {
96
+ /** References to direct child component instances. */
97
+ children?: HydrogenChildComponentReference[]
98
+ /** ISO timestamp recording when the component instance was created. */
99
+ createdAt?: string
100
+ /** Persisted component setting values and structured payloads. */
101
+ data?: Record<string, ComponentDataValue | Record<string, unknown>>
102
+ /** ISO timestamp recording soft deletion, when applicable. */
103
+ deletedAt?: string
104
+ /** Unique component instance identifier. */
105
+ id: string
106
+ /** Registered component type used to select its renderer. */
107
+ type: string
108
+ /** ISO timestamp recording the latest component update. */
109
+ updatedAt?: string
110
+ }
111
+
112
+ /**
113
+ * Optimized: Use Zod-inferred SchemaType directly instead of extending
114
+ * This ensures perfect type consistency with the schema validation
115
+ */
116
+ export type HydrogenComponentSchema = SchemaType
117
+
118
+ /** Props supplied by Weaverse when rendering a registered Hydrogen component. */
119
+ export interface HydrogenComponentProps<L = any> extends WeaverseElement {
120
+ /** Rendered child component instances. */
121
+ children?: React.JSX.Element[]
122
+ /** Optional CSS class passed through by the renderer. */
123
+ className?: string
124
+ /** Result returned by the component's server-side loader. */
125
+ loaderData?: L
126
+ }
127
+
128
+ /** Normalized request details attached to loader data for Studio navigation. */
129
+ export type WeaverseLoaderRequestInfo = {
130
+ /** URL search string, including the leading question mark when present. */
131
+ search: string
132
+ /** Storefront request pathname. */
133
+ pathname: string
134
+ /** Parsed request query parameters. */
135
+ queries: {
136
+ /** Query parameter value keyed by parameter name. */
137
+ [key: string]: string | boolean
138
+ }
139
+ /** Locale used to load the page. */
140
+ i18n: WeaverseI18n
141
+ }
142
+
143
+ /** Published theme setting values keyed by schema setting name. */
144
+ export type HydrogenThemeSettings = {
145
+ /** Published theme setting value keyed by schema setting name. */
146
+ [key: string]: any
147
+ }
148
+
149
+ /** Project metadata returned with a Weaverse page payload. */
150
+ export type HydrogenProjectType = {
151
+ /** Unique Weaverse project identifier. */
152
+ id: string
153
+ /** Identifier of the Shopify shop connected to the project. */
154
+ weaverseShopId: string
155
+ /** Human-readable project name. */
156
+ name: string
157
+ /** Additional project metadata returned by the content API. */
158
+ [key: string]: any
159
+ }
160
+
161
+ /** Runtime services and project metadata exposed to Weaverse integrations. */
162
+ export type WeaverseInternal = {
163
+ /** Route assignment for the rendered Weaverse page. */
164
+ pageAssignment: HydrogenPageAssignment
165
+ /** Metadata for the active Weaverse project. */
166
+ project: HydrogenProjectType
167
+ /** React Router navigation function, attached in design mode. */
168
+ navigate: NavigateFunction
169
+ /** Revalidates the active React Router data routes. */
170
+ revalidate: () => void
171
+ /** Mutable theme settings store used by Studio. */
172
+ themeSettingsStore: ThemeSettingsStore
173
+ /** Mutable translation store used by Studio, when translations are enabled. */
174
+ translationStore?: TranslationStore | null
175
+ /** @deprecated Use translationStore instead. */
176
+ themeTextStore?: TranslationStore | null
177
+ /** Active-locale merchant translation overrides. */
178
+ merchantOverrides?: Record<string, unknown> | null
179
+ }
180
+
181
+ /**
182
+ * Optimized: Use direct type alias to maintain consistency
183
+ */
184
+ export type HydrogenComponentPresets = SchemaComponentPresets
185
+
186
+ /** Registered runtime definition for a Hydrogen component type. */
187
+ export type HydrogenElement = {
188
+ /** React renderer for this registered component type. */
189
+ Component:
190
+ | ForwardRefExoticComponent<HydrogenComponentProps>
191
+ | ((props: HydrogenComponentProps) => React.JSX.Element)
192
+ /** Unique component type matching the component schema. */
193
+ type: string
194
+ /** Component schema used for settings, defaults, and availability. */
195
+ schema?: HydrogenComponentSchema
196
+ /** Optional data loader function for server-side data fetching. */
197
+ loader?: (args: ComponentLoaderArgs) => Promise<unknown>
198
+ }
199
+
200
+ /** Initialization parameters for a request-scoped {@link WeaverseHydrogen} runtime. */
201
+ export interface WeaverseHydrogenParams
202
+ extends Omit<WeaverseCoreParams, 'ItemConstructor'> {
203
+ /** Page content used to initialize component instances. */
204
+ data: HydrogenPageData
205
+ /** Route loader data made available to component data bindings. */
206
+ dataContext?: Record<string, unknown> | null
207
+ /** Runtime services and metadata available to integrations. */
208
+ internal: Partial<WeaverseInternal>
209
+ /** Whether the page is running inside the visual editor. */
210
+ isDesignMode?: boolean
211
+ /** Whether a component preview is being rendered. */
212
+ isPreviewMode?: boolean
213
+ /** Whether a saved page revision is being previewed. */
214
+ isRevisionPreview?: boolean
215
+ /** Identifier of the page being rendered. */
216
+ pageId: string
217
+ /** Identifier of the Weaverse project supplying content. */
218
+ projectId: string
219
+ /** Normalized URL and locale information for this request. */
220
+ requestInfo: WeaverseLoaderRequestInfo
221
+ /** Component type requested by section preview mode. */
222
+ sectionType?: string
223
+ /** Base URL used for public Weaverse API requests. */
224
+ weaverseApiBase: string
225
+ /**
226
+ * API key read from environment/configuration for storefront requests or
227
+ * supplied by Studio requests while editing and previewing.
228
+ */
229
+ weaverseApiKey: string
230
+ /** Origin used for Weaverse Studio assets and editor communication. */
231
+ weaverseHost: string
232
+ /**
233
+ * Public data API origin. Keep `weaverseHost` for Studio scripts/editor
234
+ * assets; point this at the Cloudflare proxy (`https://api.weaverse.io`)
235
+ * when edge caching is enabled.
236
+ */
237
+ weaversePublicApiBase?: string
238
+ /** Optional Studio asset version used by preview integrations. */
239
+ weaverseVersion?: string
240
+ }
241
+
242
+ /** Export shape for a renderable component, its schema, and optional loader. */
243
+ export type HydrogenComponent<T extends HydrogenComponentProps = any> = {
244
+ /** React renderer exported by the component module. */
245
+ default: ForwardRefExoticComponent<T> | ((props: T) => React.JSX.Element)
246
+ /** Schema exported by the component module. */
247
+ schema: HydrogenComponentSchema
248
+ /** Optional data loader function for server-side data fetching. */
249
+ loader?: (args: ComponentLoaderArgs) => Promise<unknown>
250
+ }
251
+
252
+ /** Weaverse Studio query parameters recognized by the Hydrogen runtime. */
253
+ export type WeaverseStudioQueries = {
254
+ /** Project identifier selected by Studio for this request. */
255
+ weaverseProjectId: string
256
+ /** API key passed by Studio for design and preview requests. */
257
+ weaverseApiKey: string
258
+ /** Studio origin serving editor assets and APIs. */
259
+ weaverseHost: string
260
+ /** Studio asset version requested by the editor. */
261
+ weaverseVersion: string
262
+ /** Whether the request is for the visual editor. */
263
+ isDesignMode: boolean
264
+ /** Whether the request renders a component preview. */
265
+ isPreviewMode?: boolean
266
+ /** Component type requested for section preview. */
267
+ sectionType?: string
268
+ }
269
+
270
+ /** Storefront-safe environment values exposed with theme settings. */
271
+ export type PublicEnv = {
272
+ /** Public Shopify storefront domain. */
273
+ PUBLIC_STORE_DOMAIN: string
274
+ /** Public Storefront API access token. */
275
+ PUBLIC_STOREFRONT_API_TOKEN: string
276
+ }
277
+
278
+ /** Resolved project, API endpoint, and rendering-mode configuration. */
279
+ export type WeaverseProjectConfigs = {
280
+ /** Identifier of the Weaverse project supplying content. */
281
+ projectId: string
282
+ /** Origin used for Studio assets and editor communication. */
283
+ weaverseHost: string
284
+ /** Base URL used for public Weaverse content API requests. */
285
+ weaverseApiBase: string
286
+ /** Explicit public data API origin, when separately configured. */
287
+ weaversePublicApiBase?: string
288
+ /**
289
+ * API key read from environment/configuration for storefront requests or
290
+ * supplied by Studio requests while editing and previewing.
291
+ */
292
+ weaverseApiKey: string
293
+ /** Optional Studio asset version. */
294
+ weaverseVersion?: string
295
+ /** Whether the request is running inside the visual editor. */
296
+ isDesignMode?: boolean
297
+ /** Whether the request renders a component preview. */
298
+ isPreviewMode?: boolean
299
+ /** Whether the request previews a saved page revision. */
300
+ isRevisionPreview?: boolean
301
+ /** Component type requested for section preview. */
302
+ sectionType?: string
303
+ /** Storefront-safe environment values exposed with theme settings. */
304
+ publicEnv?: PublicEnv
305
+ }
306
+
307
+ /** Assignment describing which project page handles a storefront route. */
308
+ export type HydrogenPageAssignment = {
309
+ /** Project identifier owning the assigned page. */
310
+ projectId: string
311
+ /** Storefront page type matched by the assignment. */
312
+ type: PageType
313
+ /** Route or resource handle matched by the assignment. */
314
+ handle: string
315
+ /** Locale matched by the assignment. */
316
+ locale: string
317
+ /** Inheritance details when the assignment comes from another project. */
318
+ meta?: {
319
+ /** Whether the assignment was inherited. */
320
+ inherited: boolean
321
+ /** Project identifier where the assignment originated. */
322
+ sourceProjectId: string
323
+ /** Number of inheritance levels traversed. */
324
+ depth: number
325
+ }
326
+ }
327
+
328
+ /** Complete payload returned by {@link WeaverseClient.loadPage}. */
329
+ export type WeaverseLoaderData = {
330
+ /** Resolved runtime configuration and normalized request details. */
331
+ configs: Omit<WeaverseProjectConfigs, 'publicEnv'> & {
332
+ /** Normalized URL and locale information for the request. */
333
+ requestInfo: WeaverseLoaderRequestInfo
334
+ }
335
+ /** Published page content to render. */
336
+ page: HydrogenPageData
337
+ /** Metadata for the project supplying the page. */
338
+ project: HydrogenProjectType
339
+ /** Route assignment that selected the page, when available. */
340
+ pageAssignment?: HydrogenPageAssignment
341
+ }
342
+
343
+ /** Published Weaverse page content consumed by the Hydrogen renderer. */
344
+ export interface HydrogenPageData extends WeaverseProjectDataType {
345
+ /** Internal cache identifier attached by the content API when available. */
346
+ __cacheId?: string
347
+ /** Unique page identifier. */
348
+ id: string
349
+ /** Serialized component instances belonging to the page. */
350
+ items: HydrogenComponentData[]
351
+ /** Human-readable page name. */
352
+ name: string
353
+ /**
354
+ * Page-level SEO metadata published by Weaverse Builder. `null` when
355
+ * the page has no `PageSeo` row; absent on revision snapshots that
356
+ * predate the SEO feature. Themes should treat both as "no Weaverse
357
+ * override".
358
+ */
359
+ seo?: PageSEOData | null
360
+ /** Additional page fields supplied by the content API. */
361
+ [key: string]: any
362
+ }
363
+
364
+ /** Locale metadata used when requesting localized Weaverse content. */
365
+ export type WeaverseI18n = I18nBase & {
366
+ /** Human-readable locale label displayed in Studio. */
367
+ label?: string
368
+ /** Locale path prefix used by the storefront router. */
369
+ pathPrefix?: string
370
+ /** Additional locale metadata supplied by the storefront. */
371
+ [key: string]: any
372
+ }
373
+
374
+ /** Theme metadata, global settings, and localization configuration. */
375
+ export type HydrogenThemeSchema = {
376
+ /** Theme identity, author, and support metadata. */
377
+ info: {
378
+ /** Human-readable theme name. */
379
+ name: string
380
+ /** Theme version displayed in Studio. */
381
+ version: string
382
+ /** Theme author name. */
383
+ author: string
384
+ /** URL of the theme author's profile image. */
385
+ authorProfilePhoto: string
386
+ /** URL of the theme documentation. */
387
+ documentationUrl: string
388
+ /** URL where merchants can request theme support. */
389
+ supportUrl: string
390
+ }
391
+ /** @deprecated Use settings instead. */
392
+ inspector?: InspectorGroup[]
393
+ /** Groups of global theme settings exposed in Studio. */
394
+ settings?: InspectorGroup[]
395
+ /** Theme localization configuration. */
396
+ i18n?: {
397
+ /** Strategy used to encode the locale in storefront URLs. */
398
+ urlStructure: 'url-path' | 'subdomain' | 'top-level-domain'
399
+ /** Locale used when no localized route is selected. */
400
+ defaultLocale: WeaverseI18n
401
+ /** Locales enabled for the connected Shopify shop. */
402
+ shopLocales: WeaverseI18n[]
403
+ /** Default-locale static translation content. */
404
+ staticContent?: Record<string, unknown>
405
+ /** Enable the translation UI in the builder. */
406
+ translation?: boolean
407
+ }
408
+ }
409
+
410
+ /** Request body sent to the Weaverse project content endpoint. */
411
+ export type FetchProjectRequestBody = {
412
+ /** Identifier of the project to load. */
413
+ projectId: string
414
+ /** Normalized storefront URL being resolved. */
415
+ url: string
416
+ /** Storefront locale for localized content. */
417
+ i18n?: WeaverseI18n
418
+ /** Optional route-specific page lookup parameters. */
419
+ params?: {
420
+ /** Storefront page type to load. */
421
+ type?: PageType
422
+ /** Locale override for this page lookup. */
423
+ locale?: string
424
+ /** Resource or custom-page handle to load. */
425
+ handle?: string
426
+ }
427
+ /** Whether draft editor content should be returned. */
428
+ isDesignMode?: boolean
429
+ }
430
+
431
+ /** Project content response before it is normalized into loader data. */
432
+ export type FetchProjectPayload = {
433
+ /** Published or draft page content; absent when no page matches. */
434
+ page?: HydrogenPageData
435
+ /** Project metadata; absent in some error responses. */
436
+ project?: HydrogenProjectType
437
+ /** Assignment that selected the page, when one matched. */
438
+ pageAssignment?: HydrogenPageAssignment
439
+ /** API error message, when the request could not be fulfilled. */
440
+ error?: string
441
+ /** Additional fields returned by compatible API versions. */
442
+ [key: string]: any
443
+ }
444
+
445
+ /**
446
+ * Project identifier value - can be static string or dynamic function.
447
+ *
448
+ * **Static String**: Direct project ID reference
449
+ * ```ts
450
+ * 'project-abc-123'
451
+ * ```
452
+ *
453
+ * **Synchronous Function**: Returns project ID based on request context
454
+ * ```ts
455
+ * () => {
456
+ * const host = new URL(request.url).hostname
457
+ * return PROJECT_MAP[host] || 'default-project'
458
+ * }
459
+ * ```
460
+ *
461
+ * **Asynchronous Function**: Async project resolution (must be awaited before passing)
462
+ * ```ts
463
+ * async () => {
464
+ * return await database.getProjectId(userId)
465
+ * }
466
+ * ```
467
+ */
468
+ export type ProjectIdValue = string | (() => string) | (() => Promise<string>)
469
+
470
+ /**
471
+ * Type guard for detecting function-based projectId.
472
+ *
473
+ * Used internally by WeaverseClient constructor to determine
474
+ * if projectId needs evaluation or can be used directly.
475
+ */
476
+ export function isProjectIdFunction(
477
+ projectId: ProjectIdValue | undefined
478
+ ): projectId is (() => string) | (() => Promise<string>) {
479
+ return typeof projectId === 'function'
480
+ }
481
+
482
+ /**
483
+ * Extended WeaverseClient constructor arguments supporting multi-project architecture.
484
+ *
485
+ * @example Static project (existing pattern - backward compatible)
486
+ * ```ts
487
+ * const weaverse = new WeaverseClient({
488
+ * ...hydrogenContext,
489
+ * projectId: 'project-default-123'
490
+ * })
491
+ * ```
492
+ *
493
+ * @example Dynamic project selection (new capability)
494
+ * ```ts
495
+ * const weaverse = new WeaverseClient({
496
+ * ...hydrogenContext,
497
+ * projectId: () => {
498
+ * const origin = new URL(request.url).origin
499
+ * if (origin === 'https://mystore.se') return process.env.WEAVERSE_PROJECT_SWEDEN!
500
+ * if (origin === 'https://mystore.fr') return process.env.WEAVERSE_PROJECT_FRANCE!
501
+ * return process.env.WEAVERSE_PROJECT_ID!
502
+ * }
503
+ * })
504
+ * ```
505
+ *
506
+ * **Priority Chain** (highest to lowest):
507
+ * 1. URL query parameter: `?weaverseProjectId=...` (design mode, preview mode)
508
+ * 2. Function result (if function provided)
509
+ * 3. Explicit string value (if string provided)
510
+ * 4. Environment variable: `WEAVERSE_PROJECT_ID` (Hydrogen env or process.env)
511
+ * 5. Empty string (triggers validation error in methods)
512
+ *
513
+ * **Function Requirements**:
514
+ * - Must return non-empty string
515
+ * - Can access request via closure for routing decisions
516
+ * - Evaluated once per WeaverseClient instance (request-scoped)
517
+ * - Async functions must be awaited before passing to constructor
518
+ * - Should handle edge cases (missing headers, invalid domains, etc.)
519
+ *
520
+ * **Request Context Access**:
521
+ * Functions access request via closure from constructor arguments.
522
+ */
523
+ export type WeaverseClientArgs = HydrogenContext & {
524
+ /**
525
+ * React components registered with Weaverse CMS.
526
+ * Each component must have a schema defining its properties and settings.
527
+ */
528
+ components: HydrogenComponent[]
529
+
530
+ /**
531
+ * Theme schema defining global theme settings (colors, fonts, layouts).
532
+ * Used to generate default theme configuration and validate theme data.
533
+ */
534
+ themeSchema: HydrogenThemeSchema
535
+
536
+ /**
537
+ * Incoming HTTP request object from React Router loader.
538
+ * Provides access to URL, headers, cookies for dynamic routing decisions.
539
+ */
540
+ request: Request
541
+
542
+ /**
543
+ * Hydrogen cache instance for content caching.
544
+ *Supports multi-tenant caching with project-specific cache keys.
545
+ */
546
+ cache: Cache
547
+
548
+ /**
549
+ * Project identifier for loading content from Weaverse CMS.
550
+ *
551
+ * **Value Types**:
552
+ * - Static string: 'project-123' (existing usage)
553
+ * - Synchronous function: () => determineProject(request)
554
+ * - Asynchronous function: async () => await getProject(request) (must be awaited)
555
+ *
556
+ * **Backward Compatibility**:
557
+ * - Optional parameter (defaults to environment variable)
558
+ * - Existing code without projectId continues to work unchanged
559
+ *
560
+ * **Cache Isolation**:
561
+ * ProjectId is included in cache keys to prevent cross-project content pollution.
562
+ * Each project's content is cached separately, ensuring multi-tenant isolation.
563
+ */
564
+ projectId?: ProjectIdValue
565
+
566
+ /**
567
+ * Fetch timeout in milliseconds for API requests.
568
+ * Defaults to 10000ms (10 seconds) if not specified.
569
+ * Useful for adjusting based on network conditions or deployment environment.
570
+ *
571
+ * @default 10000
572
+ * @example
573
+ * ```typescript
574
+ * new WeaverseClient({
575
+ * // ... other args
576
+ * fetchTimeoutMs: 5000 // 5 second timeout
577
+ * })
578
+ * ```
579
+ */
580
+ fetchTimeoutMs?: number
581
+ }
582
+
583
+ /** Product selected through a Weaverse resource-picker setting. */
584
+ export type WeaverseProduct = WeaverseResourcePickerData
585
+ /** Collection selected through a Weaverse resource-picker setting. */
586
+ export type WeaverseCollection = WeaverseResourcePickerData
587
+ /** Blog selected through a Weaverse resource-picker setting. */
588
+ export type WeaverseBlog = WeaverseResourcePickerData
589
+ /** Article selected through a Weaverse resource-picker setting. */
590
+ export type WeaverseArticle = WeaverseResourcePickerData
591
+ /** Metaobject selected through a Weaverse resource-picker setting. */
592
+ export type WeaverseMetaObject = WeaverseResourcePickerData
593
+
594
+ /** Response returned by Hydrogen's cached fetch helper. */
595
+ export type WithCacheFetchResponse<T> = {
596
+ /** Parsed response payload. */
597
+ data: T
598
+ /** Underlying Fetch API response. */
599
+ response: Response
600
+ }
601
+
602
+ /** Theme configuration returned by the Weaverse project API. */
603
+ export type ThemeSettingsResponse = {
604
+ /** Published theme setting values. */
605
+ theme?: HydrogenThemeSettings
606
+ /** Theme schema included for Studio editing. */
607
+ schema?: HydrogenThemeSchema
608
+ /** Storefront-safe environment values included in design mode. */
609
+ publicEnv?: PublicEnv
610
+ /** Theme's default locale JSON from `themeSchema.i18n.staticContent`. */
611
+ staticContent?: Record<string, unknown>
612
+ /** Locale-specific merchant overrides from the API. */
613
+ merchantOverrides?: Record<string, unknown>
614
+ /** Diagnostic message when loading fell back to schema defaults. */
615
+ _error?: string
616
+ /** Whether remote theme settings failed to load. */
617
+ _loadFailed?: boolean
618
+ }
619
+
620
+ /**
621
+ * Legacy data-or-error response shape retained for compatibility.
622
+ *
623
+ * The client's current direct-fetch implementation uses
624
+ * {@link WithCacheFetchResponse} internally instead of returning this shape.
625
+ */
626
+ export type DirectFetchResponse<T = unknown> = {
627
+ /** Parsed payload when the legacy request succeeded. */
628
+ data?: T
629
+ /** Error message when the legacy request failed. */
630
+ error?: string
631
+ }
632
+
633
+ /** Predicate used to decide whether a fetched response may be cached. */
634
+ export type CacheResponseValidator<T = unknown> = (
635
+ response: WithCacheFetchResponse<T> | T
636
+ ) => boolean
637
+
638
+ /** Error raised by Weaverse requests with a stable code and optional context. */
639
+ export class WeaverseError extends Error {
640
+ /** Machine-readable error code. */
641
+ public readonly code: string
642
+ /** HTTP status associated with the failure, when available. */
643
+ public readonly statusCode?: number
644
+ /** Structured diagnostic details for logging and error handling. */
645
+ public readonly context?: Record<string, unknown>
646
+
647
+ /** Creates a Weaverse request error with a stable code and diagnostics. */
648
+ constructor(
649
+ message: string,
650
+ code = 'WEAVERSE_ERROR',
651
+ statusCode?: number,
652
+ context?: Record<string, unknown>
653
+ ) {
654
+ super(message)
655
+ this.name = 'WeaverseError'
656
+ this.code = code
657
+ this.statusCode = statusCode
658
+ this.context = context
659
+
660
+ // Maintains proper stack trace for where our error was thrown
661
+ if (Error.captureStackTrace) {
662
+ Error.captureStackTrace(this, WeaverseError)
663
+ }
664
+ }
665
+ }
666
+
667
+ /**
668
+ * Validation result type for project ID validation.
669
+ * Returns validation status with optional error message.
670
+ */
671
+ export type ProjectIdValidationResult = {
672
+ /** Whether the project identifier passed validation. */
673
+ valid: boolean
674
+ /** Validation error message when `valid` is false. */
675
+ error?: string
676
+ }
677
+
678
+ /** Published custom page entry suitable for sitemap generation. */
679
+ export interface CustomPageEntry {
680
+ /** Suggested sitemap update frequency. */
681
+ changeFrequency?: 'daily' | 'weekly' | 'monthly'
682
+ /** Weaverse custom page handle. */
683
+ handle: string
684
+ /** ISO timestamp of the latest published update. */
685
+ lastModified: string
686
+ /** Locale code, or `null` for the project's default locale. */
687
+ locale: string | null
688
+ /** Storefront path for the custom page. */
689
+ path: string
690
+ /** Optional sitemap priority from zero to one. */
691
+ priority?: number
692
+ }
693
+
694
+ /**
695
+ * Type guards for response validation
696
+ */
697
+
698
+ export function isWithCacheFetchResponse<T>(
699
+ response: unknown
700
+ ): response is WithCacheFetchResponse<T> {
701
+ return (
702
+ typeof response === 'object' &&
703
+ response !== null &&
704
+ 'data' in response &&
705
+ 'response' in response
706
+ )
707
+ }
708
+
709
+ /** Checks whether a value contains the required project response fields. */
710
+ export function isFetchProjectPayload(
711
+ payload: unknown
712
+ ): payload is FetchProjectPayload {
713
+ return (
714
+ typeof payload === 'object' &&
715
+ payload !== null &&
716
+ 'page' in payload &&
717
+ 'project' in payload &&
718
+ 'pageAssignment' in payload
719
+ )
720
+ }
721
+
722
+ /** Response containing an error message returned by a Weaverse request. */
723
+ export interface WeaverseErrorResponse {
724
+ /** Human-readable request failure message. */
725
+ error: string
726
+ }
727
+
728
+ /** Checks whether a response contains a string error message. */
729
+ export function hasError(response: unknown): response is WeaverseErrorResponse {
730
+ return (
731
+ typeof response === 'object' &&
732
+ response !== null &&
733
+ 'error' in response &&
734
+ typeof (response as Record<string, unknown>).error === 'string'
735
+ )
736
+ }
737
+
738
+ /** Checks whether a value contains a theme settings object. */
739
+ export function isThemeSettingsResponse(
740
+ data: unknown
741
+ ): data is ThemeSettingsResponse {
742
+ if (typeof data !== 'object' || data === null) {
743
+ return false
744
+ }
745
+
746
+ const record = data as Record<string, unknown>
747
+ return (
748
+ 'theme' in record &&
749
+ typeof record.theme === 'object' &&
750
+ record.theme !== null
751
+ )
752
+ }
753
+
754
+ /**
755
+ * Enhanced type utilities for better development experience
756
+ */
757
+ export type HydrogenSchemaValidationResult =
758
+ SchemaValidationResult<HydrogenComponentSchema>
759
+
760
+ /**
761
+ * Type guard to check if a schema is valid.
762
+ * Leverages validation from @weaverse/schema package which provides
763
+ * comprehensive Zod-based validation with the ElementSchema.
764
+ *
765
+ * @param schema - Unknown value to validate
766
+ * @returns True if schema is a valid HydrogenComponentSchema
767
+ *
768
+ * @example
769
+ * ```typescript
770
+ * if (isValidHydrogenSchema(userInput)) {
771
+ * // userInput is now typed as HydrogenComponentSchema
772
+ * console.log(userInput.type)
773
+ * }
774
+ * ```
775
+ */
776
+ export function isValidHydrogenSchema(
777
+ schema: unknown
778
+ ): schema is HydrogenComponentSchema {
779
+ // Use the comprehensive validation from @weaverse/schema package
780
+ return isValidSchema(schema)
781
+ }
782
+
783
+ /** Type-safe component schema authoring options. */
784
+ export type CreateHydrogenSchemaOptions = {
785
+ /** Human-readable component title displayed in Studio. */
786
+ title: string
787
+ /** Unique component type used for registration and persisted items. */
788
+ type: string
789
+ /** Maximum number of instances allowed in the containing scope. */
790
+ limit?: number
791
+ /** Inspector groups defining editable component settings. */
792
+ settings?: InspectorGroup[]
793
+ /** Component types allowed as direct children. */
794
+ childTypes?: string[]
795
+ /**
796
+ * Legacy page and placement availability restrictions.
797
+ *
798
+ * @deprecated Use `enabled` instead. Convert the arrays to checks in an
799
+ * `enabled` resolver, for example:
800
+ * `enabled: ({page, group}) => pages.includes(page.type) &&
801
+ * (groups.includes('*') || groups.includes(group))`.
802
+ */
803
+ enabledOn?: {
804
+ /** Page types where the component can be inserted. */
805
+ pages?: PageType[]
806
+ /** Placement groups where the component can be inserted; `*` allows all. */
807
+ groups?: ('*' | 'header' | 'footer' | 'body')[]
808
+ }
809
+ /** Static or context-aware component availability rule. */
810
+ enabled?: Resolvable<boolean, ComponentAvailabilityContext>
811
+ /** Default component data and optional nested component presets. */
812
+ presets?: {
813
+ /** Components inserted as children by the preset. */
814
+ children?: SchemaComponentPresets[]
815
+ /** Additional default setting value keyed by setting name. */
816
+ [key: string]: any
817
+ }
818
+ }
819
+
820
+ // Extended window interface for hydrogen-specific globals
821
+ declare global {
822
+ interface Window {
823
+ __weaverse?: WeaverseHydrogen
824
+ __weaverses?: Record<string, WeaverseHydrogen>
825
+ __weaverseThemeSettingsStore?: ThemeSettingsStore
826
+ }
827
+ }
828
+
829
+ /** Browser bridge exposed by Weaverse Studio in design and preview modes. */
830
+ export interface WeaverseStudio {
831
+ /** Connects Studio to a newly created Hydrogen runtime. */
832
+ init: (weaverse: WeaverseHydrogen) => void
833
+ /** Refreshes Studio after the active runtime configuration changes. */
834
+ refreshStudio: (params: WeaverseHydrogenParams) => void
835
+ }
836
+
837
+ /** Browser window after the Weaverse Studio bridge has initialized. */
838
+ export interface WeaverseStudioWindow extends Window {
839
+ /** Studio bridge used to initialize and refresh the Hydrogen runtime. */
840
+ weaverseStudio: WeaverseStudio
841
+ }
842
+
843
+ /** Checks whether the browser window exposes the Weaverse Studio bridge. */
844
+ export function hasWeaverseStudio(
845
+ window: Window
846
+ ): window is WeaverseStudioWindow {
847
+ return 'weaverseStudio' in window && typeof window.weaverseStudio === 'object'
848
+ }
849
+
850
+ declare module '@shopify/remix-oxygen' {
851
+ interface AppLoadContext {
852
+ weaverse: WeaverseClient
853
+ }
854
+ }
855
+
856
+ declare module '@shopify/hydrogen' {
857
+ interface HydrogenEnv {
858
+ CUSTOM_COLLECTION_BANNER_METAFIELD: string
859
+ JUDGEME_PRIVATE_API_TOKEN: string
860
+ KLAVIYO_PRIVATE_API_TOKEN: string
861
+ METAOBJECT_COLOR_NAME_KEY: string
862
+ METAOBJECT_COLOR_VALUE_KEY: string
863
+ METAOBJECT_COLORS_TYPE: string
864
+ PUBLIC_GOOGLE_GTM_ID: string
865
+ PUBLIC_SHOPIFY_INBOX_SHOP_ID: string
866
+ PUBLIC_STORE_DOMAIN: string
867
+ PUBLIC_STOREFRONT_API_TOKEN: string
868
+ WEAVERSE_API_KEY: string
869
+ WEAVERSE_HOST?: string
870
+ WEAVERSE_PROJECT_ID: string
871
+ WEAVERSE_PUBLIC_API_BASE?: string
872
+ }
873
+ }
874
+
875
+ /**
876
+ * Parameters for loadPage method supporting route-level project override.
877
+ *
878
+ * @example Basic usage (uses client-level project)
879
+ * ```ts
880
+ * const weaverseData = await weaverse.loadPage({
881
+ * type: 'PRODUCT',
882
+ * handle: params.productHandle
883
+ * })
884
+ * ```
885
+ *
886
+ * @example Route-level project override
887
+ * ```ts
888
+ * export async function loader({ params, context }: LoaderFunctionArgs) {
889
+ * const { weaverse } = context
890
+ *
891
+ * // Use special campaign project for this route only
892
+ * const weaverseData = await weaverse.loadPage({
893
+ * type: 'PRODUCT',
894
+ * handle: params.productHandle,
895
+ * projectId: process.env.WEAVERSE_PROJECT_CAMPAIGN // Override
896
+ * })
897
+ *
898
+ * return { weaverseData }
899
+ * }
900
+ * ```
901
+ */
902
+ export type LoadPageParams = {
903
+ /**
904
+ * Page type to load from Weaverse CMS.
905
+ *
906
+ * Determines which template to use for rendering the page.
907
+ * Falls back to 'INDEX' if not specified or if page type doesn't exist.
908
+ *
909
+ * @default 'INDEX'
910
+ */
911
+ type?: PageType
912
+
913
+ /**
914
+ * Locale for internationalization.
915
+ *
916
+ * Format: IETF BCP 47 language tag (e.g., 'en-US', 'fr-FR', 'de-DE')
917
+ * Used to load locale-specific content and translations.
918
+ */
919
+ locale?: string
920
+
921
+ /**
922
+ * Page handle for dynamic pages.
923
+ *
924
+ * Identifies specific resource within page type:
925
+ * - Product handle: 'red-sneakers'
926
+ * - Collection handle: 'summer-sale'
927
+ * - Page handle: 'about-us'
928
+ * - Article handle: 'how-to-style-sneakers'
929
+ */
930
+ handle?: string
931
+
932
+ /**
933
+ * Cache strategy override for this specific page load.
934
+ *
935
+ * Overrides default cache strategy for special use cases:
936
+ * - Fresh content for checkout pages (no cache)
937
+ * - Long-lived cache for static pages (1 hour+)
938
+ * - Short-lived cache for frequently updated content (5 minutes)
939
+ */
940
+ strategy?: CachingStrategy
941
+
942
+ /**
943
+ * Optional project override for this specific page load.
944
+ *
945
+ * **Precedence**: Route-level projectId takes precedence over client-level projectId.
946
+ *
947
+ * **Use Cases**:
948
+ * - Campaign landing pages with custom content
949
+ * - VIP customer experiences with dedicated projects
950
+ * - A/B testing specific pages without changing global config
951
+ * - Seasonal promotions with limited-time content
952
+ *
953
+ * **Validation**:
954
+ * - Must be non-empty string
955
+ * - Validated before API call
956
+ * - Falls back to client-level projectId if undefined
957
+ * - Does NOT support function (string only)
958
+ *
959
+ * **Cache Isolation**:
960
+ * Override projectId is included in cache key, ensuring separate caches
961
+ * for different projects even on the same route.
962
+ *
963
+ * @example Campaign page override
964
+ * ```ts
965
+ * const campaignData = await weaverse.loadPage({
966
+ * type: 'PAGE',
967
+ * handle: 'summer-sale',
968
+ * projectId: process.env.WEAVERSE_PROJECT_CAMPAIGN
969
+ * })
970
+ * ```
971
+ */
972
+ projectId?: string
973
+ }
974
+
975
+ // ─── Translation sidecar types (design mode) ─────────────────────────
976
+
977
+ /** A single translated field for one item. */
978
+ export interface TranslationMapEntry {
979
+ /** Source-locale value used to detect subsequent content changes. */
980
+ originalValue: string
981
+ /** Localized value rendered for the target locale. */
982
+ translatedValue: string
983
+ }
984
+
985
+ /** Per-item translation fields, keyed by field name */
986
+ export type TranslationItemEntry = {
987
+ /** Translation entry keyed by component field name. */
988
+ [key: string]: TranslationMapEntry
989
+ }
990
+
991
+ /**
992
+ * Translation map sent from the builder alongside page data in design mode.
993
+ * Keyed by item ID, each value maps field names to translation entries.
994
+ */
995
+ export type TranslationMap = {
996
+ /** Translated fields keyed by component instance identifier. */
997
+ [itemId: string]: TranslationItemEntry
998
+ }
999
+
1000
+ /** A single translation entry for save payloads. */
1001
+ export interface TranslationEntry {
1002
+ /** Marks an existing translation for deletion. */
1003
+ deleted?: boolean
1004
+ /** Identifier of the component instance owning the field. */
1005
+ itemId: string
1006
+ /** Dot-path to the translated component field. */
1007
+ key: string
1008
+ /** Source-locale value used to detect content changes. */
1009
+ originalValue: string
1010
+ /** Localized value to persist. */
1011
+ translatedValue: string
1012
+ }
1013
+
1014
+ /** Result of collecting translation changes for the save flow */
1015
+ export type TranslationChanges = {
1016
+ /** Builder language identifier receiving the changes. */
1017
+ languageId: string
1018
+ /** Translation entries to create, update, or delete. */
1019
+ entries: TranslationEntry[]
1020
+ }