@kilivi/payloadcms-theme-management 1.1.0 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -31
- package/dist/components/ThemeLivePreviewSync.d.ts +11 -0
- package/dist/components/ThemeLivePreviewSync.d.ts.map +1 -0
- package/dist/components/ThemeLivePreviewSync.js +40 -0
- package/dist/components/ThemeLivePreviewSync.js.map +1 -0
- package/dist/fields/ThemeColorPickerField.d.ts.map +1 -1
- package/dist/fields/ThemeColorPickerField.js +26 -9
- package/dist/fields/ThemeColorPickerField.js.map +1 -1
- package/dist/fields/ThemePreviewField.d.ts.map +1 -1
- package/dist/fields/ThemePreviewField.js +2 -1
- package/dist/fields/ThemePreviewField.js.map +1 -1
- package/dist/fields/ThemeTokenSelectField.js +2 -2
- package/dist/fields/ThemeTokenSelectField.js.map +1 -1
- package/dist/fields/themeConfigurationField.d.ts +1 -0
- package/dist/fields/themeConfigurationField.d.ts.map +1 -1
- package/dist/fields/themeConfigurationField.js +3 -2
- package/dist/fields/themeConfigurationField.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +337 -16
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +30 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +42 -0
- package/dist/server.js.map +1 -1
- package/dist/types/color.d.js +2 -0
- package/dist/types/color.d.js.map +1 -0
- package/dist/types.d.ts +69 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/livePreviewRefresh.d.ts +17 -0
- package/dist/utils/livePreviewRefresh.d.ts.map +1 -0
- package/dist/utils/livePreviewRefresh.js +20 -0
- package/dist/utils/livePreviewRefresh.js.map +1 -0
- package/dist/utils/livePreviewThemeRuntime.d.ts +7 -0
- package/dist/utils/livePreviewThemeRuntime.d.ts.map +1 -0
- package/dist/utils/livePreviewThemeRuntime.js +58 -0
- package/dist/utils/livePreviewThemeRuntime.js.map +1 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -79,10 +79,313 @@ const THEME_FIELD_NAME = 'themeConfiguration';
|
|
|
79
79
|
return sanitizedFields.map((field)=>field.type === 'tabs' ? updatedTabsField : field);
|
|
80
80
|
};
|
|
81
81
|
const ensureCollectionsArray = (collections)=>Array.isArray(collections) ? collections : [];
|
|
82
|
+
const ensureEndpointsArray = (endpoints)=>Array.isArray(endpoints) ? endpoints : [];
|
|
83
|
+
const normalizeLivePreviewOptions = (livePreview)=>{
|
|
84
|
+
if (livePreview === false) {
|
|
85
|
+
return {
|
|
86
|
+
enabled: false,
|
|
87
|
+
pageCollection: 'pages',
|
|
88
|
+
pageSlug: 'home',
|
|
89
|
+
fallbackToFirstPage: true,
|
|
90
|
+
tenantField: 'tenant',
|
|
91
|
+
tenantQueryParam: 'tenant',
|
|
92
|
+
breakpoints: undefined
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const raw = typeof livePreview === 'object' && livePreview ? livePreview : {};
|
|
96
|
+
return {
|
|
97
|
+
enabled: raw.enabled ?? true,
|
|
98
|
+
pageCollection: raw.pageCollection ?? 'pages',
|
|
99
|
+
pageSlug: raw.pageSlug ?? 'home',
|
|
100
|
+
fallbackToFirstPage: raw.fallbackToFirstPage ?? true,
|
|
101
|
+
tenantField: raw.tenantField ?? 'tenant',
|
|
102
|
+
tenantQueryParam: raw.tenantQueryParam ?? 'tenant',
|
|
103
|
+
breakpoints: raw.breakpoints,
|
|
104
|
+
url: raw.url
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
const dedupeStrings = (values)=>[
|
|
108
|
+
...new Set(values.filter((value)=>typeof value === 'string' && value.trim().length > 0))
|
|
109
|
+
];
|
|
110
|
+
const normalizeRoutePath = (path)=>{
|
|
111
|
+
if (!path || !path.trim()) {
|
|
112
|
+
return '/theme/revalidate';
|
|
113
|
+
}
|
|
114
|
+
return path.startsWith('/') ? path : `/${path}`;
|
|
115
|
+
};
|
|
116
|
+
const normalizeCacheRevalidationOptions = (args)=>{
|
|
117
|
+
const { cacheRevalidation, standaloneCollectionSlug, useStandaloneCollection } = args;
|
|
118
|
+
if (cacheRevalidation === false) {
|
|
119
|
+
return {
|
|
120
|
+
enabled: false,
|
|
121
|
+
injectRoute: false,
|
|
122
|
+
routePath: '/theme/revalidate',
|
|
123
|
+
tags: [],
|
|
124
|
+
paths: []
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
const raw = typeof cacheRevalidation === 'object' && cacheRevalidation ? cacheRevalidation : {};
|
|
128
|
+
const defaultTag = `global_${standaloneCollectionSlug}`;
|
|
129
|
+
return {
|
|
130
|
+
enabled: raw.enabled ?? useStandaloneCollection,
|
|
131
|
+
injectRoute: raw.injectRoute ?? true,
|
|
132
|
+
routePath: normalizeRoutePath(raw.routePath),
|
|
133
|
+
secret: raw.secret,
|
|
134
|
+
tags: dedupeStrings([
|
|
135
|
+
defaultTag,
|
|
136
|
+
...raw.tags ?? []
|
|
137
|
+
]),
|
|
138
|
+
paths: dedupeStrings(raw.paths ?? [])
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
const asRecord = (value)=>{
|
|
142
|
+
if (value && typeof value === 'object') {
|
|
143
|
+
return value;
|
|
144
|
+
}
|
|
145
|
+
return undefined;
|
|
146
|
+
};
|
|
147
|
+
const pickString = (value)=>{
|
|
148
|
+
if (typeof value === 'string' && value.trim()) return value;
|
|
149
|
+
return undefined;
|
|
150
|
+
};
|
|
151
|
+
const extractTenantValue = (value)=>{
|
|
152
|
+
if (!value) return undefined;
|
|
153
|
+
if (typeof value === 'string') return pickString(value);
|
|
154
|
+
const tenantRecord = asRecord(value);
|
|
155
|
+
if (!tenantRecord) return undefined;
|
|
156
|
+
return pickString(tenantRecord.id) ?? pickString(tenantRecord.slug) ?? pickString(tenantRecord.value) ?? pickString(tenantRecord.tenant);
|
|
157
|
+
};
|
|
158
|
+
const resolveTenantSlug = (req, tenantField, data)=>{
|
|
159
|
+
const fromData = extractTenantValue(data?.[tenantField]);
|
|
160
|
+
if (fromData) return fromData;
|
|
161
|
+
const query = req.query;
|
|
162
|
+
if (query && typeof URLSearchParams !== 'undefined' && query instanceof URLSearchParams) {
|
|
163
|
+
return pickString(query.get('tenant')) ?? pickString(query.get('tenantSlug')) ?? pickString(query.get('tenantId'));
|
|
164
|
+
}
|
|
165
|
+
const queryRecord = asRecord(query);
|
|
166
|
+
const fromQuery = extractTenantValue(queryRecord?.tenant) ?? extractTenantValue(queryRecord?.tenantSlug) ?? extractTenantValue(queryRecord?.tenantId);
|
|
167
|
+
if (fromQuery) return fromQuery;
|
|
168
|
+
const userRecord = asRecord(req.user);
|
|
169
|
+
const fromUser = extractTenantValue(userRecord?.[tenantField]) ?? extractTenantValue(userRecord?.tenant) ?? extractTenantValue(userRecord?.tenantSlug);
|
|
170
|
+
if (fromUser) return fromUser;
|
|
171
|
+
const headers = req.headers;
|
|
172
|
+
if (headers && typeof Headers !== 'undefined' && headers instanceof Headers) {
|
|
173
|
+
return pickString(headers.get('x-tenant-id')) ?? pickString(headers.get('x-tenant')) ?? pickString(headers.get('payload-tenant'));
|
|
174
|
+
}
|
|
175
|
+
const headerRecord = asRecord(headers);
|
|
176
|
+
return extractTenantValue(headerRecord?.['x-tenant-id']) ?? extractTenantValue(headerRecord?.['x-tenant']) ?? extractTenantValue(headerRecord?.['payload-tenant']);
|
|
177
|
+
};
|
|
178
|
+
const buildDefaultPreviewPath = (pageSlug, tenantSlug, tenantQueryParam)=>{
|
|
179
|
+
const normalizedSlug = pageSlug === 'home' ? '' : pageSlug;
|
|
180
|
+
const basePath = normalizedSlug ? `/${normalizedSlug}` : '/';
|
|
181
|
+
if (!tenantSlug) {
|
|
182
|
+
return basePath;
|
|
183
|
+
}
|
|
184
|
+
const separator = basePath.includes('?') ? '&' : '?';
|
|
185
|
+
return `${basePath}${separator}${tenantQueryParam}=${encodeURIComponent(tenantSlug)}`;
|
|
186
|
+
};
|
|
187
|
+
const resolveLivePreviewUrl = async (args)=>{
|
|
188
|
+
const { req, data, livePreview, enableLogging } = args;
|
|
189
|
+
const tenantSlug = resolveTenantSlug(req, livePreview.tenantField, data);
|
|
190
|
+
const tenantWhere = tenantSlug ? {
|
|
191
|
+
[livePreview.tenantField]: {
|
|
192
|
+
equals: tenantSlug
|
|
193
|
+
}
|
|
194
|
+
} : undefined;
|
|
195
|
+
const homeWhere = {
|
|
196
|
+
and: [
|
|
197
|
+
{
|
|
198
|
+
slug: {
|
|
199
|
+
equals: livePreview.pageSlug
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
...tenantWhere ? [
|
|
203
|
+
tenantWhere
|
|
204
|
+
] : []
|
|
205
|
+
]
|
|
206
|
+
};
|
|
207
|
+
try {
|
|
208
|
+
const preferredPageResponse = await req.payload.find({
|
|
209
|
+
collection: livePreview.pageCollection,
|
|
210
|
+
where: homeWhere,
|
|
211
|
+
depth: 0,
|
|
212
|
+
draft: true,
|
|
213
|
+
limit: 1,
|
|
214
|
+
overrideAccess: true,
|
|
215
|
+
pagination: false
|
|
216
|
+
});
|
|
217
|
+
let page = preferredPageResponse?.docs?.[0];
|
|
218
|
+
if (!page && livePreview.fallbackToFirstPage) {
|
|
219
|
+
const fallbackResponse = await req.payload.find({
|
|
220
|
+
collection: livePreview.pageCollection,
|
|
221
|
+
where: tenantWhere,
|
|
222
|
+
depth: 0,
|
|
223
|
+
draft: true,
|
|
224
|
+
limit: 1,
|
|
225
|
+
overrideAccess: true,
|
|
226
|
+
pagination: false
|
|
227
|
+
});
|
|
228
|
+
page = fallbackResponse?.docs?.[0];
|
|
229
|
+
}
|
|
230
|
+
const pageRecord = asRecord(page);
|
|
231
|
+
const resolvedPageSlug = pickString(pageRecord?.slug) ?? livePreview.pageSlug;
|
|
232
|
+
if (livePreview.url) {
|
|
233
|
+
return await livePreview.url({
|
|
234
|
+
page: pageRecord,
|
|
235
|
+
pageSlug: resolvedPageSlug,
|
|
236
|
+
tenantSlug,
|
|
237
|
+
req
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
return buildDefaultPreviewPath(resolvedPageSlug, tenantSlug, livePreview.tenantQueryParam);
|
|
241
|
+
} catch (error) {
|
|
242
|
+
if (enableLogging) {
|
|
243
|
+
req.payload.logger?.warn?.('🎨 Theme Management Plugin: live preview URL fallback used', error);
|
|
244
|
+
}
|
|
245
|
+
return buildDefaultPreviewPath(livePreview.pageSlug, tenantSlug, livePreview.tenantQueryParam);
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
const createPreviewAdminConfig = (normalizedLivePreview, enableLogging)=>{
|
|
249
|
+
if (!normalizedLivePreview.enabled) {
|
|
250
|
+
return {};
|
|
251
|
+
}
|
|
252
|
+
return {
|
|
253
|
+
livePreview: {
|
|
254
|
+
breakpoints: normalizedLivePreview.breakpoints,
|
|
255
|
+
url: ({ data, req })=>resolveLivePreviewUrl({
|
|
256
|
+
req: req,
|
|
257
|
+
data: asRecord(data),
|
|
258
|
+
livePreview: normalizedLivePreview,
|
|
259
|
+
enableLogging
|
|
260
|
+
})
|
|
261
|
+
},
|
|
262
|
+
preview: (data, options)=>{
|
|
263
|
+
const req = options?.req;
|
|
264
|
+
if (!req) return null;
|
|
265
|
+
return resolveLivePreviewUrl({
|
|
266
|
+
req: req,
|
|
267
|
+
data,
|
|
268
|
+
livePreview: normalizedLivePreview,
|
|
269
|
+
enableLogging
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
};
|
|
274
|
+
const readSecretFromRequest = async (req)=>{
|
|
275
|
+
const requestRecord = asRecord(req);
|
|
276
|
+
const headersValue = requestRecord?.headers;
|
|
277
|
+
if (headersValue && typeof Headers !== 'undefined' && headersValue instanceof Headers) {
|
|
278
|
+
return pickString(headersValue.get('x-theme-revalidate-secret')) ?? pickString(headersValue.get('x-revalidate-secret'));
|
|
279
|
+
}
|
|
280
|
+
const headerRecord = asRecord(headersValue);
|
|
281
|
+
const fromHeaders = pickString(headerRecord?.['x-theme-revalidate-secret']) ?? pickString(headerRecord?.['x-revalidate-secret']);
|
|
282
|
+
if (fromHeaders) {
|
|
283
|
+
return fromHeaders;
|
|
284
|
+
}
|
|
285
|
+
const requestWithJson = req;
|
|
286
|
+
const body = typeof requestWithJson?.json === 'function' ? await requestWithJson.json() : undefined;
|
|
287
|
+
const bodyRecord = asRecord(body);
|
|
288
|
+
const fromBody = pickString(bodyRecord?.secret);
|
|
289
|
+
if (fromBody) {
|
|
290
|
+
return fromBody;
|
|
291
|
+
}
|
|
292
|
+
const queryRecord = asRecord(requestRecord?.query);
|
|
293
|
+
return pickString(queryRecord?.secret);
|
|
294
|
+
};
|
|
295
|
+
const executeThemeRevalidation = async (options)=>{
|
|
296
|
+
const { tags, paths, enableLogging, logger } = options;
|
|
297
|
+
try {
|
|
298
|
+
const { revalidatePath, revalidateTag } = await import('next/cache');
|
|
299
|
+
tags.forEach((tag)=>revalidateTag(tag));
|
|
300
|
+
paths.forEach((path)=>revalidatePath(path));
|
|
301
|
+
if (enableLogging) {
|
|
302
|
+
logger?.info?.(`🎨 Theme Management Plugin: revalidated cache tags=[${tags.join(', ')}] paths=[${paths.join(', ')}]`);
|
|
303
|
+
}
|
|
304
|
+
} catch (error) {
|
|
305
|
+
if (enableLogging) {
|
|
306
|
+
logger?.error?.('🎨 Theme Management Plugin: cache invalidation failed:', error);
|
|
307
|
+
}
|
|
308
|
+
throw error;
|
|
309
|
+
}
|
|
310
|
+
return {
|
|
311
|
+
tags,
|
|
312
|
+
paths
|
|
313
|
+
};
|
|
314
|
+
};
|
|
315
|
+
const createCacheRevalidationEndpoint = (options)=>{
|
|
316
|
+
const { cacheRevalidation, enableLogging } = options;
|
|
317
|
+
if (!cacheRevalidation.enabled || !cacheRevalidation.injectRoute) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
return {
|
|
321
|
+
path: cacheRevalidation.routePath,
|
|
322
|
+
method: 'post',
|
|
323
|
+
handler: async (req)=>{
|
|
324
|
+
const reqRecord = asRecord(req);
|
|
325
|
+
const payload = asRecord(reqRecord?.payload);
|
|
326
|
+
const logger = payload?.logger;
|
|
327
|
+
if (cacheRevalidation.secret) {
|
|
328
|
+
const providedSecret = await readSecretFromRequest(req);
|
|
329
|
+
if (providedSecret !== cacheRevalidation.secret) {
|
|
330
|
+
return jsonResponse({
|
|
331
|
+
error: 'Unauthorized'
|
|
332
|
+
}, 401);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
const result = await executeThemeRevalidation({
|
|
337
|
+
tags: cacheRevalidation.tags,
|
|
338
|
+
paths: cacheRevalidation.paths,
|
|
339
|
+
enableLogging,
|
|
340
|
+
logger
|
|
341
|
+
});
|
|
342
|
+
return jsonResponse({
|
|
343
|
+
ok: true,
|
|
344
|
+
revalidated: result
|
|
345
|
+
});
|
|
346
|
+
} catch {
|
|
347
|
+
return jsonResponse({
|
|
348
|
+
ok: false,
|
|
349
|
+
error: 'Revalidation failed'
|
|
350
|
+
}, 500);
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
const mergeEndpoint = (endpoints, endpoint)=>{
|
|
356
|
+
if (!endpoint) {
|
|
357
|
+
return endpoints;
|
|
358
|
+
}
|
|
359
|
+
const withoutExisting = endpoints.filter((candidate)=>{
|
|
360
|
+
const record = candidate;
|
|
361
|
+
return !(record?.path === endpoint.path && typeof record.method === 'string' && record.method.toLowerCase() === endpoint.method);
|
|
362
|
+
});
|
|
363
|
+
return [
|
|
364
|
+
...withoutExisting,
|
|
365
|
+
endpoint
|
|
366
|
+
];
|
|
367
|
+
};
|
|
368
|
+
const jsonResponse = (body, status = 200)=>{
|
|
369
|
+
if (typeof Response !== 'undefined' && typeof Response.json === 'function') {
|
|
370
|
+
return Response.json(body, {
|
|
371
|
+
status
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
return {
|
|
375
|
+
status,
|
|
376
|
+
json: async ()=>body
|
|
377
|
+
};
|
|
378
|
+
};
|
|
82
379
|
export const themeManagementPlugin = (options = {})=>{
|
|
83
380
|
return (config)=>{
|
|
84
381
|
const { enabled = true, targetCollection = 'site-settings', useStandaloneCollection = false, standaloneCollectionSlug = 'appearance-settings', // Allow either string or localized object; default comes from plugin translations
|
|
85
|
-
standaloneCollectionLabel = getTranslations().standaloneCollectionLabel, themePresets = allThemePresets, defaultTheme = 'cool', includeColorModeToggle = true, includeCustomCSS = true, includeBrandIdentity = false, enableAdvancedFeatures = true, enableLogging = false } = options;
|
|
382
|
+
standaloneCollectionLabel = getTranslations().standaloneCollectionLabel, themePresets = allThemePresets, defaultTheme = 'cool', includeColorModeToggle = true, includeCustomCSS = true, includeBrandIdentity = false, enableAdvancedFeatures = true, enableLogging = false, livePreview = true, cacheRevalidation } = options;
|
|
383
|
+
const normalizedLivePreview = normalizeLivePreviewOptions(livePreview);
|
|
384
|
+
const normalizedCacheRevalidation = normalizeCacheRevalidationOptions({
|
|
385
|
+
cacheRevalidation,
|
|
386
|
+
standaloneCollectionSlug,
|
|
387
|
+
useStandaloneCollection
|
|
388
|
+
});
|
|
86
389
|
if (!enabled) {
|
|
87
390
|
if (enableLogging) {
|
|
88
391
|
console.log('🎨 Theme Management Plugin: disabled via options, skipping.');
|
|
@@ -95,7 +398,8 @@ export const themeManagementPlugin = (options = {})=>{
|
|
|
95
398
|
includeColorModeToggle,
|
|
96
399
|
includeCustomCSS,
|
|
97
400
|
includeBrandIdentity: includeBrandIdentity ?? false,
|
|
98
|
-
enableAdvancedFeatures
|
|
401
|
+
enableAdvancedFeatures,
|
|
402
|
+
useThemePreviewField: !normalizedLivePreview.enabled
|
|
99
403
|
});
|
|
100
404
|
// If using standalone collection, create a new global
|
|
101
405
|
if (useStandaloneCollection) {
|
|
@@ -139,7 +443,8 @@ export const themeManagementPlugin = (options = {})=>{
|
|
|
139
443
|
slug: standaloneCollectionSlug,
|
|
140
444
|
label: standaloneCollectionLabel,
|
|
141
445
|
admin: {
|
|
142
|
-
group: 'Settings'
|
|
446
|
+
group: 'Settings',
|
|
447
|
+
...createPreviewAdminConfig(normalizedLivePreview, enableLogging)
|
|
143
448
|
},
|
|
144
449
|
// Provide a broad access object but cast to GlobalConfig['access'] to satisfy types
|
|
145
450
|
access: (()=>{
|
|
@@ -159,19 +464,16 @@ export const themeManagementPlugin = (options = {})=>{
|
|
|
159
464
|
afterChange: [
|
|
160
465
|
async ({ doc, req })=>{
|
|
161
466
|
// Invalidate cache after appearance settings change
|
|
162
|
-
if (!req?.context?.disableRevalidate) {
|
|
467
|
+
if (!req?.context?.disableRevalidate && normalizedCacheRevalidation.enabled) {
|
|
163
468
|
try {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
if (enableLogging) {
|
|
173
|
-
req.payload.logger.error('🎨 Theme Management Plugin: cache invalidation failed:', error);
|
|
174
|
-
}
|
|
469
|
+
await executeThemeRevalidation({
|
|
470
|
+
tags: normalizedCacheRevalidation.tags,
|
|
471
|
+
paths: normalizedCacheRevalidation.paths,
|
|
472
|
+
enableLogging,
|
|
473
|
+
logger: req?.payload?.logger
|
|
474
|
+
});
|
|
475
|
+
} catch {
|
|
476
|
+
// no-op: logging is handled in executeThemeRevalidation
|
|
175
477
|
}
|
|
176
478
|
}
|
|
177
479
|
return doc;
|
|
@@ -188,8 +490,15 @@ export const themeManagementPlugin = (options = {})=>{
|
|
|
188
490
|
}
|
|
189
491
|
return config;
|
|
190
492
|
}
|
|
493
|
+
const currentEndpoints = ensureEndpointsArray(config.endpoints);
|
|
494
|
+
const cacheEndpoint = createCacheRevalidationEndpoint({
|
|
495
|
+
cacheRevalidation: normalizedCacheRevalidation,
|
|
496
|
+
enableLogging
|
|
497
|
+
});
|
|
498
|
+
const endpoints = mergeEndpoint(currentEndpoints, cacheEndpoint);
|
|
191
499
|
return {
|
|
192
500
|
...config,
|
|
501
|
+
endpoints,
|
|
193
502
|
globals: [
|
|
194
503
|
...globals,
|
|
195
504
|
standaloneGlobal
|
|
@@ -208,9 +517,14 @@ export const themeManagementPlugin = (options = {})=>{
|
|
|
208
517
|
}
|
|
209
518
|
const existingFields = Array.isArray(collection.fields) ? collection.fields : [];
|
|
210
519
|
const fields = injectThemeTab(existingFields, themeTab, enableLogging);
|
|
520
|
+
const admin = {
|
|
521
|
+
...collection.admin,
|
|
522
|
+
...createPreviewAdminConfig(normalizedLivePreview, enableLogging)
|
|
523
|
+
};
|
|
211
524
|
return {
|
|
212
525
|
...collection,
|
|
213
|
-
fields
|
|
526
|
+
fields,
|
|
527
|
+
admin
|
|
214
528
|
};
|
|
215
529
|
});
|
|
216
530
|
if (!collectionTouched) {
|
|
@@ -219,8 +533,15 @@ export const themeManagementPlugin = (options = {})=>{
|
|
|
219
533
|
}
|
|
220
534
|
return config;
|
|
221
535
|
}
|
|
536
|
+
const currentEndpoints = ensureEndpointsArray(config.endpoints);
|
|
537
|
+
const cacheEndpoint = createCacheRevalidationEndpoint({
|
|
538
|
+
cacheRevalidation: normalizedCacheRevalidation,
|
|
539
|
+
enableLogging
|
|
540
|
+
});
|
|
541
|
+
const endpoints = mergeEndpoint(currentEndpoints, cacheEndpoint);
|
|
222
542
|
return {
|
|
223
543
|
...config,
|
|
544
|
+
endpoints,
|
|
224
545
|
collections
|
|
225
546
|
};
|
|
226
547
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config, Field, GlobalConfig, Plugin, TabsField } from 'payload'\nimport { createThemeConfigurationField } from './fields/themeConfigurationField.js'\nimport type { ThemeTab } from './fields/themeConfigurationField.js'\nimport type { SiteThemeConfiguration } from './payload-types.js'\nimport type { ThemePreset } from './presets.js'\nimport { allThemePresets } from './presets.js'\nimport { getTranslations, translations } from './translations.js'\nimport type { FetchThemeConfigurationOptions, ThemeManagementPluginOptions } from './types.js'\n\nconst THEME_FIELD_NAME = 'themeConfiguration'\n\n/**\n * Removes existing theme configuration from a group field (legacy)\n */\nconst removeExistingThemeField = (fields: Field[] = []): Field[] =>\n fields.filter((field) => {\n const candidate = field as { name?: unknown }\n return candidate?.name !== THEME_FIELD_NAME\n })\n\n/**\n * Finds the tabs field in the collection fields array\n */\nconst findTabsField = (fields: Field[] = []): TabsField | null => {\n for (const field of fields) {\n if (field.type === 'tabs') {\n return field as TabsField\n }\n }\n return null\n}\n\n/**\n * Removes existing Appearance Settings tab if it exists\n */\nconst removeExistingThemeTab = (\n tabs: NonNullable<TabsField['tabs']>,\n): NonNullable<TabsField['tabs']> => {\n const knownLabels = Object.values(translations).map((t) => t.tabLabel)\n return tabs.filter((tab) => {\n // Normalize label to string (support localized object or plain string)\n let labelValues: string[] = []\n if (typeof tab.label === 'object' && tab.label !== null) {\n labelValues = Object.values(tab.label as Record<string, string>)\n } else if (typeof tab.label === 'string') {\n labelValues = [tab.label]\n }\n\n // If any of the label values match a known plugin tab label, remove it\n const matchesKnown = labelValues.some((v) => knownLabels.includes(v))\n\n return !matchesKnown\n })\n}\n\n/**\n * Injects theme tab into existing tabs field\n */\nconst injectThemeTab = (\n fields: Field[] | undefined,\n themeTab: ThemeTab,\n enableLogging: boolean,\n): Field[] => {\n // First, remove any legacy theme field (group-based)\n const sanitizedFields = removeExistingThemeField(fields ?? [])\n\n // Find the tabs field\n const tabsField = findTabsField(sanitizedFields)\n\n if (!tabsField || !tabsField.tabs) {\n if (enableLogging) {\n console.warn(\n '🎨 Theme Management Plugin: No tabs field found. Creating a new tabs structure.',\n )\n }\n\n // If no tabs exist, create a basic tabs structure with just the theme tab\n const newTabsField: TabsField = {\n type: 'tabs',\n tabs: [themeTab],\n }\n\n return [...sanitizedFields, newTabsField]\n }\n\n // Remove existing theme tab if present\n const sanitizedTabs = removeExistingThemeTab(tabsField.tabs)\n\n // Add theme tab to the end\n const updatedTabs = [...sanitizedTabs, themeTab]\n\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: injecting Appearance Settings tab')\n }\n\n // Update the tabs field\n const updatedTabsField: TabsField = {\n ...tabsField,\n tabs: updatedTabs,\n }\n\n // Replace the old tabs field with the updated one\n return sanitizedFields.map((field) => (field.type === 'tabs' ? updatedTabsField : field))\n}\n\nconst ensureCollectionsArray = (collections: Config['collections']): CollectionConfig[] =>\n Array.isArray(collections) ? collections : []\n\nexport const themeManagementPlugin = (options: ThemeManagementPluginOptions = {}): Plugin => {\n return (config: Config): Config => {\n const {\n enabled = true,\n targetCollection = 'site-settings',\n useStandaloneCollection = false,\n standaloneCollectionSlug = 'appearance-settings',\n // Allow either string or localized object; default comes from plugin translations\n standaloneCollectionLabel = getTranslations().standaloneCollectionLabel,\n themePresets = allThemePresets,\n defaultTheme = 'cool',\n includeColorModeToggle = true,\n includeCustomCSS = true,\n includeBrandIdentity = false,\n enableAdvancedFeatures = true,\n enableLogging = false,\n } = options\n\n if (!enabled) {\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: disabled via options, skipping.')\n }\n return config\n }\n\n const themeTab = createThemeConfigurationField({\n themePresets,\n defaultTheme,\n includeColorModeToggle,\n includeCustomCSS,\n includeBrandIdentity: includeBrandIdentity ?? false,\n enableAdvancedFeatures,\n })\n\n // If using standalone collection, create a new global\n if (useStandaloneCollection) {\n if (enableLogging) {\n console.log(\n `🎨 Theme Management Plugin: creating standalone global \"${standaloneCollectionSlug}\"`,\n )\n }\n\n // Extract the fields from the tab directly (no wrapping in group)\n const tabFields = (themeTab.fields ?? []) as Field[]\n\n /**\n * Hook to auto-populate lightMode and darkMode colors when theme changes\n */\n type BeforeChangeArgs = {\n data?: {\n themeConfiguration?: {\n theme?: string\n lightMode?: Record<string, unknown>\n darkMode?: Record<string, unknown>\n }\n }\n }\n\n const beforeChangeHook = async (args: BeforeChangeArgs) => {\n const { data } = args\n\n // If theme is being changed, auto-populate color modes\n if (data?.themeConfiguration?.theme) {\n const themeName = data.themeConfiguration.theme\n const selectedPreset = themePresets.find((p) => p.name === themeName)\n\n if (selectedPreset) {\n // Initialize light and dark mode colors from preset if not already set\n if (!data.themeConfiguration.lightMode) {\n data.themeConfiguration.lightMode = {}\n }\n if (!data.themeConfiguration.darkMode) {\n data.themeConfiguration.darkMode = {}\n }\n\n // Only populate if not manually edited (first time or empty)\n const isLightModeEmpty = !data.themeConfiguration.lightMode?.background\n const isDarkModeEmpty = !data.themeConfiguration.darkMode?.background\n\n if (isLightModeEmpty && selectedPreset.lightMode) {\n data.themeConfiguration.lightMode = { ...selectedPreset.lightMode }\n }\n\n if (isDarkModeEmpty && selectedPreset.darkMode) {\n data.themeConfiguration.darkMode = { ...selectedPreset.darkMode }\n }\n }\n }\n\n return data\n }\n\n const standaloneGlobal: GlobalConfig = {\n slug: standaloneCollectionSlug,\n label: standaloneCollectionLabel,\n admin: {\n group: 'Settings',\n },\n // Provide a broad access object but cast to GlobalConfig['access'] to satisfy types\n access: ((): GlobalConfig['access'] => {\n const accessObj = {\n read: () => true,\n create: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n update: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n delete: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n } as unknown as GlobalConfig['access']\n return accessObj\n })(),\n fields: tabFields,\n hooks: {\n beforeChange: [beforeChangeHook],\n afterChange: [\n async ({ doc, req }) => {\n // Invalidate cache after appearance settings change\n if (!req?.context?.disableRevalidate) {\n try {\n const cacheTag = `global_${standaloneCollectionSlug}`\n // Import revalidateTag dynamically to avoid issues in non-Next.js environments\n const { revalidateTag } = await import('next/cache')\n revalidateTag(cacheTag)\n if (enableLogging) {\n req.payload.logger.info(\n `🎨 Theme Management Plugin: cache invalidated for tag \"${cacheTag}\"`,\n )\n }\n } catch (error) {\n if (enableLogging) {\n req.payload.logger.error(\n '🎨 Theme Management Plugin: cache invalidation failed:',\n error,\n )\n }\n }\n }\n return doc\n },\n ],\n },\n }\n\n const globals = Array.isArray(config.globals) ? config.globals : []\n\n // Check if global already exists\n const existingIndex = globals.findIndex((g) => g.slug === standaloneCollectionSlug)\n\n if (existingIndex !== -1) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: global \"${standaloneCollectionSlug}\" already exists, skipping creation.`,\n )\n }\n return config\n }\n\n return {\n ...config,\n globals: [...globals, standaloneGlobal],\n }\n }\n\n // Otherwise, add as tab to existing collection\n let collectionTouched = false\n\n const collections = ensureCollectionsArray(config.collections).map((collection) => {\n if (collection.slug !== targetCollection) {\n return collection\n }\n\n collectionTouched = true\n\n if (enableLogging) {\n console.log(`🎨 Theme Management Plugin: enhancing collection \"${collection.slug}\"`)\n }\n\n const existingFields = Array.isArray(collection.fields) ? collection.fields : []\n\n const fields = injectThemeTab(existingFields, themeTab, enableLogging)\n\n return {\n ...collection,\n fields,\n }\n })\n\n if (!collectionTouched) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: collection \"${targetCollection}\" was not found, leaving config untouched.`,\n )\n }\n return config\n }\n\n return {\n ...config,\n collections,\n }\n }\n}\n\ntype FetchOptionsInput = string | FetchThemeConfigurationOptions\n\nexport const fetchThemeConfiguration = async (\n options?: FetchOptionsInput,\n): Promise<SiteThemeConfiguration | null> => {\n const normalizedOptions = typeof options === 'string' ? { tenantSlug: options } : (options ?? {})\n\n const {\n tenantSlug,\n collectionSlug = 'site-settings', // Can be overridden to 'appearance-settings' if using standalone\n depth,\n locale,\n draft,\n queryParams = {},\n useGlobal = false, // Set to true if using standalone global instead of collection\n } = normalizedOptions\n\n try {\n if (useGlobal) {\n // Fetch from global endpoint\n const params = new URLSearchParams()\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For globals, keep tenant param for backwards compatibility, and also add where[...] filter\n if (tenantSlug) {\n params.set('tenant', tenantSlug)\n params.set('where[tenant][equals]', String(tenantSlug))\n }\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const queryString = params.toString()\n const url = `/api/globals/${collectionSlug}${queryString ? `?${queryString}` : ''}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme global (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n themeConfiguration?: SiteThemeConfiguration\n }\n\n return data?.themeConfiguration ?? null\n } else {\n // Fetch from collection endpoint (legacy/default behavior)\n const params = new URLSearchParams({ limit: '1' })\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For collections, use a where[tenant][equals] filter so Payload's find endpoint applies tenant scoping\n if (tenantSlug) params.set('where[tenant][equals]', String(tenantSlug))\n if (locale) params.set('locale', locale)\n if (draft) params.set('draft', 'true')\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const url = `/api/${collectionSlug}?${params.toString()}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme configuration (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n docs?: Array<{ themeConfiguration?: SiteThemeConfiguration }>\n }\n\n const doc = data.docs?.[0]\n\n return doc?.themeConfiguration ?? null\n }\n } catch (error) {\n console.warn('Failed to fetch theme configuration:', error)\n return null\n }\n}\n\nexport const getThemePreset = (themeName: string): ThemePreset | null => {\n return allThemePresets.find((preset) => preset.name === themeName) || null\n}\n\nexport const getAvailableThemePresets = (): ThemePreset[] => {\n return allThemePresets\n}\n\nexport { defaultThemePresets, allThemePresets } from './presets.js'\nexport type { ThemePreset, ThemeTypographyPreset } from './presets.js'\nexport type { ThemeTab } from './fields/themeConfigurationField.js'\nexport {\n extendedThemePresets,\n allExtendedThemePresets,\n extendedThemeToCSSVariables,\n} from './extended-presets.js'\nexport type { ExtendedThemePreset, ShadcnColorTokens } from './extended-presets.js'\nexport {\n applyExtendedTheme,\n generateExtendedThemeCSS,\n resetExtendedTheme,\n getExtendedThemeTokens,\n createUseExtendedTheme,\n getTailwindVarReferences,\n} from './utils/extendedThemeHelpers.js'\nexport type { ThemeManagementPluginOptions, FetchThemeConfigurationOptions } from './types.js'\nexport {\n DEFAULT_THEME_CONFIGURATION,\n resolveThemeConfiguration,\n} from './utils/resolveThemeConfiguration.js'\nexport type { ResolvedThemeConfiguration } from './utils/resolveThemeConfiguration.js'\nexport { generateThemeColorsCss, hexToHsl } from './utils/themeColors.js'\nexport { generateThemeCSS, getThemeStyles } from './utils/themeUtils.js'\nexport { getThemeHtmlAttributes } from './utils/themeHtmlAttributes.js'\n\n// Dynamic theme CSS generation\nexport {\n generateThemeCSS as generatePresetCSS,\n generateAllThemesCSS,\n} from './utils/generateThemeCSS.js'\nexport { getThemeDynamicCSS, getAllDynamicThemesCSS } from './utils/themeCSS.js'\n\nexport type { Mode, ThemeDefaults } from './providers/Theme/types.js'\nexport { ThemeProvider } from './providers/Theme/index.js'\n\n// Font loading utilities for Next.js integration\nexport {\n getFontLoaderCode,\n getThemeFontFamilies,\n ThemeFontProvider,\n useThemeFonts,\n FONT_IMPORT_MAP,\n} from './providers/font-loader.js'\n\n// Note: Do NOT re-export client components from the root entry to avoid\n// server-side evaluation during `payload generate:importmap`.\n// If needed, import directly from subpath: `@kilivi/payloadcms-theme-management/fields/ThemeLivePreview`\n\nexport const ThemeManagementPlugin = themeManagementPlugin\n/** @deprecated use {@link themeManagementPlugin} */\nexport const themeConfigurationPlugin = themeManagementPlugin\n\n// Export plugin translations for consumers to merge into their payload translations\nexport {\n translations,\n getTranslations,\n registerTranslations,\n availableLanguages,\n} from './translations.js'\n\nexport default themeManagementPlugin\n"],"names":["createThemeConfigurationField","allThemePresets","getTranslations","translations","THEME_FIELD_NAME","removeExistingThemeField","fields","filter","field","candidate","name","findTabsField","type","removeExistingThemeTab","tabs","knownLabels","Object","values","map","t","tabLabel","tab","labelValues","label","matchesKnown","some","v","includes","injectThemeTab","themeTab","enableLogging","sanitizedFields","tabsField","console","warn","newTabsField","sanitizedTabs","updatedTabs","log","updatedTabsField","ensureCollectionsArray","collections","Array","isArray","themeManagementPlugin","options","config","enabled","targetCollection","useStandaloneCollection","standaloneCollectionSlug","standaloneCollectionLabel","themePresets","defaultTheme","includeColorModeToggle","includeCustomCSS","includeBrandIdentity","enableAdvancedFeatures","tabFields","beforeChangeHook","args","data","themeConfiguration","theme","themeName","selectedPreset","find","p","lightMode","darkMode","isLightModeEmpty","background","isDarkModeEmpty","standaloneGlobal","slug","admin","group","access","accessObj","read","create","req","user","update","delete","hooks","beforeChange","afterChange","doc","context","disableRevalidate","cacheTag","revalidateTag","payload","logger","info","error","globals","existingIndex","findIndex","g","collectionTouched","collection","existingFields","fetchThemeConfiguration","normalizedOptions","tenantSlug","collectionSlug","depth","locale","draft","queryParams","useGlobal","params","URLSearchParams","set","String","entries","forEach","key","value","undefined","queryString","toString","url","response","fetch","ok","Error","status","json","limit","docs","getThemePreset","preset","getAvailableThemePresets","defaultThemePresets","extendedThemePresets","allExtendedThemePresets","extendedThemeToCSSVariables","applyExtendedTheme","generateExtendedThemeCSS","resetExtendedTheme","getExtendedThemeTokens","createUseExtendedTheme","getTailwindVarReferences","DEFAULT_THEME_CONFIGURATION","resolveThemeConfiguration","generateThemeColorsCss","hexToHsl","generateThemeCSS","getThemeStyles","getThemeHtmlAttributes","generatePresetCSS","generateAllThemesCSS","getThemeDynamicCSS","getAllDynamicThemesCSS","ThemeProvider","getFontLoaderCode","getThemeFontFamilies","ThemeFontProvider","useThemeFonts","FONT_IMPORT_MAP","ThemeManagementPlugin","themeConfigurationPlugin","registerTranslations","availableLanguages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import type { CollectionConfig, Config, Field, GlobalConfig, Plugin, TabsField } from 'payload'\nimport { createThemeConfigurationField } from './fields/themeConfigurationField.js'\nimport type { ThemeTab } from './fields/themeConfigurationField.js'\nimport type { SiteThemeConfiguration } from './payload-types.js'\nimport type { ThemePreset } from './presets.js'\nimport { allThemePresets } from './presets.js'\nimport { getTranslations, translations } from './translations.js'\nimport type {\n FetchThemeConfigurationOptions,\n ThemeManagementLivePreviewOptions,\n ThemeManagementLivePreviewUrlArgs,\n ThemeManagementPluginOptions,\n} from './types.js'\n\nconst THEME_FIELD_NAME = 'themeConfiguration'\n\n/**\n * Removes existing theme configuration from a group field (legacy)\n */\nconst removeExistingThemeField = (fields: Field[] = []): Field[] =>\n fields.filter((field) => {\n const candidate = field as { name?: unknown }\n return candidate?.name !== THEME_FIELD_NAME\n })\n\n/**\n * Finds the tabs field in the collection fields array\n */\nconst findTabsField = (fields: Field[] = []): TabsField | null => {\n for (const field of fields) {\n if (field.type === 'tabs') {\n return field as TabsField\n }\n }\n return null\n}\n\n/**\n * Removes existing Appearance Settings tab if it exists\n */\nconst removeExistingThemeTab = (\n tabs: NonNullable<TabsField['tabs']>,\n): NonNullable<TabsField['tabs']> => {\n const knownLabels = Object.values(translations).map((t) => t.tabLabel)\n return tabs.filter((tab) => {\n // Normalize label to string (support localized object or plain string)\n let labelValues: string[] = []\n if (typeof tab.label === 'object' && tab.label !== null) {\n labelValues = Object.values(tab.label as Record<string, string>)\n } else if (typeof tab.label === 'string') {\n labelValues = [tab.label]\n }\n\n // If any of the label values match a known plugin tab label, remove it\n const matchesKnown = labelValues.some((v) => knownLabels.includes(v))\n\n return !matchesKnown\n })\n}\n\n/**\n * Injects theme tab into existing tabs field\n */\nconst injectThemeTab = (\n fields: Field[] | undefined,\n themeTab: ThemeTab,\n enableLogging: boolean,\n): Field[] => {\n // First, remove any legacy theme field (group-based)\n const sanitizedFields = removeExistingThemeField(fields ?? [])\n\n // Find the tabs field\n const tabsField = findTabsField(sanitizedFields)\n\n if (!tabsField || !tabsField.tabs) {\n if (enableLogging) {\n console.warn(\n '🎨 Theme Management Plugin: No tabs field found. Creating a new tabs structure.',\n )\n }\n\n // If no tabs exist, create a basic tabs structure with just the theme tab\n const newTabsField: TabsField = {\n type: 'tabs',\n tabs: [themeTab],\n }\n\n return [...sanitizedFields, newTabsField]\n }\n\n // Remove existing theme tab if present\n const sanitizedTabs = removeExistingThemeTab(tabsField.tabs)\n\n // Add theme tab to the end\n const updatedTabs = [...sanitizedTabs, themeTab]\n\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: injecting Appearance Settings tab')\n }\n\n // Update the tabs field\n const updatedTabsField: TabsField = {\n ...tabsField,\n tabs: updatedTabs,\n }\n\n // Replace the old tabs field with the updated one\n return sanitizedFields.map((field) => (field.type === 'tabs' ? updatedTabsField : field))\n}\n\nconst ensureCollectionsArray = (collections: Config['collections']): CollectionConfig[] =>\n Array.isArray(collections) ? collections : []\n\nconst ensureEndpointsArray = (endpoints: Config['endpoints']): NonNullable<Config['endpoints']> =>\n Array.isArray(endpoints) ? endpoints : []\n\ntype NormalizedLivePreviewOptions = {\n enabled: boolean\n pageCollection: string\n pageSlug: string\n fallbackToFirstPage: boolean\n tenantField: string\n tenantQueryParam: string\n breakpoints?: ThemeManagementLivePreviewOptions['breakpoints']\n url?: ThemeManagementLivePreviewOptions['url']\n}\n\ntype NormalizedCacheRevalidationOptions = {\n enabled: boolean\n injectRoute: boolean\n routePath: string\n secret?: string\n tags: string[]\n paths: string[]\n}\n\ntype MinimalPayloadRequest = ThemeManagementLivePreviewUrlArgs['req']\n\nconst normalizeLivePreviewOptions = (\n livePreview: ThemeManagementPluginOptions['livePreview'],\n): NormalizedLivePreviewOptions => {\n if (livePreview === false) {\n return {\n enabled: false,\n pageCollection: 'pages',\n pageSlug: 'home',\n fallbackToFirstPage: true,\n tenantField: 'tenant',\n tenantQueryParam: 'tenant',\n breakpoints: undefined,\n }\n }\n\n const raw = typeof livePreview === 'object' && livePreview ? livePreview : {}\n\n return {\n enabled: raw.enabled ?? true,\n pageCollection: raw.pageCollection ?? 'pages',\n pageSlug: raw.pageSlug ?? 'home',\n fallbackToFirstPage: raw.fallbackToFirstPage ?? true,\n tenantField: raw.tenantField ?? 'tenant',\n tenantQueryParam: raw.tenantQueryParam ?? 'tenant',\n breakpoints: raw.breakpoints,\n url: raw.url,\n }\n}\n\nconst dedupeStrings = (values: (string | undefined)[]): string[] => [\n ...new Set(\n values.filter((value): value is string => typeof value === 'string' && value.trim().length > 0),\n ),\n]\n\nconst normalizeRoutePath = (path: string | undefined): string => {\n if (!path || !path.trim()) {\n return '/theme/revalidate'\n }\n\n return path.startsWith('/') ? path : `/${path}`\n}\n\nconst normalizeCacheRevalidationOptions = (args: {\n cacheRevalidation: ThemeManagementPluginOptions['cacheRevalidation']\n standaloneCollectionSlug: string\n useStandaloneCollection: boolean\n}): NormalizedCacheRevalidationOptions => {\n const { cacheRevalidation, standaloneCollectionSlug, useStandaloneCollection } = args\n\n if (cacheRevalidation === false) {\n return {\n enabled: false,\n injectRoute: false,\n routePath: '/theme/revalidate',\n tags: [],\n paths: [],\n }\n }\n\n const raw = typeof cacheRevalidation === 'object' && cacheRevalidation ? cacheRevalidation : {}\n const defaultTag = `global_${standaloneCollectionSlug}`\n\n return {\n enabled: raw.enabled ?? useStandaloneCollection,\n injectRoute: raw.injectRoute ?? true,\n routePath: normalizeRoutePath(raw.routePath),\n secret: raw.secret,\n tags: dedupeStrings([defaultTag, ...(raw.tags ?? [])]),\n paths: dedupeStrings(raw.paths ?? []),\n }\n}\n\nconst asRecord = (value: unknown): Record<string, unknown> | undefined => {\n if (value && typeof value === 'object') {\n return value as Record<string, unknown>\n }\n return undefined\n}\n\nconst pickString = (value: unknown): string | undefined => {\n if (typeof value === 'string' && value.trim()) return value\n return undefined\n}\n\nconst extractTenantValue = (value: unknown): string | undefined => {\n if (!value) return undefined\n if (typeof value === 'string') return pickString(value)\n\n const tenantRecord = asRecord(value)\n if (!tenantRecord) return undefined\n\n return (\n pickString(tenantRecord.id) ??\n pickString(tenantRecord.slug) ??\n pickString(tenantRecord.value) ??\n pickString(tenantRecord.tenant)\n )\n}\n\nconst resolveTenantSlug = (\n req: MinimalPayloadRequest,\n tenantField: string,\n data?: Record<string, unknown>,\n): string | undefined => {\n const fromData = extractTenantValue(data?.[tenantField])\n if (fromData) return fromData\n\n const query = req.query\n if (query && typeof URLSearchParams !== 'undefined' && query instanceof URLSearchParams) {\n return (\n pickString(query.get('tenant')) ??\n pickString(query.get('tenantSlug')) ??\n pickString(query.get('tenantId'))\n )\n }\n\n const queryRecord = asRecord(query)\n const fromQuery =\n extractTenantValue(queryRecord?.tenant) ??\n extractTenantValue(queryRecord?.tenantSlug) ??\n extractTenantValue(queryRecord?.tenantId)\n if (fromQuery) return fromQuery\n\n const userRecord = asRecord(req.user)\n const fromUser =\n extractTenantValue(userRecord?.[tenantField]) ??\n extractTenantValue(userRecord?.tenant) ??\n extractTenantValue(userRecord?.tenantSlug)\n if (fromUser) return fromUser\n\n const headers = req.headers\n if (headers && typeof Headers !== 'undefined' && headers instanceof Headers) {\n return (\n pickString(headers.get('x-tenant-id')) ??\n pickString(headers.get('x-tenant')) ??\n pickString(headers.get('payload-tenant'))\n )\n }\n\n const headerRecord = asRecord(headers)\n return (\n extractTenantValue(headerRecord?.['x-tenant-id']) ??\n extractTenantValue(headerRecord?.['x-tenant']) ??\n extractTenantValue(headerRecord?.['payload-tenant'])\n )\n}\n\nconst buildDefaultPreviewPath = (\n pageSlug: string,\n tenantSlug: string | undefined,\n tenantQueryParam: string,\n): string => {\n const normalizedSlug = pageSlug === 'home' ? '' : pageSlug\n const basePath = normalizedSlug ? `/${normalizedSlug}` : '/'\n\n if (!tenantSlug) {\n return basePath\n }\n\n const separator = basePath.includes('?') ? '&' : '?'\n return `${basePath}${separator}${tenantQueryParam}=${encodeURIComponent(tenantSlug)}`\n}\n\nconst resolveLivePreviewUrl = async (args: {\n req: MinimalPayloadRequest\n data?: Record<string, unknown>\n livePreview: NormalizedLivePreviewOptions\n enableLogging: boolean\n}): Promise<string> => {\n const { req, data, livePreview, enableLogging } = args\n\n const tenantSlug = resolveTenantSlug(req, livePreview.tenantField, data)\n\n const tenantWhere = tenantSlug\n ? {\n [livePreview.tenantField]: {\n equals: tenantSlug,\n },\n }\n : undefined\n\n const homeWhere = {\n and: [\n {\n slug: {\n equals: livePreview.pageSlug,\n },\n },\n ...(tenantWhere ? [tenantWhere] : []),\n ],\n }\n\n try {\n const preferredPageResponse = await req.payload.find({\n collection: livePreview.pageCollection,\n where: homeWhere,\n depth: 0,\n draft: true,\n limit: 1,\n overrideAccess: true,\n pagination: false,\n })\n\n let page = preferredPageResponse?.docs?.[0]\n\n if (!page && livePreview.fallbackToFirstPage) {\n const fallbackResponse = await req.payload.find({\n collection: livePreview.pageCollection,\n where: tenantWhere,\n depth: 0,\n draft: true,\n limit: 1,\n overrideAccess: true,\n pagination: false,\n })\n\n page = fallbackResponse?.docs?.[0]\n }\n\n const pageRecord = asRecord(page)\n const resolvedPageSlug = pickString(pageRecord?.slug) ?? livePreview.pageSlug\n\n if (livePreview.url) {\n return await livePreview.url({\n page: pageRecord,\n pageSlug: resolvedPageSlug,\n tenantSlug,\n req,\n })\n }\n\n return buildDefaultPreviewPath(resolvedPageSlug, tenantSlug, livePreview.tenantQueryParam)\n } catch (error) {\n if (enableLogging) {\n req.payload.logger?.warn?.(\n '🎨 Theme Management Plugin: live preview URL fallback used',\n error,\n )\n }\n\n return buildDefaultPreviewPath(livePreview.pageSlug, tenantSlug, livePreview.tenantQueryParam)\n }\n}\n\nconst createPreviewAdminConfig = (\n normalizedLivePreview: NormalizedLivePreviewOptions,\n enableLogging: boolean,\n) => {\n if (!normalizedLivePreview.enabled) {\n return {}\n }\n\n return {\n livePreview: {\n breakpoints: normalizedLivePreview.breakpoints,\n url: ({ data, req }: { data?: unknown; req: unknown }) =>\n resolveLivePreviewUrl({\n req: req as MinimalPayloadRequest,\n data: asRecord(data),\n livePreview: normalizedLivePreview,\n enableLogging,\n }),\n },\n preview: (data: Record<string, unknown>, options: { req?: unknown }) => {\n const req = options?.req\n if (!req) return null\n\n return resolveLivePreviewUrl({\n req: req as MinimalPayloadRequest,\n data,\n livePreview: normalizedLivePreview,\n enableLogging,\n })\n },\n }\n}\n\nconst readSecretFromRequest = async (req: unknown): Promise<string | undefined> => {\n const requestRecord = asRecord(req)\n const headersValue = requestRecord?.headers\n\n if (headersValue && typeof Headers !== 'undefined' && headersValue instanceof Headers) {\n return (\n pickString(headersValue.get('x-theme-revalidate-secret')) ??\n pickString(headersValue.get('x-revalidate-secret'))\n )\n }\n\n const headerRecord = asRecord(headersValue)\n const fromHeaders =\n pickString(headerRecord?.['x-theme-revalidate-secret']) ??\n pickString(headerRecord?.['x-revalidate-secret'])\n if (fromHeaders) {\n return fromHeaders\n }\n\n const requestWithJson = req as { json?: () => Promise<unknown> }\n const body =\n typeof requestWithJson?.json === 'function' ? await requestWithJson.json() : undefined\n const bodyRecord = asRecord(body)\n const fromBody = pickString(bodyRecord?.secret)\n if (fromBody) {\n return fromBody\n }\n\n const queryRecord = asRecord(requestRecord?.query)\n return pickString(queryRecord?.secret)\n}\n\nconst executeThemeRevalidation = async (options: {\n tags: string[]\n paths: string[]\n enableLogging: boolean\n logger?: { info?: (...args: any[]) => void; error?: (...args: any[]) => void }\n}): Promise<{ tags: string[]; paths: string[] }> => {\n const { tags, paths, enableLogging, logger } = options\n\n try {\n const { revalidatePath, revalidateTag } = await import('next/cache')\n\n tags.forEach((tag) => revalidateTag(tag))\n paths.forEach((path) => revalidatePath(path))\n\n if (enableLogging) {\n logger?.info?.(\n `🎨 Theme Management Plugin: revalidated cache tags=[${tags.join(', ')}] paths=[${paths.join(', ')}]`,\n )\n }\n } catch (error) {\n if (enableLogging) {\n logger?.error?.('🎨 Theme Management Plugin: cache invalidation failed:', error)\n }\n throw error\n }\n\n return { tags, paths }\n}\n\nconst createCacheRevalidationEndpoint = (options: {\n cacheRevalidation: NormalizedCacheRevalidationOptions\n enableLogging: boolean\n}) => {\n const { cacheRevalidation, enableLogging } = options\n\n if (!cacheRevalidation.enabled || !cacheRevalidation.injectRoute) {\n return null\n }\n\n return {\n path: cacheRevalidation.routePath,\n method: 'post',\n handler: async (req: unknown) => {\n const reqRecord = asRecord(req)\n const payload = asRecord(reqRecord?.payload)\n const logger = payload?.logger as\n | { info?: (...args: any[]) => void; error?: (...args: any[]) => void }\n | undefined\n\n if (cacheRevalidation.secret) {\n const providedSecret = await readSecretFromRequest(req)\n if (providedSecret !== cacheRevalidation.secret) {\n return jsonResponse({ error: 'Unauthorized' }, 401)\n }\n }\n\n try {\n const result = await executeThemeRevalidation({\n tags: cacheRevalidation.tags,\n paths: cacheRevalidation.paths,\n enableLogging,\n logger,\n })\n\n return jsonResponse({ ok: true, revalidated: result })\n } catch {\n return jsonResponse({ ok: false, error: 'Revalidation failed' }, 500)\n }\n },\n }\n}\n\nconst mergeEndpoint = (\n endpoints: NonNullable<Config['endpoints']>,\n endpoint: ReturnType<typeof createCacheRevalidationEndpoint>,\n): NonNullable<Config['endpoints']> => {\n if (!endpoint) {\n return endpoints\n }\n\n const withoutExisting = endpoints.filter((candidate) => {\n const record = candidate as unknown as { path?: string; method?: string }\n return !(\n record?.path === endpoint.path &&\n typeof record.method === 'string' &&\n record.method.toLowerCase() === endpoint.method\n )\n })\n\n return [...withoutExisting, endpoint as unknown as NonNullable<Config['endpoints']>[number]]\n}\n\nconst jsonResponse = (body: Record<string, unknown>, status = 200): unknown => {\n if (typeof Response !== 'undefined' && typeof Response.json === 'function') {\n return Response.json(body, { status })\n }\n\n return {\n status,\n json: async () => body,\n }\n}\n\nexport const themeManagementPlugin = (options: ThemeManagementPluginOptions = {}): Plugin => {\n return (config: Config): Config => {\n const {\n enabled = true,\n targetCollection = 'site-settings',\n useStandaloneCollection = false,\n standaloneCollectionSlug = 'appearance-settings',\n // Allow either string or localized object; default comes from plugin translations\n standaloneCollectionLabel = getTranslations().standaloneCollectionLabel,\n themePresets = allThemePresets,\n defaultTheme = 'cool',\n includeColorModeToggle = true,\n includeCustomCSS = true,\n includeBrandIdentity = false,\n enableAdvancedFeatures = true,\n enableLogging = false,\n livePreview = true,\n cacheRevalidation,\n } = options\n\n const normalizedLivePreview = normalizeLivePreviewOptions(livePreview)\n const normalizedCacheRevalidation = normalizeCacheRevalidationOptions({\n cacheRevalidation,\n standaloneCollectionSlug,\n useStandaloneCollection,\n })\n\n if (!enabled) {\n if (enableLogging) {\n console.log('🎨 Theme Management Plugin: disabled via options, skipping.')\n }\n return config\n }\n\n const themeTab = createThemeConfigurationField({\n themePresets,\n defaultTheme,\n includeColorModeToggle,\n includeCustomCSS,\n includeBrandIdentity: includeBrandIdentity ?? false,\n enableAdvancedFeatures,\n useThemePreviewField: !normalizedLivePreview.enabled,\n })\n\n // If using standalone collection, create a new global\n if (useStandaloneCollection) {\n if (enableLogging) {\n console.log(\n `🎨 Theme Management Plugin: creating standalone global \"${standaloneCollectionSlug}\"`,\n )\n }\n\n // Extract the fields from the tab directly (no wrapping in group)\n const tabFields = (themeTab.fields ?? []) as Field[]\n\n /**\n * Hook to auto-populate lightMode and darkMode colors when theme changes\n */\n type BeforeChangeArgs = {\n data?: {\n themeConfiguration?: {\n theme?: string\n lightMode?: Record<string, unknown>\n darkMode?: Record<string, unknown>\n }\n }\n }\n\n const beforeChangeHook = async (args: BeforeChangeArgs) => {\n const { data } = args\n\n // If theme is being changed, auto-populate color modes\n if (data?.themeConfiguration?.theme) {\n const themeName = data.themeConfiguration.theme\n const selectedPreset = themePresets.find((p) => p.name === themeName)\n\n if (selectedPreset) {\n // Initialize light and dark mode colors from preset if not already set\n if (!data.themeConfiguration.lightMode) {\n data.themeConfiguration.lightMode = {}\n }\n if (!data.themeConfiguration.darkMode) {\n data.themeConfiguration.darkMode = {}\n }\n\n // Only populate if not manually edited (first time or empty)\n const isLightModeEmpty = !data.themeConfiguration.lightMode?.background\n const isDarkModeEmpty = !data.themeConfiguration.darkMode?.background\n\n if (isLightModeEmpty && selectedPreset.lightMode) {\n data.themeConfiguration.lightMode = { ...selectedPreset.lightMode }\n }\n\n if (isDarkModeEmpty && selectedPreset.darkMode) {\n data.themeConfiguration.darkMode = { ...selectedPreset.darkMode }\n }\n }\n }\n\n return data\n }\n\n const standaloneGlobal: GlobalConfig = {\n slug: standaloneCollectionSlug,\n label: standaloneCollectionLabel,\n admin: {\n group: 'Settings',\n ...createPreviewAdminConfig(normalizedLivePreview, enableLogging),\n },\n // Provide a broad access object but cast to GlobalConfig['access'] to satisfy types\n access: ((): GlobalConfig['access'] => {\n const accessObj = {\n read: () => true,\n create: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n update: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n delete: ({ req }: { req?: { user?: unknown } }) => !!req?.user,\n } as unknown as GlobalConfig['access']\n return accessObj\n })(),\n fields: tabFields,\n hooks: {\n beforeChange: [beforeChangeHook],\n afterChange: [\n async ({ doc, req }) => {\n // Invalidate cache after appearance settings change\n if (!req?.context?.disableRevalidate && normalizedCacheRevalidation.enabled) {\n try {\n await executeThemeRevalidation({\n tags: normalizedCacheRevalidation.tags,\n paths: normalizedCacheRevalidation.paths,\n enableLogging,\n logger: req?.payload?.logger,\n })\n } catch {\n // no-op: logging is handled in executeThemeRevalidation\n }\n }\n return doc\n },\n ],\n },\n }\n\n const globals = Array.isArray(config.globals) ? config.globals : []\n\n // Check if global already exists\n const existingIndex = globals.findIndex((g) => g.slug === standaloneCollectionSlug)\n\n if (existingIndex !== -1) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: global \"${standaloneCollectionSlug}\" already exists, skipping creation.`,\n )\n }\n return config\n }\n\n const currentEndpoints = ensureEndpointsArray(config.endpoints)\n const cacheEndpoint = createCacheRevalidationEndpoint({\n cacheRevalidation: normalizedCacheRevalidation,\n enableLogging,\n })\n const endpoints = mergeEndpoint(currentEndpoints, cacheEndpoint)\n\n return {\n ...config,\n endpoints,\n globals: [...globals, standaloneGlobal],\n }\n }\n\n // Otherwise, add as tab to existing collection\n let collectionTouched = false\n\n const collections = ensureCollectionsArray(config.collections).map((collection) => {\n if (collection.slug !== targetCollection) {\n return collection\n }\n\n collectionTouched = true\n\n if (enableLogging) {\n console.log(`🎨 Theme Management Plugin: enhancing collection \"${collection.slug}\"`)\n }\n\n const existingFields = Array.isArray(collection.fields) ? collection.fields : []\n\n const fields = injectThemeTab(existingFields, themeTab, enableLogging)\n\n const admin = {\n ...collection.admin,\n ...createPreviewAdminConfig(normalizedLivePreview, enableLogging),\n }\n\n return {\n ...collection,\n fields,\n admin,\n }\n })\n\n if (!collectionTouched) {\n if (enableLogging) {\n console.warn(\n `🎨 Theme Management Plugin: collection \"${targetCollection}\" was not found, leaving config untouched.`,\n )\n }\n return config\n }\n\n const currentEndpoints = ensureEndpointsArray(config.endpoints)\n const cacheEndpoint = createCacheRevalidationEndpoint({\n cacheRevalidation: normalizedCacheRevalidation,\n enableLogging,\n })\n const endpoints = mergeEndpoint(currentEndpoints, cacheEndpoint)\n\n return {\n ...config,\n endpoints,\n collections,\n }\n }\n}\n\ntype FetchOptionsInput = string | FetchThemeConfigurationOptions\n\nexport const fetchThemeConfiguration = async (\n options?: FetchOptionsInput,\n): Promise<SiteThemeConfiguration | null> => {\n const normalizedOptions = typeof options === 'string' ? { tenantSlug: options } : (options ?? {})\n\n const {\n tenantSlug,\n collectionSlug = 'site-settings', // Can be overridden to 'appearance-settings' if using standalone\n depth,\n locale,\n draft,\n queryParams = {},\n useGlobal = false, // Set to true if using standalone global instead of collection\n } = normalizedOptions\n\n try {\n if (useGlobal) {\n // Fetch from global endpoint\n const params = new URLSearchParams()\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For globals, keep tenant param for backwards compatibility, and also add where[...] filter\n if (tenantSlug) {\n params.set('tenant', tenantSlug)\n params.set('where[tenant][equals]', String(tenantSlug))\n }\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const queryString = params.toString()\n const url = `/api/globals/${collectionSlug}${queryString ? `?${queryString}` : ''}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme global (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n themeConfiguration?: SiteThemeConfiguration\n }\n\n return data?.themeConfiguration ?? null\n } else {\n // Fetch from collection endpoint (legacy/default behavior)\n const params = new URLSearchParams({ limit: '1' })\n\n if (typeof depth === 'number') params.set('depth', String(depth))\n // For collections, use a where[tenant][equals] filter so Payload's find endpoint applies tenant scoping\n if (tenantSlug) params.set('where[tenant][equals]', String(tenantSlug))\n if (locale) params.set('locale', locale)\n if (draft) params.set('draft', 'true')\n\n Object.entries(queryParams).forEach(([key, value]) => {\n if (value === undefined) return\n params.set(key, String(value))\n })\n\n const url = `/api/${collectionSlug}?${params.toString()}`\n\n const response = await fetch(url)\n if (!response.ok) {\n throw new Error(`Failed to fetch theme configuration (status ${response.status})`)\n }\n\n const data = (await response.json()) as {\n docs?: Array<{ themeConfiguration?: SiteThemeConfiguration }>\n }\n\n const doc = data.docs?.[0]\n\n return doc?.themeConfiguration ?? null\n }\n } catch (error) {\n console.warn('Failed to fetch theme configuration:', error)\n return null\n }\n}\n\nexport const getThemePreset = (themeName: string): ThemePreset | null => {\n return allThemePresets.find((preset) => preset.name === themeName) || null\n}\n\nexport const getAvailableThemePresets = (): ThemePreset[] => {\n return allThemePresets\n}\n\nexport { defaultThemePresets, allThemePresets } from './presets.js'\nexport type { ThemePreset, ThemeTypographyPreset } from './presets.js'\nexport type { ThemeTab } from './fields/themeConfigurationField.js'\nexport {\n extendedThemePresets,\n allExtendedThemePresets,\n extendedThemeToCSSVariables,\n} from './extended-presets.js'\nexport type { ExtendedThemePreset, ShadcnColorTokens } from './extended-presets.js'\nexport {\n applyExtendedTheme,\n generateExtendedThemeCSS,\n resetExtendedTheme,\n getExtendedThemeTokens,\n createUseExtendedTheme,\n getTailwindVarReferences,\n} from './utils/extendedThemeHelpers.js'\nexport type {\n ThemeManagementPluginOptions,\n ThemeManagementCacheRevalidationOptions,\n FetchThemeConfigurationOptions,\n ThemeManagementLivePreviewOptions,\n ThemeManagementLivePreviewUrlArgs,\n} from './types.js'\nexport {\n DEFAULT_THEME_CONFIGURATION,\n resolveThemeConfiguration,\n} from './utils/resolveThemeConfiguration.js'\nexport type { ResolvedThemeConfiguration } from './utils/resolveThemeConfiguration.js'\nexport { generateThemeColorsCss, hexToHsl } from './utils/themeColors.js'\nexport { generateThemeCSS, getThemeStyles } from './utils/themeUtils.js'\nexport { getThemeHtmlAttributes } from './utils/themeHtmlAttributes.js'\n\n// Dynamic theme CSS generation\nexport {\n generateThemeCSS as generatePresetCSS,\n generateAllThemesCSS,\n} from './utils/generateThemeCSS.js'\nexport { getThemeDynamicCSS, getAllDynamicThemesCSS } from './utils/themeCSS.js'\n\nexport type { Mode, ThemeDefaults } from './providers/Theme/types.js'\nexport { ThemeProvider } from './providers/Theme/index.js'\n\n// Font loading utilities for Next.js integration\nexport {\n getFontLoaderCode,\n getThemeFontFamilies,\n ThemeFontProvider,\n useThemeFonts,\n FONT_IMPORT_MAP,\n} from './providers/font-loader.js'\n\n// Note: Do NOT re-export client components from the root entry to avoid\n// server-side evaluation during `payload generate:importmap`.\n// If needed, import directly from subpath: `@kilivi/payloadcms-theme-management/fields/ThemeLivePreview`\n\nexport const ThemeManagementPlugin = themeManagementPlugin\n/** @deprecated use {@link themeManagementPlugin} */\nexport const themeConfigurationPlugin = themeManagementPlugin\n\n// Export plugin translations for consumers to merge into their payload translations\nexport {\n translations,\n getTranslations,\n registerTranslations,\n availableLanguages,\n} from './translations.js'\n\nexport default themeManagementPlugin\n"],"names":["createThemeConfigurationField","allThemePresets","getTranslations","translations","THEME_FIELD_NAME","removeExistingThemeField","fields","filter","field","candidate","name","findTabsField","type","removeExistingThemeTab","tabs","knownLabels","Object","values","map","t","tabLabel","tab","labelValues","label","matchesKnown","some","v","includes","injectThemeTab","themeTab","enableLogging","sanitizedFields","tabsField","console","warn","newTabsField","sanitizedTabs","updatedTabs","log","updatedTabsField","ensureCollectionsArray","collections","Array","isArray","ensureEndpointsArray","endpoints","normalizeLivePreviewOptions","livePreview","enabled","pageCollection","pageSlug","fallbackToFirstPage","tenantField","tenantQueryParam","breakpoints","undefined","raw","url","dedupeStrings","Set","value","trim","length","normalizeRoutePath","path","startsWith","normalizeCacheRevalidationOptions","args","cacheRevalidation","standaloneCollectionSlug","useStandaloneCollection","injectRoute","routePath","tags","paths","defaultTag","secret","asRecord","pickString","extractTenantValue","tenantRecord","id","slug","tenant","resolveTenantSlug","req","data","fromData","query","URLSearchParams","get","queryRecord","fromQuery","tenantSlug","tenantId","userRecord","user","fromUser","headers","Headers","headerRecord","buildDefaultPreviewPath","normalizedSlug","basePath","separator","encodeURIComponent","resolveLivePreviewUrl","tenantWhere","equals","homeWhere","and","preferredPageResponse","payload","find","collection","where","depth","draft","limit","overrideAccess","pagination","page","docs","fallbackResponse","pageRecord","resolvedPageSlug","error","logger","createPreviewAdminConfig","normalizedLivePreview","preview","options","readSecretFromRequest","requestRecord","headersValue","fromHeaders","requestWithJson","body","json","bodyRecord","fromBody","executeThemeRevalidation","revalidatePath","revalidateTag","forEach","tag","info","join","createCacheRevalidationEndpoint","method","handler","reqRecord","providedSecret","jsonResponse","result","ok","revalidated","mergeEndpoint","endpoint","withoutExisting","record","toLowerCase","status","Response","themeManagementPlugin","config","targetCollection","standaloneCollectionLabel","themePresets","defaultTheme","includeColorModeToggle","includeCustomCSS","includeBrandIdentity","enableAdvancedFeatures","normalizedCacheRevalidation","useThemePreviewField","tabFields","beforeChangeHook","themeConfiguration","theme","themeName","selectedPreset","p","lightMode","darkMode","isLightModeEmpty","background","isDarkModeEmpty","standaloneGlobal","admin","group","access","accessObj","read","create","update","delete","hooks","beforeChange","afterChange","doc","context","disableRevalidate","globals","existingIndex","findIndex","g","currentEndpoints","cacheEndpoint","collectionTouched","existingFields","fetchThemeConfiguration","normalizedOptions","collectionSlug","locale","queryParams","useGlobal","params","set","String","entries","key","queryString","toString","response","fetch","Error","getThemePreset","preset","getAvailableThemePresets","defaultThemePresets","extendedThemePresets","allExtendedThemePresets","extendedThemeToCSSVariables","applyExtendedTheme","generateExtendedThemeCSS","resetExtendedTheme","getExtendedThemeTokens","createUseExtendedTheme","getTailwindVarReferences","DEFAULT_THEME_CONFIGURATION","resolveThemeConfiguration","generateThemeColorsCss","hexToHsl","generateThemeCSS","getThemeStyles","getThemeHtmlAttributes","generatePresetCSS","generateAllThemesCSS","getThemeDynamicCSS","getAllDynamicThemesCSS","ThemeProvider","getFontLoaderCode","getThemeFontFamilies","ThemeFontProvider","useThemeFonts","FONT_IMPORT_MAP","ThemeManagementPlugin","themeConfigurationPlugin","registerTranslations","availableLanguages"],"mappings":"AACA,SAASA,6BAA6B,QAAQ,sCAAqC;AAInF,SAASC,eAAe,QAAQ,eAAc;AAC9C,SAASC,eAAe,EAAEC,YAAY,QAAQ,oBAAmB;AAQjE,MAAMC,mBAAmB;AAEzB;;CAEC,GACD,MAAMC,2BAA2B,CAACC,SAAkB,EAAE,GACpDA,OAAOC,MAAM,CAAC,CAACC;QACb,MAAMC,YAAYD;QAClB,OAAOC,WAAWC,SAASN;IAC7B;AAEF;;CAEC,GACD,MAAMO,gBAAgB,CAACL,SAAkB,EAAE;IACzC,KAAK,MAAME,SAASF,OAAQ;QAC1B,IAAIE,MAAMI,IAAI,KAAK,QAAQ;YACzB,OAAOJ;QACT;IACF;IACA,OAAO;AACT;AAEA;;CAEC,GACD,MAAMK,yBAAyB,CAC7BC;IAEA,MAAMC,cAAcC,OAAOC,MAAM,CAACd,cAAce,GAAG,CAAC,CAACC,IAAMA,EAAEC,QAAQ;IACrE,OAAON,KAAKP,MAAM,CAAC,CAACc;QAClB,uEAAuE;QACvE,IAAIC,cAAwB,EAAE;QAC9B,IAAI,OAAOD,IAAIE,KAAK,KAAK,YAAYF,IAAIE,KAAK,KAAK,MAAM;YACvDD,cAAcN,OAAOC,MAAM,CAACI,IAAIE,KAAK;QACvC,OAAO,IAAI,OAAOF,IAAIE,KAAK,KAAK,UAAU;YACxCD,cAAc;gBAACD,IAAIE,KAAK;aAAC;QAC3B;QAEA,uEAAuE;QACvE,MAAMC,eAAeF,YAAYG,IAAI,CAAC,CAACC,IAAMX,YAAYY,QAAQ,CAACD;QAElE,OAAO,CAACF;IACV;AACF;AAEA;;CAEC,GACD,MAAMI,iBAAiB,CACrBtB,QACAuB,UACAC;IAEA,qDAAqD;IACrD,MAAMC,kBAAkB1B,yBAAyBC,UAAU,EAAE;IAE7D,sBAAsB;IACtB,MAAM0B,YAAYrB,cAAcoB;IAEhC,IAAI,CAACC,aAAa,CAACA,UAAUlB,IAAI,EAAE;QACjC,IAAIgB,eAAe;YACjBG,QAAQC,IAAI,CACV;QAEJ;QAEA,0EAA0E;QAC1E,MAAMC,eAA0B;YAC9BvB,MAAM;YACNE,MAAM;gBAACe;aAAS;QAClB;QAEA,OAAO;eAAIE;YAAiBI;SAAa;IAC3C;IAEA,uCAAuC;IACvC,MAAMC,gBAAgBvB,uBAAuBmB,UAAUlB,IAAI;IAE3D,2BAA2B;IAC3B,MAAMuB,cAAc;WAAID;QAAeP;KAAS;IAEhD,IAAIC,eAAe;QACjBG,QAAQK,GAAG,CAAC;IACd;IAEA,wBAAwB;IACxB,MAAMC,mBAA8B;QAClC,GAAGP,SAAS;QACZlB,MAAMuB;IACR;IAEA,kDAAkD;IAClD,OAAON,gBAAgBb,GAAG,CAAC,CAACV,QAAWA,MAAMI,IAAI,KAAK,SAAS2B,mBAAmB/B;AACpF;AAEA,MAAMgC,yBAAyB,CAACC,cAC9BC,MAAMC,OAAO,CAACF,eAAeA,cAAc,EAAE;AAE/C,MAAMG,uBAAuB,CAACC,YAC5BH,MAAMC,OAAO,CAACE,aAAaA,YAAY,EAAE;AAwB3C,MAAMC,8BAA8B,CAClCC;IAEA,IAAIA,gBAAgB,OAAO;QACzB,OAAO;YACLC,SAAS;YACTC,gBAAgB;YAChBC,UAAU;YACVC,qBAAqB;YACrBC,aAAa;YACbC,kBAAkB;YAClBC,aAAaC;QACf;IACF;IAEA,MAAMC,MAAM,OAAOT,gBAAgB,YAAYA,cAAcA,cAAc,CAAC;IAE5E,OAAO;QACLC,SAASQ,IAAIR,OAAO,IAAI;QACxBC,gBAAgBO,IAAIP,cAAc,IAAI;QACtCC,UAAUM,IAAIN,QAAQ,IAAI;QAC1BC,qBAAqBK,IAAIL,mBAAmB,IAAI;QAChDC,aAAaI,IAAIJ,WAAW,IAAI;QAChCC,kBAAkBG,IAAIH,gBAAgB,IAAI;QAC1CC,aAAaE,IAAIF,WAAW;QAC5BG,KAAKD,IAAIC,GAAG;IACd;AACF;AAEA,MAAMC,gBAAgB,CAACzC,SAA6C;WAC/D,IAAI0C,IACL1C,OAAOV,MAAM,CAAC,CAACqD,QAA2B,OAAOA,UAAU,YAAYA,MAAMC,IAAI,GAAGC,MAAM,GAAG;KAEhG;AAED,MAAMC,qBAAqB,CAACC;IAC1B,IAAI,CAACA,QAAQ,CAACA,KAAKH,IAAI,IAAI;QACzB,OAAO;IACT;IAEA,OAAOG,KAAKC,UAAU,CAAC,OAAOD,OAAO,CAAC,CAAC,EAAEA,MAAM;AACjD;AAEA,MAAME,oCAAoC,CAACC;IAKzC,MAAM,EAAEC,iBAAiB,EAAEC,wBAAwB,EAAEC,uBAAuB,EAAE,GAAGH;IAEjF,IAAIC,sBAAsB,OAAO;QAC/B,OAAO;YACLpB,SAAS;YACTuB,aAAa;YACbC,WAAW;YACXC,MAAM,EAAE;YACRC,OAAO,EAAE;QACX;IACF;IAEA,MAAMlB,MAAM,OAAOY,sBAAsB,YAAYA,oBAAoBA,oBAAoB,CAAC;IAC9F,MAAMO,aAAa,CAAC,OAAO,EAAEN,0BAA0B;IAEvD,OAAO;QACLrB,SAASQ,IAAIR,OAAO,IAAIsB;QACxBC,aAAaf,IAAIe,WAAW,IAAI;QAChCC,WAAWT,mBAAmBP,IAAIgB,SAAS;QAC3CI,QAAQpB,IAAIoB,MAAM;QAClBH,MAAMf,cAAc;YAACiB;eAAgBnB,IAAIiB,IAAI,IAAI,EAAE;SAAE;QACrDC,OAAOhB,cAAcF,IAAIkB,KAAK,IAAI,EAAE;IACtC;AACF;AAEA,MAAMG,WAAW,CAACjB;IAChB,IAAIA,SAAS,OAAOA,UAAU,UAAU;QACtC,OAAOA;IACT;IACA,OAAOL;AACT;AAEA,MAAMuB,aAAa,CAAClB;IAClB,IAAI,OAAOA,UAAU,YAAYA,MAAMC,IAAI,IAAI,OAAOD;IACtD,OAAOL;AACT;AAEA,MAAMwB,qBAAqB,CAACnB;IAC1B,IAAI,CAACA,OAAO,OAAOL;IACnB,IAAI,OAAOK,UAAU,UAAU,OAAOkB,WAAWlB;IAEjD,MAAMoB,eAAeH,SAASjB;IAC9B,IAAI,CAACoB,cAAc,OAAOzB;IAE1B,OACEuB,WAAWE,aAAaC,EAAE,KAC1BH,WAAWE,aAAaE,IAAI,KAC5BJ,WAAWE,aAAapB,KAAK,KAC7BkB,WAAWE,aAAaG,MAAM;AAElC;AAEA,MAAMC,oBAAoB,CACxBC,KACAjC,aACAkC;IAEA,MAAMC,WAAWR,mBAAmBO,MAAM,CAAClC,YAAY;IACvD,IAAImC,UAAU,OAAOA;IAErB,MAAMC,QAAQH,IAAIG,KAAK;IACvB,IAAIA,SAAS,OAAOC,oBAAoB,eAAeD,iBAAiBC,iBAAiB;QACvF,OACEX,WAAWU,MAAME,GAAG,CAAC,cACrBZ,WAAWU,MAAME,GAAG,CAAC,kBACrBZ,WAAWU,MAAME,GAAG,CAAC;IAEzB;IAEA,MAAMC,cAAcd,SAASW;IAC7B,MAAMI,YACJb,mBAAmBY,aAAaR,WAChCJ,mBAAmBY,aAAaE,eAChCd,mBAAmBY,aAAaG;IAClC,IAAIF,WAAW,OAAOA;IAEtB,MAAMG,aAAalB,SAASQ,IAAIW,IAAI;IACpC,MAAMC,WACJlB,mBAAmBgB,YAAY,CAAC3C,YAAY,KAC5C2B,mBAAmBgB,YAAYZ,WAC/BJ,mBAAmBgB,YAAYF;IACjC,IAAII,UAAU,OAAOA;IAErB,MAAMC,UAAUb,IAAIa,OAAO;IAC3B,IAAIA,WAAW,OAAOC,YAAY,eAAeD,mBAAmBC,SAAS;QAC3E,OACErB,WAAWoB,QAAQR,GAAG,CAAC,mBACvBZ,WAAWoB,QAAQR,GAAG,CAAC,gBACvBZ,WAAWoB,QAAQR,GAAG,CAAC;IAE3B;IAEA,MAAMU,eAAevB,SAASqB;IAC9B,OACEnB,mBAAmBqB,cAAc,CAAC,cAAc,KAChDrB,mBAAmBqB,cAAc,CAAC,WAAW,KAC7CrB,mBAAmBqB,cAAc,CAAC,iBAAiB;AAEvD;AAEA,MAAMC,0BAA0B,CAC9BnD,UACA2C,YACAxC;IAEA,MAAMiD,iBAAiBpD,aAAa,SAAS,KAAKA;IAClD,MAAMqD,WAAWD,iBAAiB,CAAC,CAAC,EAAEA,gBAAgB,GAAG;IAEzD,IAAI,CAACT,YAAY;QACf,OAAOU;IACT;IAEA,MAAMC,YAAYD,SAAS5E,QAAQ,CAAC,OAAO,MAAM;IACjD,OAAO,GAAG4E,WAAWC,YAAYnD,iBAAiB,CAAC,EAAEoD,mBAAmBZ,aAAa;AACvF;AAEA,MAAMa,wBAAwB,OAAOvC;IAMnC,MAAM,EAAEkB,GAAG,EAAEC,IAAI,EAAEvC,WAAW,EAAEjB,aAAa,EAAE,GAAGqC;IAElD,MAAM0B,aAAaT,kBAAkBC,KAAKtC,YAAYK,WAAW,EAAEkC;IAEnE,MAAMqB,cAAcd,aAChB;QACE,CAAC9C,YAAYK,WAAW,CAAC,EAAE;YACzBwD,QAAQf;QACV;IACF,IACAtC;IAEJ,MAAMsD,YAAY;QAChBC,KAAK;YACH;gBACE5B,MAAM;oBACJ0B,QAAQ7D,YAAYG,QAAQ;gBAC9B;YACF;eACIyD,cAAc;gBAACA;aAAY,GAAG,EAAE;SACrC;IACH;IAEA,IAAI;QACF,MAAMI,wBAAwB,MAAM1B,IAAI2B,OAAO,CAACC,IAAI,CAAC;YACnDC,YAAYnE,YAAYE,cAAc;YACtCkE,OAAON;YACPO,OAAO;YACPC,OAAO;YACPC,OAAO;YACPC,gBAAgB;YAChBC,YAAY;QACd;QAEA,IAAIC,OAAOV,uBAAuBW,MAAM,CAAC,EAAE;QAE3C,IAAI,CAACD,QAAQ1E,YAAYI,mBAAmB,EAAE;YAC5C,MAAMwE,mBAAmB,MAAMtC,IAAI2B,OAAO,CAACC,IAAI,CAAC;gBAC9CC,YAAYnE,YAAYE,cAAc;gBACtCkE,OAAOR;gBACPS,OAAO;gBACPC,OAAO;gBACPC,OAAO;gBACPC,gBAAgB;gBAChBC,YAAY;YACd;YAEAC,OAAOE,kBAAkBD,MAAM,CAAC,EAAE;QACpC;QAEA,MAAME,aAAa/C,SAAS4C;QAC5B,MAAMI,mBAAmB/C,WAAW8C,YAAY1C,SAASnC,YAAYG,QAAQ;QAE7E,IAAIH,YAAYU,GAAG,EAAE;YACnB,OAAO,MAAMV,YAAYU,GAAG,CAAC;gBAC3BgE,MAAMG;gBACN1E,UAAU2E;gBACVhC;gBACAR;YACF;QACF;QAEA,OAAOgB,wBAAwBwB,kBAAkBhC,YAAY9C,YAAYM,gBAAgB;IAC3F,EAAE,OAAOyE,OAAO;QACd,IAAIhG,eAAe;YACjBuD,IAAI2B,OAAO,CAACe,MAAM,EAAE7F,OAClB,8DACA4F;QAEJ;QAEA,OAAOzB,wBAAwBtD,YAAYG,QAAQ,EAAE2C,YAAY9C,YAAYM,gBAAgB;IAC/F;AACF;AAEA,MAAM2E,2BAA2B,CAC/BC,uBACAnG;IAEA,IAAI,CAACmG,sBAAsBjF,OAAO,EAAE;QAClC,OAAO,CAAC;IACV;IAEA,OAAO;QACLD,aAAa;YACXO,aAAa2E,sBAAsB3E,WAAW;YAC9CG,KAAK,CAAC,EAAE6B,IAAI,EAAED,GAAG,EAAoC,GACnDqB,sBAAsB;oBACpBrB,KAAKA;oBACLC,MAAMT,SAASS;oBACfvC,aAAakF;oBACbnG;gBACF;QACJ;QACAoG,SAAS,CAAC5C,MAA+B6C;YACvC,MAAM9C,MAAM8C,SAAS9C;YACrB,IAAI,CAACA,KAAK,OAAO;YAEjB,OAAOqB,sBAAsB;gBAC3BrB,KAAKA;gBACLC;gBACAvC,aAAakF;gBACbnG;YACF;QACF;IACF;AACF;AAEA,MAAMsG,wBAAwB,OAAO/C;IACnC,MAAMgD,gBAAgBxD,SAASQ;IAC/B,MAAMiD,eAAeD,eAAenC;IAEpC,IAAIoC,gBAAgB,OAAOnC,YAAY,eAAemC,wBAAwBnC,SAAS;QACrF,OACErB,WAAWwD,aAAa5C,GAAG,CAAC,iCAC5BZ,WAAWwD,aAAa5C,GAAG,CAAC;IAEhC;IAEA,MAAMU,eAAevB,SAASyD;IAC9B,MAAMC,cACJzD,WAAWsB,cAAc,CAAC,4BAA4B,KACtDtB,WAAWsB,cAAc,CAAC,sBAAsB;IAClD,IAAImC,aAAa;QACf,OAAOA;IACT;IAEA,MAAMC,kBAAkBnD;IACxB,MAAMoD,OACJ,OAAOD,iBAAiBE,SAAS,aAAa,MAAMF,gBAAgBE,IAAI,KAAKnF;IAC/E,MAAMoF,aAAa9D,SAAS4D;IAC5B,MAAMG,WAAW9D,WAAW6D,YAAY/D;IACxC,IAAIgE,UAAU;QACZ,OAAOA;IACT;IAEA,MAAMjD,cAAcd,SAASwD,eAAe7C;IAC5C,OAAOV,WAAWa,aAAaf;AACjC;AAEA,MAAMiE,2BAA2B,OAAOV;IAMtC,MAAM,EAAE1D,IAAI,EAAEC,KAAK,EAAE5C,aAAa,EAAEiG,MAAM,EAAE,GAAGI;IAE/C,IAAI;QACF,MAAM,EAAEW,cAAc,EAAEC,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC;QAEvDtE,KAAKuE,OAAO,CAAC,CAACC,MAAQF,cAAcE;QACpCvE,MAAMsE,OAAO,CAAC,CAAChF,OAAS8E,eAAe9E;QAEvC,IAAIlC,eAAe;YACjBiG,QAAQmB,OACN,CAAC,oDAAoD,EAAEzE,KAAK0E,IAAI,CAAC,MAAM,SAAS,EAAEzE,MAAMyE,IAAI,CAAC,MAAM,CAAC,CAAC;QAEzG;IACF,EAAE,OAAOrB,OAAO;QACd,IAAIhG,eAAe;YACjBiG,QAAQD,QAAQ,0DAA0DA;QAC5E;QACA,MAAMA;IACR;IAEA,OAAO;QAAErD;QAAMC;IAAM;AACvB;AAEA,MAAM0E,kCAAkC,CAACjB;IAIvC,MAAM,EAAE/D,iBAAiB,EAAEtC,aAAa,EAAE,GAAGqG;IAE7C,IAAI,CAAC/D,kBAAkBpB,OAAO,IAAI,CAACoB,kBAAkBG,WAAW,EAAE;QAChE,OAAO;IACT;IAEA,OAAO;QACLP,MAAMI,kBAAkBI,SAAS;QACjC6E,QAAQ;QACRC,SAAS,OAAOjE;YACd,MAAMkE,YAAY1E,SAASQ;YAC3B,MAAM2B,UAAUnC,SAAS0E,WAAWvC;YACpC,MAAMe,SAASf,SAASe;YAIxB,IAAI3D,kBAAkBQ,MAAM,EAAE;gBAC5B,MAAM4E,iBAAiB,MAAMpB,sBAAsB/C;gBACnD,IAAImE,mBAAmBpF,kBAAkBQ,MAAM,EAAE;oBAC/C,OAAO6E,aAAa;wBAAE3B,OAAO;oBAAe,GAAG;gBACjD;YACF;YAEA,IAAI;gBACF,MAAM4B,SAAS,MAAMb,yBAAyB;oBAC5CpE,MAAML,kBAAkBK,IAAI;oBAC5BC,OAAON,kBAAkBM,KAAK;oBAC9B5C;oBACAiG;gBACF;gBAEA,OAAO0B,aAAa;oBAAEE,IAAI;oBAAMC,aAAaF;gBAAO;YACtD,EAAE,OAAM;gBACN,OAAOD,aAAa;oBAAEE,IAAI;oBAAO7B,OAAO;gBAAsB,GAAG;YACnE;QACF;IACF;AACF;AAEA,MAAM+B,gBAAgB,CACpBhH,WACAiH;IAEA,IAAI,CAACA,UAAU;QACb,OAAOjH;IACT;IAEA,MAAMkH,kBAAkBlH,UAAUtC,MAAM,CAAC,CAACE;QACxC,MAAMuJ,SAASvJ;QACf,OAAO,CACLuJ,CAAAA,QAAQhG,SAAS8F,SAAS9F,IAAI,IAC9B,OAAOgG,OAAOX,MAAM,KAAK,YACzBW,OAAOX,MAAM,CAACY,WAAW,OAAOH,SAAST,MAAM,AAAD;IAElD;IAEA,OAAO;WAAIU;QAAiBD;KAAgE;AAC9F;AAEA,MAAML,eAAe,CAAChB,MAA+ByB,SAAS,GAAG;IAC/D,IAAI,OAAOC,aAAa,eAAe,OAAOA,SAASzB,IAAI,KAAK,YAAY;QAC1E,OAAOyB,SAASzB,IAAI,CAACD,MAAM;YAAEyB;QAAO;IACtC;IAEA,OAAO;QACLA;QACAxB,MAAM,UAAYD;IACpB;AACF;AAEA,OAAO,MAAM2B,wBAAwB,CAACjC,UAAwC,CAAC,CAAC;IAC9E,OAAO,CAACkC;QACN,MAAM,EACJrH,UAAU,IAAI,EACdsH,mBAAmB,eAAe,EAClChG,0BAA0B,KAAK,EAC/BD,2BAA2B,qBAAqB,EAChD,kFAAkF;QAClFkG,4BAA4BrK,kBAAkBqK,yBAAyB,EACvEC,eAAevK,eAAe,EAC9BwK,eAAe,MAAM,EACrBC,yBAAyB,IAAI,EAC7BC,mBAAmB,IAAI,EACvBC,uBAAuB,KAAK,EAC5BC,yBAAyB,IAAI,EAC7B/I,gBAAgB,KAAK,EACrBiB,cAAc,IAAI,EAClBqB,iBAAiB,EAClB,GAAG+D;QAEJ,MAAMF,wBAAwBnF,4BAA4BC;QAC1D,MAAM+H,8BAA8B5G,kCAAkC;YACpEE;YACAC;YACAC;QACF;QAEA,IAAI,CAACtB,SAAS;YACZ,IAAIlB,eAAe;gBACjBG,QAAQK,GAAG,CAAC;YACd;YACA,OAAO+H;QACT;QAEA,MAAMxI,WAAW7B,8BAA8B;YAC7CwK;YACAC;YACAC;YACAC;YACAC,sBAAsBA,wBAAwB;YAC9CC;YACAE,sBAAsB,CAAC9C,sBAAsBjF,OAAO;QACtD;QAEA,sDAAsD;QACtD,IAAIsB,yBAAyB;YAC3B,IAAIxC,eAAe;gBACjBG,QAAQK,GAAG,CACT,CAAC,wDAAwD,EAAE+B,yBAAyB,CAAC,CAAC;YAE1F;YAEA,kEAAkE;YAClE,MAAM2G,YAAanJ,SAASvB,MAAM,IAAI,EAAE;YAexC,MAAM2K,mBAAmB,OAAO9G;gBAC9B,MAAM,EAAEmB,IAAI,EAAE,GAAGnB;gBAEjB,uDAAuD;gBACvD,IAAImB,MAAM4F,oBAAoBC,OAAO;oBACnC,MAAMC,YAAY9F,KAAK4F,kBAAkB,CAACC,KAAK;oBAC/C,MAAME,iBAAiBb,aAAavD,IAAI,CAAC,CAACqE,IAAMA,EAAE5K,IAAI,KAAK0K;oBAE3D,IAAIC,gBAAgB;wBAClB,uEAAuE;wBACvE,IAAI,CAAC/F,KAAK4F,kBAAkB,CAACK,SAAS,EAAE;4BACtCjG,KAAK4F,kBAAkB,CAACK,SAAS,GAAG,CAAC;wBACvC;wBACA,IAAI,CAACjG,KAAK4F,kBAAkB,CAACM,QAAQ,EAAE;4BACrClG,KAAK4F,kBAAkB,CAACM,QAAQ,GAAG,CAAC;wBACtC;wBAEA,6DAA6D;wBAC7D,MAAMC,mBAAmB,CAACnG,KAAK4F,kBAAkB,CAACK,SAAS,EAAEG;wBAC7D,MAAMC,kBAAkB,CAACrG,KAAK4F,kBAAkB,CAACM,QAAQ,EAAEE;wBAE3D,IAAID,oBAAoBJ,eAAeE,SAAS,EAAE;4BAChDjG,KAAK4F,kBAAkB,CAACK,SAAS,GAAG;gCAAE,GAAGF,eAAeE,SAAS;4BAAC;wBACpE;wBAEA,IAAII,mBAAmBN,eAAeG,QAAQ,EAAE;4BAC9ClG,KAAK4F,kBAAkB,CAACM,QAAQ,GAAG;gCAAE,GAAGH,eAAeG,QAAQ;4BAAC;wBAClE;oBACF;gBACF;gBAEA,OAAOlG;YACT;YAEA,MAAMsG,mBAAiC;gBACrC1G,MAAMb;gBACN9C,OAAOgJ;gBACPsB,OAAO;oBACLC,OAAO;oBACP,GAAG9D,yBAAyBC,uBAAuBnG,cAAc;gBACnE;gBACA,oFAAoF;gBACpFiK,QAAQ,AAAC,CAAA;oBACP,MAAMC,YAAY;wBAChBC,MAAM,IAAM;wBACZC,QAAQ,CAAC,EAAE7G,GAAG,EAAgC,GAAK,CAAC,CAACA,KAAKW;wBAC1DmG,QAAQ,CAAC,EAAE9G,GAAG,EAAgC,GAAK,CAAC,CAACA,KAAKW;wBAC1DoG,QAAQ,CAAC,EAAE/G,GAAG,EAAgC,GAAK,CAAC,CAACA,KAAKW;oBAC5D;oBACA,OAAOgG;gBACT,CAAA;gBACA1L,QAAQ0K;gBACRqB,OAAO;oBACLC,cAAc;wBAACrB;qBAAiB;oBAChCsB,aAAa;wBACX,OAAO,EAAEC,GAAG,EAAEnH,GAAG,EAAE;4BACjB,oDAAoD;4BACpD,IAAI,CAACA,KAAKoH,SAASC,qBAAqB5B,4BAA4B9H,OAAO,EAAE;gCAC3E,IAAI;oCACF,MAAM6F,yBAAyB;wCAC7BpE,MAAMqG,4BAA4BrG,IAAI;wCACtCC,OAAOoG,4BAA4BpG,KAAK;wCACxC5C;wCACAiG,QAAQ1C,KAAK2B,SAASe;oCACxB;gCACF,EAAE,OAAM;gCACN,wDAAwD;gCAC1D;4BACF;4BACA,OAAOyE;wBACT;qBACD;gBACH;YACF;YAEA,MAAMG,UAAUjK,MAAMC,OAAO,CAAC0H,OAAOsC,OAAO,IAAItC,OAAOsC,OAAO,GAAG,EAAE;YAEnE,iCAAiC;YACjC,MAAMC,gBAAgBD,QAAQE,SAAS,CAAC,CAACC,IAAMA,EAAE5H,IAAI,KAAKb;YAE1D,IAAIuI,kBAAkB,CAAC,GAAG;gBACxB,IAAI9K,eAAe;oBACjBG,QAAQC,IAAI,CACV,CAAC,oCAAoC,EAAEmC,yBAAyB,oCAAoC,CAAC;gBAEzG;gBACA,OAAOgG;YACT;YAEA,MAAM0C,mBAAmBnK,qBAAqByH,OAAOxH,SAAS;YAC9D,MAAMmK,gBAAgB5D,gCAAgC;gBACpDhF,mBAAmB0G;gBACnBhJ;YACF;YACA,MAAMe,YAAYgH,cAAckD,kBAAkBC;YAElD,OAAO;gBACL,GAAG3C,MAAM;gBACTxH;gBACA8J,SAAS;uBAAIA;oBAASf;iBAAiB;YACzC;QACF;QAEA,+CAA+C;QAC/C,IAAIqB,oBAAoB;QAExB,MAAMxK,cAAcD,uBAAuB6H,OAAO5H,WAAW,EAAEvB,GAAG,CAAC,CAACgG;YAClE,IAAIA,WAAWhC,IAAI,KAAKoF,kBAAkB;gBACxC,OAAOpD;YACT;YAEA+F,oBAAoB;YAEpB,IAAInL,eAAe;gBACjBG,QAAQK,GAAG,CAAC,CAAC,kDAAkD,EAAE4E,WAAWhC,IAAI,CAAC,CAAC,CAAC;YACrF;YAEA,MAAMgI,iBAAiBxK,MAAMC,OAAO,CAACuE,WAAW5G,MAAM,IAAI4G,WAAW5G,MAAM,GAAG,EAAE;YAEhF,MAAMA,SAASsB,eAAesL,gBAAgBrL,UAAUC;YAExD,MAAM+J,QAAQ;gBACZ,GAAG3E,WAAW2E,KAAK;gBACnB,GAAG7D,yBAAyBC,uBAAuBnG,cAAc;YACnE;YAEA,OAAO;gBACL,GAAGoF,UAAU;gBACb5G;gBACAuL;YACF;QACF;QAEA,IAAI,CAACoB,mBAAmB;YACtB,IAAInL,eAAe;gBACjBG,QAAQC,IAAI,CACV,CAAC,wCAAwC,EAAEoI,iBAAiB,0CAA0C,CAAC;YAE3G;YACA,OAAOD;QACT;QAEA,MAAM0C,mBAAmBnK,qBAAqByH,OAAOxH,SAAS;QAC9D,MAAMmK,gBAAgB5D,gCAAgC;YACpDhF,mBAAmB0G;YACnBhJ;QACF;QACA,MAAMe,YAAYgH,cAAckD,kBAAkBC;QAElD,OAAO;YACL,GAAG3C,MAAM;YACTxH;YACAJ;QACF;IACF;AACF,EAAC;AAID,OAAO,MAAM0K,0BAA0B,OACrChF;IAEA,MAAMiF,oBAAoB,OAAOjF,YAAY,WAAW;QAAEtC,YAAYsC;IAAQ,IAAKA,WAAW,CAAC;IAE/F,MAAM,EACJtC,UAAU,EACVwH,iBAAiB,eAAe,EAChCjG,KAAK,EACLkG,MAAM,EACNjG,KAAK,EACLkG,cAAc,CAAC,CAAC,EAChBC,YAAY,KAAK,EAClB,GAAGJ;IAEJ,IAAI;QACF,IAAII,WAAW;YACb,6BAA6B;YAC7B,MAAMC,SAAS,IAAIhI;YAEnB,IAAI,OAAO2B,UAAU,UAAUqG,OAAOC,GAAG,CAAC,SAASC,OAAOvG;YAC1D,6FAA6F;YAC7F,IAAIvB,YAAY;gBACd4H,OAAOC,GAAG,CAAC,UAAU7H;gBACrB4H,OAAOC,GAAG,CAAC,yBAAyBC,OAAO9H;YAC7C;YAEA7E,OAAO4M,OAAO,CAACL,aAAavE,OAAO,CAAC,CAAC,CAAC6E,KAAKjK,MAAM;gBAC/C,IAAIA,UAAUL,WAAW;gBACzBkK,OAAOC,GAAG,CAACG,KAAKF,OAAO/J;YACzB;YAEA,MAAMkK,cAAcL,OAAOM,QAAQ;YACnC,MAAMtK,MAAM,CAAC,aAAa,EAAE4J,iBAAiBS,cAAc,CAAC,CAAC,EAAEA,aAAa,GAAG,IAAI;YAEnF,MAAME,WAAW,MAAMC,MAAMxK;YAC7B,IAAI,CAACuK,SAASrE,EAAE,EAAE;gBAChB,MAAM,IAAIuE,MAAM,CAAC,qCAAqC,EAAEF,SAAS9D,MAAM,CAAC,CAAC,CAAC;YAC5E;YAEA,MAAM5E,OAAQ,MAAM0I,SAAStF,IAAI;YAIjC,OAAOpD,MAAM4F,sBAAsB;QACrC,OAAO;YACL,2DAA2D;YAC3D,MAAMuC,SAAS,IAAIhI,gBAAgB;gBAAE6B,OAAO;YAAI;YAEhD,IAAI,OAAOF,UAAU,UAAUqG,OAAOC,GAAG,CAAC,SAASC,OAAOvG;YAC1D,wGAAwG;YACxG,IAAIvB,YAAY4H,OAAOC,GAAG,CAAC,yBAAyBC,OAAO9H;YAC3D,IAAIyH,QAAQG,OAAOC,GAAG,CAAC,UAAUJ;YACjC,IAAIjG,OAAOoG,OAAOC,GAAG,CAAC,SAAS;YAE/B1M,OAAO4M,OAAO,CAACL,aAAavE,OAAO,CAAC,CAAC,CAAC6E,KAAKjK,MAAM;gBAC/C,IAAIA,UAAUL,WAAW;gBACzBkK,OAAOC,GAAG,CAACG,KAAKF,OAAO/J;YACzB;YAEA,MAAMH,MAAM,CAAC,KAAK,EAAE4J,eAAe,CAAC,EAAEI,OAAOM,QAAQ,IAAI;YAEzD,MAAMC,WAAW,MAAMC,MAAMxK;YAC7B,IAAI,CAACuK,SAASrE,EAAE,EAAE;gBAChB,MAAM,IAAIuE,MAAM,CAAC,4CAA4C,EAAEF,SAAS9D,MAAM,CAAC,CAAC,CAAC;YACnF;YAEA,MAAM5E,OAAQ,MAAM0I,SAAStF,IAAI;YAIjC,MAAM8D,MAAMlH,KAAKoC,IAAI,EAAE,CAAC,EAAE;YAE1B,OAAO8E,KAAKtB,sBAAsB;QACpC;IACF,EAAE,OAAOpD,OAAO;QACd7F,QAAQC,IAAI,CAAC,wCAAwC4F;QACrD,OAAO;IACT;AACF,EAAC;AAED,OAAO,MAAMqG,iBAAiB,CAAC/C;IAC7B,OAAOnL,gBAAgBgH,IAAI,CAAC,CAACmH,SAAWA,OAAO1N,IAAI,KAAK0K,cAAc;AACxE,EAAC;AAED,OAAO,MAAMiD,2BAA2B;IACtC,OAAOpO;AACT,EAAC;AAED,SAASqO,mBAAmB,EAAErO,eAAe,QAAQ,eAAc;AAGnE,SACEsO,oBAAoB,EACpBC,uBAAuB,EACvBC,2BAA2B,QACtB,wBAAuB;AAE9B,SACEC,kBAAkB,EAClBC,wBAAwB,EACxBC,kBAAkB,EAClBC,sBAAsB,EACtBC,sBAAsB,EACtBC,wBAAwB,QACnB,kCAAiC;AAQxC,SACEC,2BAA2B,EAC3BC,yBAAyB,QACpB,uCAAsC;AAE7C,SAASC,sBAAsB,EAAEC,QAAQ,QAAQ,yBAAwB;AACzE,SAASC,gBAAgB,EAAEC,cAAc,QAAQ,wBAAuB;AACxE,SAASC,sBAAsB,QAAQ,iCAAgC;AAEvE,+BAA+B;AAC/B,SACEF,oBAAoBG,iBAAiB,EACrCC,oBAAoB,QACf,8BAA6B;AACpC,SAASC,kBAAkB,EAAEC,sBAAsB,QAAQ,sBAAqB;AAGhF,SAASC,aAAa,QAAQ,6BAA4B;AAE1D,iDAAiD;AACjD,SACEC,iBAAiB,EACjBC,oBAAoB,EACpBC,iBAAiB,EACjBC,aAAa,EACbC,eAAe,QACV,6BAA4B;AAEnC,wEAAwE;AACxE,8DAA8D;AAC9D,yGAAyG;AAEzG,OAAO,MAAMC,wBAAwB7F,sBAAqB;AAC1D,kDAAkD,GAClD,OAAO,MAAM8F,2BAA2B9F,sBAAqB;AAE7D,oFAAoF;AACpF,SACEjK,YAAY,EACZD,eAAe,EACfiQ,oBAAoB,EACpBC,kBAAkB,QACb,oBAAmB;AAE1B,eAAehG,sBAAqB"}
|
package/dist/server.d.ts
CHANGED
|
@@ -1,4 +1,34 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
|
+
import type { SiteThemeConfiguration } from './payload-types.js';
|
|
2
3
|
export { ServerThemeInjector } from './components/ServerThemeInjector.js';
|
|
3
4
|
export { createFallbackCriticalCSS, getThemeCriticalCSS, getThemeCSS, generateThemePreloadLinks, getThemeCSSPath, } from './utils/themeAssets.js';
|
|
5
|
+
export declare const getThemeCacheTag: (globalSlug?: string) => string;
|
|
6
|
+
interface ThemeGlobalLike {
|
|
7
|
+
themeConfiguration?: SiteThemeConfiguration | null;
|
|
8
|
+
}
|
|
9
|
+
interface CreateCachedThemeFetcherOptions {
|
|
10
|
+
/** Function that loads the appearance global document. */
|
|
11
|
+
loadAppearanceSettings: () => Promise<ThemeGlobalLike | null | undefined>;
|
|
12
|
+
/** Optional global slug used for default cache tag and key (default: 'appearance-settings'). */
|
|
13
|
+
globalSlug?: string;
|
|
14
|
+
/** Additional cache key parts passed to unstable_cache. */
|
|
15
|
+
cacheKeyParts?: string[];
|
|
16
|
+
/** Additional tags to include besides the default `global_{slug}` tag. */
|
|
17
|
+
tags?: string[];
|
|
18
|
+
/** Next.js revalidate interval in seconds (default: 3600). */
|
|
19
|
+
revalidate?: number | false;
|
|
20
|
+
}
|
|
21
|
+
export declare const createCachedThemeFetcher: (options: CreateCachedThemeFetcherOptions) => () => Promise<import("./index.js").ResolvedThemeConfiguration>;
|
|
22
|
+
interface RevalidateThemeCacheOptions {
|
|
23
|
+
/** Optional global slug for default tag (default: 'appearance-settings'). */
|
|
24
|
+
globalSlug?: string;
|
|
25
|
+
/** Extra cache tags to invalidate. */
|
|
26
|
+
tags?: string[];
|
|
27
|
+
/** Optional paths to invalidate with revalidatePath. */
|
|
28
|
+
paths?: string[];
|
|
29
|
+
}
|
|
30
|
+
export declare const revalidateThemeCache: (options?: RevalidateThemeCacheOptions) => Promise<{
|
|
31
|
+
tags: string[];
|
|
32
|
+
paths: string[];
|
|
33
|
+
}>;
|
|
4
34
|
//# sourceMappingURL=server.d.ts.map
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AAEzE,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,eAAe,GAChB,MAAM,wBAAwB,CAAA"}
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAA;AAMhE,OAAO,EAAE,mBAAmB,EAAE,MAAM,qCAAqC,CAAA;AAEzE,OAAO,EACL,yBAAyB,EACzB,mBAAmB,EACnB,WAAW,EACX,yBAAyB,EACzB,eAAe,GAChB,MAAM,wBAAwB,CAAA;AAE/B,eAAO,MAAM,gBAAgB,GAAI,mBAAkC,KAAG,MAC9C,CAAA;AAExB,UAAU,eAAe;IACvB,kBAAkB,CAAC,EAAE,sBAAsB,GAAG,IAAI,CAAA;CACnD;AAED,UAAU,+BAA+B;IACvC,0DAA0D;IAC1D,sBAAsB,EAAE,MAAM,OAAO,CAAC,eAAe,GAAG,IAAI,GAAG,SAAS,CAAC,CAAA;IACzE,gGAAgG;IAChG,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,2DAA2D;IAC3D,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,0EAA0E;IAC1E,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,GAAG,KAAK,CAAA;CAC5B;AAED,eAAO,MAAM,wBAAwB,GAAI,SAAS,+BAA+B,mEA0BhF,CAAA;AAED,UAAU,2BAA2B;IACnC,6EAA6E;IAC7E,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,sCAAsC;IACtC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,wDAAwD;IACxD,KAAK,CAAC,EAAE,MAAM,EAAE,CAAA;CACjB;AAED,eAAO,MAAM,oBAAoB,GAC/B,UAAS,2BAAgC,KACxC,OAAO,CAAC;IAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,EAAE,CAAA;CAAE,CAa7C,CAAA"}
|