@samva/markup 0.8.0 → 0.10.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 (172) hide show
  1. package/AGENTS.md +107 -46
  2. package/CHANGELOG.md +345 -0
  3. package/README.md +188 -52
  4. package/dist/{brand-DcoVkh_S.d.ts → assets-BIsyMQ92.d.ts} +41 -11
  5. package/dist/{email/brand.js → brand-C0MKTwmX.js} +64 -4
  6. package/dist/{theme-css.d.ts → brand.d.ts} +12 -3
  7. package/dist/brand.js +4 -0
  8. package/dist/channel-specs-C2feJwuP.d.ts +13 -0
  9. package/dist/compiler.d.ts +88 -115
  10. package/dist/compiler.js +750 -171
  11. package/dist/components-BZCqegS8.js +1864 -0
  12. package/dist/diagnostic-model-DJtqbETd.js +38 -0
  13. package/dist/{diagnostics-OcQKQYSY.d.ts → diagnostic-model-DxthUZBT.d.ts} +3 -21
  14. package/dist/{diagnostics-BMYtBCQk.d.ts → diagnostics-B-Gym34R.d.ts} +8 -4
  15. package/dist/{email/diagnostics.js → diagnostics-CnKFefKz.js} +4 -3
  16. package/dist/diagnostics.d.ts +410 -2
  17. package/dist/diagnostics.js +402 -52
  18. package/dist/edit.d.ts +234 -0
  19. package/dist/edit.js +947 -0
  20. package/dist/email/jsx-dev-runtime.d.ts +2 -2
  21. package/dist/email/jsx-dev-runtime.js +1 -2
  22. package/dist/email/jsx-runtime.d.ts +1 -1
  23. package/dist/email/jsx-runtime.js +1 -85
  24. package/dist/{email/components.d.ts → email.d.ts} +22 -11
  25. package/dist/email.js +2 -0
  26. package/dist/fmt.d.ts +32 -0
  27. package/dist/fmt.js +174 -0
  28. package/dist/index.d.ts +2 -0
  29. package/dist/index.js +2 -0
  30. package/dist/{render-vAv_4r9v.js → ir-CLhlklKV.js} +96 -279
  31. package/dist/jsx-runtime-CBlexoeR.js +98 -0
  32. package/dist/{elements-BzjjnoCS.d.ts → jsx-runtime-ylIOnaSf.d.ts} +76 -76
  33. package/dist/profile-pWGtWZXF.js +3803 -0
  34. package/dist/render-BPonDpCl.d.ts +539 -0
  35. package/dist/render-BQmfh94k.js +257 -0
  36. package/dist/render.d.ts +35 -0
  37. package/dist/render.js +49 -0
  38. package/dist/sms.d.ts +16 -0
  39. package/dist/sms.js +12 -0
  40. package/dist/source-locations-C8wCsiAy.d.ts +23 -0
  41. package/dist/template-DMPwxMSq.d.ts +65 -0
  42. package/dist/template-zLUjcwfF.js +42 -0
  43. package/dist/{theme-css-hFqcPSar.js → theme-css-JtRCm1fb.js} +2 -2
  44. package/dist/whatsapp.d.ts +57 -0
  45. package/dist/whatsapp.js +22 -0
  46. package/generated/contract.json +1788 -0
  47. package/generated/reference.md +360 -0
  48. package/package.json +46 -239
  49. package/samva-brand.d.ts +4 -4
  50. package/skills/sml/SKILL.md +123 -0
  51. package/dist/ast-BrDtApwS.d.ts +0 -107
  52. package/dist/ast.d.ts +0 -2
  53. package/dist/ast.js +0 -124
  54. package/dist/candidate.d.ts +0 -29
  55. package/dist/candidate.js +0 -88
  56. package/dist/catalog-CKuOooB8.d.ts +0 -354
  57. package/dist/checks-D73Xizbw.js +0 -59366
  58. package/dist/checks.d.ts +0 -33
  59. package/dist/checks.js +0 -2
  60. package/dist/classes.d.ts +0 -26
  61. package/dist/classes.js +0 -184
  62. package/dist/compile-sms.d.ts +0 -28
  63. package/dist/compile-sms.js +0 -44
  64. package/dist/compile-whatsapp.d.ts +0 -56
  65. package/dist/compile-whatsapp.js +0 -186
  66. package/dist/compile.d.ts +0 -18
  67. package/dist/compile.js +0 -29
  68. package/dist/components.d.ts +0 -289
  69. package/dist/components.js +0 -106
  70. package/dist/conditionals.d.ts +0 -10
  71. package/dist/conditionals.js +0 -74
  72. package/dist/corpus-CPPfgAHN.d.ts +0 -106
  73. package/dist/css-CS2jLID6.d.ts +0 -109
  74. package/dist/email/assets.d.ts +0 -40
  75. package/dist/email/assets.js +0 -63
  76. package/dist/email/brand-footer.d.ts +0 -34
  77. package/dist/email/brand-footer.js +0 -62
  78. package/dist/email/brand.d.ts +0 -2
  79. package/dist/email/components.js +0 -240
  80. package/dist/email/diagnostics.d.ts +0 -2
  81. package/dist/email/elements.d.ts +0 -2
  82. package/dist/email/elements.js +0 -299
  83. package/dist/email/html.d.ts +0 -2
  84. package/dist/email/html.js +0 -278
  85. package/dist/email/render.d.ts +0 -50
  86. package/dist/email/render.js +0 -3
  87. package/dist/email/selection.d.ts +0 -2
  88. package/dist/email/selection.js +0 -91
  89. package/dist/email/source-edit.d.ts +0 -67
  90. package/dist/email/source-edit.js +0 -185
  91. package/dist/email/stylesheets.d.ts +0 -15
  92. package/dist/email/stylesheets.js +0 -48
  93. package/dist/email/text.d.ts +0 -7
  94. package/dist/email/text.js +0 -100
  95. package/dist/emit.d.ts +0 -51
  96. package/dist/emit.js +0 -151
  97. package/dist/html-Bl9BAdqc.d.ts +0 -42
  98. package/dist/interpolate.d.ts +0 -24
  99. package/dist/interpolate.js +0 -43
  100. package/dist/jsx-dev-runtime.d.ts +0 -11
  101. package/dist/jsx-dev-runtime.js +0 -15
  102. package/dist/jsx-runtime-I-1nCtl2.d.ts +0 -57
  103. package/dist/jsx-runtime.d.ts +0 -2
  104. package/dist/jsx-runtime.js +0 -121
  105. package/dist/lexer.d.ts +0 -60
  106. package/dist/lexer.js +0 -281
  107. package/dist/model.d.ts +0 -24
  108. package/dist/model.js +0 -77
  109. package/dist/ops-BvwqHl7V.js +0 -630
  110. package/dist/ops.d.ts +0 -114
  111. package/dist/ops.js +0 -2
  112. package/dist/parser-t29cHLVL.d.ts +0 -396
  113. package/dist/parser.d.ts +0 -2
  114. package/dist/parser.js +0 -859
  115. package/dist/predicate-BI6uRRM-.js +0 -549
  116. package/dist/predicate-M-05Nd7R.d.ts +0 -56
  117. package/dist/predicate.d.ts +0 -2
  118. package/dist/predicate.js +0 -2
  119. package/dist/printer.d.ts +0 -6
  120. package/dist/printer.js +0 -122
  121. package/dist/registry-Dcp6QEK_.d.ts +0 -73
  122. package/dist/registry.d.ts +0 -2
  123. package/dist/registry.js +0 -646
  124. package/dist/render-template.d.ts +0 -45
  125. package/dist/render-template.js +0 -76
  126. package/dist/selection-CCArx9lU.d.ts +0 -91
  127. package/dist/showcase-egkusQBf.d.ts +0 -415
  128. package/dist/sms-segments-y4FpPilJ.d.ts +0 -13
  129. package/dist/sms-segments.d.ts +0 -2
  130. package/dist/sms-segments.js +0 -46
  131. package/dist/source-locations-DrCM82Ym.d.ts +0 -67
  132. package/dist/source-locations.d.ts +0 -2
  133. package/dist/source-locations.js +0 -102
  134. package/dist/starters/category-mapping.d.ts +0 -13
  135. package/dist/starters/category-mapping.js +0 -49
  136. package/dist/starters/corpus.d.ts +0 -2
  137. package/dist/starters/corpus.js +0 -194
  138. package/dist/starters/library.d.ts +0 -18
  139. package/dist/starters/library.js +0 -692
  140. package/dist/starters/public-gallery.d.ts +0 -266
  141. package/dist/starters/public-gallery.js +0 -916
  142. package/dist/starters/public-handoff.d.ts +0 -164
  143. package/dist/starters/public-handoff.js +0 -361
  144. package/dist/starters/public-preview-artifacts.d.ts +0 -43
  145. package/dist/starters/public-preview-artifacts.js +0 -104
  146. package/dist/starters/public-preview.d.ts +0 -61
  147. package/dist/starters/public-preview.js +0 -83
  148. package/dist/starters/showcase.d.ts +0 -2
  149. package/dist/starters/showcase.js +0 -335
  150. package/dist/starters/sources.d.ts +0 -45
  151. package/dist/starters/sources.js +0 -7762
  152. package/dist/starters/theme.d.ts +0 -45
  153. package/dist/starters/theme.js +0 -77
  154. package/dist/starters.d.ts +0 -2
  155. package/dist/starters.js +0 -874
  156. package/dist/tailwind-BYq7Lo6u.js +0 -727
  157. package/dist/template-DWftqh4x.d.ts +0 -60
  158. package/dist/template.d.ts +0 -2
  159. package/dist/template.js +0 -37
  160. package/dist/theme-css.js +0 -2
  161. package/dist/tsx-source-instrumentation.d.ts +0 -30
  162. package/dist/tsx-source-instrumentation.js +0 -115
  163. package/dist/tsx-tracer.d.ts +0 -112
  164. package/dist/tsx-tracer.js +0 -985
  165. package/dist/variables-J_L3qxRa.d.ts +0 -77
  166. package/dist/variables.d.ts +0 -2
  167. package/dist/variables.js +0 -141
  168. package/dist/version-BITr58kk.js +0 -96
  169. package/generated/sml-agent-contract.json +0 -709
  170. package/generated/sml-email-agent-contract.json +0 -615
  171. package/generated/sml-email-language-reference.md +0 -94
  172. package/generated/sml-language-reference.md +0 -195
@@ -1,67 +0,0 @@
1
- import { f as ElementNode, x as SmlNode } from "./ast-BrDtApwS.js";
2
- //#region src/source-locations.d.ts
3
- /**
4
- * The source payload emitted by the JSX development transform. The transform
5
- * may omit any field for synthetic calls; only a complete payload can identify
6
- * a source origin safely.
7
- */
8
- interface JsxSource {
9
- readonly fileName?: string | undefined;
10
- readonly lineNumber?: number | undefined;
11
- readonly columnNumber?: number | undefined;
12
- }
13
- /** A complete, normalized source origin for a JSX element. */
14
- interface JsxSourceLocation {
15
- readonly fileName: string;
16
- readonly lineNumber: number;
17
- readonly columnNumber: number;
18
- }
19
- /**
20
- * Runtime-only carrier for JSX source metadata. It is global so separately
21
- * bundled `jsx-dev-runtime` and `render-template` entries still agree on the
22
- * sidecar key, and it is a Symbol so it cannot enter SML, HTML, or JSON.
23
- */
24
- declare const JSX_SOURCE_LOCATION: unique symbol;
25
- /** Internal JSX prop used only by an editor preview source transform. */
26
- declare const JSX_SOURCE_LOCATION_PROP: "__samva_source_location";
27
- /**
28
- * A source map is useful only when it is trustworthy. Production `jsx`/`jsxs`
29
- * currently provide no source metadata, so that path reports a typed absence
30
- * rather than guessing from output order.
31
- */
32
- type SourceLocationUnavailableReason = "no-source-metadata" | "structure-mismatch" | "duplicate-source-origin" | "render-failed" | "stale-preview";
33
- type UnboundTemplateSourceLocations = {
34
- readonly kind: "available";
35
- /** Parsed SML node id → the JSX origin that produced that element. */
36
- readonly byNodeId: Readonly<Record<string, JsxSourceLocation>>;
37
- } | {
38
- readonly kind: "unavailable";
39
- readonly reason: SourceLocationUnavailableReason;
40
- };
41
- /** Revision-fenced source map exposed by a mutable workspace preview. */
42
- type TemplateSourceLocations = {
43
- readonly kind: "available";
44
- readonly revision: string;
45
- /** Parsed SML node id → the JSX origin that produced that element. */
46
- readonly byNodeId: Readonly<Record<string, JsxSourceLocation>>;
47
- } | {
48
- readonly kind: "unavailable";
49
- readonly reason: SourceLocationUnavailableReason;
50
- };
51
- /** Normalize the optional payload accepted by `jsxDEV`. */
52
- declare const completeJsxSourceLocation: (source: JsxSource | null | undefined) => JsxSourceLocation | undefined;
53
- /** Attach a source origin without changing the serialized draft shape. */
54
- declare const attachJsxSourceLocation: (node: ElementNode, source: JsxSourceLocation) => void;
55
- /** Read the ephemeral origin, if this draft element has one. */
56
- declare const jsxSourceLocationOf: (node: SmlNode) => JsxSourceLocation | undefined;
57
- /**
58
- * Pair a draft tree with its parsed SML tree by element preorder. Text nodes
59
- * are intentionally ignored: the SML parser normalizes inline whitespace, so
60
- * only the element structure is stable enough to be a source-map contract.
61
- */
62
- declare const mapJsxSourceLocations: (draft: ElementNode, parsed: ElementNode) => UnboundTemplateSourceLocations;
63
- /** Compare source-map statuses for the emission determinism guard. */
64
- declare const sameTemplateSourceLocations: (left: UnboundTemplateSourceLocations, right: UnboundTemplateSourceLocations) => boolean;
65
- //#endregion
66
- export { SourceLocationUnavailableReason as a, attachJsxSourceLocation as c, mapJsxSourceLocations as d, sameTemplateSourceLocations as f, JsxSourceLocation as i, completeJsxSourceLocation as l, JSX_SOURCE_LOCATION_PROP as n, TemplateSourceLocations as o, JsxSource as r, UnboundTemplateSourceLocations as s, JSX_SOURCE_LOCATION as t, jsxSourceLocationOf as u };
67
- //# sourceMappingURL=source-locations-DrCM82Ym.d.ts.map
@@ -1,2 +0,0 @@
1
- import { a as SourceLocationUnavailableReason, c as attachJsxSourceLocation, d as mapJsxSourceLocations, f as sameTemplateSourceLocations, i as JsxSourceLocation, l as completeJsxSourceLocation, n as JSX_SOURCE_LOCATION_PROP, o as TemplateSourceLocations, r as JsxSource, s as UnboundTemplateSourceLocations, t as JSX_SOURCE_LOCATION, u as jsxSourceLocationOf } from "./source-locations-DrCM82Ym.js";
2
- export { JSX_SOURCE_LOCATION, JSX_SOURCE_LOCATION_PROP, JsxSource, JsxSourceLocation, SourceLocationUnavailableReason, TemplateSourceLocations, UnboundTemplateSourceLocations, attachJsxSourceLocation, completeJsxSourceLocation, jsxSourceLocationOf, mapJsxSourceLocations, sameTemplateSourceLocations };
@@ -1,102 +0,0 @@
1
- import { t as hasProperty } from "./guards-eV1qLbf2.js";
2
- //#region src/source-locations.ts
3
- /**
4
- * Runtime-only carrier for JSX source metadata. It is global so separately
5
- * bundled `jsx-dev-runtime` and `render-template` entries still agree on the
6
- * sidecar key, and it is a Symbol so it cannot enter SML, HTML, or JSON.
7
- */
8
- const JSX_SOURCE_LOCATION = Symbol.for("@samva/markup/jsx-source-location");
9
- /** Internal JSX prop used only by an editor preview source transform. */
10
- const JSX_SOURCE_LOCATION_PROP = "__samva_source_location";
11
- /** Normalize the optional payload accepted by `jsxDEV`. */
12
- const completeJsxSourceLocation = (source) => {
13
- if (source?.fileName === void 0 || source.lineNumber === void 0 || source.columnNumber === void 0) return;
14
- return Object.freeze({
15
- fileName: source.fileName,
16
- lineNumber: source.lineNumber,
17
- columnNumber: source.columnNumber
18
- });
19
- };
20
- /** Attach a source origin without changing the serialized draft shape. */
21
- const attachJsxSourceLocation = (node, source) => {
22
- if (Object.hasOwn(node, JSX_SOURCE_LOCATION)) return;
23
- Object.defineProperty(node, JSX_SOURCE_LOCATION, {
24
- configurable: false,
25
- enumerable: false,
26
- value: source,
27
- writable: false
28
- });
29
- };
30
- const isJsxSourceLocation = (value) => hasProperty(value, "fileName") && typeof value.fileName === "string" && hasProperty(value, "lineNumber") && typeof value.lineNumber === "number" && Number.isInteger(value.lineNumber) && hasProperty(value, "columnNumber") && typeof value.columnNumber === "number" && Number.isInteger(value.columnNumber);
31
- /** Read the ephemeral origin, if this draft element has one. */
32
- const jsxSourceLocationOf = (node) => {
33
- if (node.kind !== "element") return void 0;
34
- const value = Object.getOwnPropertyDescriptor(node, JSX_SOURCE_LOCATION)?.value;
35
- return isJsxSourceLocation(value) ? value : void 0;
36
- };
37
- const elementChildren = (node) => node.children.filter((child) => child.kind === "element");
38
- const sourceOriginKey = (source) => JSON.stringify([
39
- source.fileName,
40
- source.lineNumber,
41
- source.columnNumber
42
- ]);
43
- /**
44
- * Pair a draft tree with its parsed SML tree by element preorder. Text nodes
45
- * are intentionally ignored: the SML parser normalizes inline whitespace, so
46
- * only the element structure is stable enough to be a source-map contract.
47
- */
48
- const mapJsxSourceLocations = (draft, parsed) => {
49
- const byNodeId = {};
50
- const origins = /* @__PURE__ */ new Set();
51
- let duplicateOrigin = false;
52
- const visit = (draftNode, parsedNode) => {
53
- if (draftNode.tag !== parsedNode.tag) return false;
54
- const source = jsxSourceLocationOf(draftNode);
55
- if (source !== void 0) {
56
- const origin = sourceOriginKey(source);
57
- if (origins.has(origin)) duplicateOrigin = true;
58
- origins.add(origin);
59
- if (Object.hasOwn(byNodeId, parsedNode.id)) return false;
60
- byNodeId[parsedNode.id] = source;
61
- }
62
- const draftChildren = elementChildren(draftNode);
63
- const parsedChildren = elementChildren(parsedNode);
64
- if (draftChildren.length !== parsedChildren.length) return false;
65
- for (let index = 0; index < draftChildren.length; index++) if (!visit(draftChildren[index], parsedChildren[index])) return false;
66
- return true;
67
- };
68
- if (!visit(draft, parsed)) return {
69
- kind: "unavailable",
70
- reason: "structure-mismatch"
71
- };
72
- if (duplicateOrigin) return {
73
- kind: "unavailable",
74
- reason: "duplicate-source-origin"
75
- };
76
- if (Object.keys(byNodeId).length === 0) return {
77
- kind: "unavailable",
78
- reason: "no-source-metadata"
79
- };
80
- return {
81
- kind: "available",
82
- byNodeId: Object.freeze(byNodeId)
83
- };
84
- };
85
- /** Compare source-map statuses for the emission determinism guard. */
86
- const sameTemplateSourceLocations = (left, right) => {
87
- if (left.kind !== right.kind) return false;
88
- if (left.kind === "unavailable") return right.kind === "unavailable" && left.reason === right.reason;
89
- if (right.kind === "unavailable") return false;
90
- const leftEntries = Object.entries(left.byNodeId);
91
- const rightEntries = Object.entries(right.byNodeId);
92
- if (leftEntries.length !== rightEntries.length) return false;
93
- for (const [nodeId, source] of leftEntries) {
94
- const other = right.byNodeId[nodeId];
95
- if (other === void 0 || other.fileName !== source.fileName || other.lineNumber !== source.lineNumber || other.columnNumber !== source.columnNumber) return false;
96
- }
97
- return true;
98
- };
99
- //#endregion
100
- export { JSX_SOURCE_LOCATION, JSX_SOURCE_LOCATION_PROP, attachJsxSourceLocation, completeJsxSourceLocation, jsxSourceLocationOf, mapJsxSourceLocations, sameTemplateSourceLocations };
101
-
102
- //# sourceMappingURL=source-locations.js.map
@@ -1,13 +0,0 @@
1
- import { r as StarterCategory } from "../catalog-CKuOooB8.js";
2
- import { TemplateCollectionId } from "./public-gallery.js";
3
- //#region starters/category-mapping.d.ts
4
- declare const LAB_DIMENSIONS: readonly ["newsletter", "receipt", "security", "product-update", "onboarding", "promotion", "shipping", "social-notification"];
5
- type LabDimension = (typeof LAB_DIMENSIONS)[number];
6
- declare const LAB_KINDS: readonly ["newsletter", "receipt", "security", "product-update", "onboarding", "promotion", "shipping", "social-notification", "digest", "invoice", "account", "event", "statement", "developer-notification", "unknown"];
7
- type LabKind = (typeof LAB_KINDS)[number];
8
- declare const labKindToStarterCategory: Record<LabKind, StarterCategory>;
9
- declare const starterCategoryToCollection: Record<StarterCategory, TemplateCollectionId>;
10
- declare const labKindToCollection: (kind: LabKind) => TemplateCollectionId;
11
- //#endregion
12
- export { LAB_DIMENSIONS, LAB_KINDS, LabDimension, LabKind, labKindToCollection, labKindToStarterCategory, starterCategoryToCollection };
13
- //# sourceMappingURL=category-mapping.d.ts.map
@@ -1,49 +0,0 @@
1
- //#region starters/category-mapping.ts
2
- const LAB_DIMENSIONS = [
3
- "newsletter",
4
- "receipt",
5
- "security",
6
- "product-update",
7
- "onboarding",
8
- "promotion",
9
- "shipping",
10
- "social-notification"
11
- ];
12
- const LAB_KINDS = [
13
- ...LAB_DIMENSIONS,
14
- "digest",
15
- "invoice",
16
- "account",
17
- "event",
18
- "statement",
19
- "developer-notification",
20
- "unknown"
21
- ];
22
- const labKindToStarterCategory = {
23
- newsletter: "digest",
24
- receipt: "transactional",
25
- security: "transactional",
26
- "product-update": "marketing",
27
- onboarding: "lifecycle",
28
- promotion: "marketing",
29
- shipping: "transactional",
30
- "social-notification": "transactional",
31
- digest: "digest",
32
- invoice: "transactional",
33
- account: "transactional",
34
- event: "marketing",
35
- statement: "transactional",
36
- "developer-notification": "transactional",
37
- unknown: "transactional"
38
- };
39
- const starterCategoryToCollection = {
40
- transactional: "category:transactional",
41
- digest: "category:digest-editorial",
42
- marketing: "category:marketing",
43
- lifecycle: "category:lifecycle"
44
- };
45
- const labKindToCollection = (kind) => starterCategoryToCollection[labKindToStarterCategory[kind]];
46
- //#endregion
47
- export { LAB_DIMENSIONS, LAB_KINDS, labKindToCollection, labKindToStarterCategory, starterCategoryToCollection };
48
-
49
- //# sourceMappingURL=category-mapping.js.map
@@ -1,2 +0,0 @@
1
- import { a as PublicCorpusRegistrationIssue, c as TemplateFacetQuery, d as matchesTemplateFacets, f as ownedShowcaseStarterSources, h as templateFacetOptions, i as PublicCorpusRegistration, l as TemplateFacetSet, m as registerPublicCorpusEntry, n as InspirationReference, o as TemplateCorpusKind, p as ownedStarterSourcePath, r as OwnedEditableStarter, s as TemplateCorpusRecord, t as BrandRecreationStarter, u as brandRecreationProvenance } from "../corpus-CPPfgAHN.js";
2
- export { BrandRecreationStarter, InspirationReference, OwnedEditableStarter, PublicCorpusRegistration, PublicCorpusRegistrationIssue, TemplateCorpusKind, TemplateCorpusRecord, TemplateFacetQuery, TemplateFacetSet, brandRecreationProvenance, matchesTemplateFacets, ownedShowcaseStarterSources, ownedStarterSourcePath, registerPublicCorpusEntry, templateFacetOptions };
@@ -1,194 +0,0 @@
1
- import { n as isObject } from "../guards-eV1qLbf2.js";
2
- import { starterCatalog } from "../starters.js";
3
- import { showcaseProject, showcaseProjects, showcaseSourcePath } from "./showcase.js";
4
- import { Result } from "better-result";
5
- //#region starters/corpus.ts
6
- const templateFacetOptions = {
7
- jobType: [
8
- "account-access",
9
- "commerce",
10
- "product-communication",
11
- "lifecycle",
12
- "publishing-campaigns"
13
- ],
14
- lifecycle: [
15
- "acquisition",
16
- "activation",
17
- "engagement",
18
- "transaction",
19
- "retention",
20
- "recovery"
21
- ],
22
- industry: [
23
- "saas",
24
- "ecommerce",
25
- "developer-tools",
26
- "newsletters-media"
27
- ],
28
- season: ["evergreen", "seasonal"],
29
- audience: [
30
- "product-users",
31
- "customers",
32
- "members",
33
- "readers",
34
- "shoppers",
35
- "teams"
36
- ],
37
- design: [
38
- "minimal",
39
- "branded",
40
- "editorial",
41
- "data-heavy",
42
- "single-cta"
43
- ],
44
- brandProvenance: ["samva-original", "third-party-reference"]
45
- };
46
- /** Clean-room recreations of a named brand's own email, authored as editable Samva projects. */
47
- const brandRecreationProvenance = Object.fromEntries(showcaseProjects.flatMap((project) => project.provenance.kind === "brand-recreation" ? [[project.id, {
48
- owner: "Samva",
49
- sourcePath: showcaseSourcePath(project),
50
- recordedAt: project.recordedAt,
51
- brand: project.provenance.brand,
52
- subject: project.provenance.subject,
53
- reviewedNote: project.provenance.reviewedNote
54
- }]] : []));
55
- /**
56
- * Owned starters authored as complete showcase projects with their own stylesheet and assets.
57
- * Every other owned starter is the single module `packages/markup/starters/<id>.tsx`.
58
- */
59
- const ownedShowcaseStarterSources = Object.fromEntries(showcaseProjects.flatMap((project) => project.provenance.kind === "owned" ? [[project.id, showcaseSourcePath(project)]] : []));
60
- const ownedStarterSourcePath = (id) => {
61
- const project = showcaseProject(id);
62
- return project === void 0 || project.provenance.kind !== "owned" ? `packages/markup/starters/${id}.tsx` : showcaseSourcePath(project);
63
- };
64
- const ISO_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/;
65
- const nonEmpty = (value) => value.trim().length > 0;
66
- const isHttpsUrl = (value) => {
67
- const url = URL.parse(value);
68
- return url?.protocol === "https:" && url.hostname.length > 0 && url.username.length === 0 && url.password.length === 0;
69
- };
70
- const requiredFacetDimensions = [
71
- "jobType",
72
- "lifecycle",
73
- "industry",
74
- "season",
75
- "audience",
76
- "design",
77
- "brandProvenance"
78
- ];
79
- /** Exact key sets: a record carrying anything else is not the shape this gate admits. */
80
- const exactKeys = (value, keys) => isObject(value) && Object.keys(value).length === keys.length && keys.every((key) => Object.hasOwn(value, key));
81
- const isStringIn = (value, values) => typeof value === "string" && values.includes(value);
82
- const isStringArrayIn = (value, values) => Array.isArray(value) && value.every((entry) => isStringIn(entry, values));
83
- const isReview = (value) => exactKeys(value, [
84
- "state",
85
- "reviewedBy",
86
- "reviewedAt",
87
- "notes"
88
- ]) && isStringIn(value.state, [
89
- "draft",
90
- "approved",
91
- "rejected"
92
- ]) && typeof value.reviewedBy === "string" && typeof value.reviewedAt === "string" && typeof value.notes === "string";
93
- const isDisplay = (value) => exactKeys(value, ["state", "attributionLabel"]) && isStringIn(value.state, ["hidden", "public"]) && typeof value.attributionLabel === "string";
94
- const isRetention = (value) => exactKeys(value, ["policy", "reviewedAt"]) && isStringIn(value.policy, ["retain-until-withdrawn", "retain-while-linked"]) && typeof value.reviewedAt === "string";
95
- const isTakedown = (value) => exactKeys(value, [
96
- "state",
97
- "contact",
98
- "procedureUrl"
99
- ]) && isStringIn(value.state, ["active", "removed"]) && typeof value.contact === "string" && typeof value.procedureUrl === "string";
100
- /** The four governance blocks every corpus record carries, whatever its kind. */
101
- const hasGovernance = (value) => isReview(value.review) && isDisplay(value.display) && isRetention(value.retention) && isTakedown(value.takedown);
102
- const CORPUS_KEYS = [
103
- "type",
104
- "corpusKind",
105
- "provenance",
106
- "review",
107
- "display",
108
- "retention",
109
- "takedown"
110
- ];
111
- const isCorpusRecord = (value) => {
112
- if (!exactKeys(value, CORPUS_KEYS) || !hasGovernance(value)) return false;
113
- const provenance = value.provenance;
114
- if (value.type === "OwnedEditableStarter") return value.corpusKind === "owned-editable-sml" && exactKeys(provenance, [
115
- "owner",
116
- "sourcePath",
117
- "recordedAt"
118
- ]) && provenance.owner === "Samva" && typeof provenance.sourcePath === "string" && typeof provenance.recordedAt === "string";
119
- if (value.type === "BrandRecreationStarter") return value.corpusKind === "brand-recreation-sml" && exactKeys(provenance, [
120
- "owner",
121
- "sourcePath",
122
- "recordedAt",
123
- "brand",
124
- "subject",
125
- "reviewedNote"
126
- ]) && provenance.owner === "Samva" && typeof provenance.sourcePath === "string" && typeof provenance.recordedAt === "string" && typeof provenance.brand === "string" && typeof provenance.subject === "string" && typeof provenance.reviewedNote === "string";
127
- return value.type === "InspirationReference" && value.corpusKind === "inspiration-reference" && exactKeys(provenance, [
128
- "publisher",
129
- "sourceUrl",
130
- "capturedAt",
131
- "rightsBasis"
132
- ]) && typeof provenance.publisher === "string" && typeof provenance.sourceUrl === "string" && typeof provenance.capturedAt === "string" && isStringIn(provenance.rightsBasis, ["display-link-and-commentary", "permission"]);
133
- };
134
- const isFacetSet = (value) => exactKeys(value, requiredFacetDimensions) && requiredFacetDimensions.every((dimension) => isStringArrayIn(value[dimension], templateFacetOptions[dimension]));
135
- const isCorpusEntry = (value) => exactKeys(value, [
136
- "id",
137
- "corpus",
138
- "facets"
139
- ]) && typeof value.id === "string" && isCorpusRecord(value.corpus) && isFacetSet(value.facets);
140
- const canonicalOwnedStarterSources = new Map(starterCatalog.filter((starter) => starter.channel === "email" && !Object.hasOwn(brandRecreationProvenance, starter.id)).map((starter) => [starter.id, ownedStarterSourcePath(starter.id)]));
141
- /** Decode and gate a record before it can enter any public projection. */
142
- const registerPublicCorpusEntry = (input) => {
143
- if (!isCorpusEntry(input)) return Result.err({
144
- id: "unknown",
145
- message: "record does not match a corpus schema"
146
- });
147
- const { id, corpus, facets } = input;
148
- const timestamps = [
149
- corpus.review.reviewedAt,
150
- corpus.retention.reviewedAt,
151
- corpus.type === "InspirationReference" ? corpus.provenance.capturedAt : corpus.provenance.recordedAt
152
- ];
153
- if (!nonEmpty(id) || corpus.review.state !== "approved" || !nonEmpty(corpus.review.reviewedBy) || !nonEmpty(corpus.review.notes) || corpus.display.state !== "public" || !nonEmpty(corpus.display.attributionLabel) || corpus.takedown.state !== "active" || !nonEmpty(corpus.takedown.contact) || !isHttpsUrl(corpus.takedown.procedureUrl) || timestamps.some((timestamp) => !ISO_TIMESTAMP.test(timestamp))) return Result.err({
154
- id,
155
- message: "public corpus records require approved review, display, retention, and takedown metadata"
156
- });
157
- if (corpus.type === "OwnedEditableStarter" && (canonicalOwnedStarterSources.get(id) !== corpus.provenance.sourcePath || corpus.retention.policy !== "retain-until-withdrawn" || facets.brandProvenance.some((value) => value !== "samva-original"))) return Result.err({
158
- id,
159
- message: "owned starters require a canonical editable TSX source"
160
- });
161
- if (corpus.type === "BrandRecreationStarter") {
162
- const canonical = Object.entries(brandRecreationProvenance).find(([starterId]) => starterId === id)?.[1];
163
- if (canonical === void 0 || Object.entries(canonical).some(([key, value]) => corpus.provenance[key] !== value) || !nonEmpty(corpus.provenance.brand) || !nonEmpty(corpus.provenance.subject) || corpus.retention.policy !== "retain-until-withdrawn" || facets.brandProvenance.some((value) => value !== "third-party-reference")) return Result.err({
164
- id,
165
- message: "brand recreations require a canonical source, a referenced brand and subject, and third-party provenance"
166
- });
167
- }
168
- if (corpus.type === "InspirationReference" && (!isHttpsUrl(corpus.provenance.sourceUrl) || corpus.retention.policy !== "retain-while-linked" || facets.brandProvenance.some((value) => value !== "third-party-reference"))) return Result.err({
169
- id,
170
- message: "inspiration references require an HTTPS source and third-party provenance facet"
171
- });
172
- for (const dimension of requiredFacetDimensions) {
173
- const values = facets[dimension];
174
- if (values.length === 0 || new Set(values).size !== values.length) return Result.err({
175
- id,
176
- message: `facet ${dimension} must be populated without duplicates`
177
- });
178
- }
179
- return Result.ok({
180
- id,
181
- corpus,
182
- facets
183
- });
184
- };
185
- /** Strict intersection: every selected value in every selected dimension must match. */
186
- const matchesTemplateFacets = (facets, query) => requiredFacetDimensions.every((dimension) => {
187
- const selected = query[dimension];
188
- const available = new Set(facets[dimension]);
189
- return selected === void 0 || selected.every((value) => available.has(value));
190
- });
191
- //#endregion
192
- export { brandRecreationProvenance, matchesTemplateFacets, ownedShowcaseStarterSources, ownedStarterSourcePath, registerPublicCorpusEntry, templateFacetOptions };
193
-
194
- //# sourceMappingURL=corpus.js.map
@@ -1,18 +0,0 @@
1
- //#region starters/library.gen.d.ts
2
- /** One public gallery template whose project the Agents Worker serves at `/library/<digest>.json`. */
3
- interface LibraryTemplate {
4
- readonly slug: string;
5
- readonly starterId: string;
6
- readonly name: string;
7
- /** SHA-256 of the served project bytes, lowercase hex. */
8
- readonly digest: string;
9
- /** Project-relative paths, so a listing needs no fetch. */
10
- readonly paths: ReadonlyArray<string>;
11
- readonly byteSize: number;
12
- }
13
- declare const libraryTemplates: ReadonlyArray<LibraryTemplate>;
14
- /** Identifies this exact library; a workspace records it to notice a changed gallery. */
15
- declare const libraryManifestDigest = "60bd511a973a6d1fe17bc6a03990118dd2a0e8a1f14556f09aaf54713420fd53";
16
- //#endregion
17
- export { LibraryTemplate, libraryManifestDigest, libraryTemplates };
18
- //# sourceMappingURL=library.d.ts.map