@weatherboard/cms 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 ADDED
@@ -0,0 +1,71 @@
1
+ # @weatherboard/cms
2
+
3
+ Published content contracts and server readers. The pure root and
4
+ `@weatherboard/cms/site-content` expose `siteHeroQuery`, `parseSiteHero` and the
5
+ hero types without a provider SDK or environment access. Server reads use
6
+ `@weatherboard/cms/server` or `/next`, with the `/sanity` adapter; `/webhook`
7
+ provides portable signature verification. `/testing` and `/guard` are tooling.
8
+
9
+ ## Site hero
10
+
11
+ The singleton `siteHero` keeps its existing heading (1–80 characters, single
12
+ line, no trailing full stop) and intro (1–320 characters). Both trim whitespace,
13
+ count Unicode code points and refuse an em dash.
14
+
15
+ The additive fields in 0.2.0 are:
16
+
17
+ - `layout`: `"columns"` (Side by side) or `"rows"` (Stacked), exported as
18
+ `SITE_HERO_LAYOUTS`. Missing or unknown CMS values resolve to `"columns"`,
19
+ including when the local fallback selects rows.
20
+ - `taglines`: `{ key: string, text: string }[]`. Keys are site-defined lowercase
21
+ identifiers, 1–32 characters, starting with a letter; remaining characters
22
+ may be letters, digits, short dashes or underscores. Duplicate keys refuse
23
+ the whole field. Text uses the heading copy rules and is limited to
24
+ `SITE_HERO_TAGLINE_MAX_LENGTH` (provisionally 36 Unicode code points).
25
+ An empty array deliberately clears taglines; the site can continue using
26
+ heading. A missing or invalid array uses the reviewed local array, or `[]`
27
+ for a legacy fallback.
28
+
29
+ `SiteHero` accepts existing heading/intro-only fallbacks. `parseSiteHero` returns
30
+ normalized `ParsedSiteHero` data with both new fields present. Invalid CMS fields
31
+ fall back individually, preserving valid siblings. Invalid local fallbacks throw
32
+ before network I/O. A missing whole document uses the normalized local hero.
33
+
34
+ A defaulted CMS layout records `SITE_HERO_LAYOUT_WARNING`, whose value is
35
+ `siteHero.layout.defaulted`, in the resolution/read result's `warnings`, with
36
+ `layout` in `fallbackFields`. The server reader includes it in its existing safe
37
+ `cms.partial-fallback` diagnostic (or `cms.fallback` for a whole fallback).
38
+ Supply `onDiagnostic` to log diagnostics; without it the reader logs safe JSON
39
+ through `console.warn`. Diagnostics contain paths and warning names, never copy.
40
+
41
+ ```ts
42
+ import { parseSiteHero } from '@weatherboard/cms/site-content';
43
+
44
+ const fallback = { heading: 'Fresh air at home', intro: 'Comfort through the year' };
45
+ const resolved = parseSiteHero({
46
+ heading: 'Fresh air at home',
47
+ intro: 'Comfort through the year',
48
+ layout: 'rows',
49
+ taglines: [{ key: 'spring', text: 'Welcome the fresh air' }],
50
+ }, fallback);
51
+ ```
52
+
53
+ ## Schema and release delivery
54
+
55
+ `@weatherboard/sanity-schema-base` derives the hero schema from these rules:
56
+ Layout is a radio with initial value columns; taglines use the same validator
57
+ for item fields and duplicate keys. Schema validation is advisory; Content Lake
58
+ API writes still need boundary validation.
59
+
60
+ The schema source and its committed TypeGen outputs are local artifacts. Updating
61
+ this package does not mutate or deploy a dataset schema. Existing operator/admin
62
+ schema consumers must take the updated shared schema and rebuild their schema
63
+ bundle; generated client schemas require their existing reviewed upgrade path.
64
+ The dashboard's later editor slice must add the picker/tagline controls and use
65
+ these validators before publishing. New field values require a separately
66
+ authorized content write; existing documents remain readable with defaults.
67
+
68
+ 0.2.0 is an additive minor under the pilot semver policy. CI publishes CMS after
69
+ merge through the registered release workflow; clients then need an exact package
70
+ bump and deploy. The CI publish and trusted-publisher proof are release evidence
71
+ that this source change alone cannot supply.
@@ -7,6 +7,7 @@ export type CmsDependencies = {
7
7
  export type CmsResolution<T> = {
8
8
  readonly data: T;
9
9
  readonly fallbackFields: readonly string[];
10
+ readonly warnings?: readonly "siteHero.layout.defaulted"[];
10
11
  };
11
12
  export type CmsQuery<T> = {
12
13
  readonly name: string;
@@ -7,6 +7,7 @@ export type CmsDependencies = {
7
7
  export type CmsResolution<T> = {
8
8
  readonly data: T;
9
9
  readonly fallbackFields: readonly string[];
10
+ readonly warnings?: readonly "siteHero.layout.defaulted"[];
10
11
  };
11
12
  export type CmsQuery<T> = {
12
13
  readonly name: string;
@@ -7,6 +7,7 @@ export type CmsDependencies = {
7
7
  export type CmsResolution<T> = {
8
8
  readonly data: T;
9
9
  readonly fallbackFields: readonly string[];
10
+ readonly warnings?: readonly "siteHero.layout.defaulted"[];
10
11
  };
11
12
  export type CmsQuery<T> = {
12
13
  readonly name: string;
@@ -1,7 +1,22 @@
1
- import { type CmsQuery } from "./query.cjs";
1
+ import { type CmsQuery, type CmsResolution } from "./query.cjs";
2
+ export declare const SITE_HERO_LAYOUTS: readonly ["columns", "rows"];
3
+ export declare const SITE_HERO_TAGLINE_MAX_LENGTH = 36;
4
+ export declare const SITE_HERO_LAYOUT_WARNING: "siteHero.layout.defaulted";
5
+ export type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];
6
+ export type SiteHeroTagline = {
7
+ readonly key: string;
8
+ readonly text: string;
9
+ };
10
+ /** Optional additions preserve existing heading/intro-only consumer fallbacks. */
2
11
  export type SiteHero = {
3
12
  readonly heading: string;
4
13
  readonly intro: string;
14
+ readonly layout?: SiteHeroLayout;
15
+ readonly taglines?: readonly SiteHeroTagline[];
16
+ };
17
+ export type ParsedSiteHero = SiteHero & {
18
+ readonly layout: SiteHeroLayout;
19
+ readonly taglines: readonly SiteHeroTagline[];
5
20
  };
6
21
  export type TextFieldDefinition = {
7
22
  readonly name: string;
@@ -37,4 +52,14 @@ export type TextValidation = {
37
52
  export declare const CMS_CONTRACT_VERSION = 1;
38
53
  export declare const SITE_HERO: TextDocumentDefinition;
39
54
  export declare function validateTextDocument(definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>): TextValidation;
55
+ /** Shared with the schema adapter; no provider metadata is returned. */
56
+ export declare function validateSiteHeroTaglines(raw: unknown): {
57
+ readonly ok: true;
58
+ readonly value: readonly SiteHeroTagline[];
59
+ } | {
60
+ readonly ok: false;
61
+ readonly error: string;
62
+ };
63
+ /** Strict per-field resolution: an invalid list never partially changes keyed copy. */
64
+ export declare function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero>;
40
65
  export declare function siteHeroQuery(): CmsQuery<SiteHero>;
@@ -1,7 +1,22 @@
1
- import { type CmsQuery } from "./query.mjs";
1
+ import { type CmsQuery, type CmsResolution } from "./query.mjs";
2
+ export declare const SITE_HERO_LAYOUTS: readonly ["columns", "rows"];
3
+ export declare const SITE_HERO_TAGLINE_MAX_LENGTH = 36;
4
+ export declare const SITE_HERO_LAYOUT_WARNING: "siteHero.layout.defaulted";
5
+ export type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];
6
+ export type SiteHeroTagline = {
7
+ readonly key: string;
8
+ readonly text: string;
9
+ };
10
+ /** Optional additions preserve existing heading/intro-only consumer fallbacks. */
2
11
  export type SiteHero = {
3
12
  readonly heading: string;
4
13
  readonly intro: string;
14
+ readonly layout?: SiteHeroLayout;
15
+ readonly taglines?: readonly SiteHeroTagline[];
16
+ };
17
+ export type ParsedSiteHero = SiteHero & {
18
+ readonly layout: SiteHeroLayout;
19
+ readonly taglines: readonly SiteHeroTagline[];
5
20
  };
6
21
  export type TextFieldDefinition = {
7
22
  readonly name: string;
@@ -37,4 +52,14 @@ export type TextValidation = {
37
52
  export declare const CMS_CONTRACT_VERSION = 1;
38
53
  export declare const SITE_HERO: TextDocumentDefinition;
39
54
  export declare function validateTextDocument(definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>): TextValidation;
55
+ /** Shared with the schema adapter; no provider metadata is returned. */
56
+ export declare function validateSiteHeroTaglines(raw: unknown): {
57
+ readonly ok: true;
58
+ readonly value: readonly SiteHeroTagline[];
59
+ } | {
60
+ readonly ok: false;
61
+ readonly error: string;
62
+ };
63
+ /** Strict per-field resolution: an invalid list never partially changes keyed copy. */
64
+ export declare function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero>;
40
65
  export declare function siteHeroQuery(): CmsQuery<SiteHero>;
@@ -1,7 +1,22 @@
1
- import { type CmsQuery } from "./query.js";
1
+ import { type CmsQuery, type CmsResolution } from "./query.js";
2
+ export declare const SITE_HERO_LAYOUTS: readonly ["columns", "rows"];
3
+ export declare const SITE_HERO_TAGLINE_MAX_LENGTH = 36;
4
+ export declare const SITE_HERO_LAYOUT_WARNING: "siteHero.layout.defaulted";
5
+ export type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];
6
+ export type SiteHeroTagline = {
7
+ readonly key: string;
8
+ readonly text: string;
9
+ };
10
+ /** Optional additions preserve existing heading/intro-only consumer fallbacks. */
2
11
  export type SiteHero = {
3
12
  readonly heading: string;
4
13
  readonly intro: string;
14
+ readonly layout?: SiteHeroLayout;
15
+ readonly taglines?: readonly SiteHeroTagline[];
16
+ };
17
+ export type ParsedSiteHero = SiteHero & {
18
+ readonly layout: SiteHeroLayout;
19
+ readonly taglines: readonly SiteHeroTagline[];
5
20
  };
6
21
  export type TextFieldDefinition = {
7
22
  readonly name: string;
@@ -37,4 +52,14 @@ export type TextValidation = {
37
52
  export declare const CMS_CONTRACT_VERSION = 1;
38
53
  export declare const SITE_HERO: TextDocumentDefinition;
39
54
  export declare function validateTextDocument(definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>): TextValidation;
55
+ /** Shared with the schema adapter; no provider metadata is returned. */
56
+ export declare function validateSiteHeroTaglines(raw: unknown): {
57
+ readonly ok: true;
58
+ readonly value: readonly SiteHeroTagline[];
59
+ } | {
60
+ readonly ok: false;
61
+ readonly error: string;
62
+ };
63
+ /** Strict per-field resolution: an invalid list never partially changes keyed copy. */
64
+ export declare function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero>;
40
65
  export declare function siteHeroQuery(): CmsQuery<SiteHero>;
package/dist/index.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var y=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var h=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var T=(e,n)=>{for(var o in n)y(e,o,{get:n[o],enumerable:!0})},w=(e,n,o,t)=>{if(n&&typeof n=="object"||typeof n=="function")for(let r of h(n))!b.call(e,r)&&r!==o&&y(e,r,{get:()=>n[r],enumerable:!(t=g(n,r))||t.enumerable});return e};var C=e=>w(y({},"__esModule",{value:!0}),e);var v={};T(v,{CMS_CONTRACT_VERSION:()=>p,SITE_HERO:()=>a,cmsTags:()=>m,defineCmsQuery:()=>d,siteHeroQuery:()=>f,validateTextDocument:()=>u});module.exports=C(v);var O=/^[A-Za-z][A-Za-z0-9_]{0,63}$/,x=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,S=/^[a-z0-9]{6,12}\.[a-z][a-z0-9_-]{0,63}$/;function c(e){if(!e||!Array.isArray(e.types)||e.types.length===0)throw new TypeError("CMS dependencies require document types");let n=[...e.types];for(let t of n)if(typeof t!="string"||!O.test(t))throw new TypeError("Invalid CMS document type");if(e.ids!==void 0&&!Array.isArray(e.ids))throw new TypeError("Invalid CMS document IDs");let o=e.ids===void 0?void 0:[...e.ids];for(let t of o??[])if(typeof t!="string"||!x.test(t)||/^(drafts|versions)\./.test(t))throw new TypeError("Invalid CMS document ID");if(new Set(n).size+new Set(o).size>128)throw new TypeError("Too many CMS tags");return Object.freeze({types:Object.freeze(n),...o===void 0?{}:{ids:Object.freeze(o)}})}function d(e){if(!e||typeof e.name!="string"||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(e.name)||typeof e.query!="string"||e.query.trim()===""||typeof e.resolve!="function")throw new TypeError("Invalid CMS query configuration");let n=e.params;if(!n||typeof n!="object"||Object.getPrototypeOf(n)!==Object.prototype&&Object.getPrototypeOf(n)!==null)throw new TypeError("CMS params must be plain JSON scalars");let o={};for(let t of Reflect.ownKeys(n)){let r=Object.getOwnPropertyDescriptor(n,t);if(typeof t!="string"||!r||!Object.hasOwn(r,"value")||!r.enumerable)throw new TypeError("CMS params must be plain JSON scalars");let i=r.value;if(!(i===null||typeof i=="string"||typeof i=="boolean"||typeof i=="number"&&Number.isFinite(i)))throw new TypeError("CMS params must be plain JSON scalars");Object.defineProperty(o,t,{value:i,enumerable:!0})}return Object.freeze({name:e.name,query:e.query,params:Object.freeze(o),dependencies:c(e.dependencies),resolve:e.resolve})}function m(e,n){if(typeof e!="string"||e.length>77||!S.test(e))throw new TypeError("Invalid CMS scope");let o=c(n),t=[...[...new Set(o.types)].sort().map(r=>`cms:${e}:type:${r}`),...[...new Set(o.ids??[])].sort().map(r=>`cms:${e}:id:${r}`)];return Object.freeze(t)}var p=1,a={key:"hero",documentId:"siteHero",documentType:"siteHero",fields:[{name:"heading",label:"Heading",noun:{article:"a",word:"heading"},kind:"single-line",required:!0,minLength:1,maxLength:80,noTrailingFullStop:!0},{name:"intro",label:"Introduction",noun:{article:"an",word:"introduction"},kind:"multi-line",required:!0,minLength:1,maxLength:320}],copy:{currentTitle:"On your site now",editTitle:"Edit and publish",empty:"Your site has no hero text yet. Whatever you publish below becomes its first version."}};function k(e,n){let{article:o,word:t}=e.noun;if(n.length===0)return e.required?`Enter ${o} ${t}.`:null;let r=[...n].length;return r<e.minLength?`Make the ${t} at least ${String(e.minLength)} characters. It is ${String(r)} now.`:r>e.maxLength?`Keep the ${t} to ${String(e.maxLength)} characters or fewer. It is ${String(r)} now.`:n.includes("\u2014")?`The ${t} contains a long dash. Use a comma, a colon or a short dash instead.`:e.kind==="single-line"&&/[\r\n]/.test(n)?`The ${t} must be a single line.`:e.noTrailingFullStop===!0&&n.endsWith(".")?`${t.charAt(0).toUpperCase()}${t.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`:null}function u(e,n){let o={},t={};for(let r of e.fields){let i=Object.hasOwn(n,r.name)?n[r.name]:void 0,s=typeof i=="string"?i.trim():"",l=k(r,s);Object.defineProperty(l===null?o:t,r.name,{value:l??s,enumerable:!0})}return Object.keys(t).length>0?{ok:!1,errors:t}:{ok:!0,value:o}}function f(){return d({name:"siteHero.v1",query:'*[_id == $id && _type == "siteHero"][0]{heading,intro}',params:{id:"siteHero"},dependencies:{types:["siteHero"],ids:["siteHero"]},resolve:(e,n)=>{let o=u(a,n);if(!o.ok)throw new TypeError("Invalid siteHero fallback");let t={heading:o.value.heading??"",intro:o.value.intro??""};if(e===null||typeof e!="object"||Array.isArray(e))return{data:t,fallbackFields:["$"]};let r=u(a,e);if(r.ok)return{data:{heading:r.value.heading??"",intro:r.value.intro??""},fallbackFields:[]};let i=Object.keys(r.errors);for(let s of a.fields)if(!Object.hasOwn(r.errors,s.name)){let l=Object.hasOwn(e,s.name)?e[s.name]:void 0;typeof l=="string"&&(s.name==="heading"||s.name==="intro")&&(t[s.name]=l.trim())}return{data:t,fallbackFields:i.length===a.fields.length?["$"]:i}}})}0&&(module.exports={CMS_CONTRACT_VERSION,SITE_HERO,cmsTags,defineCmsQuery,siteHeroQuery,validateTextDocument});
1
+ "use strict";var f=Object.defineProperty;var C=Object.getOwnPropertyDescriptor;var R=Object.getOwnPropertyNames;var v=Object.prototype.hasOwnProperty;var _=(e,t)=>{for(var o in t)f(e,o,{get:t[o],enumerable:!0})},A=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of R(t))!v.call(e,n)&&n!==o&&f(e,n,{get:()=>t[n],enumerable:!(r=C(t,n))||r.enumerable});return e};var I=e=>A(f({},"__esModule",{value:!0}),e);var z={};_(z,{CMS_CONTRACT_VERSION:()=>k,SITE_HERO:()=>l,SITE_HERO_LAYOUTS:()=>m,SITE_HERO_LAYOUT_WARNING:()=>h,SITE_HERO_TAGLINE_MAX_LENGTH:()=>T,cmsTags:()=>H,defineCmsQuery:()=>c,parseSiteHero:()=>S,siteHeroQuery:()=>E,validateSiteHeroTaglines:()=>p,validateTextDocument:()=>y});module.exports=I(z);var L=/^[A-Za-z][A-Za-z0-9_]{0,63}$/,j=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,D=/^[a-z0-9]{6,12}\.[a-z][a-z0-9_-]{0,63}$/;function x(e){if(!e||!Array.isArray(e.types)||e.types.length===0)throw new TypeError("CMS dependencies require document types");let t=[...e.types];for(let r of t)if(typeof r!="string"||!L.test(r))throw new TypeError("Invalid CMS document type");if(e.ids!==void 0&&!Array.isArray(e.ids))throw new TypeError("Invalid CMS document IDs");let o=e.ids===void 0?void 0:[...e.ids];for(let r of o??[])if(typeof r!="string"||!j.test(r)||/^(drafts|versions)\./.test(r))throw new TypeError("Invalid CMS document ID");if(new Set(t).size+new Set(o).size>128)throw new TypeError("Too many CMS tags");return Object.freeze({types:Object.freeze(t),...o===void 0?{}:{ids:Object.freeze(o)}})}function c(e){if(!e||typeof e.name!="string"||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(e.name)||typeof e.query!="string"||e.query.trim()===""||typeof e.resolve!="function")throw new TypeError("Invalid CMS query configuration");let t=e.params;if(!t||typeof t!="object"||Object.getPrototypeOf(t)!==Object.prototype&&Object.getPrototypeOf(t)!==null)throw new TypeError("CMS params must be plain JSON scalars");let o={};for(let r of Reflect.ownKeys(t)){let n=Object.getOwnPropertyDescriptor(t,r);if(typeof r!="string"||!n||!Object.hasOwn(n,"value")||!n.enumerable)throw new TypeError("CMS params must be plain JSON scalars");let i=n.value;if(!(i===null||typeof i=="string"||typeof i=="boolean"||typeof i=="number"&&Number.isFinite(i)))throw new TypeError("CMS params must be plain JSON scalars");Object.defineProperty(o,r,{value:i,enumerable:!0})}return Object.freeze({name:e.name,query:e.query,params:Object.freeze(o),dependencies:x(e.dependencies),resolve:e.resolve})}function H(e,t){if(typeof e!="string"||e.length>77||!D.test(e))throw new TypeError("Invalid CMS scope");let o=x(t),r=[...[...new Set(o.types)].sort().map(n=>`cms:${e}:type:${n}`),...[...new Set(o.ids??[])].sort().map(n=>`cms:${e}:id:${n}`)];return Object.freeze(r)}var m=["columns","rows"],T=36,h="siteHero.layout.defaulted",k=1,l={key:"hero",documentId:"siteHero",documentType:"siteHero",fields:[{name:"heading",label:"Heading",noun:{article:"a",word:"heading"},kind:"single-line",required:!0,minLength:1,maxLength:80,noTrailingFullStop:!0},{name:"intro",label:"Introduction",noun:{article:"an",word:"introduction"},kind:"multi-line",required:!0,minLength:1,maxLength:320}],copy:{currentTitle:"On your site now",editTitle:"Edit and publish",empty:"Your site has no hero text yet. Whatever you publish below becomes its first version."}};function $(e,t){let{article:o,word:r}=e.noun;if(t.length===0)return e.required?`Enter ${o} ${r}.`:null;let n=[...t].length;return n<e.minLength?`Make the ${r} at least ${String(e.minLength)} characters. It is ${String(n)} now.`:n>e.maxLength?`Keep the ${r} to ${String(e.maxLength)} characters or fewer. It is ${String(n)} now.`:t.includes("\u2014")?`The ${r} contains a long dash. Use a comma, a colon or a short dash instead.`:e.kind==="single-line"&&/[\r\n]/.test(t)?`The ${r} must be a single line.`:e.noTrailingFullStop===!0&&t.endsWith(".")?`${r.charAt(0).toUpperCase()}${r.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`:null}function y(e,t){let o={},r={};for(let n of e.fields){let i=Object.hasOwn(t,n.name)?t[n.name]:void 0,a=typeof i=="string"?i.trim():"",s=$(n,a);Object.defineProperty(s===null?o:r,n.name,{value:s??a,enumerable:!0})}return Object.keys(r).length>0?{ok:!1,errors:r}:{ok:!0,value:o}}function p(e){if(!Array.isArray(e))return{ok:!1,error:"Enter a list of taglines."};let t=l.fields[0];if(!t)throw new TypeError("Missing siteHero heading definition");let o={...t,name:"text",noun:{article:"a",word:"tagline"},maxLength:T},r=[],n=new Set;for(let i of e){if(!i||typeof i!="object"||Array.isArray(i))return{ok:!1,error:"Enter a key and text for each tagline."};let a=i,s=Object.hasOwn(a,"key")?a.key:void 0;if(typeof s!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(s))return{ok:!1,error:"Use a lowercase key of 1 to 32 letters, numbers, short dashes or underscores, starting with a letter."};if(n.has(s))return{ok:!1,error:"Use each tagline key only once."};let d=y({...l,fields:[o]},a);if(!d.ok)return{ok:!1,error:d.errors.text??"Invalid tagline."};n.add(s),r.push({key:s,text:d.value.text??""})}return{ok:!0,value:r}}function O(e){return m.some(t=>e===t)}function S(e,t){let o=y(l,t),r=p(t.taglines??[]);if(!o.ok||!r.ok||t.layout!==void 0&&!O(t.layout))throw new TypeError("Invalid siteHero fallback");let n={heading:o.value.heading??"",intro:o.value.intro??"",layout:t.layout??"columns",taglines:r.value};if(e===null||typeof e!="object"||Array.isArray(e))return{data:n,fallbackFields:["$"]};let i=e,a=y(l,i),s=a.ok?[]:Object.keys(a.errors);for(let u of l.fields)if(!s.includes(u.name)){let b=a.ok?a.value[u.name]:i[u.name];typeof b=="string"&&(u.name==="heading"||u.name==="intro")&&(n[u.name]=b.trim())}let d=Object.hasOwn(i,"layout")?i.layout:void 0,g=[];O(d)?n.layout=d:(n.layout="columns",s.push("layout"),g.push(h));let w=p(Object.hasOwn(i,"taglines")?i.taglines:void 0);return w.ok?n.taglines=w.value:s.push("taglines"),{data:n,fallbackFields:s.length===l.fields.length+2?["$"]:s,...g.length>0?{warnings:g}:{}}}function E(){return c({name:"siteHero.v1",query:'*[_id == $id && _type == "siteHero"][0]{heading,intro,layout,taglines}',params:{id:"siteHero"},dependencies:{types:["siteHero"],ids:["siteHero"]},resolve:S})}0&&(module.exports={CMS_CONTRACT_VERSION,SITE_HERO,SITE_HERO_LAYOUTS,SITE_HERO_LAYOUT_WARNING,SITE_HERO_TAGLINE_MAX_LENGTH,cmsTags,defineCmsQuery,parseSiteHero,siteHeroQuery,validateSiteHeroTaglines,validateTextDocument});
2
2
  //# sourceMappingURL=index.cjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/index.ts", "../src/contracts/query.ts", "../src/contracts/text.ts"],
4
- "sourcesContent": ["export { defineCmsQuery, cmsTags } from \"./contracts/query.js\";\nexport type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from \"./contracts/query.js\";\nexport { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery } from \"./contracts/text.js\";\nexport type { SiteHero, TextFieldDefinition, TextDocumentDefinition, TextValidation } from \"./contracts/text.js\";\n", "/** A-1822 S1 owns this implementation. S0 registers the public signatures. */\nexport type CmsParams = Readonly<Record<string, string | number | boolean | null>>;\nexport type CmsDependencies = {\n readonly types: readonly string[];\n readonly ids?: readonly string[];\n};\nexport type CmsResolution<T> = {\n readonly data: T;\n readonly fallbackFields: readonly string[];\n};\nexport type CmsQuery<T> = {\n readonly name: string;\n readonly query: string;\n readonly params: CmsParams;\n readonly dependencies: CmsDependencies;\n readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;\n};\n\nconst TYPE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;\nconst SCOPE = /^[a-z0-9]{6,12}\\.[a-z][a-z0-9_-]{0,63}$/;\n\nfunction dependenciesCopy(dependencies: CmsDependencies): CmsDependencies {\n if (!dependencies || !Array.isArray(dependencies.types) || dependencies.types.length === 0) {\n throw new TypeError(\"CMS dependencies require document types\");\n }\n const types = [...dependencies.types];\n for (const type of types) {\n if (typeof type !== \"string\" || !TYPE.test(type)) throw new TypeError(\"Invalid CMS document type\");\n }\n if (dependencies.ids !== undefined && !Array.isArray(dependencies.ids)) throw new TypeError(\"Invalid CMS document IDs\");\n const ids = dependencies.ids === undefined ? undefined : [...dependencies.ids];\n for (const id of ids ?? []) {\n if (typeof id !== \"string\" || !ID.test(id) || /^(drafts|versions)\\./.test(id)) {\n throw new TypeError(\"Invalid CMS document ID\");\n }\n }\n if (new Set(types).size + new Set(ids).size > 128) throw new TypeError(\"Too many CMS tags\");\n return Object.freeze({ types: Object.freeze(types), ...(ids === undefined ? {} : { ids: Object.freeze(ids) }) });\n}\n\nexport function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T> {\n if (!query || typeof query.name !== \"string\" || !/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(query.name)\n || typeof query.query !== \"string\" || query.query.trim() === \"\" || typeof query.resolve !== \"function\") {\n throw new TypeError(\"Invalid CMS query configuration\");\n }\n const params = query.params;\n if (!params || typeof params !== \"object\" || (Object.getPrototypeOf(params) !== Object.prototype && Object.getPrototypeOf(params) !== null)) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const copied: Record<string, string | number | boolean | null> = {};\n for (const key of Reflect.ownKeys(params)) {\n const descriptor = Object.getOwnPropertyDescriptor(params, key);\n if (typeof key !== \"string\" || !descriptor || !Object.hasOwn(descriptor, \"value\") || !descriptor.enumerable) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const value: unknown = descriptor.value;\n if (!(value === null || typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value)))) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n Object.defineProperty(copied, key, { value, enumerable: true });\n }\n return Object.freeze({ name: query.name, query: query.query, params: Object.freeze(copied), dependencies: dependenciesCopy(query.dependencies), resolve: query.resolve });\n}\n\nexport function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[] {\n if (typeof scope !== \"string\" || scope.length > 77 || !SCOPE.test(scope)) throw new TypeError(\"Invalid CMS scope\");\n const copied = dependenciesCopy(dependencies);\n const tags = [\n ...[...new Set(copied.types)].sort().map((type) => `cms:${scope}:type:${type}`),\n ...[...new Set(copied.ids ?? [])].sort().map((id) => `cms:${scope}:id:${id}`),\n ];\n return Object.freeze(tags);\n}\n", "import { defineCmsQuery, type CmsQuery } from \"./query.js\";\n\nexport type SiteHero = { readonly heading: string; readonly intro: string };\nexport type TextFieldDefinition = {\n readonly name: string;\n readonly label: string;\n readonly noun: { readonly article: \"a\" | \"an\"; readonly word: string };\n readonly kind: \"single-line\" | \"multi-line\";\n readonly required: boolean;\n readonly minLength: number;\n readonly maxLength: number;\n readonly noTrailingFullStop?: boolean;\n};\nexport type TextDocumentDefinition = {\n readonly key: string;\n readonly documentId: string;\n readonly documentType: string;\n readonly fields: readonly TextFieldDefinition[];\n readonly copy: {\n readonly currentTitle: string;\n readonly editTitle: string;\n readonly empty: string;\n };\n};\nexport type TextValidation =\n | { readonly ok: true; readonly value: Readonly<Record<string, string>> }\n | { readonly ok: false; readonly errors: Readonly<Record<string, string>> };\n\nexport const CMS_CONTRACT_VERSION = 1;\n\nexport const SITE_HERO: TextDocumentDefinition = {\n key: \"hero\",\n documentId: \"siteHero\",\n documentType: \"siteHero\",\n fields: [\n {\n name: \"heading\",\n label: \"Heading\",\n noun: { article: \"a\", word: \"heading\" },\n kind: \"single-line\",\n required: true,\n minLength: 1,\n maxLength: 80,\n noTrailingFullStop: true,\n },\n {\n name: \"intro\",\n label: \"Introduction\",\n noun: { article: \"an\", word: \"introduction\" },\n kind: \"multi-line\",\n required: true,\n minLength: 1,\n maxLength: 320,\n },\n ],\n copy: {\n currentTitle: \"On your site now\",\n editTitle: \"Edit and publish\",\n empty: \"Your site has no hero text yet. Whatever you publish below becomes its first version.\",\n },\n};\n\nfunction fieldError(field: TextFieldDefinition, text: string): string | null {\n const { article, word } = field.noun;\n if (text.length === 0) return field.required ? `Enter ${article} ${word}.` : null;\n const count = [...text].length;\n if (count < field.minLength) return `Make the ${word} at least ${String(field.minLength)} characters. It is ${String(count)} now.`;\n if (count > field.maxLength) return `Keep the ${word} to ${String(field.maxLength)} characters or fewer. It is ${String(count)} now.`;\n if (text.includes(\"\\u2014\")) return `The ${word} contains a long dash. Use a comma, a colon or a short dash instead.`;\n if (field.kind === \"single-line\" && /[\\r\\n]/.test(text)) return `The ${word} must be a single line.`;\n if (field.noTrailingFullStop === true && text.endsWith(\".\")) {\n return `${word.charAt(0).toUpperCase()}${word.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`;\n }\n return null;\n}\n\nexport function validateTextDocument(\n definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>,\n): TextValidation {\n const value: Record<string, string> = {};\n const errors: Record<string, string> = {};\n for (const field of definition.fields) {\n const submitted = Object.hasOwn(raw, field.name) ? raw[field.name] : undefined;\n const text = typeof submitted === \"string\" ? submitted.trim() : \"\";\n const error = fieldError(field, text);\n Object.defineProperty(error === null ? value : errors, field.name, { value: error ?? text, enumerable: true });\n }\n return Object.keys(errors).length > 0 ? { ok: false, errors } : { ok: true, value };\n}\n\nexport function siteHeroQuery(): CmsQuery<SiteHero> {\n return defineCmsQuery({\n name: \"siteHero.v1\", query: '*[_id == $id && _type == \"siteHero\"][0]{heading,intro}',\n params: { id: \"siteHero\" }, dependencies: { types: [\"siteHero\"], ids: [\"siteHero\"] },\n resolve: (raw, fallback) => {\n const local = validateTextDocument(SITE_HERO, fallback);\n if (!local.ok) throw new TypeError(\"Invalid siteHero fallback\");\n const data = { heading: local.value.heading ?? \"\", intro: local.value.intro ?? \"\" };\n if (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) return { data, fallbackFields: [\"$\"] };\n const result = validateTextDocument(SITE_HERO, raw as Readonly<Record<string, unknown>>);\n if (result.ok) return { data: { heading: result.value.heading ?? \"\", intro: result.value.intro ?? \"\" }, fallbackFields: [] };\n const fallbackFields = Object.keys(result.errors);\n for (const field of SITE_HERO.fields) {\n if (!Object.hasOwn(result.errors, field.name)) {\n const submitted = Object.hasOwn(raw, field.name) ? (raw as Record<string, unknown>)[field.name] : undefined;\n if (typeof submitted === \"string\" && (field.name === \"heading\" || field.name === \"intro\")) data[field.name] = submitted.trim();\n }\n }\n return { data, fallbackFields: fallbackFields.length === SITE_HERO.fields.length ? [\"$\"] : fallbackFields };\n },\n });\n}\n"],
5
- "mappings": "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",
6
- "names": ["index_exports", "__export", "CMS_CONTRACT_VERSION", "SITE_HERO", "cmsTags", "defineCmsQuery", "siteHeroQuery", "validateTextDocument", "__toCommonJS", "TYPE", "ID", "SCOPE", "dependenciesCopy", "dependencies", "types", "type", "ids", "id", "defineCmsQuery", "query", "params", "copied", "key", "descriptor", "value", "cmsTags", "scope", "tags", "CMS_CONTRACT_VERSION", "SITE_HERO", "fieldError", "field", "text", "article", "word", "count", "validateTextDocument", "definition", "raw", "value", "errors", "submitted", "error", "siteHeroQuery", "defineCmsQuery", "fallback", "local", "data", "result", "fallbackFields"]
4
+ "sourcesContent": ["export { defineCmsQuery, cmsTags } from \"./contracts/query.js\";\nexport type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from \"./contracts/query.js\";\nexport { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery, SITE_HERO_LAYOUTS, SITE_HERO_TAGLINE_MAX_LENGTH, SITE_HERO_LAYOUT_WARNING, parseSiteHero, validateSiteHeroTaglines } from \"./contracts/text.js\";\nexport type { SiteHero, ParsedSiteHero, SiteHeroLayout, SiteHeroTagline, TextFieldDefinition, TextDocumentDefinition, TextValidation } from \"./contracts/text.js\";\n", "/** A-1822 S1 owns this implementation. S0 registers the public signatures. */\nexport type CmsParams = Readonly<Record<string, string | number | boolean | null>>;\nexport type CmsDependencies = {\n readonly types: readonly string[];\n readonly ids?: readonly string[];\n};\nexport type CmsResolution<T> = {\n readonly data: T;\n readonly fallbackFields: readonly string[];\n readonly warnings?: readonly \"siteHero.layout.defaulted\"[];\n};\nexport type CmsQuery<T> = {\n readonly name: string;\n readonly query: string;\n readonly params: CmsParams;\n readonly dependencies: CmsDependencies;\n readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;\n};\n\nconst TYPE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;\nconst SCOPE = /^[a-z0-9]{6,12}\\.[a-z][a-z0-9_-]{0,63}$/;\n\nfunction dependenciesCopy(dependencies: CmsDependencies): CmsDependencies {\n if (!dependencies || !Array.isArray(dependencies.types) || dependencies.types.length === 0) {\n throw new TypeError(\"CMS dependencies require document types\");\n }\n const types = [...dependencies.types];\n for (const type of types) {\n if (typeof type !== \"string\" || !TYPE.test(type)) throw new TypeError(\"Invalid CMS document type\");\n }\n if (dependencies.ids !== undefined && !Array.isArray(dependencies.ids)) throw new TypeError(\"Invalid CMS document IDs\");\n const ids = dependencies.ids === undefined ? undefined : [...dependencies.ids];\n for (const id of ids ?? []) {\n if (typeof id !== \"string\" || !ID.test(id) || /^(drafts|versions)\\./.test(id)) {\n throw new TypeError(\"Invalid CMS document ID\");\n }\n }\n if (new Set(types).size + new Set(ids).size > 128) throw new TypeError(\"Too many CMS tags\");\n return Object.freeze({ types: Object.freeze(types), ...(ids === undefined ? {} : { ids: Object.freeze(ids) }) });\n}\n\nexport function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T> {\n if (!query || typeof query.name !== \"string\" || !/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(query.name)\n || typeof query.query !== \"string\" || query.query.trim() === \"\" || typeof query.resolve !== \"function\") {\n throw new TypeError(\"Invalid CMS query configuration\");\n }\n const params = query.params;\n if (!params || typeof params !== \"object\" || (Object.getPrototypeOf(params) !== Object.prototype && Object.getPrototypeOf(params) !== null)) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const copied: Record<string, string | number | boolean | null> = {};\n for (const key of Reflect.ownKeys(params)) {\n const descriptor = Object.getOwnPropertyDescriptor(params, key);\n if (typeof key !== \"string\" || !descriptor || !Object.hasOwn(descriptor, \"value\") || !descriptor.enumerable) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const value: unknown = descriptor.value;\n if (!(value === null || typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value)))) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n Object.defineProperty(copied, key, { value, enumerable: true });\n }\n return Object.freeze({ name: query.name, query: query.query, params: Object.freeze(copied), dependencies: dependenciesCopy(query.dependencies), resolve: query.resolve });\n}\n\nexport function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[] {\n if (typeof scope !== \"string\" || scope.length > 77 || !SCOPE.test(scope)) throw new TypeError(\"Invalid CMS scope\");\n const copied = dependenciesCopy(dependencies);\n const tags = [\n ...[...new Set(copied.types)].sort().map((type) => `cms:${scope}:type:${type}`),\n ...[...new Set(copied.ids ?? [])].sort().map((id) => `cms:${scope}:id:${id}`),\n ];\n return Object.freeze(tags);\n}\n", "import { defineCmsQuery, type CmsQuery, type CmsResolution } from \"./query.js\";\n\nexport const SITE_HERO_LAYOUTS = [\"columns\", \"rows\"] as const;\nexport const SITE_HERO_TAGLINE_MAX_LENGTH = 36;\nexport const SITE_HERO_LAYOUT_WARNING = \"siteHero.layout.defaulted\" as const;\nexport type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];\nexport type SiteHeroTagline = { readonly key: string; readonly text: string };\n/** Optional additions preserve existing heading/intro-only consumer fallbacks. */\nexport type SiteHero = {\n readonly heading: string;\n readonly intro: string;\n readonly layout?: SiteHeroLayout;\n readonly taglines?: readonly SiteHeroTagline[];\n};\nexport type ParsedSiteHero = SiteHero & {\n readonly layout: SiteHeroLayout;\n readonly taglines: readonly SiteHeroTagline[];\n};\nexport type TextFieldDefinition = {\n readonly name: string;\n readonly label: string;\n readonly noun: { readonly article: \"a\" | \"an\"; readonly word: string };\n readonly kind: \"single-line\" | \"multi-line\";\n readonly required: boolean;\n readonly minLength: number;\n readonly maxLength: number;\n readonly noTrailingFullStop?: boolean;\n};\nexport type TextDocumentDefinition = {\n readonly key: string;\n readonly documentId: string;\n readonly documentType: string;\n readonly fields: readonly TextFieldDefinition[];\n readonly copy: {\n readonly currentTitle: string;\n readonly editTitle: string;\n readonly empty: string;\n };\n};\nexport type TextValidation =\n | { readonly ok: true; readonly value: Readonly<Record<string, string>> }\n | { readonly ok: false; readonly errors: Readonly<Record<string, string>> };\n\nexport const CMS_CONTRACT_VERSION = 1;\n\nexport const SITE_HERO: TextDocumentDefinition = {\n key: \"hero\",\n documentId: \"siteHero\",\n documentType: \"siteHero\",\n fields: [\n {\n name: \"heading\",\n label: \"Heading\",\n noun: { article: \"a\", word: \"heading\" },\n kind: \"single-line\",\n required: true,\n minLength: 1,\n maxLength: 80,\n noTrailingFullStop: true,\n },\n {\n name: \"intro\",\n label: \"Introduction\",\n noun: { article: \"an\", word: \"introduction\" },\n kind: \"multi-line\",\n required: true,\n minLength: 1,\n maxLength: 320,\n },\n ],\n copy: {\n currentTitle: \"On your site now\",\n editTitle: \"Edit and publish\",\n empty: \"Your site has no hero text yet. Whatever you publish below becomes its first version.\",\n },\n};\n\nfunction fieldError(field: TextFieldDefinition, text: string): string | null {\n const { article, word } = field.noun;\n if (text.length === 0) return field.required ? `Enter ${article} ${word}.` : null;\n const count = [...text].length;\n if (count < field.minLength) return `Make the ${word} at least ${String(field.minLength)} characters. It is ${String(count)} now.`;\n if (count > field.maxLength) return `Keep the ${word} to ${String(field.maxLength)} characters or fewer. It is ${String(count)} now.`;\n if (text.includes(\"\\u2014\")) return `The ${word} contains a long dash. Use a comma, a colon or a short dash instead.`;\n if (field.kind === \"single-line\" && /[\\r\\n]/.test(text)) return `The ${word} must be a single line.`;\n if (field.noTrailingFullStop === true && text.endsWith(\".\")) {\n return `${word.charAt(0).toUpperCase()}${word.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`;\n }\n return null;\n}\n\nexport function validateTextDocument(\n definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>,\n): TextValidation {\n const value: Record<string, string> = {};\n const errors: Record<string, string> = {};\n for (const field of definition.fields) {\n const submitted = Object.hasOwn(raw, field.name) ? raw[field.name] : undefined;\n const text = typeof submitted === \"string\" ? submitted.trim() : \"\";\n const error = fieldError(field, text);\n Object.defineProperty(error === null ? value : errors, field.name, { value: error ?? text, enumerable: true });\n }\n return Object.keys(errors).length > 0 ? { ok: false, errors } : { ok: true, value };\n}\n\n/** Shared with the schema adapter; no provider metadata is returned. */\nexport function validateSiteHeroTaglines(raw: unknown):\n | { readonly ok: true; readonly value: readonly SiteHeroTagline[] }\n | { readonly ok: false; readonly error: string } {\n if (!Array.isArray(raw)) return { ok: false, error: \"Enter a list of taglines.\" };\n const heading = SITE_HERO.fields[0];\n if (!heading) throw new TypeError(\"Missing siteHero heading definition\");\n const field = { ...heading, name: \"text\", noun: { article: \"a\", word: \"tagline\" } as const,\n maxLength: SITE_HERO_TAGLINE_MAX_LENGTH };\n const value: SiteHeroTagline[] = [];\n const keys = new Set<string>();\n for (const item of raw as unknown[]) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { ok: false, error: \"Enter a key and text for each tagline.\" };\n const record = item as Record<string, unknown>;\n const key = Object.hasOwn(record, \"key\") ? record.key : undefined;\n if (typeof key !== \"string\" || !/^[a-z][a-z0-9_-]{0,31}$/.test(key)) {\n return { ok: false, error: \"Use a lowercase key of 1 to 32 letters, numbers, short dashes or underscores, starting with a letter.\" };\n }\n if (keys.has(key)) return { ok: false, error: \"Use each tagline key only once.\" };\n const text = validateTextDocument({ ...SITE_HERO, fields: [field] }, record);\n if (!text.ok) return { ok: false, error: text.errors.text ?? \"Invalid tagline.\" };\n keys.add(key);\n value.push({ key, text: text.value.text ?? \"\" });\n }\n return { ok: true, value };\n}\n\nfunction isLayout(value: unknown): value is SiteHeroLayout {\n return SITE_HERO_LAYOUTS.some((layout) => value === layout);\n}\n\n/** Strict per-field resolution: an invalid list never partially changes keyed copy. */\nexport function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero> {\n const local = validateTextDocument(SITE_HERO, fallback);\n const localTaglines = validateSiteHeroTaglines(fallback.taglines ?? []);\n if (!local.ok || !localTaglines.ok || (fallback.layout !== undefined && !isLayout(fallback.layout))) {\n throw new TypeError(\"Invalid siteHero fallback\");\n }\n const data: { heading: string; intro: string; layout: SiteHeroLayout; taglines: readonly SiteHeroTagline[] } = {\n heading: local.value.heading ?? \"\", intro: local.value.intro ?? \"\",\n layout: fallback.layout ?? \"columns\", taglines: localTaglines.value,\n };\n if (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) return { data, fallbackFields: [\"$\"] };\n const record = raw as Readonly<Record<string, unknown>>;\n const text = validateTextDocument(SITE_HERO, record);\n const fallbackFields: string[] = text.ok ? [] : Object.keys(text.errors);\n for (const field of SITE_HERO.fields) {\n if (!fallbackFields.includes(field.name)) {\n const value = text.ok ? text.value[field.name] : record[field.name];\n if (typeof value === \"string\" && (field.name === \"heading\" || field.name === \"intro\")) data[field.name] = value.trim();\n }\n }\n const layout = Object.hasOwn(record, \"layout\") ? record.layout : undefined;\n const warnings: (typeof SITE_HERO_LAYOUT_WARNING)[] = [];\n if (isLayout(layout)) data.layout = layout;\n else {\n data.layout = \"columns\";\n fallbackFields.push(\"layout\");\n warnings.push(SITE_HERO_LAYOUT_WARNING);\n }\n const taglines = validateSiteHeroTaglines(Object.hasOwn(record, \"taglines\") ? record.taglines : undefined);\n if (taglines.ok) data.taglines = taglines.value;\n else fallbackFields.push(\"taglines\");\n return { data, fallbackFields: fallbackFields.length === SITE_HERO.fields.length + 2 ? [\"$\"] : fallbackFields,\n ...(warnings.length > 0 ? { warnings } : {}) };\n}\n\nexport function siteHeroQuery(): CmsQuery<SiteHero> {\n return defineCmsQuery<SiteHero>({\n name: \"siteHero.v1\", query: '*[_id == $id && _type == \"siteHero\"][0]{heading,intro,layout,taglines}',\n params: { id: \"siteHero\" }, dependencies: { types: [\"siteHero\"], ids: [\"siteHero\"] },\n resolve: parseSiteHero,\n });\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["index_exports", "__export", "CMS_CONTRACT_VERSION", "SITE_HERO", "SITE_HERO_LAYOUTS", "SITE_HERO_LAYOUT_WARNING", "SITE_HERO_TAGLINE_MAX_LENGTH", "cmsTags", "defineCmsQuery", "parseSiteHero", "siteHeroQuery", "validateSiteHeroTaglines", "validateTextDocument", "__toCommonJS", "TYPE", "ID", "SCOPE", "dependenciesCopy", "dependencies", "types", "type", "ids", "id", "defineCmsQuery", "query", "params", "copied", "key", "descriptor", "value", "cmsTags", "scope", "tags", "SITE_HERO_LAYOUTS", "SITE_HERO_TAGLINE_MAX_LENGTH", "SITE_HERO_LAYOUT_WARNING", "CMS_CONTRACT_VERSION", "SITE_HERO", "fieldError", "field", "text", "article", "word", "count", "validateTextDocument", "definition", "raw", "value", "errors", "submitted", "error", "validateSiteHeroTaglines", "heading", "keys", "item", "record", "key", "isLayout", "layout", "parseSiteHero", "fallback", "local", "localTaglines", "data", "fallbackFields", "warnings", "taglines", "siteHeroQuery", "defineCmsQuery"]
7
7
  }
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { defineCmsQuery, cmsTags } from "./contracts/query.cjs";
2
2
  export type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from "./contracts/query.cjs";
3
- export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery } from "./contracts/text.cjs";
4
- export type { SiteHero, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.cjs";
3
+ export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery, SITE_HERO_LAYOUTS, SITE_HERO_TAGLINE_MAX_LENGTH, SITE_HERO_LAYOUT_WARNING, parseSiteHero, validateSiteHeroTaglines } from "./contracts/text.cjs";
4
+ export type { SiteHero, ParsedSiteHero, SiteHeroLayout, SiteHeroTagline, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.cjs";
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { defineCmsQuery, cmsTags } from "./contracts/query.mjs";
2
2
  export type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from "./contracts/query.mjs";
3
- export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery } from "./contracts/text.mjs";
4
- export type { SiteHero, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.mjs";
3
+ export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery, SITE_HERO_LAYOUTS, SITE_HERO_TAGLINE_MAX_LENGTH, SITE_HERO_LAYOUT_WARNING, parseSiteHero, validateSiteHeroTaglines } from "./contracts/text.mjs";
4
+ export type { SiteHero, ParsedSiteHero, SiteHeroLayout, SiteHeroTagline, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.mjs";
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { defineCmsQuery, cmsTags } from "./contracts/query.js";
2
2
  export type { CmsParams, CmsDependencies, CmsResolution, CmsQuery } from "./contracts/query.js";
3
- export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery } from "./contracts/text.js";
4
- export type { SiteHero, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.js";
3
+ export { SITE_HERO, CMS_CONTRACT_VERSION, validateTextDocument, siteHeroQuery, SITE_HERO_LAYOUTS, SITE_HERO_TAGLINE_MAX_LENGTH, SITE_HERO_LAYOUT_WARNING, parseSiteHero, validateSiteHeroTaglines } from "./contracts/text.js";
4
+ export type { SiteHero, ParsedSiteHero, SiteHeroLayout, SiteHeroTagline, TextFieldDefinition, TextDocumentDefinition, TextValidation } from "./contracts/text.js";
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var c=/^[A-Za-z][A-Za-z0-9_]{0,63}$/,m=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,p=/^[a-z0-9]{6,12}\.[a-z][a-z0-9_-]{0,63}$/;function y(e){if(!e||!Array.isArray(e.types)||e.types.length===0)throw new TypeError("CMS dependencies require document types");let r=[...e.types];for(let n of r)if(typeof n!="string"||!c.test(n))throw new TypeError("Invalid CMS document type");if(e.ids!==void 0&&!Array.isArray(e.ids))throw new TypeError("Invalid CMS document IDs");let o=e.ids===void 0?void 0:[...e.ids];for(let n of o??[])if(typeof n!="string"||!m.test(n)||/^(drafts|versions)\./.test(n))throw new TypeError("Invalid CMS document ID");if(new Set(r).size+new Set(o).size>128)throw new TypeError("Too many CMS tags");return Object.freeze({types:Object.freeze(r),...o===void 0?{}:{ids:Object.freeze(o)}})}function d(e){if(!e||typeof e.name!="string"||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(e.name)||typeof e.query!="string"||e.query.trim()===""||typeof e.resolve!="function")throw new TypeError("Invalid CMS query configuration");let r=e.params;if(!r||typeof r!="object"||Object.getPrototypeOf(r)!==Object.prototype&&Object.getPrototypeOf(r)!==null)throw new TypeError("CMS params must be plain JSON scalars");let o={};for(let n of Reflect.ownKeys(r)){let t=Object.getOwnPropertyDescriptor(r,n);if(typeof n!="string"||!t||!Object.hasOwn(t,"value")||!t.enumerable)throw new TypeError("CMS params must be plain JSON scalars");let i=t.value;if(!(i===null||typeof i=="string"||typeof i=="boolean"||typeof i=="number"&&Number.isFinite(i)))throw new TypeError("CMS params must be plain JSON scalars");Object.defineProperty(o,n,{value:i,enumerable:!0})}return Object.freeze({name:e.name,query:e.query,params:Object.freeze(o),dependencies:y(e.dependencies),resolve:e.resolve})}function f(e,r){if(typeof e!="string"||e.length>77||!p.test(e))throw new TypeError("Invalid CMS scope");let o=y(r),n=[...[...new Set(o.types)].sort().map(t=>`cms:${e}:type:${t}`),...[...new Set(o.ids??[])].sort().map(t=>`cms:${e}:id:${t}`)];return Object.freeze(n)}var g=1,l={key:"hero",documentId:"siteHero",documentType:"siteHero",fields:[{name:"heading",label:"Heading",noun:{article:"a",word:"heading"},kind:"single-line",required:!0,minLength:1,maxLength:80,noTrailingFullStop:!0},{name:"intro",label:"Introduction",noun:{article:"an",word:"introduction"},kind:"multi-line",required:!0,minLength:1,maxLength:320}],copy:{currentTitle:"On your site now",editTitle:"Edit and publish",empty:"Your site has no hero text yet. Whatever you publish below becomes its first version."}};function h(e,r){let{article:o,word:n}=e.noun;if(r.length===0)return e.required?`Enter ${o} ${n}.`:null;let t=[...r].length;return t<e.minLength?`Make the ${n} at least ${String(e.minLength)} characters. It is ${String(t)} now.`:t>e.maxLength?`Keep the ${n} to ${String(e.maxLength)} characters or fewer. It is ${String(t)} now.`:r.includes("\u2014")?`The ${n} contains a long dash. Use a comma, a colon or a short dash instead.`:e.kind==="single-line"&&/[\r\n]/.test(r)?`The ${n} must be a single line.`:e.noTrailingFullStop===!0&&r.endsWith(".")?`${n.charAt(0).toUpperCase()}${n.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`:null}function u(e,r){let o={},n={};for(let t of e.fields){let i=Object.hasOwn(r,t.name)?r[t.name]:void 0,s=typeof i=="string"?i.trim():"",a=h(t,s);Object.defineProperty(a===null?o:n,t.name,{value:a??s,enumerable:!0})}return Object.keys(n).length>0?{ok:!1,errors:n}:{ok:!0,value:o}}function b(){return d({name:"siteHero.v1",query:'*[_id == $id && _type == "siteHero"][0]{heading,intro}',params:{id:"siteHero"},dependencies:{types:["siteHero"],ids:["siteHero"]},resolve:(e,r)=>{let o=u(l,r);if(!o.ok)throw new TypeError("Invalid siteHero fallback");let n={heading:o.value.heading??"",intro:o.value.intro??""};if(e===null||typeof e!="object"||Array.isArray(e))return{data:n,fallbackFields:["$"]};let t=u(l,e);if(t.ok)return{data:{heading:t.value.heading??"",intro:t.value.intro??""},fallbackFields:[]};let i=Object.keys(t.errors);for(let s of l.fields)if(!Object.hasOwn(t.errors,s.name)){let a=Object.hasOwn(e,s.name)?e[s.name]:void 0;typeof a=="string"&&(s.name==="heading"||s.name==="intro")&&(n[s.name]=a.trim())}return{data:n,fallbackFields:i.length===l.fields.length?["$"]:i}}})}export{g as CMS_CONTRACT_VERSION,l as SITE_HERO,f as cmsTags,d as defineCmsQuery,b as siteHeroQuery,u as validateTextDocument};
1
+ var H=/^[A-Za-z][A-Za-z0-9_]{0,63}$/,O=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,k=/^[a-z0-9]{6,12}\.[a-z][a-z0-9_-]{0,63}$/;function T(e){if(!e||!Array.isArray(e.types)||e.types.length===0)throw new TypeError("CMS dependencies require document types");let t=[...e.types];for(let n of t)if(typeof n!="string"||!H.test(n))throw new TypeError("Invalid CMS document type");if(e.ids!==void 0&&!Array.isArray(e.ids))throw new TypeError("Invalid CMS document IDs");let o=e.ids===void 0?void 0:[...e.ids];for(let n of o??[])if(typeof n!="string"||!O.test(n)||/^(drafts|versions)\./.test(n))throw new TypeError("Invalid CMS document ID");if(new Set(t).size+new Set(o).size>128)throw new TypeError("Too many CMS tags");return Object.freeze({types:Object.freeze(t),...o===void 0?{}:{ids:Object.freeze(o)}})}function p(e){if(!e||typeof e.name!="string"||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(e.name)||typeof e.query!="string"||e.query.trim()===""||typeof e.resolve!="function")throw new TypeError("Invalid CMS query configuration");let t=e.params;if(!t||typeof t!="object"||Object.getPrototypeOf(t)!==Object.prototype&&Object.getPrototypeOf(t)!==null)throw new TypeError("CMS params must be plain JSON scalars");let o={};for(let n of Reflect.ownKeys(t)){let r=Object.getOwnPropertyDescriptor(t,n);if(typeof n!="string"||!r||!Object.hasOwn(r,"value")||!r.enumerable)throw new TypeError("CMS params must be plain JSON scalars");let i=r.value;if(!(i===null||typeof i=="string"||typeof i=="boolean"||typeof i=="number"&&Number.isFinite(i)))throw new TypeError("CMS params must be plain JSON scalars");Object.defineProperty(o,n,{value:i,enumerable:!0})}return Object.freeze({name:e.name,query:e.query,params:Object.freeze(o),dependencies:T(e.dependencies),resolve:e.resolve})}function E(e,t){if(typeof e!="string"||e.length>77||!k.test(e))throw new TypeError("Invalid CMS scope");let o=T(t),n=[...[...new Set(o.types)].sort().map(r=>`cms:${e}:type:${r}`),...[...new Set(o.ids??[])].sort().map(r=>`cms:${e}:id:${r}`)];return Object.freeze(n)}var S=["columns","rows"],w=36,b="siteHero.layout.defaulted",C=1,l={key:"hero",documentId:"siteHero",documentType:"siteHero",fields:[{name:"heading",label:"Heading",noun:{article:"a",word:"heading"},kind:"single-line",required:!0,minLength:1,maxLength:80,noTrailingFullStop:!0},{name:"intro",label:"Introduction",noun:{article:"an",word:"introduction"},kind:"multi-line",required:!0,minLength:1,maxLength:320}],copy:{currentTitle:"On your site now",editTitle:"Edit and publish",empty:"Your site has no hero text yet. Whatever you publish below becomes its first version."}};function R(e,t){let{article:o,word:n}=e.noun;if(t.length===0)return e.required?`Enter ${o} ${n}.`:null;let r=[...t].length;return r<e.minLength?`Make the ${n} at least ${String(e.minLength)} characters. It is ${String(r)} now.`:r>e.maxLength?`Keep the ${n} to ${String(e.maxLength)} characters or fewer. It is ${String(r)} now.`:t.includes("\u2014")?`The ${n} contains a long dash. Use a comma, a colon or a short dash instead.`:e.kind==="single-line"&&/[\r\n]/.test(t)?`The ${n} must be a single line.`:e.noTrailingFullStop===!0&&t.endsWith(".")?`${n.charAt(0).toUpperCase()}${n.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`:null}function y(e,t){let o={},n={};for(let r of e.fields){let i=Object.hasOwn(t,r.name)?t[r.name]:void 0,a=typeof i=="string"?i.trim():"",s=R(r,a);Object.defineProperty(s===null?o:n,r.name,{value:s??a,enumerable:!0})}return Object.keys(n).length>0?{ok:!1,errors:n}:{ok:!0,value:o}}function g(e){if(!Array.isArray(e))return{ok:!1,error:"Enter a list of taglines."};let t=l.fields[0];if(!t)throw new TypeError("Missing siteHero heading definition");let o={...t,name:"text",noun:{article:"a",word:"tagline"},maxLength:w},n=[],r=new Set;for(let i of e){if(!i||typeof i!="object"||Array.isArray(i))return{ok:!1,error:"Enter a key and text for each tagline."};let a=i,s=Object.hasOwn(a,"key")?a.key:void 0;if(typeof s!="string"||!/^[a-z][a-z0-9_-]{0,31}$/.test(s))return{ok:!1,error:"Use a lowercase key of 1 to 32 letters, numbers, short dashes or underscores, starting with a letter."};if(r.has(s))return{ok:!1,error:"Use each tagline key only once."};let d=y({...l,fields:[o]},a);if(!d.ok)return{ok:!1,error:d.errors.text??"Invalid tagline."};r.add(s),n.push({key:s,text:d.value.text??""})}return{ok:!0,value:n}}function h(e){return S.some(t=>e===t)}function x(e,t){let o=y(l,t),n=g(t.taglines??[]);if(!o.ok||!n.ok||t.layout!==void 0&&!h(t.layout))throw new TypeError("Invalid siteHero fallback");let r={heading:o.value.heading??"",intro:o.value.intro??"",layout:t.layout??"columns",taglines:n.value};if(e===null||typeof e!="object"||Array.isArray(e))return{data:r,fallbackFields:["$"]};let i=e,a=y(l,i),s=a.ok?[]:Object.keys(a.errors);for(let u of l.fields)if(!s.includes(u.name)){let m=a.ok?a.value[u.name]:i[u.name];typeof m=="string"&&(u.name==="heading"||u.name==="intro")&&(r[u.name]=m.trim())}let d=Object.hasOwn(i,"layout")?i.layout:void 0,c=[];h(d)?r.layout=d:(r.layout="columns",s.push("layout"),c.push(b));let f=g(Object.hasOwn(i,"taglines")?i.taglines:void 0);return f.ok?r.taglines=f.value:s.push("taglines"),{data:r,fallbackFields:s.length===l.fields.length+2?["$"]:s,...c.length>0?{warnings:c}:{}}}function v(){return p({name:"siteHero.v1",query:'*[_id == $id && _type == "siteHero"][0]{heading,intro,layout,taglines}',params:{id:"siteHero"},dependencies:{types:["siteHero"],ids:["siteHero"]},resolve:x})}export{C as CMS_CONTRACT_VERSION,l as SITE_HERO,S as SITE_HERO_LAYOUTS,b as SITE_HERO_LAYOUT_WARNING,w as SITE_HERO_TAGLINE_MAX_LENGTH,E as cmsTags,p as defineCmsQuery,x as parseSiteHero,v as siteHeroQuery,g as validateSiteHeroTaglines,y as validateTextDocument};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/contracts/query.ts", "../src/contracts/text.ts"],
4
- "sourcesContent": ["/** A-1822 S1 owns this implementation. S0 registers the public signatures. */\nexport type CmsParams = Readonly<Record<string, string | number | boolean | null>>;\nexport type CmsDependencies = {\n readonly types: readonly string[];\n readonly ids?: readonly string[];\n};\nexport type CmsResolution<T> = {\n readonly data: T;\n readonly fallbackFields: readonly string[];\n};\nexport type CmsQuery<T> = {\n readonly name: string;\n readonly query: string;\n readonly params: CmsParams;\n readonly dependencies: CmsDependencies;\n readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;\n};\n\nconst TYPE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;\nconst SCOPE = /^[a-z0-9]{6,12}\\.[a-z][a-z0-9_-]{0,63}$/;\n\nfunction dependenciesCopy(dependencies: CmsDependencies): CmsDependencies {\n if (!dependencies || !Array.isArray(dependencies.types) || dependencies.types.length === 0) {\n throw new TypeError(\"CMS dependencies require document types\");\n }\n const types = [...dependencies.types];\n for (const type of types) {\n if (typeof type !== \"string\" || !TYPE.test(type)) throw new TypeError(\"Invalid CMS document type\");\n }\n if (dependencies.ids !== undefined && !Array.isArray(dependencies.ids)) throw new TypeError(\"Invalid CMS document IDs\");\n const ids = dependencies.ids === undefined ? undefined : [...dependencies.ids];\n for (const id of ids ?? []) {\n if (typeof id !== \"string\" || !ID.test(id) || /^(drafts|versions)\\./.test(id)) {\n throw new TypeError(\"Invalid CMS document ID\");\n }\n }\n if (new Set(types).size + new Set(ids).size > 128) throw new TypeError(\"Too many CMS tags\");\n return Object.freeze({ types: Object.freeze(types), ...(ids === undefined ? {} : { ids: Object.freeze(ids) }) });\n}\n\nexport function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T> {\n if (!query || typeof query.name !== \"string\" || !/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(query.name)\n || typeof query.query !== \"string\" || query.query.trim() === \"\" || typeof query.resolve !== \"function\") {\n throw new TypeError(\"Invalid CMS query configuration\");\n }\n const params = query.params;\n if (!params || typeof params !== \"object\" || (Object.getPrototypeOf(params) !== Object.prototype && Object.getPrototypeOf(params) !== null)) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const copied: Record<string, string | number | boolean | null> = {};\n for (const key of Reflect.ownKeys(params)) {\n const descriptor = Object.getOwnPropertyDescriptor(params, key);\n if (typeof key !== \"string\" || !descriptor || !Object.hasOwn(descriptor, \"value\") || !descriptor.enumerable) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const value: unknown = descriptor.value;\n if (!(value === null || typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value)))) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n Object.defineProperty(copied, key, { value, enumerable: true });\n }\n return Object.freeze({ name: query.name, query: query.query, params: Object.freeze(copied), dependencies: dependenciesCopy(query.dependencies), resolve: query.resolve });\n}\n\nexport function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[] {\n if (typeof scope !== \"string\" || scope.length > 77 || !SCOPE.test(scope)) throw new TypeError(\"Invalid CMS scope\");\n const copied = dependenciesCopy(dependencies);\n const tags = [\n ...[...new Set(copied.types)].sort().map((type) => `cms:${scope}:type:${type}`),\n ...[...new Set(copied.ids ?? [])].sort().map((id) => `cms:${scope}:id:${id}`),\n ];\n return Object.freeze(tags);\n}\n", "import { defineCmsQuery, type CmsQuery } from \"./query.js\";\n\nexport type SiteHero = { readonly heading: string; readonly intro: string };\nexport type TextFieldDefinition = {\n readonly name: string;\n readonly label: string;\n readonly noun: { readonly article: \"a\" | \"an\"; readonly word: string };\n readonly kind: \"single-line\" | \"multi-line\";\n readonly required: boolean;\n readonly minLength: number;\n readonly maxLength: number;\n readonly noTrailingFullStop?: boolean;\n};\nexport type TextDocumentDefinition = {\n readonly key: string;\n readonly documentId: string;\n readonly documentType: string;\n readonly fields: readonly TextFieldDefinition[];\n readonly copy: {\n readonly currentTitle: string;\n readonly editTitle: string;\n readonly empty: string;\n };\n};\nexport type TextValidation =\n | { readonly ok: true; readonly value: Readonly<Record<string, string>> }\n | { readonly ok: false; readonly errors: Readonly<Record<string, string>> };\n\nexport const CMS_CONTRACT_VERSION = 1;\n\nexport const SITE_HERO: TextDocumentDefinition = {\n key: \"hero\",\n documentId: \"siteHero\",\n documentType: \"siteHero\",\n fields: [\n {\n name: \"heading\",\n label: \"Heading\",\n noun: { article: \"a\", word: \"heading\" },\n kind: \"single-line\",\n required: true,\n minLength: 1,\n maxLength: 80,\n noTrailingFullStop: true,\n },\n {\n name: \"intro\",\n label: \"Introduction\",\n noun: { article: \"an\", word: \"introduction\" },\n kind: \"multi-line\",\n required: true,\n minLength: 1,\n maxLength: 320,\n },\n ],\n copy: {\n currentTitle: \"On your site now\",\n editTitle: \"Edit and publish\",\n empty: \"Your site has no hero text yet. Whatever you publish below becomes its first version.\",\n },\n};\n\nfunction fieldError(field: TextFieldDefinition, text: string): string | null {\n const { article, word } = field.noun;\n if (text.length === 0) return field.required ? `Enter ${article} ${word}.` : null;\n const count = [...text].length;\n if (count < field.minLength) return `Make the ${word} at least ${String(field.minLength)} characters. It is ${String(count)} now.`;\n if (count > field.maxLength) return `Keep the ${word} to ${String(field.maxLength)} characters or fewer. It is ${String(count)} now.`;\n if (text.includes(\"\\u2014\")) return `The ${word} contains a long dash. Use a comma, a colon or a short dash instead.`;\n if (field.kind === \"single-line\" && /[\\r\\n]/.test(text)) return `The ${word} must be a single line.`;\n if (field.noTrailingFullStop === true && text.endsWith(\".\")) {\n return `${word.charAt(0).toUpperCase()}${word.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`;\n }\n return null;\n}\n\nexport function validateTextDocument(\n definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>,\n): TextValidation {\n const value: Record<string, string> = {};\n const errors: Record<string, string> = {};\n for (const field of definition.fields) {\n const submitted = Object.hasOwn(raw, field.name) ? raw[field.name] : undefined;\n const text = typeof submitted === \"string\" ? submitted.trim() : \"\";\n const error = fieldError(field, text);\n Object.defineProperty(error === null ? value : errors, field.name, { value: error ?? text, enumerable: true });\n }\n return Object.keys(errors).length > 0 ? { ok: false, errors } : { ok: true, value };\n}\n\nexport function siteHeroQuery(): CmsQuery<SiteHero> {\n return defineCmsQuery({\n name: \"siteHero.v1\", query: '*[_id == $id && _type == \"siteHero\"][0]{heading,intro}',\n params: { id: \"siteHero\" }, dependencies: { types: [\"siteHero\"], ids: [\"siteHero\"] },\n resolve: (raw, fallback) => {\n const local = validateTextDocument(SITE_HERO, fallback);\n if (!local.ok) throw new TypeError(\"Invalid siteHero fallback\");\n const data = { heading: local.value.heading ?? \"\", intro: local.value.intro ?? \"\" };\n if (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) return { data, fallbackFields: [\"$\"] };\n const result = validateTextDocument(SITE_HERO, raw as Readonly<Record<string, unknown>>);\n if (result.ok) return { data: { heading: result.value.heading ?? \"\", intro: result.value.intro ?? \"\" }, fallbackFields: [] };\n const fallbackFields = Object.keys(result.errors);\n for (const field of SITE_HERO.fields) {\n if (!Object.hasOwn(result.errors, field.name)) {\n const submitted = Object.hasOwn(raw, field.name) ? (raw as Record<string, unknown>)[field.name] : undefined;\n if (typeof submitted === \"string\" && (field.name === \"heading\" || field.name === \"intro\")) data[field.name] = submitted.trim();\n }\n }\n return { data, fallbackFields: fallbackFields.length === SITE_HERO.fields.length ? [\"$\"] : fallbackFields };\n },\n });\n}\n"],
5
- "mappings": "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",
6
- "names": ["TYPE", "ID", "SCOPE", "dependenciesCopy", "dependencies", "types", "type", "ids", "id", "defineCmsQuery", "query", "params", "copied", "key", "descriptor", "value", "cmsTags", "scope", "tags", "CMS_CONTRACT_VERSION", "SITE_HERO", "fieldError", "field", "text", "article", "word", "count", "validateTextDocument", "definition", "raw", "value", "errors", "submitted", "error", "siteHeroQuery", "defineCmsQuery", "fallback", "local", "data", "result", "fallbackFields"]
4
+ "sourcesContent": ["/** A-1822 S1 owns this implementation. S0 registers the public signatures. */\nexport type CmsParams = Readonly<Record<string, string | number | boolean | null>>;\nexport type CmsDependencies = {\n readonly types: readonly string[];\n readonly ids?: readonly string[];\n};\nexport type CmsResolution<T> = {\n readonly data: T;\n readonly fallbackFields: readonly string[];\n readonly warnings?: readonly \"siteHero.layout.defaulted\"[];\n};\nexport type CmsQuery<T> = {\n readonly name: string;\n readonly query: string;\n readonly params: CmsParams;\n readonly dependencies: CmsDependencies;\n readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;\n};\n\nconst TYPE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;\nconst ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;\nconst SCOPE = /^[a-z0-9]{6,12}\\.[a-z][a-z0-9_-]{0,63}$/;\n\nfunction dependenciesCopy(dependencies: CmsDependencies): CmsDependencies {\n if (!dependencies || !Array.isArray(dependencies.types) || dependencies.types.length === 0) {\n throw new TypeError(\"CMS dependencies require document types\");\n }\n const types = [...dependencies.types];\n for (const type of types) {\n if (typeof type !== \"string\" || !TYPE.test(type)) throw new TypeError(\"Invalid CMS document type\");\n }\n if (dependencies.ids !== undefined && !Array.isArray(dependencies.ids)) throw new TypeError(\"Invalid CMS document IDs\");\n const ids = dependencies.ids === undefined ? undefined : [...dependencies.ids];\n for (const id of ids ?? []) {\n if (typeof id !== \"string\" || !ID.test(id) || /^(drafts|versions)\\./.test(id)) {\n throw new TypeError(\"Invalid CMS document ID\");\n }\n }\n if (new Set(types).size + new Set(ids).size > 128) throw new TypeError(\"Too many CMS tags\");\n return Object.freeze({ types: Object.freeze(types), ...(ids === undefined ? {} : { ids: Object.freeze(ids) }) });\n}\n\nexport function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T> {\n if (!query || typeof query.name !== \"string\" || !/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(query.name)\n || typeof query.query !== \"string\" || query.query.trim() === \"\" || typeof query.resolve !== \"function\") {\n throw new TypeError(\"Invalid CMS query configuration\");\n }\n const params = query.params;\n if (!params || typeof params !== \"object\" || (Object.getPrototypeOf(params) !== Object.prototype && Object.getPrototypeOf(params) !== null)) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const copied: Record<string, string | number | boolean | null> = {};\n for (const key of Reflect.ownKeys(params)) {\n const descriptor = Object.getOwnPropertyDescriptor(params, key);\n if (typeof key !== \"string\" || !descriptor || !Object.hasOwn(descriptor, \"value\") || !descriptor.enumerable) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n const value: unknown = descriptor.value;\n if (!(value === null || typeof value === \"string\" || typeof value === \"boolean\" || (typeof value === \"number\" && Number.isFinite(value)))) {\n throw new TypeError(\"CMS params must be plain JSON scalars\");\n }\n Object.defineProperty(copied, key, { value, enumerable: true });\n }\n return Object.freeze({ name: query.name, query: query.query, params: Object.freeze(copied), dependencies: dependenciesCopy(query.dependencies), resolve: query.resolve });\n}\n\nexport function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[] {\n if (typeof scope !== \"string\" || scope.length > 77 || !SCOPE.test(scope)) throw new TypeError(\"Invalid CMS scope\");\n const copied = dependenciesCopy(dependencies);\n const tags = [\n ...[...new Set(copied.types)].sort().map((type) => `cms:${scope}:type:${type}`),\n ...[...new Set(copied.ids ?? [])].sort().map((id) => `cms:${scope}:id:${id}`),\n ];\n return Object.freeze(tags);\n}\n", "import { defineCmsQuery, type CmsQuery, type CmsResolution } from \"./query.js\";\n\nexport const SITE_HERO_LAYOUTS = [\"columns\", \"rows\"] as const;\nexport const SITE_HERO_TAGLINE_MAX_LENGTH = 36;\nexport const SITE_HERO_LAYOUT_WARNING = \"siteHero.layout.defaulted\" as const;\nexport type SiteHeroLayout = typeof SITE_HERO_LAYOUTS[number];\nexport type SiteHeroTagline = { readonly key: string; readonly text: string };\n/** Optional additions preserve existing heading/intro-only consumer fallbacks. */\nexport type SiteHero = {\n readonly heading: string;\n readonly intro: string;\n readonly layout?: SiteHeroLayout;\n readonly taglines?: readonly SiteHeroTagline[];\n};\nexport type ParsedSiteHero = SiteHero & {\n readonly layout: SiteHeroLayout;\n readonly taglines: readonly SiteHeroTagline[];\n};\nexport type TextFieldDefinition = {\n readonly name: string;\n readonly label: string;\n readonly noun: { readonly article: \"a\" | \"an\"; readonly word: string };\n readonly kind: \"single-line\" | \"multi-line\";\n readonly required: boolean;\n readonly minLength: number;\n readonly maxLength: number;\n readonly noTrailingFullStop?: boolean;\n};\nexport type TextDocumentDefinition = {\n readonly key: string;\n readonly documentId: string;\n readonly documentType: string;\n readonly fields: readonly TextFieldDefinition[];\n readonly copy: {\n readonly currentTitle: string;\n readonly editTitle: string;\n readonly empty: string;\n };\n};\nexport type TextValidation =\n | { readonly ok: true; readonly value: Readonly<Record<string, string>> }\n | { readonly ok: false; readonly errors: Readonly<Record<string, string>> };\n\nexport const CMS_CONTRACT_VERSION = 1;\n\nexport const SITE_HERO: TextDocumentDefinition = {\n key: \"hero\",\n documentId: \"siteHero\",\n documentType: \"siteHero\",\n fields: [\n {\n name: \"heading\",\n label: \"Heading\",\n noun: { article: \"a\", word: \"heading\" },\n kind: \"single-line\",\n required: true,\n minLength: 1,\n maxLength: 80,\n noTrailingFullStop: true,\n },\n {\n name: \"intro\",\n label: \"Introduction\",\n noun: { article: \"an\", word: \"introduction\" },\n kind: \"multi-line\",\n required: true,\n minLength: 1,\n maxLength: 320,\n },\n ],\n copy: {\n currentTitle: \"On your site now\",\n editTitle: \"Edit and publish\",\n empty: \"Your site has no hero text yet. Whatever you publish below becomes its first version.\",\n },\n};\n\nfunction fieldError(field: TextFieldDefinition, text: string): string | null {\n const { article, word } = field.noun;\n if (text.length === 0) return field.required ? `Enter ${article} ${word}.` : null;\n const count = [...text].length;\n if (count < field.minLength) return `Make the ${word} at least ${String(field.minLength)} characters. It is ${String(count)} now.`;\n if (count > field.maxLength) return `Keep the ${word} to ${String(field.maxLength)} characters or fewer. It is ${String(count)} now.`;\n if (text.includes(\"\\u2014\")) return `The ${word} contains a long dash. Use a comma, a colon or a short dash instead.`;\n if (field.kind === \"single-line\" && /[\\r\\n]/.test(text)) return `The ${word} must be a single line.`;\n if (field.noTrailingFullStop === true && text.endsWith(\".\")) {\n return `${word.charAt(0).toUpperCase()}${word.slice(1)}s on your site do not end with a full stop. Remove the last full stop.`;\n }\n return null;\n}\n\nexport function validateTextDocument(\n definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>,\n): TextValidation {\n const value: Record<string, string> = {};\n const errors: Record<string, string> = {};\n for (const field of definition.fields) {\n const submitted = Object.hasOwn(raw, field.name) ? raw[field.name] : undefined;\n const text = typeof submitted === \"string\" ? submitted.trim() : \"\";\n const error = fieldError(field, text);\n Object.defineProperty(error === null ? value : errors, field.name, { value: error ?? text, enumerable: true });\n }\n return Object.keys(errors).length > 0 ? { ok: false, errors } : { ok: true, value };\n}\n\n/** Shared with the schema adapter; no provider metadata is returned. */\nexport function validateSiteHeroTaglines(raw: unknown):\n | { readonly ok: true; readonly value: readonly SiteHeroTagline[] }\n | { readonly ok: false; readonly error: string } {\n if (!Array.isArray(raw)) return { ok: false, error: \"Enter a list of taglines.\" };\n const heading = SITE_HERO.fields[0];\n if (!heading) throw new TypeError(\"Missing siteHero heading definition\");\n const field = { ...heading, name: \"text\", noun: { article: \"a\", word: \"tagline\" } as const,\n maxLength: SITE_HERO_TAGLINE_MAX_LENGTH };\n const value: SiteHeroTagline[] = [];\n const keys = new Set<string>();\n for (const item of raw as unknown[]) {\n if (!item || typeof item !== \"object\" || Array.isArray(item)) return { ok: false, error: \"Enter a key and text for each tagline.\" };\n const record = item as Record<string, unknown>;\n const key = Object.hasOwn(record, \"key\") ? record.key : undefined;\n if (typeof key !== \"string\" || !/^[a-z][a-z0-9_-]{0,31}$/.test(key)) {\n return { ok: false, error: \"Use a lowercase key of 1 to 32 letters, numbers, short dashes or underscores, starting with a letter.\" };\n }\n if (keys.has(key)) return { ok: false, error: \"Use each tagline key only once.\" };\n const text = validateTextDocument({ ...SITE_HERO, fields: [field] }, record);\n if (!text.ok) return { ok: false, error: text.errors.text ?? \"Invalid tagline.\" };\n keys.add(key);\n value.push({ key, text: text.value.text ?? \"\" });\n }\n return { ok: true, value };\n}\n\nfunction isLayout(value: unknown): value is SiteHeroLayout {\n return SITE_HERO_LAYOUTS.some((layout) => value === layout);\n}\n\n/** Strict per-field resolution: an invalid list never partially changes keyed copy. */\nexport function parseSiteHero(raw: unknown, fallback: SiteHero): CmsResolution<ParsedSiteHero> {\n const local = validateTextDocument(SITE_HERO, fallback);\n const localTaglines = validateSiteHeroTaglines(fallback.taglines ?? []);\n if (!local.ok || !localTaglines.ok || (fallback.layout !== undefined && !isLayout(fallback.layout))) {\n throw new TypeError(\"Invalid siteHero fallback\");\n }\n const data: { heading: string; intro: string; layout: SiteHeroLayout; taglines: readonly SiteHeroTagline[] } = {\n heading: local.value.heading ?? \"\", intro: local.value.intro ?? \"\",\n layout: fallback.layout ?? \"columns\", taglines: localTaglines.value,\n };\n if (raw === null || typeof raw !== \"object\" || Array.isArray(raw)) return { data, fallbackFields: [\"$\"] };\n const record = raw as Readonly<Record<string, unknown>>;\n const text = validateTextDocument(SITE_HERO, record);\n const fallbackFields: string[] = text.ok ? [] : Object.keys(text.errors);\n for (const field of SITE_HERO.fields) {\n if (!fallbackFields.includes(field.name)) {\n const value = text.ok ? text.value[field.name] : record[field.name];\n if (typeof value === \"string\" && (field.name === \"heading\" || field.name === \"intro\")) data[field.name] = value.trim();\n }\n }\n const layout = Object.hasOwn(record, \"layout\") ? record.layout : undefined;\n const warnings: (typeof SITE_HERO_LAYOUT_WARNING)[] = [];\n if (isLayout(layout)) data.layout = layout;\n else {\n data.layout = \"columns\";\n fallbackFields.push(\"layout\");\n warnings.push(SITE_HERO_LAYOUT_WARNING);\n }\n const taglines = validateSiteHeroTaglines(Object.hasOwn(record, \"taglines\") ? record.taglines : undefined);\n if (taglines.ok) data.taglines = taglines.value;\n else fallbackFields.push(\"taglines\");\n return { data, fallbackFields: fallbackFields.length === SITE_HERO.fields.length + 2 ? [\"$\"] : fallbackFields,\n ...(warnings.length > 0 ? { warnings } : {}) };\n}\n\nexport function siteHeroQuery(): CmsQuery<SiteHero> {\n return defineCmsQuery<SiteHero>({\n name: \"siteHero.v1\", query: '*[_id == $id && _type == \"siteHero\"][0]{heading,intro,layout,taglines}',\n params: { id: \"siteHero\" }, dependencies: { types: [\"siteHero\"], ids: [\"siteHero\"] },\n resolve: parseSiteHero,\n });\n}\n"],
5
+ "mappings": "AAmBA,IAAMA,EAAO,+BACPC,EAAK,qCACLC,EAAQ,0CAEd,SAASC,EAAiBC,EAAgD,CACxE,GAAI,CAACA,GAAgB,CAAC,MAAM,QAAQA,EAAa,KAAK,GAAKA,EAAa,MAAM,SAAW,EACvF,MAAM,IAAI,UAAU,yCAAyC,EAE/D,IAAMC,EAAQ,CAAC,GAAGD,EAAa,KAAK,EACpC,QAAWE,KAAQD,EACjB,GAAI,OAAOC,GAAS,UAAY,CAACN,EAAK,KAAKM,CAAI,EAAG,MAAM,IAAI,UAAU,2BAA2B,EAEnG,GAAIF,EAAa,MAAQ,QAAa,CAAC,MAAM,QAAQA,EAAa,GAAG,EAAG,MAAM,IAAI,UAAU,0BAA0B,EACtH,IAAMG,EAAMH,EAAa,MAAQ,OAAY,OAAY,CAAC,GAAGA,EAAa,GAAG,EAC7E,QAAWI,KAAMD,GAAO,CAAC,EACvB,GAAI,OAAOC,GAAO,UAAY,CAACP,EAAG,KAAKO,CAAE,GAAK,uBAAuB,KAAKA,CAAE,EAC1E,MAAM,IAAI,UAAU,yBAAyB,EAGjD,GAAI,IAAI,IAAIH,CAAK,EAAE,KAAO,IAAI,IAAIE,CAAG,EAAE,KAAO,IAAK,MAAM,IAAI,UAAU,mBAAmB,EAC1F,OAAO,OAAO,OAAO,CAAE,MAAO,OAAO,OAAOF,CAAK,EAAG,GAAIE,IAAQ,OAAY,CAAC,EAAI,CAAE,IAAK,OAAO,OAAOA,CAAG,CAAE,CAAG,CAAC,CACjH,CAEO,SAASE,EAAkBC,EAAiC,CACjE,GAAI,CAACA,GAAS,OAAOA,EAAM,MAAS,UAAY,CAAC,kCAAkC,KAAKA,EAAM,IAAI,GAC7F,OAAOA,EAAM,OAAU,UAAYA,EAAM,MAAM,KAAK,IAAM,IAAM,OAAOA,EAAM,SAAY,WAC5F,MAAM,IAAI,UAAU,iCAAiC,EAEvD,IAAMC,EAASD,EAAM,OACrB,GAAI,CAACC,GAAU,OAAOA,GAAW,UAAa,OAAO,eAAeA,CAAM,IAAM,OAAO,WAAa,OAAO,eAAeA,CAAM,IAAM,KACpI,MAAM,IAAI,UAAU,uCAAuC,EAE7D,IAAMC,EAA2D,CAAC,EAClE,QAAWC,KAAO,QAAQ,QAAQF,CAAM,EAAG,CACzC,IAAMG,EAAa,OAAO,yBAAyBH,EAAQE,CAAG,EAC9D,GAAI,OAAOA,GAAQ,UAAY,CAACC,GAAc,CAAC,OAAO,OAAOA,EAAY,OAAO,GAAK,CAACA,EAAW,WAC/F,MAAM,IAAI,UAAU,uCAAuC,EAE7D,IAAMC,EAAiBD,EAAW,MAClC,GAAI,EAAEC,IAAU,MAAQ,OAAOA,GAAU,UAAY,OAAOA,GAAU,WAAc,OAAOA,GAAU,UAAY,OAAO,SAASA,CAAK,GACpI,MAAM,IAAI,UAAU,uCAAuC,EAE7D,OAAO,eAAeH,EAAQC,EAAK,CAAE,MAAAE,EAAO,WAAY,EAAK,CAAC,CAChE,CACA,OAAO,OAAO,OAAO,CAAE,KAAML,EAAM,KAAM,MAAOA,EAAM,MAAO,OAAQ,OAAO,OAAOE,CAAM,EAAG,aAAcT,EAAiBO,EAAM,YAAY,EAAG,QAASA,EAAM,OAAQ,CAAC,CAC1K,CAEO,SAASM,EAAQC,EAAeb,EAAkD,CACvF,GAAI,OAAOa,GAAU,UAAYA,EAAM,OAAS,IAAM,CAACf,EAAM,KAAKe,CAAK,EAAG,MAAM,IAAI,UAAU,mBAAmB,EACjH,IAAML,EAAST,EAAiBC,CAAY,EACtCc,EAAO,CACX,GAAG,CAAC,GAAG,IAAI,IAAIN,EAAO,KAAK,CAAC,EAAE,KAAK,EAAE,IAAKN,GAAS,OAAOW,CAAK,SAASX,CAAI,EAAE,EAC9E,GAAG,CAAC,GAAG,IAAI,IAAIM,EAAO,KAAO,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAKJ,GAAO,OAAOS,CAAK,OAAOT,CAAE,EAAE,CAC9E,EACA,OAAO,OAAO,OAAOU,CAAI,CAC3B,CCxEO,IAAMC,EAAoB,CAAC,UAAW,MAAM,EACtCC,EAA+B,GAC/BC,EAA2B,4BAuC3BC,EAAuB,EAEvBC,EAAoC,CAC/C,IAAK,OACL,WAAY,WACZ,aAAc,WACd,OAAQ,CACN,CACE,KAAM,UACN,MAAO,UACP,KAAM,CAAE,QAAS,IAAK,KAAM,SAAU,EACtC,KAAM,cACN,SAAU,GACV,UAAW,EACX,UAAW,GACX,mBAAoB,EACtB,EACA,CACE,KAAM,QACN,MAAO,eACP,KAAM,CAAE,QAAS,KAAM,KAAM,cAAe,EAC5C,KAAM,aACN,SAAU,GACV,UAAW,EACX,UAAW,GACb,CACF,EACA,KAAM,CACJ,aAAc,mBACd,UAAW,mBACX,MAAO,uFACT,CACF,EAEA,SAASC,EAAWC,EAA4BC,EAA6B,CAC3E,GAAM,CAAE,QAAAC,EAAS,KAAAC,CAAK,EAAIH,EAAM,KAChC,GAAIC,EAAK,SAAW,EAAG,OAAOD,EAAM,SAAW,SAASE,CAAO,IAAIC,CAAI,IAAM,KAC7E,IAAMC,EAAQ,CAAC,GAAGH,CAAI,EAAE,OACxB,OAAIG,EAAQJ,EAAM,UAAkB,YAAYG,CAAI,aAAa,OAAOH,EAAM,SAAS,CAAC,sBAAsB,OAAOI,CAAK,CAAC,QACvHA,EAAQJ,EAAM,UAAkB,YAAYG,CAAI,OAAO,OAAOH,EAAM,SAAS,CAAC,+BAA+B,OAAOI,CAAK,CAAC,QAC1HH,EAAK,SAAS,QAAQ,EAAU,OAAOE,CAAI,uEAC3CH,EAAM,OAAS,eAAiB,SAAS,KAAKC,CAAI,EAAU,OAAOE,CAAI,0BACvEH,EAAM,qBAAuB,IAAQC,EAAK,SAAS,GAAG,EACjD,GAAGE,EAAK,OAAO,CAAC,EAAE,YAAY,CAAC,GAAGA,EAAK,MAAM,CAAC,CAAC,yEAEjD,IACT,CAEO,SAASE,EACdC,EAAoCC,EACpB,CAChB,IAAMC,EAAgC,CAAC,EACjCC,EAAiC,CAAC,EACxC,QAAWT,KAASM,EAAW,OAAQ,CACrC,IAAMI,EAAY,OAAO,OAAOH,EAAKP,EAAM,IAAI,EAAIO,EAAIP,EAAM,IAAI,EAAI,OAC/DC,EAAO,OAAOS,GAAc,SAAWA,EAAU,KAAK,EAAI,GAC1DC,EAAQZ,EAAWC,EAAOC,CAAI,EACpC,OAAO,eAAeU,IAAU,KAAOH,EAAQC,EAAQT,EAAM,KAAM,CAAE,MAAOW,GAASV,EAAM,WAAY,EAAK,CAAC,CAC/G,CACA,OAAO,OAAO,KAAKQ,CAAM,EAAE,OAAS,EAAI,CAAE,GAAI,GAAO,OAAAA,CAAO,EAAI,CAAE,GAAI,GAAM,MAAAD,CAAM,CACpF,CAGO,SAASI,EAAyBL,EAEU,CACjD,GAAI,CAAC,MAAM,QAAQA,CAAG,EAAG,MAAO,CAAE,GAAI,GAAO,MAAO,2BAA4B,EAChF,IAAMM,EAAUf,EAAU,OAAO,CAAC,EAClC,GAAI,CAACe,EAAS,MAAM,IAAI,UAAU,qCAAqC,EACvE,IAAMb,EAAQ,CAAE,GAAGa,EAAS,KAAM,OAAQ,KAAM,CAAE,QAAS,IAAK,KAAM,SAAU,EAC9E,UAAWlB,CAA6B,EACpCa,EAA2B,CAAC,EAC5BM,EAAO,IAAI,IACjB,QAAWC,KAAQR,EAAkB,CACnC,GAAI,CAACQ,GAAQ,OAAOA,GAAS,UAAY,MAAM,QAAQA,CAAI,EAAG,MAAO,CAAE,GAAI,GAAO,MAAO,wCAAyC,EAClI,IAAMC,EAASD,EACTE,EAAM,OAAO,OAAOD,EAAQ,KAAK,EAAIA,EAAO,IAAM,OACxD,GAAI,OAAOC,GAAQ,UAAY,CAAC,0BAA0B,KAAKA,CAAG,EAChE,MAAO,CAAE,GAAI,GAAO,MAAO,uGAAwG,EAErI,GAAIH,EAAK,IAAIG,CAAG,EAAG,MAAO,CAAE,GAAI,GAAO,MAAO,iCAAkC,EAChF,IAAMhB,EAAOI,EAAqB,CAAE,GAAGP,EAAW,OAAQ,CAACE,CAAK,CAAE,EAAGgB,CAAM,EAC3E,GAAI,CAACf,EAAK,GAAI,MAAO,CAAE,GAAI,GAAO,MAAOA,EAAK,OAAO,MAAQ,kBAAmB,EAChFa,EAAK,IAAIG,CAAG,EACZT,EAAM,KAAK,CAAE,IAAAS,EAAK,KAAMhB,EAAK,MAAM,MAAQ,EAAG,CAAC,CACjD,CACA,MAAO,CAAE,GAAI,GAAM,MAAAO,CAAM,CAC3B,CAEA,SAASU,EAASV,EAAyC,CACzD,OAAOd,EAAkB,KAAMyB,GAAWX,IAAUW,CAAM,CAC5D,CAGO,SAASC,EAAcb,EAAcc,EAAmD,CAC7F,IAAMC,EAAQjB,EAAqBP,EAAWuB,CAAQ,EAChDE,EAAgBX,EAAyBS,EAAS,UAAY,CAAC,CAAC,EACtE,GAAI,CAACC,EAAM,IAAM,CAACC,EAAc,IAAOF,EAAS,SAAW,QAAa,CAACH,EAASG,EAAS,MAAM,EAC/F,MAAM,IAAI,UAAU,2BAA2B,EAEjD,IAAMG,EAAyG,CAC7G,QAASF,EAAM,MAAM,SAAW,GAAI,MAAOA,EAAM,MAAM,OAAS,GAChE,OAAQD,EAAS,QAAU,UAAW,SAAUE,EAAc,KAChE,EACA,GAAIhB,IAAQ,MAAQ,OAAOA,GAAQ,UAAY,MAAM,QAAQA,CAAG,EAAG,MAAO,CAAE,KAAAiB,EAAM,eAAgB,CAAC,GAAG,CAAE,EACxG,IAAMR,EAAST,EACTN,EAAOI,EAAqBP,EAAWkB,CAAM,EAC7CS,EAA2BxB,EAAK,GAAK,CAAC,EAAI,OAAO,KAAKA,EAAK,MAAM,EACvE,QAAWD,KAASF,EAAU,OAC5B,GAAI,CAAC2B,EAAe,SAASzB,EAAM,IAAI,EAAG,CACxC,IAAMQ,EAAQP,EAAK,GAAKA,EAAK,MAAMD,EAAM,IAAI,EAAIgB,EAAOhB,EAAM,IAAI,EAC9D,OAAOQ,GAAU,WAAaR,EAAM,OAAS,WAAaA,EAAM,OAAS,WAAUwB,EAAKxB,EAAM,IAAI,EAAIQ,EAAM,KAAK,EACvH,CAEF,IAAMW,EAAS,OAAO,OAAOH,EAAQ,QAAQ,EAAIA,EAAO,OAAS,OAC3DU,EAAgD,CAAC,EACnDR,EAASC,CAAM,EAAGK,EAAK,OAASL,GAElCK,EAAK,OAAS,UACdC,EAAe,KAAK,QAAQ,EAC5BC,EAAS,KAAK9B,CAAwB,GAExC,IAAM+B,EAAWf,EAAyB,OAAO,OAAOI,EAAQ,UAAU,EAAIA,EAAO,SAAW,MAAS,EACzG,OAAIW,EAAS,GAAIH,EAAK,SAAWG,EAAS,MACrCF,EAAe,KAAK,UAAU,EAC5B,CAAE,KAAAD,EAAM,eAAgBC,EAAe,SAAW3B,EAAU,OAAO,OAAS,EAAI,CAAC,GAAG,EAAI2B,EAC7F,GAAIC,EAAS,OAAS,EAAI,CAAE,SAAAA,CAAS,EAAI,CAAC,CAAG,CACjD,CAEO,SAASE,GAAoC,CAClD,OAAOC,EAAyB,CAC9B,KAAM,cAAe,MAAO,yEAC5B,OAAQ,CAAE,GAAI,UAAW,EAAG,aAAc,CAAE,MAAO,CAAC,UAAU,EAAG,IAAK,CAAC,UAAU,CAAE,EACnF,QAAST,CACX,CAAC,CACH",
6
+ "names": ["TYPE", "ID", "SCOPE", "dependenciesCopy", "dependencies", "types", "type", "ids", "id", "defineCmsQuery", "query", "params", "copied", "key", "descriptor", "value", "cmsTags", "scope", "tags", "SITE_HERO_LAYOUTS", "SITE_HERO_TAGLINE_MAX_LENGTH", "SITE_HERO_LAYOUT_WARNING", "CMS_CONTRACT_VERSION", "SITE_HERO", "fieldError", "field", "text", "article", "word", "count", "validateTextDocument", "definition", "raw", "value", "errors", "submitted", "error", "validateSiteHeroTaglines", "heading", "keys", "item", "record", "key", "isLayout", "layout", "parseSiteHero", "fallback", "local", "localTaglines", "data", "fallbackFields", "warnings", "taglines", "siteHeroQuery", "defineCmsQuery"]
7
7
  }
package/dist/next.cjs CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";var R=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var F=(e,r)=>{for(var t in r)R(e,t,{get:r[t],enumerable:!0})},$=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of z(r))!N.call(e,o)&&o!==t&&R(e,o,{get:()=>r[o],enumerable:!(n=j(r,o))||n.enumerable});return e};var U=e=>$(R({},"__esModule",{value:!0}),e);var K={};F(K,{createNextCmsReader:()=>O,createRevalidateRoute:()=>D});module.exports=U(K);var de=require("server-only");var L=/^[A-Za-z][A-Za-z0-9_]{0,63}$/,H=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,Z=/^[a-z0-9]{6,12}\.[a-z][a-z0-9_-]{0,63}$/;function E(e){if(!e||!Array.isArray(e.types)||e.types.length===0)throw new TypeError("CMS dependencies require document types");let r=[...e.types];for(let n of r)if(typeof n!="string"||!L.test(n))throw new TypeError("Invalid CMS document type");if(e.ids!==void 0&&!Array.isArray(e.ids))throw new TypeError("Invalid CMS document IDs");let t=e.ids===void 0?void 0:[...e.ids];for(let n of t??[])if(typeof n!="string"||!H.test(n)||/^(drafts|versions)\./.test(n))throw new TypeError("Invalid CMS document ID");if(new Set(r).size+new Set(t).size>128)throw new TypeError("Too many CMS tags");return Object.freeze({types:Object.freeze(r),...t===void 0?{}:{ids:Object.freeze(t)}})}function k(e){if(!e||typeof e.name!="string"||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(e.name)||typeof e.query!="string"||e.query.trim()===""||typeof e.resolve!="function")throw new TypeError("Invalid CMS query configuration");let r=e.params;if(!r||typeof r!="object"||Object.getPrototypeOf(r)!==Object.prototype&&Object.getPrototypeOf(r)!==null)throw new TypeError("CMS params must be plain JSON scalars");let t={};for(let n of Reflect.ownKeys(r)){let o=Object.getOwnPropertyDescriptor(r,n);if(typeof n!="string"||!o||!Object.hasOwn(o,"value")||!o.enumerable)throw new TypeError("CMS params must be plain JSON scalars");let a=o.value;if(!(a===null||typeof a=="string"||typeof a=="boolean"||typeof a=="number"&&Number.isFinite(a)))throw new TypeError("CMS params must be plain JSON scalars");Object.defineProperty(t,n,{value:a,enumerable:!0})}return Object.freeze({name:e.name,query:e.query,params:Object.freeze(t),dependencies:E(e.dependencies),resolve:e.resolve})}function b(e,r){if(typeof e!="string"||e.length>77||!Z.test(e))throw new TypeError("Invalid CMS scope");let t=E(r),n=[...[...new Set(t.types)].sort().map(o=>`cms:${e}:type:${o}`),...[...new Set(t.ids??[])].sort().map(o=>`cms:${e}:id:${o}`)];return Object.freeze(n)}function A(e){if(!e||!Object.hasOwn(e,"data")||!Array.isArray(e.fallbackFields)||![...e.fallbackFields].every(r=>typeof r=="string"&&(r==="$"||/^[A-Za-z][A-Za-z0-9_.[\]-]{0,127}$/.test(r))))throw new TypeError("Invalid CMS resolution");return{data:e.data,fallbackFields:Object.freeze([...new Set(e.fallbackFields)])}}function S(e){let r=e?.revalidateSeconds??3600;if(!Number.isSafeInteger(r)||r<3600||!e?.adapter||typeof e.adapter.read!="function"||e.onDiagnostic!==void 0&&typeof e.onDiagnostic!="function")throw new TypeError("Invalid CMS reader configuration");let t=e.adapter;b(t.scope,{types:["ScopeValidation"]});let n=o=>{try{e.onDiagnostic?e.onDiagnostic(o):console.warn(JSON.stringify(o))}catch{}};return{async read(o,a){let s,l,d;try{if(s=k(o),d=b(t.scope,s.dependencies),!a||!Object.hasOwn(a,"fallback"))throw new TypeError;l=A(s.resolve(null,a.fallback))}catch{throw new TypeError("Invalid CMS query or fallback configuration")}let m=(f,c)=>(n({event:"cms.fallback",query:s.name,reason:f,fields:["$"],...c===void 0?{}:{status:c}}),{data:l.data,source:"fallback",fallbackFields:["$"],reason:f}),i;try{i=await t.read({name:s.name,query:s.query,params:s.params},{tags:d,revalidateSeconds:r})}catch{return m("network")}if(!i.ok){let c=["configuration","network","timeout","rate-limit","upstream","plan-limit","permission","malformed"].includes(i.reason)?i.reason:"malformed",T=Number.isInteger(i.status)&&(i.status??0)>=100&&(i.status??0)<=599?i.status:void 0;return m(c,T)}if(i.value===null||i.value===void 0)return m("missing");let y;try{y=A(s.resolve(i.value,a.fallback))}catch{return m("malformed")}return y.fallbackFields.includes("$")?m("invalid-field"):y.fallbackFields.length>0?(n({event:"cms.partial-fallback",query:s.name,reason:"invalid-field",fields:y.fallbackFields}),{...y,source:"mixed",reason:"invalid-field"}):{...y,source:"cms"}}}}var O=S;var _=require("next/cache.js");var h="sanity-webhook-signature",Q=/^t=(\d+)[, ]+v1=([^, ]+)$/;var I=new TextEncoder;function V(e){return crypto.subtle.importKey("raw",I.encode(e),{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"])}function B(e){if(!/^[A-Za-z0-9_-]+={0,2}$/.test(e))return null;let r=e.replace(/-/g,"+").replace(/_/g,"/");try{let t=atob(r),n=new Uint8Array(t.length);for(let o=0;o<t.length;o+=1)n[o]=t.charCodeAt(o);return n}catch{return null}}async function x(e){let{secret:r,rawBody:t,headers:n}=e,o=e.now??Date.now(),a=e.toleranceMs??3e5;if(!r||r.length===0)return{ok:!1,reason:"no-secret"};let s=n.get(h);if(!s)return{ok:!1,reason:"no-signature"};let l=Q.exec(s.trim());if(l===null)return{ok:!1,reason:"malformed-signature"};let d=Number(l[1]),m=l[2]??"";if(!Number.isSafeInteger(d))return{ok:!1,reason:"malformed-signature"};if(d<16094592e5)return{ok:!1,reason:"stale-timestamp"};if(Math.abs(o-d)>a)return{ok:!1,reason:"stale-timestamp"};let i=B(m);if(i===null)return{ok:!1,reason:"malformed-signature"};let y=await V(r);return await crypto.subtle.verify("HMAC",y,i,I.encode(`${d}.${t}`))?{ok:!0}:{ok:!1,reason:"bad-signature"}}var q=16*1024,W=1500,Y=new TextEncoder;function u(e,r,t={},n=!1){return new Response(n?null:JSON.stringify(r),{status:e,headers:{"Content-Type":"application/json","Cache-Control":"no-store",...t}})}function J(e,r){if(!r||typeof r!="object"||Array.isArray(r)||Object.keys(r).length===0)throw new TypeError("Invalid CMS invalidation mapping");let t=Object.create(null);for(let n of Reflect.ownKeys(r)){let o=Object.getOwnPropertyDescriptor(r,n);if(typeof n!="string"||!o?.enumerable||!Object.hasOwn(o,"value"))throw new TypeError("Invalid CMS invalidation mapping");let a=o.value;if(!Array.isArray(a)||!a.includes(n))throw new TypeError("Invalid CMS invalidation mapping");b(e,{types:a,ids:["validation"]}),t[n]=Object.freeze([...a])}for(let n of Object.values(t))if(n.some(o=>!Object.hasOwn(t,o)))throw new TypeError("Invalid CMS invalidation mapping");return Object.freeze(t)}function M(e){return typeof e=="string"&&e.trim()!==""&&Y.encode(e).byteLength>=32}var w=class extends Error{constructor(t){super("Invalid CMS webhook body");this.status=t}status};async function G(e){let r=e.body?.getReader();if(!r)return"";let t=new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}),n,o=new Promise((a,s)=>{n=setTimeout(()=>s(new w(400)),W)});try{let a=0,s="";for(;;){let{done:l,value:d}=await Promise.race([r.read(),o]);if(l)return s+t.decode();if(a+=d.byteLength,a>q)throw new w(413);s+=t.decode(d,{stream:!0})}}catch(a){throw r.cancel().catch(()=>{}),a}finally{clearTimeout(n),r.releaseLock()}}function D(e){let r=e.scope,t=J(r,e.typeToTags),n=e.secretEnv??"SANITY_REVALIDATE_SECRET",o=e.previousSecretEnv??"SANITY_REVALIDATE_SECRET_PREVIOUS",a=e.env??(()=>process.env),s=e.now??Date.now,l=async d=>{if(d.method!=="POST")return u(405,{error:"Method not allowed"},{Allow:"POST"},d.method==="HEAD");let m,i;try{let p=a(),C=p[n],g=p[o];if(!M(C)||g!==void 0&&!M(g))throw new Error;m=C,i=g}catch{return u(503,{error:"COULD NOT ANSWER: revalidation configuration unavailable"})}let y=d.headers.get(h);if(!y||y.length>512||!/^t=\d+[, ]+v1=[A-Za-z0-9_-]+={0,2}$/.test(y.trim()))return u(401,{error:"Unauthorized"});let f;try{f=await G(d)}catch(p){return p instanceof w&&p.status===413?u(413,{error:"Payload too large"}):u(400,{error:"Invalid body"})}try{let p=s();if(!Number.isFinite(p))throw new Error;if(!(await Promise.all([m,...i===void 0?[]:[i]].map(g=>x({secret:g,rawBody:f,headers:d.headers,now:p})))).some(g=>g.ok))return u(401,{error:"Unauthorized"})}catch{return u(401,{error:"Unauthorized"})}let c;try{c=JSON.parse(f)}catch{return u(400,{error:"Invalid payload"})}if(!c||typeof c!="object"||Array.isArray(c)||Object.keys(c).length!==2||!Object.hasOwn(c,"_type")||!Object.hasOwn(c,"_id"))return u(400,{error:"Invalid payload"});let{_type:T,_id:v}=c;if(typeof T!="string"||!/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(T)||typeof v!="string"||!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(v))return u(400,{error:"Invalid payload"});if(!Object.hasOwn(t,T)||/^(drafts|versions)\./.test(v))return u(400,{error:"Unsupported document"});let P=b(r,{types:t[T],ids:[v]});try{for(let p of P)(0,_.revalidateTag)(p,{expire:0})}catch{return u(500,{error:"Could not revalidate"})}return u(200,{revalidated:!0})};return Object.freeze({POST:l,GET:l,HEAD:l,PUT:l,PATCH:l,DELETE:l,OPTIONS:l})}0&&(module.exports={createNextCmsReader,createRevalidateRoute});
1
+ "use strict";var R=Object.defineProperty;var j=Object.getOwnPropertyDescriptor;var z=Object.getOwnPropertyNames;var N=Object.prototype.hasOwnProperty;var F=(e,r)=>{for(var t in r)R(e,t,{get:r[t],enumerable:!0})},$=(e,r,t,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let o of z(r))!N.call(e,o)&&o!==t&&R(e,o,{get:()=>r[o],enumerable:!(n=j(r,o))||n.enumerable});return e};var U=e=>$(R({},"__esModule",{value:!0}),e);var K={};F(K,{createNextCmsReader:()=>O,createRevalidateRoute:()=>D});module.exports=U(K);var de=require("server-only");var H=/^[A-Za-z][A-Za-z0-9_]{0,63}$/,L=/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/,Z=/^[a-z0-9]{6,12}\.[a-z][a-z0-9_-]{0,63}$/;function k(e){if(!e||!Array.isArray(e.types)||e.types.length===0)throw new TypeError("CMS dependencies require document types");let r=[...e.types];for(let n of r)if(typeof n!="string"||!H.test(n))throw new TypeError("Invalid CMS document type");if(e.ids!==void 0&&!Array.isArray(e.ids))throw new TypeError("Invalid CMS document IDs");let t=e.ids===void 0?void 0:[...e.ids];for(let n of t??[])if(typeof n!="string"||!L.test(n)||/^(drafts|versions)\./.test(n))throw new TypeError("Invalid CMS document ID");if(new Set(r).size+new Set(t).size>128)throw new TypeError("Too many CMS tags");return Object.freeze({types:Object.freeze(r),...t===void 0?{}:{ids:Object.freeze(t)}})}function E(e){if(!e||typeof e.name!="string"||!/^[A-Za-z][A-Za-z0-9_.-]{0,127}$/.test(e.name)||typeof e.query!="string"||e.query.trim()===""||typeof e.resolve!="function")throw new TypeError("Invalid CMS query configuration");let r=e.params;if(!r||typeof r!="object"||Object.getPrototypeOf(r)!==Object.prototype&&Object.getPrototypeOf(r)!==null)throw new TypeError("CMS params must be plain JSON scalars");let t={};for(let n of Reflect.ownKeys(r)){let o=Object.getOwnPropertyDescriptor(r,n);if(typeof n!="string"||!o||!Object.hasOwn(o,"value")||!o.enumerable)throw new TypeError("CMS params must be plain JSON scalars");let a=o.value;if(!(a===null||typeof a=="string"||typeof a=="boolean"||typeof a=="number"&&Number.isFinite(a)))throw new TypeError("CMS params must be plain JSON scalars");Object.defineProperty(t,n,{value:a,enumerable:!0})}return Object.freeze({name:e.name,query:e.query,params:Object.freeze(t),dependencies:k(e.dependencies),resolve:e.resolve})}function T(e,r){if(typeof e!="string"||e.length>77||!Z.test(e))throw new TypeError("Invalid CMS scope");let t=k(r),n=[...[...new Set(t.types)].sort().map(o=>`cms:${e}:type:${o}`),...[...new Set(t.ids??[])].sort().map(o=>`cms:${e}:id:${o}`)];return Object.freeze(n)}function A(e){if(!e||!Object.hasOwn(e,"data")||!Array.isArray(e.fallbackFields)||![...e.fallbackFields].every(r=>typeof r=="string"&&(r==="$"||/^[A-Za-z][A-Za-z0-9_.[\]-]{0,127}$/.test(r))))throw new TypeError("Invalid CMS resolution");if(e.warnings!==void 0&&(!Array.isArray(e.warnings)||![...e.warnings].every(r=>r==="siteHero.layout.defaulted")))throw new TypeError("Invalid CMS resolution warnings");return{data:e.data,fallbackFields:Object.freeze([...new Set(e.fallbackFields)]),...e.warnings?.length?{warnings:Object.freeze([...new Set(e.warnings)])}:{}}}function S(e){let r=e?.revalidateSeconds??3600;if(!Number.isSafeInteger(r)||r<3600||!e?.adapter||typeof e.adapter.read!="function"||e.onDiagnostic!==void 0&&typeof e.onDiagnostic!="function")throw new TypeError("Invalid CMS reader configuration");let t=e.adapter;T(t.scope,{types:["ScopeValidation"]});let n=o=>{try{e.onDiagnostic?e.onDiagnostic(o):console.warn(JSON.stringify(o))}catch{}};return{async read(o,a){let s,l,d;try{if(s=E(o),d=T(t.scope,s.dependencies),!a||!Object.hasOwn(a,"fallback"))throw new TypeError;l=A(s.resolve(null,a.fallback))}catch{throw new TypeError("Invalid CMS query or fallback configuration")}let f=(g,u,m)=>(n({event:"cms.fallback",query:s.name,reason:g,fields:["$"],...u===void 0?{}:{status:u},...m?{warnings:m}:{}}),{data:l.data,source:"fallback",fallbackFields:["$"],reason:g,...m?{warnings:m}:{}}),i;try{i=await t.read({name:s.name,query:s.query,params:s.params},{tags:d,revalidateSeconds:r})}catch{return f("network")}if(!i.ok){let u=["configuration","network","timeout","rate-limit","upstream","plan-limit","permission","malformed"].includes(i.reason)?i.reason:"malformed",m=Number.isInteger(i.status)&&(i.status??0)>=100&&(i.status??0)<=599?i.status:void 0;return f(u,m)}if(i.value===null||i.value===void 0)return f("missing");let c;try{c=A(s.resolve(i.value,a.fallback))}catch{return f("malformed")}return c.fallbackFields.includes("$")?{...f("invalid-field",void 0,c.warnings),data:c.data}:c.fallbackFields.length>0?(n({event:"cms.partial-fallback",query:s.name,reason:"invalid-field",fields:c.fallbackFields,...c.warnings?{warnings:c.warnings}:{}}),{...c,source:"mixed",reason:"invalid-field"}):{...c,source:"cms"}}}}var O=S;var _=require("next/cache.js");var h="sanity-webhook-signature",Q=/^t=(\d+)[, ]+v1=([^, ]+)$/;var I=new TextEncoder;function V(e){return crypto.subtle.importKey("raw",I.encode(e),{name:"HMAC",hash:"SHA-256"},!1,["sign","verify"])}function B(e){if(!/^[A-Za-z0-9_-]+={0,2}$/.test(e))return null;let r=e.replace(/-/g,"+").replace(/_/g,"/");try{let t=atob(r),n=new Uint8Array(t.length);for(let o=0;o<t.length;o+=1)n[o]=t.charCodeAt(o);return n}catch{return null}}async function x(e){let{secret:r,rawBody:t,headers:n}=e,o=e.now??Date.now(),a=e.toleranceMs??3e5;if(!r||r.length===0)return{ok:!1,reason:"no-secret"};let s=n.get(h);if(!s)return{ok:!1,reason:"no-signature"};let l=Q.exec(s.trim());if(l===null)return{ok:!1,reason:"malformed-signature"};let d=Number(l[1]),f=l[2]??"";if(!Number.isSafeInteger(d))return{ok:!1,reason:"malformed-signature"};if(d<16094592e5)return{ok:!1,reason:"stale-timestamp"};if(Math.abs(o-d)>a)return{ok:!1,reason:"stale-timestamp"};let i=B(f);if(i===null)return{ok:!1,reason:"malformed-signature"};let c=await V(r);return await crypto.subtle.verify("HMAC",c,i,I.encode(`${d}.${t}`))?{ok:!0}:{ok:!1,reason:"bad-signature"}}var q=16*1024,W=1500,Y=new TextEncoder;function y(e,r,t={},n=!1){return new Response(n?null:JSON.stringify(r),{status:e,headers:{"Content-Type":"application/json","Cache-Control":"no-store",...t}})}function J(e,r){if(!r||typeof r!="object"||Array.isArray(r)||Object.keys(r).length===0)throw new TypeError("Invalid CMS invalidation mapping");let t=Object.create(null);for(let n of Reflect.ownKeys(r)){let o=Object.getOwnPropertyDescriptor(r,n);if(typeof n!="string"||!o?.enumerable||!Object.hasOwn(o,"value"))throw new TypeError("Invalid CMS invalidation mapping");let a=o.value;if(!Array.isArray(a)||!a.includes(n))throw new TypeError("Invalid CMS invalidation mapping");T(e,{types:a,ids:["validation"]}),t[n]=Object.freeze([...a])}for(let n of Object.values(t))if(n.some(o=>!Object.hasOwn(t,o)))throw new TypeError("Invalid CMS invalidation mapping");return Object.freeze(t)}function M(e){return typeof e=="string"&&e.trim()!==""&&Y.encode(e).byteLength>=32}var b=class extends Error{constructor(t){super("Invalid CMS webhook body");this.status=t}status};async function G(e){let r=e.body?.getReader();if(!r)return"";let t=new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0}),n,o=new Promise((a,s)=>{n=setTimeout(()=>s(new b(400)),W)});try{let a=0,s="";for(;;){let{done:l,value:d}=await Promise.race([r.read(),o]);if(l)return s+t.decode();if(a+=d.byteLength,a>q)throw new b(413);s+=t.decode(d,{stream:!0})}}catch(a){throw r.cancel().catch(()=>{}),a}finally{clearTimeout(n),r.releaseLock()}}function D(e){let r=e.scope,t=J(r,e.typeToTags),n=e.secretEnv??"SANITY_REVALIDATE_SECRET",o=e.previousSecretEnv??"SANITY_REVALIDATE_SECRET_PREVIOUS",a=e.env??(()=>process.env),s=e.now??Date.now,l=async d=>{if(d.method!=="POST")return y(405,{error:"Method not allowed"},{Allow:"POST"},d.method==="HEAD");let f,i;try{let p=a(),v=p[n],w=p[o];if(!M(v)||w!==void 0&&!M(w))throw new Error;f=v,i=w}catch{return y(503,{error:"COULD NOT ANSWER: revalidation configuration unavailable"})}let c=d.headers.get(h);if(!c||c.length>512||!/^t=\d+[, ]+v1=[A-Za-z0-9_-]+={0,2}$/.test(c.trim()))return y(401,{error:"Unauthorized"});let g;try{g=await G(d)}catch(p){return p instanceof b&&p.status===413?y(413,{error:"Payload too large"}):y(400,{error:"Invalid body"})}try{let p=s();if(!Number.isFinite(p))throw new Error;if(!(await Promise.all([f,...i===void 0?[]:[i]].map(w=>x({secret:w,rawBody:g,headers:d.headers,now:p})))).some(w=>w.ok))return y(401,{error:"Unauthorized"})}catch{return y(401,{error:"Unauthorized"})}let u;try{u=JSON.parse(g)}catch{return y(400,{error:"Invalid payload"})}if(!u||typeof u!="object"||Array.isArray(u)||Object.keys(u).length!==2||!Object.hasOwn(u,"_type")||!Object.hasOwn(u,"_id"))return y(400,{error:"Invalid payload"});let{_type:m,_id:C}=u;if(typeof m!="string"||!/^[A-Za-z][A-Za-z0-9_]{0,63}$/.test(m)||typeof C!="string"||!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(C))return y(400,{error:"Invalid payload"});if(!Object.hasOwn(t,m)||/^(drafts|versions)\./.test(C))return y(400,{error:"Unsupported document"});let P=T(r,{types:t[m],ids:[C]});try{for(let p of P)(0,_.revalidateTag)(p,{expire:0})}catch{return y(500,{error:"Could not revalidate"})}return y(200,{revalidated:!0})};return Object.freeze({POST:l,GET:l,HEAD:l,PUT:l,PATCH:l,DELETE:l,OPTIONS:l})}0&&(module.exports={createNextCmsReader,createRevalidateRoute});
2
2
  //# sourceMappingURL=next.cjs.map