@getquick/content 0.2.0 → 0.3.1

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.
@@ -1,53 +1,7 @@
1
1
  import { r as ConsentConfiguration, t as AnalyticsSettings } from "./configuration-C_JGygQI.js";
2
2
  import { r as LegalLanguage } from "./legal-C5Xiq59W.js";
3
- //#endregion
4
- //#region frontend/src/site-language.d.ts
5
- /**
6
- * The `<html lang>` for a WordPress locale: its language and region as a
7
- * BCP 47 tag (pt_PT_ao90 → pt-PT). WordPress's variants (ao90, formal) aren't
8
- * BCP 47 subtags, so they are left out; no locale means English.
9
- */
10
- declare function htmlLang(locale: string | undefined): string;
11
- /** A language the site serves. */
12
- interface SiteLanguage {
13
- /** Its WordPress locale (pt_PT_ao90); empty when configuration names none. */
14
- locale: string;
15
- /** Polylang's slug, its URL directory: the default language's is its language code. */
16
- slug: string;
17
- /** Its GraphQL LanguageCodeEnum value: the slug in upper case (pt-br → PT_BR). */
18
- code: string;
19
- /** Its `<html lang>`. */
20
- lang: string;
21
- isDefault: boolean;
22
- /** Its home route: / for the default language, /<slug>/ for the others. */
23
- home: string;
24
- }
25
- interface WordPressLanguages {
26
- locale?: string;
27
- languages?: readonly {
28
- locale: string;
29
- slug: string;
30
- }[];
31
- }
32
- /**
33
- * configuration's languages: wordpress.locale, the default, served at /, then
34
- * each of wordpress.languages under its slug. A monolingual Site has one.
35
- */
36
- declare function siteLanguages(wordpress: WordPressLanguages | undefined): SiteLanguage[];
37
- /**
38
- * A route's language: the one whose slug is its first segment, else the
39
- * default language, which has no directory.
40
- */
41
- declare function routeLanguage(route: string, among: readonly SiteLanguage[]): SiteLanguage;
42
- /**
43
- * How logs and reports name something a language has: "the front page" for
44
- * the default language's, "the en front page" for another's.
45
- */
46
- declare function languageSubject(language: SiteLanguage, what: string): string;
47
- /** Whether a route is a language's home (/, /en/): served as a home, never as an entry. */
48
- declare function isLanguageHome(route: string, among: readonly SiteLanguage[]): boolean;
49
3
  declare namespace content_types_d_exports {
50
- export { CmsFailure, CmsFailureReason, Delivery, DesignPresets, EntryContent, Extended, Found, HomeContent, Missing, PublishedEntry, SiteChrome, Translation, Unavailable, WordPressImage, WordPressMenuItem, WordPressPost, WordPressSettings };
4
+ export { Archives, CmsFailure, CmsFailureReason, CollectionMembership, CollectionTerm, Delivery, DesignPresets, EntryContent, Extended, Found, HomeContent, Missing, PublishedEntry, SiteChrome, Translation, Unavailable, WordPressImage, WordPressMenuItem, WordPressPost, WordPressSettings };
51
5
  }
52
6
  interface WordPressImage {
53
7
  sourceUrl: string;
@@ -104,6 +58,19 @@ interface HomeContent<X = unknown> extends DesignPresets {
104
58
  /** WordPress failed on the blocks, so this is the page without them. */
105
59
  blocksOmitted: boolean;
106
60
  }
61
+ /** A term of one of a collection's taxonomies, as an item carries it. */
62
+ interface CollectionTerm {
63
+ slug: string;
64
+ name: string;
65
+ }
66
+ /**
67
+ * The collection an entry is an item of (ContentConfig's `collections`): its
68
+ * name, and its terms in each of the collection's taxonomies.
69
+ */
70
+ interface CollectionMembership {
71
+ name: string;
72
+ terms: Record<string, CollectionTerm[]>;
73
+ }
107
74
  /** A published translation of an entry: its URI and its language's slug. */
108
75
  interface Translation {
109
76
  uri: string;
@@ -118,6 +85,8 @@ interface EntryContent<X = unknown> extends WordPressPost, DesignPresets, Extend
118
85
  blocksOmitted: boolean;
119
86
  /** When WordPress last modified it (ms, the CMS's clock), if it said. */
120
87
  modifiedAt: number | null;
88
+ /** The collection it is an item of, when it is one (not a page or post). */
89
+ collection?: CollectionMembership;
121
90
  }
122
91
  /** A published page or post as WordPress lists it: its id, URI and last modification. */
123
92
  interface PublishedEntry {
@@ -127,10 +96,20 @@ interface PublishedEntry {
127
96
  /** When WordPress last modified it (ms, the CMS's clock), if it said. */
128
97
  modifiedAt: number | null;
129
98
  }
99
+ /** Where each collection's archive is (a path), by its post type. */
100
+ type Archives = Record<string, string>;
130
101
  interface SiteChrome {
131
102
  menuItems: WordPressMenuItem[];
132
103
  siteIcon: WordPressImage | null;
133
104
  siteLogo: WordPressImage | null;
105
+ /**
106
+ * The patterns GQ Design's Header & Footer selects for the Site's header and
107
+ * footer (render them with `renderDesignPattern`). Null when the region uses
108
+ * an ordinary template part, or nothing published is selected: the Site
109
+ * keeps its own header or footer then.
110
+ */
111
+ header: DesignPattern | null;
112
+ footer: DesignPattern | null;
134
113
  /**
135
114
  * This language's LEGAL-1 Contract from gq-config, on a Site with consent
136
115
  * CMS settings enabled (null when gq-config has none for it).
@@ -166,6 +145,138 @@ interface Unavailable {
166
145
  }
167
146
  type Delivery<T> = Found<T> | Missing | Unavailable;
168
147
  //#endregion
148
+ //#region frontend/src/design-patterns.d.ts
149
+ /**
150
+ * A block of a GQ Design pattern, as its layout API shapes it (`blocksJson`):
151
+ * its name, its public attributes (including those a Site's serializer adds,
152
+ * such as `getquick/header-navigation`'s `menuItems`), the HTML WordPress saved
153
+ * for it (null for a dynamic block, such as `core/site-logo`), and its inner
154
+ * blocks, with synced patterns already inlined.
155
+ */
156
+ interface DesignBlock {
157
+ name: string;
158
+ attributes: Record<string, unknown>;
159
+ content: string | null;
160
+ children: DesignBlock[];
161
+ }
162
+ /**
163
+ * The published synced pattern GQ Design's Header & Footer selects for a
164
+ * region of the Site chrome (`designPattern`), as its block tree.
165
+ */
166
+ interface DesignPattern {
167
+ title: string;
168
+ blocks: DesignBlock[];
169
+ }
170
+ /**
171
+ * A complete pattern tree from JSON text or a parsed list. Malformed nodes
172
+ * fail the whole read: dropping one could promote a partial header or footer.
173
+ * PHP's empty attributes (`[]`) normalize to an object.
174
+ */
175
+ declare function parseDesignBlocks(value: unknown): DesignBlock[] | undefined;
176
+ declare function escapeHtml(value: string): string;
177
+ /** What a block renderer is given besides its block. */
178
+ interface DesignRenderContext {
179
+ /** The block's children, rendered in order by the same renderers (when read). */
180
+ children: string;
181
+ /** The blocks it is inside, outermost first. */
182
+ ancestors: DesignBlock[];
183
+ /** Renders other blocks (a subset of the children, say) by the same renderers. */
184
+ render(this: void, blocks: DesignBlock[]): string;
185
+ /**
186
+ * A link from CMS data as the Frontend serves it: one into this Site (the
187
+ * CMS or the Site origin) becomes its path, another http(s) link stays
188
+ * absolute, and anything else (`javascript:`, say) becomes "#".
189
+ */
190
+ href(this: void, url: unknown): string;
191
+ /** The home page of the language being served ("/" unless the options say). */
192
+ home: string;
193
+ }
194
+ /**
195
+ * Renders one block as HTML. Its output is not escaped again: escape what the
196
+ * CMS supplied (`escapeHtml`) and pass links through `context.href`.
197
+ */
198
+ type DesignBlockRenderer = (block: DesignBlock, context: DesignRenderContext) => string;
199
+ interface DesignRenderOptions {
200
+ /**
201
+ * The Site's renderers, by block name: its own blocks (such as
202
+ * `getquick/header-navigation`), and any core block it renders itself.
203
+ * They take precedence over the built-in ones.
204
+ */
205
+ blocks?: Record<string, DesignBlockRenderer>;
206
+ /** The origins whose links are this Site's: the CMS's and the Site's. */
207
+ internalOrigins?: string[];
208
+ /**
209
+ * Told about each block without children that has neither a renderer nor
210
+ * saved HTML (a dynamic block): it renders nothing.
211
+ */
212
+ onUnrendered?: (block: DesignBlock) => void;
213
+ /** The home page of the language being served, for home links: "/" by default. */
214
+ home?: string;
215
+ }
216
+ /**
217
+ * A pattern (or blocks of one) as HTML. Each block is rendered by the Site's
218
+ * renderer for its name, else a built-in one, else as the HTML WordPress saved
219
+ * for it, else, with children, as a WordPress container wrapping them. A block
220
+ * with none of those (a dynamic block, such as a Site's own) renders nothing
221
+ * and is reported to `onUnrendered`. Null renders nothing, so the Site keeps
222
+ * its own header or footer.
223
+ */
224
+ declare function renderDesignPattern(pattern: DesignPattern | DesignBlock[] | null | undefined, options?: DesignRenderOptions): string;
225
+ /**
226
+ * A menu a Site block carries in its attributes (a flat list of `{ id,
227
+ * parentId, label, url, target }`, as GQ Design's serializer filter documents
228
+ * for `getquick/header-navigation`) as a tree, with each link as the
229
+ * Frontend serves it. Items that aren't menu items are left out; one whose
230
+ * parent isn't listed, or that is in a cycle of parents, is a top-level item.
231
+ */
232
+ declare function designMenuItems(value: unknown, href?: (url: unknown) => string): WordPressMenuItem[];
233
+ //#endregion
234
+ //#region frontend/src/site-language.d.ts
235
+ /**
236
+ * The `<html lang>` for a WordPress locale: its language and region as a
237
+ * BCP 47 tag (pt_PT_ao90 → pt-PT). WordPress's variants (ao90, formal) aren't
238
+ * BCP 47 subtags, so they are left out; no locale means English.
239
+ */
240
+ declare function htmlLang(locale: string | undefined): string;
241
+ /** A language the site serves. */
242
+ interface SiteLanguage {
243
+ /** Its WordPress locale (pt_PT_ao90); empty when configuration names none. */
244
+ locale: string;
245
+ /** Polylang's slug, its URL directory: the default language's is its language code. */
246
+ slug: string;
247
+ /** Its GraphQL LanguageCodeEnum value: the slug in upper case (pt-br → PT_BR). */
248
+ code: string;
249
+ /** Its `<html lang>`. */
250
+ lang: string;
251
+ isDefault: boolean;
252
+ /** Its home route: / for the default language, /<slug>/ for the others. */
253
+ home: string;
254
+ }
255
+ interface WordPressLanguages {
256
+ locale?: string;
257
+ languages?: readonly {
258
+ locale: string;
259
+ slug: string;
260
+ }[];
261
+ }
262
+ /**
263
+ * configuration's languages: wordpress.locale, the default, served at /, then
264
+ * each of wordpress.languages under its slug. A monolingual Site has one.
265
+ */
266
+ declare function siteLanguages(wordpress: WordPressLanguages | undefined): SiteLanguage[];
267
+ /**
268
+ * A route's language: the one whose slug is its first segment, else the
269
+ * default language, which has no directory.
270
+ */
271
+ declare function routeLanguage(route: string, among: readonly SiteLanguage[]): SiteLanguage;
272
+ /**
273
+ * How logs and reports name something a language has: "the front page" for
274
+ * the default language's, "the en front page" for another's.
275
+ */
276
+ declare function languageSubject(language: SiteLanguage, what: string): string;
277
+ /** Whether a route is a language's home (/, /en/): served as a home, never as an entry. */
278
+ declare function isLanguageHome(route: string, among: readonly SiteLanguage[]): boolean;
279
+ //#endregion
169
280
  //#region frontend/src/bindings.d.ts
170
281
  interface SqlStatement {
171
282
  bind(...values: unknown[]): SqlStatement;
@@ -248,6 +359,61 @@ type HomeDelivery<X = unknown> = Found<HomePage<X>> | (Missing & {
248
359
  type EntryDelivery<X = unknown> = Found<EntryPage<X>> | (Missing & {
249
360
  chrome: SiteChrome | null;
250
361
  }) | Moved | NotServed;
362
+ /** Which of a collection's items to list, from the publication store. */
363
+ interface CollectionQuery {
364
+ /** The collection's name, as ContentConfig's `collections` declares it. */
365
+ collection: string;
366
+ /**
367
+ * Only items with one of these terms (slugs) in each of these taxonomies:
368
+ * any slug of a taxonomy, and every taxonomy given.
369
+ */
370
+ terms?: Record<string, readonly string[]>;
371
+ /** Only items whose title or excerpt contains this text (ignoring case and accents). */
372
+ search?: string;
373
+ /** The page of items, from 1 (the default). */
374
+ page?: number;
375
+ /** Items per page, 1 to 100; 12 by default. */
376
+ perPage?: number;
377
+ /** A multilingual Site's language (its slug); the default language's by default. */
378
+ language?: string;
379
+ }
380
+ /** An item as a collection lists it. */
381
+ interface CollectionItem<X = unknown> {
382
+ uri: string;
383
+ title: string;
384
+ /** When it was published, as WordPress gives it (its date, without a zone). */
385
+ date: string;
386
+ /** When WordPress last modified it (ms, the CMS's clock), if it said. */
387
+ modifiedAt: number | null;
388
+ excerpt: string;
389
+ featuredImage: WordPressImage | null;
390
+ /** Its terms in each of the collection's taxonomies. */
391
+ terms: Record<string, CollectionTerm[]>;
392
+ /** The Site's own content on it (ContentConfig's `extension`), when it has one. */
393
+ extension?: X;
394
+ /** Its language's slug, on a multilingual Site. */
395
+ language?: string;
396
+ }
397
+ /** A page of a collection's items, newest first, and how many there are in all. */
398
+ interface CollectionPage<X = unknown> {
399
+ items: CollectionItem<X>[];
400
+ /** Items matching the query, on every page. */
401
+ total: number;
402
+ page: number;
403
+ /** Pages of items matching the query (0 when none does). */
404
+ pages: number;
405
+ }
406
+ type CollectionListing<X = unknown> = ({
407
+ kind: "found";
408
+ } & CollectionPage<X>) | NotServed;
409
+ /** A term of a collection's taxonomy, and how many of its stored items have it. */
410
+ interface CollectionTermCount extends CollectionTerm {
411
+ count: number;
412
+ }
413
+ type CollectionTermListing = {
414
+ kind: "found";
415
+ terms: CollectionTermCount[];
416
+ } | NotServed;
251
417
  //#endregion
252
418
  //#region frontend/src/server.d.ts
253
419
  interface ContentConfig<X = never> {
@@ -255,6 +421,12 @@ interface ContentConfig<X = never> {
255
421
  graphqlEndpoint: string;
256
422
  cmsOrigin: string;
257
423
  wordpress?: WordPressLanguages;
424
+ /**
425
+ * The GQ Design route (Design → Header & Footer) whose header and footer
426
+ * patterns are the Site chrome's: "page" by default; "front-page", "home",
427
+ * "archive", "single-post" or a route a Site plugin defines.
428
+ */
429
+ designTemplate?: string;
258
430
  /** Live delivery without a publication store is opt-in; false by default. */
259
431
  development?: boolean;
260
432
  isServer: () => boolean;
@@ -272,6 +444,25 @@ interface ContentConfig<X = never> {
272
444
  * the publication and served as its `extension`.
273
445
  */
274
446
  extension?: ContentExtension<X>;
447
+ /**
448
+ * The content types the runtime stores besides pages and posts, by the
449
+ * Site's name for each (`biblioteca`). Their items are stored, refreshed,
450
+ * withdrawn and reconciled as pages and posts are, served by
451
+ * `publishedEntry`, and listed from the store by `list`.
452
+ */
453
+ collections?: Record<string, CollectionConfig>;
454
+ }
455
+ /** A content type (a WordPress custom post type) whose items the runtime stores. */
456
+ interface CollectionConfig {
457
+ /** WordPress's name for the post type (register_post_type's), e.g. `biblioteca`. */
458
+ postType: string;
459
+ /** Its WPGraphQL type (its `graphql_single_name`), e.g. `Biblioteca`. */
460
+ graphqlType: string;
461
+ /**
462
+ * The taxonomies (WordPress's names) whose terms are stored with each item,
463
+ * for filtering and showing them. Each must be shown in WPGraphQL.
464
+ */
465
+ taxonomies?: readonly string[];
275
466
  }
276
467
  /**
277
468
  * A Site's own content on its pages and posts, beyond what the runtime reads:
@@ -285,11 +476,12 @@ interface ContentExtension<X> {
285
476
  * to front pages and pages, `post` to posts (e.g. `wpBlocksJson`). They are
286
477
  * read with the blocks: a read WordPress can only complete without its
287
478
  * blocks leaves them out too, and isn't stored. A kind without fields has
288
- * no extension.
479
+ * no extension. `collections`: each collection's items' fields, by its name.
289
480
  */
290
481
  fields: {
291
482
  page?: string;
292
483
  post?: string;
484
+ collections?: Partial<Record<string, string>>;
293
485
  };
294
486
  /**
295
487
  * The Site's value for a node WordPress returned (its fields, the runtime's
@@ -308,9 +500,11 @@ interface ContentExtension<X> {
308
500
  */
309
501
  parse(stored: unknown): X | undefined;
310
502
  }
311
- /** A front page, page or post as WordPress returned it, for a Site's extension. */
503
+ /** A front page, page, post or collection item as WordPress returned it, for a Site's extension. */
312
504
  interface ExtensionNode {
313
- kind: "page" | "post";
505
+ kind: "page" | "post" | "item";
506
+ /** The collection's name, for an item. */
507
+ collection?: string;
314
508
  fields: Readonly<Record<string, unknown>>;
315
509
  }
316
510
  interface ContentConsentConfig {
@@ -343,7 +537,34 @@ declare function createContentRuntime<X = never>(input: ContentConfig<X>): {
343
537
  }) => Promise<Response>;
344
538
  publishedHome: (siteOrigin?: string, language?: SiteLanguage) => Promise<HomeDelivery<X>>;
345
539
  publishedEntry: (path: string, siteOrigin?: string) => Promise<EntryDelivery<X>>;
540
+ /**
541
+ * A page of a collection's items, from the publication store alone (never
542
+ * WordPress), newest first: those with the given terms and text, in the
543
+ * language. Unavailable when the store can't be read, or there is none.
544
+ */
545
+ list: (query: CollectionQuery) => Promise<CollectionListing<X>>;
546
+ /**
547
+ * The terms of a collection's taxonomy that its stored items have, with how
548
+ * many of them have each, by name: for filters.
549
+ */
550
+ terms: (name: string, taxonomy: string, options?: {
551
+ language?: string;
552
+ }) => Promise<CollectionTermListing>;
553
+ /**
554
+ * Where a collection's archive is: the Page assigned to it in GETQUICK →
555
+ * Archives, else its post type's own archive. Null when it has neither, or
556
+ * the store can't be read.
557
+ */
558
+ archiveUri: (collection: string) => Promise<string | null>;
346
559
  pageChrome: (siteOrigin?: string) => Promise<SiteChrome | null>;
560
+ /**
561
+ * A chrome pattern as HTML, by the Site's block renderers (see
562
+ * `renderDesignPattern`), with links into the CMS or `siteOrigin` served
563
+ * as this Site's paths.
564
+ */
565
+ renderDesignPattern: (pattern: DesignPattern | DesignBlock[] | null | undefined, options?: DesignRenderOptions & {
566
+ siteOrigin?: string;
567
+ }) => string;
347
568
  /**
348
569
  * The design presets every page shares (GQ Design's spacing sizes and
349
570
  * colors), for a page that isn't a publication: the stored ones when there
@@ -375,10 +596,11 @@ interface WordPressClient<X = unknown> {
375
596
  requests: number;
376
597
  }> | Unavailable>;
377
598
  getPublishedRoutes(this: void): Promise<Found<string[]> | Unavailable>;
599
+ getArchives(this: void): Promise<Found<Archives> | Unavailable>;
378
600
  getSiteChrome(this: void, siteOrigin?: string, options?: {
379
601
  location?: string;
380
602
  language?: SiteLanguage;
381
603
  }): Promise<Found<SiteChrome> | Unavailable>;
382
604
  }
383
605
  //#endregion
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 };
606
+ export { Found as $, htmlLang as A, designMenuItems as B, Moved as C, SqlStatement as D, SqlDatabase as E, DesignBlock as F, CmsFailure as G, parseDesignBlocks as H, DesignBlockRenderer as I, CollectionTerm as J, CmsFailureReason as K, DesignPattern as L, languageSubject as M, routeLanguage as N, SiteLanguage as O, siteLanguages as P, Extended as Q, DesignRenderContext as R, HomePublication as S, ContentBindings as T, renderDesignPattern as U, escapeHtml as V, Archives as W, DesignPresets as X, Delivery as Y, EntryContent as Z, EntryDelivery as _, ContentExtension as a, Unavailable as at, HomeDelivery as b, createContentRuntime as c, WordPressPost as ct, CollectionListing as d, HomeContent as et, CollectionPage as f, DeliveryFailureReason as g, CollectionTermListing as h, ContentConsentConfig as i, Translation as it, isLanguageHome as j, WordPressLanguages as k, Alternate as l, WordPressSettings as lt, CollectionTermCount as m, CollectionConfig as n, PublishedEntry as nt, ContentRuntime as o, WordPressImage as ot, CollectionQuery as p, CollectionMembership as q, ContentConfig as r, SiteChrome as rt, ExtensionNode as s, WordPressMenuItem as st, WordPressClient as t, Missing as tt, CollectionItem as u, EntryPage as v, NotServed as w, HomePage as x, EntryPublication as y, DesignRenderOptions as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getquick/content",
3
- "version": "0.2.0",
3
+ "version": "0.3.1",
4
4
  "license": "UNLICENSED",
5
5
  "files": [
6
6
  "dist",
@@ -45,6 +45,18 @@
45
45
  "./consent/testing": {
46
46
  "types": "./dist/consent-testing.d.ts",
47
47
  "import": "./dist/consent-testing.js"
48
+ },
49
+ "./metadata": {
50
+ "types": "./dist/metadata.d.ts",
51
+ "import": "./dist/metadata.js"
52
+ },
53
+ "./metadata/testing": {
54
+ "types": "./dist/metadata-testing.d.ts",
55
+ "import": "./dist/metadata-testing.js"
56
+ },
57
+ "./metadata/content": {
58
+ "types": "./dist/metadata-content.d.ts",
59
+ "import": "./dist/metadata-content.js"
48
60
  }
49
61
  },
50
62
  "publishConfig": {