@duffcloudservices/cms-core 0.4.4 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{browser-BAFXkAvg.d.ts → browser-Ds57q3s6.d.ts} +28 -3
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +166 -3
- package/dist/browser.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +166 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -408,7 +408,10 @@ interface FetchOptions {
|
|
|
408
408
|
* Fetch runtime content from the DCS API.
|
|
409
409
|
* This is a premium tier feature - returns 403 for non-premium sites.
|
|
410
410
|
*
|
|
411
|
-
* @param siteSlug - The site's slug identifier
|
|
411
|
+
* @param siteSlug - The site's slug identifier.
|
|
412
|
+
* @deprecated The site is now resolved server-side from the request Host or the
|
|
413
|
+
* dedicated Container App's `DCS_SITE_SLUG`. This argument is retained for source
|
|
414
|
+
* compatibility but is ignored for routing (no longer placed in the URL path).
|
|
412
415
|
* @param options - Fetch options
|
|
413
416
|
* @returns Content configuration or null if fetch fails
|
|
414
417
|
*/
|
|
@@ -417,10 +420,32 @@ declare function fetchRuntimeContent(siteSlug: string, options?: FetchOptions):
|
|
|
417
420
|
* Fetch runtime SEO configuration from the DCS API.
|
|
418
421
|
* This is a premium tier feature - returns 403 for non-premium sites.
|
|
419
422
|
*
|
|
420
|
-
* @param siteSlug - The site's slug identifier
|
|
423
|
+
* @param siteSlug - The site's slug identifier.
|
|
424
|
+
* @deprecated The site is now resolved server-side from the request Host or the
|
|
425
|
+
* dedicated Container App's `DCS_SITE_SLUG`. This argument is retained for source
|
|
426
|
+
* compatibility but is ignored for routing (no longer placed in the URL path).
|
|
421
427
|
* @param options - Fetch options
|
|
422
428
|
* @returns SEO configuration or null if fetch fails
|
|
423
429
|
*/
|
|
424
430
|
declare function fetchRuntimeSeo(siteSlug: string, options?: FetchOptions): Promise<SeoConfiguration | null>;
|
|
425
431
|
|
|
426
|
-
|
|
432
|
+
type DcsPasskeyOptions = {
|
|
433
|
+
apiBaseUrl?: string;
|
|
434
|
+
returnTo?: string;
|
|
435
|
+
immediate?: boolean;
|
|
436
|
+
};
|
|
437
|
+
type DcsPasskeyResult = {
|
|
438
|
+
success: boolean;
|
|
439
|
+
redirectTo?: string;
|
|
440
|
+
visitor?: {
|
|
441
|
+
email: string;
|
|
442
|
+
name: string;
|
|
443
|
+
picture?: string;
|
|
444
|
+
};
|
|
445
|
+
};
|
|
446
|
+
declare const isDcsPasskeySupported: () => boolean;
|
|
447
|
+
declare const isDcsPasskeyImmediateUIAvailable: () => Promise<boolean>;
|
|
448
|
+
declare const registerDcsSitePasskey: (options?: DcsPasskeyOptions) => Promise<string | null>;
|
|
449
|
+
declare const authenticateDcsSitePasskey: (options?: DcsPasskeyOptions) => Promise<DcsPasskeyResult>;
|
|
450
|
+
|
|
451
|
+
export { type ContentConfiguration as C, type DcsPasskeyOptions as D, type FetchOptions as F, type GlobalSeoConfig as G, type MetaTag as M, type PagesConfiguration as P, type ResolvedSeo as R, type SeoConfiguration as S, type UnifiedConfiguration as U, type ContentConfigurationV1 as a, type PageSeoConfig as b, type SeoAuthorConfig as c, type SeoSocialConfig as d, type SeoImagesConfig as e, type SeoOpenGraphConfig as f, type SeoTwitterConfig as g, type SeoSchemaConfig as h, type SeoAlternateConfig as i, type SeoVerificationConfig as j, type PageEntry as k, type UnifiedSiteConfig as l, getPageContent as m, getGlobalContent as n, resolveSeoForPage as o, buildMetaTags as p, fetchRuntimeContent as q, resolveTextKey as r, fetchRuntimeSeo as s, authenticateDcsSitePasskey as t, isDcsPasskeyImmediateUIAvailable as u, isDcsPasskeySupported as v, registerDcsSitePasskey as w, type DcsPasskeyResult as x };
|
package/dist/browser.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { C as ContentConfiguration, a as ContentConfigurationV1, F as FetchOptions, G as GlobalSeoConfig, M as MetaTag, k as PageEntry, b as PageSeoConfig, P as PagesConfiguration, R as ResolvedSeo, i as SeoAlternateConfig, c as SeoAuthorConfig, S as SeoConfiguration, e as SeoImagesConfig, f as SeoOpenGraphConfig, h as SeoSchemaConfig, d as SeoSocialConfig, g as SeoTwitterConfig, j as SeoVerificationConfig, p as buildMetaTags, q as fetchRuntimeContent, s as fetchRuntimeSeo, n as getGlobalContent, m as getPageContent, o as resolveSeoForPage, r as resolveTextKey } from './browser-
|
|
1
|
+
export { C as ContentConfiguration, a as ContentConfigurationV1, D as DcsPasskeyOptions, x as DcsPasskeyResult, F as FetchOptions, G as GlobalSeoConfig, M as MetaTag, k as PageEntry, b as PageSeoConfig, P as PagesConfiguration, R as ResolvedSeo, i as SeoAlternateConfig, c as SeoAuthorConfig, S as SeoConfiguration, e as SeoImagesConfig, f as SeoOpenGraphConfig, h as SeoSchemaConfig, d as SeoSocialConfig, g as SeoTwitterConfig, j as SeoVerificationConfig, t as authenticateDcsSitePasskey, p as buildMetaTags, q as fetchRuntimeContent, s as fetchRuntimeSeo, n as getGlobalContent, m as getPageContent, u as isDcsPasskeyImmediateUIAvailable, v as isDcsPasskeySupported, w as registerDcsSitePasskey, o as resolveSeoForPage, r as resolveTextKey } from './browser-Ds57q3s6.js';
|
package/dist/browser.js
CHANGED
|
@@ -142,7 +142,7 @@ async function fetchRuntimeContent(siteSlug, options = {}) {
|
|
|
142
142
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
143
143
|
try {
|
|
144
144
|
const response = await fetch(
|
|
145
|
-
`${apiBaseUrl}/
|
|
145
|
+
`${apiBaseUrl}/api/v1/content/runtime`,
|
|
146
146
|
{
|
|
147
147
|
method: "GET",
|
|
148
148
|
headers: {
|
|
@@ -178,7 +178,7 @@ async function fetchRuntimeSeo(siteSlug, options = {}) {
|
|
|
178
178
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
179
179
|
try {
|
|
180
180
|
const response = await fetch(
|
|
181
|
-
`${apiBaseUrl}/
|
|
181
|
+
`${apiBaseUrl}/api/v1/seo/runtime`,
|
|
182
182
|
{
|
|
183
183
|
method: "GET",
|
|
184
184
|
headers: {
|
|
@@ -209,6 +209,169 @@ async function fetchRuntimeSeo(siteSlug, options = {}) {
|
|
|
209
209
|
}
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
-
|
|
212
|
+
// src/passkeys.ts
|
|
213
|
+
var getPublicKeyCredentialConstructor = () => {
|
|
214
|
+
if (typeof window === "undefined" || typeof window.PublicKeyCredential === "undefined") {
|
|
215
|
+
return void 0;
|
|
216
|
+
}
|
|
217
|
+
return window.PublicKeyCredential;
|
|
218
|
+
};
|
|
219
|
+
var apiBase = (value) => (value ?? "/api/v1").replace(/\/$/u, "");
|
|
220
|
+
var base64UrlToBuffer = (value) => {
|
|
221
|
+
const base64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
222
|
+
const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
|
|
223
|
+
const raw = window.atob(padded);
|
|
224
|
+
const output = new Uint8Array(raw.length);
|
|
225
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
226
|
+
output[index] = raw.charCodeAt(index);
|
|
227
|
+
}
|
|
228
|
+
return output.buffer;
|
|
229
|
+
};
|
|
230
|
+
var bufferToBase64Url = (value) => {
|
|
231
|
+
if (!value) {
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
const bytes = new Uint8Array(value);
|
|
235
|
+
let binary = "";
|
|
236
|
+
bytes.forEach((byte) => {
|
|
237
|
+
binary += String.fromCharCode(byte);
|
|
238
|
+
});
|
|
239
|
+
return window.btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/u, "");
|
|
240
|
+
};
|
|
241
|
+
var decodeDescriptors = (items) => {
|
|
242
|
+
if (!Array.isArray(items)) {
|
|
243
|
+
return void 0;
|
|
244
|
+
}
|
|
245
|
+
return items.map((item) => {
|
|
246
|
+
const descriptor = item;
|
|
247
|
+
return {
|
|
248
|
+
...descriptor,
|
|
249
|
+
id: typeof descriptor.id === "string" ? base64UrlToBuffer(descriptor.id) : descriptor.id,
|
|
250
|
+
type: descriptor.type ?? "public-key"
|
|
251
|
+
};
|
|
252
|
+
});
|
|
253
|
+
};
|
|
254
|
+
var decodeCreationOptions = (publicKey) => {
|
|
255
|
+
const user = publicKey.user;
|
|
256
|
+
return {
|
|
257
|
+
...publicKey,
|
|
258
|
+
challenge: base64UrlToBuffer(String(publicKey.challenge)),
|
|
259
|
+
user: {
|
|
260
|
+
...user ?? {},
|
|
261
|
+
id: typeof user?.id === "string" ? base64UrlToBuffer(user.id) : user?.id
|
|
262
|
+
},
|
|
263
|
+
excludeCredentials: decodeDescriptors(publicKey.excludeCredentials)
|
|
264
|
+
};
|
|
265
|
+
};
|
|
266
|
+
var decodeRequestOptions = (publicKey) => ({
|
|
267
|
+
...publicKey,
|
|
268
|
+
challenge: base64UrlToBuffer(String(publicKey.challenge)),
|
|
269
|
+
allowCredentials: decodeDescriptors(publicKey.allowCredentials)
|
|
270
|
+
});
|
|
271
|
+
var serializeCredential = (credential) => {
|
|
272
|
+
const response = credential.response;
|
|
273
|
+
const base = {
|
|
274
|
+
id: credential.id,
|
|
275
|
+
type: credential.type,
|
|
276
|
+
rawId: bufferToBase64Url(credential.rawId),
|
|
277
|
+
authenticatorAttachment: credential.authenticatorAttachment,
|
|
278
|
+
clientExtensionResults: credential.getClientExtensionResults()
|
|
279
|
+
};
|
|
280
|
+
if (response instanceof AuthenticatorAttestationResponse) {
|
|
281
|
+
return {
|
|
282
|
+
...base,
|
|
283
|
+
response: {
|
|
284
|
+
clientDataJSON: bufferToBase64Url(response.clientDataJSON),
|
|
285
|
+
attestationObject: bufferToBase64Url(response.attestationObject),
|
|
286
|
+
transports: response.getTransports?.() ?? []
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
const assertion = response;
|
|
291
|
+
return {
|
|
292
|
+
...base,
|
|
293
|
+
response: {
|
|
294
|
+
clientDataJSON: bufferToBase64Url(assertion.clientDataJSON),
|
|
295
|
+
authenticatorData: bufferToBase64Url(assertion.authenticatorData),
|
|
296
|
+
signature: bufferToBase64Url(assertion.signature),
|
|
297
|
+
userHandle: bufferToBase64Url(assertion.userHandle)
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
};
|
|
301
|
+
var postJSON = async (url, body) => {
|
|
302
|
+
const response = await fetch(url, {
|
|
303
|
+
method: "POST",
|
|
304
|
+
credentials: "include",
|
|
305
|
+
headers: {
|
|
306
|
+
"Content-Type": "application/json"
|
|
307
|
+
},
|
|
308
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
309
|
+
});
|
|
310
|
+
if (!response.ok) {
|
|
311
|
+
throw new Error(`Passkey request failed (${response.status})`);
|
|
312
|
+
}
|
|
313
|
+
return await response.json();
|
|
314
|
+
};
|
|
315
|
+
var isDcsPasskeySupported = () => getPublicKeyCredentialConstructor() !== void 0 && typeof navigator !== "undefined" && typeof navigator.credentials?.get === "function" && typeof navigator.credentials?.create === "function";
|
|
316
|
+
var isDcsPasskeyImmediateUIAvailable = async () => {
|
|
317
|
+
const publicKeyCredential = getPublicKeyCredentialConstructor();
|
|
318
|
+
if (!isDcsPasskeySupported() || typeof publicKeyCredential?.getClientCapabilities !== "function") {
|
|
319
|
+
return false;
|
|
320
|
+
}
|
|
321
|
+
try {
|
|
322
|
+
const capabilities = await publicKeyCredential.getClientCapabilities();
|
|
323
|
+
return capabilities.immediateGet === true;
|
|
324
|
+
} catch {
|
|
325
|
+
return false;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
var registerDcsSitePasskey = async (options) => {
|
|
329
|
+
if (!isDcsPasskeySupported()) {
|
|
330
|
+
throw new Error("Passkeys are not available in this browser.");
|
|
331
|
+
}
|
|
332
|
+
const base = apiBase(options?.apiBaseUrl);
|
|
333
|
+
const ceremony = await postJSON(`${base}/site-auth/passkeys/register/options`);
|
|
334
|
+
const credential = await navigator.credentials.create({
|
|
335
|
+
publicKey: decodeCreationOptions(ceremony.publicKey)
|
|
336
|
+
});
|
|
337
|
+
if (!(credential instanceof PublicKeyCredential)) {
|
|
338
|
+
throw new Error("Passkey registration was cancelled.");
|
|
339
|
+
}
|
|
340
|
+
const result = await postJSON(
|
|
341
|
+
`${base}/site-auth/passkeys/register/verify`,
|
|
342
|
+
{
|
|
343
|
+
state: ceremony.state,
|
|
344
|
+
credential: serializeCredential(credential)
|
|
345
|
+
}
|
|
346
|
+
);
|
|
347
|
+
if (!result.success) {
|
|
348
|
+
throw new Error("Passkey registration failed.");
|
|
349
|
+
}
|
|
350
|
+
return result.credentialId ?? null;
|
|
351
|
+
};
|
|
352
|
+
var authenticateDcsSitePasskey = async (options) => {
|
|
353
|
+
if (!isDcsPasskeySupported()) {
|
|
354
|
+
throw new Error("Passkeys are not available in this browser.");
|
|
355
|
+
}
|
|
356
|
+
const base = apiBase(options?.apiBaseUrl);
|
|
357
|
+
const ceremony = await postJSON(`${base}/site-auth/passkeys/authenticate/options`);
|
|
358
|
+
const request = {
|
|
359
|
+
publicKey: decodeRequestOptions(ceremony.publicKey)
|
|
360
|
+
};
|
|
361
|
+
if (options?.immediate) {
|
|
362
|
+
request.uiMode = "immediate";
|
|
363
|
+
}
|
|
364
|
+
const credential = await navigator.credentials.get(request);
|
|
365
|
+
if (!(credential instanceof PublicKeyCredential)) {
|
|
366
|
+
throw new Error("Passkey sign-in was cancelled.");
|
|
367
|
+
}
|
|
368
|
+
return await postJSON(`${base}/site-auth/passkeys/authenticate/verify`, {
|
|
369
|
+
state: ceremony.state,
|
|
370
|
+
credential: serializeCredential(credential),
|
|
371
|
+
returnTo: options?.returnTo ?? "/"
|
|
372
|
+
});
|
|
373
|
+
};
|
|
374
|
+
|
|
375
|
+
export { authenticateDcsSitePasskey, buildMetaTags, fetchRuntimeContent, fetchRuntimeSeo, getGlobalContent, getPageContent, isDcsPasskeyImmediateUIAvailable, isDcsPasskeySupported, registerDcsSitePasskey, resolveSeoForPage, resolveTextKey };
|
|
213
376
|
//# sourceMappingURL=browser.js.map
|
|
214
377
|
//# sourceMappingURL=browser.js.map
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/content.ts","../src/seo.ts","../src/fetch.ts"],"names":[],"mappings":"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","file":"browser.js","sourcesContent":["/**\n * Content resolution utilities\n */\n\nimport type { ContentConfiguration } from './types'\n\n/**\n * Resolve a text key for a specific page.\n * Checks page-specific content first, then falls back to global content.\n *\n * @param content - The content configuration\n * @param page - The page slug\n * @param key - The text key to resolve\n * @returns The resolved text value, or undefined if not found\n */\nexport function resolveTextKey(\n content: ContentConfiguration,\n page: string,\n key: string\n): string | undefined {\n // Check page-specific content first\n const pageContent = content.pages?.[page]\n if (pageContent && key in pageContent) {\n return pageContent[key]\n }\n\n // Fall back to global content\n if (content.global && key in content.global) {\n return content.global[key]\n }\n\n return undefined\n}\n\n/**\n * Get all content for a specific page, merging global and page-specific.\n *\n * @param content - The content configuration\n * @param page - The page slug\n * @returns Merged content object (global values overridden by page values)\n */\nexport function getPageContent(\n content: ContentConfiguration,\n page: string\n): Record<string, string> {\n const global = content.global ?? {}\n const pageContent = content.pages?.[page] ?? {}\n return { ...global, ...pageContent }\n}\n\n/**\n * Get only the global content.\n *\n * @param content - The content configuration\n * @returns Global content object\n */\nexport function getGlobalContent(\n content: ContentConfiguration\n): Record<string, string> {\n return content.global ?? {}\n}\n","/**\n * SEO resolution utilities\n */\n\nimport type {\n SeoConfiguration,\n ResolvedSeo,\n SeoOpenGraphConfig,\n SeoTwitterConfig,\n} from './types'\n\n/**\n * Resolve SEO configuration for a specific page.\n * Merges global defaults with page-specific overrides.\n *\n * @param seo - The SEO configuration\n * @param page - The page slug\n * @returns Resolved SEO object with all values filled in\n */\nexport function resolveSeoForPage(\n seo: SeoConfiguration,\n page: string\n): ResolvedSeo {\n const global = seo.global ?? {}\n const pageSeo = seo.pages?.[page] ?? {}\n\n // Resolve title with template\n let title = pageSeo.title ?? global.defaultTitle ?? ''\n if (title && global.titleTemplate && !pageSeo.noTitleTemplate) {\n title = global.titleTemplate.replace('%s', title)\n }\n\n const description = pageSeo.description ?? global.defaultDescription ?? ''\n\n // Resolve Open Graph\n const ogImage =\n pageSeo.openGraph?.image ?? global.images?.ogDefault ?? undefined\n const openGraph = resolveOpenGraph(pageSeo.openGraph, ogImage, title, description)\n\n // Resolve Twitter Card\n const twitterImage =\n pageSeo.twitter?.image ?? global.images?.twitterDefault ?? ogImage\n const twitter = resolveTwitterCard(\n pageSeo.twitter,\n twitterImage,\n title,\n description,\n global.social?.twitter\n )\n\n return {\n title,\n description,\n image: ogImage,\n siteName: global.siteName,\n siteUrl: global.siteUrl,\n locale: global.locale,\n canonical: pageSeo.canonical,\n robots: pageSeo.robots ?? global.robots,\n noIndex: pageSeo.robots?.includes('noindex'),\n openGraph,\n twitter,\n schemas: pageSeo.schemas ?? global.schemas,\n alternates: pageSeo.alternates,\n }\n}\n\n/**\n * Resolve Open Graph configuration\n */\nfunction resolveOpenGraph(\n pageOg: SeoOpenGraphConfig | undefined,\n ogImage: string | undefined,\n title: string,\n description: string\n): SeoOpenGraphConfig | undefined {\n if (pageOg) {\n return {\n ...pageOg,\n title: pageOg.title ?? title,\n description: pageOg.description ?? description,\n image: ogImage,\n }\n }\n\n if (ogImage) {\n return {\n title,\n description,\n image: ogImage,\n type: 'website',\n }\n }\n\n return undefined\n}\n\n/**\n * Resolve Twitter Card configuration\n */\nfunction resolveTwitterCard(\n pageTwitter: SeoTwitterConfig | undefined,\n twitterImage: string | undefined,\n title: string,\n description: string,\n globalTwitterHandle: string | undefined\n): SeoTwitterConfig | undefined {\n if (pageTwitter) {\n return {\n card: pageTwitter.card ?? 'summary_large_image',\n site: pageTwitter.site ?? globalTwitterHandle,\n ...pageTwitter,\n title: pageTwitter.title ?? title,\n description: pageTwitter.description ?? description,\n image: twitterImage,\n }\n }\n\n if (globalTwitterHandle || twitterImage) {\n return {\n card: 'summary_large_image',\n site: globalTwitterHandle,\n title,\n description,\n image: twitterImage,\n }\n }\n\n return undefined\n}\n\n/**\n * Meta tag representation for framework-agnostic usage\n */\nexport interface MetaTag {\n name?: string\n property?: string\n content: string\n}\n\n/**\n * Helper to add a meta tag if content exists\n */\nfunction addTag(\n tags: MetaTag[],\n content: string | undefined,\n attr: { name?: string; property?: string }\n): void {\n if (content) {\n tags.push({ ...attr, content })\n }\n}\n\n/**\n * Build Open Graph meta tags\n */\nfunction buildOpenGraphTags(\n tags: MetaTag[],\n seo: ResolvedSeo\n): void {\n const og = seo.openGraph\n if (!og) return\n\n addTag(tags, og.title, { property: 'og:title' })\n addTag(tags, og.description, { property: 'og:description' })\n addTag(tags, og.image, { property: 'og:image' })\n addTag(tags, og.imageAlt, { property: 'og:image:alt' })\n addTag(tags, og.imageWidth?.toString(), { property: 'og:image:width' })\n addTag(tags, og.imageHeight?.toString(), { property: 'og:image:height' })\n addTag(tags, og.type, { property: 'og:type' })\n addTag(tags, og.url, { property: 'og:url' })\n addTag(tags, seo.siteName, { property: 'og:site_name' })\n addTag(tags, seo.locale, { property: 'og:locale' })\n}\n\n/**\n * Build Twitter Card meta tags\n */\nfunction buildTwitterTags(\n tags: MetaTag[],\n seo: ResolvedSeo\n): void {\n const tw = seo.twitter\n if (!tw) return\n\n addTag(tags, tw.card, { name: 'twitter:card' })\n addTag(tags, tw.site ? `@${tw.site}` : undefined, { name: 'twitter:site' })\n addTag(tags, tw.creator ? `@${tw.creator}` : undefined, { name: 'twitter:creator' })\n addTag(tags, tw.title, { name: 'twitter:title' })\n addTag(tags, tw.description, { name: 'twitter:description' })\n addTag(tags, tw.image, { name: 'twitter:image' })\n addTag(tags, tw.imageAlt, { name: 'twitter:image:alt' })\n}\n\n/**\n * Build an array of meta tags from resolved SEO.\n * Useful for frameworks that need to manually set meta tags.\n *\n * @param seo - Resolved SEO object\n * @returns Array of meta tag objects\n */\nexport function buildMetaTags(seo: ResolvedSeo): MetaTag[] {\n const tags: MetaTag[] = []\n\n // Basic meta\n addTag(tags, seo.description, { name: 'description' })\n addTag(tags, seo.robots, { name: 'robots' })\n\n // Open Graph\n buildOpenGraphTags(tags, seo)\n\n // Twitter Card\n buildTwitterTags(tags, seo)\n\n return tags\n}\n","/**\n * Runtime content fetching for premium tier customers\n */\n\nimport type { ContentConfiguration, SeoConfiguration } from './types'\n\n/**\n * Options for runtime fetch operations\n */\nexport interface FetchOptions {\n /** Base URL for the DCS API */\n apiBaseUrl?: string\n /** Timeout in milliseconds (default: 5000) */\n timeout?: number\n /** Custom headers to include */\n headers?: Record<string, string>\n}\n\nconst DEFAULT_API_URL = 'https://api.duffcloudservices.com'\nconst DEFAULT_TIMEOUT = 5000\n\n/**\n * Fetch runtime content from the DCS API.\n * This is a premium tier feature - returns 403 for non-premium sites.\n *\n * @param siteSlug - The site's slug identifier\n * @param options - Fetch options\n * @returns Content configuration or null if fetch fails\n */\nexport async function fetchRuntimeContent(\n siteSlug: string,\n options: FetchOptions = {}\n): Promise<ContentConfiguration | null> {\n const { apiBaseUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/portal/sites/${siteSlug}/content/runtime`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n signal: controller.signal,\n }\n )\n\n if (!response.ok) {\n if (response.status === 403) {\n console.warn(\n '[DCS] Runtime content requires premium tier. Using build-time content.'\n )\n }\n return null\n }\n\n return (await response.json()) as ContentConfiguration\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[DCS] Runtime content fetch timed out')\n } else {\n console.warn('[DCS] Runtime content fetch failed:', error)\n }\n return null\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Fetch runtime SEO configuration from the DCS API.\n * This is a premium tier feature - returns 403 for non-premium sites.\n *\n * @param siteSlug - The site's slug identifier\n * @param options - Fetch options\n * @returns SEO configuration or null if fetch fails\n */\nexport async function fetchRuntimeSeo(\n siteSlug: string,\n options: FetchOptions = {}\n): Promise<SeoConfiguration | null> {\n const { apiBaseUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/portal/sites/${siteSlug}/seo/runtime`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n signal: controller.signal,\n }\n )\n\n if (!response.ok) {\n if (response.status === 403) {\n console.warn(\n '[DCS] Runtime SEO requires premium tier. Using build-time SEO.'\n )\n }\n return null\n }\n\n return (await response.json()) as SeoConfiguration\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[DCS] Runtime SEO fetch timed out')\n } else {\n console.warn('[DCS] Runtime SEO fetch failed:', error)\n }\n return null\n } finally {\n clearTimeout(timeoutId)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/content.ts","../src/seo.ts","../src/fetch.ts","../src/passkeys.ts"],"names":[],"mappings":"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","file":"browser.js","sourcesContent":["/**\n * Content resolution utilities\n */\n\nimport type { ContentConfiguration } from './types'\n\n/**\n * Resolve a text key for a specific page.\n * Checks page-specific content first, then falls back to global content.\n *\n * @param content - The content configuration\n * @param page - The page slug\n * @param key - The text key to resolve\n * @returns The resolved text value, or undefined if not found\n */\nexport function resolveTextKey(\n content: ContentConfiguration,\n page: string,\n key: string\n): string | undefined {\n // Check page-specific content first\n const pageContent = content.pages?.[page]\n if (pageContent && key in pageContent) {\n return pageContent[key]\n }\n\n // Fall back to global content\n if (content.global && key in content.global) {\n return content.global[key]\n }\n\n return undefined\n}\n\n/**\n * Get all content for a specific page, merging global and page-specific.\n *\n * @param content - The content configuration\n * @param page - The page slug\n * @returns Merged content object (global values overridden by page values)\n */\nexport function getPageContent(\n content: ContentConfiguration,\n page: string\n): Record<string, string> {\n const global = content.global ?? {}\n const pageContent = content.pages?.[page] ?? {}\n return { ...global, ...pageContent }\n}\n\n/**\n * Get only the global content.\n *\n * @param content - The content configuration\n * @returns Global content object\n */\nexport function getGlobalContent(\n content: ContentConfiguration\n): Record<string, string> {\n return content.global ?? {}\n}\n","/**\n * SEO resolution utilities\n */\n\nimport type {\n SeoConfiguration,\n ResolvedSeo,\n SeoOpenGraphConfig,\n SeoTwitterConfig,\n} from './types'\n\n/**\n * Resolve SEO configuration for a specific page.\n * Merges global defaults with page-specific overrides.\n *\n * @param seo - The SEO configuration\n * @param page - The page slug\n * @returns Resolved SEO object with all values filled in\n */\nexport function resolveSeoForPage(\n seo: SeoConfiguration,\n page: string\n): ResolvedSeo {\n const global = seo.global ?? {}\n const pageSeo = seo.pages?.[page] ?? {}\n\n // Resolve title with template\n let title = pageSeo.title ?? global.defaultTitle ?? ''\n if (title && global.titleTemplate && !pageSeo.noTitleTemplate) {\n title = global.titleTemplate.replace('%s', title)\n }\n\n const description = pageSeo.description ?? global.defaultDescription ?? ''\n\n // Resolve Open Graph\n const ogImage =\n pageSeo.openGraph?.image ?? global.images?.ogDefault ?? undefined\n const openGraph = resolveOpenGraph(pageSeo.openGraph, ogImage, title, description)\n\n // Resolve Twitter Card\n const twitterImage =\n pageSeo.twitter?.image ?? global.images?.twitterDefault ?? ogImage\n const twitter = resolveTwitterCard(\n pageSeo.twitter,\n twitterImage,\n title,\n description,\n global.social?.twitter\n )\n\n return {\n title,\n description,\n image: ogImage,\n siteName: global.siteName,\n siteUrl: global.siteUrl,\n locale: global.locale,\n canonical: pageSeo.canonical,\n robots: pageSeo.robots ?? global.robots,\n noIndex: pageSeo.robots?.includes('noindex'),\n openGraph,\n twitter,\n schemas: pageSeo.schemas ?? global.schemas,\n alternates: pageSeo.alternates,\n }\n}\n\n/**\n * Resolve Open Graph configuration\n */\nfunction resolveOpenGraph(\n pageOg: SeoOpenGraphConfig | undefined,\n ogImage: string | undefined,\n title: string,\n description: string\n): SeoOpenGraphConfig | undefined {\n if (pageOg) {\n return {\n ...pageOg,\n title: pageOg.title ?? title,\n description: pageOg.description ?? description,\n image: ogImage,\n }\n }\n\n if (ogImage) {\n return {\n title,\n description,\n image: ogImage,\n type: 'website',\n }\n }\n\n return undefined\n}\n\n/**\n * Resolve Twitter Card configuration\n */\nfunction resolveTwitterCard(\n pageTwitter: SeoTwitterConfig | undefined,\n twitterImage: string | undefined,\n title: string,\n description: string,\n globalTwitterHandle: string | undefined\n): SeoTwitterConfig | undefined {\n if (pageTwitter) {\n return {\n card: pageTwitter.card ?? 'summary_large_image',\n site: pageTwitter.site ?? globalTwitterHandle,\n ...pageTwitter,\n title: pageTwitter.title ?? title,\n description: pageTwitter.description ?? description,\n image: twitterImage,\n }\n }\n\n if (globalTwitterHandle || twitterImage) {\n return {\n card: 'summary_large_image',\n site: globalTwitterHandle,\n title,\n description,\n image: twitterImage,\n }\n }\n\n return undefined\n}\n\n/**\n * Meta tag representation for framework-agnostic usage\n */\nexport interface MetaTag {\n name?: string\n property?: string\n content: string\n}\n\n/**\n * Helper to add a meta tag if content exists\n */\nfunction addTag(\n tags: MetaTag[],\n content: string | undefined,\n attr: { name?: string; property?: string }\n): void {\n if (content) {\n tags.push({ ...attr, content })\n }\n}\n\n/**\n * Build Open Graph meta tags\n */\nfunction buildOpenGraphTags(\n tags: MetaTag[],\n seo: ResolvedSeo\n): void {\n const og = seo.openGraph\n if (!og) return\n\n addTag(tags, og.title, { property: 'og:title' })\n addTag(tags, og.description, { property: 'og:description' })\n addTag(tags, og.image, { property: 'og:image' })\n addTag(tags, og.imageAlt, { property: 'og:image:alt' })\n addTag(tags, og.imageWidth?.toString(), { property: 'og:image:width' })\n addTag(tags, og.imageHeight?.toString(), { property: 'og:image:height' })\n addTag(tags, og.type, { property: 'og:type' })\n addTag(tags, og.url, { property: 'og:url' })\n addTag(tags, seo.siteName, { property: 'og:site_name' })\n addTag(tags, seo.locale, { property: 'og:locale' })\n}\n\n/**\n * Build Twitter Card meta tags\n */\nfunction buildTwitterTags(\n tags: MetaTag[],\n seo: ResolvedSeo\n): void {\n const tw = seo.twitter\n if (!tw) return\n\n addTag(tags, tw.card, { name: 'twitter:card' })\n addTag(tags, tw.site ? `@${tw.site}` : undefined, { name: 'twitter:site' })\n addTag(tags, tw.creator ? `@${tw.creator}` : undefined, { name: 'twitter:creator' })\n addTag(tags, tw.title, { name: 'twitter:title' })\n addTag(tags, tw.description, { name: 'twitter:description' })\n addTag(tags, tw.image, { name: 'twitter:image' })\n addTag(tags, tw.imageAlt, { name: 'twitter:image:alt' })\n}\n\n/**\n * Build an array of meta tags from resolved SEO.\n * Useful for frameworks that need to manually set meta tags.\n *\n * @param seo - Resolved SEO object\n * @returns Array of meta tag objects\n */\nexport function buildMetaTags(seo: ResolvedSeo): MetaTag[] {\n const tags: MetaTag[] = []\n\n // Basic meta\n addTag(tags, seo.description, { name: 'description' })\n addTag(tags, seo.robots, { name: 'robots' })\n\n // Open Graph\n buildOpenGraphTags(tags, seo)\n\n // Twitter Card\n buildTwitterTags(tags, seo)\n\n return tags\n}\n","/**\n * Runtime content fetching for premium tier customers\n */\n\nimport type { ContentConfiguration, SeoConfiguration } from './types'\n\n/**\n * Options for runtime fetch operations\n */\nexport interface FetchOptions {\n /** Base URL for the DCS API */\n apiBaseUrl?: string\n /** Timeout in milliseconds (default: 5000) */\n timeout?: number\n /** Custom headers to include */\n headers?: Record<string, string>\n}\n\nconst DEFAULT_API_URL = 'https://api.duffcloudservices.com'\nconst DEFAULT_TIMEOUT = 5000\n\n/**\n * Fetch runtime content from the DCS API.\n * This is a premium tier feature - returns 403 for non-premium sites.\n *\n * @param siteSlug - The site's slug identifier.\n * @deprecated The site is now resolved server-side from the request Host or the\n * dedicated Container App's `DCS_SITE_SLUG`. This argument is retained for source\n * compatibility but is ignored for routing (no longer placed in the URL path).\n * @param options - Fetch options\n * @returns Content configuration or null if fetch fails\n */\nexport async function fetchRuntimeContent(\n siteSlug: string,\n options: FetchOptions = {}\n): Promise<ContentConfiguration | null> {\n // `siteSlug` intentionally unused: the site is resolved server-side (Host / DCS_SITE_SLUG).\n void siteSlug\n const { apiBaseUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/api/v1/content/runtime`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n signal: controller.signal,\n }\n )\n\n if (!response.ok) {\n if (response.status === 403) {\n console.warn(\n '[DCS] Runtime content requires premium tier. Using build-time content.'\n )\n }\n return null\n }\n\n return (await response.json()) as ContentConfiguration\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[DCS] Runtime content fetch timed out')\n } else {\n console.warn('[DCS] Runtime content fetch failed:', error)\n }\n return null\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Fetch runtime SEO configuration from the DCS API.\n * This is a premium tier feature - returns 403 for non-premium sites.\n *\n * @param siteSlug - The site's slug identifier.\n * @deprecated The site is now resolved server-side from the request Host or the\n * dedicated Container App's `DCS_SITE_SLUG`. This argument is retained for source\n * compatibility but is ignored for routing (no longer placed in the URL path).\n * @param options - Fetch options\n * @returns SEO configuration or null if fetch fails\n */\nexport async function fetchRuntimeSeo(\n siteSlug: string,\n options: FetchOptions = {}\n): Promise<SeoConfiguration | null> {\n // `siteSlug` intentionally unused: the site is resolved server-side (Host / DCS_SITE_SLUG).\n void siteSlug\n const { apiBaseUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/api/v1/seo/runtime`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n signal: controller.signal,\n }\n )\n\n if (!response.ok) {\n if (response.status === 403) {\n console.warn(\n '[DCS] Runtime SEO requires premium tier. Using build-time SEO.'\n )\n }\n return null\n }\n\n return (await response.json()) as SeoConfiguration\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[DCS] Runtime SEO fetch timed out')\n } else {\n console.warn('[DCS] Runtime SEO fetch failed:', error)\n }\n return null\n } finally {\n clearTimeout(timeoutId)\n }\n}\n","export type DcsPasskeyOptions = {\n apiBaseUrl?: string\n returnTo?: string\n immediate?: boolean\n}\n\nexport type DcsPasskeyResult = {\n success: boolean\n redirectTo?: string\n visitor?: {\n email: string\n name: string\n picture?: string\n }\n}\n\ntype CeremonyOptions = {\n state: string\n publicKey: Record<string, unknown>\n}\n\ntype CredentialRequestWithImmediateUI = CredentialRequestOptions & {\n uiMode?: 'immediate'\n}\n\ntype ClientCapabilities = {\n immediateGet?: boolean\n}\n\ntype PublicKeyCredentialConstructorWithCapabilities = typeof PublicKeyCredential & {\n getClientCapabilities?: () => Promise<ClientCapabilities>\n}\n\nconst getPublicKeyCredentialConstructor = (): PublicKeyCredentialConstructorWithCapabilities | undefined => {\n if (typeof window === 'undefined' || typeof window.PublicKeyCredential === 'undefined') {\n return undefined\n }\n return window.PublicKeyCredential as PublicKeyCredentialConstructorWithCapabilities\n}\n\nconst apiBase = (value?: string) => (value ?? '/api/v1').replace(/\\/$/u, '')\n\nconst base64UrlToBuffer = (value: string): ArrayBuffer => {\n const base64 = value.replace(/-/g, '+').replace(/_/g, '/')\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=')\n const raw = window.atob(padded)\n const output = new Uint8Array(raw.length)\n for (let index = 0; index < raw.length; index += 1) {\n output[index] = raw.charCodeAt(index)\n }\n return output.buffer\n}\n\nconst bufferToBase64Url = (value: ArrayBuffer | null): string | null => {\n if (!value) {\n return null\n }\n const bytes = new Uint8Array(value)\n let binary = ''\n bytes.forEach(byte => {\n binary += String.fromCharCode(byte)\n })\n return window.btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '')\n}\n\nconst decodeDescriptors = (items: unknown): PublicKeyCredentialDescriptor[] | undefined => {\n if (!Array.isArray(items)) {\n return undefined\n }\n return items.map(item => {\n const descriptor = item as { id?: unknown; type?: PublicKeyCredentialType; transports?: AuthenticatorTransport[] }\n return {\n ...descriptor,\n id: typeof descriptor.id === 'string' ? base64UrlToBuffer(descriptor.id) : descriptor.id,\n type: descriptor.type ?? 'public-key',\n } as PublicKeyCredentialDescriptor\n })\n}\n\nconst decodeCreationOptions = (publicKey: Record<string, unknown>): PublicKeyCredentialCreationOptions => {\n const user = publicKey.user as { id?: unknown } | undefined\n return {\n ...publicKey,\n challenge: base64UrlToBuffer(String(publicKey.challenge)),\n user: {\n ...(user ?? {}),\n id: typeof user?.id === 'string' ? base64UrlToBuffer(user.id) : user?.id,\n } as PublicKeyCredentialUserEntity,\n excludeCredentials: decodeDescriptors(publicKey.excludeCredentials),\n } as PublicKeyCredentialCreationOptions\n}\n\nconst decodeRequestOptions = (publicKey: Record<string, unknown>): PublicKeyCredentialRequestOptions => ({\n ...publicKey,\n challenge: base64UrlToBuffer(String(publicKey.challenge)),\n allowCredentials: decodeDescriptors(publicKey.allowCredentials),\n}) as PublicKeyCredentialRequestOptions\n\nconst serializeCredential = (credential: PublicKeyCredential): Record<string, unknown> => {\n const response = credential.response\n const base = {\n id: credential.id,\n type: credential.type,\n rawId: bufferToBase64Url(credential.rawId),\n authenticatorAttachment: credential.authenticatorAttachment,\n clientExtensionResults: credential.getClientExtensionResults(),\n }\n\n if (response instanceof AuthenticatorAttestationResponse) {\n return {\n ...base,\n response: {\n clientDataJSON: bufferToBase64Url(response.clientDataJSON),\n attestationObject: bufferToBase64Url(response.attestationObject),\n transports: response.getTransports?.() ?? [],\n },\n }\n }\n\n const assertion = response as AuthenticatorAssertionResponse\n return {\n ...base,\n response: {\n clientDataJSON: bufferToBase64Url(assertion.clientDataJSON),\n authenticatorData: bufferToBase64Url(assertion.authenticatorData),\n signature: bufferToBase64Url(assertion.signature),\n userHandle: bufferToBase64Url(assertion.userHandle),\n },\n }\n}\n\nconst postJSON = async <T>(url: string, body?: unknown): Promise<T> => {\n const response = await fetch(url, {\n method: 'POST',\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n })\n if (!response.ok) {\n throw new Error(`Passkey request failed (${response.status})`)\n }\n return await response.json() as T\n}\n\nexport const isDcsPasskeySupported = (): boolean =>\n getPublicKeyCredentialConstructor() !== undefined &&\n typeof navigator !== 'undefined' &&\n typeof navigator.credentials?.get === 'function' &&\n typeof navigator.credentials?.create === 'function'\n\nexport const isDcsPasskeyImmediateUIAvailable = async (): Promise<boolean> => {\n const publicKeyCredential = getPublicKeyCredentialConstructor()\n if (!isDcsPasskeySupported() || typeof publicKeyCredential?.getClientCapabilities !== 'function') {\n return false\n }\n try {\n const capabilities = await publicKeyCredential.getClientCapabilities()\n return capabilities.immediateGet === true\n } catch {\n return false\n }\n}\n\nexport const registerDcsSitePasskey = async (options?: DcsPasskeyOptions): Promise<string | null> => {\n if (!isDcsPasskeySupported()) {\n throw new Error('Passkeys are not available in this browser.')\n }\n const base = apiBase(options?.apiBaseUrl)\n const ceremony = await postJSON<CeremonyOptions>(`${base}/site-auth/passkeys/register/options`)\n const credential = await navigator.credentials.create({\n publicKey: decodeCreationOptions(ceremony.publicKey),\n })\n if (!(credential instanceof PublicKeyCredential)) {\n throw new Error('Passkey registration was cancelled.')\n }\n const result = await postJSON<{ success: boolean; credentialId?: string }>(\n `${base}/site-auth/passkeys/register/verify`,\n {\n state: ceremony.state,\n credential: serializeCredential(credential),\n },\n )\n if (!result.success) {\n throw new Error('Passkey registration failed.')\n }\n return result.credentialId ?? null\n}\n\nexport const authenticateDcsSitePasskey = async (options?: DcsPasskeyOptions): Promise<DcsPasskeyResult> => {\n if (!isDcsPasskeySupported()) {\n throw new Error('Passkeys are not available in this browser.')\n }\n const base = apiBase(options?.apiBaseUrl)\n const ceremony = await postJSON<CeremonyOptions>(`${base}/site-auth/passkeys/authenticate/options`)\n const request: CredentialRequestWithImmediateUI = {\n publicKey: decodeRequestOptions(ceremony.publicKey),\n }\n if (options?.immediate) {\n request.uiMode = 'immediate'\n }\n const credential = await navigator.credentials.get(request)\n if (!(credential instanceof PublicKeyCredential)) {\n throw new Error('Passkey sign-in was cancelled.')\n }\n return await postJSON<DcsPasskeyResult>(`${base}/site-auth/passkeys/authenticate/verify`, {\n state: ceremony.state,\n credential: serializeCredential(credential),\n returnTo: options?.returnTo ?? '/',\n })\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as ContentConfiguration, S as SeoConfiguration, P as PagesConfiguration } from './browser-
|
|
2
|
-
export { a as ContentConfigurationV1, F as FetchOptions, G as GlobalSeoConfig, M as MetaTag, k as PageEntry, b as PageSeoConfig, R as ResolvedSeo, i as SeoAlternateConfig, c as SeoAuthorConfig, e as SeoImagesConfig, f as SeoOpenGraphConfig, h as SeoSchemaConfig, d as SeoSocialConfig, g as SeoTwitterConfig, j as SeoVerificationConfig, U as UnifiedConfiguration, l as UnifiedSiteConfig, p as buildMetaTags, q as fetchRuntimeContent, s as fetchRuntimeSeo, n as getGlobalContent, m as getPageContent, o as resolveSeoForPage, r as resolveTextKey } from './browser-
|
|
1
|
+
import { C as ContentConfiguration, S as SeoConfiguration, P as PagesConfiguration } from './browser-Ds57q3s6.js';
|
|
2
|
+
export { a as ContentConfigurationV1, D as DcsPasskeyOptions, x as DcsPasskeyResult, F as FetchOptions, G as GlobalSeoConfig, M as MetaTag, k as PageEntry, b as PageSeoConfig, R as ResolvedSeo, i as SeoAlternateConfig, c as SeoAuthorConfig, e as SeoImagesConfig, f as SeoOpenGraphConfig, h as SeoSchemaConfig, d as SeoSocialConfig, g as SeoTwitterConfig, j as SeoVerificationConfig, U as UnifiedConfiguration, l as UnifiedSiteConfig, t as authenticateDcsSitePasskey, p as buildMetaTags, q as fetchRuntimeContent, s as fetchRuntimeSeo, n as getGlobalContent, m as getPageContent, u as isDcsPasskeyImmediateUIAvailable, v as isDcsPasskeySupported, w as registerDcsSitePasskey, o as resolveSeoForPage, r as resolveTextKey } from './browser-Ds57q3s6.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* YAML file loaders for DCS configuration files
|
package/dist/index.js
CHANGED
|
@@ -246,7 +246,7 @@ async function fetchRuntimeContent(siteSlug, options = {}) {
|
|
|
246
246
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
247
247
|
try {
|
|
248
248
|
const response = await fetch(
|
|
249
|
-
`${apiBaseUrl}/
|
|
249
|
+
`${apiBaseUrl}/api/v1/content/runtime`,
|
|
250
250
|
{
|
|
251
251
|
method: "GET",
|
|
252
252
|
headers: {
|
|
@@ -282,7 +282,7 @@ async function fetchRuntimeSeo(siteSlug, options = {}) {
|
|
|
282
282
|
const timeoutId = setTimeout(() => controller.abort(), timeout);
|
|
283
283
|
try {
|
|
284
284
|
const response = await fetch(
|
|
285
|
-
`${apiBaseUrl}/
|
|
285
|
+
`${apiBaseUrl}/api/v1/seo/runtime`,
|
|
286
286
|
{
|
|
287
287
|
method: "GET",
|
|
288
288
|
headers: {
|
|
@@ -390,6 +390,169 @@ function isCdnAssetUrl(url) {
|
|
|
390
390
|
return CDN_PATTERN.test(url);
|
|
391
391
|
}
|
|
392
392
|
|
|
393
|
-
|
|
393
|
+
// src/passkeys.ts
|
|
394
|
+
var getPublicKeyCredentialConstructor = () => {
|
|
395
|
+
if (typeof window === "undefined" || typeof window.PublicKeyCredential === "undefined") {
|
|
396
|
+
return void 0;
|
|
397
|
+
}
|
|
398
|
+
return window.PublicKeyCredential;
|
|
399
|
+
};
|
|
400
|
+
var apiBase = (value) => (value ?? "/api/v1").replace(/\/$/u, "");
|
|
401
|
+
var base64UrlToBuffer = (value) => {
|
|
402
|
+
const base64 = value.replace(/-/g, "+").replace(/_/g, "/");
|
|
403
|
+
const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "=");
|
|
404
|
+
const raw = window.atob(padded);
|
|
405
|
+
const output = new Uint8Array(raw.length);
|
|
406
|
+
for (let index = 0; index < raw.length; index += 1) {
|
|
407
|
+
output[index] = raw.charCodeAt(index);
|
|
408
|
+
}
|
|
409
|
+
return output.buffer;
|
|
410
|
+
};
|
|
411
|
+
var bufferToBase64Url = (value) => {
|
|
412
|
+
if (!value) {
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
const bytes = new Uint8Array(value);
|
|
416
|
+
let binary = "";
|
|
417
|
+
bytes.forEach((byte) => {
|
|
418
|
+
binary += String.fromCharCode(byte);
|
|
419
|
+
});
|
|
420
|
+
return window.btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/u, "");
|
|
421
|
+
};
|
|
422
|
+
var decodeDescriptors = (items) => {
|
|
423
|
+
if (!Array.isArray(items)) {
|
|
424
|
+
return void 0;
|
|
425
|
+
}
|
|
426
|
+
return items.map((item) => {
|
|
427
|
+
const descriptor = item;
|
|
428
|
+
return {
|
|
429
|
+
...descriptor,
|
|
430
|
+
id: typeof descriptor.id === "string" ? base64UrlToBuffer(descriptor.id) : descriptor.id,
|
|
431
|
+
type: descriptor.type ?? "public-key"
|
|
432
|
+
};
|
|
433
|
+
});
|
|
434
|
+
};
|
|
435
|
+
var decodeCreationOptions = (publicKey) => {
|
|
436
|
+
const user = publicKey.user;
|
|
437
|
+
return {
|
|
438
|
+
...publicKey,
|
|
439
|
+
challenge: base64UrlToBuffer(String(publicKey.challenge)),
|
|
440
|
+
user: {
|
|
441
|
+
...user ?? {},
|
|
442
|
+
id: typeof user?.id === "string" ? base64UrlToBuffer(user.id) : user?.id
|
|
443
|
+
},
|
|
444
|
+
excludeCredentials: decodeDescriptors(publicKey.excludeCredentials)
|
|
445
|
+
};
|
|
446
|
+
};
|
|
447
|
+
var decodeRequestOptions = (publicKey) => ({
|
|
448
|
+
...publicKey,
|
|
449
|
+
challenge: base64UrlToBuffer(String(publicKey.challenge)),
|
|
450
|
+
allowCredentials: decodeDescriptors(publicKey.allowCredentials)
|
|
451
|
+
});
|
|
452
|
+
var serializeCredential = (credential) => {
|
|
453
|
+
const response = credential.response;
|
|
454
|
+
const base = {
|
|
455
|
+
id: credential.id,
|
|
456
|
+
type: credential.type,
|
|
457
|
+
rawId: bufferToBase64Url(credential.rawId),
|
|
458
|
+
authenticatorAttachment: credential.authenticatorAttachment,
|
|
459
|
+
clientExtensionResults: credential.getClientExtensionResults()
|
|
460
|
+
};
|
|
461
|
+
if (response instanceof AuthenticatorAttestationResponse) {
|
|
462
|
+
return {
|
|
463
|
+
...base,
|
|
464
|
+
response: {
|
|
465
|
+
clientDataJSON: bufferToBase64Url(response.clientDataJSON),
|
|
466
|
+
attestationObject: bufferToBase64Url(response.attestationObject),
|
|
467
|
+
transports: response.getTransports?.() ?? []
|
|
468
|
+
}
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
const assertion = response;
|
|
472
|
+
return {
|
|
473
|
+
...base,
|
|
474
|
+
response: {
|
|
475
|
+
clientDataJSON: bufferToBase64Url(assertion.clientDataJSON),
|
|
476
|
+
authenticatorData: bufferToBase64Url(assertion.authenticatorData),
|
|
477
|
+
signature: bufferToBase64Url(assertion.signature),
|
|
478
|
+
userHandle: bufferToBase64Url(assertion.userHandle)
|
|
479
|
+
}
|
|
480
|
+
};
|
|
481
|
+
};
|
|
482
|
+
var postJSON = async (url, body) => {
|
|
483
|
+
const response = await fetch(url, {
|
|
484
|
+
method: "POST",
|
|
485
|
+
credentials: "include",
|
|
486
|
+
headers: {
|
|
487
|
+
"Content-Type": "application/json"
|
|
488
|
+
},
|
|
489
|
+
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
490
|
+
});
|
|
491
|
+
if (!response.ok) {
|
|
492
|
+
throw new Error(`Passkey request failed (${response.status})`);
|
|
493
|
+
}
|
|
494
|
+
return await response.json();
|
|
495
|
+
};
|
|
496
|
+
var isDcsPasskeySupported = () => getPublicKeyCredentialConstructor() !== void 0 && typeof navigator !== "undefined" && typeof navigator.credentials?.get === "function" && typeof navigator.credentials?.create === "function";
|
|
497
|
+
var isDcsPasskeyImmediateUIAvailable = async () => {
|
|
498
|
+
const publicKeyCredential = getPublicKeyCredentialConstructor();
|
|
499
|
+
if (!isDcsPasskeySupported() || typeof publicKeyCredential?.getClientCapabilities !== "function") {
|
|
500
|
+
return false;
|
|
501
|
+
}
|
|
502
|
+
try {
|
|
503
|
+
const capabilities = await publicKeyCredential.getClientCapabilities();
|
|
504
|
+
return capabilities.immediateGet === true;
|
|
505
|
+
} catch {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
};
|
|
509
|
+
var registerDcsSitePasskey = async (options) => {
|
|
510
|
+
if (!isDcsPasskeySupported()) {
|
|
511
|
+
throw new Error("Passkeys are not available in this browser.");
|
|
512
|
+
}
|
|
513
|
+
const base = apiBase(options?.apiBaseUrl);
|
|
514
|
+
const ceremony = await postJSON(`${base}/site-auth/passkeys/register/options`);
|
|
515
|
+
const credential = await navigator.credentials.create({
|
|
516
|
+
publicKey: decodeCreationOptions(ceremony.publicKey)
|
|
517
|
+
});
|
|
518
|
+
if (!(credential instanceof PublicKeyCredential)) {
|
|
519
|
+
throw new Error("Passkey registration was cancelled.");
|
|
520
|
+
}
|
|
521
|
+
const result = await postJSON(
|
|
522
|
+
`${base}/site-auth/passkeys/register/verify`,
|
|
523
|
+
{
|
|
524
|
+
state: ceremony.state,
|
|
525
|
+
credential: serializeCredential(credential)
|
|
526
|
+
}
|
|
527
|
+
);
|
|
528
|
+
if (!result.success) {
|
|
529
|
+
throw new Error("Passkey registration failed.");
|
|
530
|
+
}
|
|
531
|
+
return result.credentialId ?? null;
|
|
532
|
+
};
|
|
533
|
+
var authenticateDcsSitePasskey = async (options) => {
|
|
534
|
+
if (!isDcsPasskeySupported()) {
|
|
535
|
+
throw new Error("Passkeys are not available in this browser.");
|
|
536
|
+
}
|
|
537
|
+
const base = apiBase(options?.apiBaseUrl);
|
|
538
|
+
const ceremony = await postJSON(`${base}/site-auth/passkeys/authenticate/options`);
|
|
539
|
+
const request = {
|
|
540
|
+
publicKey: decodeRequestOptions(ceremony.publicKey)
|
|
541
|
+
};
|
|
542
|
+
if (options?.immediate) {
|
|
543
|
+
request.uiMode = "immediate";
|
|
544
|
+
}
|
|
545
|
+
const credential = await navigator.credentials.get(request);
|
|
546
|
+
if (!(credential instanceof PublicKeyCredential)) {
|
|
547
|
+
throw new Error("Passkey sign-in was cancelled.");
|
|
548
|
+
}
|
|
549
|
+
return await postJSON(`${base}/site-auth/passkeys/authenticate/verify`, {
|
|
550
|
+
state: ceremony.state,
|
|
551
|
+
credential: serializeCredential(credential),
|
|
552
|
+
returnTo: options?.returnTo ?? "/"
|
|
553
|
+
});
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
export { authenticateDcsSitePasskey, buildMetaTags, fetchRuntimeContent, fetchRuntimeSeo, getGlobalContent, getPageContent, isCdnAssetUrl, isDcsPasskeyImmediateUIAvailable, isDcsPasskeySupported, loadConfigYaml, loadContentYaml, loadPagesYaml, loadSeoYaml, registerDcsSitePasskey, resolveResponsiveImage, resolveSeoForPage, resolveTextKey };
|
|
394
557
|
//# sourceMappingURL=index.js.map
|
|
395
558
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/content.ts","../src/seo.ts","../src/loaders.ts","../src/fetch.ts","../src/responsive-image.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Content resolution utilities\n */\n\nimport type { ContentConfiguration } from './types'\n\n/**\n * Resolve a text key for a specific page.\n * Checks page-specific content first, then falls back to global content.\n *\n * @param content - The content configuration\n * @param page - The page slug\n * @param key - The text key to resolve\n * @returns The resolved text value, or undefined if not found\n */\nexport function resolveTextKey(\n content: ContentConfiguration,\n page: string,\n key: string\n): string | undefined {\n // Check page-specific content first\n const pageContent = content.pages?.[page]\n if (pageContent && key in pageContent) {\n return pageContent[key]\n }\n\n // Fall back to global content\n if (content.global && key in content.global) {\n return content.global[key]\n }\n\n return undefined\n}\n\n/**\n * Get all content for a specific page, merging global and page-specific.\n *\n * @param content - The content configuration\n * @param page - The page slug\n * @returns Merged content object (global values overridden by page values)\n */\nexport function getPageContent(\n content: ContentConfiguration,\n page: string\n): Record<string, string> {\n const global = content.global ?? {}\n const pageContent = content.pages?.[page] ?? {}\n return { ...global, ...pageContent }\n}\n\n/**\n * Get only the global content.\n *\n * @param content - The content configuration\n * @returns Global content object\n */\nexport function getGlobalContent(\n content: ContentConfiguration\n): Record<string, string> {\n return content.global ?? {}\n}\n","/**\n * SEO resolution utilities\n */\n\nimport type {\n SeoConfiguration,\n ResolvedSeo,\n SeoOpenGraphConfig,\n SeoTwitterConfig,\n} from './types'\n\n/**\n * Resolve SEO configuration for a specific page.\n * Merges global defaults with page-specific overrides.\n *\n * @param seo - The SEO configuration\n * @param page - The page slug\n * @returns Resolved SEO object with all values filled in\n */\nexport function resolveSeoForPage(\n seo: SeoConfiguration,\n page: string\n): ResolvedSeo {\n const global = seo.global ?? {}\n const pageSeo = seo.pages?.[page] ?? {}\n\n // Resolve title with template\n let title = pageSeo.title ?? global.defaultTitle ?? ''\n if (title && global.titleTemplate && !pageSeo.noTitleTemplate) {\n title = global.titleTemplate.replace('%s', title)\n }\n\n const description = pageSeo.description ?? global.defaultDescription ?? ''\n\n // Resolve Open Graph\n const ogImage =\n pageSeo.openGraph?.image ?? global.images?.ogDefault ?? undefined\n const openGraph = resolveOpenGraph(pageSeo.openGraph, ogImage, title, description)\n\n // Resolve Twitter Card\n const twitterImage =\n pageSeo.twitter?.image ?? global.images?.twitterDefault ?? ogImage\n const twitter = resolveTwitterCard(\n pageSeo.twitter,\n twitterImage,\n title,\n description,\n global.social?.twitter\n )\n\n return {\n title,\n description,\n image: ogImage,\n siteName: global.siteName,\n siteUrl: global.siteUrl,\n locale: global.locale,\n canonical: pageSeo.canonical,\n robots: pageSeo.robots ?? global.robots,\n noIndex: pageSeo.robots?.includes('noindex'),\n openGraph,\n twitter,\n schemas: pageSeo.schemas ?? global.schemas,\n alternates: pageSeo.alternates,\n }\n}\n\n/**\n * Resolve Open Graph configuration\n */\nfunction resolveOpenGraph(\n pageOg: SeoOpenGraphConfig | undefined,\n ogImage: string | undefined,\n title: string,\n description: string\n): SeoOpenGraphConfig | undefined {\n if (pageOg) {\n return {\n ...pageOg,\n title: pageOg.title ?? title,\n description: pageOg.description ?? description,\n image: ogImage,\n }\n }\n\n if (ogImage) {\n return {\n title,\n description,\n image: ogImage,\n type: 'website',\n }\n }\n\n return undefined\n}\n\n/**\n * Resolve Twitter Card configuration\n */\nfunction resolveTwitterCard(\n pageTwitter: SeoTwitterConfig | undefined,\n twitterImage: string | undefined,\n title: string,\n description: string,\n globalTwitterHandle: string | undefined\n): SeoTwitterConfig | undefined {\n if (pageTwitter) {\n return {\n card: pageTwitter.card ?? 'summary_large_image',\n site: pageTwitter.site ?? globalTwitterHandle,\n ...pageTwitter,\n title: pageTwitter.title ?? title,\n description: pageTwitter.description ?? description,\n image: twitterImage,\n }\n }\n\n if (globalTwitterHandle || twitterImage) {\n return {\n card: 'summary_large_image',\n site: globalTwitterHandle,\n title,\n description,\n image: twitterImage,\n }\n }\n\n return undefined\n}\n\n/**\n * Meta tag representation for framework-agnostic usage\n */\nexport interface MetaTag {\n name?: string\n property?: string\n content: string\n}\n\n/**\n * Helper to add a meta tag if content exists\n */\nfunction addTag(\n tags: MetaTag[],\n content: string | undefined,\n attr: { name?: string; property?: string }\n): void {\n if (content) {\n tags.push({ ...attr, content })\n }\n}\n\n/**\n * Build Open Graph meta tags\n */\nfunction buildOpenGraphTags(\n tags: MetaTag[],\n seo: ResolvedSeo\n): void {\n const og = seo.openGraph\n if (!og) return\n\n addTag(tags, og.title, { property: 'og:title' })\n addTag(tags, og.description, { property: 'og:description' })\n addTag(tags, og.image, { property: 'og:image' })\n addTag(tags, og.imageAlt, { property: 'og:image:alt' })\n addTag(tags, og.imageWidth?.toString(), { property: 'og:image:width' })\n addTag(tags, og.imageHeight?.toString(), { property: 'og:image:height' })\n addTag(tags, og.type, { property: 'og:type' })\n addTag(tags, og.url, { property: 'og:url' })\n addTag(tags, seo.siteName, { property: 'og:site_name' })\n addTag(tags, seo.locale, { property: 'og:locale' })\n}\n\n/**\n * Build Twitter Card meta tags\n */\nfunction buildTwitterTags(\n tags: MetaTag[],\n seo: ResolvedSeo\n): void {\n const tw = seo.twitter\n if (!tw) return\n\n addTag(tags, tw.card, { name: 'twitter:card' })\n addTag(tags, tw.site ? `@${tw.site}` : undefined, { name: 'twitter:site' })\n addTag(tags, tw.creator ? `@${tw.creator}` : undefined, { name: 'twitter:creator' })\n addTag(tags, tw.title, { name: 'twitter:title' })\n addTag(tags, tw.description, { name: 'twitter:description' })\n addTag(tags, tw.image, { name: 'twitter:image' })\n addTag(tags, tw.imageAlt, { name: 'twitter:image:alt' })\n}\n\n/**\n * Build an array of meta tags from resolved SEO.\n * Useful for frameworks that need to manually set meta tags.\n *\n * @param seo - Resolved SEO object\n * @returns Array of meta tag objects\n */\nexport function buildMetaTags(seo: ResolvedSeo): MetaTag[] {\n const tags: MetaTag[] = []\n\n // Basic meta\n addTag(tags, seo.description, { name: 'description' })\n addTag(tags, seo.robots, { name: 'robots' })\n\n // Open Graph\n buildOpenGraphTags(tags, seo)\n\n // Twitter Card\n buildTwitterTags(tags, seo)\n\n return tags\n}\n","/**\n * YAML file loaders for DCS configuration files\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport yaml from 'js-yaml'\nimport type {\n ContentConfiguration,\n SeoConfiguration,\n PagesConfiguration,\n UnifiedConfiguration,\n} from './types'\n\n/**\n * Load and parse .dcs/content.yaml\n *\n * @param filePath - Path to content.yaml (absolute or relative to cwd)\n * @returns Parsed content configuration\n * @throws Error if file not found or parse fails\n */\nexport async function loadContentYaml(\n filePath: string\n): Promise<ContentConfiguration> {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath)\n\n const fileContent = fs.readFileSync(absolutePath, 'utf8')\n const content = yaml.load(fileContent) as ContentConfiguration\n\n // Ensure required fields exist\n if (!content.version) {\n content.version = 1\n }\n if (!content.global) {\n content.global = {}\n }\n if (!content.pages) {\n content.pages = {}\n }\n\n return content\n}\n\n/**\n * Load and parse .dcs/seo.yaml\n *\n * @param filePath - Path to seo.yaml (absolute or relative to cwd)\n * @returns Parsed SEO configuration\n * @throws Error if file not found or parse fails\n */\nexport async function loadSeoYaml(filePath: string): Promise<SeoConfiguration> {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath)\n\n const fileContent = fs.readFileSync(absolutePath, 'utf8')\n const seo = yaml.load(fileContent) as SeoConfiguration\n\n // Ensure required fields exist\n if (!seo.version) {\n seo.version = 1\n }\n\n return seo\n}\n\n/**\n * Load and parse .dcs/pages.yaml\n *\n * @param filePath - Path to pages.yaml (absolute or relative to cwd)\n * @returns Parsed pages configuration\n * @throws Error if file not found or parse fails\n */\nexport async function loadPagesYaml(\n filePath: string\n): Promise<PagesConfiguration> {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath)\n\n const fileContent = fs.readFileSync(absolutePath, 'utf8')\n const pages = yaml.load(fileContent) as PagesConfiguration\n\n // Ensure required fields exist\n if (!pages.version) {\n pages.version = 3\n }\n if (!pages.pages) {\n pages.pages = []\n }\n\n return pages\n}\n\n/**\n * Try to find a DCS config file in common locations\n *\n * @param filename - The config file name (e.g., 'content.yaml')\n * @param projectRoot - The project root directory\n * @returns The found path, or undefined if not found\n */\nexport function findDcsConfigFile(\n filename: string,\n projectRoot: string\n): string | undefined {\n const possiblePaths = [\n path.resolve(projectRoot, '.dcs', filename),\n path.resolve(projectRoot, '..', '.dcs', filename), // For VitePress docs folder\n path.resolve(process.cwd(), '.dcs', filename),\n ]\n\n for (const testPath of possiblePaths) {\n if (fs.existsSync(testPath)) {\n return testPath\n }\n }\n\n return undefined\n}\n\n// ─── Unified Config Loader ──────────────────────────────────────\n\n/**\n * Result of loading DCS configuration, whether from unified config.yaml\n * or individual split files.\n */\nexport interface DcsConfigResult {\n /** Resolved content configuration */\n content: ContentConfiguration\n /** Resolved SEO configuration */\n seo: SeoConfiguration\n /** Resolved pages configuration */\n pages: PagesConfiguration\n /** Whether the configuration was loaded from a unified config.yaml */\n isUnified: boolean\n /** The source file path(s) that were loaded */\n sources: string[]\n}\n\n/**\n * Load DCS configuration from either a unified `.dcs/config.yaml` (version 2)\n * or fall back to individual split files (content.yaml, seo.yaml, pages.yaml).\n *\n * The unified format is preferred when `.dcs/config.yaml` exists and has `version: 2`.\n * This provides a single source of truth for all site configuration.\n *\n * @param projectRoot - The project root directory containing `.dcs/`\n * @returns Resolved configuration from all sources\n *\n * @example\n * ```typescript\n * const config = await loadConfigYaml('/path/to/site')\n * console.log(config.content.pages.home)\n * console.log(config.seo.global?.siteName)\n * console.log(config.pages.pages)\n * console.log(config.isUnified) // true if loaded from config.yaml\n * ```\n */\nexport async function loadConfigYaml(projectRoot: string): Promise<DcsConfigResult> {\n // Try unified config.yaml first\n const unifiedPath = findDcsConfigFile('config.yaml', projectRoot)\n if (unifiedPath) {\n try {\n const fileContent = fs.readFileSync(unifiedPath, 'utf8')\n const raw = yaml.load(fileContent) as Record<string, unknown>\n\n // Only treat as unified if version === 2\n if (raw && raw.version === 2) {\n const unified = raw as unknown as UnifiedConfiguration\n return {\n content: unified.content ?? { version: 1, global: {}, pages: {} },\n seo: unified.seo ?? { version: 1 },\n pages: {\n version: 3,\n siteSlug: unified.siteSlug ?? unified.site?.slug ?? '',\n pages: unified.pages ?? [],\n },\n isUnified: true,\n sources: [unifiedPath],\n }\n }\n } catch {\n // config.yaml exists but failed to parse — fall through to split files\n }\n }\n\n // Fall back to individual split files\n const sources: string[] = []\n\n let content: ContentConfiguration = { version: 1, global: {}, pages: {} }\n const contentPath = findDcsConfigFile('content.yaml', projectRoot)\n if (contentPath) {\n content = await loadContentYaml(contentPath)\n sources.push(contentPath)\n }\n\n let seo: SeoConfiguration = { version: 1 }\n const seoPath = findDcsConfigFile('seo.yaml', projectRoot)\n if (seoPath) {\n seo = await loadSeoYaml(seoPath)\n sources.push(seoPath)\n }\n\n let pages: PagesConfiguration = { version: 3, siteSlug: '', pages: [] }\n const pagesPath = findDcsConfigFile('pages.yaml', projectRoot)\n if (pagesPath) {\n pages = await loadPagesYaml(pagesPath)\n sources.push(pagesPath)\n }\n\n return {\n content,\n seo,\n pages,\n isUnified: false,\n sources,\n }\n}\n","/**\n * Runtime content fetching for premium tier customers\n */\n\nimport type { ContentConfiguration, SeoConfiguration } from './types'\n\n/**\n * Options for runtime fetch operations\n */\nexport interface FetchOptions {\n /** Base URL for the DCS API */\n apiBaseUrl?: string\n /** Timeout in milliseconds (default: 5000) */\n timeout?: number\n /** Custom headers to include */\n headers?: Record<string, string>\n}\n\nconst DEFAULT_API_URL = 'https://api.duffcloudservices.com'\nconst DEFAULT_TIMEOUT = 5000\n\n/**\n * Fetch runtime content from the DCS API.\n * This is a premium tier feature - returns 403 for non-premium sites.\n *\n * @param siteSlug - The site's slug identifier\n * @param options - Fetch options\n * @returns Content configuration or null if fetch fails\n */\nexport async function fetchRuntimeContent(\n siteSlug: string,\n options: FetchOptions = {}\n): Promise<ContentConfiguration | null> {\n const { apiBaseUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/portal/sites/${siteSlug}/content/runtime`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n signal: controller.signal,\n }\n )\n\n if (!response.ok) {\n if (response.status === 403) {\n console.warn(\n '[DCS] Runtime content requires premium tier. Using build-time content.'\n )\n }\n return null\n }\n\n return (await response.json()) as ContentConfiguration\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[DCS] Runtime content fetch timed out')\n } else {\n console.warn('[DCS] Runtime content fetch failed:', error)\n }\n return null\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Fetch runtime SEO configuration from the DCS API.\n * This is a premium tier feature - returns 403 for non-premium sites.\n *\n * @param siteSlug - The site's slug identifier\n * @param options - Fetch options\n * @returns SEO configuration or null if fetch fails\n */\nexport async function fetchRuntimeSeo(\n siteSlug: string,\n options: FetchOptions = {}\n): Promise<SeoConfiguration | null> {\n const { apiBaseUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/portal/sites/${siteSlug}/seo/runtime`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n signal: controller.signal,\n }\n )\n\n if (!response.ok) {\n if (response.status === 403) {\n console.warn(\n '[DCS] Runtime SEO requires premium tier. Using build-time SEO.'\n )\n }\n return null\n }\n\n return (await response.json()) as SeoConfiguration\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[DCS] Runtime SEO fetch timed out')\n } else {\n console.warn('[DCS] Runtime SEO fetch failed:', error)\n }\n return null\n } finally {\n clearTimeout(timeoutId)\n }\n}\n","/**\n * Pure functions for resolving responsive image variants from DCS CDN URLs.\n *\n * The DCS imaging pipeline generates WebP variants during upload:\n * - thumb (150px) — grid thumbnails\n * - sm (640px) — mobile displays\n * - md (1024px) — tablet / blog body\n * - lg (1920px) — desktop / hero sections\n * - og (1200×630) — social sharing (fixed aspect)\n *\n * This module provides framework-agnostic resolution logic that\n * framework packages (@duffcloudservices/cms, cms-react, etc.) wrap\n * in their respective APIs.\n *\n * @module responsive-image\n */\n\n/** Sizing context that controls which variants are included in the srcset. */\nexport type ImageContext = 'hero' | 'card' | 'thumbnail' | 'content' | 'og' | 'lightbox'\n\n/** Options for resolving a responsive image. */\nexport interface ResponsiveImageOptions {\n /** Source URL — original CDN URL or local path. */\n src: string\n /** Alt text for accessibility. */\n alt: string\n /** Sizing context — determines which variants to include. */\n context?: ImageContext\n /** Optional explicit width hints for the browser `sizes` attribute. */\n sizes?: string\n /** Skip variant resolution and return the original URL only. */\n original?: boolean\n}\n\n/** A single `<source>` entry for a `<picture>` element. */\nexport interface ResponsiveSource {\n srcset: string\n type: string\n sizes?: string\n}\n\n/** Resolved image properties for rendering. */\nexport interface ResponsiveImageResult {\n /** Props spreadable onto an `<img>` element. */\n imgProps: {\n src: string\n alt: string\n loading: 'lazy' | 'eager'\n decoding: 'async' | 'auto'\n }\n /** WebP `<source>` entries for a `<picture>` element. */\n sources: ResponsiveSource[]\n /** Whether responsive variants were detected. */\n hasVariants: boolean\n}\n\n/**\n * Regex that matches DCS CDN asset URLs and captures the base path, UUID, and extension.\n *\n * Supports both URL formats:\n * - `https://files.duffcloudservices.com/{slug}/assets/{uuid}.ext` (branding container)\n * - `https://files.duffcloudservices.com/content/{slug}/assets/{uuid}.ext` (content container)\n *\n * Group 1: base path including trailing slash (e.g. `https://files.duffcloudservices.com/content/kept/assets/`)\n * Group 2: UUID (e.g. `abc-123`)\n * Group 3: file extension (e.g. `jpg`)\n */\nconst CDN_PATTERN = /^(https?:\\/\\/files\\.[^/]+\\/(?:content\\/)?[^/]+\\/assets\\/(?:[^/]+\\/)*)([a-f0-9-]+)\\.(\\w+)$/\n\n/** Variant definitions mapping suffix → pixel width. */\nconst VARIANT_MAP: Record<string, { suffix: string; width: number }> = {\n thumb: { suffix: '-thumb', width: 150 },\n sm: { suffix: '-sm', width: 640 },\n md: { suffix: '-md', width: 1024 },\n lg: { suffix: '-lg', width: 1920 },\n}\n\n/** Which variants each context includes (smallest → largest). */\nconst CONTEXT_VARIANTS: Record<ImageContext, string[]> = {\n hero: ['sm', 'md', 'lg'],\n card: ['thumb', 'sm', 'md'],\n thumbnail: ['thumb', 'sm'],\n content: ['sm', 'md', 'lg'],\n og: [], // OG uses the dedicated -og variant, not srcset\n lightbox: ['md', 'lg'], // Full-screen lightbox — only large variants\n}\n\n/** Default `sizes` attribute per context. */\nconst DEFAULT_SIZES: Record<ImageContext, string> = {\n hero: '100vw',\n card: '(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw',\n thumbnail: '150px',\n content: '(max-width: 1024px) 100vw, 1024px',\n og: '',\n lightbox: '100vw',\n}\n\n/**\n * Resolves responsive image metadata from a DCS CDN URL.\n *\n * If the URL matches the CDN asset pattern, a srcset of WebP variants\n * is generated based on the sizing `context`. Non-CDN URLs are returned\n * as-is with no variants.\n *\n * @example\n * ```ts\n * const result = resolveResponsiveImage({\n * src: 'https://files.duffcloudservices.com/kept/assets/hero/abc-123.jpg',\n * alt: 'Hero image',\n * context: 'hero',\n * })\n * // result.hasVariants === true\n * // result.sources[0].srcset contains sm, md, lg WebP sizes\n * // result.imgProps.loading === 'eager' (hero context)\n * ```\n */\nexport function resolveResponsiveImage(options: ResponsiveImageOptions): ResponsiveImageResult {\n const { src, alt, context = 'content', sizes, original } = options\n\n const fallback: ResponsiveImageResult = {\n imgProps: {\n src,\n alt,\n loading: context === 'hero' ? 'eager' : 'lazy',\n decoding: context === 'hero' ? 'auto' : 'async',\n },\n sources: [],\n hasVariants: false,\n }\n\n if (original) {\n return fallback\n }\n\n const match = src.match(CDN_PATTERN)\n if (!match) {\n return fallback\n }\n\n const [, basePath, uuid] = match\n\n const variants = CONTEXT_VARIANTS[context] ?? CONTEXT_VARIANTS.content\n if (variants.length === 0) {\n return fallback\n }\n\n const srcsetParts = variants.map((key) => {\n const v = VARIANT_MAP[key]\n return `${basePath}${uuid}${v.suffix}.webp ${v.width}w`\n })\n\n const resolvedSizes = sizes ?? DEFAULT_SIZES[context] ?? DEFAULT_SIZES.content\n\n return {\n imgProps: {\n src: `${basePath}${uuid}${context === 'lightbox' ? '-lg' : '-md'}.webp`, // Lightbox uses lg fallback for max quality\n alt,\n loading: context === 'hero' ? 'eager' : 'lazy',\n decoding: context === 'hero' ? 'auto' : 'async',\n },\n sources: [\n {\n srcset: srcsetParts.join(', '),\n type: 'image/webp',\n ...(resolvedSizes ? { sizes: resolvedSizes } : {}),\n },\n ],\n hasVariants: true,\n }\n}\n\n/**\n * Tests whether a URL matches the DCS CDN asset pattern.\n *\n * Useful when rendering a mix of CDN-hosted and local images\n * to decide whether responsive treatment is applicable.\n */\nexport function isCdnAssetUrl(url: string): boolean {\n return CDN_PATTERN.test(url)\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/content.ts","../src/seo.ts","../src/loaders.ts","../src/fetch.ts","../src/responsive-image.ts","../src/passkeys.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Content resolution utilities\n */\n\nimport type { ContentConfiguration } from './types'\n\n/**\n * Resolve a text key for a specific page.\n * Checks page-specific content first, then falls back to global content.\n *\n * @param content - The content configuration\n * @param page - The page slug\n * @param key - The text key to resolve\n * @returns The resolved text value, or undefined if not found\n */\nexport function resolveTextKey(\n content: ContentConfiguration,\n page: string,\n key: string\n): string | undefined {\n // Check page-specific content first\n const pageContent = content.pages?.[page]\n if (pageContent && key in pageContent) {\n return pageContent[key]\n }\n\n // Fall back to global content\n if (content.global && key in content.global) {\n return content.global[key]\n }\n\n return undefined\n}\n\n/**\n * Get all content for a specific page, merging global and page-specific.\n *\n * @param content - The content configuration\n * @param page - The page slug\n * @returns Merged content object (global values overridden by page values)\n */\nexport function getPageContent(\n content: ContentConfiguration,\n page: string\n): Record<string, string> {\n const global = content.global ?? {}\n const pageContent = content.pages?.[page] ?? {}\n return { ...global, ...pageContent }\n}\n\n/**\n * Get only the global content.\n *\n * @param content - The content configuration\n * @returns Global content object\n */\nexport function getGlobalContent(\n content: ContentConfiguration\n): Record<string, string> {\n return content.global ?? {}\n}\n","/**\n * SEO resolution utilities\n */\n\nimport type {\n SeoConfiguration,\n ResolvedSeo,\n SeoOpenGraphConfig,\n SeoTwitterConfig,\n} from './types'\n\n/**\n * Resolve SEO configuration for a specific page.\n * Merges global defaults with page-specific overrides.\n *\n * @param seo - The SEO configuration\n * @param page - The page slug\n * @returns Resolved SEO object with all values filled in\n */\nexport function resolveSeoForPage(\n seo: SeoConfiguration,\n page: string\n): ResolvedSeo {\n const global = seo.global ?? {}\n const pageSeo = seo.pages?.[page] ?? {}\n\n // Resolve title with template\n let title = pageSeo.title ?? global.defaultTitle ?? ''\n if (title && global.titleTemplate && !pageSeo.noTitleTemplate) {\n title = global.titleTemplate.replace('%s', title)\n }\n\n const description = pageSeo.description ?? global.defaultDescription ?? ''\n\n // Resolve Open Graph\n const ogImage =\n pageSeo.openGraph?.image ?? global.images?.ogDefault ?? undefined\n const openGraph = resolveOpenGraph(pageSeo.openGraph, ogImage, title, description)\n\n // Resolve Twitter Card\n const twitterImage =\n pageSeo.twitter?.image ?? global.images?.twitterDefault ?? ogImage\n const twitter = resolveTwitterCard(\n pageSeo.twitter,\n twitterImage,\n title,\n description,\n global.social?.twitter\n )\n\n return {\n title,\n description,\n image: ogImage,\n siteName: global.siteName,\n siteUrl: global.siteUrl,\n locale: global.locale,\n canonical: pageSeo.canonical,\n robots: pageSeo.robots ?? global.robots,\n noIndex: pageSeo.robots?.includes('noindex'),\n openGraph,\n twitter,\n schemas: pageSeo.schemas ?? global.schemas,\n alternates: pageSeo.alternates,\n }\n}\n\n/**\n * Resolve Open Graph configuration\n */\nfunction resolveOpenGraph(\n pageOg: SeoOpenGraphConfig | undefined,\n ogImage: string | undefined,\n title: string,\n description: string\n): SeoOpenGraphConfig | undefined {\n if (pageOg) {\n return {\n ...pageOg,\n title: pageOg.title ?? title,\n description: pageOg.description ?? description,\n image: ogImage,\n }\n }\n\n if (ogImage) {\n return {\n title,\n description,\n image: ogImage,\n type: 'website',\n }\n }\n\n return undefined\n}\n\n/**\n * Resolve Twitter Card configuration\n */\nfunction resolveTwitterCard(\n pageTwitter: SeoTwitterConfig | undefined,\n twitterImage: string | undefined,\n title: string,\n description: string,\n globalTwitterHandle: string | undefined\n): SeoTwitterConfig | undefined {\n if (pageTwitter) {\n return {\n card: pageTwitter.card ?? 'summary_large_image',\n site: pageTwitter.site ?? globalTwitterHandle,\n ...pageTwitter,\n title: pageTwitter.title ?? title,\n description: pageTwitter.description ?? description,\n image: twitterImage,\n }\n }\n\n if (globalTwitterHandle || twitterImage) {\n return {\n card: 'summary_large_image',\n site: globalTwitterHandle,\n title,\n description,\n image: twitterImage,\n }\n }\n\n return undefined\n}\n\n/**\n * Meta tag representation for framework-agnostic usage\n */\nexport interface MetaTag {\n name?: string\n property?: string\n content: string\n}\n\n/**\n * Helper to add a meta tag if content exists\n */\nfunction addTag(\n tags: MetaTag[],\n content: string | undefined,\n attr: { name?: string; property?: string }\n): void {\n if (content) {\n tags.push({ ...attr, content })\n }\n}\n\n/**\n * Build Open Graph meta tags\n */\nfunction buildOpenGraphTags(\n tags: MetaTag[],\n seo: ResolvedSeo\n): void {\n const og = seo.openGraph\n if (!og) return\n\n addTag(tags, og.title, { property: 'og:title' })\n addTag(tags, og.description, { property: 'og:description' })\n addTag(tags, og.image, { property: 'og:image' })\n addTag(tags, og.imageAlt, { property: 'og:image:alt' })\n addTag(tags, og.imageWidth?.toString(), { property: 'og:image:width' })\n addTag(tags, og.imageHeight?.toString(), { property: 'og:image:height' })\n addTag(tags, og.type, { property: 'og:type' })\n addTag(tags, og.url, { property: 'og:url' })\n addTag(tags, seo.siteName, { property: 'og:site_name' })\n addTag(tags, seo.locale, { property: 'og:locale' })\n}\n\n/**\n * Build Twitter Card meta tags\n */\nfunction buildTwitterTags(\n tags: MetaTag[],\n seo: ResolvedSeo\n): void {\n const tw = seo.twitter\n if (!tw) return\n\n addTag(tags, tw.card, { name: 'twitter:card' })\n addTag(tags, tw.site ? `@${tw.site}` : undefined, { name: 'twitter:site' })\n addTag(tags, tw.creator ? `@${tw.creator}` : undefined, { name: 'twitter:creator' })\n addTag(tags, tw.title, { name: 'twitter:title' })\n addTag(tags, tw.description, { name: 'twitter:description' })\n addTag(tags, tw.image, { name: 'twitter:image' })\n addTag(tags, tw.imageAlt, { name: 'twitter:image:alt' })\n}\n\n/**\n * Build an array of meta tags from resolved SEO.\n * Useful for frameworks that need to manually set meta tags.\n *\n * @param seo - Resolved SEO object\n * @returns Array of meta tag objects\n */\nexport function buildMetaTags(seo: ResolvedSeo): MetaTag[] {\n const tags: MetaTag[] = []\n\n // Basic meta\n addTag(tags, seo.description, { name: 'description' })\n addTag(tags, seo.robots, { name: 'robots' })\n\n // Open Graph\n buildOpenGraphTags(tags, seo)\n\n // Twitter Card\n buildTwitterTags(tags, seo)\n\n return tags\n}\n","/**\n * YAML file loaders for DCS configuration files\n */\n\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport yaml from 'js-yaml'\nimport type {\n ContentConfiguration,\n SeoConfiguration,\n PagesConfiguration,\n UnifiedConfiguration,\n} from './types'\n\n/**\n * Load and parse .dcs/content.yaml\n *\n * @param filePath - Path to content.yaml (absolute or relative to cwd)\n * @returns Parsed content configuration\n * @throws Error if file not found or parse fails\n */\nexport async function loadContentYaml(\n filePath: string\n): Promise<ContentConfiguration> {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath)\n\n const fileContent = fs.readFileSync(absolutePath, 'utf8')\n const content = yaml.load(fileContent) as ContentConfiguration\n\n // Ensure required fields exist\n if (!content.version) {\n content.version = 1\n }\n if (!content.global) {\n content.global = {}\n }\n if (!content.pages) {\n content.pages = {}\n }\n\n return content\n}\n\n/**\n * Load and parse .dcs/seo.yaml\n *\n * @param filePath - Path to seo.yaml (absolute or relative to cwd)\n * @returns Parsed SEO configuration\n * @throws Error if file not found or parse fails\n */\nexport async function loadSeoYaml(filePath: string): Promise<SeoConfiguration> {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath)\n\n const fileContent = fs.readFileSync(absolutePath, 'utf8')\n const seo = yaml.load(fileContent) as SeoConfiguration\n\n // Ensure required fields exist\n if (!seo.version) {\n seo.version = 1\n }\n\n return seo\n}\n\n/**\n * Load and parse .dcs/pages.yaml\n *\n * @param filePath - Path to pages.yaml (absolute or relative to cwd)\n * @returns Parsed pages configuration\n * @throws Error if file not found or parse fails\n */\nexport async function loadPagesYaml(\n filePath: string\n): Promise<PagesConfiguration> {\n const absolutePath = path.isAbsolute(filePath)\n ? filePath\n : path.resolve(process.cwd(), filePath)\n\n const fileContent = fs.readFileSync(absolutePath, 'utf8')\n const pages = yaml.load(fileContent) as PagesConfiguration\n\n // Ensure required fields exist\n if (!pages.version) {\n pages.version = 3\n }\n if (!pages.pages) {\n pages.pages = []\n }\n\n return pages\n}\n\n/**\n * Try to find a DCS config file in common locations\n *\n * @param filename - The config file name (e.g., 'content.yaml')\n * @param projectRoot - The project root directory\n * @returns The found path, or undefined if not found\n */\nexport function findDcsConfigFile(\n filename: string,\n projectRoot: string\n): string | undefined {\n const possiblePaths = [\n path.resolve(projectRoot, '.dcs', filename),\n path.resolve(projectRoot, '..', '.dcs', filename), // For VitePress docs folder\n path.resolve(process.cwd(), '.dcs', filename),\n ]\n\n for (const testPath of possiblePaths) {\n if (fs.existsSync(testPath)) {\n return testPath\n }\n }\n\n return undefined\n}\n\n// ─── Unified Config Loader ──────────────────────────────────────\n\n/**\n * Result of loading DCS configuration, whether from unified config.yaml\n * or individual split files.\n */\nexport interface DcsConfigResult {\n /** Resolved content configuration */\n content: ContentConfiguration\n /** Resolved SEO configuration */\n seo: SeoConfiguration\n /** Resolved pages configuration */\n pages: PagesConfiguration\n /** Whether the configuration was loaded from a unified config.yaml */\n isUnified: boolean\n /** The source file path(s) that were loaded */\n sources: string[]\n}\n\n/**\n * Load DCS configuration from either a unified `.dcs/config.yaml` (version 2)\n * or fall back to individual split files (content.yaml, seo.yaml, pages.yaml).\n *\n * The unified format is preferred when `.dcs/config.yaml` exists and has `version: 2`.\n * This provides a single source of truth for all site configuration.\n *\n * @param projectRoot - The project root directory containing `.dcs/`\n * @returns Resolved configuration from all sources\n *\n * @example\n * ```typescript\n * const config = await loadConfigYaml('/path/to/site')\n * console.log(config.content.pages.home)\n * console.log(config.seo.global?.siteName)\n * console.log(config.pages.pages)\n * console.log(config.isUnified) // true if loaded from config.yaml\n * ```\n */\nexport async function loadConfigYaml(projectRoot: string): Promise<DcsConfigResult> {\n // Try unified config.yaml first\n const unifiedPath = findDcsConfigFile('config.yaml', projectRoot)\n if (unifiedPath) {\n try {\n const fileContent = fs.readFileSync(unifiedPath, 'utf8')\n const raw = yaml.load(fileContent) as Record<string, unknown>\n\n // Only treat as unified if version === 2\n if (raw && raw.version === 2) {\n const unified = raw as unknown as UnifiedConfiguration\n return {\n content: unified.content ?? { version: 1, global: {}, pages: {} },\n seo: unified.seo ?? { version: 1 },\n pages: {\n version: 3,\n siteSlug: unified.siteSlug ?? unified.site?.slug ?? '',\n pages: unified.pages ?? [],\n },\n isUnified: true,\n sources: [unifiedPath],\n }\n }\n } catch {\n // config.yaml exists but failed to parse — fall through to split files\n }\n }\n\n // Fall back to individual split files\n const sources: string[] = []\n\n let content: ContentConfiguration = { version: 1, global: {}, pages: {} }\n const contentPath = findDcsConfigFile('content.yaml', projectRoot)\n if (contentPath) {\n content = await loadContentYaml(contentPath)\n sources.push(contentPath)\n }\n\n let seo: SeoConfiguration = { version: 1 }\n const seoPath = findDcsConfigFile('seo.yaml', projectRoot)\n if (seoPath) {\n seo = await loadSeoYaml(seoPath)\n sources.push(seoPath)\n }\n\n let pages: PagesConfiguration = { version: 3, siteSlug: '', pages: [] }\n const pagesPath = findDcsConfigFile('pages.yaml', projectRoot)\n if (pagesPath) {\n pages = await loadPagesYaml(pagesPath)\n sources.push(pagesPath)\n }\n\n return {\n content,\n seo,\n pages,\n isUnified: false,\n sources,\n }\n}\n","/**\n * Runtime content fetching for premium tier customers\n */\n\nimport type { ContentConfiguration, SeoConfiguration } from './types'\n\n/**\n * Options for runtime fetch operations\n */\nexport interface FetchOptions {\n /** Base URL for the DCS API */\n apiBaseUrl?: string\n /** Timeout in milliseconds (default: 5000) */\n timeout?: number\n /** Custom headers to include */\n headers?: Record<string, string>\n}\n\nconst DEFAULT_API_URL = 'https://api.duffcloudservices.com'\nconst DEFAULT_TIMEOUT = 5000\n\n/**\n * Fetch runtime content from the DCS API.\n * This is a premium tier feature - returns 403 for non-premium sites.\n *\n * @param siteSlug - The site's slug identifier.\n * @deprecated The site is now resolved server-side from the request Host or the\n * dedicated Container App's `DCS_SITE_SLUG`. This argument is retained for source\n * compatibility but is ignored for routing (no longer placed in the URL path).\n * @param options - Fetch options\n * @returns Content configuration or null if fetch fails\n */\nexport async function fetchRuntimeContent(\n siteSlug: string,\n options: FetchOptions = {}\n): Promise<ContentConfiguration | null> {\n // `siteSlug` intentionally unused: the site is resolved server-side (Host / DCS_SITE_SLUG).\n void siteSlug\n const { apiBaseUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/api/v1/content/runtime`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n signal: controller.signal,\n }\n )\n\n if (!response.ok) {\n if (response.status === 403) {\n console.warn(\n '[DCS] Runtime content requires premium tier. Using build-time content.'\n )\n }\n return null\n }\n\n return (await response.json()) as ContentConfiguration\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[DCS] Runtime content fetch timed out')\n } else {\n console.warn('[DCS] Runtime content fetch failed:', error)\n }\n return null\n } finally {\n clearTimeout(timeoutId)\n }\n}\n\n/**\n * Fetch runtime SEO configuration from the DCS API.\n * This is a premium tier feature - returns 403 for non-premium sites.\n *\n * @param siteSlug - The site's slug identifier.\n * @deprecated The site is now resolved server-side from the request Host or the\n * dedicated Container App's `DCS_SITE_SLUG`. This argument is retained for source\n * compatibility but is ignored for routing (no longer placed in the URL path).\n * @param options - Fetch options\n * @returns SEO configuration or null if fetch fails\n */\nexport async function fetchRuntimeSeo(\n siteSlug: string,\n options: FetchOptions = {}\n): Promise<SeoConfiguration | null> {\n // `siteSlug` intentionally unused: the site is resolved server-side (Host / DCS_SITE_SLUG).\n void siteSlug\n const { apiBaseUrl = DEFAULT_API_URL, timeout = DEFAULT_TIMEOUT } = options\n\n const controller = new AbortController()\n const timeoutId = setTimeout(() => controller.abort(), timeout)\n\n try {\n const response = await fetch(\n `${apiBaseUrl}/api/v1/seo/runtime`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n signal: controller.signal,\n }\n )\n\n if (!response.ok) {\n if (response.status === 403) {\n console.warn(\n '[DCS] Runtime SEO requires premium tier. Using build-time SEO.'\n )\n }\n return null\n }\n\n return (await response.json()) as SeoConfiguration\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n console.warn('[DCS] Runtime SEO fetch timed out')\n } else {\n console.warn('[DCS] Runtime SEO fetch failed:', error)\n }\n return null\n } finally {\n clearTimeout(timeoutId)\n }\n}\n","/**\n * Pure functions for resolving responsive image variants from DCS CDN URLs.\n *\n * The DCS imaging pipeline generates WebP variants during upload:\n * - thumb (150px) — grid thumbnails\n * - sm (640px) — mobile displays\n * - md (1024px) — tablet / blog body\n * - lg (1920px) — desktop / hero sections\n * - og (1200×630) — social sharing (fixed aspect)\n *\n * This module provides framework-agnostic resolution logic that\n * framework packages (@duffcloudservices/cms, cms-react, etc.) wrap\n * in their respective APIs.\n *\n * @module responsive-image\n */\n\n/** Sizing context that controls which variants are included in the srcset. */\nexport type ImageContext = 'hero' | 'card' | 'thumbnail' | 'content' | 'og' | 'lightbox'\n\n/** Options for resolving a responsive image. */\nexport interface ResponsiveImageOptions {\n /** Source URL — original CDN URL or local path. */\n src: string\n /** Alt text for accessibility. */\n alt: string\n /** Sizing context — determines which variants to include. */\n context?: ImageContext\n /** Optional explicit width hints for the browser `sizes` attribute. */\n sizes?: string\n /** Skip variant resolution and return the original URL only. */\n original?: boolean\n}\n\n/** A single `<source>` entry for a `<picture>` element. */\nexport interface ResponsiveSource {\n srcset: string\n type: string\n sizes?: string\n}\n\n/** Resolved image properties for rendering. */\nexport interface ResponsiveImageResult {\n /** Props spreadable onto an `<img>` element. */\n imgProps: {\n src: string\n alt: string\n loading: 'lazy' | 'eager'\n decoding: 'async' | 'auto'\n }\n /** WebP `<source>` entries for a `<picture>` element. */\n sources: ResponsiveSource[]\n /** Whether responsive variants were detected. */\n hasVariants: boolean\n}\n\n/**\n * Regex that matches DCS CDN asset URLs and captures the base path, UUID, and extension.\n *\n * Supports both URL formats:\n * - `https://files.duffcloudservices.com/{slug}/assets/{uuid}.ext` (branding container)\n * - `https://files.duffcloudservices.com/content/{slug}/assets/{uuid}.ext` (content container)\n *\n * Group 1: base path including trailing slash (e.g. `https://files.duffcloudservices.com/content/kept/assets/`)\n * Group 2: UUID (e.g. `abc-123`)\n * Group 3: file extension (e.g. `jpg`)\n */\nconst CDN_PATTERN = /^(https?:\\/\\/files\\.[^/]+\\/(?:content\\/)?[^/]+\\/assets\\/(?:[^/]+\\/)*)([a-f0-9-]+)\\.(\\w+)$/\n\n/** Variant definitions mapping suffix → pixel width. */\nconst VARIANT_MAP: Record<string, { suffix: string; width: number }> = {\n thumb: { suffix: '-thumb', width: 150 },\n sm: { suffix: '-sm', width: 640 },\n md: { suffix: '-md', width: 1024 },\n lg: { suffix: '-lg', width: 1920 },\n}\n\n/** Which variants each context includes (smallest → largest). */\nconst CONTEXT_VARIANTS: Record<ImageContext, string[]> = {\n hero: ['sm', 'md', 'lg'],\n card: ['thumb', 'sm', 'md'],\n thumbnail: ['thumb', 'sm'],\n content: ['sm', 'md', 'lg'],\n og: [], // OG uses the dedicated -og variant, not srcset\n lightbox: ['md', 'lg'], // Full-screen lightbox — only large variants\n}\n\n/** Default `sizes` attribute per context. */\nconst DEFAULT_SIZES: Record<ImageContext, string> = {\n hero: '100vw',\n card: '(max-width: 640px) 100vw, (max-width: 1024px) 50vw, 33vw',\n thumbnail: '150px',\n content: '(max-width: 1024px) 100vw, 1024px',\n og: '',\n lightbox: '100vw',\n}\n\n/**\n * Resolves responsive image metadata from a DCS CDN URL.\n *\n * If the URL matches the CDN asset pattern, a srcset of WebP variants\n * is generated based on the sizing `context`. Non-CDN URLs are returned\n * as-is with no variants.\n *\n * @example\n * ```ts\n * const result = resolveResponsiveImage({\n * src: 'https://files.duffcloudservices.com/kept/assets/hero/abc-123.jpg',\n * alt: 'Hero image',\n * context: 'hero',\n * })\n * // result.hasVariants === true\n * // result.sources[0].srcset contains sm, md, lg WebP sizes\n * // result.imgProps.loading === 'eager' (hero context)\n * ```\n */\nexport function resolveResponsiveImage(options: ResponsiveImageOptions): ResponsiveImageResult {\n const { src, alt, context = 'content', sizes, original } = options\n\n const fallback: ResponsiveImageResult = {\n imgProps: {\n src,\n alt,\n loading: context === 'hero' ? 'eager' : 'lazy',\n decoding: context === 'hero' ? 'auto' : 'async',\n },\n sources: [],\n hasVariants: false,\n }\n\n if (original) {\n return fallback\n }\n\n const match = src.match(CDN_PATTERN)\n if (!match) {\n return fallback\n }\n\n const [, basePath, uuid] = match\n\n const variants = CONTEXT_VARIANTS[context] ?? CONTEXT_VARIANTS.content\n if (variants.length === 0) {\n return fallback\n }\n\n const srcsetParts = variants.map((key) => {\n const v = VARIANT_MAP[key]\n return `${basePath}${uuid}${v.suffix}.webp ${v.width}w`\n })\n\n const resolvedSizes = sizes ?? DEFAULT_SIZES[context] ?? DEFAULT_SIZES.content\n\n return {\n imgProps: {\n src: `${basePath}${uuid}${context === 'lightbox' ? '-lg' : '-md'}.webp`, // Lightbox uses lg fallback for max quality\n alt,\n loading: context === 'hero' ? 'eager' : 'lazy',\n decoding: context === 'hero' ? 'auto' : 'async',\n },\n sources: [\n {\n srcset: srcsetParts.join(', '),\n type: 'image/webp',\n ...(resolvedSizes ? { sizes: resolvedSizes } : {}),\n },\n ],\n hasVariants: true,\n }\n}\n\n/**\n * Tests whether a URL matches the DCS CDN asset pattern.\n *\n * Useful when rendering a mix of CDN-hosted and local images\n * to decide whether responsive treatment is applicable.\n */\nexport function isCdnAssetUrl(url: string): boolean {\n return CDN_PATTERN.test(url)\n}\n","export type DcsPasskeyOptions = {\n apiBaseUrl?: string\n returnTo?: string\n immediate?: boolean\n}\n\nexport type DcsPasskeyResult = {\n success: boolean\n redirectTo?: string\n visitor?: {\n email: string\n name: string\n picture?: string\n }\n}\n\ntype CeremonyOptions = {\n state: string\n publicKey: Record<string, unknown>\n}\n\ntype CredentialRequestWithImmediateUI = CredentialRequestOptions & {\n uiMode?: 'immediate'\n}\n\ntype ClientCapabilities = {\n immediateGet?: boolean\n}\n\ntype PublicKeyCredentialConstructorWithCapabilities = typeof PublicKeyCredential & {\n getClientCapabilities?: () => Promise<ClientCapabilities>\n}\n\nconst getPublicKeyCredentialConstructor = (): PublicKeyCredentialConstructorWithCapabilities | undefined => {\n if (typeof window === 'undefined' || typeof window.PublicKeyCredential === 'undefined') {\n return undefined\n }\n return window.PublicKeyCredential as PublicKeyCredentialConstructorWithCapabilities\n}\n\nconst apiBase = (value?: string) => (value ?? '/api/v1').replace(/\\/$/u, '')\n\nconst base64UrlToBuffer = (value: string): ArrayBuffer => {\n const base64 = value.replace(/-/g, '+').replace(/_/g, '/')\n const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, '=')\n const raw = window.atob(padded)\n const output = new Uint8Array(raw.length)\n for (let index = 0; index < raw.length; index += 1) {\n output[index] = raw.charCodeAt(index)\n }\n return output.buffer\n}\n\nconst bufferToBase64Url = (value: ArrayBuffer | null): string | null => {\n if (!value) {\n return null\n }\n const bytes = new Uint8Array(value)\n let binary = ''\n bytes.forEach(byte => {\n binary += String.fromCharCode(byte)\n })\n return window.btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/u, '')\n}\n\nconst decodeDescriptors = (items: unknown): PublicKeyCredentialDescriptor[] | undefined => {\n if (!Array.isArray(items)) {\n return undefined\n }\n return items.map(item => {\n const descriptor = item as { id?: unknown; type?: PublicKeyCredentialType; transports?: AuthenticatorTransport[] }\n return {\n ...descriptor,\n id: typeof descriptor.id === 'string' ? base64UrlToBuffer(descriptor.id) : descriptor.id,\n type: descriptor.type ?? 'public-key',\n } as PublicKeyCredentialDescriptor\n })\n}\n\nconst decodeCreationOptions = (publicKey: Record<string, unknown>): PublicKeyCredentialCreationOptions => {\n const user = publicKey.user as { id?: unknown } | undefined\n return {\n ...publicKey,\n challenge: base64UrlToBuffer(String(publicKey.challenge)),\n user: {\n ...(user ?? {}),\n id: typeof user?.id === 'string' ? base64UrlToBuffer(user.id) : user?.id,\n } as PublicKeyCredentialUserEntity,\n excludeCredentials: decodeDescriptors(publicKey.excludeCredentials),\n } as PublicKeyCredentialCreationOptions\n}\n\nconst decodeRequestOptions = (publicKey: Record<string, unknown>): PublicKeyCredentialRequestOptions => ({\n ...publicKey,\n challenge: base64UrlToBuffer(String(publicKey.challenge)),\n allowCredentials: decodeDescriptors(publicKey.allowCredentials),\n}) as PublicKeyCredentialRequestOptions\n\nconst serializeCredential = (credential: PublicKeyCredential): Record<string, unknown> => {\n const response = credential.response\n const base = {\n id: credential.id,\n type: credential.type,\n rawId: bufferToBase64Url(credential.rawId),\n authenticatorAttachment: credential.authenticatorAttachment,\n clientExtensionResults: credential.getClientExtensionResults(),\n }\n\n if (response instanceof AuthenticatorAttestationResponse) {\n return {\n ...base,\n response: {\n clientDataJSON: bufferToBase64Url(response.clientDataJSON),\n attestationObject: bufferToBase64Url(response.attestationObject),\n transports: response.getTransports?.() ?? [],\n },\n }\n }\n\n const assertion = response as AuthenticatorAssertionResponse\n return {\n ...base,\n response: {\n clientDataJSON: bufferToBase64Url(assertion.clientDataJSON),\n authenticatorData: bufferToBase64Url(assertion.authenticatorData),\n signature: bufferToBase64Url(assertion.signature),\n userHandle: bufferToBase64Url(assertion.userHandle),\n },\n }\n}\n\nconst postJSON = async <T>(url: string, body?: unknown): Promise<T> => {\n const response = await fetch(url, {\n method: 'POST',\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n })\n if (!response.ok) {\n throw new Error(`Passkey request failed (${response.status})`)\n }\n return await response.json() as T\n}\n\nexport const isDcsPasskeySupported = (): boolean =>\n getPublicKeyCredentialConstructor() !== undefined &&\n typeof navigator !== 'undefined' &&\n typeof navigator.credentials?.get === 'function' &&\n typeof navigator.credentials?.create === 'function'\n\nexport const isDcsPasskeyImmediateUIAvailable = async (): Promise<boolean> => {\n const publicKeyCredential = getPublicKeyCredentialConstructor()\n if (!isDcsPasskeySupported() || typeof publicKeyCredential?.getClientCapabilities !== 'function') {\n return false\n }\n try {\n const capabilities = await publicKeyCredential.getClientCapabilities()\n return capabilities.immediateGet === true\n } catch {\n return false\n }\n}\n\nexport const registerDcsSitePasskey = async (options?: DcsPasskeyOptions): Promise<string | null> => {\n if (!isDcsPasskeySupported()) {\n throw new Error('Passkeys are not available in this browser.')\n }\n const base = apiBase(options?.apiBaseUrl)\n const ceremony = await postJSON<CeremonyOptions>(`${base}/site-auth/passkeys/register/options`)\n const credential = await navigator.credentials.create({\n publicKey: decodeCreationOptions(ceremony.publicKey),\n })\n if (!(credential instanceof PublicKeyCredential)) {\n throw new Error('Passkey registration was cancelled.')\n }\n const result = await postJSON<{ success: boolean; credentialId?: string }>(\n `${base}/site-auth/passkeys/register/verify`,\n {\n state: ceremony.state,\n credential: serializeCredential(credential),\n },\n )\n if (!result.success) {\n throw new Error('Passkey registration failed.')\n }\n return result.credentialId ?? null\n}\n\nexport const authenticateDcsSitePasskey = async (options?: DcsPasskeyOptions): Promise<DcsPasskeyResult> => {\n if (!isDcsPasskeySupported()) {\n throw new Error('Passkeys are not available in this browser.')\n }\n const base = apiBase(options?.apiBaseUrl)\n const ceremony = await postJSON<CeremonyOptions>(`${base}/site-auth/passkeys/authenticate/options`)\n const request: CredentialRequestWithImmediateUI = {\n publicKey: decodeRequestOptions(ceremony.publicKey),\n }\n if (options?.immediate) {\n request.uiMode = 'immediate'\n }\n const credential = await navigator.credentials.get(request)\n if (!(credential instanceof PublicKeyCredential)) {\n throw new Error('Passkey sign-in was cancelled.')\n }\n return await postJSON<DcsPasskeyResult>(`${base}/site-auth/passkeys/authenticate/verify`, {\n state: ceremony.state,\n credential: serializeCredential(credential),\n returnTo: options?.returnTo ?? '/',\n })\n}\n"]}
|