@marvalt/digivalt-core 0.2.30 → 0.2.33

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 (59) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/GLOBAL-SHORTCODES.md +7 -7
  3. package/README.md +10 -8
  4. package/bin/env-example-fragments.cjs +6 -0
  5. package/bin/init.cjs +44 -5
  6. package/dist/generators/index.d.ts +3 -0
  7. package/dist/generators/prerender-seo.d.ts +6 -0
  8. package/dist/generators/seo-manifest.d.ts +3 -0
  9. package/dist/generators/seo-urls.d.ts +29 -0
  10. package/dist/generators/sitemap-paths.d.ts +5 -9
  11. package/dist/generators.cjs +1005 -155
  12. package/dist/generators.cjs.map +1 -1
  13. package/dist/generators.d.ts +86 -6
  14. package/dist/generators.esm.js +992 -156
  15. package/dist/generators.esm.js.map +1 -1
  16. package/dist/index.cjs +1019 -156
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.d.ts +103 -9
  19. package/dist/index.esm.js +1006 -157
  20. package/dist/index.esm.js.map +1 -1
  21. package/dist/registry/index.d.ts +20 -0
  22. package/dist/registry.cjs +1528 -0
  23. package/dist/registry.cjs.map +1 -0
  24. package/dist/registry.d.ts +26 -0
  25. package/dist/registry.esm.js +1523 -0
  26. package/dist/registry.esm.js.map +1 -0
  27. package/dist/seo/DigiValtRouteSeo.d.ts +12 -0
  28. package/dist/seo/DigiValtSeoHead.d.ts +2 -0
  29. package/dist/seo/buildPageJsonLd.d.ts +11 -0
  30. package/dist/seo/html.d.ts +8 -0
  31. package/dist/seo/index.d.ts +7 -0
  32. package/dist/seo/resolvePageSeo.d.ts +17 -0
  33. package/dist/seo/seoTypes.d.ts +57 -0
  34. package/dist/seo.cjs +307 -86
  35. package/dist/seo.cjs.map +1 -1
  36. package/dist/seo.d.ts +105 -2
  37. package/dist/seo.esm.js +300 -87
  38. package/dist/seo.esm.js.map +1 -1
  39. package/dist/static/wpStatic.d.ts +16 -0
  40. package/dist/static.cjs +10 -0
  41. package/dist/static.cjs.map +1 -1
  42. package/dist/static.d.ts +38 -2
  43. package/dist/static.esm.js +10 -1
  44. package/dist/static.esm.js.map +1 -1
  45. package/dist/utils/notifications.d.ts +3 -0
  46. package/docs/AI-LOCAL-WORDPRESS-BOOTSTRAP.md +7 -3
  47. package/docs/AI-MASTER-PROMPT.md +37 -0
  48. package/docs/ENVIRONMENT.md +3 -3
  49. package/docs/README.md +6 -4
  50. package/docs/SEO-AIO.md +59 -0
  51. package/docs/SEO-PERFORMANCE.md +44 -11
  52. package/docs/SHORTCODES.md +4 -5
  53. package/package.json +17 -6
  54. package/template/DIGIVALT_SETUP.md +14 -8
  55. package/template/functions/robots.txt.ts +27 -0
  56. package/template/functions/sitemap.xml.ts +143 -65
  57. package/template/scripts/generate.ts +3 -10
  58. package/template/scripts/prerender-seo.ts +10 -0
  59. package/docs/LOVABLE-MASTER-PROMPT.md +0 -140
@@ -0,0 +1,1523 @@
1
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
+ import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
3
+ import { QueryClientProvider } from '@tanstack/react-query';
4
+ import helmetAsync from 'react-helmet-async';
5
+ import { WPPage, createEnhancedRegistry } from '@marvalt/wparser';
6
+ import { MauticForm as MauticForm$1, getMauticShortcodeHandlers } from '@marvalt/madapter';
7
+ import { getPhplistShortcodeHandlers } from '@marvalt/plister';
8
+ import { useNavigate } from 'react-router-dom';
9
+ import { GravityFormsClient } from '@marvalt/wadapter';
10
+ import 'clsx';
11
+ import 'tailwind-merge';
12
+
13
+ /**
14
+ * Prefix a root-absolute path with Vite's `import.meta.env.BASE_URL`.
15
+ * Used so Pages Function URLs (`/api/...`) work when the app is built with a non-root `base`
16
+ * (e.g. path mounts via digivalt-uworker).
17
+ *
18
+ * - Absolute http(s) URLs and protocol-relative URLs are returned unchanged.
19
+ * - Empty / unset BASE_URL (`/` or `./`) leaves root-absolute paths as-is.
20
+ */
21
+ function withBasePath(path) {
22
+ if (/^https?:\/\//i.test(path) || path.startsWith("//")) {
23
+ return path;
24
+ }
25
+ const baseRaw = typeof import.meta !== "undefined" && import.meta.env && typeof import.meta.env.BASE_URL === "string"
26
+ ? import.meta.env.BASE_URL
27
+ : "/";
28
+ const base = baseRaw === "./" ? "/" : baseRaw;
29
+ if (!base || base === "/") {
30
+ return path;
31
+ }
32
+ const baseNorm = base.endsWith("/") ? base.slice(0, -1) : base;
33
+ if (path.startsWith(baseNorm + "/") || path === baseNorm) {
34
+ return path;
35
+ }
36
+ if (path.startsWith("/")) {
37
+ return `${baseNorm}${path}`;
38
+ }
39
+ return `${baseNorm}/${path}`;
40
+ }
41
+
42
+ const getImportMetaEnv = () => {
43
+ try {
44
+ return typeof import.meta !== 'undefined' ? import.meta.env : undefined;
45
+ }
46
+ catch {
47
+ return undefined;
48
+ }
49
+ };
50
+ const getEnv = (key) => {
51
+ const viteEnv = getImportMetaEnv();
52
+ if (viteEnv && key in viteEnv) {
53
+ const value = viteEnv[key];
54
+ return value == null ? undefined : String(value);
55
+ }
56
+ if (typeof process !== 'undefined' && process.env && key in process.env) {
57
+ const value = process.env[key];
58
+ return value == null ? undefined : String(value);
59
+ }
60
+ return undefined;
61
+ };
62
+ const isDevEnvironment = () => {
63
+ const viteEnv = getImportMetaEnv();
64
+ if (viteEnv && 'DEV' in viteEnv) {
65
+ return Boolean(viteEnv.DEV);
66
+ }
67
+ return typeof process !== 'undefined' && process.env?.NODE_ENV === 'development';
68
+ };
69
+ const isBrowserEnvironment = () => {
70
+ return typeof window !== 'undefined' && typeof document !== 'undefined';
71
+ };
72
+
73
+ // @ts-nocheck
74
+ // Gravity Forms data store with proper environment handling
75
+ const transformForm = (formData) => {
76
+ // Transform fields to ensure proper structure
77
+ const transformedFields = (formData.fields || []).map((field) => ({
78
+ id: field.id.toString(), // Ensure ID is string
79
+ type: field.type,
80
+ label: field.label,
81
+ description: field.description,
82
+ isRequired: field.isRequired ?? field.is_required ?? field.required ?? false,
83
+ placeholder: field.placeholder,
84
+ defaultValue: field.defaultValue ?? field.default_value,
85
+ cssClass: field.cssClass ?? field.css_class,
86
+ content: field.content,
87
+ inputs: field.inputs || null,
88
+ choices: field.choices || [],
89
+ validation: {
90
+ message: field.errorMessage ?? field.validationMessage ?? field.validation_message,
91
+ pattern: field.inputMaskValue
92
+ },
93
+ conditionalLogic: field.conditionalLogic ?? field.conditional_logic
94
+ }));
95
+ return {
96
+ id: formData.id.toString(), // Ensure ID is string
97
+ title: formData.title || formData.name || `Form ${formData.id}`,
98
+ description: formData.description,
99
+ fields: transformedFields,
100
+ button: {
101
+ text: formData.button?.text || 'Submit',
102
+ type: formData.button?.type || 'text',
103
+ imageUrl: formData.button?.imageUrl,
104
+ },
105
+ confirmation: {
106
+ type: formData.confirmation?.type || 'message',
107
+ message: formData.confirmation?.message,
108
+ url: formData.confirmation?.url,
109
+ pageId: formData.confirmation?.pageId,
110
+ queryString: formData.confirmation?.queryString,
111
+ isDefault: formData.confirmation?.isDefault,
112
+ },
113
+ settings: {
114
+ enableHoneypot: formData.enableHoneypot || false,
115
+ enableAnimation: formData.enableAnimation || false,
116
+ validationSummary: formData.validationSummary || false,
117
+ saveAndContinue: formData.save?.enabled || false,
118
+ limitEntries: {
119
+ enabled: formData.limitEntries || false,
120
+ limit: formData.limitEntriesCount,
121
+ message: formData.limitEntriesMessage
122
+ },
123
+ scheduleForm: {
124
+ enabled: formData.scheduleForm || false,
125
+ start: formData.scheduleStart,
126
+ end: formData.scheduleEnd,
127
+ message: formData.scheduleMessage
128
+ },
129
+ },
130
+ isActive: formData.isActive === true || formData.is_active === "1" || formData.is_active === true,
131
+ isPublished: formData.isPublished === true || formData.is_trash === "0" || formData.is_trash === false || formData.is_active === "1" || formData.is_active === true,
132
+ };
133
+ };
134
+ // Default fallback data
135
+ const defaultData = {
136
+ generated_at: new Date().toISOString(),
137
+ total_forms: 0,
138
+ forms: []
139
+ };
140
+ // Load static data from the generated JSON file
141
+ let gravityFormsData = defaultData;
142
+ // Function to load data dynamically
143
+ const loadGravityFormsData = async () => {
144
+ if (!isBrowserEnvironment()) {
145
+ return gravityFormsData;
146
+ }
147
+ try {
148
+ console.log('🔄 Loading Gravity Forms data from /gravity-forms-data.json...');
149
+ const response = await fetch('/gravity-forms-data.json');
150
+ if (response.ok) {
151
+ const jsonData = await response.json();
152
+ console.log('🔍 Gravity Forms Data Load Debug:', {
153
+ totalForms: jsonData.total_forms,
154
+ formsCount: jsonData.forms?.length || 0,
155
+ firstForm: jsonData.forms?.[0] ? {
156
+ id: jsonData.forms[0].id,
157
+ title: jsonData.forms[0].title,
158
+ is_active: jsonData.forms[0].is_active,
159
+ isActive: jsonData.forms[0].isActive,
160
+ isPublished: jsonData.forms[0].isPublished
161
+ } : null
162
+ });
163
+ // Transform the data to ensure it matches our interface
164
+ const transformedForms = jsonData.forms.map((form) => transformForm(form));
165
+ gravityFormsData = {
166
+ generated_at: jsonData.generated_at,
167
+ total_forms: jsonData.total_forms,
168
+ forms: transformedForms
169
+ };
170
+ console.log('🔍 Form Transformation Debug:', {
171
+ originalForms: jsonData.forms.map((f) => ({ id: f.id, title: f.title, is_active: f.is_active })),
172
+ transformedForms: transformedForms.map(f => ({ id: f.id, title: f.title, isActive: f.isActive, isPublished: f.isPublished }))
173
+ });
174
+ console.log('🔍 Transformed Forms Debug:', {
175
+ totalForms: gravityFormsData.total_forms,
176
+ formsCount: gravityFormsData.forms.length,
177
+ activeForms: gravityFormsData.forms.filter(f => f.isActive).length,
178
+ publishedForms: gravityFormsData.forms.filter(f => f.isPublished).length
179
+ });
180
+ return gravityFormsData;
181
+ }
182
+ else {
183
+ console.error('❌ Failed to load gravityForms.json:', response.status, response.statusText);
184
+ }
185
+ }
186
+ catch (error) {
187
+ console.error('❌ Error loading gravityForms.json:', error);
188
+ }
189
+ return defaultData;
190
+ };
191
+ const getFormById$1 = (id) => {
192
+ const idStr = String(id);
193
+ const idNum = typeof id === 'number' ? id : parseInt(idStr, 10);
194
+ return gravityFormsData.forms.find(form => String(form.id) === idStr || form.id === idNum);
195
+ };
196
+
197
+ /** Notify an app without depending on an app-local toast component. */
198
+ function notify(level, message) {
199
+ if (typeof window !== 'undefined') {
200
+ window.dispatchEvent(new CustomEvent('digivalt:notification', {
201
+ detail: { level, message },
202
+ }));
203
+ }
204
+ const logger = level === 'error' ? console.error : console.info;
205
+ logger(`[DigiValt] ${message}`);
206
+ }
207
+
208
+ /**
209
+ * Decodes HTML entities in a string
210
+ * Handles both named entities (&, ") and numeric entities (', ’)
211
+ * @param text - The text string with HTML entities
212
+ * @returns Decoded text string
213
+ */
214
+ function decodeHtmlEntities(text) {
215
+ if (!text)
216
+ return '';
217
+ // Use browser's built-in decoder if available (most efficient)
218
+ if (typeof document !== 'undefined') {
219
+ const textarea = document.createElement('textarea');
220
+ textarea.innerHTML = text;
221
+ return textarea.value;
222
+ }
223
+ // Fallback for server-side or when document is not available
224
+ // Decode common named entities
225
+ const namedEntities = {
226
+ '&': '&',
227
+ '&lt;': '<',
228
+ '&gt;': '>',
229
+ '&quot;': '"',
230
+ '&apos;': "'",
231
+ '&nbsp;': ' ',
232
+ '&copy;': '©',
233
+ '&reg;': '®',
234
+ '&trade;': '™',
235
+ '&hellip;': '…',
236
+ '&mdash;': '—',
237
+ '&ndash;': '–',
238
+ '&lsquo;': '\u2018', // Left single quotation mark
239
+ '&rsquo;': '\u2019', // Right single quotation mark
240
+ '&ldquo;': '\u201C', // Left double quotation mark
241
+ '&rdquo;': '\u201D', // Right double quotation mark
242
+ };
243
+ let decoded = text;
244
+ // Decode numeric entities (&#039;, &#8217;, etc.)
245
+ decoded = decoded.replace(/&#(\d+);/g, (match, dec) => {
246
+ return String.fromCharCode(parseInt(dec, 10));
247
+ });
248
+ // Decode hex entities (&#x27;, etc.)
249
+ decoded = decoded.replace(/&#x([0-9a-fA-F]+);/g, (match, hex) => {
250
+ return String.fromCharCode(parseInt(hex, 16));
251
+ });
252
+ // Decode named entities
253
+ Object.entries(namedEntities).forEach(([entity, char]) => {
254
+ decoded = decoded.replace(new RegExp(entity, 'g'), char);
255
+ });
256
+ return decoded;
257
+ }
258
+ /**
259
+ * Replaces common WordPress HTML entities so they display as expected (e.g. en dash as hyphen, &#038;/&amp; as &).
260
+ * Use on block innerHTML or other WP-rendered HTML before passing to dangerouslySetInnerHTML.
261
+ */
262
+ function normalizeWordPressHtmlEntities(html) {
263
+ if (!html)
264
+ return '';
265
+ return decodeHtmlEntities(html.replace(/&#8211;/g, '-'));
266
+ }
267
+ /**
268
+ * Validates if a URL is safe for redirects
269
+ * @param url - The URL to validate
270
+ * @param allowedDomains - Array of allowed domains (optional)
271
+ * @returns boolean indicating if the URL is safe
272
+ */
273
+ function isValidRedirectUrl(url, allowedDomains = []) {
274
+ if (!url)
275
+ return false;
276
+ try {
277
+ const urlObj = new URL(url);
278
+ // Check if it's a relative URL (safe)
279
+ if (!urlObj.protocol)
280
+ return true;
281
+ // Check if it's HTTP/HTTPS
282
+ if (!['http:', 'https:'].includes(urlObj.protocol))
283
+ return false;
284
+ // If allowed domains are specified, check against them
285
+ if (allowedDomains.length > 0) {
286
+ return allowedDomains.some(domain => urlObj.hostname === domain || urlObj.hostname.endsWith(`.${domain}`));
287
+ }
288
+ // Default: allow any HTTPS URL or same-origin HTTP
289
+ return urlObj.protocol === 'https:' || urlObj.hostname === window.location.hostname;
290
+ }
291
+ catch {
292
+ return false;
293
+ }
294
+ }
295
+ /**
296
+ * Safely redirects to a URL after validation
297
+ * @param url - The URL to redirect to
298
+ * @param allowedDomains - Array of allowed domains (optional)
299
+ * @param fallbackUrl - Fallback URL if validation fails (optional)
300
+ */
301
+ function safeRedirect(url, allowedDomains = [], fallbackUrl) {
302
+ if (isValidRedirectUrl(url, allowedDomains)) {
303
+ window.location.href = url;
304
+ }
305
+ else {
306
+ console.warn('Invalid redirect URL:', url);
307
+ }
308
+ }
309
+
310
+ // @ts-nocheck
311
+ // Minimal browser-safe static data loader to avoid importing Node-only code in the runtime bundle.
312
+ /** Recursively normalize WordPress HTML entities (e.g. &#8211; → "-") in block innerHTML. */
313
+ function normalizeBlocksHtml(blocks) {
314
+ if (!blocks)
315
+ return;
316
+ for (const block of blocks) {
317
+ if (block.innerHTML && typeof block.innerHTML === 'string') {
318
+ block.innerHTML = normalizeWordPressHtmlEntities(block.innerHTML);
319
+ }
320
+ if (block.innerBlocks?.length)
321
+ normalizeBlocksHtml(block.innerBlocks);
322
+ }
323
+ }
324
+ /** Recursively decode HTML entities in all string values of an event_meta-like object (mutate in place). */
325
+ function normalizeEventMetaStrings(meta) {
326
+ for (const key of Object.keys(meta)) {
327
+ const v = meta[key];
328
+ if (typeof v === 'string') {
329
+ meta[key] = decodeHtmlEntities(v);
330
+ }
331
+ else if (Array.isArray(v)) {
332
+ for (let i = 0; i < v.length; i++) {
333
+ const el = v[i];
334
+ if (typeof el === 'string') {
335
+ v[i] = decodeHtmlEntities(el);
336
+ }
337
+ else if (el && typeof el === 'object' && !Array.isArray(el)) {
338
+ normalizeEventMetaStrings(el);
339
+ }
340
+ }
341
+ }
342
+ }
343
+ }
344
+ /** Normalize title.rendered, excerpt.rendered, content.rendered, content_cloudflare on a WP-like item (mutate in place). */
345
+ function normalizeRenderedStrings(item) {
346
+ if (!item || typeof item !== 'object')
347
+ return;
348
+ if (typeof item.title?.rendered === 'string') {
349
+ item.title.rendered = normalizeWordPressHtmlEntities(item.title.rendered);
350
+ }
351
+ if (typeof item.excerpt?.rendered === 'string') {
352
+ item.excerpt.rendered = normalizeWordPressHtmlEntities(item.excerpt.rendered);
353
+ }
354
+ if (typeof item.content?.rendered === 'string') {
355
+ item.content.rendered = normalizeWordPressHtmlEntities(item.content.rendered);
356
+ }
357
+ if (typeof item.content_cloudflare === 'string') {
358
+ item.content_cloudflare = normalizeWordPressHtmlEntities(item.content_cloudflare);
359
+ }
360
+ }
361
+ /**
362
+ * Mask email for privacy: first char of local + ***@****** + last char of domain name + TLD.
363
+ * Example: name@example.com.au → n***@******e.com.au
364
+ */
365
+ function maskEmail(email) {
366
+ const s = typeof email === 'string' ? email.trim() : '';
367
+ if (!s || !s.includes('@'))
368
+ return '***@***.***';
369
+ const parts = s.split('@', 2);
370
+ const local = parts[0];
371
+ const domain = parts[1];
372
+ if (!local || !domain)
373
+ return '***@***.***';
374
+ const localFirst = local.slice(0, 1);
375
+ const domainBits = domain.split('.');
376
+ if (domainBits.length < 2)
377
+ return localFirst + '***@******.' + domain;
378
+ const domainName = domainBits.shift() ?? '';
379
+ const tld = domainBits.join('.');
380
+ const domainLast = domainName.slice(-1);
381
+ return localFirst + '***@******' + domainLast + '.' + tld;
382
+ }
383
+ /** Replace raw members_email with masked value on each member in member arrays. */
384
+ function maskMemberEmailsInStaticData(data) {
385
+ if (!data)
386
+ return;
387
+ const memberKeys = ['chapter_member', 'members', 'member'];
388
+ const dataRecord = data;
389
+ for (const key of memberKeys) {
390
+ const arr = dataRecord[key];
391
+ if (!Array.isArray(arr))
392
+ continue;
393
+ for (const item of arr) {
394
+ if (item && typeof item === 'object') {
395
+ const obj = item;
396
+ if (obj.member_meta && typeof obj.member_meta === 'object') {
397
+ const meta = obj.member_meta;
398
+ if (meta.members_email != null)
399
+ meta.members_email = maskEmail(meta.members_email);
400
+ }
401
+ if (obj.public_profile && typeof obj.public_profile === 'object') {
402
+ const profile = obj.public_profile;
403
+ if (profile.members_email != null)
404
+ profile.members_email = maskEmail(profile.members_email);
405
+ }
406
+ }
407
+ }
408
+ }
409
+ }
410
+ /** Walk static data and normalize block HTML and .rendered/content fields so entities like &#8211; display correctly. */
411
+ function normalizeWordPressHtmlInStaticData(data) {
412
+ if (!data)
413
+ return;
414
+ if (data.pages) {
415
+ for (const page of data.pages) {
416
+ normalizeRenderedStrings(page);
417
+ if (page.blocks)
418
+ normalizeBlocksHtml(page.blocks);
419
+ }
420
+ }
421
+ if (data.posts) {
422
+ for (const post of data.posts) {
423
+ normalizeRenderedStrings(post);
424
+ }
425
+ }
426
+ const cptKeys = ['eventbrite_event', 'member', 'testimonial', 'chapter_member', 'members'];
427
+ const dataRecord = data;
428
+ for (const key of cptKeys) {
429
+ const arr = dataRecord[key];
430
+ if (Array.isArray(arr)) {
431
+ for (const item of arr) {
432
+ normalizeRenderedStrings(item);
433
+ if (key === 'eventbrite_event' && item?.event_meta && typeof item.event_meta === 'object' && !Array.isArray(item.event_meta)) {
434
+ normalizeEventMetaStrings(item.event_meta);
435
+ }
436
+ }
437
+ }
438
+ }
439
+ if (data.site_settings && typeof data.site_settings === 'object') {
440
+ const settings = data.site_settings;
441
+ if (typeof settings.name === 'string')
442
+ settings.name = normalizeWordPressHtmlEntities(settings.name);
443
+ if (typeof settings.description === 'string')
444
+ settings.description = normalizeWordPressHtmlEntities(settings.description);
445
+ }
446
+ if (data.header?.blocks)
447
+ normalizeBlocksHtml(data.header.blocks);
448
+ if (data.footer?.blocks)
449
+ normalizeBlocksHtml(data.footer.blocks);
450
+ }
451
+ let wpStaticCache = null;
452
+ const loadWordPressData = async (path = '/wordpress-data.json') => {
453
+ if (wpStaticCache)
454
+ return;
455
+ const res = await fetch(path);
456
+ if (!res.ok)
457
+ throw new Error(`Failed to load WordPress static data: ${res.status}`);
458
+ wpStaticCache = (await res.json());
459
+ normalizeWordPressHtmlInStaticData(wpStaticCache);
460
+ maskMemberEmailsInStaticData(wpStaticCache);
461
+ // Expose cache globally for theme loading (temporary workaround)
462
+ if (typeof window !== 'undefined') {
463
+ window.__wpStaticCache = wpStaticCache;
464
+ }
465
+ };
466
+ const getWordPressPages = () => wpStaticCache?.pages ?? [];
467
+ const getWordPressPageBySlug = (slug) => {
468
+ const pages = getWordPressPages();
469
+ return pages.find(page => page.slug === slug);
470
+ };
471
+ const getWordPressPageById = (id) => {
472
+ const pages = getWordPressPages();
473
+ return pages.find(page => page.id === id);
474
+ };
475
+
476
+ const TurnstileWidget = ({ siteKey, action, cData, onSuccess, onError, onExpire, theme = 'auto', size = 'normal', tabIndex, onWidgetId, }) => {
477
+ const widgetRef = useRef(null);
478
+ const widgetId = useRef(null);
479
+ const scriptLoaded = useRef(false);
480
+ useEffect(() => {
481
+ if (!widgetRef.current || !siteKey)
482
+ return;
483
+ const loadTurnstile = () => {
484
+ if (window.turnstile && widgetRef.current && !widgetId.current) {
485
+ try {
486
+ widgetId.current = window.turnstile.render(widgetRef.current, {
487
+ sitekey: siteKey,
488
+ callback: onSuccess,
489
+ 'error-callback': onError,
490
+ 'expired-callback': onExpire,
491
+ theme,
492
+ size,
493
+ tabindex: tabIndex,
494
+ });
495
+ // Notify parent component of widget ID for reset capability
496
+ if (widgetId.current && onWidgetId) {
497
+ onWidgetId(widgetId.current);
498
+ }
499
+ }
500
+ catch (error) {
501
+ console.error('Failed to render Turnstile widget:', error);
502
+ onError?.();
503
+ }
504
+ }
505
+ };
506
+ // Check if Turnstile is already loaded
507
+ if (window.turnstile) {
508
+ loadTurnstile();
509
+ }
510
+ else if (!scriptLoaded.current) {
511
+ // Load Turnstile script
512
+ scriptLoaded.current = true;
513
+ const script = document.createElement('script');
514
+ script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js';
515
+ script.async = true;
516
+ script.defer = true;
517
+ script.onload = loadTurnstile;
518
+ script.onerror = () => {
519
+ console.error('Failed to load Turnstile script');
520
+ onError?.();
521
+ };
522
+ document.head.appendChild(script);
523
+ }
524
+ return () => {
525
+ if (widgetId.current && window.turnstile) {
526
+ try {
527
+ window.turnstile.remove(widgetId.current);
528
+ }
529
+ catch (error) {
530
+ console.error('Failed to remove Turnstile widget:', error);
531
+ }
532
+ widgetId.current = null;
533
+ }
534
+ };
535
+ }, [siteKey, onSuccess, onError, onExpire, theme, size, tabIndex]);
536
+ return jsx("div", { ref: widgetRef, className: "cf-turnstile" });
537
+ };
538
+ const StaticGravityForm = ({ formId, config, className = '', onSubmit, onError, }) => {
539
+ const navigate = useNavigate();
540
+ const [form, setForm] = useState(null);
541
+ const [loading, setLoading] = useState(true);
542
+ const [error, setError] = useState(null); // For loading/data errors only
543
+ const [submissionError, setSubmissionError] = useState(null); // For submission errors only
544
+ const [submitting, setSubmitting] = useState(false);
545
+ const [result, setResult] = useState(null);
546
+ const [submitted, setSubmitted] = useState(false); // Track if form was successfully submitted
547
+ const [formData, setFormData] = useState({});
548
+ const [turnstileToken, setTurnstileToken] = useState(null);
549
+ const [turnstileError, setTurnstileError] = useState(null);
550
+ const turnstileWidgetIdRef = useRef(null);
551
+ // Load form from static data
552
+ useEffect(() => {
553
+ const loadForm = async () => {
554
+ try {
555
+ setLoading(true);
556
+ setError(null);
557
+ if (process.env.NODE_ENV !== 'production') {
558
+ console.log('🔍 StaticGravityForm: Loading form', { formId, formIdType: typeof formId });
559
+ }
560
+ // Ensure static data is loaded
561
+ const dataStore = await loadGravityFormsData();
562
+ if (process.env.NODE_ENV !== 'production') {
563
+ console.log('🔍 StaticGravityForm: Data loaded', {
564
+ totalForms: dataStore?.total_forms,
565
+ formsCount: dataStore?.forms?.length,
566
+ availableFormIds: dataStore?.forms?.map(f => f.id),
567
+ });
568
+ }
569
+ // Get form from static store - try both string and number formats
570
+ const formIdStr = String(formId);
571
+ const formIdNum = typeof formId === 'number' ? formId : parseInt(formIdStr, 10);
572
+ let staticForm = getFormById$1(formIdStr);
573
+ // If not found with string, try with number as string
574
+ if (!staticForm && !isNaN(formIdNum)) {
575
+ staticForm = getFormById$1(String(formIdNum));
576
+ }
577
+ if (process.env.NODE_ENV !== 'production') {
578
+ console.log('🔍 StaticGravityForm: Form lookup', {
579
+ formId,
580
+ formIdStr,
581
+ formIdNum,
582
+ found: !!staticForm,
583
+ formTitle: staticForm?.title,
584
+ });
585
+ }
586
+ if (!staticForm) {
587
+ const errorMsg = `Form with ID ${formId} not found in static data. Please ensure the form exists in /gravity-forms-data.json and run 'npm run generate:gf' to regenerate static data.`;
588
+ console.error('❌ StaticGravityForm:', errorMsg);
589
+ setError(new Error(errorMsg));
590
+ setLoading(false);
591
+ return;
592
+ }
593
+ setForm(staticForm);
594
+ if (process.env.NODE_ENV !== 'production') {
595
+ console.log('✅ StaticGravityForm: Form loaded successfully', {
596
+ formId: staticForm.id,
597
+ title: staticForm.title,
598
+ fieldsCount: staticForm.fields?.length,
599
+ });
600
+ }
601
+ }
602
+ catch (err) {
603
+ const error = err instanceof Error ? err : new Error('Failed to load form from static data');
604
+ console.error('❌ StaticGravityForm error:', error);
605
+ setError(error);
606
+ if (onError) {
607
+ onError(error);
608
+ }
609
+ }
610
+ finally {
611
+ setLoading(false);
612
+ }
613
+ };
614
+ loadForm();
615
+ }, [formId, onError]);
616
+ // Get Turnstile site key from environment - memoized to prevent re-renders
617
+ const turnstilesiteKey = useMemo(() => {
618
+ try {
619
+ // @ts-ignore - import.meta is a Vite-specific global
620
+ if (typeof import.meta !== 'undefined' && import.meta.env) {
621
+ // @ts-ignore
622
+ const key = import.meta.env.VITE_TURNSTILE_SITE_KEY;
623
+ // Ensure we return a string or undefined, not an object
624
+ return typeof key === 'string' ? key : undefined;
625
+ }
626
+ }
627
+ catch (e) {
628
+ // import.meta not available
629
+ }
630
+ return undefined;
631
+ }, []); // Empty deps - site key doesn't change during runtime
632
+ // Memoize Turnstile callbacks to prevent widget re-renders
633
+ const handleTurnstileSuccess = useCallback((token) => {
634
+ setTurnstileToken(token);
635
+ setTurnstileError(null);
636
+ }, []);
637
+ const handleTurnstileError = useCallback(() => {
638
+ setTurnstileToken(null);
639
+ setTurnstileError('Verification failed. Please try again.');
640
+ }, []);
641
+ const handleTurnstileExpire = useCallback(() => {
642
+ setTurnstileToken(null);
643
+ setTurnstileError('Verification expired. Please verify again.');
644
+ }, []);
645
+ // Handle form submission using API
646
+ const handleSubmit = async (e) => {
647
+ e.preventDefault();
648
+ // Check Turnstile token if enabled
649
+ if (turnstilesiteKey && !turnstileToken) {
650
+ setTurnstileError('Please complete the verification');
651
+ return;
652
+ }
653
+ if (!form) {
654
+ const error = new Error('Form data not available');
655
+ setError(error);
656
+ if (onError) {
657
+ onError(error);
658
+ }
659
+ return;
660
+ }
661
+ console.log('🔍 StaticGravityForm.handleSubmit:', {
662
+ formId,
663
+ formData,
664
+ formDataKeys: Object.keys(formData),
665
+ turnstileToken,
666
+ });
667
+ try {
668
+ setSubmitting(true);
669
+ setSubmissionError(null);
670
+ setResult(null);
671
+ // Create GravityFormsClient for submission only
672
+ const client = new GravityFormsClient({
673
+ ...config,
674
+ proxyEndpoint: config.proxyEndpoint || withBasePath('/api/gravity-forms-submit'),
675
+ });
676
+ const submission = {
677
+ form_id: parseInt(String(formId), 10),
678
+ field_values: formData,
679
+ ...(turnstileToken ? {
680
+ headers: {
681
+ 'cf-turnstile-response': turnstileToken
682
+ }
683
+ } : {})
684
+ };
685
+ console.log('🔍 StaticGravityForm submission object:', submission);
686
+ // Submit form via API
687
+ const submissionResult = await client.submitForm(parseInt(String(formId), 10), submission);
688
+ setResult(submissionResult);
689
+ // Clear form data after successful submission
690
+ setFormData({});
691
+ // Reset Turnstile widget if present
692
+ if (turnstileWidgetIdRef.current && window.turnstile) {
693
+ try {
694
+ window.turnstile.reset(turnstileWidgetIdRef.current);
695
+ }
696
+ catch (e) {
697
+ console.warn('Failed to reset Turnstile widget:', e);
698
+ }
699
+ }
700
+ setTurnstileToken(null);
701
+ setTurnstileError(null);
702
+ // Mark form as submitted
703
+ setSubmitted(true);
704
+ // Show success toast
705
+ notify('success', submissionResult.message || 'Form submitted successfully!');
706
+ // Handle confirmation types
707
+ const confirmation = submissionResult.confirmation;
708
+ if (confirmation) {
709
+ if (confirmation.type === 'redirect' && confirmation.url) {
710
+ // Redirect to URL
711
+ setTimeout(() => {
712
+ safeRedirect(confirmation.url);
713
+ }, 1500); // Small delay to show success message
714
+ }
715
+ else if (confirmation.type === 'page' && (confirmation.pageId || confirmation.page_id)) {
716
+ // Resolve page slug from ID and navigate
717
+ // Handle both camelCase (pageId) and snake_case (page_id) from API
718
+ const pageId = confirmation.pageId || confirmation.page_id;
719
+ // Load WordPress data if not already loaded, then resolve page
720
+ loadWordPressData().then(() => {
721
+ const page = getWordPressPageById(Number(pageId));
722
+ if (page?.slug) {
723
+ setTimeout(() => {
724
+ navigate(`/${page.slug}`);
725
+ }, 1500); // Small delay to show success message
726
+ }
727
+ else {
728
+ console.warn(`Page with ID ${pageId} not found in static data`);
729
+ }
730
+ }).catch((err) => {
731
+ console.error('Failed to load WordPress data for page redirect:', err);
732
+ });
733
+ }
734
+ // For 'message' type, we'll show the confirmation message in the UI
735
+ }
736
+ if (onSubmit) {
737
+ onSubmit(submissionResult);
738
+ }
739
+ }
740
+ catch (err) {
741
+ const error = err instanceof Error ? err : new Error('Unknown error');
742
+ console.error('❌ StaticGravityForm submission error:', error);
743
+ console.error('🔍 Error details:', {
744
+ message: error.message,
745
+ data: error.data,
746
+ validation_errors: error.validation_errors,
747
+ code: error.code,
748
+ });
749
+ // Determine error type and show appropriate message
750
+ let errorMessage = 'Form submission failed. Please try again.';
751
+ // Check if this is a CORS or network error
752
+ // Only show "Wrangler not running" if it's a clear network failure (ERR_FAILED, network error)
753
+ // Not for generic "Failed to fetch" which can happen for many reasons
754
+ const isNetworkError = error.message.includes('ERR_FAILED') ||
755
+ error.message.includes('NetworkError') ||
756
+ (error.message.includes('Failed to fetch') && !error.message.includes('403') && !error.message.includes('404') && !error.message.includes('500'));
757
+ const isCorsError = error.message.includes('CORS') || error.message.includes('Access-Control');
758
+ if (isNetworkError && config.proxyEndpoint?.includes('127.0.0.1:8788')) {
759
+ // Only show Wrangler error for clear network failures when using Wrangler proxy
760
+ errorMessage = 'Unable to connect to Wrangler development server. Please ensure it is running with `npm run pages:dev` on port 8788, or disable VITE_LOCAL_DEVELOPMENT to use the production proxy.';
761
+ }
762
+ else if (isCorsError) {
763
+ errorMessage = 'CORS error: The server is not allowing requests from this origin. Please check server configuration.';
764
+ }
765
+ else if (isNetworkError) {
766
+ errorMessage = 'Unable to connect to form server. Please check your connection or try again later.';
767
+ }
768
+ else if (error.message.includes('404') || error.message.includes('Not Found')) {
769
+ errorMessage = 'Form submission endpoint not found. Please contact support.';
770
+ }
771
+ else if (error.message.includes('403') || error.message.includes('Forbidden')) {
772
+ errorMessage = 'Form submission was denied. Please check your permissions.';
773
+ }
774
+ else if (error.message.includes('400') || error.message.includes('Bad Request')) {
775
+ // Try to extract validation errors from the error object
776
+ // WordPress REST API format: { code, message, data: { status, validation_errors } }
777
+ const errorData = error.data;
778
+ const validationErrors = error.validation_errors || errorData?.data?.validation_errors || errorData?.validation_errors;
779
+ if (validationErrors && typeof validationErrors === 'object') {
780
+ // Format validation errors for display
781
+ const errorList = Object.entries(validationErrors)
782
+ .map(([field, message]) => {
783
+ // Try to get field label from form if available
784
+ // For name fields, check if it's a sub-input (e.g., "1.3") and find parent field
785
+ let fieldObj = form?.fields?.find((f) => String(f.id) === String(field));
786
+ // If not found, it might be a sub-input of a name field
787
+ if (!fieldObj && field.includes('.')) {
788
+ const parentFieldId = field.split('.')[0];
789
+ fieldObj = form?.fields?.find((f) => String(f.id) === String(parentFieldId));
790
+ // If it's a name field, use the parent field's label
791
+ if (fieldObj?.type === 'name') {
792
+ return `${decodeHtmlEntities(fieldObj.label)}: ${message}`;
793
+ }
794
+ }
795
+ const fieldLabel = fieldObj?.label ? decodeHtmlEntities(fieldObj.label) : `Field ${field}`;
796
+ return `${fieldLabel}: ${message}`;
797
+ })
798
+ .join('; ');
799
+ errorMessage = `Validation failed: ${errorList}`;
800
+ }
801
+ else if (error.message.includes('Validation failed')) {
802
+ errorMessage = 'Form validation failed. Please check all required fields are filled correctly.';
803
+ }
804
+ else {
805
+ // Use the error message from WordPress
806
+ errorMessage = error.message || 'Form submission failed. Please try again.';
807
+ }
808
+ }
809
+ else if (error.message.includes('Network') || error.message.includes('network')) {
810
+ errorMessage = 'Network error. Please check your internet connection and try again.';
811
+ }
812
+ else if (error.message) {
813
+ // Use the error message if it's user-friendly
814
+ errorMessage = error.message;
815
+ }
816
+ setSubmissionError(error);
817
+ // Show error toast
818
+ notify('error', errorMessage);
819
+ if (onError) {
820
+ onError(error);
821
+ }
822
+ }
823
+ finally {
824
+ setSubmitting(false);
825
+ }
826
+ };
827
+ const handleFieldChange = (fieldId, value) => {
828
+ setFormData(prev => ({
829
+ ...prev,
830
+ [fieldId]: value,
831
+ }));
832
+ };
833
+ // Loading state
834
+ if (loading) {
835
+ return jsx("div", { className: `gravity-form loading ${className}`, children: "Loading form..." });
836
+ }
837
+ // Loading/Data error state (not submission errors)
838
+ if (error) {
839
+ return (jsxs("div", { className: `gravity-form error ${className}`, children: [jsxs("p", { children: ["Error: ", error.message] }), process.env.NODE_ENV !== 'production' && (jsx("p", { className: "text-sm text-gray-500 mt-2", children: "Make sure the form exists in /gravity-forms-data.json and run `npm run generate:gf` to regenerate static data." }))] }));
840
+ }
841
+ // Form not found state
842
+ if (!form) {
843
+ return (jsxs("div", { className: `gravity-form not-found ${className}`, children: [jsx("p", { children: "Form not found" }), process.env.NODE_ENV !== 'production' && (jsxs("p", { className: "text-sm text-gray-500 mt-2", children: ["Form ID: ", formId, ". Check /gravity-forms-data.json or run `npm run generate:gf`."] }))] }));
844
+ }
845
+ // Show confirmation message if form was submitted and confirmation type is 'message'
846
+ const confirmation = result?.confirmation;
847
+ const showConfirmation = submitted && confirmation?.type === 'message';
848
+ return (jsx("div", { className: `gravity-form max-w-2xl mx-auto ${className}`, children: showConfirmation ? (
849
+ // Show confirmation message instead of form
850
+ jsxs("div", { className: "space-y-6 bg-white/95 backdrop-blur-sm p-6 md:p-8 rounded-lg shadow-lg", children: [form.title && (jsx("h2", { className: "text-2xl md:text-3xl font-bold mb-4 text-gray-900", children: form.title })), jsx("div", { className: "rounded-md bg-green-50 px-4 py-3 text-sm text-green-800 border border-green-200", children: confirmation?.message || result?.message || 'Thank you for your submission!' })] })) : (
851
+ // Show form
852
+ jsxs("form", { onSubmit: handleSubmit, className: "space-y-6 bg-white/95 backdrop-blur-sm p-6 md:p-8 rounded-lg shadow-lg", children: [form.title && (jsx("h2", { className: "text-2xl md:text-3xl font-bold mb-4 text-gray-900", children: form.title })), form.description && (jsx("p", { className: "text-gray-600 mb-6", children: decodeHtmlEntities(form.description) })), form.fields.map(field => (jsxs("div", { className: `field field-${field.type} space-y-2`, children: [field.type !== 'html' && (jsxs("label", { htmlFor: `field_${field.id}`, className: "block text-sm font-medium text-gray-700", children: [decodeHtmlEntities(field.label), field.isRequired && jsx("span", { className: "text-red-500 ml-1", children: "*" })] })), field.type !== 'html' && field.description && (jsx("p", { className: "field-description text-sm text-gray-500", children: decodeHtmlEntities(field.description) })), field.type === 'html' && (jsx("div", { className: "gf-html-field prose max-w-none text-gray-700", dangerouslySetInnerHTML: { __html: decodeHtmlEntities(field.content || field.description || '') } })), field.type === 'text' && (jsx("input", { type: "text", id: `field_${field.id}`, name: field.label, required: field.isRequired, placeholder: field.placeholder ? decodeHtmlEntities(field.placeholder) : undefined, value: formData[field.id] || field.defaultValue || '', onChange: (e) => handleFieldChange(field.id, e.target.value), className: "w-full px-4 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white" })), field.type === 'email' && (jsx("input", { type: "email", id: `field_${field.id}`, name: field.label, required: field.isRequired, placeholder: field.placeholder ? decodeHtmlEntities(field.placeholder) : undefined, value: formData[field.id] || field.defaultValue || '', onChange: (e) => handleFieldChange(field.id, e.target.value), className: "w-full px-4 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white" })), field.type === 'textarea' && (jsx("textarea", { id: `field_${field.id}`, name: field.label, required: field.isRequired, placeholder: field.placeholder ? decodeHtmlEntities(field.placeholder) : undefined, value: formData[field.id] || field.defaultValue || '', onChange: (e) => handleFieldChange(field.id, e.target.value), rows: 4, className: "w-full px-4 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white resize-y" })), field.type === 'select' && field.choices && (jsxs("select", { id: `field_${field.id}`, name: field.label, required: field.isRequired, value: formData[field.id] || field.defaultValue || (field.choices.find(c => c.isSelected)?.value || ''), onChange: (e) => handleFieldChange(field.id, e.target.value), className: "w-full px-4 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white", children: [jsx("option", { value: "", children: "Select an option" }), field.choices.map((choice, index) => (jsx("option", { value: choice.value, children: decodeHtmlEntities(choice.text) }, index)))] })), field.type === 'name' && field.inputs && (jsx("div", { className: "name-field-inputs grid grid-cols-1 md:grid-cols-2 gap-4", children: field.inputs
853
+ .filter((input) => !input.isHidden)
854
+ .map((input) => (jsxs("div", { className: "name-input space-y-2", children: [jsxs("label", { htmlFor: `field_${input.id}`, className: "block text-sm font-medium text-gray-700", children: [input.label, field.isRequired && input.label.toLowerCase().includes('first') && (jsx("span", { className: "text-red-500 ml-1", children: "*" }))] }), input.choices ? (jsxs("select", { id: `field_${input.id}`, name: input.name || input.label, onChange: (e) => handleFieldChange(input.id, e.target.value), className: "w-full px-4 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white", children: [jsxs("option", { value: "", children: ["Select ", decodeHtmlEntities(input.label)] }), input.choices.map((choice, index) => (jsx("option", { value: choice.value, children: decodeHtmlEntities(choice.text) }, index)))] })) : (jsx("input", { type: "text", id: `field_${input.id}`, name: input.name || input.label, placeholder: input.placeholder ? decodeHtmlEntities(input.placeholder) : undefined, required: field.isRequired && input.label.toLowerCase().includes('first'), autoComplete: input.autocompleteAttribute, value: formData[input.id] || '', onChange: (e) => handleFieldChange(input.id, e.target.value), className: "w-full px-4 py-2 border border-gray-300 rounded-md shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-gray-900 bg-white" }))] }, input.id))) }))] }, field.id))), turnstilesiteKey && (jsxs("div", { className: "form-turnstile flex justify-center py-4", children: [jsx(TurnstileWidget, { siteKey: turnstilesiteKey, onSuccess: handleTurnstileSuccess, onError: handleTurnstileError, onExpire: handleTurnstileExpire, onWidgetId: (id) => { turnstileWidgetIdRef.current = id; }, theme: "auto", size: "normal" }), turnstileError && (jsx("p", { className: "field-error turnstile-error text-red-600 text-sm mt-2", children: turnstileError }))] })), jsx("button", { type: "submit", disabled: submitting || (!!turnstilesiteKey && !turnstileToken), className: "w-full md:w-auto px-6 py-3 bg-blue-600 hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed text-white font-semibold rounded-md shadow-md transition-colors duration-200", children: submitting
855
+ ? 'Submitting...'
856
+ : (turnstilesiteKey && !turnstileToken)
857
+ ? 'Complete verification first'
858
+ : form.button?.text || 'Submit' }), result && !result.success && (jsx("div", { className: `result p-4 rounded-md bg-red-50 text-red-800 border border-red-200`, children: result.message }))] })) }));
859
+ };
860
+
861
+ var forms = [
862
+ {
863
+ id: 3,
864
+ name: "Eventbright Form",
865
+ alias: "eventbrigh",
866
+ description: null,
867
+ isPublished: true,
868
+ fields: [
869
+ {
870
+ id: 10,
871
+ label: "First Name",
872
+ showLabel: true,
873
+ alias: "first_name",
874
+ type: "text",
875
+ defaultValue: null,
876
+ isRequired: true,
877
+ validationMessage: null,
878
+ helpMessage: null,
879
+ order: 1,
880
+ properties: {
881
+ placeholder: null
882
+ },
883
+ validation: [
884
+ ],
885
+ parent: null,
886
+ conditions: [
887
+ ],
888
+ labelAttributes: null,
889
+ inputAttributes: null,
890
+ containerAttributes: null,
891
+ leadField: "firstname",
892
+ saveResult: true,
893
+ isAutoFill: true,
894
+ isReadOnly: false,
895
+ mappedObject: "contact",
896
+ mappedField: "firstname"
897
+ },
898
+ {
899
+ id: 11,
900
+ label: "Last Name",
901
+ showLabel: true,
902
+ alias: "last_name",
903
+ type: "text",
904
+ defaultValue: null,
905
+ isRequired: true,
906
+ validationMessage: null,
907
+ helpMessage: null,
908
+ order: 2,
909
+ properties: {
910
+ placeholder: null
911
+ },
912
+ validation: [
913
+ ],
914
+ parent: null,
915
+ conditions: [
916
+ ],
917
+ labelAttributes: null,
918
+ inputAttributes: null,
919
+ containerAttributes: null,
920
+ leadField: "lastname",
921
+ saveResult: true,
922
+ isAutoFill: true,
923
+ isReadOnly: false,
924
+ mappedObject: "contact",
925
+ mappedField: "lastname"
926
+ },
927
+ {
928
+ id: 8,
929
+ label: "Email",
930
+ showLabel: true,
931
+ alias: "email",
932
+ type: "email",
933
+ defaultValue: null,
934
+ isRequired: true,
935
+ validationMessage: null,
936
+ helpMessage: null,
937
+ order: 3,
938
+ properties: {
939
+ placeholder: null
940
+ },
941
+ validation: [
942
+ ],
943
+ parent: null,
944
+ conditions: [
945
+ ],
946
+ labelAttributes: null,
947
+ inputAttributes: null,
948
+ containerAttributes: null,
949
+ leadField: "email",
950
+ saveResult: true,
951
+ isAutoFill: true,
952
+ isReadOnly: false,
953
+ mappedObject: "contact",
954
+ mappedField: "email"
955
+ },
956
+ {
957
+ id: 9,
958
+ label: "Submit",
959
+ showLabel: true,
960
+ alias: "submit",
961
+ type: "button",
962
+ defaultValue: null,
963
+ isRequired: false,
964
+ validationMessage: null,
965
+ helpMessage: null,
966
+ order: 4,
967
+ properties: [
968
+ ],
969
+ validation: [
970
+ ],
971
+ parent: null,
972
+ conditions: [
973
+ ],
974
+ labelAttributes: null,
975
+ inputAttributes: "class=\"btn btn-ghost\"",
976
+ containerAttributes: null,
977
+ leadField: null,
978
+ saveResult: true,
979
+ isAutoFill: false,
980
+ isReadOnly: false,
981
+ mappedObject: null,
982
+ mappedField: null
983
+ }
984
+ ],
985
+ actions: [
986
+ {
987
+ id: 1,
988
+ name: "Email",
989
+ description: null,
990
+ type: "lead.addutmtags",
991
+ order: 1,
992
+ properties: [
993
+ ]
994
+ },
995
+ {
996
+ id: 2,
997
+ name: "THank You Notif 1",
998
+ description: null,
999
+ type: "email.send.user",
1000
+ order: 2,
1001
+ properties: {
1002
+ useremail: {
1003
+ email: "2"
1004
+ },
1005
+ user_id: [
1006
+ 1
1007
+ ]
1008
+ }
1009
+ },
1010
+ {
1011
+ id: 3,
1012
+ name: "Registered +10 (HOT)",
1013
+ description: null,
1014
+ type: "lead.changetags",
1015
+ order: 3,
1016
+ properties: {
1017
+ add_tags: [
1018
+ "HOT"
1019
+ ],
1020
+ remove_tags: [
1021
+ ]
1022
+ }
1023
+ }
1024
+ ],
1025
+ postAction: "message",
1026
+ postActionProperty: "Thanks for your submission. An email will be sent to you shortly.",
1027
+ formType: "campaign"
1028
+ },
1029
+ {
1030
+ id: 2,
1031
+ name: "second form",
1032
+ alias: "second_for",
1033
+ description: null,
1034
+ isPublished: true,
1035
+ fields: [
1036
+ {
1037
+ id: 4,
1038
+ label: "Name",
1039
+ showLabel: false,
1040
+ alias: "f_name",
1041
+ type: "text",
1042
+ defaultValue: null,
1043
+ isRequired: true,
1044
+ validationMessage: "this field is required",
1045
+ helpMessage: null,
1046
+ order: 1,
1047
+ properties: {
1048
+ placeholder: "your first name"
1049
+ },
1050
+ validation: [
1051
+ ],
1052
+ parent: null,
1053
+ conditions: [
1054
+ ],
1055
+ labelAttributes: null,
1056
+ inputAttributes: null,
1057
+ containerAttributes: null,
1058
+ leadField: "firstname",
1059
+ saveResult: true,
1060
+ isAutoFill: false,
1061
+ isReadOnly: false,
1062
+ mappedObject: "contact",
1063
+ mappedField: "firstname"
1064
+ },
1065
+ {
1066
+ id: 5,
1067
+ label: "Email",
1068
+ showLabel: true,
1069
+ alias: "email",
1070
+ type: "email",
1071
+ defaultValue: null,
1072
+ isRequired: true,
1073
+ validationMessage: "this is a required field",
1074
+ helpMessage: null,
1075
+ order: 2,
1076
+ properties: {
1077
+ placeholder: "email"
1078
+ },
1079
+ validation: [
1080
+ ],
1081
+ parent: null,
1082
+ conditions: [
1083
+ ],
1084
+ labelAttributes: null,
1085
+ inputAttributes: null,
1086
+ containerAttributes: null,
1087
+ leadField: "email",
1088
+ saveResult: true,
1089
+ isAutoFill: false,
1090
+ isReadOnly: false,
1091
+ mappedObject: "contact",
1092
+ mappedField: "email"
1093
+ },
1094
+ {
1095
+ id: 6,
1096
+ label: "Message",
1097
+ showLabel: false,
1098
+ alias: "f_message",
1099
+ type: "textarea",
1100
+ defaultValue: null,
1101
+ isRequired: true,
1102
+ validationMessage: "we need your message",
1103
+ helpMessage: null,
1104
+ order: 3,
1105
+ properties: [
1106
+ ],
1107
+ validation: [
1108
+ ],
1109
+ parent: null,
1110
+ conditions: [
1111
+ ],
1112
+ labelAttributes: null,
1113
+ inputAttributes: null,
1114
+ containerAttributes: null,
1115
+ leadField: "companyaddress1",
1116
+ saveResult: true,
1117
+ isAutoFill: false,
1118
+ isReadOnly: false,
1119
+ mappedObject: "company",
1120
+ mappedField: "companyaddress1"
1121
+ },
1122
+ {
1123
+ id: 7,
1124
+ label: "Submit",
1125
+ showLabel: true,
1126
+ alias: "submit",
1127
+ type: "button",
1128
+ defaultValue: null,
1129
+ isRequired: false,
1130
+ validationMessage: null,
1131
+ helpMessage: null,
1132
+ order: 4,
1133
+ properties: [
1134
+ ],
1135
+ validation: [
1136
+ ],
1137
+ parent: null,
1138
+ conditions: [
1139
+ ],
1140
+ labelAttributes: null,
1141
+ inputAttributes: "class=\"btn btn-ghost\"",
1142
+ containerAttributes: null,
1143
+ leadField: null,
1144
+ saveResult: true,
1145
+ isAutoFill: false,
1146
+ isReadOnly: false,
1147
+ mappedObject: null,
1148
+ mappedField: null
1149
+ }
1150
+ ],
1151
+ actions: [
1152
+ ],
1153
+ postAction: "message",
1154
+ postActionProperty: "Great, you have made it!",
1155
+ formType: "standalone"
1156
+ },
1157
+ {
1158
+ id: 1,
1159
+ name: "Simple form",
1160
+ alias: "simple_for",
1161
+ description: null,
1162
+ isPublished: true,
1163
+ fields: [
1164
+ {
1165
+ id: 1,
1166
+ label: "Name",
1167
+ showLabel: false,
1168
+ alias: "f_name",
1169
+ type: "text",
1170
+ defaultValue: null,
1171
+ isRequired: true,
1172
+ validationMessage: "This field is required",
1173
+ helpMessage: null,
1174
+ order: 1,
1175
+ properties: {
1176
+ placeholder: "Your name"
1177
+ },
1178
+ validation: [
1179
+ ],
1180
+ parent: null,
1181
+ conditions: [
1182
+ ],
1183
+ labelAttributes: null,
1184
+ inputAttributes: null,
1185
+ containerAttributes: null,
1186
+ leadField: "firstname",
1187
+ saveResult: true,
1188
+ isAutoFill: false,
1189
+ isReadOnly: false,
1190
+ mappedObject: "contact",
1191
+ mappedField: "firstname"
1192
+ },
1193
+ {
1194
+ id: 2,
1195
+ label: "EMail",
1196
+ showLabel: false,
1197
+ alias: "email",
1198
+ type: "email",
1199
+ defaultValue: null,
1200
+ isRequired: true,
1201
+ validationMessage: "This field is required",
1202
+ helpMessage: null,
1203
+ order: 2,
1204
+ properties: {
1205
+ placeholder: "Your email"
1206
+ },
1207
+ validation: [
1208
+ ],
1209
+ parent: null,
1210
+ conditions: [
1211
+ ],
1212
+ labelAttributes: null,
1213
+ inputAttributes: null,
1214
+ containerAttributes: null,
1215
+ leadField: "email",
1216
+ saveResult: true,
1217
+ isAutoFill: false,
1218
+ isReadOnly: false,
1219
+ mappedObject: "contact",
1220
+ mappedField: "email"
1221
+ },
1222
+ {
1223
+ id: 3,
1224
+ label: "Submit",
1225
+ showLabel: true,
1226
+ alias: "submit",
1227
+ type: "button",
1228
+ defaultValue: null,
1229
+ isRequired: false,
1230
+ validationMessage: null,
1231
+ helpMessage: null,
1232
+ order: 3,
1233
+ properties: [
1234
+ ],
1235
+ validation: [
1236
+ ],
1237
+ parent: null,
1238
+ conditions: [
1239
+ ],
1240
+ labelAttributes: null,
1241
+ inputAttributes: "class=\"btn btn-ghost\"",
1242
+ containerAttributes: null,
1243
+ leadField: null,
1244
+ saveResult: true,
1245
+ isAutoFill: false,
1246
+ isReadOnly: false,
1247
+ mappedObject: null,
1248
+ mappedField: null
1249
+ }
1250
+ ],
1251
+ actions: [
1252
+ ],
1253
+ postAction: "redirect",
1254
+ postActionProperty: "/mautic-test",
1255
+ formType: "standalone"
1256
+ }
1257
+ ];
1258
+ var mauticFormsData = {
1259
+ forms: forms
1260
+ };
1261
+
1262
+ // @ts-nocheck
1263
+ // Import the generated Mautic forms data
1264
+ // Create the data store
1265
+ const mauticData = {
1266
+ forms: mauticFormsData.forms
1267
+ };
1268
+ const getFormById = (id) => mauticData.forms.find(form => form.id === id);
1269
+
1270
+ /**
1271
+ * Integration Configuration
1272
+ * Centralized configuration for all third-party integrations
1273
+ */
1274
+ function envBool(key, defaultValue) {
1275
+ const v = getEnv(key);
1276
+ if (v === undefined || v === '')
1277
+ return defaultValue;
1278
+ const lower = v.toLowerCase();
1279
+ if (lower === 'false' || lower === '0' || lower === 'no')
1280
+ return false;
1281
+ if (lower === 'true' || lower === '1' || lower === 'yes')
1282
+ return true;
1283
+ return defaultValue;
1284
+ }
1285
+ /**
1286
+ * Get integration configuration with environment variable fallbacks
1287
+ */
1288
+ function getIntegrationConfig() {
1289
+ isDevEnvironment();
1290
+ return {
1291
+ wordpress: {
1292
+ enabled: true,
1293
+ apiUrl: getEnv('VITE_WORDPRESS_API_URL') || '',
1294
+ authMode: getEnv('VITE_AUTH_MODE') || 'direct',
1295
+ },
1296
+ supabase: {
1297
+ enabled: getEnv('VITE_AUTH_MODE') === 'supabase_proxy',
1298
+ url: getEnv('VITE_SUPABASE_URL') || '',
1299
+ anonKey: getEnv('VITE_SUPABASE_ANON_KEY') || '',
1300
+ serviceRoleKey: getEnv('VITE_SUPABASE_SERVICE_ROLE_KEY'),
1301
+ },
1302
+ gravityForms: {
1303
+ enabled: !!(getEnv('VITE_CLOUDFLARE_WORKER_URL') || getEnv('VITE_WORDPRESS_API_URL')),
1304
+ url: getEnv('VITE_WORDPRESS_API_URL'),
1305
+ proxyUrl: getEnv('VITE_CLOUDFLARE_WORKER_URL'),
1306
+ consumerKey: getEnv('VITE_GF_CONSUMER_KEY'),
1307
+ consumerSecret: getEnv('VITE_GF_CONSUMER_SECRET'),
1308
+ forms: {
1309
+ 'contact': {
1310
+ name: 'Contact Form',
1311
+ type: 'contact',
1312
+ successMessage: 'Thank you for your message. We\'ll get back to you soon!',
1313
+ },
1314
+ 'newsletter': {
1315
+ name: 'Newsletter Signup',
1316
+ type: 'newsletter',
1317
+ successMessage: 'Thank you for subscribing to our newsletter!',
1318
+ },
1319
+ 'support': {
1320
+ name: 'Support Request',
1321
+ type: 'support',
1322
+ successMessage: 'Your support request has been submitted successfully.',
1323
+ },
1324
+ },
1325
+ },
1326
+ mautic: {
1327
+ enabled: !!(getEnv('VITE_MAUTIC_PROXY_URL') || getEnv('VITE_MAUTIC_URL')),
1328
+ url: getEnv('VITE_MAUTIC_URL') || '',
1329
+ proxyUrl: getEnv('VITE_MAUTIC_PROXY_URL'),
1330
+ forms: {
1331
+ '1': {
1332
+ name: 'Newsletter Signup',
1333
+ type: 'newsletter',
1334
+ successMessage: 'Thank you for subscribing to our newsletter!',
1335
+ postAction: 'message',
1336
+ postActionProperty: 'Thank you for your submission!'
1337
+ },
1338
+ '2': {
1339
+ name: 'Contact Form',
1340
+ type: 'contact',
1341
+ successMessage: 'Thank you for contacting us! We\'ll get back to you soon.',
1342
+ postAction: 'message',
1343
+ postActionProperty: 'Thank you for your message!'
1344
+ },
1345
+ '3': {
1346
+ name: 'Lead Capture',
1347
+ type: 'lead',
1348
+ successMessage: 'Thank you for your interest! We\'ll be in touch.',
1349
+ postAction: 'message',
1350
+ postActionProperty: 'Thank you for your submission!'
1351
+ }
1352
+ }
1353
+ },
1354
+ phplist: {
1355
+ enabled: !!(getEnv('VITE_PHPLIST_URL') || getEnv('PHPLIST_URL')),
1356
+ url: getEnv('VITE_PHPLIST_URL') || getEnv('PHPLIST_URL'),
1357
+ proxyUrl: getEnv('VITE_PHPLIST_PROXY_URL') || getEnv('PHPLIST_PROXY_URL'),
1358
+ listId: parseInt(getEnv('VITE_PHPLIST_LIST_ID') || getEnv('PHPLIST_LIST_ID') || '0', 10) || undefined,
1359
+ subscribePageIds: (getEnv('VITE_PHPLIST_SUBSCRIBE_PAGE_IDS') || getEnv('PHPLIST_SUBSCRIBE_PAGE_IDS') || '')
1360
+ .split(',')
1361
+ .map((s) => parseInt(s.trim(), 10))
1362
+ .filter((n) => !Number.isNaN(n)),
1363
+ newsletterRouteBase: getEnv('VITE_PHPLIST_NEWSLETTER_ROUTE_BASE') || '/newsletters',
1364
+ },
1365
+ suiteCRM: {
1366
+ enabled: !!(getEnv('VITE_SUITECRM_URL') && getEnv('VITE_SUITECRM_CLIENT_ID') && getEnv('VITE_SUITECRM_CLIENT_SECRET')),
1367
+ url: getEnv('VITE_SUITECRM_URL'),
1368
+ proxyUrl: getEnv('VITE_SUITECRM_PROXY_URL'),
1369
+ appId: undefined,
1370
+ workerSecret: undefined,
1371
+ oauth2: {
1372
+ clientId: getEnv('VITE_SUITECRM_CLIENT_ID'),
1373
+ clientSecret: getEnv('VITE_SUITECRM_CLIENT_SECRET'),
1374
+ username: getEnv('VITE_SUITECRM_USERNAME'),
1375
+ password: getEnv('VITE_SUITECRM_PASSWORD'),
1376
+ },
1377
+ },
1378
+ chatwoot: {
1379
+ enabled: !!(getEnv('VITE_CHATWOOT_WEBSITE_TOKEN') && getEnv('VITE_CHATWOOT_BASE_URL')),
1380
+ websiteToken: getEnv('VITE_CHATWOOT_WEBSITE_TOKEN') || '',
1381
+ baseUrl: getEnv('VITE_CHATWOOT_BASE_URL') || '',
1382
+ locale: 'en',
1383
+ type: 'standard',
1384
+ launcherTitle: 'Chat',
1385
+ hideMessageBubble: false,
1386
+ position: 'right',
1387
+ showPopoutButton: false,
1388
+ },
1389
+ analytics: {
1390
+ googleAnalytics: { enabled: false },
1391
+ googleTagManager: { enabled: false },
1392
+ facebookPixel: { enabled: false },
1393
+ linkedinInsight: { enabled: false },
1394
+ },
1395
+ seo: (() => {
1396
+ const opt = (key) => {
1397
+ const v = getEnv(key);
1398
+ if (v === undefined || v === '')
1399
+ return undefined;
1400
+ const t = v.trim();
1401
+ return t || undefined;
1402
+ };
1403
+ const siteUrl = (getEnv('VITE_SEO_SITE_URL') || '').replace(/\/+$/, '').trim();
1404
+ const siteName = (getEnv('VITE_SEO_SITE_NAME') || '').trim();
1405
+ const defaultTitle = (getEnv('VITE_SEO_DEFAULT_TITLE') || '').trim() || siteName || '';
1406
+ return {
1407
+ defaultTitle,
1408
+ defaultDescription: (getEnv('VITE_SEO_DEFAULT_DESCRIPTION') || '').trim(),
1409
+ defaultKeywords: opt('VITE_SEO_DEFAULT_KEYWORDS'),
1410
+ defaultImage: (getEnv('VITE_SEO_DEFAULT_OG_IMAGE') || '').trim(),
1411
+ siteName,
1412
+ siteUrl,
1413
+ twitterHandle: opt('VITE_SEO_TWITTER_SITE'),
1414
+ facebookAppId: opt('VITE_SEO_FACEBOOK_APP_ID'),
1415
+ googleSiteVerification: opt('VITE_SEO_GOOGLE_SITE_VERIFICATION'),
1416
+ bingSiteVerification: opt('VITE_SEO_BING_SITE_VERIFICATION'),
1417
+ };
1418
+ })(),
1419
+ performance: {
1420
+ enableLazyLoading: envBool('VITE_PERF_LAZY_LOADING', true),
1421
+ enableImageOptimization: envBool('VITE_PERF_IMAGE_OPTIMIZATION', true),
1422
+ enableCodeSplitting: envBool('VITE_PERF_CODE_SPLITTING', true),
1423
+ enableServiceWorker: envBool('VITE_PERF_SERVICE_WORKER', false),
1424
+ enableCaching: envBool('VITE_PERF_CACHING', true),
1425
+ }
1426
+ };
1427
+ }
1428
+
1429
+ const MauticForm = ({ formId, title, description, className = '' }) => {
1430
+ // Get form from static data
1431
+ const form = getFormById(parseInt(formId));
1432
+ // Get form configuration from integrations config
1433
+ const integrationConfig = getIntegrationConfig();
1434
+ const formConfig = integrationConfig.mautic.forms[formId];
1435
+ // Debug logging in development
1436
+ if (import.meta.env.DEV && form) {
1437
+ console.log('MauticForm Debug:', {
1438
+ formId,
1439
+ formPostAction: form.postAction,
1440
+ formPostActionProperty: form.postActionProperty,
1441
+ configPostAction: formConfig?.postAction,
1442
+ configPostActionProperty: formConfig?.postActionProperty,
1443
+ finalPostAction: form.postAction || formConfig?.postAction || 'message',
1444
+ finalPostActionProperty: form.postActionProperty || formConfig?.postActionProperty || 'Thank you for your submission!'
1445
+ });
1446
+ }
1447
+ // Use the package component
1448
+ return (jsx(MauticForm$1, { formId: formId, title: title, description: description, className: className, form: form, onSuccess: (data) => {
1449
+ console.log('Form submitted successfully:', data);
1450
+ }, onError: (error) => {
1451
+ console.error('Form submission error:', error);
1452
+ } }));
1453
+ };
1454
+
1455
+ const { HelmetProvider } = helmetAsync;
1456
+ const gravityFormsConfig = () => ({
1457
+ apiUrl: import.meta.env.VITE_WORDPRESS_API_URL,
1458
+ timeout: 30000,
1459
+ proxyEndpoint: withBasePath('/api/gravity-forms-submit'),
1460
+ });
1461
+ const InlineGravityForm = ({ formId }) => (jsx(StaticGravityForm, { formId: formId, config: gravityFormsConfig() }));
1462
+ const ContentPopup = ({ buttonText, title, children }) => {
1463
+ const [isOpen, setIsOpen] = useState(false);
1464
+ return (jsxs(Fragment, { children: [jsx("button", { type: "button", onClick: () => setIsOpen(true), "data-digivalt-popup-trigger": true, children: buttonText }), isOpen && (jsx("div", { role: "dialog", "aria-modal": "true", "aria-label": typeof title === 'string' ? title : undefined, "data-digivalt-popup": true, children: jsxs("div", { "data-digivalt-popup-content": true, children: [jsxs("header", { children: [jsx("h2", { children: title }), jsx("button", { type: "button", onClick: () => setIsOpen(false), "aria-label": "Close", children: "\u00D7" })] }), children] }) }))] }));
1465
+ };
1466
+ /**
1467
+ * Registry for WordPress page-body blocks and DigiValt integration shortcodes.
1468
+ * Header and footer template parts deliberately remain app-owned.
1469
+ */
1470
+ function createContentRegistry(themePalette) {
1471
+ const colorMapper = themePalette
1472
+ ? (colorName) => colorName ? themePalette[colorName] || null : null
1473
+ : undefined;
1474
+ const registry = createEnhancedRegistry([], undefined, colorMapper);
1475
+ registry.renderers['gravityforms/form'] = ({ block }) => {
1476
+ const attrs = block?.attributes || {};
1477
+ const formId = attrs.formId || attrs.id || attrs.form_id || '1';
1478
+ return jsx(InlineGravityForm, { formId: formId });
1479
+ };
1480
+ registry.shortcodes = {
1481
+ ...registry.shortcodes,
1482
+ ...getMauticShortcodeHandlers({
1483
+ renderForm: ({ formId, title, description }) => (jsx(MauticForm, { formId: formId, title: title, description: description })),
1484
+ }),
1485
+ ...getPhplistShortcodeHandlers(),
1486
+ gf_embed: (attrs) => (jsx(InlineGravityForm, { formId: attrs.id || attrs.formId || '1' })),
1487
+ gform: (attrs) => (jsx(InlineGravityForm, { formId: attrs.form_id || attrs.id || attrs.formId || '1' })),
1488
+ popupbtn_gf: (attrs) => (jsx(ContentPopup, { buttonText: attrs.text || attrs.buttonText || 'Submit', title: attrs.title || 'Contact Form', children: jsx(InlineGravityForm, { formId: attrs.id || attrs.formId || '1' }) })),
1489
+ popupgform: (attrs) => (jsx(ContentPopup, { buttonText: attrs.text || attrs.buttonText || 'Submit', title: attrs.title || 'Contact Form', children: jsx(InlineGravityForm, { formId: attrs.form_id || attrs.id || attrs.formId || '1' }) })),
1490
+ popupbtn_mautic: (attrs) => {
1491
+ const formId = attrs.id || attrs.formId || '1';
1492
+ return (jsx(ContentPopup, { buttonText: attrs.text || attrs.buttonText || 'Submit', title: attrs.title || attrs.popupTitle || 'Contact Form', children: jsx(MauticForm, { formId: String(formId) }) }));
1493
+ },
1494
+ };
1495
+ return registry;
1496
+ }
1497
+ /** Load and render one WordPress page body. */
1498
+ const DigiValtWpPage = ({ slug, className, dataPath = '/wordpress-data.json', themePalette, }) => {
1499
+ const [page, setPage] = useState(() => getWordPressPageBySlug(slug));
1500
+ const registry = useMemo(() => createContentRegistry(themePalette), [themePalette]);
1501
+ useEffect(() => {
1502
+ let active = true;
1503
+ loadWordPressData(dataPath).then(() => {
1504
+ if (active)
1505
+ setPage(getWordPressPageBySlug(slug));
1506
+ });
1507
+ return () => {
1508
+ active = false;
1509
+ };
1510
+ }, [dataPath, slug]);
1511
+ return page && Array.isArray(page.blocks)
1512
+ ? jsx(WPPage, { page: page, registry: registry, className: className })
1513
+ : null;
1514
+ };
1515
+ const DigiValtProviders = ({ children, queryClient }) => {
1516
+ const content = queryClient
1517
+ ? jsx(QueryClientProvider, { client: queryClient, children: children })
1518
+ : children;
1519
+ return jsx(HelmetProvider, { children: content });
1520
+ };
1521
+
1522
+ export { DigiValtProviders, DigiValtWpPage, createContentRegistry };
1523
+ //# sourceMappingURL=registry.esm.js.map