@seamlet/astro 1.4.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/feeds.js ADDED
@@ -0,0 +1,174 @@
1
+ import {
2
+ plainTextOf
3
+ } from "./chunk-PAGIPRTS.js";
4
+
5
+ // src/feeds/xml.ts
6
+ var ESCAPES = {
7
+ "&": "&",
8
+ "<": "&lt;",
9
+ ">": "&gt;",
10
+ '"': "&quot;",
11
+ "'": "&apos;"
12
+ };
13
+ var TAB = 9;
14
+ var LINE_FEED = 10;
15
+ var CARRIAGE_RETURN = 13;
16
+ var FIRST_PRINTED = 32;
17
+ var NOT_CHARACTERS = /* @__PURE__ */ new Set([65534, 65535]);
18
+ function escapeXml(text) {
19
+ const kept = Array.from(text).filter(isXmlCharacter).join("");
20
+ return kept.replace(
21
+ /[&<>"']/gu,
22
+ (character) => ESCAPES[character] ?? character
23
+ );
24
+ }
25
+ function isXmlCharacter(character) {
26
+ const code = character.codePointAt(0) ?? 0;
27
+ const isWhitespace = code === TAB || code === LINE_FEED || code === CARRIAGE_RETURN;
28
+ return (isWhitespace || code >= FIRST_PRINTED) && !NOT_CHARACTERS.has(code);
29
+ }
30
+ function textElement(name, text) {
31
+ return `<${name}>${escapeXml(text)}</${name}>`;
32
+ }
33
+ var XML_DECLARATION = '<?xml version="1.0" encoding="UTF-8"?>';
34
+
35
+ // src/feeds/avito-feed.ts
36
+ var TITLE_LENGTH = 50;
37
+ var MOST_IMAGES = 10;
38
+ var DESCRIPTION_LENGTH = 7500;
39
+ function avitoFeedOf(seller, offers, fieldsOf = () => ({})) {
40
+ const priced = offers.filter((offer) => (offer.price ?? 0) > 0);
41
+ const ads = priced.map((offer) => adOf(seller, offer, fieldsOf(offer)));
42
+ return [
43
+ XML_DECLARATION,
44
+ '<Ads formatVersion="3" target="Avito.ru">',
45
+ ...ads,
46
+ "</Ads>"
47
+ ].join("\n");
48
+ }
49
+ function adOf(seller, offer, fields) {
50
+ const images = offer.pictures.slice(0, MOST_IMAGES).map((picture) => `<Image url="${escapeXml(picture)}"/>`);
51
+ const extra = Object.entries(fields).map(
52
+ ([name, value]) => textElement(name, value)
53
+ );
54
+ return [
55
+ "<Ad>",
56
+ textElement("Id", offer.id),
57
+ textElement("Address", seller.address),
58
+ textElement("Category", seller.category),
59
+ textElement("Title", titleOf(offer.name)),
60
+ textElement("Description", offer.description.slice(0, DESCRIPTION_LENGTH)),
61
+ textElement("Price", String(offer.price)),
62
+ textElement("ContactPhone", seller.contactPhone),
63
+ images.length === 0 ? "" : `<Images>${images.join("")}</Images>`,
64
+ ...extra,
65
+ "</Ad>"
66
+ ].join("");
67
+ }
68
+ var GRAPHEMES = new Intl.Segmenter("ru-RU", { granularity: "grapheme" });
69
+ function titleOf(name) {
70
+ const characters = Array.from(
71
+ GRAPHEMES.segment(name.trim()),
72
+ ({ segment }) => segment
73
+ );
74
+ const cut = characters.slice(0, TITLE_LENGTH).join("");
75
+ const isWhole = characters.length <= TITLE_LENGTH;
76
+ if (isWhole) return cut;
77
+ const lastSpace = cut.lastIndexOf(" ");
78
+ return (lastSpace > 0 ? cut.slice(0, lastSpace) : cut).trim();
79
+ }
80
+
81
+ // src/feeds/offers.ts
82
+ function productOffersOf(products, options) {
83
+ return products.flatMap((product) => {
84
+ const id = product.id;
85
+ if (product.isHidden || id === void 0) return [];
86
+ return [offerOf(product, id, options)];
87
+ });
88
+ }
89
+ function offerOf(product, id, options) {
90
+ const path = options.pathOf?.(product) ?? options.catalogPath ?? "/";
91
+ const photos = product.photos.flatMap(
92
+ ({ photo }) => photo === null || photo.src.trim() === "" ? [] : [photo.src]
93
+ );
94
+ const description = descriptionOf(product);
95
+ const category = options.categoryOf?.(product);
96
+ return {
97
+ id,
98
+ name: product.name,
99
+ url: new URL(path, options.siteUrl).href,
100
+ price: product.price,
101
+ description,
102
+ pictures: photos.map((src) => new URL(src, options.siteUrl).href),
103
+ ...category === void 0 ? {} : { category }
104
+ };
105
+ }
106
+ function descriptionOf(product) {
107
+ const whole = plainTextOf(product.description).trim();
108
+ return whole === "" ? plainTextOf(product.summary).trim() : whole;
109
+ }
110
+
111
+ // src/feeds/yandex-feed.ts
112
+ var OFFER_ID_LENGTH = 20;
113
+ var NOT_OFFER_ID = /[^A-Za-z0-9]/gu;
114
+ var DESCRIPTION_LENGTH2 = 3e3;
115
+ var SHOP_CATEGORY_ID = "1";
116
+ function yandexFeedOf(shop, offers, madeAt) {
117
+ const priced = offers.filter((offer) => (offer.price ?? 0) > 0);
118
+ const categories = categoryIdsOf(priced, shop.name);
119
+ const offerElements = priced.map(
120
+ (offer) => offerElementOf(
121
+ offer,
122
+ categories.get(offer.category ?? shop.name) ?? SHOP_CATEGORY_ID
123
+ )
124
+ );
125
+ const categoryElements = [...categories].map(
126
+ ([name, id]) => `<category id="${id}">${escapeXml(name)}</category>`
127
+ );
128
+ return [
129
+ XML_DECLARATION,
130
+ `<yml_catalog date="${dateOf(madeAt)}">`,
131
+ "<shop>",
132
+ textElement("name", shop.name),
133
+ textElement("company", shop.company),
134
+ textElement("url", shop.url),
135
+ '<currencies><currency id="RUB" rate="1"/></currencies>',
136
+ `<categories>${categoryElements.join("")}</categories>`,
137
+ `<offers>${offerElements.join("")}</offers>`,
138
+ "</shop>",
139
+ "</yml_catalog>"
140
+ ].join("\n");
141
+ }
142
+ function categoryIdsOf(offers, shopName) {
143
+ const names = offers.map((offer) => offer.category ?? shopName);
144
+ const unique = [...new Set(names)];
145
+ return new Map(unique.map((name, index) => [name, String(index + 1)]));
146
+ }
147
+ function offerElementOf(offer, categoryId) {
148
+ const pictures = offer.pictures.map(
149
+ (picture) => textElement("picture", picture)
150
+ );
151
+ const description = offer.description.slice(0, DESCRIPTION_LENGTH2);
152
+ return [
153
+ `<offer id="${offerIdOf(offer.id)}" available="true">`,
154
+ textElement("name", offer.name),
155
+ textElement("url", offer.url),
156
+ textElement("price", String(offer.price)),
157
+ "<currencyId>RUB</currencyId>",
158
+ textElement("categoryId", categoryId),
159
+ ...pictures,
160
+ description === "" ? "" : textElement("description", description),
161
+ "</offer>"
162
+ ].join("");
163
+ }
164
+ function offerIdOf(id) {
165
+ return id.replace(NOT_OFFER_ID, "").slice(0, OFFER_ID_LENGTH);
166
+ }
167
+ function dateOf(moment) {
168
+ return `${moment.toISOString().slice(0, 19)}Z`;
169
+ }
170
+ export {
171
+ avitoFeedOf,
172
+ productOffersOf,
173
+ yandexFeedOf
174
+ };
package/dist/index.js CHANGED
@@ -1,21 +1,21 @@
1
+ import {
2
+ isUploadedFile
3
+ } from "./chunk-NOAAAA5T.js";
1
4
  import {
2
5
  OWN_PHOTOS_PATH
3
6
  } from "./chunk-W2LIOR2C.js";
4
- import {
5
- PREVIEW_PATH,
6
- SITE_MODULE_FILE,
7
- UPLOADS_PATH
8
- } from "./chunk-QCVWHHJC.js";
9
- import {
10
- isUploadedFile
11
- } from "./chunk-JQ4YD7MM.js";
12
- import "./chunk-ULOKDC6D.js";
7
+ import "./chunk-CTS7Q45A.js";
13
8
  import {
14
9
  SITE_CONFIG_FILE,
15
10
  SITE_DESCRIPTION_PATH,
16
11
  isJsonObject,
17
12
  readSiteConfig
18
- } from "./chunk-TMN7KG5M.js";
13
+ } from "./chunk-PAGIPRTS.js";
14
+ import {
15
+ PREVIEW_PATH,
16
+ SITE_MODULE_FILE,
17
+ UPLOADS_PATH
18
+ } from "./chunk-QCVWHHJC.js";
19
19
 
20
20
  // src/index.ts
21
21
  import process from "process";
@@ -1,4 +1,5 @@
1
- import { R as RichText, F as Fields, C as Content, a as FieldPath } from './parse-content-CT2cUVL-.js';
1
+ import { f as RichText, F as Fields, C as Content } from './content-ZG6F3MPA.js';
2
+ import { F as FieldPath } from './parse-content-Dtec5MKj.js';
2
3
 
3
4
  interface Box {
4
5
  readonly top: number;
@@ -0,0 +1,83 @@
1
+ import { F as Fields, e as ContentOf } from './content-ZG6F3MPA.js';
2
+
3
+ /** Where a value lives in the content: field names and, inside a collection, record indexes. */
4
+ type FieldPath = readonly (string | number)[];
5
+ type ContentIssue = {
6
+ readonly path: FieldPath;
7
+ readonly code: "invalid-type";
8
+ } | {
9
+ readonly path: FieldPath;
10
+ readonly code: "invalid-date";
11
+ } | {
12
+ readonly path: FieldPath;
13
+ readonly code: "invalid-time";
14
+ } | {
15
+ readonly path: FieldPath;
16
+ readonly code: "too-long";
17
+ readonly maxLength: number;
18
+ } | {
19
+ readonly path: FieldPath;
20
+ readonly code: "below-min";
21
+ readonly min: number;
22
+ } | {
23
+ readonly path: FieldPath;
24
+ readonly code: "above-max";
25
+ readonly max: number;
26
+ } | {
27
+ readonly path: FieldPath;
28
+ readonly code: "missing-image-src";
29
+ } | {
30
+ readonly path: FieldPath;
31
+ readonly code: "missing-file-src";
32
+ } | {
33
+ readonly path: FieldPath;
34
+ readonly code: "missing-link-href";
35
+ } | {
36
+ readonly path: FieldPath;
37
+ readonly code: "unsupported-link-href";
38
+ } | {
39
+ readonly path: FieldPath;
40
+ readonly code: "unsupported-url";
41
+ } | {
42
+ readonly path: FieldPath;
43
+ readonly code: "unknown-choice";
44
+ readonly value: string;
45
+ } | {
46
+ readonly path: FieldPath;
47
+ readonly code: "missing-record";
48
+ readonly id: string;
49
+ }
50
+ /** A slug with a character an address does not have. */
51
+ | {
52
+ readonly path: FieldPath;
53
+ readonly code: "invalid-slug";
54
+ }
55
+ /** A slug another record of the collection has as its slug or its id. */
56
+ | {
57
+ readonly path: FieldPath;
58
+ readonly code: "taken-slug";
59
+ };
60
+ interface ParsedContent<C> {
61
+ readonly content: C;
62
+ readonly issues: readonly ContentIssue[];
63
+ }
64
+ declare function formatFieldPath(path: FieldPath): string;
65
+ /**
66
+ * The length that `maxLength` limits: characters as people see them (grapheme clusters), so
67
+ * "й" and "👍🏽" are one character each, whatever number of code units they take.
68
+ */
69
+ declare function countCharacters(text: string): number;
70
+ /**
71
+ * Brings any input to the shape of the schema, so the result is always content of that schema:
72
+ * - a field missing from the input (the schema grew after the content was saved) gets its default;
73
+ * - a value of the wrong type or format gets the default too, and an issue;
74
+ * - a value of the right type that breaks a rule of its field (too long, below the minimum) is
75
+ * kept, with an issue: nothing a person typed is lost;
76
+ * - keys the schema does not know are dropped; a record keeps its id (see withRecordIds);
77
+ * - a reference to a record its collection does not have (removed since) is kept, with an issue;
78
+ * - a slug another record of the collection has is kept, with an issue.
79
+ * Content with issues is valid to show and edit, but not to save.
80
+ */
81
+ declare function parseContent<F extends Fields>(schema: F, input: unknown): ParsedContent<ContentOf<F>>;
82
+
83
+ export { type ContentIssue as C, type FieldPath as F, type ParsedContent as P, countCharacters as c, formatFieldPath as f, parseContent as p };
@@ -0,0 +1,104 @@
1
+ import { T as TextField, S as SlugField, a as CollectionField, I as ImageField, R as RichTextField, N as NumberField, b as ToggleField, G as GroupField, L as LinkField, U as UrlField, c as ChoicesField, d as TimeField } from './content-ZG6F3MPA.js';
2
+
3
+ /** What search engines and a link shared in a messenger show: one per page. */
4
+ declare function seoFields(options?: {
5
+ readonly label?: string;
6
+ }): GroupField<{
7
+ title: TextField;
8
+ description: TextField;
9
+ image: ImageField;
10
+ }>;
11
+ /** How to reach the business: the phone, the address with a map, the messengers. */
12
+ declare function contactsFields(options?: {
13
+ readonly label?: string;
14
+ }): GroupField<{
15
+ phone: LinkField;
16
+ address: TextField;
17
+ map: UrlField;
18
+ messengers: CollectionField<{
19
+ link: LinkField;
20
+ }>;
21
+ }>;
22
+ declare const WEEKDAYS: readonly [{
23
+ readonly value: "mon";
24
+ readonly label: "Пн";
25
+ }, {
26
+ readonly value: "tue";
27
+ readonly label: "Вт";
28
+ }, {
29
+ readonly value: "wed";
30
+ readonly label: "Ср";
31
+ }, {
32
+ readonly value: "thu";
33
+ readonly label: "Чт";
34
+ }, {
35
+ readonly value: "fri";
36
+ readonly label: "Пт";
37
+ }, {
38
+ readonly value: "sat";
39
+ readonly label: "Сб";
40
+ }, {
41
+ readonly value: "sun";
42
+ readonly label: "Вс";
43
+ }];
44
+ /** When the business is open: rows of days with the same hours, «Пн–Пт 08:00–21:00». */
45
+ declare function openingHoursField(options?: {
46
+ readonly label?: string;
47
+ }): CollectionField<{
48
+ days: ChoicesField<readonly [{
49
+ readonly value: "mon";
50
+ readonly label: "Пн";
51
+ }, {
52
+ readonly value: "tue";
53
+ readonly label: "Вт";
54
+ }, {
55
+ readonly value: "wed";
56
+ readonly label: "Ср";
57
+ }, {
58
+ readonly value: "thu";
59
+ readonly label: "Чт";
60
+ }, {
61
+ readonly value: "fri";
62
+ readonly label: "Пт";
63
+ }, {
64
+ readonly value: "sat";
65
+ readonly label: "Сб";
66
+ }, {
67
+ readonly value: "sun";
68
+ readonly label: "Вс";
69
+ }]>;
70
+ opens: TimeField;
71
+ closes: TimeField;
72
+ note: TextField;
73
+ }>;
74
+ /**
75
+ * The fields of a product of a catalog: its name and the address of its page, its photos (the first
76
+ * is the main one), a short line for a card and a whole description for its page, the price and a
77
+ * word about it («от», «за м²»), characteristics as pairs of a name and a value, so the owner adds a
78
+ * property without code, the switch that hides it, and what search engines show for its page. A
79
+ * site puts them into its collection and adds its own fields beside them:
80
+ * `item: { ...productFields(), category: reference({ label: "Категория", collection: "categories" }) }`.
81
+ */
82
+ declare function productFields(): {
83
+ name: TextField;
84
+ slug: SlugField;
85
+ photos: CollectionField<{
86
+ photo: ImageField;
87
+ }>;
88
+ summary: RichTextField;
89
+ description: RichTextField;
90
+ price: NumberField;
91
+ priceNote: TextField;
92
+ characteristics: CollectionField<{
93
+ name: TextField;
94
+ value: TextField;
95
+ }>;
96
+ isHidden: ToggleField;
97
+ seo: GroupField<{
98
+ title: TextField;
99
+ description: TextField;
100
+ image: ImageField;
101
+ }>;
102
+ };
103
+
104
+ export { WEEKDAYS as W, contactsFields as c, openingHoursField as o, productFields as p, seoFields as s };
@@ -1,5 +1,6 @@
1
- import { C as Content } from './parse-content-CT2cUVL-.js';
2
- import { S as SiteDescription } from './site-description-cKiFtNHW.js';
1
+ import { C as Content } from './content-ZG6F3MPA.js';
2
+ import { S as SiteDescription } from './site-description-0UU5Wukx.js';
3
+ import './parse-content-Dtec5MKj.js';
3
4
 
4
5
  /** Far more than the content of a site ever takes; a bigger body is not a draft. */
5
6
  declare const MAX_DRAFT_BYTES: number;
@@ -6,9 +6,9 @@ import {
6
6
  previewContentAt,
7
7
  previewHeadersOf,
8
8
  readDraft
9
- } from "./chunk-JQ4YD7MM.js";
10
- import "./chunk-ULOKDC6D.js";
11
- import "./chunk-TMN7KG5M.js";
9
+ } from "./chunk-NOAAAA5T.js";
10
+ import "./chunk-CTS7Q45A.js";
11
+ import "./chunk-PAGIPRTS.js";
12
12
  export {
13
13
  MAX_DRAFT_BYTES,
14
14
  isPageAddress,
@@ -1,6 +1,7 @@
1
- import { S as Shortcut, T as TextFormats } from './messages-Dwjthhrk.js';
2
- export { B as Box, a as EditorKey, E as EditorMessage, I as InlineEditingOutcome, L as LinkBox, M as MarkerBox, b as PROTOCOL_VERSION, c as PageLayout, P as PageMessage, d as Point, e as TextFormat, f as TypedSelection, V as Viewport, r as readEditorMessage, g as readPageMessage } from './messages-Dwjthhrk.js';
3
- import { F as Fields, a as FieldPath, I as ImageField, R as RichText } from './parse-content-CT2cUVL-.js';
1
+ import { S as Shortcut, T as TextFormats } from './messages-d-elsH_0.js';
2
+ export { B as Box, a as EditorKey, E as EditorMessage, I as InlineEditingOutcome, L as LinkBox, M as MarkerBox, b as PROTOCOL_VERSION, c as PageLayout, P as PageMessage, d as Point, e as TextFormat, f as TypedSelection, V as Viewport, r as readEditorMessage, g as readPageMessage } from './messages-d-elsH_0.js';
3
+ import { F as Fields, I as ImageField, f as RichText } from './content-ZG6F3MPA.js';
4
+ import { F as FieldPath } from './parse-content-Dtec5MKj.js';
4
5
 
5
6
  declare function shortcutOf(event: KeyboardEvent): Shortcut | undefined;
6
7
 
package/dist/protocol.js CHANGED
@@ -22,9 +22,9 @@ import {
22
22
  shortcutOf,
23
23
  toggleList,
24
24
  toggleMark
25
- } from "./chunk-BCJUH3ZD.js";
25
+ } from "./chunk-XZDRTVJH.js";
26
+ import "./chunk-PAGIPRTS.js";
26
27
  import "./chunk-QCVWHHJC.js";
27
- import "./chunk-TMN7KG5M.js";
28
28
  export {
29
29
  OWN_PHOTOS_PATH,
30
30
  PROTOCOL_VERSION,
@@ -12,7 +12,7 @@ import {
12
12
  isJsonObject,
13
13
  readRequestForm,
14
14
  readRequestValues
15
- } from "./chunk-TMN7KG5M.js";
15
+ } from "./chunk-PAGIPRTS.js";
16
16
 
17
17
  // src/request-sending.ts
18
18
  var STATUS_CREATED = 201;
@@ -1,11 +1,11 @@
1
+ import {
2
+ isUploadedFile
3
+ } from "../chunk-NOAAAA5T.js";
4
+ import "../chunk-CTS7Q45A.js";
5
+ import "../chunk-PAGIPRTS.js";
1
6
  import {
2
7
  uploadedPhotoPath
3
8
  } from "../chunk-QCVWHHJC.js";
4
- import {
5
- isUploadedFile
6
- } from "../chunk-JQ4YD7MM.js";
7
- import "../chunk-ULOKDC6D.js";
8
- import "../chunk-TMN7KG5M.js";
9
9
 
10
10
  // src/routes/media.ts
11
11
  import { cmsOrigin } from "virtual:seamlet/config";
package/dist/schema.d.ts CHANGED
@@ -1,7 +1,9 @@
1
- import { h as ImageValue, L as LinkValue, d as CollectionField, C as Content, F as Fields, e as RecordFields, b as ContentOf, G as GroupField, i as LinkField, T as TextField, U as UrlField, j as ChoicesField, k as TimeField, S as SlugField, I as ImageField, l as RichTextField, N as NumberField, m as ToggleField } from './parse-content-CT2cUVL-.js';
2
- export { n as ChoiceField, o as ChoiceOption, g as ContentIssue, D as DateField, c as Field, p as FieldKind, a as FieldPath, q as FieldValue, r as FileField, s as FileValue, t as ImageFocus, O as OptionValue, P as ParsedContent, f as RecordOf, u as ReferenceField, v as ReferencesField, w as RichBlock, x as RichLine, y as RichSpan, R as RichText, V as ValueOf, z as asOneParagraph, A as choice, B as choices, E as collection, H as countCharacters, J as date, K as defaultContent, M as defaultValue, Q as defineSchema, W as file, X as formatFieldPath, Y as group, Z as image, _ as linesOf, $ as link, a0 as normalizedLine, a1 as number, a2 as parseContent, a3 as plainTextOf, a4 as readRichText, a5 as reference, a6 as references, a7 as richText, a8 as richTextOf, a9 as slug, aa as text, ab as time, ac as toggle, ad as url } from './parse-content-CT2cUVL-.js';
3
- import { R as RequestForm } from './site-description-cKiFtNHW.js';
4
- export { C as CollectionPath, D as DEFAULT_LONG_TEXT_LENGTH, b as DEFAULT_TEXT_LENGTH, F as FIELD_PATH_SEPARATOR, c as FieldTarget, d as FieldsReading, H as HOME_PAGE_PATH, M as MAX_REQUEST_FIELD_LENGTH, P as PAGE_PATH_SEPARATOR, e as PageProblemReason, f as PlacedRecord, g as RECORD_PLACEHOLDER, h as RecordFieldsAt, i as RecordPagePath, j as RecordPageProblemReason, k as RecordPages, l as RequestChoiceField, m as RequestEmailField, n as RequestField, o as RequestFieldKind, p as RequestFields, q as RequestFormProblemReason, r as RequestFormReading, s as RequestLongTextField, t as RequestPhoneField, u as RequestTextField, v as SITE_DESCRIPTION_PATH, w as SchemaProblem, x as SchemaProblemReason, S as SiteDescription, y as SiteDescriptionProblem, z as SiteDescriptionReading, A as SitePageDescription, B as SiteRecordPageDescription, a as SiteRecordPages, E as checkFields, G as checkSiteDescription, I as isFormId, J as isRecordPagePath, K as isSearchTextsGroup, L as maxLengthOf, N as readFields, O as readRequestForm, Q as readSiteDescription, T as recordAddressOf, U as recordAt, V as recordPageAt, W as recordPagePath, X as recordPages, Y as requestChoice, Z as requestEmail, _ as requestForm, $ as requestLongText, a0 as requestPhone, a1 as requestText, a2 as resolveFieldPath } from './site-description-cKiFtNHW.js';
1
+ import { j as ImageValue, k as LinkValue, a as CollectionField, C as Content, F as Fields, i as RecordFields, e as ContentOf, g as RecordOf, T as TextField, N as NumberField, G as GroupField, R as RichTextField, f as RichText } from './content-ZG6F3MPA.js';
2
+ export { l as ChoiceField, m as ChoiceOption, c as ChoicesField, D as DateField, h as Field, n as FieldKind, o as FieldValue, p as FileField, q as FileValue, I as ImageField, r as ImageFocus, L as LinkField, O as OptionValue, s as ReferenceField, t as ReferencesField, u as RichBlock, v as RichLine, w as RichSpan, S as SlugField, d as TimeField, b as ToggleField, U as UrlField, V as ValueOf, x as asOneParagraph, y as choice, z as choices, A as collection, B as date, E as defaultContent, H as defaultValue, J as defineSchema, K as file, M as group, P as image, Q as linesOf, W as link, X as normalizedLine, Y as number, Z as plainTextOf, _ as readRichText, $ as reference, a0 as references, a1 as richText, a2 as richTextOf, a3 as slug, a4 as text, a5 as time, a6 as toggle, a7 as url } from './content-ZG6F3MPA.js';
3
+ export { C as ContentIssue, F as FieldPath, P as ParsedContent, c as countCharacters, f as formatFieldPath, p as parseContent } from './parse-content-Dtec5MKj.js';
4
+ import { R as RequestForm } from './site-description-0UU5Wukx.js';
5
+ export { C as CollectionPath, D as DEFAULT_LONG_TEXT_LENGTH, b as DEFAULT_TEXT_LENGTH, F as FIELD_PATH_SEPARATOR, c as FieldTarget, d as FieldsReading, H as HOME_PAGE_PATH, M as MAX_REQUEST_FIELD_LENGTH, P as PAGE_PATH_SEPARATOR, e as PageProblemReason, f as PlacedRecord, g as RECORD_PLACEHOLDER, h as RecordFieldsAt, i as RecordPagePath, j as RecordPageProblemReason, k as RecordPages, l as RequestChoiceField, m as RequestEmailField, n as RequestField, o as RequestFieldKind, p as RequestFields, q as RequestFormProblemReason, r as RequestFormReading, s as RequestLongTextField, t as RequestPhoneField, u as RequestTextField, v as SITE_DESCRIPTION_PATH, w as SchemaProblem, x as SchemaProblemReason, S as SiteDescription, y as SiteDescriptionProblem, z as SiteDescriptionReading, A as SitePageDescription, B as SiteRecordPageDescription, a as SiteRecordPages, E as checkFields, G as checkSiteDescription, I as isFormId, J as isRecordPagePath, K as isSearchTextsGroup, L as maxLengthOf, N as readFields, O as readRequestForm, Q as readSiteDescription, T as recordAddressOf, U as recordAt, V as recordPageAt, W as recordPagePath, X as recordPages, Y as requestChoice, Z as requestEmail, _ as requestForm, $ as requestLongText, a0 as requestPhone, a1 as requestText, a2 as resolveFieldPath } from './site-description-0UU5Wukx.js';
6
+ export { W as WEEKDAYS, c as contactsFields, o as openingHoursField, p as productFields, s as seoFields } from './presets-Ch54FeQK.js';
5
7
 
6
8
  declare const FIELD_PATH_ATTRIBUTE = "data-cms-path";
7
9
  interface FieldMarker {
@@ -89,106 +91,21 @@ declare function hrefOf(target: LinkTarget): string;
89
91
  /** `object-position` of the photo: "50% 30%"; the middle when no point is chosen. */
90
92
  declare function imagePosition(image: ImageValue | null): string;
91
93
 
92
- /** What search engines and a link shared in a messenger show: one per page. */
93
- declare function seoFields(options?: {
94
- readonly label?: string;
95
- }): GroupField<{
96
- title: TextField;
97
- description: TextField;
98
- image: ImageField;
99
- }>;
100
- /** How to reach the business: the phone, the address with a map, the messengers. */
101
- declare function contactsFields(options?: {
102
- readonly label?: string;
103
- }): GroupField<{
104
- phone: LinkField;
105
- address: TextField;
106
- map: UrlField;
107
- messengers: CollectionField<{
108
- link: LinkField;
109
- }>;
110
- }>;
111
- declare const WEEKDAYS: readonly [{
112
- readonly value: "mon";
113
- readonly label: "Пн";
114
- }, {
115
- readonly value: "tue";
116
- readonly label: "Вт";
117
- }, {
118
- readonly value: "wed";
119
- readonly label: "Ср";
120
- }, {
121
- readonly value: "thu";
122
- readonly label: "Чт";
123
- }, {
124
- readonly value: "fri";
125
- readonly label: "Пт";
126
- }, {
127
- readonly value: "sat";
128
- readonly label: "Сб";
129
- }, {
130
- readonly value: "sun";
131
- readonly label: "Вс";
132
- }];
133
- /** When the business is open: rows of days with the same hours, «Пн–Пт 08:00–21:00». */
134
- declare function openingHoursField(options?: {
94
+ /** The rates of a calculator: what is counted, in what unit and at what price. */
95
+ declare function ratesField(options?: {
135
96
  readonly label?: string;
136
97
  }): CollectionField<{
137
- days: ChoicesField<readonly [{
138
- readonly value: "mon";
139
- readonly label: "Пн";
140
- }, {
141
- readonly value: "tue";
142
- readonly label: "Вт";
143
- }, {
144
- readonly value: "wed";
145
- readonly label: "Ср";
146
- }, {
147
- readonly value: "thu";
148
- readonly label: "Чт";
149
- }, {
150
- readonly value: "fri";
151
- readonly label: "Пт";
152
- }, {
153
- readonly value: "sat";
154
- readonly label: "Сб";
155
- }, {
156
- readonly value: "sun";
157
- readonly label: "Вс";
158
- }]>;
159
- opens: TimeField;
160
- closes: TimeField;
161
- note: TextField;
98
+ name: TextField;
99
+ unit: TextField;
100
+ price: NumberField;
162
101
  }>;
102
+ type Rate = RecordOf<ReturnType<typeof ratesField>["item"]>;
163
103
  /**
164
- * The fields of a product of a catalog: its name and the address of its page, its photos (the first
165
- * is the main one), a short line for a card and a whole description for its page, the price and a
166
- * word about it («от», «за м²»), characteristics as pairs of a name and a value, so the owner adds a
167
- * property without code, the switch that hides it, and what search engines show for its page. A
168
- * site puts them into its collection and adds its own fields beside them:
169
- * `item: { ...productFields(), category: reference({ label: "Категория", collection: "categories" }) }`.
104
+ * The sum of the amounts a visitor chose at the rates, in whole rubles. An amount is known by the
105
+ * id of its rate; a rate without a price, an amount of no rate and an amount below zero add
106
+ * nothing.
170
107
  */
171
- declare function productFields(): {
172
- name: TextField;
173
- slug: SlugField;
174
- photos: CollectionField<{
175
- photo: ImageField;
176
- }>;
177
- summary: RichTextField;
178
- description: RichTextField;
179
- price: NumberField;
180
- priceNote: TextField;
181
- characteristics: CollectionField<{
182
- name: TextField;
183
- value: TextField;
184
- }>;
185
- isHidden: ToggleField;
186
- seo: GroupField<{
187
- title: TextField;
188
- description: TextField;
189
- image: ImageField;
190
- }>;
191
- };
108
+ declare function estimateOf(rates: readonly Rate[], amounts: Readonly<Record<string, number>>): number;
192
109
 
193
110
  /** An object of named values: not null, not a list. */
194
111
  type JsonObject = Readonly<Record<string, unknown>>;
@@ -291,12 +208,35 @@ declare function requestPageOf(entries: RequestEntries): string;
291
208
  declare function isPhoneNumber(typed: string): boolean;
292
209
  declare function isEmailAddress(typed: string): boolean;
293
210
 
294
- /** The two texts a form's visitor reads before sending: the consent and the operator's policy. */
295
- type LegalDocument = "consent" | "privacy";
296
211
  /** Where the site's forms send their requests, on the CMS's origin. */
297
212
  declare function requestsPathOf(siteId: string): string;
298
- /** Where the CMS shows a text of the business that owns the site, to anyone. */
299
- declare function legalPagePathOf(siteId: string, document: LegalDocument): string;
213
+
214
+ /** The business that collects the data: as its documents name it. */
215
+ interface PolicyOperator {
216
+ /** «ООО «Лесная мастерская»» or «ИП Иванов Иван Иванович». */
217
+ readonly name: string;
218
+ readonly inn: string;
219
+ readonly address: string;
220
+ /** Where a visitor writes about their data: to withdraw the consent, to ask what is kept. */
221
+ readonly email: string;
222
+ }
223
+ interface PolicySource {
224
+ readonly siteTitle: string;
225
+ readonly operator: PolicyOperator;
226
+ /** The site's forms, whose fields the policy names. */
227
+ readonly forms: readonly RequestForm[];
228
+ }
229
+ /** The page of the policy on a site, which a form's consent links to unless the site says another. */
230
+ declare const PRIVACY_PAGE_PATH = "/privacy";
231
+ /** The policy as content: its title and its text, which the owner edits like any other text. */
232
+ declare function privacyPolicyFields(options?: {
233
+ readonly label?: string;
234
+ }): GroupField<{
235
+ title: TextField;
236
+ text: RichTextField;
237
+ }>;
238
+ /** A policy to start with, made from the business's details and what the site's forms ask. */
239
+ declare function privacyPolicyTextOf(source: PolicySource): RichText;
300
240
 
301
241
  /**
302
242
  * Before the request is sent, once the form takes what was typed. Cancelable: a site that calls
@@ -333,4 +273,4 @@ interface RequestFailedDetail {
333
273
  readonly issues: readonly RequestIssue[];
334
274
  }
335
275
 
336
- export { CONSENT_REQUIRED_TEXT, ChoicesField, CollectionField, type CollectionRecords, Content, ContentOf, type ContentPath, FIELD_PATH_ATTRIBUTE, type FieldMarker, Fields, GroupField, ImageField, ImageValue, type JsonObject, type LegalDocument, LinkField, type LinkKind, type LinkTarget, LinkValue, MAX_SLUG_LENGTH, NumberField, RECORD_ID_KEY, REQUEST_CONSENT_KEY, REQUEST_FAILED_EVENT, REQUEST_FORM_KEY, REQUEST_ISSUE_TEXTS, REQUEST_PAGE_KEY, REQUEST_SEND_EVENT, REQUEST_SENT_EVENT, REQUEST_TRAP_KEY, REVEALED_ATTRIBUTE, REVEAL_ATTRIBUTE, REVEAL_EVENT, RecordFields, type RequestEntries, type RequestFailedDetail, type RequestFailure, RequestForm, type RequestIssue, type RequestIssueCode, type RequestReading, type RequestSendDetail, type RequestSentDetail, type RequestValue, RichTextField, SITE_CONFIG_FILE, type SiteConfig, type SiteConfigField, type SiteConfigReading, SlugField, TextField, TimeField, ToggleField, UrlField, WEEKDAYS, collectionAt, collectionFieldAt, contactsFields, editable, findRecord, hrefOf, imagePosition, isConsentGiven, isContentObject, isEmailAddress, isJsonObject, isPhoneNumber, isRecordId, isSiteId, isSlug, isTrapFilled, legalPagePathOf, linkTargetOf, newRecord, openingHoursField, productFields, readRequestEntries, readRequestValues, readSiteConfig, requestPageOf, requestsPathOf, safeHref, seoFields, slugFieldOf, slugOf, withRecordIds };
276
+ export { CONSENT_REQUIRED_TEXT, CollectionField, type CollectionRecords, Content, ContentOf, type ContentPath, FIELD_PATH_ATTRIBUTE, type FieldMarker, Fields, GroupField, ImageValue, type JsonObject, type LinkKind, type LinkTarget, LinkValue, MAX_SLUG_LENGTH, NumberField, PRIVACY_PAGE_PATH, type PolicyOperator, type PolicySource, RECORD_ID_KEY, REQUEST_CONSENT_KEY, REQUEST_FAILED_EVENT, REQUEST_FORM_KEY, REQUEST_ISSUE_TEXTS, REQUEST_PAGE_KEY, REQUEST_SEND_EVENT, REQUEST_SENT_EVENT, REQUEST_TRAP_KEY, REVEALED_ATTRIBUTE, REVEAL_ATTRIBUTE, REVEAL_EVENT, type Rate, RecordFields, RecordOf, type RequestEntries, type RequestFailedDetail, type RequestFailure, RequestForm, type RequestIssue, type RequestIssueCode, type RequestReading, type RequestSendDetail, type RequestSentDetail, type RequestValue, RichText, RichTextField, SITE_CONFIG_FILE, type SiteConfig, type SiteConfigField, type SiteConfigReading, TextField, collectionAt, collectionFieldAt, editable, estimateOf, findRecord, hrefOf, imagePosition, isConsentGiven, isContentObject, isEmailAddress, isJsonObject, isPhoneNumber, isRecordId, isSiteId, isSlug, isTrapFilled, linkTargetOf, newRecord, privacyPolicyFields, privacyPolicyTextOf, ratesField, readRequestEntries, readRequestValues, readSiteConfig, requestPageOf, requestsPathOf, safeHref, slugFieldOf, slugOf, withRecordIds };