@seamlet/astro 1.3.0 → 1.5.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-53O34DN3.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-JN6XVHCW.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
- isUploadedPhoto
11
- } from "./chunk-MFD4TJPV.js";
12
- import "./chunk-VQKAWFCQ.js";
7
+ import "./chunk-62XHZAPK.js";
13
8
  import {
14
9
  SITE_CONFIG_FILE,
15
10
  SITE_DESCRIPTION_PATH,
16
11
  isJsonObject,
17
12
  readSiteConfig
18
- } from "./chunk-ENMUO442.js";
13
+ } from "./chunk-53O34DN3.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";
@@ -33,7 +33,7 @@ var PHOTOS_COPIED_AT_ONCE = 6;
33
33
  var PHOTO_TIMEOUT_MS = 6e4;
34
34
  function uploadedPhotoAddresses(html, siteId) {
35
35
  const addresses = [...html.matchAll(PHOTO_ADDRESS)].flatMap(
36
- ([address, site, fileName]) => site === siteId && isUploadedPhoto(fileName) ? [address] : []
36
+ ([address, site, fileName]) => site === siteId && isUploadedFile(fileName) ? [address] : []
37
37
  );
38
38
  return [...new Set(addresses)];
39
39
  }
@@ -1,4 +1,5 @@
1
- import { R as RichText, F as Fields, C as Content, a as FieldPath } from './parse-content-Bnn6Wa-l.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-Bnn6Wa-l.js';
2
- import { S as SiteDescription } from './site-description-DSHyBrAL.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;
@@ -33,5 +34,7 @@ declare function isPageAddress(description: SiteDescription, rest: string | unde
33
34
  declare function previewContentAt(description: SiteDescription, content: Content, rest: string | undefined): Content;
34
35
  /** Whether a name can be a photo uploaded to the CMS: the hash of its bytes, as WebP. */
35
36
  declare function isUploadedPhoto(fileName: string | undefined): fileName is string;
37
+ /** Whether a name can be a file uploaded to the CMS: a photo or a document. */
38
+ declare function isUploadedFile(fileName: string | undefined): fileName is string;
36
39
 
37
- export { type DraftReading, MAX_DRAFT_BYTES, isPageAddress, isUploadedPhoto, previewContentAt, previewHeadersOf, readDraft };
40
+ export { type DraftReading, MAX_DRAFT_BYTES, isPageAddress, isUploadedFile, isUploadedPhoto, previewContentAt, previewHeadersOf, readDraft };
@@ -1,16 +1,18 @@
1
1
  import {
2
2
  MAX_DRAFT_BYTES,
3
3
  isPageAddress,
4
+ isUploadedFile,
4
5
  isUploadedPhoto,
5
6
  previewContentAt,
6
7
  previewHeadersOf,
7
8
  readDraft
8
- } from "./chunk-MFD4TJPV.js";
9
- import "./chunk-VQKAWFCQ.js";
10
- import "./chunk-ENMUO442.js";
9
+ } from "./chunk-JN6XVHCW.js";
10
+ import "./chunk-62XHZAPK.js";
11
+ import "./chunk-53O34DN3.js";
11
12
  export {
12
13
  MAX_DRAFT_BYTES,
13
14
  isPageAddress,
15
+ isUploadedFile,
14
16
  isUploadedPhoto,
15
17
  previewContentAt,
16
18
  previewHeadersOf,
@@ -1,6 +1,7 @@
1
- import { S as Shortcut, T as TextFormats } from './messages-C2OjqFmy.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-C2OjqFmy.js';
3
- import { F as Fields, a as FieldPath, I as ImageField, R as RichText } from './parse-content-Bnn6Wa-l.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-2GZZHXP5.js";
25
+ } from "./chunk-WABVCYGZ.js";
26
+ import "./chunk-53O34DN3.js";
26
27
  import "./chunk-QCVWHHJC.js";
27
- import "./chunk-ENMUO442.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-ENMUO442.js";
15
+ } from "./chunk-53O34DN3.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-JN6XVHCW.js";
4
+ import "../chunk-62XHZAPK.js";
5
+ import "../chunk-53O34DN3.js";
1
6
  import {
2
7
  uploadedPhotoPath
3
8
  } from "../chunk-QCVWHHJC.js";
4
- import {
5
- isUploadedPhoto
6
- } from "../chunk-MFD4TJPV.js";
7
- import "../chunk-VQKAWFCQ.js";
8
- import "../chunk-ENMUO442.js";
9
9
 
10
10
  // src/routes/media.ts
11
11
  import { cmsOrigin } from "virtual:seamlet/config";
@@ -15,7 +15,7 @@ var BAD_GATEWAY = 502;
15
15
  var PHOTO_TIMEOUT_MS = 1e4;
16
16
  var GET = async ({ params }) => {
17
17
  const fileName = params["file"];
18
- const isOurs = params["site"] === site.id && isUploadedPhoto(fileName);
18
+ const isOurs = params["site"] === site.id && isUploadedFile(fileName);
19
19
  if (!isOurs) {
20
20
  return new Response(null, { status: NOT_FOUND });
21
21
  }
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-Bnn6Wa-l.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 ImageFocus, O as OptionValue, P as ParsedContent, f as RecordOf, s as ReferenceField, t as ReferencesField, u as RichBlock, v as RichLine, w as RichSpan, R as RichText, V as ValueOf, x as asOneParagraph, y as choice, z as choices, A as collection, B as countCharacters, E as date, H as defaultContent, J as defaultValue, K as defineSchema, M as formatFieldPath, Q as group, W as image, X as linesOf, Y as link, Z as normalizedLine, _ as number, $ as parseContent, a0 as plainTextOf, a1 as readRichText, a2 as reference, a3 as references, a4 as richText, a5 as richTextOf, a6 as slug, a7 as text, a8 as time, a9 as toggle, aa as url } from './parse-content-Bnn6Wa-l.js';
3
- import { R as RequestForm } from './site-description-DSHyBrAL.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-DSHyBrAL.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 } 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, G as GroupField, 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, f as RichText, R as RichTextField, 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>>;
@@ -333,4 +250,4 @@ interface RequestFailedDetail {
333
250
  readonly issues: readonly RequestIssue[];
334
251
  }
335
252
 
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 };
253
+ export { CONSENT_REQUIRED_TEXT, CollectionField, type CollectionRecords, Content, ContentOf, type ContentPath, FIELD_PATH_ATTRIBUTE, type FieldMarker, Fields, ImageValue, type JsonObject, type LegalDocument, 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, type Rate, RecordFields, RecordOf, type RequestEntries, type RequestFailedDetail, type RequestFailure, RequestForm, type RequestIssue, type RequestIssueCode, type RequestReading, type RequestSendDetail, type RequestSentDetail, type RequestValue, 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, legalPagePathOf, linkTargetOf, newRecord, ratesField, readRequestEntries, readRequestValues, readSiteConfig, requestPageOf, requestsPathOf, safeHref, slugFieldOf, slugOf, withRecordIds };