@getquick/content 0.1.0 → 0.2.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/README.md +42 -5
- package/dist/consent-astro.js +1 -1
- package/dist/consent.js +1 -1
- package/dist/index.d.ts +15 -4
- package/dist/index.js +23 -4
- package/dist/server.d.ts +2 -2
- package/dist/server.js +109 -12
- package/dist/{version-Dn6VLZJO.js → version-DyyNhsuU.js} +1 -1
- package/dist/{wordpress-CPL40-vq.d.ts → wordpress-CUFb6YZZ.d.ts} +88 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
The configured content runtime for WordPress HTML and WPGraphQL. This slice
|
|
4
4
|
provides pure helpers, the configured WordPress client, durable delivery and
|
|
5
|
-
installed SQL migrations, and event/refresh HTTP handlers.
|
|
6
|
-
|
|
5
|
+
installed SQL migrations, and event/refresh HTTP handlers. It is released as a
|
|
6
|
+
pair with the Composer package `getquick/gq-content`, at the same version and tag.
|
|
7
7
|
|
|
8
8
|
```ts
|
|
9
9
|
import { renderWordPressBlocks, htmlLang } from "@getquick/content";
|
|
@@ -37,8 +37,8 @@ manual redirects and an eight-second deadline; failed reads return unavailable,
|
|
|
37
37
|
confirmed absence returns missing, and successful reads return found.
|
|
38
38
|
|
|
39
39
|
The root entry contains pure helpers and public structural types. The server
|
|
40
|
-
entry exports `createContentRuntime`, `ContentConfig`, `
|
|
41
|
-
`ContentRuntime` and `WordPressClient`. Runtime properties contain languages,
|
|
40
|
+
entry exports `createContentRuntime`, `ContentConfig`, `ContentExtension`,
|
|
41
|
+
`ExtensionNode`, `ContentBindings`, `ContentRuntime` and `WordPressClient`. Runtime properties contain languages,
|
|
42
42
|
routing functions and the WordPress methods; credentials/configuration are kept
|
|
43
43
|
in closures. Language configuration retains the source's normalization policy,
|
|
44
44
|
and routing returns the same language objects held in that instance's array.
|
|
@@ -62,7 +62,8 @@ untracked. The npm tarball allowlist contains only compiled output, the five ori
|
|
|
62
62
|
separate consent database migrations and package metadata (npm also includes this README).
|
|
63
63
|
|
|
64
64
|
The public delivery methods are `publishedHome(siteOrigin?, language?)`,
|
|
65
|
-
`publishedEntry(path, siteOrigin?)
|
|
65
|
+
`publishedEntry(path, siteOrigin?)`, `pageChrome(siteOrigin?)` and
|
|
66
|
+
`designPresets()`. Supply a
|
|
66
67
|
`PUBLICATION_DB` structural binding to serve durable publications. Stored reads
|
|
67
68
|
need no event or refresh secret and retain last-known-good content without an
|
|
68
69
|
age limit. Cold entry lookups read the CMS once, preserving missing versus
|
|
@@ -72,6 +73,42 @@ Production without a store returns unavailable (chrome returns null). Only
|
|
|
72
73
|
activates that fallback. All public reads guard server context before bindings
|
|
73
74
|
or transport.
|
|
74
75
|
|
|
76
|
+
`designPresets()` returns the stored design presets for a page that isn't a
|
|
77
|
+
publication (live only in explicit development, null otherwise), and
|
|
78
|
+
`internalOrigins(siteOrigin?)` the origins `menuItemHref` treats as this Site's.
|
|
79
|
+
`blockPresetStyles(spacing, colors, scope?)` scopes the preset classes to a
|
|
80
|
+
container (`.prose-wp` by default); `presetRootStyle(spacing, colors)` declares
|
|
81
|
+
the presets on `:root`.
|
|
82
|
+
|
|
83
|
+
## A Site's own content
|
|
84
|
+
|
|
85
|
+
A Site whose WordPress plugin adds fields to its pages and posts declares them
|
|
86
|
+
as an `extension`. The runtime reads them with each front page, page and post
|
|
87
|
+
(with its blocks), stores the Site's value with the publication and serves it,
|
|
88
|
+
typed, through outages:
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
const content = createContentRuntime<SiteBlocks>({
|
|
92
|
+
// …the configuration above…
|
|
93
|
+
extension: {
|
|
94
|
+
fields: { page: "wpBlocksJson pageBackgroundColor", post: "wpBlocksJson" },
|
|
95
|
+
// The Site's value for a node WordPress returned, or undefined for none.
|
|
96
|
+
read: ({ kind, fields }) => siteBlocks(fields.wpBlocksJson, fields.pageBackgroundColor),
|
|
97
|
+
// The stored value (JSON) read back, or undefined when it can't be served.
|
|
98
|
+
parse: (stored) => storedSiteBlocks.safeParse(stored).data,
|
|
99
|
+
},
|
|
100
|
+
});
|
|
101
|
+
const page = await content.publishedEntry("/about/");
|
|
102
|
+
if (page.kind === "found" && page.content.entry.extension) {
|
|
103
|
+
// Render page.content.entry.extension (SiteBlocks); the front page's is
|
|
104
|
+
// home.page.extension.
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Rows stored before the Site declared it serve without it; a refresh stores it.
|
|
109
|
+
A read throwing fails as WordPress's answer not matching the schema, and a read
|
|
110
|
+
without its blocks stores nothing, so the stored page stays served. See ADR 0004.
|
|
111
|
+
|
|
75
112
|
Infrastructure imports the Node-only migration entry separately:
|
|
76
113
|
|
|
77
114
|
```ts
|
package/dist/consent-astro.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { S as SERVICE_CATALOG, T as copyLanguage, c as grantedCategories, d as promptReason, f as readConsentCookie, x as OPTIONAL_CATEGORIES } from "./state-BYWc5TUB.js";
|
|
2
2
|
import { a as CONSENT_COPY, c as legalRevisions, r as escapeHtml } from "./embeds-p9SyGNZI.js";
|
|
3
|
-
import { t as CONSENT_UI_VERSION } from "./version-
|
|
3
|
+
import { t as CONSENT_UI_VERSION } from "./version-DyyNhsuU.js";
|
|
4
4
|
import { t as CONSENT_CONFIG_ID } from "./client-config-B3LNSOxl.js";
|
|
5
5
|
import { t as CONSENT_PATH } from "./paths-Cmzzof3v.js";
|
|
6
6
|
//#region frontend/src/consent/astro.ts
|
package/dist/consent.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as SERVICE_IDS, D as hostMatches, E as embedService, O as hostService, S as SERVICE_CATALOG, T as copyLanguage, _ as consentConfiguration, a as consentCookie, b as COPY_LANGUAGES, c as grantedCategories, d as promptReason, f as readConsentCookie, g as MEASUREMENT_ID, h as CONSENT_COPY_REVISION, i as DECISION_VALIDITY_MS, k as isServiceId, l as isConsentId, m as serviceGranted, n as CONSENT_COOKIE, o as decide, p as serializeConsentState, r as CONSENT_COOKIE_MAX_AGE_SECONDS, s as denyAll, t as CONSENT_ACTIONS, u as parseConsentState, v as needsBanner, w as catalogService, x as OPTIONAL_CATEGORIES, y as CONSENT_CATEGORIES } from "./state-BYWc5TUB.js";
|
|
2
2
|
import { a as parseConsentRecordRequest, i as isRecordToken, n as consentRecordRequest, r as isLegalRoleName, t as MAX_RECORD_BYTES } from "./records-Dumrz759.js";
|
|
3
3
|
import { a as CONSENT_COPY, c as legalRevisions, i as rewriteEmbeds, l as parseLegalLanguage, n as embedPlaceholder, o as LEGAL_ROLES, r as escapeHtml, s as REQUIRED_LEGAL_ROLES, t as blockedPlaceholder } from "./embeds-p9SyGNZI.js";
|
|
4
|
-
import { t as CONSENT_UI_VERSION } from "./version-
|
|
4
|
+
import { t as CONSENT_UI_VERSION } from "./version-DyyNhsuU.js";
|
|
5
5
|
export { CONSENT_ACTIONS, CONSENT_CATEGORIES, CONSENT_COOKIE, CONSENT_COOKIE_MAX_AGE_SECONDS, CONSENT_COPY, CONSENT_COPY_REVISION, CONSENT_UI_VERSION, COPY_LANGUAGES, DECISION_VALIDITY_MS, LEGAL_ROLES, MAX_RECORD_BYTES, MEASUREMENT_ID, OPTIONAL_CATEGORIES, REQUIRED_LEGAL_ROLES, SERVICE_CATALOG, SERVICE_IDS, blockedPlaceholder, catalogService, consentConfiguration, consentCookie, consentRecordRequest, copyLanguage, decide, denyAll, embedPlaceholder, embedService, escapeHtml, grantedCategories, hostMatches, hostService, isConsentId, isLegalRoleName, isRecordToken, isServiceId, legalRevisions, needsBanner, parseConsentRecordRequest, parseConsentState, parseLegalLanguage, promptReason, readConsentCookie, rewriteEmbeds, serializeConsentState, serviceGranted };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as
|
|
1
|
+
import { A as PublishedEntry, B as htmlLang, C as Delivery, D as Found, E as Extended, F as WordPressMenuItem, H as languageSubject, I as WordPressPost, L as WordPressSettings, M as Translation, N as Unavailable, O as HomeContent, P as WordPressImage, R as SiteLanguage, S as CmsFailureReason, T as EntryContent, U as routeLanguage, V as isLanguageHome, W as siteLanguages, _ as NotServed, a as ContentRuntime, b as SqlStatement, c as Alternate, d as EntryPage, f as EntryPublication, g as Moved, h as HomePublication, i as ContentExtension, j as SiteChrome, k as Missing, l as DeliveryFailureReason, m as HomePage, n as ContentConfig, o as ExtensionNode, p as HomeDelivery, r as ContentConsentConfig, t as WordPressClient, u as EntryDelivery, v as ContentBindings, w as DesignPresets, x as CmsFailure, y as SqlDatabase, z as WordPressLanguages } from "./wordpress-CUFb6YZZ.js";
|
|
2
2
|
//#region frontend/src/wp-block-styles.d.ts
|
|
3
3
|
export interface Preset {
|
|
4
4
|
slug: string;
|
|
@@ -13,8 +13,19 @@ export interface BlockPresetStyles {
|
|
|
13
13
|
vars: Record<string, string>;
|
|
14
14
|
colorRules: string;
|
|
15
15
|
}
|
|
16
|
-
/**
|
|
17
|
-
|
|
16
|
+
/**
|
|
17
|
+
* WordPress preset classes need the CMS palette as well as CSS variables.
|
|
18
|
+
* `scope` is the content's container (`.prose-wp` by default; another for
|
|
19
|
+
* content a Site renders itself).
|
|
20
|
+
*/
|
|
21
|
+
export declare function blockPresetStyles(spacingSizes: SpacingPreset[], colors: ColorPreset[], scope?: string): BlockPresetStyles;
|
|
22
|
+
/**
|
|
23
|
+
* The design presets as WordPress defines them, on `:root`, for styles that
|
|
24
|
+
* read the palette and spacing from these variables outside the content's
|
|
25
|
+
* container. Presets with an invalid slug, or a value that could end the
|
|
26
|
+
* rule, are left out; "" without any.
|
|
27
|
+
*/
|
|
28
|
+
export declare function presetRootStyle(spacingSizes: SpacingPreset[], colors: ColorPreset[]): string;
|
|
18
29
|
//#endregion
|
|
19
30
|
//#region frontend/src/wp-block-renderer.d.ts
|
|
20
31
|
export interface WordPressBlock {
|
|
@@ -61,4 +72,4 @@ export declare function stripHtml(value: string): string;
|
|
|
61
72
|
export declare function formatDate(value: string, lang?: string): string;
|
|
62
73
|
export declare function routeOf(path: string): string;
|
|
63
74
|
//#endregion
|
|
64
|
-
export { Alternate, CmsFailure, CmsFailureReason, ContentBindings, type ContentConfig, type ContentConsentConfig, type ContentRuntime, Delivery, DeliveryFailureReason, DesignPresets, EntryContent, EntryDelivery, EntryPage, EntryPublication, Found, HomeContent, HomeDelivery, HomePage, HomePublication, Missing, Moved, NotServed, PublishedEntry, SiteChrome, SiteLanguage, SqlDatabase, SqlStatement, Translation, Unavailable, type WordPressClient, WordPressImage, WordPressLanguages, WordPressMenuItem, WordPressPost, WordPressSettings, htmlLang, isLanguageHome, languageSubject, routeLanguage, siteLanguages };
|
|
75
|
+
export { Alternate, CmsFailure, CmsFailureReason, ContentBindings, type ContentConfig, type ContentConsentConfig, type ContentExtension, type ContentRuntime, Delivery, DeliveryFailureReason, DesignPresets, EntryContent, EntryDelivery, EntryPage, EntryPublication, Extended, type ExtensionNode, Found, HomeContent, HomeDelivery, HomePage, HomePublication, Missing, Moved, NotServed, PublishedEntry, SiteChrome, SiteLanguage, SqlDatabase, SqlStatement, Translation, Unavailable, type WordPressClient, WordPressImage, WordPressLanguages, WordPressMenuItem, WordPressPost, WordPressSettings, htmlLang, isLanguageHome, languageSubject, routeLanguage, siteLanguages };
|
package/dist/index.js
CHANGED
|
@@ -1,20 +1,39 @@
|
|
|
1
1
|
import { _ as youtubeVideoId, a as routeOf, c as htmlLang, d as routeLanguage, f as siteLanguages, g as renderWordPressBlocks, h as parseWordPressBlocks, i as responseStatus, l as isLanguageHome, m as hasVideoHero, n as formatDate, o as stripHtml, p as VIDEO_HERO_BLOCK, r as menuItemHref, s as uriPath, t as cmsTime, u as languageSubject, v as containerChildLayoutHtml, y as containerLayoutHtml } from "./formatting-wOk2jz6J.js";
|
|
2
2
|
//#region frontend/src/wp-block-styles.ts
|
|
3
3
|
const validSlug = (slug) => /^[a-z0-9][a-z0-9-]*$/.test(slug);
|
|
4
|
-
/**
|
|
5
|
-
|
|
4
|
+
/** A CSS value safe inside a stylesheet: a color or length, nothing that ends a rule. */
|
|
5
|
+
const safeValue = (value) => /^[#(),.%\w\s-]+$/.test(value);
|
|
6
|
+
/** A selector for the content's container: classes, ids, elements and descendants. */
|
|
7
|
+
const validScope = (scope) => /^[.#]?[A-Za-z][\w-]*(?:[ .#>][A-Za-z][\w-]*)*$/.test(scope);
|
|
8
|
+
/**
|
|
9
|
+
* WordPress preset classes need the CMS palette as well as CSS variables.
|
|
10
|
+
* `scope` is the content's container (`.prose-wp` by default; another for
|
|
11
|
+
* content a Site renders itself).
|
|
12
|
+
*/
|
|
13
|
+
function blockPresetStyles(spacingSizes, colors, scope = ".prose-wp") {
|
|
14
|
+
if (!validScope(scope)) throw new Error(`${JSON.stringify(scope)} isn't a container selector`);
|
|
6
15
|
const vars = {};
|
|
7
16
|
const colorRules = [];
|
|
8
17
|
for (const { slug, size } of spacingSizes) if (validSlug(slug)) vars[`--wp--preset--spacing--${slug}`] = size;
|
|
9
18
|
for (const { slug, color } of colors) {
|
|
10
19
|
if (!validSlug(slug)) continue;
|
|
11
20
|
vars[`--wp--preset--color--${slug}`] = color;
|
|
12
|
-
colorRules.push(
|
|
21
|
+
colorRules.push(`${scope} .has-${slug}-color{color:var(--wp--preset--color--${slug})}`, `${scope} .has-${slug}-background-color{background-color:var(--wp--preset--color--${slug})}`, `${scope} .has-${slug}-color.has-link-color a{color:var(--wp--preset--color--${slug})}`);
|
|
13
22
|
}
|
|
14
23
|
return {
|
|
15
24
|
vars,
|
|
16
25
|
colorRules: colorRules.join("\n")
|
|
17
26
|
};
|
|
18
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* The design presets as WordPress defines them, on `:root`, for styles that
|
|
30
|
+
* read the palette and spacing from these variables outside the content's
|
|
31
|
+
* container. Presets with an invalid slug, or a value that could end the
|
|
32
|
+
* rule, are left out; "" without any.
|
|
33
|
+
*/
|
|
34
|
+
function presetRootStyle(spacingSizes, colors) {
|
|
35
|
+
const declarations = [...spacingSizes.filter(({ slug, size }) => validSlug(slug) && safeValue(size)).map(({ slug, size }) => `--wp--preset--spacing--${slug}:${size}`), ...colors.filter(({ slug, color }) => validSlug(slug) && safeValue(color)).map(({ slug, color }) => `--wp--preset--color--${slug}:${color}`)];
|
|
36
|
+
return declarations.length ? `:root{${declarations.join(";")}}` : "";
|
|
37
|
+
}
|
|
19
38
|
//#endregion
|
|
20
|
-
export { VIDEO_HERO_BLOCK, blockPresetStyles, cmsTime, containerChildLayoutHtml, containerLayoutHtml, formatDate, hasVideoHero, htmlLang, isLanguageHome, languageSubject, menuItemHref, parseWordPressBlocks, renderWordPressBlocks, responseStatus, routeLanguage, routeOf, siteLanguages, stripHtml, uriPath, youtubeVideoId };
|
|
39
|
+
export { VIDEO_HERO_BLOCK, blockPresetStyles, cmsTime, containerChildLayoutHtml, containerLayoutHtml, formatDate, hasVideoHero, htmlLang, isLanguageHome, languageSubject, menuItemHref, parseWordPressBlocks, presetRootStyle, renderWordPressBlocks, responseStatus, routeLanguage, routeOf, siteLanguages, stripHtml, uriPath, youtubeVideoId };
|
package/dist/server.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { type ContentBindings, ContentConfig, ContentConsentConfig, ContentRuntime, type WordPressClient, createContentRuntime };
|
|
1
|
+
import { a as ContentRuntime, i as ContentExtension, n as ContentConfig, o as ExtensionNode, r as ContentConsentConfig, s as createContentRuntime, t as WordPressClient, v as ContentBindings } from "./wordpress-CUFb6YZZ.js";
|
|
2
|
+
export { type ContentBindings, ContentConfig, ContentConsentConfig, ContentExtension, ContentRuntime, ExtensionNode, type WordPressClient, createContentRuntime };
|
package/dist/server.js
CHANGED
|
@@ -3550,6 +3550,7 @@ ZodOptional.create;
|
|
|
3550
3550
|
ZodNullable.create;
|
|
3551
3551
|
ZodEffects.createWithPreprocess;
|
|
3552
3552
|
ZodPipeline.create;
|
|
3553
|
+
const NEVER = INVALID;
|
|
3553
3554
|
/** The store couldn't be read or written. Says nothing about the content. */
|
|
3554
3555
|
var StoreFailure = class extends Error {};
|
|
3555
3556
|
const eventOf = (row) => ({
|
|
@@ -4743,6 +4744,29 @@ function configuredDelivery(config, languages, wordpress, transformHtml) {
|
|
|
4743
4744
|
slug: stringType(),
|
|
4744
4745
|
color: stringType()
|
|
4745
4746
|
}));
|
|
4747
|
+
/**
|
|
4748
|
+
* The Site's extension of a page or post, as its `parse` reads it back. A
|
|
4749
|
+
* row stored without one (before the Site declared it) still serves; an
|
|
4750
|
+
* extension stored without the Site declaring one now is left out.
|
|
4751
|
+
*/
|
|
4752
|
+
const extension = config.extension;
|
|
4753
|
+
const extended = extension ? { extension: unknownType().optional().transform((value, context) => {
|
|
4754
|
+
if (value === void 0) return void 0;
|
|
4755
|
+
let parsed;
|
|
4756
|
+
try {
|
|
4757
|
+
parsed = extension.parse(value);
|
|
4758
|
+
} catch {
|
|
4759
|
+
parsed = void 0;
|
|
4760
|
+
}
|
|
4761
|
+
if (parsed === void 0) {
|
|
4762
|
+
context.addIssue({
|
|
4763
|
+
code: "custom",
|
|
4764
|
+
message: "the Site can't serve this extension"
|
|
4765
|
+
});
|
|
4766
|
+
return NEVER;
|
|
4767
|
+
}
|
|
4768
|
+
return parsed;
|
|
4769
|
+
}) } : {};
|
|
4746
4770
|
const homePublication = objectType({
|
|
4747
4771
|
settings: objectType({
|
|
4748
4772
|
title: stringType(),
|
|
@@ -4751,7 +4775,8 @@ function configuredDelivery(config, languages, wordpress, transformHtml) {
|
|
|
4751
4775
|
page: objectType({
|
|
4752
4776
|
title: stringType(),
|
|
4753
4777
|
content: stringType(),
|
|
4754
|
-
hasVideoHero: booleanType()
|
|
4778
|
+
hasVideoHero: booleanType(),
|
|
4779
|
+
...extended
|
|
4755
4780
|
}),
|
|
4756
4781
|
spacingSizes,
|
|
4757
4782
|
colors
|
|
@@ -4772,7 +4797,8 @@ function configuredDelivery(config, languages, wordpress, transformHtml) {
|
|
|
4772
4797
|
featuredImage: image,
|
|
4773
4798
|
hasVideoHero: booleanType(),
|
|
4774
4799
|
spacingSizes,
|
|
4775
|
-
colors
|
|
4800
|
+
colors,
|
|
4801
|
+
...extended
|
|
4776
4802
|
});
|
|
4777
4803
|
const legalRole = objectType({
|
|
4778
4804
|
role: stringType(),
|
|
@@ -5126,6 +5152,27 @@ function configuredDelivery(config, languages, wordpress, transformHtml) {
|
|
|
5126
5152
|
}
|
|
5127
5153
|
}
|
|
5128
5154
|
/**
|
|
5155
|
+
* The design presets for a page that isn't a publication: the stored ones
|
|
5156
|
+
* when there is a store, else a live read in explicit development. Null
|
|
5157
|
+
* when neither has them; the page is then served without them.
|
|
5158
|
+
*/
|
|
5159
|
+
async function pageDesign() {
|
|
5160
|
+
if (!config.isServer()) return null;
|
|
5161
|
+
const store = await boundStore();
|
|
5162
|
+
if (!store) {
|
|
5163
|
+
if (!config.development) return null;
|
|
5164
|
+
const design = await getDesignPresets();
|
|
5165
|
+
return design.kind === "found" ? design.content : null;
|
|
5166
|
+
}
|
|
5167
|
+
try {
|
|
5168
|
+
return sharedDesign(await store.read(DESIGN, parseDesign));
|
|
5169
|
+
} catch (error) {
|
|
5170
|
+
if (!(error instanceof StoreFailure)) throw error;
|
|
5171
|
+
console.error(`Delivery: the design presets can't be served (store): ${error.message}`);
|
|
5172
|
+
return null;
|
|
5173
|
+
}
|
|
5174
|
+
}
|
|
5175
|
+
/**
|
|
5129
5176
|
* Refreshes the whole Site, the explicit preparation of its store: each
|
|
5130
5177
|
* language's front page and chrome, the shared design presets, and every
|
|
5131
5178
|
* entry WordPress lists as published or the store already holds (so one
|
|
@@ -5599,14 +5646,28 @@ function configuredDelivery(config, languages, wordpress, transformHtml) {
|
|
|
5599
5646
|
isAuthorized,
|
|
5600
5647
|
publishedHome: (siteOrigin, language) => safely(async () => html.home(await publishedHome(siteOrigin, language), language), () => notServed("the front page", "store", "The publication store couldn't be loaded")),
|
|
5601
5648
|
publishedEntry: (path, siteOrigin) => safely(async () => html.entry(await publishedEntry(path, siteOrigin), routeLanguage$1(routeOf(path))), () => notServed("the entry", "store", "The publication store couldn't be loaded")),
|
|
5602
|
-
pageChrome: (siteOrigin) => safely(() => pageChrome(siteOrigin), () => null)
|
|
5649
|
+
pageChrome: (siteOrigin) => safely(() => pageChrome(siteOrigin), () => null),
|
|
5650
|
+
designPresets: () => safely(() => pageDesign(), () => null)
|
|
5603
5651
|
};
|
|
5604
5652
|
}
|
|
5605
5653
|
//#endregion
|
|
5606
5654
|
//#region frontend/src/wordpress.ts
|
|
5655
|
+
/** The origins a link into this Site may use: WordPress's, and the Frontend's when given. */
|
|
5656
|
+
function internalOrigins(config, siteOrigin) {
|
|
5657
|
+
return [new URL(config.graphqlEndpoint).origin, ...siteOrigin ? [siteOrigin] : []];
|
|
5658
|
+
}
|
|
5607
5659
|
function configuredWordPress(config, languages) {
|
|
5608
5660
|
const defaultLanguage = languages[0];
|
|
5609
5661
|
const multilingual = languages.length > 1;
|
|
5662
|
+
const extension = config.extension;
|
|
5663
|
+
/**
|
|
5664
|
+
* The Site's extension fields on a kind of node, read with the blocks (left
|
|
5665
|
+
* out with them when WordPress fails on them).
|
|
5666
|
+
*/
|
|
5667
|
+
const extensionFields = (kind) => {
|
|
5668
|
+
const fields = extension?.fields[kind]?.trim();
|
|
5669
|
+
return fields ? `\n... @include(if: $withBlocks) {\n${fields}\n}` : "";
|
|
5670
|
+
};
|
|
5610
5671
|
const image = objectType({
|
|
5611
5672
|
sourceUrl: stringType(),
|
|
5612
5673
|
altText: stringType().nullable()
|
|
@@ -5634,7 +5695,7 @@ function configuredWordPress(config, languages) {
|
|
|
5634
5695
|
title: stringType().nullable(),
|
|
5635
5696
|
content: stringType().nullable(),
|
|
5636
5697
|
blocks: unknownType().optional()
|
|
5637
|
-
}), objectType({ __typename: stringType().refine((typename) => typename !== "Page") })]).nullable(),
|
|
5698
|
+
}).passthrough(), objectType({ __typename: stringType().refine((typename) => typename !== "Page") })]).nullable(),
|
|
5638
5699
|
designTokens
|
|
5639
5700
|
});
|
|
5640
5701
|
const pageEntry = objectType({
|
|
@@ -5647,7 +5708,7 @@ function configuredWordPress(config, languages) {
|
|
|
5647
5708
|
modifiedGmt: stringType().nullable().optional(),
|
|
5648
5709
|
featuredImage: imageEdge,
|
|
5649
5710
|
blocks: unknownType().optional()
|
|
5650
|
-
});
|
|
5711
|
+
}).passthrough();
|
|
5651
5712
|
const postEntry = pageEntry.extend({
|
|
5652
5713
|
excerpt: stringType().nullable(),
|
|
5653
5714
|
date: stringType().nullable()
|
|
@@ -5745,7 +5806,7 @@ function configuredWordPress(config, languages) {
|
|
|
5745
5806
|
content
|
|
5746
5807
|
blocks(attributes: true, htmlContent: true, dynamicContent: true, postTemplate: false)
|
|
5747
5808
|
@include(if: $withBlocks)
|
|
5748
|
-
isFrontPage
|
|
5809
|
+
isFrontPage${extensionFields("page")}
|
|
5749
5810
|
}
|
|
5750
5811
|
}
|
|
5751
5812
|
designTokens {
|
|
@@ -5774,7 +5835,7 @@ function configuredWordPress(config, languages) {
|
|
|
5774
5835
|
content
|
|
5775
5836
|
blocks(attributes: true, htmlContent: true, dynamicContent: true, postTemplate: false)
|
|
5776
5837
|
@include(if: $withBlocks)
|
|
5777
|
-
isFrontPage
|
|
5838
|
+
isFrontPage${extensionFields("page")}
|
|
5778
5839
|
}
|
|
5779
5840
|
}
|
|
5780
5841
|
designTokens {
|
|
@@ -5860,7 +5921,7 @@ function configuredWordPress(config, languages) {
|
|
|
5860
5921
|
sourceUrl
|
|
5861
5922
|
altText
|
|
5862
5923
|
}
|
|
5863
|
-
}
|
|
5924
|
+
}${extensionFields("post")}
|
|
5864
5925
|
}
|
|
5865
5926
|
pageBy(uri: $uri) {
|
|
5866
5927
|
id
|
|
@@ -5877,7 +5938,7 @@ function configuredWordPress(config, languages) {
|
|
|
5877
5938
|
sourceUrl
|
|
5878
5939
|
altText
|
|
5879
5940
|
}
|
|
5880
|
-
}
|
|
5941
|
+
}${extensionFields("page")}
|
|
5881
5942
|
}
|
|
5882
5943
|
}
|
|
5883
5944
|
`;
|
|
@@ -5946,6 +6007,27 @@ function configuredWordPress(config, languages) {
|
|
|
5946
6007
|
function describeIssues(error) {
|
|
5947
6008
|
return error.issues.map((issue) => `${issue.path.join(".") || "data"}: ${issue.message}`).join("; ");
|
|
5948
6009
|
}
|
|
6010
|
+
/**
|
|
6011
|
+
* `{ extension }` with the Site's value for a node WordPress returned, or
|
|
6012
|
+
* nothing: without an extension, fields for its kind, or a value, and when
|
|
6013
|
+
* the blocks (and with them the fields) were left out.
|
|
6014
|
+
*/
|
|
6015
|
+
function extended(kind, node, blocksOmitted) {
|
|
6016
|
+
if (!extension || !extensionFields(kind) || blocksOmitted) return {};
|
|
6017
|
+
let value;
|
|
6018
|
+
try {
|
|
6019
|
+
value = extension.read({
|
|
6020
|
+
kind,
|
|
6021
|
+
fields: node
|
|
6022
|
+
});
|
|
6023
|
+
} catch (error) {
|
|
6024
|
+
throw new CmsFailureError({
|
|
6025
|
+
reason: "schema",
|
|
6026
|
+
message: `WordPress's ${kind} doesn't match the Site's extension: ${error instanceof Error ? error.message : String(error)}`
|
|
6027
|
+
}, { cause: error });
|
|
6028
|
+
}
|
|
6029
|
+
return value === void 0 ? {} : { extension: value };
|
|
6030
|
+
}
|
|
5949
6031
|
async function query(schema, queryText, variables) {
|
|
5950
6032
|
let response;
|
|
5951
6033
|
let credentials = [];
|
|
@@ -6105,7 +6187,8 @@ function configuredWordPress(config, languages) {
|
|
|
6105
6187
|
page: {
|
|
6106
6188
|
title: node.title ?? "",
|
|
6107
6189
|
content: containsVideoHero ? renderWordPressBlocks(blocks) : node.content ?? "",
|
|
6108
|
-
hasVideoHero: containsVideoHero
|
|
6190
|
+
hasVideoHero: containsVideoHero,
|
|
6191
|
+
...extended("page", node, blocksOmitted)
|
|
6109
6192
|
},
|
|
6110
6193
|
blocksOmitted,
|
|
6111
6194
|
spacingSizes: data.designTokens.spacingSizes,
|
|
@@ -6137,7 +6220,8 @@ function configuredWordPress(config, languages) {
|
|
|
6137
6220
|
modifiedAt: cmsTime(post.modifiedGmt),
|
|
6138
6221
|
spacingSizes: data.designTokens.spacingSizes,
|
|
6139
6222
|
colors: data.designTokens.colors,
|
|
6140
|
-
...multilingual ? languageOf(post) : {}
|
|
6223
|
+
...multilingual ? languageOf(post) : {},
|
|
6224
|
+
...extended(data.postBy ? "post" : "page", post, blocksOmitted)
|
|
6141
6225
|
}
|
|
6142
6226
|
};
|
|
6143
6227
|
});
|
|
@@ -6265,7 +6349,7 @@ function configuredWordPress(config, languages) {
|
|
|
6265
6349
|
location,
|
|
6266
6350
|
language: language.code
|
|
6267
6351
|
}), config.consent?.cmsSettings ? consentSettings(language) : null]);
|
|
6268
|
-
const origins =
|
|
6352
|
+
const origins = internalOrigins(config, siteOrigin);
|
|
6269
6353
|
return {
|
|
6270
6354
|
kind: "found",
|
|
6271
6355
|
content: {
|
|
@@ -6297,6 +6381,7 @@ function configuredWordPress(config, languages) {
|
|
|
6297
6381
|
function createContentRuntime(input) {
|
|
6298
6382
|
const site = input.site.trim();
|
|
6299
6383
|
if (!site) throw new Error("A nonempty Site identity is required");
|
|
6384
|
+
for (const [kind, fields] of Object.entries(input.extension?.fields ?? {})) if (fields !== void 0 && !fields.trim()) throw new Error(`The extension's ${kind} fields are empty; leave them out instead`);
|
|
6300
6385
|
const config = {
|
|
6301
6386
|
...input,
|
|
6302
6387
|
site,
|
|
@@ -6353,6 +6438,18 @@ function createContentRuntime(input) {
|
|
|
6353
6438
|
publishedEntry: delivery.publishedEntry,
|
|
6354
6439
|
pageChrome: delivery.pageChrome,
|
|
6355
6440
|
/**
|
|
6441
|
+
* The design presets every page shares (GQ Design's spacing sizes and
|
|
6442
|
+
* colors), for a page that isn't a publication: the stored ones when there
|
|
6443
|
+
* is a store, else (in explicit development) a live read. Null when
|
|
6444
|
+
* neither has them.
|
|
6445
|
+
*/
|
|
6446
|
+
designPresets: delivery.designPresets,
|
|
6447
|
+
/**
|
|
6448
|
+
* The origins a link into this Site may use: WordPress's, and the
|
|
6449
|
+
* Frontend's when given. `menuItemHref` turns links at them into paths.
|
|
6450
|
+
*/
|
|
6451
|
+
internalOrigins: (siteOrigin) => internalOrigins(config, siteOrigin),
|
|
6452
|
+
/**
|
|
6356
6453
|
* The Site's consent configuration for a page served with this chrome:
|
|
6357
6454
|
* declared services, GA4 when gq-config's toggle is on, and the
|
|
6358
6455
|
* controller from the Legal Contract. Null when consent isn't configured.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
//#endregion
|
|
2
2
|
//#region frontend/src/consent/version.ts
|
|
3
3
|
/** The UI/adapter version recorded with each decision (CN-R7). */
|
|
4
|
-
const CONSENT_UI_VERSION = `gq-content@0.
|
|
4
|
+
const CONSENT_UI_VERSION = `gq-content@0.2.0`;
|
|
5
5
|
//#endregion
|
|
6
6
|
export { CONSENT_UI_VERSION as t };
|
|
@@ -47,7 +47,7 @@ declare function languageSubject(language: SiteLanguage, what: string): string;
|
|
|
47
47
|
/** Whether a route is a language's home (/, /en/): served as a home, never as an entry. */
|
|
48
48
|
declare function isLanguageHome(route: string, among: readonly SiteLanguage[]): boolean;
|
|
49
49
|
declare namespace content_types_d_exports {
|
|
50
|
-
export { CmsFailure, CmsFailureReason, Delivery, DesignPresets, EntryContent, Found, HomeContent, Missing, PublishedEntry, SiteChrome, Translation, Unavailable, WordPressImage, WordPressMenuItem, WordPressPost, WordPressSettings };
|
|
50
|
+
export { CmsFailure, CmsFailureReason, Delivery, DesignPresets, EntryContent, Extended, Found, HomeContent, Missing, PublishedEntry, SiteChrome, Translation, Unavailable, WordPressImage, WordPressMenuItem, WordPressPost, WordPressSettings };
|
|
51
51
|
}
|
|
52
52
|
interface WordPressImage {
|
|
53
53
|
sourceUrl: string;
|
|
@@ -84,7 +84,15 @@ interface DesignPresets {
|
|
|
84
84
|
color: string;
|
|
85
85
|
}>;
|
|
86
86
|
}
|
|
87
|
-
|
|
87
|
+
/**
|
|
88
|
+
* A page or post's own content as the Site's extension read it
|
|
89
|
+
* (ContentConfig's `extension`): present only when the Site declares one and
|
|
90
|
+
* its read returned a value for that page or post.
|
|
91
|
+
*/
|
|
92
|
+
interface Extended<X = unknown> {
|
|
93
|
+
extension?: X;
|
|
94
|
+
}
|
|
95
|
+
interface HomeContent<X = unknown> extends DesignPresets {
|
|
88
96
|
/** The front page's WordPress entry (WPGraphQL's global id), if WordPress gave it. */
|
|
89
97
|
nodeId: string | null;
|
|
90
98
|
settings: WordPressSettings;
|
|
@@ -92,7 +100,7 @@ interface HomeContent extends DesignPresets {
|
|
|
92
100
|
title: string;
|
|
93
101
|
content: string;
|
|
94
102
|
hasVideoHero: boolean;
|
|
95
|
-
}
|
|
103
|
+
} & Extended<X>;
|
|
96
104
|
/** WordPress failed on the blocks, so this is the page without them. */
|
|
97
105
|
blocksOmitted: boolean;
|
|
98
106
|
}
|
|
@@ -101,7 +109,7 @@ interface Translation {
|
|
|
101
109
|
uri: string;
|
|
102
110
|
language: string;
|
|
103
111
|
}
|
|
104
|
-
interface EntryContent extends WordPressPost, DesignPresets {
|
|
112
|
+
interface EntryContent<X = unknown> extends WordPressPost, DesignPresets, Extended<X> {
|
|
105
113
|
/** Its language's slug, on a multilingual Site. */
|
|
106
114
|
language?: string;
|
|
107
115
|
/** Its published translations into the site's other languages, on a multilingual Site. */
|
|
@@ -192,9 +200,9 @@ interface ContentBindings {
|
|
|
192
200
|
//#endregion
|
|
193
201
|
//#region frontend/src/page-types.d.ts
|
|
194
202
|
/** The front page as stored: what WordPress delivered, without read details. */
|
|
195
|
-
type HomePublication = Omit<HomeContent
|
|
203
|
+
type HomePublication<X = unknown> = Omit<HomeContent<X>, "blocksOmitted" | "nodeId">;
|
|
196
204
|
/** A published page or post as stored, with the design presets it was read with. */
|
|
197
|
-
type EntryPublication = Omit<EntryContent
|
|
205
|
+
type EntryPublication<X = unknown> = Omit<EntryContent<X>, "blocksOmitted" | "modifiedAt">;
|
|
198
206
|
/**
|
|
199
207
|
* A page in another language that a visitor of this one may switch to: its
|
|
200
208
|
* published translation (`translation`), or else that language's home.
|
|
@@ -204,14 +212,14 @@ interface Alternate {
|
|
|
204
212
|
route: string;
|
|
205
213
|
translation: boolean;
|
|
206
214
|
}
|
|
207
|
-
interface HomePage {
|
|
208
|
-
home: HomePublication
|
|
215
|
+
interface HomePage<X = unknown> {
|
|
216
|
+
home: HomePublication<X>;
|
|
209
217
|
chrome: SiteChrome;
|
|
210
218
|
/** The other languages' homes that are served; none on a monolingual Site. */
|
|
211
219
|
alternates: Alternate[];
|
|
212
220
|
}
|
|
213
|
-
interface EntryPage {
|
|
214
|
-
entry: EntryPublication
|
|
221
|
+
interface EntryPage<X = unknown> {
|
|
222
|
+
entry: EntryPublication<X>;
|
|
215
223
|
chrome: SiteChrome;
|
|
216
224
|
/** Where its readers may switch language; none on a monolingual Site. */
|
|
217
225
|
alternates: Alternate[];
|
|
@@ -234,15 +242,15 @@ interface NotServed {
|
|
|
234
242
|
message: string;
|
|
235
243
|
};
|
|
236
244
|
}
|
|
237
|
-
type HomeDelivery = Found<HomePage
|
|
245
|
+
type HomeDelivery<X = unknown> = Found<HomePage<X>> | (Missing & {
|
|
238
246
|
chrome: SiteChrome | null;
|
|
239
247
|
}) | NotServed;
|
|
240
|
-
type EntryDelivery = Found<EntryPage
|
|
248
|
+
type EntryDelivery<X = unknown> = Found<EntryPage<X>> | (Missing & {
|
|
241
249
|
chrome: SiteChrome | null;
|
|
242
250
|
}) | Moved | NotServed;
|
|
243
251
|
//#endregion
|
|
244
252
|
//#region frontend/src/server.d.ts
|
|
245
|
-
interface ContentConfig {
|
|
253
|
+
interface ContentConfig<X = never> {
|
|
246
254
|
site: string;
|
|
247
255
|
graphqlEndpoint: string;
|
|
248
256
|
cmsOrigin: string;
|
|
@@ -258,6 +266,52 @@ interface ContentConfig {
|
|
|
258
266
|
* delivery; absent, bodies are delivered as published.
|
|
259
267
|
*/
|
|
260
268
|
consent?: ContentConsentConfig;
|
|
269
|
+
/**
|
|
270
|
+
* The Site's own content on its pages and posts: GraphQL fields the runtime
|
|
271
|
+
* reads with each of them, and the value the Site makes of them, stored with
|
|
272
|
+
* the publication and served as its `extension`.
|
|
273
|
+
*/
|
|
274
|
+
extension?: ContentExtension<X>;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* A Site's own content on its pages and posts, beyond what the runtime reads:
|
|
278
|
+
* fields a plugin adds to WPGraphQL (a block tree, a page setting), read with
|
|
279
|
+
* every front page, page and post, stored with it, and served with it through
|
|
280
|
+
* outages, as the rest of it is.
|
|
281
|
+
*/
|
|
282
|
+
interface ContentExtension<X> {
|
|
283
|
+
/**
|
|
284
|
+
* GraphQL selections added to each kind of node the runtime reads: `page`
|
|
285
|
+
* to front pages and pages, `post` to posts (e.g. `wpBlocksJson`). They are
|
|
286
|
+
* read with the blocks: a read WordPress can only complete without its
|
|
287
|
+
* blocks leaves them out too, and isn't stored. A kind without fields has
|
|
288
|
+
* no extension.
|
|
289
|
+
*/
|
|
290
|
+
fields: {
|
|
291
|
+
page?: string;
|
|
292
|
+
post?: string;
|
|
293
|
+
};
|
|
294
|
+
/**
|
|
295
|
+
* The Site's value for a node WordPress returned (its fields, the runtime's
|
|
296
|
+
* among them), or undefined when it has none (`extension` is then left
|
|
297
|
+
* out). It is stored as JSON, so it must survive JSON. Throwing fails the
|
|
298
|
+
* read as WordPress answering with the wrong schema: what is stored stays
|
|
299
|
+
* served.
|
|
300
|
+
*/
|
|
301
|
+
read(node: ExtensionNode): X | undefined;
|
|
302
|
+
/**
|
|
303
|
+
* The value read back from the store, or from a read about to be stored
|
|
304
|
+
* (JSON), or undefined when the Site can't serve it. A stored row whose
|
|
305
|
+
* extension doesn't parse is unusable, as any body that doesn't; one stored
|
|
306
|
+
* without an extension (before the Site declared it) still serves, without.
|
|
307
|
+
* Return a valid value as it is: reconciliation compares it with new reads.
|
|
308
|
+
*/
|
|
309
|
+
parse(stored: unknown): X | undefined;
|
|
310
|
+
}
|
|
311
|
+
/** A front page, page or post as WordPress returned it, for a Site's extension. */
|
|
312
|
+
interface ExtensionNode {
|
|
313
|
+
kind: "page" | "post";
|
|
314
|
+
fields: Readonly<Record<string, unknown>>;
|
|
261
315
|
}
|
|
262
316
|
interface ContentConsentConfig {
|
|
263
317
|
/** The catalog services the Site declares in code (e.g. "youtube", "google_maps"). */
|
|
@@ -274,22 +328,34 @@ interface ContentConsentConfig {
|
|
|
274
328
|
*/
|
|
275
329
|
cmsSettings?: boolean;
|
|
276
330
|
}
|
|
277
|
-
declare function createContentRuntime(input: ContentConfig): {
|
|
331
|
+
declare function createContentRuntime<X = never>(input: ContentConfig<X>): {
|
|
278
332
|
languages: SiteLanguage[];
|
|
279
333
|
defaultLanguage: SiteLanguage;
|
|
280
334
|
multilingual: boolean;
|
|
281
335
|
routeLanguage: (route: string) => SiteLanguage;
|
|
282
336
|
isLanguageHome: (route: string) => boolean;
|
|
283
|
-
wordpress: WordPressClient
|
|
337
|
+
wordpress: WordPressClient<X>;
|
|
284
338
|
handleEvent: (request: Request, context?: {
|
|
285
339
|
siteOrigin?: string;
|
|
286
340
|
}) => Promise<Response>;
|
|
287
341
|
handleRefresh: (request: Request, context?: {
|
|
288
342
|
siteOrigin?: string;
|
|
289
343
|
}) => Promise<Response>;
|
|
290
|
-
publishedHome: (siteOrigin?: string, language?: SiteLanguage) => Promise<HomeDelivery
|
|
291
|
-
publishedEntry: (path: string, siteOrigin?: string) => Promise<EntryDelivery
|
|
344
|
+
publishedHome: (siteOrigin?: string, language?: SiteLanguage) => Promise<HomeDelivery<X>>;
|
|
345
|
+
publishedEntry: (path: string, siteOrigin?: string) => Promise<EntryDelivery<X>>;
|
|
292
346
|
pageChrome: (siteOrigin?: string) => Promise<SiteChrome | null>;
|
|
347
|
+
/**
|
|
348
|
+
* The design presets every page shares (GQ Design's spacing sizes and
|
|
349
|
+
* colors), for a page that isn't a publication: the stored ones when there
|
|
350
|
+
* is a store, else (in explicit development) a live read. Null when
|
|
351
|
+
* neither has them.
|
|
352
|
+
*/
|
|
353
|
+
designPresets: () => Promise<DesignPresets | null>;
|
|
354
|
+
/**
|
|
355
|
+
* The origins a link into this Site may use: WordPress's, and the
|
|
356
|
+
* Frontend's when given. `menuItemHref` turns links at them into paths.
|
|
357
|
+
*/
|
|
358
|
+
internalOrigins: (siteOrigin?: string) => string[];
|
|
293
359
|
/**
|
|
294
360
|
* The Site's consent configuration for a page served with this chrome:
|
|
295
361
|
* declared services, GA4 when gq-config's toggle is on, and the
|
|
@@ -297,12 +363,12 @@ declare function createContentRuntime(input: ContentConfig): {
|
|
|
297
363
|
*/
|
|
298
364
|
consentConfiguration: (chrome?: SiteChrome | null) => ConsentConfiguration | null;
|
|
299
365
|
};
|
|
300
|
-
type ContentRuntime = ReturnType<typeof createContentRuntime
|
|
366
|
+
type ContentRuntime<X = never> = ReturnType<typeof createContentRuntime<X>>;
|
|
301
367
|
//#endregion
|
|
302
368
|
//#region frontend/src/wordpress.d.ts
|
|
303
|
-
interface WordPressClient {
|
|
304
|
-
getHomeContent(this: void, language?: SiteLanguage): Promise<Delivery<HomeContent
|
|
305
|
-
getEntryByUri(this: void, uri: string): Promise<Delivery<EntryContent
|
|
369
|
+
interface WordPressClient<X = unknown> {
|
|
370
|
+
getHomeContent(this: void, language?: SiteLanguage): Promise<Delivery<HomeContent<X>>>;
|
|
371
|
+
getEntryByUri(this: void, uri: string): Promise<Delivery<EntryContent<X>>>;
|
|
306
372
|
getDesignPresets(this: void): Promise<Found<DesignPresets> | Unavailable>;
|
|
307
373
|
getPublishedEntries(this: void): Promise<Found<{
|
|
308
374
|
entries: PublishedEntry[];
|
|
@@ -315,4 +381,4 @@ interface WordPressClient {
|
|
|
315
381
|
}): Promise<Found<SiteChrome> | Unavailable>;
|
|
316
382
|
}
|
|
317
383
|
//#endregion
|
|
318
|
-
export {
|
|
384
|
+
export { PublishedEntry as A, htmlLang as B, Delivery as C, Found as D, Extended as E, WordPressMenuItem as F, languageSubject as H, WordPressPost as I, WordPressSettings as L, Translation as M, Unavailable as N, HomeContent as O, WordPressImage as P, SiteLanguage as R, CmsFailureReason as S, EntryContent as T, routeLanguage as U, isLanguageHome as V, siteLanguages as W, NotServed as _, ContentRuntime as a, SqlStatement as b, Alternate as c, EntryPage as d, EntryPublication as f, Moved as g, HomePublication as h, ContentExtension as i, SiteChrome as j, Missing as k, DeliveryFailureReason as l, HomePage as m, ContentConfig as n, ExtensionNode as o, HomeDelivery as p, ContentConsentConfig as r, createContentRuntime as s, WordPressClient as t, EntryDelivery as u, ContentBindings as v, DesignPresets as w, CmsFailure as x, SqlDatabase as y, WordPressLanguages as z };
|