@weatherboard/cms 0.0.0-stage → 0.1.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.
Files changed (100) hide show
  1. package/dist/adapters/next/reader.d.cts +2 -0
  2. package/dist/adapters/next/reader.d.mts +2 -0
  3. package/dist/adapters/next/reader.d.ts +2 -0
  4. package/dist/adapters/sanity/adapter.d.cts +15 -0
  5. package/dist/adapters/sanity/adapter.d.mts +15 -0
  6. package/dist/adapters/sanity/adapter.d.ts +15 -0
  7. package/dist/contracts/query.d.cts +19 -0
  8. package/dist/contracts/query.d.mts +19 -0
  9. package/dist/contracts/query.d.ts +19 -0
  10. package/dist/contracts/text.d.cts +40 -0
  11. package/dist/contracts/text.d.mts +40 -0
  12. package/dist/contracts/text.d.ts +40 -0
  13. package/dist/guard.cjs +3 -0
  14. package/dist/guard.cjs.map +7 -0
  15. package/dist/guard.d.cts +2 -0
  16. package/dist/guard.d.mts +2 -0
  17. package/dist/guard.d.ts +2 -0
  18. package/dist/guard.mjs +3 -0
  19. package/dist/guard.mjs.map +7 -0
  20. package/dist/index.cjs +2 -0
  21. package/dist/index.cjs.map +7 -0
  22. package/dist/index.d.cts +4 -0
  23. package/dist/index.d.mts +4 -0
  24. package/dist/index.d.ts +4 -0
  25. package/dist/index.mjs +2 -0
  26. package/dist/index.mjs.map +7 -0
  27. package/dist/invalidation/route.d.cts +12 -0
  28. package/dist/invalidation/route.d.mts +12 -0
  29. package/dist/invalidation/route.d.ts +12 -0
  30. package/dist/next.cjs +2 -0
  31. package/dist/next.cjs.map +7 -0
  32. package/dist/next.d.cts +4 -0
  33. package/dist/next.d.mts +4 -0
  34. package/dist/next.d.ts +4 -0
  35. package/dist/next.mjs +2 -0
  36. package/dist/next.mjs.map +7 -0
  37. package/dist/portable/array.d.cts +2 -0
  38. package/dist/portable/array.d.mts +2 -0
  39. package/dist/portable/array.d.ts +2 -0
  40. package/dist/portable/fallback.d.cts +4 -0
  41. package/dist/portable/fallback.d.mts +4 -0
  42. package/dist/portable/fallback.d.ts +4 -0
  43. package/dist/portable/site-content.d.cts +220 -0
  44. package/dist/portable/site-content.d.mts +220 -0
  45. package/dist/portable/site-content.d.ts +220 -0
  46. package/dist/portable/webhook.d.cts +133 -0
  47. package/dist/portable/webhook.d.mts +133 -0
  48. package/dist/portable/webhook.d.ts +133 -0
  49. package/dist/runtime/reader.d.cts +49 -0
  50. package/dist/runtime/reader.d.mts +49 -0
  51. package/dist/runtime/reader.d.ts +49 -0
  52. package/dist/sanity.cjs +2 -0
  53. package/dist/sanity.cjs.map +7 -0
  54. package/dist/sanity.d.cts +3 -0
  55. package/dist/sanity.d.mts +3 -0
  56. package/dist/sanity.d.ts +3 -0
  57. package/dist/sanity.mjs +2 -0
  58. package/dist/sanity.mjs.map +7 -0
  59. package/dist/server.cjs +2 -0
  60. package/dist/server.cjs.map +7 -0
  61. package/dist/server.d.cts +3 -0
  62. package/dist/server.d.mts +3 -0
  63. package/dist/server.d.ts +3 -0
  64. package/dist/server.mjs +2 -0
  65. package/dist/server.mjs.map +7 -0
  66. package/dist/site-content.cjs +7 -0
  67. package/dist/site-content.cjs.map +7 -0
  68. package/dist/site-content.d.cts +2 -0
  69. package/dist/site-content.d.mts +2 -0
  70. package/dist/site-content.d.ts +2 -0
  71. package/dist/site-content.mjs +7 -0
  72. package/dist/site-content.mjs.map +7 -0
  73. package/dist/testing.cjs +2 -0
  74. package/dist/testing.cjs.map +7 -0
  75. package/dist/testing.d.cts +2 -0
  76. package/dist/testing.d.mts +2 -0
  77. package/dist/testing.d.ts +2 -0
  78. package/dist/testing.mjs +2 -0
  79. package/dist/testing.mjs.map +7 -0
  80. package/dist/tooling/guard.d.cts +13 -0
  81. package/dist/tooling/guard.d.mts +13 -0
  82. package/dist/tooling/guard.d.ts +13 -0
  83. package/dist/tooling/test-fixtures/break-proof.d.cts +1 -0
  84. package/dist/tooling/test-fixtures/break-proof.d.mts +1 -0
  85. package/dist/tooling/test-fixtures/break-proof.d.ts +1 -0
  86. package/dist/tooling/test-fixtures/consumer.d.cts +9 -0
  87. package/dist/tooling/test-fixtures/consumer.d.mts +9 -0
  88. package/dist/tooling/test-fixtures/consumer.d.ts +9 -0
  89. package/dist/tooling/testing.d.cts +10 -0
  90. package/dist/tooling/testing.d.mts +10 -0
  91. package/dist/tooling/testing.d.ts +10 -0
  92. package/dist/webhook.cjs +2 -0
  93. package/dist/webhook.cjs.map +7 -0
  94. package/dist/webhook.d.cts +2 -0
  95. package/dist/webhook.d.mts +2 -0
  96. package/dist/webhook.d.ts +2 -0
  97. package/dist/webhook.mjs +2 -0
  98. package/dist/webhook.mjs.map +7 -0
  99. package/package.json +113 -3
  100. package/README.md +0 -3
@@ -0,0 +1,2 @@
1
+ import { createCmsReader } from "../../runtime/reader.cjs";
2
+ export declare const createNextCmsReader: typeof createCmsReader;
@@ -0,0 +1,2 @@
1
+ import { createCmsReader } from "../../runtime/reader.mjs";
2
+ export declare const createNextCmsReader: typeof createCmsReader;
@@ -0,0 +1,2 @@
1
+ import { createCmsReader } from "../../runtime/reader.js";
2
+ export declare const createNextCmsReader: typeof createCmsReader;
@@ -0,0 +1,15 @@
1
+ import type { CmsAdapter, CmsFetch } from "../../runtime/reader.cjs";
2
+ export type SanityBinding = {
3
+ readonly projectId: string;
4
+ readonly dataset: string;
5
+ readonly apiVersion: string;
6
+ };
7
+ export type SanityAdapterOptions = {
8
+ readonly binding: SanityBinding;
9
+ readonly readToken?: string;
10
+ readonly fetchImpl?: CmsFetch;
11
+ readonly timeoutMs?: number;
12
+ };
13
+ /** Applies policy via fetch's Next metadata. Standard fetch has no persistent cache or HTML invalidation. */
14
+ export declare function createSanityAdapter(options: SanityAdapterOptions): CmsAdapter;
15
+ export declare function sanityBindingFromEnv(env: Readonly<Record<string, string | undefined>>): SanityBinding;
@@ -0,0 +1,15 @@
1
+ import type { CmsAdapter, CmsFetch } from "../../runtime/reader.mjs";
2
+ export type SanityBinding = {
3
+ readonly projectId: string;
4
+ readonly dataset: string;
5
+ readonly apiVersion: string;
6
+ };
7
+ export type SanityAdapterOptions = {
8
+ readonly binding: SanityBinding;
9
+ readonly readToken?: string;
10
+ readonly fetchImpl?: CmsFetch;
11
+ readonly timeoutMs?: number;
12
+ };
13
+ /** Applies policy via fetch's Next metadata. Standard fetch has no persistent cache or HTML invalidation. */
14
+ export declare function createSanityAdapter(options: SanityAdapterOptions): CmsAdapter;
15
+ export declare function sanityBindingFromEnv(env: Readonly<Record<string, string | undefined>>): SanityBinding;
@@ -0,0 +1,15 @@
1
+ import type { CmsAdapter, CmsFetch } from "../../runtime/reader.js";
2
+ export type SanityBinding = {
3
+ readonly projectId: string;
4
+ readonly dataset: string;
5
+ readonly apiVersion: string;
6
+ };
7
+ export type SanityAdapterOptions = {
8
+ readonly binding: SanityBinding;
9
+ readonly readToken?: string;
10
+ readonly fetchImpl?: CmsFetch;
11
+ readonly timeoutMs?: number;
12
+ };
13
+ /** Applies policy via fetch's Next metadata. Standard fetch has no persistent cache or HTML invalidation. */
14
+ export declare function createSanityAdapter(options: SanityAdapterOptions): CmsAdapter;
15
+ export declare function sanityBindingFromEnv(env: Readonly<Record<string, string | undefined>>): SanityBinding;
@@ -0,0 +1,19 @@
1
+ /** A-1822 S1 owns this implementation. S0 registers the public signatures. */
2
+ export type CmsParams = Readonly<Record<string, string | number | boolean | null>>;
3
+ export type CmsDependencies = {
4
+ readonly types: readonly string[];
5
+ readonly ids?: readonly string[];
6
+ };
7
+ export type CmsResolution<T> = {
8
+ readonly data: T;
9
+ readonly fallbackFields: readonly string[];
10
+ };
11
+ export type CmsQuery<T> = {
12
+ readonly name: string;
13
+ readonly query: string;
14
+ readonly params: CmsParams;
15
+ readonly dependencies: CmsDependencies;
16
+ readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;
17
+ };
18
+ export declare function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T>;
19
+ export declare function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[];
@@ -0,0 +1,19 @@
1
+ /** A-1822 S1 owns this implementation. S0 registers the public signatures. */
2
+ export type CmsParams = Readonly<Record<string, string | number | boolean | null>>;
3
+ export type CmsDependencies = {
4
+ readonly types: readonly string[];
5
+ readonly ids?: readonly string[];
6
+ };
7
+ export type CmsResolution<T> = {
8
+ readonly data: T;
9
+ readonly fallbackFields: readonly string[];
10
+ };
11
+ export type CmsQuery<T> = {
12
+ readonly name: string;
13
+ readonly query: string;
14
+ readonly params: CmsParams;
15
+ readonly dependencies: CmsDependencies;
16
+ readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;
17
+ };
18
+ export declare function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T>;
19
+ export declare function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[];
@@ -0,0 +1,19 @@
1
+ /** A-1822 S1 owns this implementation. S0 registers the public signatures. */
2
+ export type CmsParams = Readonly<Record<string, string | number | boolean | null>>;
3
+ export type CmsDependencies = {
4
+ readonly types: readonly string[];
5
+ readonly ids?: readonly string[];
6
+ };
7
+ export type CmsResolution<T> = {
8
+ readonly data: T;
9
+ readonly fallbackFields: readonly string[];
10
+ };
11
+ export type CmsQuery<T> = {
12
+ readonly name: string;
13
+ readonly query: string;
14
+ readonly params: CmsParams;
15
+ readonly dependencies: CmsDependencies;
16
+ readonly resolve: (raw: unknown, fallback: T) => CmsResolution<T>;
17
+ };
18
+ export declare function defineCmsQuery<T>(query: CmsQuery<T>): CmsQuery<T>;
19
+ export declare function cmsTags(scope: string, dependencies: CmsDependencies): readonly string[];
@@ -0,0 +1,40 @@
1
+ import { type CmsQuery } from "./query.cjs";
2
+ export type SiteHero = {
3
+ readonly heading: string;
4
+ readonly intro: string;
5
+ };
6
+ export type TextFieldDefinition = {
7
+ readonly name: string;
8
+ readonly label: string;
9
+ readonly noun: {
10
+ readonly article: "a" | "an";
11
+ readonly word: string;
12
+ };
13
+ readonly kind: "single-line" | "multi-line";
14
+ readonly required: boolean;
15
+ readonly minLength: number;
16
+ readonly maxLength: number;
17
+ readonly noTrailingFullStop?: boolean;
18
+ };
19
+ export type TextDocumentDefinition = {
20
+ readonly key: string;
21
+ readonly documentId: string;
22
+ readonly documentType: string;
23
+ readonly fields: readonly TextFieldDefinition[];
24
+ readonly copy: {
25
+ readonly currentTitle: string;
26
+ readonly editTitle: string;
27
+ readonly empty: string;
28
+ };
29
+ };
30
+ export type TextValidation = {
31
+ readonly ok: true;
32
+ readonly value: Readonly<Record<string, string>>;
33
+ } | {
34
+ readonly ok: false;
35
+ readonly errors: Readonly<Record<string, string>>;
36
+ };
37
+ export declare const CMS_CONTRACT_VERSION = 1;
38
+ export declare const SITE_HERO: TextDocumentDefinition;
39
+ export declare function validateTextDocument(definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>): TextValidation;
40
+ export declare function siteHeroQuery(): CmsQuery<SiteHero>;
@@ -0,0 +1,40 @@
1
+ import { type CmsQuery } from "./query.mjs";
2
+ export type SiteHero = {
3
+ readonly heading: string;
4
+ readonly intro: string;
5
+ };
6
+ export type TextFieldDefinition = {
7
+ readonly name: string;
8
+ readonly label: string;
9
+ readonly noun: {
10
+ readonly article: "a" | "an";
11
+ readonly word: string;
12
+ };
13
+ readonly kind: "single-line" | "multi-line";
14
+ readonly required: boolean;
15
+ readonly minLength: number;
16
+ readonly maxLength: number;
17
+ readonly noTrailingFullStop?: boolean;
18
+ };
19
+ export type TextDocumentDefinition = {
20
+ readonly key: string;
21
+ readonly documentId: string;
22
+ readonly documentType: string;
23
+ readonly fields: readonly TextFieldDefinition[];
24
+ readonly copy: {
25
+ readonly currentTitle: string;
26
+ readonly editTitle: string;
27
+ readonly empty: string;
28
+ };
29
+ };
30
+ export type TextValidation = {
31
+ readonly ok: true;
32
+ readonly value: Readonly<Record<string, string>>;
33
+ } | {
34
+ readonly ok: false;
35
+ readonly errors: Readonly<Record<string, string>>;
36
+ };
37
+ export declare const CMS_CONTRACT_VERSION = 1;
38
+ export declare const SITE_HERO: TextDocumentDefinition;
39
+ export declare function validateTextDocument(definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>): TextValidation;
40
+ export declare function siteHeroQuery(): CmsQuery<SiteHero>;
@@ -0,0 +1,40 @@
1
+ import { type CmsQuery } from "./query.js";
2
+ export type SiteHero = {
3
+ readonly heading: string;
4
+ readonly intro: string;
5
+ };
6
+ export type TextFieldDefinition = {
7
+ readonly name: string;
8
+ readonly label: string;
9
+ readonly noun: {
10
+ readonly article: "a" | "an";
11
+ readonly word: string;
12
+ };
13
+ readonly kind: "single-line" | "multi-line";
14
+ readonly required: boolean;
15
+ readonly minLength: number;
16
+ readonly maxLength: number;
17
+ readonly noTrailingFullStop?: boolean;
18
+ };
19
+ export type TextDocumentDefinition = {
20
+ readonly key: string;
21
+ readonly documentId: string;
22
+ readonly documentType: string;
23
+ readonly fields: readonly TextFieldDefinition[];
24
+ readonly copy: {
25
+ readonly currentTitle: string;
26
+ readonly editTitle: string;
27
+ readonly empty: string;
28
+ };
29
+ };
30
+ export type TextValidation = {
31
+ readonly ok: true;
32
+ readonly value: Readonly<Record<string, string>>;
33
+ } | {
34
+ readonly ok: false;
35
+ readonly errors: Readonly<Record<string, string>>;
36
+ };
37
+ export declare const CMS_CONTRACT_VERSION = 1;
38
+ export declare const SITE_HERO: TextDocumentDefinition;
39
+ export declare function validateTextDocument(definition: TextDocumentDefinition, raw: Readonly<Record<string, unknown>>): TextValidation;
40
+ export declare function siteHeroQuery(): CmsQuery<SiteHero>;
package/dist/guard.cjs ADDED
@@ -0,0 +1,3 @@
1
+ "use strict";var I=Object.create;var w=Object.defineProperty;var B=Object.getOwnPropertyDescriptor;var M=Object.getOwnPropertyNames;var A=Object.getPrototypeOf,z=Object.prototype.hasOwnProperty;var v=(i,n)=>{for(var s in n)w(i,s,{get:n[s],enumerable:!0})},D=(i,n,s,f)=>{if(n&&typeof n=="object"||typeof n=="function")for(let p of M(n))!z.call(i,p)&&p!==s&&w(i,p,{get:()=>n[p],enumerable:!(f=B(n,p))||f.enumerable});return i};var q=(i,n,s)=>(s=i!=null?I(A(i)):{},D(n||!i||!i.__esModule?w(s,"default",{value:i,enumerable:!0}):s,i)),R=i=>D(w({},"__esModule",{value:!0}),i);var $={};v($,{findCmsBoundaryViolations:()=>N});module.exports=R($);var t=q(require("typescript"),1),P=["next-sanity","@sanity/client","@sanity/webhook"],V=/\.api(?:cdn)?\.sanity\.io|\/data\/query\/|\/query(?:[/?#]|$)/i;function S(i){return t.default.isParenthesizedExpression(i)||t.default.isAsExpression(i)||t.default.isSatisfiesExpression(i)||t.default.isTypeAssertionExpression(i)||t.default.isNonNullExpression(i)?S(i.expression):t.default.isBinaryExpression(i)&&i.operatorToken.kind===t.default.SyntaxKind.CommaToken?S(i.right):i}function d(i){if(i=S(i),t.default.isStringLiteralLike(i))return i.text;if(t.default.isBinaryExpression(i)&&i.operatorToken.kind===t.default.SyntaxKind.PlusToken){let n=d(i.left),s=d(i.right);return n===void 0||s===void 0?void 0:n+s}if(t.default.isTemplateExpression(i))return i.head.text+i.templateSpans.map(n=>(d(n.expression)??"\0")+n.literal.text).join("");if(t.default.isNewExpression(i)&&t.default.isIdentifier(i.expression)&&["URL","Request"].includes(i.expression.text)&&i.arguments?.[0])return d(i.arguments[0])}function k(i,n){for(let s=i;s;s=s.parent){let f=s.bindings.get(n);if(f)return f}}function F(i,n){if(i=S(i),t.default.isIdentifier(i)){let s=n&&k(n,i.text);return s?s.aliasDepth===void 0?void 0:"fetch":i.text}if(t.default.isPropertyAccessExpression(i)){let s=F(i.expression,n);return s?`${s}.${i.name.text}`:void 0}if(t.default.isElementAccessExpression(i)&&i.argumentExpression){let s=F(i.expression,n),f=d(i.argumentExpression);return s&&f?`${s}.${f}`:void 0}}function j(i){let n={kind:"source",bindings:new Map},s=new Map([[i,n]]),f=[],p=(e,o)=>{let r=e.bindings.get(o);if(r)return r;let l={};return e.bindings.set(o,l),l},c=(e,o)=>{if(t.default.isIdentifier(o))p(e,o.text);else for(let r of o.elements)t.default.isOmittedExpression(r)||c(e,r.name)},g=(e,o)=>{if(o.parent.flags&t.default.NodeFlags.BlockScoped)return e;let r=e;for(;r.kind==="block"&&r.parent;)r=r.parent;return r},m=(e,o)=>{let r=e.importClause;if(!r)return;r.name&&p(o,r.name.text);let l=r.namedBindings;if(l&&t.default.isNamespaceImport(l))p(o,l.name.text);else if(l)for(let a of l.elements)p(o,a.name.text)},L=e=>{let o=e.propertyName??e.name;return(t.default.isIdentifier(o)||t.default.isStringLiteralLike(o))&&o.text==="fetch"},x=(e,o)=>{let r=o;if(t.default.isFunctionDeclaration(e)&&e.name||t.default.isClassDeclaration(e)&&e.name||t.default.isEnumDeclaration(e)?p(r,e.name.text):t.default.isImportDeclaration(e)?m(e,r):t.default.isImportEqualsDeclaration(e)&&p(r,e.name.text),t.default.isFunctionLike(e)){r={parent:o,kind:"function",bindings:new Map},s.set(e,r),t.default.isFunctionExpression(e)&&e.name&&p(r,e.name.text);for(let l of e.parameters)c(r,l.name)}else if(t.default.isCatchClause(e))r={parent:o,kind:"block",bindings:new Map},s.set(e,r),e.variableDeclaration&&c(r,e.variableDeclaration.name);else if(t.default.isBlock(e))r={parent:o,kind:"block",bindings:new Map},s.set(e,r);else if(t.default.isForStatement(e)||t.default.isForInStatement(e)||t.default.isForOfStatement(e)){let l=e.initializer;l&&t.default.isVariableDeclarationList(l)&&l.flags&t.default.NodeFlags.BlockScoped&&(r={parent:o,kind:"block",bindings:new Map},s.set(e,r))}if(t.default.isVariableDeclaration(e)){let l=g(r,e);if(c(l,e.name),e.initializer&&t.default.isIdentifier(e.name))f.push({binding:p(l,e.name.text),initializer:e.initializer,scope:r,globalThisFetch:!1});else if(e.initializer&&t.default.isObjectBindingPattern(e.name))for(let a of e.name.elements)!L(a)||!t.default.isIdentifier(a.name)||f.push({binding:p(l,a.name.text),initializer:e.initializer,scope:r,globalThisFetch:!0})}t.default.forEachChild(e,l=>x(l,r))};t.default.forEachChild(i,e=>x(e,n));let b=(e,o,r)=>(e=S(e),t.default.isIdentifier(e)&&r.includes(e.text)&&!k(o,e.text)),E=(e,o)=>{if(e=S(e),t.default.isIdentifier(e)){let r=k(o,e.text);return r?r.aliasDepth:e.text==="fetch"?-1:void 0}if(t.default.isPropertyAccessExpression(e)&&e.name.text==="fetch"&&b(e.expression,o,["globalThis","window"])||t.default.isElementAccessExpression(e)&&e.argumentExpression&&d(e.argumentExpression)==="fetch"&&b(e.expression,o,["globalThis","window"]))return-1};for(let e of f)(e.globalThisFetch?b(e.initializer,e.scope,["globalThis"]):E(e.initializer,e.scope)===-1)&&(e.binding.aliasDepth=0);for(let e of f)e.binding.aliasDepth===void 0&&!e.globalThisFetch&&E(e.initializer,e.scope)===0&&(e.binding.aliasDepth=1);return{scopes:s,sourceScope:n}}function T(i){return typeof i=="string"&&i.length>0&&!i.startsWith("/")&&!/[\\\0*?{}]/.test(i)&&i.split("/").every(n=>n!==""&&n!=="."&&n!=="..")}function N(i){if(!Array.isArray(i.files)||i.files.length===0)throw new TypeError("CMS guard requires source files");let n=new Set;for(let c of i.files){if(!c||!T(c.path)||typeof c.text!="string"||n.has(c.path))throw new TypeError("CMS guard requires unique readable source paths");n.add(c.path)}let s=i.allowedProviderFiles??[];if(!Array.isArray(s)||new Set(s).size!==s.length||s.some(c=>!T(c)||!n.has(c)))throw new TypeError("CMS guard requires unique exact provider exemptions present in the scan");let f=new Set,p=[];for(let c of i.files){let g=c.path.split(".").at(-1)?.toLowerCase();if(!["ts","tsx","mts","cts","js","jsx","mjs","cjs","astro"].includes(g??""))throw new TypeError("CMS guard does not support this source syntax");let m=c.text;if(g==="astro"){let a=/^(?:\uFEFF)?---[^\S\r\n]*\r?\n((?:[^\n]*\n)*?)---[^\S\r\n]*(?:\r?\n|$)/.exec(m);if(m.replace(/^\uFEFF/,"").startsWith("---")&&!a)throw new TypeError("CMS guard cannot parse Astro frontmatter");m=a?`
2
+ `+a[1]:""}let L=g==="tsx"||g==="jsx"?t.default.ScriptKind.TSX:t.default.ScriptKind.TS,x=t.default.createSourceFile(c.path,m,t.default.ScriptTarget.Latest,!0,L);if(x.parseDiagnostics.length)throw new TypeError("CMS guard cannot parse source");let{scopes:E,sourceScope:e}=j(x),o=(a,h)=>{if(s.includes(c.path)){f.add(c.path);return}p.push({path:c.path,line:x.getLineAndCharacterOfPosition(a.getStart(x)).line+1,rule:h})},r=(a,h)=>{let y=h&&d(h);y!==void 0&&P.some(u=>y===u||y.startsWith(`${u}/`))&&o(a,"forbidden-provider-import")},l=(a,h)=>{let y=E.get(a)??h;if(t.default.isImportDeclaration(a)||t.default.isExportDeclaration(a))r(a,a.moduleSpecifier);else if(t.default.isImportEqualsDeclaration(a)&&t.default.isExternalModuleReference(a.moduleReference))r(a,a.moduleReference.expression);else if(t.default.isImportTypeNode(a)&&t.default.isLiteralTypeNode(a.argument))r(a,a.argument.literal);else if(t.default.isCallExpression(a)){let u=F(a.expression,y);if((a.expression.kind===t.default.SyntaxKind.ImportKeyword||u==="require"||u==="require.resolve")&&r(a,a.arguments[0]),u==="fetch"||u?.endsWith(".fetch")){let C=a.arguments[0]&&d(a.arguments[0]);C!==void 0&&V.test(C)&&o(a,"direct-provider-read")}}t.default.forEachChild(a,u=>l(u,y))};l(x,e)}if(s.some(c=>!f.has(c)))throw new TypeError("CMS guard has an unused provider exemption");return p}0&&(module.exports={findCmsBoundaryViolations});
3
+ //# sourceMappingURL=guard.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/guard.ts", "../src/tooling/guard.ts"],
4
+ "sourcesContent": ["export { findCmsBoundaryViolations } from \"./tooling/guard.js\";\nexport type { CmsSourceFile, CmsGuardViolation } from \"./tooling/guard.js\";\n", "import ts from \"typescript\";\n\nexport type CmsSourceFile = { readonly path: string; readonly text: string };\nexport type CmsGuardViolation = { readonly path: string; readonly line: number; readonly rule: string };\n\nconst PROVIDERS = [\"next-sanity\", \"@sanity/client\", \"@sanity/webhook\"];\nconst RAW_READ = /\\.api(?:cdn)?\\.sanity\\.io|\\/data\\/query\\/|\\/query(?:[/?#]|$)/i;\n\n// These expressions preserve their operand (or the final comma operand).\n// Inspect the underlying syntax without evaluating consumer code.\nfunction unwrap(node: ts.Node): ts.Node {\n if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node)\n || ts.isSatisfiesExpression(node) || ts.isTypeAssertionExpression(node)\n || ts.isNonNullExpression(node)) return unwrap(node.expression);\n if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.CommaToken) return unwrap(node.right);\n return node;\n}\n\n// Evaluate ordinary literal expressions, without executing consumer code.\nfunction literal(node: ts.Node): string | undefined {\n node = unwrap(node);\n if (ts.isStringLiteralLike(node)) return node.text;\n if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {\n const left = literal(node.left);\n const right = literal(node.right);\n return left === undefined || right === undefined ? undefined : left + right;\n }\n if (ts.isTemplateExpression(node)) {\n return node.head.text + node.templateSpans.map((span) =>\n (literal(span.expression) ?? \"\\0\") + span.literal.text).join(\"\");\n }\n if (ts.isNewExpression(node) && ts.isIdentifier(node.expression)\n && [\"URL\", \"Request\"].includes(node.expression.text) && node.arguments?.[0]) return literal(node.arguments[0]);\n return undefined;\n}\n\ntype LexicalBinding = { aliasDepth?: 0 | 1 };\ntype LexicalScope = {\n readonly parent?: LexicalScope;\n readonly kind: \"source\" | \"function\" | \"block\";\n readonly bindings: Map<string, LexicalBinding>;\n};\n\nfunction lookupBinding(scope: LexicalScope, name: string): LexicalBinding | undefined {\n for (let current: LexicalScope | undefined = scope; current; current = current.parent) {\n const binding = current.bindings.get(name);\n if (binding) return binding;\n }\n return undefined;\n}\n\nfunction callName(node: ts.Node, scope?: LexicalScope): string | undefined {\n node = unwrap(node);\n if (ts.isIdentifier(node)) {\n const binding = scope && lookupBinding(scope, node.text);\n if (binding) return binding.aliasDepth === undefined ? undefined : \"fetch\";\n return node.text;\n }\n if (ts.isPropertyAccessExpression(node)) {\n const owner = callName(node.expression, scope);\n return owner ? `${owner}.${node.name.text}` : undefined;\n }\n if (ts.isElementAccessExpression(node) && node.argumentExpression) {\n const owner = callName(node.expression, scope);\n const key = literal(node.argumentExpression);\n return owner && key ? `${owner}.${key}` : undefined;\n }\n return undefined;\n}\n\nfunction lexicalScopes(source: ts.SourceFile): {\n readonly scopes: ReadonlyMap<ts.Node, LexicalScope>;\n readonly sourceScope: LexicalScope;\n} {\n const sourceScope: LexicalScope = { kind: \"source\", bindings: new Map() };\n const scopes = new Map<ts.Node, LexicalScope>([[source, sourceScope]]);\n const candidates: Array<{\n readonly binding: LexicalBinding;\n readonly initializer: ts.Expression;\n readonly scope: LexicalScope;\n readonly globalThisFetch: boolean;\n }> = [];\n const bind = (scope: LexicalScope, name: string) => {\n const existing = scope.bindings.get(name);\n if (existing) return existing;\n const binding: LexicalBinding = {};\n scope.bindings.set(name, binding);\n return binding;\n };\n const bindName = (scope: LexicalScope, name: ts.BindingName) => {\n if (ts.isIdentifier(name)) bind(scope, name.text);\n else for (const element of name.elements) if (!ts.isOmittedExpression(element)) bindName(scope, element.name);\n };\n const variableScope = (scope: LexicalScope, declaration: ts.VariableDeclaration) => {\n if (declaration.parent.flags & ts.NodeFlags.BlockScoped) return scope;\n let current = scope;\n while (current.kind === \"block\" && current.parent) current = current.parent;\n return current;\n };\n const bindImports = (node: ts.ImportDeclaration, scope: LexicalScope) => {\n const clause = node.importClause;\n if (!clause) return;\n if (clause.name) bind(scope, clause.name.text);\n const imports = clause.namedBindings;\n if (imports && ts.isNamespaceImport(imports)) bind(scope, imports.name.text);\n else if (imports) for (const element of imports.elements) bind(scope, element.name.text);\n };\n const destructuredFetch = (element: ts.BindingElement) => {\n const property = element.propertyName ?? element.name;\n return (ts.isIdentifier(property) || ts.isStringLiteralLike(property)) && property.text === \"fetch\";\n };\n\n const collect = (node: ts.Node, incoming: LexicalScope) => {\n let scope = incoming;\n if (ts.isFunctionDeclaration(node) && node.name) bind(scope, node.name.text);\n else if (ts.isClassDeclaration(node) && node.name) bind(scope, node.name.text);\n else if (ts.isEnumDeclaration(node)) bind(scope, node.name.text);\n else if (ts.isImportDeclaration(node)) bindImports(node, scope);\n else if (ts.isImportEqualsDeclaration(node)) bind(scope, node.name.text);\n\n if (ts.isFunctionLike(node)) {\n scope = { parent: incoming, kind: \"function\", bindings: new Map() };\n scopes.set(node, scope);\n if (ts.isFunctionExpression(node) && node.name) bind(scope, node.name.text);\n for (const parameter of node.parameters) bindName(scope, parameter.name);\n } else if (ts.isCatchClause(node)) {\n scope = { parent: incoming, kind: \"block\", bindings: new Map() };\n scopes.set(node, scope);\n if (node.variableDeclaration) bindName(scope, node.variableDeclaration.name);\n } else if (ts.isBlock(node)) {\n scope = { parent: incoming, kind: \"block\", bindings: new Map() };\n scopes.set(node, scope);\n } else if (ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node)) {\n const initializer = node.initializer;\n if (initializer && ts.isVariableDeclarationList(initializer)\n && initializer.flags & ts.NodeFlags.BlockScoped) {\n scope = { parent: incoming, kind: \"block\", bindings: new Map() };\n scopes.set(node, scope);\n }\n }\n\n if (ts.isVariableDeclaration(node)) {\n const target = variableScope(scope, node);\n bindName(target, node.name);\n if (node.initializer && ts.isIdentifier(node.name)) {\n candidates.push({\n binding: bind(target, node.name.text), initializer: node.initializer, scope,\n globalThisFetch: false,\n });\n } else if (node.initializer && ts.isObjectBindingPattern(node.name)) {\n for (const element of node.name.elements) {\n if (!destructuredFetch(element) || !ts.isIdentifier(element.name)) continue;\n candidates.push({\n binding: bind(target, element.name.text), initializer: node.initializer, scope,\n globalThisFetch: true,\n });\n }\n }\n }\n ts.forEachChild(node, (child) => collect(child, scope));\n };\n ts.forEachChild(source, (node) => collect(node, sourceScope));\n\n const isUnboundGlobal = (node: ts.Node, scope: LexicalScope, names: readonly string[]) => {\n node = unwrap(node);\n return ts.isIdentifier(node) && names.includes(node.text) && !lookupBinding(scope, node.text);\n };\n const fetchReferenceDepth = (node: ts.Node, scope: LexicalScope): -1 | 0 | 1 | undefined => {\n node = unwrap(node);\n if (ts.isIdentifier(node)) {\n const binding = lookupBinding(scope, node.text);\n if (binding) return binding.aliasDepth;\n return node.text === \"fetch\" ? -1 : undefined;\n }\n if (ts.isPropertyAccessExpression(node) && node.name.text === \"fetch\"\n && isUnboundGlobal(node.expression, scope, [\"globalThis\", \"window\"])) return -1;\n if (ts.isElementAccessExpression(node) && node.argumentExpression\n && literal(node.argumentExpression) === \"fetch\"\n && isUnboundGlobal(node.expression, scope, [\"globalThis\", \"window\"])) return -1;\n return undefined;\n };\n\n // Classify direct aliases first, then exactly one alias-to-alias hop. Binding\n // collection happens before classification so nearer non-fetch declarations\n // and parameters correctly shadow aliases in an outer scope.\n for (const candidate of candidates) {\n const direct = candidate.globalThisFetch\n ? isUnboundGlobal(candidate.initializer, candidate.scope, [\"globalThis\"])\n : fetchReferenceDepth(candidate.initializer, candidate.scope) === -1;\n if (direct) candidate.binding.aliasDepth = 0;\n }\n for (const candidate of candidates) {\n if (candidate.binding.aliasDepth === undefined && !candidate.globalThisFetch\n && fetchReferenceDepth(candidate.initializer, candidate.scope) === 0) candidate.binding.aliasDepth = 1;\n }\n return { scopes, sourceScope };\n}\n\nfunction exactPath(path: unknown): path is string {\n return typeof path === \"string\" && path.length > 0 && !path.startsWith(\"/\")\n && !/[\\\\\\0*?{}]/.test(path)\n && path.split(\"/\").every((part) => part !== \"\" && part !== \".\" && part !== \"..\");\n}\n\nexport function findCmsBoundaryViolations(options: {\n files: readonly CmsSourceFile[];\n allowedProviderFiles?: readonly string[];\n}): readonly CmsGuardViolation[] {\n if (!Array.isArray(options.files) || options.files.length === 0) throw new TypeError(\"CMS guard requires source files\");\n const paths = new Set<string>();\n for (const file of options.files) {\n if (!file || !exactPath(file.path) || typeof file.text !== \"string\" || paths.has(file.path)) {\n throw new TypeError(\"CMS guard requires unique readable source paths\");\n }\n paths.add(file.path);\n }\n const allowed = options.allowedProviderFiles ?? [];\n if (!Array.isArray(allowed) || new Set(allowed).size !== allowed.length\n || allowed.some((path) => !exactPath(path) || !paths.has(path))) {\n throw new TypeError(\"CMS guard requires unique exact provider exemptions present in the scan\");\n }\n const used = new Set<string>();\n const violations: CmsGuardViolation[] = [];\n for (const file of options.files) {\n const extension = file.path.split(\".\").at(-1)?.toLowerCase();\n if (![\"ts\", \"tsx\", \"mts\", \"cts\", \"js\", \"jsx\", \"mjs\", \"cjs\", \"astro\"].includes(extension ?? \"\")) {\n throw new TypeError(\"CMS guard does not support this source syntax\");\n }\n let text = file.text;\n if (extension === \"astro\") {\n // Keep line positions from the complete file, but parse only frontmatter.\n const frontmatter = /^(?:\\uFEFF)?---[^\\S\\r\\n]*\\r?\\n((?:[^\\n]*\\n)*?)---[^\\S\\r\\n]*(?:\\r?\\n|$)/.exec(text);\n if (text.replace(/^\\uFEFF/, \"\").startsWith(\"---\") && !frontmatter) {\n throw new TypeError(\"CMS guard cannot parse Astro frontmatter\");\n }\n text = frontmatter ? \"\\n\" + frontmatter[1] : \"\";\n }\n const kind = extension === \"tsx\" || extension === \"jsx\" ? ts.ScriptKind.TSX : ts.ScriptKind.TS;\n const source = ts.createSourceFile(file.path, text, ts.ScriptTarget.Latest, true, kind);\n const diagnostics = (source as ts.SourceFile & { parseDiagnostics: readonly ts.Diagnostic[] }).parseDiagnostics;\n if (diagnostics.length) throw new TypeError(\"CMS guard cannot parse source\");\n // Plan section 6 covers literal/template fetch URLs and ordinary lexical\n // aliases, without resolving computed transports or computed URL values.\n const { scopes, sourceScope } = lexicalScopes(source);\n const report = (node: ts.Node, rule: string) => {\n if (allowed.includes(file.path)) { used.add(file.path); return; }\n violations.push({ path: file.path, line: source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1, rule });\n };\n const checkImport = (node: ts.Node, argument: ts.Node | undefined) => {\n const specifier = argument && literal(argument);\n if (specifier !== undefined && PROVIDERS.some((name) => specifier === name || specifier.startsWith(`${name}/`))) {\n report(node, \"forbidden-provider-import\");\n }\n };\n const visit = (node: ts.Node, incoming: LexicalScope) => {\n const scope = scopes.get(node) ?? incoming;\n if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) checkImport(node, node.moduleSpecifier);\n else if (ts.isImportEqualsDeclaration(node) && ts.isExternalModuleReference(node.moduleReference)) {\n checkImport(node, node.moduleReference.expression);\n } else if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument)) checkImport(node, node.argument.literal);\n else if (ts.isCallExpression(node)) {\n const name = callName(node.expression, scope);\n if (node.expression.kind === ts.SyntaxKind.ImportKeyword || name === \"require\" || name === \"require.resolve\") {\n checkImport(node, node.arguments[0]);\n }\n if (name === \"fetch\" || name?.endsWith(\".fetch\")) {\n const url = node.arguments[0] && literal(node.arguments[0]);\n if (url !== undefined && RAW_READ.test(url)) report(node, \"direct-provider-read\");\n }\n }\n ts.forEachChild(node, (child) => visit(child, scope));\n };\n visit(source, sourceScope);\n }\n if (allowed.some((path) => !used.has(path))) throw new TypeError(\"CMS guard has an unused provider exemption\");\n return violations;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["guard_exports", "__export", "findCmsBoundaryViolations", "__toCommonJS", "import_typescript", "PROVIDERS", "RAW_READ", "unwrap", "node", "ts", "literal", "left", "right", "span", "lookupBinding", "scope", "name", "current", "binding", "callName", "owner", "key", "lexicalScopes", "source", "sourceScope", "scopes", "candidates", "bind", "existing", "bindName", "element", "variableScope", "declaration", "bindImports", "clause", "imports", "destructuredFetch", "property", "collect", "incoming", "parameter", "initializer", "target", "child", "isUnboundGlobal", "names", "fetchReferenceDepth", "candidate", "exactPath", "path", "part", "findCmsBoundaryViolations", "options", "paths", "file", "allowed", "used", "violations", "extension", "text", "frontmatter", "kind", "report", "rule", "checkImport", "argument", "specifier", "visit", "url"]
7
+ }
@@ -0,0 +1,2 @@
1
+ export { findCmsBoundaryViolations } from "./tooling/guard.cjs";
2
+ export type { CmsSourceFile, CmsGuardViolation } from "./tooling/guard.cjs";
@@ -0,0 +1,2 @@
1
+ export { findCmsBoundaryViolations } from "./tooling/guard.mjs";
2
+ export type { CmsSourceFile, CmsGuardViolation } from "./tooling/guard.mjs";
@@ -0,0 +1,2 @@
1
+ export { findCmsBoundaryViolations } from "./tooling/guard.js";
2
+ export type { CmsSourceFile, CmsGuardViolation } from "./tooling/guard.js";
package/dist/guard.mjs ADDED
@@ -0,0 +1,3 @@
1
+ import i from"typescript";var D=["next-sanity","@sanity/client","@sanity/webhook"],T=/\.api(?:cdn)?\.sanity\.io|\/data\/query\/|\/query(?:[/?#]|$)/i;function S(t){return i.isParenthesizedExpression(t)||i.isAsExpression(t)||i.isSatisfiesExpression(t)||i.isTypeAssertionExpression(t)||i.isNonNullExpression(t)?S(t.expression):i.isBinaryExpression(t)&&t.operatorToken.kind===i.SyntaxKind.CommaToken?S(t.right):t}function d(t){if(t=S(t),i.isStringLiteralLike(t))return t.text;if(i.isBinaryExpression(t)&&t.operatorToken.kind===i.SyntaxKind.PlusToken){let o=d(t.left),a=d(t.right);return o===void 0||a===void 0?void 0:o+a}if(i.isTemplateExpression(t))return t.head.text+t.templateSpans.map(o=>(d(o.expression)??"\0")+o.literal.text).join("");if(i.isNewExpression(t)&&i.isIdentifier(t.expression)&&["URL","Request"].includes(t.expression.text)&&t.arguments?.[0])return d(t.arguments[0])}function L(t,o){for(let a=t;a;a=a.parent){let f=a.bindings.get(o);if(f)return f}}function k(t,o){if(t=S(t),i.isIdentifier(t)){let a=o&&L(o,t.text);return a?a.aliasDepth===void 0?void 0:"fetch":t.text}if(i.isPropertyAccessExpression(t)){let a=k(t.expression,o);return a?`${a}.${t.name.text}`:void 0}if(i.isElementAccessExpression(t)&&t.argumentExpression){let a=k(t.expression,o),f=d(t.argumentExpression);return a&&f?`${a}.${f}`:void 0}}function N(t){let o={kind:"source",bindings:new Map},a=new Map([[t,o]]),f=[],p=(e,n)=>{let r=e.bindings.get(n);if(r)return r;let l={};return e.bindings.set(n,l),l},c=(e,n)=>{if(i.isIdentifier(n))p(e,n.text);else for(let r of n.elements)i.isOmittedExpression(r)||c(e,r.name)},g=(e,n)=>{if(n.parent.flags&i.NodeFlags.BlockScoped)return e;let r=e;for(;r.kind==="block"&&r.parent;)r=r.parent;return r},m=(e,n)=>{let r=e.importClause;if(!r)return;r.name&&p(n,r.name.text);let l=r.namedBindings;if(l&&i.isNamespaceImport(l))p(n,l.name.text);else if(l)for(let s of l.elements)p(n,s.name.text)},w=e=>{let n=e.propertyName??e.name;return(i.isIdentifier(n)||i.isStringLiteralLike(n))&&n.text==="fetch"},x=(e,n)=>{let r=n;if(i.isFunctionDeclaration(e)&&e.name||i.isClassDeclaration(e)&&e.name||i.isEnumDeclaration(e)?p(r,e.name.text):i.isImportDeclaration(e)?m(e,r):i.isImportEqualsDeclaration(e)&&p(r,e.name.text),i.isFunctionLike(e)){r={parent:n,kind:"function",bindings:new Map},a.set(e,r),i.isFunctionExpression(e)&&e.name&&p(r,e.name.text);for(let l of e.parameters)c(r,l.name)}else if(i.isCatchClause(e))r={parent:n,kind:"block",bindings:new Map},a.set(e,r),e.variableDeclaration&&c(r,e.variableDeclaration.name);else if(i.isBlock(e))r={parent:n,kind:"block",bindings:new Map},a.set(e,r);else if(i.isForStatement(e)||i.isForInStatement(e)||i.isForOfStatement(e)){let l=e.initializer;l&&i.isVariableDeclarationList(l)&&l.flags&i.NodeFlags.BlockScoped&&(r={parent:n,kind:"block",bindings:new Map},a.set(e,r))}if(i.isVariableDeclaration(e)){let l=g(r,e);if(c(l,e.name),e.initializer&&i.isIdentifier(e.name))f.push({binding:p(l,e.name.text),initializer:e.initializer,scope:r,globalThisFetch:!1});else if(e.initializer&&i.isObjectBindingPattern(e.name))for(let s of e.name.elements)!w(s)||!i.isIdentifier(s.name)||f.push({binding:p(l,s.name.text),initializer:e.initializer,scope:r,globalThisFetch:!0})}i.forEachChild(e,l=>x(l,r))};i.forEachChild(t,e=>x(e,o));let b=(e,n,r)=>(e=S(e),i.isIdentifier(e)&&r.includes(e.text)&&!L(n,e.text)),E=(e,n)=>{if(e=S(e),i.isIdentifier(e)){let r=L(n,e.text);return r?r.aliasDepth:e.text==="fetch"?-1:void 0}if(i.isPropertyAccessExpression(e)&&e.name.text==="fetch"&&b(e.expression,n,["globalThis","window"])||i.isElementAccessExpression(e)&&e.argumentExpression&&d(e.argumentExpression)==="fetch"&&b(e.expression,n,["globalThis","window"]))return-1};for(let e of f)(e.globalThisFetch?b(e.initializer,e.scope,["globalThis"]):E(e.initializer,e.scope)===-1)&&(e.binding.aliasDepth=0);for(let e of f)e.binding.aliasDepth===void 0&&!e.globalThisFetch&&E(e.initializer,e.scope)===0&&(e.binding.aliasDepth=1);return{scopes:a,sourceScope:o}}function C(t){return typeof t=="string"&&t.length>0&&!t.startsWith("/")&&!/[\\\0*?{}]/.test(t)&&t.split("/").every(o=>o!==""&&o!=="."&&o!=="..")}function I(t){if(!Array.isArray(t.files)||t.files.length===0)throw new TypeError("CMS guard requires source files");let o=new Set;for(let c of t.files){if(!c||!C(c.path)||typeof c.text!="string"||o.has(c.path))throw new TypeError("CMS guard requires unique readable source paths");o.add(c.path)}let a=t.allowedProviderFiles??[];if(!Array.isArray(a)||new Set(a).size!==a.length||a.some(c=>!C(c)||!o.has(c)))throw new TypeError("CMS guard requires unique exact provider exemptions present in the scan");let f=new Set,p=[];for(let c of t.files){let g=c.path.split(".").at(-1)?.toLowerCase();if(!["ts","tsx","mts","cts","js","jsx","mjs","cjs","astro"].includes(g??""))throw new TypeError("CMS guard does not support this source syntax");let m=c.text;if(g==="astro"){let s=/^(?:\uFEFF)?---[^\S\r\n]*\r?\n((?:[^\n]*\n)*?)---[^\S\r\n]*(?:\r?\n|$)/.exec(m);if(m.replace(/^\uFEFF/,"").startsWith("---")&&!s)throw new TypeError("CMS guard cannot parse Astro frontmatter");m=s?`
2
+ `+s[1]:""}let w=g==="tsx"||g==="jsx"?i.ScriptKind.TSX:i.ScriptKind.TS,x=i.createSourceFile(c.path,m,i.ScriptTarget.Latest,!0,w);if(x.parseDiagnostics.length)throw new TypeError("CMS guard cannot parse source");let{scopes:E,sourceScope:e}=N(x),n=(s,h)=>{if(a.includes(c.path)){f.add(c.path);return}p.push({path:c.path,line:x.getLineAndCharacterOfPosition(s.getStart(x)).line+1,rule:h})},r=(s,h)=>{let y=h&&d(h);y!==void 0&&D.some(u=>y===u||y.startsWith(`${u}/`))&&n(s,"forbidden-provider-import")},l=(s,h)=>{let y=E.get(s)??h;if(i.isImportDeclaration(s)||i.isExportDeclaration(s))r(s,s.moduleSpecifier);else if(i.isImportEqualsDeclaration(s)&&i.isExternalModuleReference(s.moduleReference))r(s,s.moduleReference.expression);else if(i.isImportTypeNode(s)&&i.isLiteralTypeNode(s.argument))r(s,s.argument.literal);else if(i.isCallExpression(s)){let u=k(s.expression,y);if((s.expression.kind===i.SyntaxKind.ImportKeyword||u==="require"||u==="require.resolve")&&r(s,s.arguments[0]),u==="fetch"||u?.endsWith(".fetch")){let F=s.arguments[0]&&d(s.arguments[0]);F!==void 0&&T.test(F)&&n(s,"direct-provider-read")}}i.forEachChild(s,u=>l(u,y))};l(x,e)}if(a.some(c=>!f.has(c)))throw new TypeError("CMS guard has an unused provider exemption");return p}export{I as findCmsBoundaryViolations};
3
+ //# sourceMappingURL=guard.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/tooling/guard.ts"],
4
+ "sourcesContent": ["import ts from \"typescript\";\n\nexport type CmsSourceFile = { readonly path: string; readonly text: string };\nexport type CmsGuardViolation = { readonly path: string; readonly line: number; readonly rule: string };\n\nconst PROVIDERS = [\"next-sanity\", \"@sanity/client\", \"@sanity/webhook\"];\nconst RAW_READ = /\\.api(?:cdn)?\\.sanity\\.io|\\/data\\/query\\/|\\/query(?:[/?#]|$)/i;\n\n// These expressions preserve their operand (or the final comma operand).\n// Inspect the underlying syntax without evaluating consumer code.\nfunction unwrap(node: ts.Node): ts.Node {\n if (ts.isParenthesizedExpression(node) || ts.isAsExpression(node)\n || ts.isSatisfiesExpression(node) || ts.isTypeAssertionExpression(node)\n || ts.isNonNullExpression(node)) return unwrap(node.expression);\n if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.CommaToken) return unwrap(node.right);\n return node;\n}\n\n// Evaluate ordinary literal expressions, without executing consumer code.\nfunction literal(node: ts.Node): string | undefined {\n node = unwrap(node);\n if (ts.isStringLiteralLike(node)) return node.text;\n if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) {\n const left = literal(node.left);\n const right = literal(node.right);\n return left === undefined || right === undefined ? undefined : left + right;\n }\n if (ts.isTemplateExpression(node)) {\n return node.head.text + node.templateSpans.map((span) =>\n (literal(span.expression) ?? \"\\0\") + span.literal.text).join(\"\");\n }\n if (ts.isNewExpression(node) && ts.isIdentifier(node.expression)\n && [\"URL\", \"Request\"].includes(node.expression.text) && node.arguments?.[0]) return literal(node.arguments[0]);\n return undefined;\n}\n\ntype LexicalBinding = { aliasDepth?: 0 | 1 };\ntype LexicalScope = {\n readonly parent?: LexicalScope;\n readonly kind: \"source\" | \"function\" | \"block\";\n readonly bindings: Map<string, LexicalBinding>;\n};\n\nfunction lookupBinding(scope: LexicalScope, name: string): LexicalBinding | undefined {\n for (let current: LexicalScope | undefined = scope; current; current = current.parent) {\n const binding = current.bindings.get(name);\n if (binding) return binding;\n }\n return undefined;\n}\n\nfunction callName(node: ts.Node, scope?: LexicalScope): string | undefined {\n node = unwrap(node);\n if (ts.isIdentifier(node)) {\n const binding = scope && lookupBinding(scope, node.text);\n if (binding) return binding.aliasDepth === undefined ? undefined : \"fetch\";\n return node.text;\n }\n if (ts.isPropertyAccessExpression(node)) {\n const owner = callName(node.expression, scope);\n return owner ? `${owner}.${node.name.text}` : undefined;\n }\n if (ts.isElementAccessExpression(node) && node.argumentExpression) {\n const owner = callName(node.expression, scope);\n const key = literal(node.argumentExpression);\n return owner && key ? `${owner}.${key}` : undefined;\n }\n return undefined;\n}\n\nfunction lexicalScopes(source: ts.SourceFile): {\n readonly scopes: ReadonlyMap<ts.Node, LexicalScope>;\n readonly sourceScope: LexicalScope;\n} {\n const sourceScope: LexicalScope = { kind: \"source\", bindings: new Map() };\n const scopes = new Map<ts.Node, LexicalScope>([[source, sourceScope]]);\n const candidates: Array<{\n readonly binding: LexicalBinding;\n readonly initializer: ts.Expression;\n readonly scope: LexicalScope;\n readonly globalThisFetch: boolean;\n }> = [];\n const bind = (scope: LexicalScope, name: string) => {\n const existing = scope.bindings.get(name);\n if (existing) return existing;\n const binding: LexicalBinding = {};\n scope.bindings.set(name, binding);\n return binding;\n };\n const bindName = (scope: LexicalScope, name: ts.BindingName) => {\n if (ts.isIdentifier(name)) bind(scope, name.text);\n else for (const element of name.elements) if (!ts.isOmittedExpression(element)) bindName(scope, element.name);\n };\n const variableScope = (scope: LexicalScope, declaration: ts.VariableDeclaration) => {\n if (declaration.parent.flags & ts.NodeFlags.BlockScoped) return scope;\n let current = scope;\n while (current.kind === \"block\" && current.parent) current = current.parent;\n return current;\n };\n const bindImports = (node: ts.ImportDeclaration, scope: LexicalScope) => {\n const clause = node.importClause;\n if (!clause) return;\n if (clause.name) bind(scope, clause.name.text);\n const imports = clause.namedBindings;\n if (imports && ts.isNamespaceImport(imports)) bind(scope, imports.name.text);\n else if (imports) for (const element of imports.elements) bind(scope, element.name.text);\n };\n const destructuredFetch = (element: ts.BindingElement) => {\n const property = element.propertyName ?? element.name;\n return (ts.isIdentifier(property) || ts.isStringLiteralLike(property)) && property.text === \"fetch\";\n };\n\n const collect = (node: ts.Node, incoming: LexicalScope) => {\n let scope = incoming;\n if (ts.isFunctionDeclaration(node) && node.name) bind(scope, node.name.text);\n else if (ts.isClassDeclaration(node) && node.name) bind(scope, node.name.text);\n else if (ts.isEnumDeclaration(node)) bind(scope, node.name.text);\n else if (ts.isImportDeclaration(node)) bindImports(node, scope);\n else if (ts.isImportEqualsDeclaration(node)) bind(scope, node.name.text);\n\n if (ts.isFunctionLike(node)) {\n scope = { parent: incoming, kind: \"function\", bindings: new Map() };\n scopes.set(node, scope);\n if (ts.isFunctionExpression(node) && node.name) bind(scope, node.name.text);\n for (const parameter of node.parameters) bindName(scope, parameter.name);\n } else if (ts.isCatchClause(node)) {\n scope = { parent: incoming, kind: \"block\", bindings: new Map() };\n scopes.set(node, scope);\n if (node.variableDeclaration) bindName(scope, node.variableDeclaration.name);\n } else if (ts.isBlock(node)) {\n scope = { parent: incoming, kind: \"block\", bindings: new Map() };\n scopes.set(node, scope);\n } else if (ts.isForStatement(node) || ts.isForInStatement(node) || ts.isForOfStatement(node)) {\n const initializer = node.initializer;\n if (initializer && ts.isVariableDeclarationList(initializer)\n && initializer.flags & ts.NodeFlags.BlockScoped) {\n scope = { parent: incoming, kind: \"block\", bindings: new Map() };\n scopes.set(node, scope);\n }\n }\n\n if (ts.isVariableDeclaration(node)) {\n const target = variableScope(scope, node);\n bindName(target, node.name);\n if (node.initializer && ts.isIdentifier(node.name)) {\n candidates.push({\n binding: bind(target, node.name.text), initializer: node.initializer, scope,\n globalThisFetch: false,\n });\n } else if (node.initializer && ts.isObjectBindingPattern(node.name)) {\n for (const element of node.name.elements) {\n if (!destructuredFetch(element) || !ts.isIdentifier(element.name)) continue;\n candidates.push({\n binding: bind(target, element.name.text), initializer: node.initializer, scope,\n globalThisFetch: true,\n });\n }\n }\n }\n ts.forEachChild(node, (child) => collect(child, scope));\n };\n ts.forEachChild(source, (node) => collect(node, sourceScope));\n\n const isUnboundGlobal = (node: ts.Node, scope: LexicalScope, names: readonly string[]) => {\n node = unwrap(node);\n return ts.isIdentifier(node) && names.includes(node.text) && !lookupBinding(scope, node.text);\n };\n const fetchReferenceDepth = (node: ts.Node, scope: LexicalScope): -1 | 0 | 1 | undefined => {\n node = unwrap(node);\n if (ts.isIdentifier(node)) {\n const binding = lookupBinding(scope, node.text);\n if (binding) return binding.aliasDepth;\n return node.text === \"fetch\" ? -1 : undefined;\n }\n if (ts.isPropertyAccessExpression(node) && node.name.text === \"fetch\"\n && isUnboundGlobal(node.expression, scope, [\"globalThis\", \"window\"])) return -1;\n if (ts.isElementAccessExpression(node) && node.argumentExpression\n && literal(node.argumentExpression) === \"fetch\"\n && isUnboundGlobal(node.expression, scope, [\"globalThis\", \"window\"])) return -1;\n return undefined;\n };\n\n // Classify direct aliases first, then exactly one alias-to-alias hop. Binding\n // collection happens before classification so nearer non-fetch declarations\n // and parameters correctly shadow aliases in an outer scope.\n for (const candidate of candidates) {\n const direct = candidate.globalThisFetch\n ? isUnboundGlobal(candidate.initializer, candidate.scope, [\"globalThis\"])\n : fetchReferenceDepth(candidate.initializer, candidate.scope) === -1;\n if (direct) candidate.binding.aliasDepth = 0;\n }\n for (const candidate of candidates) {\n if (candidate.binding.aliasDepth === undefined && !candidate.globalThisFetch\n && fetchReferenceDepth(candidate.initializer, candidate.scope) === 0) candidate.binding.aliasDepth = 1;\n }\n return { scopes, sourceScope };\n}\n\nfunction exactPath(path: unknown): path is string {\n return typeof path === \"string\" && path.length > 0 && !path.startsWith(\"/\")\n && !/[\\\\\\0*?{}]/.test(path)\n && path.split(\"/\").every((part) => part !== \"\" && part !== \".\" && part !== \"..\");\n}\n\nexport function findCmsBoundaryViolations(options: {\n files: readonly CmsSourceFile[];\n allowedProviderFiles?: readonly string[];\n}): readonly CmsGuardViolation[] {\n if (!Array.isArray(options.files) || options.files.length === 0) throw new TypeError(\"CMS guard requires source files\");\n const paths = new Set<string>();\n for (const file of options.files) {\n if (!file || !exactPath(file.path) || typeof file.text !== \"string\" || paths.has(file.path)) {\n throw new TypeError(\"CMS guard requires unique readable source paths\");\n }\n paths.add(file.path);\n }\n const allowed = options.allowedProviderFiles ?? [];\n if (!Array.isArray(allowed) || new Set(allowed).size !== allowed.length\n || allowed.some((path) => !exactPath(path) || !paths.has(path))) {\n throw new TypeError(\"CMS guard requires unique exact provider exemptions present in the scan\");\n }\n const used = new Set<string>();\n const violations: CmsGuardViolation[] = [];\n for (const file of options.files) {\n const extension = file.path.split(\".\").at(-1)?.toLowerCase();\n if (![\"ts\", \"tsx\", \"mts\", \"cts\", \"js\", \"jsx\", \"mjs\", \"cjs\", \"astro\"].includes(extension ?? \"\")) {\n throw new TypeError(\"CMS guard does not support this source syntax\");\n }\n let text = file.text;\n if (extension === \"astro\") {\n // Keep line positions from the complete file, but parse only frontmatter.\n const frontmatter = /^(?:\\uFEFF)?---[^\\S\\r\\n]*\\r?\\n((?:[^\\n]*\\n)*?)---[^\\S\\r\\n]*(?:\\r?\\n|$)/.exec(text);\n if (text.replace(/^\\uFEFF/, \"\").startsWith(\"---\") && !frontmatter) {\n throw new TypeError(\"CMS guard cannot parse Astro frontmatter\");\n }\n text = frontmatter ? \"\\n\" + frontmatter[1] : \"\";\n }\n const kind = extension === \"tsx\" || extension === \"jsx\" ? ts.ScriptKind.TSX : ts.ScriptKind.TS;\n const source = ts.createSourceFile(file.path, text, ts.ScriptTarget.Latest, true, kind);\n const diagnostics = (source as ts.SourceFile & { parseDiagnostics: readonly ts.Diagnostic[] }).parseDiagnostics;\n if (diagnostics.length) throw new TypeError(\"CMS guard cannot parse source\");\n // Plan section 6 covers literal/template fetch URLs and ordinary lexical\n // aliases, without resolving computed transports or computed URL values.\n const { scopes, sourceScope } = lexicalScopes(source);\n const report = (node: ts.Node, rule: string) => {\n if (allowed.includes(file.path)) { used.add(file.path); return; }\n violations.push({ path: file.path, line: source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1, rule });\n };\n const checkImport = (node: ts.Node, argument: ts.Node | undefined) => {\n const specifier = argument && literal(argument);\n if (specifier !== undefined && PROVIDERS.some((name) => specifier === name || specifier.startsWith(`${name}/`))) {\n report(node, \"forbidden-provider-import\");\n }\n };\n const visit = (node: ts.Node, incoming: LexicalScope) => {\n const scope = scopes.get(node) ?? incoming;\n if (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) checkImport(node, node.moduleSpecifier);\n else if (ts.isImportEqualsDeclaration(node) && ts.isExternalModuleReference(node.moduleReference)) {\n checkImport(node, node.moduleReference.expression);\n } else if (ts.isImportTypeNode(node) && ts.isLiteralTypeNode(node.argument)) checkImport(node, node.argument.literal);\n else if (ts.isCallExpression(node)) {\n const name = callName(node.expression, scope);\n if (node.expression.kind === ts.SyntaxKind.ImportKeyword || name === \"require\" || name === \"require.resolve\") {\n checkImport(node, node.arguments[0]);\n }\n if (name === \"fetch\" || name?.endsWith(\".fetch\")) {\n const url = node.arguments[0] && literal(node.arguments[0]);\n if (url !== undefined && RAW_READ.test(url)) report(node, \"direct-provider-read\");\n }\n }\n ts.forEachChild(node, (child) => visit(child, scope));\n };\n visit(source, sourceScope);\n }\n if (allowed.some((path) => !used.has(path))) throw new TypeError(\"CMS guard has an unused provider exemption\");\n return violations;\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["ts", "PROVIDERS", "RAW_READ", "unwrap", "node", "literal", "left", "right", "span", "lookupBinding", "scope", "name", "current", "binding", "callName", "owner", "key", "lexicalScopes", "source", "sourceScope", "scopes", "candidates", "bind", "existing", "bindName", "element", "variableScope", "declaration", "bindImports", "clause", "imports", "destructuredFetch", "property", "collect", "incoming", "parameter", "initializer", "target", "child", "isUnboundGlobal", "names", "fetchReferenceDepth", "candidate", "exactPath", "path", "part", "findCmsBoundaryViolations", "options", "paths", "file", "allowed", "used", "violations", "extension", "text", "frontmatter", "kind", "report", "rule", "checkImport", "argument", "specifier", "visit", "url"]
7
+ }
package/dist/index.cjs ADDED
@@ -0,0 +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});
2
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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"]
7
+ }
@@ -0,0 +1,4 @@
1
+ export { defineCmsQuery, cmsTags } from "./contracts/query.cjs";
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";
@@ -0,0 +1,4 @@
1
+ export { defineCmsQuery, cmsTags } from "./contracts/query.mjs";
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";
@@ -0,0 +1,4 @@
1
+ export { defineCmsQuery, cmsTags } from "./contracts/query.js";
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";
package/dist/index.mjs ADDED
@@ -0,0 +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};
2
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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"]
7
+ }
@@ -0,0 +1,12 @@
1
+ export type TypeToTags = Readonly<Record<string, readonly string[]>>;
2
+ export type RevalidateRouteOptions = {
3
+ readonly scope: string;
4
+ readonly secretEnv?: string;
5
+ readonly previousSecretEnv?: string;
6
+ readonly typeToTags: TypeToTags;
7
+ readonly env?: () => Readonly<Record<string, string | undefined>>;
8
+ readonly now?: () => number;
9
+ };
10
+ export type CmsRouteHandler = (request: Request) => Promise<Response>;
11
+ export type CmsRevalidateRoute = Readonly<Record<"POST" | "GET" | "HEAD" | "PUT" | "PATCH" | "DELETE" | "OPTIONS", CmsRouteHandler>>;
12
+ export declare function createRevalidateRoute(options: RevalidateRouteOptions): CmsRevalidateRoute;
@@ -0,0 +1,12 @@
1
+ export type TypeToTags = Readonly<Record<string, readonly string[]>>;
2
+ export type RevalidateRouteOptions = {
3
+ readonly scope: string;
4
+ readonly secretEnv?: string;
5
+ readonly previousSecretEnv?: string;
6
+ readonly typeToTags: TypeToTags;
7
+ readonly env?: () => Readonly<Record<string, string | undefined>>;
8
+ readonly now?: () => number;
9
+ };
10
+ export type CmsRouteHandler = (request: Request) => Promise<Response>;
11
+ export type CmsRevalidateRoute = Readonly<Record<"POST" | "GET" | "HEAD" | "PUT" | "PATCH" | "DELETE" | "OPTIONS", CmsRouteHandler>>;
12
+ export declare function createRevalidateRoute(options: RevalidateRouteOptions): CmsRevalidateRoute;
@@ -0,0 +1,12 @@
1
+ export type TypeToTags = Readonly<Record<string, readonly string[]>>;
2
+ export type RevalidateRouteOptions = {
3
+ readonly scope: string;
4
+ readonly secretEnv?: string;
5
+ readonly previousSecretEnv?: string;
6
+ readonly typeToTags: TypeToTags;
7
+ readonly env?: () => Readonly<Record<string, string | undefined>>;
8
+ readonly now?: () => number;
9
+ };
10
+ export type CmsRouteHandler = (request: Request) => Promise<Response>;
11
+ export type CmsRevalidateRoute = Readonly<Record<"POST" | "GET" | "HEAD" | "PUT" | "PATCH" | "DELETE" | "OPTIONS", CmsRouteHandler>>;
12
+ export declare function createRevalidateRoute(options: RevalidateRouteOptions): CmsRevalidateRoute;