@getquick/content 0.1.0 → 0.3.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 +155 -6
- package/dist/consent-astro.js +1 -1
- package/dist/consent.js +1 -1
- package/dist/dist-D4-CMkrf.js +7047 -0
- package/dist/index.d.ts +20 -4
- package/dist/index.js +24 -5
- package/dist/metadata-content.d.ts +36 -0
- package/dist/metadata-content.js +51 -0
- package/dist/metadata-testing.d.ts +34 -0
- package/dist/metadata-testing.js +142 -0
- package/dist/metadata.d.ts +94 -0
- package/dist/metadata.js +218 -0
- package/dist/server.d.ts +2 -2
- package/dist/server.js +943 -58
- package/dist/{formatting-wOk2jz6J.js → site-language-cBP8SFrS.js} +302 -50
- package/dist/{version-Dn6VLZJO.js → version-D_Ao31D3.js} +1 -1
- package/dist/wordpress-D_HG2rEt.d.ts +606 -0
- package/package.json +13 -1
- package/dist/wordpress-CPL40-vq.d.ts +0 -318
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`, `CollectionConfig`, `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.
|
|
@@ -50,7 +50,9 @@ The reusable client methods retain their argument order:
|
|
|
50
50
|
- `getDesignPresets()`
|
|
51
51
|
- `getPublishedEntries()`
|
|
52
52
|
- `getPublishedRoutes()`
|
|
53
|
-
- `
|
|
53
|
+
- `getArchives()`
|
|
54
|
+
- `getSiteChrome(siteOrigin?, { location?, language? }?)` (menu, logo, icon,
|
|
55
|
+
header and footer patterns)
|
|
54
56
|
|
|
55
57
|
From the repository root, use `vp install` and `vp run validate`. Validation
|
|
56
58
|
builds compiled ESM/declarations through Vite+ Pack, checks formatting/lint/types,
|
|
@@ -62,7 +64,8 @@ untracked. The npm tarball allowlist contains only compiled output, the five ori
|
|
|
62
64
|
separate consent database migrations and package metadata (npm also includes this README).
|
|
63
65
|
|
|
64
66
|
The public delivery methods are `publishedHome(siteOrigin?, language?)`,
|
|
65
|
-
`publishedEntry(path, siteOrigin?)
|
|
67
|
+
`publishedEntry(path, siteOrigin?)`, `pageChrome(siteOrigin?)` and
|
|
68
|
+
`designPresets()`. Supply a
|
|
66
69
|
`PUBLICATION_DB` structural binding to serve durable publications. Stored reads
|
|
67
70
|
need no event or refresh secret and retain last-known-good content without an
|
|
68
71
|
age limit. Cold entry lookups read the CMS once, preserving missing versus
|
|
@@ -72,6 +75,152 @@ Production without a store returns unavailable (chrome returns null). Only
|
|
|
72
75
|
activates that fallback. All public reads guard server context before bindings
|
|
73
76
|
or transport.
|
|
74
77
|
|
|
78
|
+
`designPresets()` returns the stored design presets for a page that isn't a
|
|
79
|
+
publication (live only in explicit development, null otherwise), and
|
|
80
|
+
`internalOrigins(siteOrigin?)` the origins `menuItemHref` treats as this Site's.
|
|
81
|
+
`blockPresetStyles(spacing, colors, scope?)` scopes the preset classes to a
|
|
82
|
+
container (`.prose-wp` by default); `presetRootStyle(spacing, colors)` declares
|
|
83
|
+
the presets on `:root`.
|
|
84
|
+
|
|
85
|
+
## A Site's own content
|
|
86
|
+
|
|
87
|
+
A Site whose WordPress plugin adds fields to its pages and posts declares them
|
|
88
|
+
as an `extension`. The runtime reads them with each front page, page and post
|
|
89
|
+
(with its blocks), stores the Site's value with the publication and serves it,
|
|
90
|
+
typed, through outages:
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const content = createContentRuntime<SiteBlocks>({
|
|
94
|
+
// …the configuration above…
|
|
95
|
+
extension: {
|
|
96
|
+
fields: { page: "wpBlocksJson pageBackgroundColor", post: "wpBlocksJson" },
|
|
97
|
+
// The Site's value for a node WordPress returned, or undefined for none.
|
|
98
|
+
read: ({ kind, fields }) => siteBlocks(fields.wpBlocksJson, fields.pageBackgroundColor),
|
|
99
|
+
// The stored value (JSON) read back, or undefined when it can't be served.
|
|
100
|
+
parse: (stored) => storedSiteBlocks.safeParse(stored).data,
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
const page = await content.publishedEntry("/about/");
|
|
104
|
+
if (page.kind === "found" && page.content.entry.extension) {
|
|
105
|
+
// Render page.content.entry.extension (SiteBlocks); the front page's is
|
|
106
|
+
// home.page.extension.
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Rows stored before the Site declared it serve without it; a refresh stores it.
|
|
111
|
+
A read throwing fails as WordPress's answer not matching the schema, and a read
|
|
112
|
+
without its blocks stores nothing, so the stored page stays served. See ADR 0004.
|
|
113
|
+
|
|
114
|
+
## Header and footer patterns
|
|
115
|
+
|
|
116
|
+
The chrome also carries `header` and `footer`: the synced patterns GQ Design's
|
|
117
|
+
Header & Footer selects for the design route `designTemplate` (default
|
|
118
|
+
`"page"`; also `"front-page"`, `"home"`, `"archive"`, `"single-post"` or a
|
|
119
|
+
Site-defined route). Each is `{ title, blocks }`, or null when the region uses
|
|
120
|
+
a template part or nothing published is selected: keep the Site's own header
|
|
121
|
+
or footer then. They are stored, refreshed and reconciled with the chrome, so
|
|
122
|
+
visitors keep the last-known-good regions through CMS outages. A selected
|
|
123
|
+
pattern GQ Design resolves to no blocks fails the chrome read and keeps what
|
|
124
|
+
is stored. A `patterns` settings event refreshes the chrome. See
|
|
125
|
+
[ADR 0006](../docs/adr/0006-serve-cms-selected-header-and-footer-patterns-with-site-chrome.md).
|
|
126
|
+
|
|
127
|
+
The configured route is shared globally, including the homepage and posts;
|
|
128
|
+
Content does not choose a different Design route for each visitor URL. Use a
|
|
129
|
+
key registered in Design's manifest: an unknown key also returns null, and
|
|
130
|
+
Content never retries another key.
|
|
131
|
+
|
|
132
|
+
**Required GQ Design: 0.4.1 or newer** for the default `page` (`single` and
|
|
133
|
+
`search` need 0.4.2). GQ Design 0.2.17 to 0.4.0 answer null for `page`, so the
|
|
134
|
+
Site keeps its own regions. A GQ Design without `designPattern` at all (before
|
|
135
|
+
0.2.17) doesn't fail the chrome: it is read without patterns, both null, and a
|
|
136
|
+
warning names GQ Design and the version it needs (`WordPress: GQ Design has no
|
|
137
|
+
designPattern field …`). Public selection excludes unpublished
|
|
138
|
+
route/part sources and unpublished, protected or unsynced final patterns.
|
|
139
|
+
Authoritative null removes a previous selection on a successful refresh;
|
|
140
|
+
failed or malformed reads retain it.
|
|
141
|
+
|
|
142
|
+
The ordinary menu and publication-store row remain language-specific, but
|
|
143
|
+
`designPattern` takes no language. Every language receives the same unqualified
|
|
144
|
+
pattern selection and its serialized data. Translated pattern trees are blocked
|
|
145
|
+
by [gq-design #53](https://github.com/Quick-Release/gq-design/issues/53).
|
|
146
|
+
|
|
147
|
+
Render a pattern with the Site's block renderers. Blocks with saved HTML
|
|
148
|
+
render it with their children inside; `core/site-logo` has a built-in
|
|
149
|
+
renderer; any other block without HTML (a dynamic or Site block) needs a
|
|
150
|
+
renderer. Containers receive a basic WordPress wrapper, and GQ Design's
|
|
151
|
+
`getquick-design/container` its layout (width, gap, padding) as content's
|
|
152
|
+
containers do; unresolved dynamic leaves render nothing and are reported to
|
|
153
|
+
`onUnrendered`:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { designMenuItems, escapeHtml, type DesignBlockRenderer } from "@getquick/content";
|
|
157
|
+
|
|
158
|
+
const headerNavigation: DesignBlockRenderer = (block, { href }) =>
|
|
159
|
+
`<nav aria-label="Primary"><ul>${designMenuItems(block.attributes.menuItems, href)
|
|
160
|
+
.map((item) => `<li><a href="${escapeHtml(item.href)}">${escapeHtml(item.label)}</a></li>`)
|
|
161
|
+
.join("")}</ul></nav>`;
|
|
162
|
+
|
|
163
|
+
const header = content.renderDesignPattern(chrome?.header, {
|
|
164
|
+
siteOrigin: Astro.site?.origin,
|
|
165
|
+
home: language.home,
|
|
166
|
+
blocks: { "getquick/header-navigation": headerNavigation },
|
|
167
|
+
onUnrendered: (block) => console.warn(`No renderer for ${block.name}`),
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
A renderer receives the block (`name`, `attributes`, `content`, `children`)
|
|
172
|
+
and a context: `children` (rendered on demand), `render(blocks)`,
|
|
173
|
+
`ancestors`, `home` and `href(url)`, which serves CMS and Site links as paths
|
|
174
|
+
and replaces unsafe schemes with `#`. Its output is inserted as HTML: escape
|
|
175
|
+
CMS text with `escapeHtml`. Saved HTML is trusted published CMS markup,
|
|
176
|
+
not sanitized by this helper; full custom spacing/layout styling needs a Site
|
|
177
|
+
renderer. With `consent` configured, the saved HTML in served patterns has its
|
|
178
|
+
embeds rewritten into consent placeholders, as bodies do; a renderer building
|
|
179
|
+
an embed from attributes uses `embedPlaceholder` (`@getquick/content/consent`)
|
|
180
|
+
itself. The pure `renderDesignPattern` from the root entry
|
|
181
|
+
takes `internalOrigins` instead of `siteOrigin`.
|
|
182
|
+
|
|
183
|
+
## Collections and archive Pages
|
|
184
|
+
|
|
185
|
+
A Site stores its custom post types' items as collections, and lists them from
|
|
186
|
+
the publication store alone (never WordPress), for an archive Page's listing
|
|
187
|
+
block:
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const content = createContentRuntime({
|
|
191
|
+
// …the configuration above…
|
|
192
|
+
collections: {
|
|
193
|
+
biblioteca: {
|
|
194
|
+
postType: "biblioteca", // WordPress's name
|
|
195
|
+
graphqlType: "Biblioteca", // its graphql_single_name
|
|
196
|
+
taxonomies: ["categoria_biblioteca"], // each show_in_graphql
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
const page = await content.list({
|
|
201
|
+
collection: "biblioteca",
|
|
202
|
+
terms: { categoria_biblioteca: ["legislacao"] }, // any slug; every taxonomy given slugs
|
|
203
|
+
search: "lei", // title and excerpt, ignoring case and accents
|
|
204
|
+
page: 1, // a number (or numeric string); anything else throws
|
|
205
|
+
perPage: 12,
|
|
206
|
+
});
|
|
207
|
+
// { kind: "found", items: [{ uri, title, date, modifiedAt, excerpt,
|
|
208
|
+
// featuredImage, terms, extension?, language? }], total, page, pages }
|
|
209
|
+
// or { kind: "unavailable", failure }
|
|
210
|
+
const filters = await content.terms("biblioteca", "categoria_biblioteca");
|
|
211
|
+
// { kind: "found", terms: [{ slug, name, count }] }
|
|
212
|
+
const archive = await content.archiveUri("biblioteca"); // "/biblioteca/" or null
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
Items are entries: events, withdrawals and reconciliation keep them, and
|
|
216
|
+
`publishedEntry` serves them with `entry.collection` (`name`, `terms`). The
|
|
217
|
+
extension's `fields.collections[<name>]` selects an item's own fields (`read`
|
|
218
|
+
gets `kind: "item"` and `collection`). In WordPress, GETQUICK → Archives
|
|
219
|
+
assigns each type a Page, which takes over the type's archive address; saving
|
|
220
|
+
it reads every archive address again. A type or taxonomy WPGraphQL doesn't
|
|
221
|
+
show, a `graphqlType` that isn't the type's, or a taxonomy not connected to
|
|
222
|
+
it fails the archives read, by name. See ADR 0005.
|
|
223
|
+
|
|
75
224
|
Infrastructure imports the Node-only migration entry separately:
|
|
76
225
|
|
|
77
226
|
```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-D_Ao31D3.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-D_Ao31D3.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 };
|