@wix/himalaya-cli 0.1078.0 → 0.1080.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 (46) hide show
  1. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/dev-server/src/builder.d.ts +2 -0
  2. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/define-app.d.ts +9 -0
  3. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/schema.d.ts +41 -1
  4. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/site-shell.d.ts +0 -14
  5. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/core/ts/src/validator.d.ts +36 -0
  6. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/rich-content/src/display.d.ts +26 -0
  7. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/_types/stdlib/wix-sdk/rich-content/src/index.d.ts +79 -0
  8. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/core.mjs +26 -49
  9. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/sdui.mjs +11 -3
  10. package/dist/authoring-runtime/node_modules/@wix/himalaya/dist/wix-rich-content.mjs +344 -0
  11. package/dist/authoring-runtime/node_modules/@wix/himalaya/package.json +4 -0
  12. package/dist/cli.mjs +104 -7
  13. package/guides/importable-sdks.md +1 -0
  14. package/guides/sdk-reference.json +74 -1
  15. package/guides/splash-screens.md +13 -1
  16. package/package.json +2 -2
  17. package/templates/beauty-salon-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  18. package/templates/beauty-salon-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  19. package/templates/community-club-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  20. package/templates/community-club-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  21. package/templates/community-club-owner/tier5-src/himi-owner-lite-event-form/index.ts +2 -2
  22. package/templates/events-meetups-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  23. package/templates/events-meetups-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  24. package/templates/events-meetups-owner/tier5-src/himi-owner-lite-event-form/index.ts +2 -2
  25. package/templates/gym-fitness-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  26. package/templates/gym-fitness-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  27. package/templates/gym-fitness-owner/tier5-src/himi-owner-lite-event-form/index.ts +2 -2
  28. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  29. package/templates/nonprofit-cause-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  30. package/templates/nonprofit-cause-owner/tier5-src/himi-owner-lite-event-form/index.ts +2 -2
  31. package/templates/owner-lite/tier5-src/_shared/owner-post-content.ts +7 -26
  32. package/templates/owner-lite/tier5-src/_shared/owner-rich-guard.ts +12 -41
  33. package/templates/owner-lite/tier5-src/himi-owner-lite-event-form/index.ts +2 -2
  34. package/templates/podcast-creator-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  35. package/templates/podcast-creator-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  36. package/templates/podcast-creator-owner/tier5-src/himi-owner-lite-event-form/index.ts +2 -2
  37. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  38. package/templates/portfolio-creative-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  39. package/templates/restaurant-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  40. package/templates/restaurant-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  41. package/templates/restaurant-owner/tier5-src/himi-owner-lite-event-form/index.ts +2 -2
  42. package/templates/retail-store-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  43. package/templates/retail-store-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  44. package/templates/yoga-studio-owner/tier5-src/_shared/owner-post-content.ts +7 -26
  45. package/templates/yoga-studio-owner/tier5-src/_shared/owner-rich-guard.ts +12 -41
  46. package/templates/yoga-studio-owner/tier5-src/himi-owner-lite-event-form/index.ts +2 -2
@@ -0,0 +1,344 @@
1
+ // ../../stdlib/wix-sdk/media/src/index.ts
2
+ var WIX_LIST_IMAGE = { width: 1e3, height: 1e3, quality: 85 };
3
+ var WIX_DETAIL_IMAGE = { width: 1400, height: 1400, quality: 85 };
4
+ var WIX_MEDIA = /^https?:\/\/static\.wixstatic\.com\/media\/[^/]/;
5
+ var WIX_IMAGE = /^wix:image:\/\/v1\/([^/]+)/i;
6
+ var WIX_TRANSFORM = /^(https?:\/\/static\.wixstatic\.com\/media\/[^/]+\/v1\/)([^/]+)\/([^/?#]+)(?:\/([^/?#]+))?([?#].*)?$/i;
7
+ var SIZING_PARAM = /^(w|h|q)_\d+$/i;
8
+ var WEB_URL = /^https?:\/\//i;
9
+ var RESIZABLE_MODES = /* @__PURE__ */ new Set(["fit", "fill"]);
10
+ var OWNED_PARAM = /^(w|h|q)_/i;
11
+ var DROPPED_PARAM = /^enc_/i;
12
+ function wixMediaId(reference) {
13
+ return WIX_IMAGE.exec(reference)?.[1] ?? (reference.includes("/") || reference.includes(":") ? "" : reference);
14
+ }
15
+ function resolveWixMediaReference(reference) {
16
+ const mediaId = wixMediaId(reference);
17
+ return mediaId ? `https://static.wixstatic.com/media/${mediaId}` : reference;
18
+ }
19
+ function requestedParams(size) {
20
+ return [`w_${size.width}`, `h_${size.height}`, `q_${size.quality ?? 85}`];
21
+ }
22
+ function fittedParams(size, source, mode) {
23
+ const quality = `q_${size.quality ?? 85}`;
24
+ const { width: sourceWidth, height: sourceHeight } = source;
25
+ if (sourceWidth && sourceHeight) {
26
+ if (mode.toLowerCase() === "fill") {
27
+ const scale = Math.min(size.width / sourceWidth, size.height / sourceHeight, 1);
28
+ return [
29
+ `w_${Math.max(1, Math.round(sourceWidth * scale))}`,
30
+ `h_${Math.max(1, Math.round(sourceHeight * scale))}`,
31
+ quality
32
+ ];
33
+ }
34
+ return [
35
+ `w_${Math.min(sourceWidth, size.width)}`,
36
+ `h_${Math.min(sourceHeight, size.height)}`,
37
+ quality
38
+ ];
39
+ }
40
+ if (sourceWidth) return [`w_${Math.min(sourceWidth, size.width)}`, quality];
41
+ if (sourceHeight) return [`h_${Math.min(sourceHeight, size.height)}`, quality];
42
+ return requestedParams(size);
43
+ }
44
+ function resizeWixTransform(url, size) {
45
+ const transform = WIX_TRANSFORM.exec(url);
46
+ if (!transform || !RESIZABLE_MODES.has(transform[2].toLowerCase())) return url;
47
+ const [, base, mode, rawParams, filename, suffix] = transform;
48
+ const source = rawParams.split(",").filter(Boolean);
49
+ if (!filename && !source.some((param) => SIZING_PARAM.test(param))) return url;
50
+ const dimensions = dimensionsOf(source);
51
+ if (mode.toLowerCase() === "fill" && !dimensions.width && !dimensions.height) return url;
52
+ const stated = [dimensions.width, dimensions.height].filter((d) => d !== void 0);
53
+ if (stated.length > 0 && (dimensions.width ?? 0) <= size.width && (dimensions.height ?? 0) <= size.height) return url;
54
+ const carried = source.filter((p) => !OWNED_PARAM.test(p) && !DROPPED_PARAM.test(p));
55
+ const params = [...fittedParams(size, dimensions, mode), ...carried];
56
+ return `${base}${mode}/${params.join(",")}/image.jpg${suffix ?? ""}`;
57
+ }
58
+ function wixTransformDimension(params, name) {
59
+ const match = params.find((param) => new RegExp(`^${name}_\\d+$`, "i").test(param));
60
+ return match ? Number(match.slice(2)) : void 0;
61
+ }
62
+ function dimensionsOf(params) {
63
+ return {
64
+ width: wixTransformDimension(params, "w"),
65
+ height: wixTransformDimension(params, "h")
66
+ };
67
+ }
68
+ function wixMediaUrl(value, size = WIX_LIST_IMAGE) {
69
+ const reference = typeof value === "string" ? value.trim() : "";
70
+ if (!reference) return "";
71
+ const resolvedUrl = resolveWixMediaReference(reference);
72
+ if (!WEB_URL.test(resolvedUrl)) return "";
73
+ if (size === null) return resolvedUrl;
74
+ if (!WIX_MEDIA.test(resolvedUrl)) return resolvedUrl;
75
+ const base = resolvedUrl.split(/[?#]/)[0];
76
+ if (base.includes("/v1/")) return resizeWixTransform(resolvedUrl, size);
77
+ const suffix = resolvedUrl.slice(base.length);
78
+ return `${base}/v1/fit/${requestedParams(size).join(",")}/image.jpg${suffix}`;
79
+ }
80
+
81
+ // ../../stdlib/wix-sdk/rich-content/src/display.ts
82
+ var HTTPS = /^https:\/\/[^\s/?#]\S*$/i;
83
+ var LINK = /^(https?:\/\/[^\s/?#]\S*|mailto:\S+|tel:\S+)$/i;
84
+ var HTTP_HOST = /^https?:\/\/([^\s/?#]+)/i;
85
+ var VIDEO_CARD_HOST = /^(?:(?:www\.|m\.)?youtube\.com|youtu\.be|(?:www\.|player\.)?vimeo\.com)$/;
86
+ function trimAscii(s) {
87
+ return s.replace(/^[\t\n\v\f\r ]+|[\t\n\v\f\r ]+$/g, "");
88
+ }
89
+ function normalizeMediaRef(s) {
90
+ return s.trim().replace(/^http:\/\/(static|video)\.wixstatic\.com\//i, (_all, sub) => `https://${sub.toLowerCase()}.wixstatic.com/`);
91
+ }
92
+ var hostOf = (url) => HTTP_HOST.exec(url)?.[1]?.toLowerCase().replace(/:\d+$/, "");
93
+ function cleanLink(url) {
94
+ if (typeof url !== "string") return void 0;
95
+ const t = trimAscii(url);
96
+ return LINK.test(t) ? t : void 0;
97
+ }
98
+ function ricosImageUrl(holder, width) {
99
+ const src = holder?.image?.src;
100
+ const fromUrl = typeof src?.url === "string" ? normalizeMediaRef(src.url) : "";
101
+ const ref = fromUrl !== "" ? fromUrl : typeof src?.id === "string" ? normalizeMediaRef(src.id) : src?.id;
102
+ const url = wixMediaUrl(ref, { width, height: width, quality: 85 });
103
+ return HTTPS.test(url) ? url : "";
104
+ }
105
+ function ricosVideoUrl(src) {
106
+ if (!src || typeof src !== "object") return "";
107
+ const { url, id } = src;
108
+ if (typeof url === "string" && url.trim() !== "") {
109
+ const link = cleanLink(url);
110
+ const linkHost = link === void 0 ? void 0 : hostOf(link);
111
+ if (link !== void 0 && linkHost !== void 0 && VIDEO_CARD_HOST.test(linkHost)) return link;
112
+ const media = normalizeMediaRef(url);
113
+ const mediaHost = hostOf(media);
114
+ return HTTPS.test(media) && !(mediaHost !== void 0 && VIDEO_CARD_HOST.test(mediaHost)) ? media : "";
115
+ }
116
+ const ref = typeof id === "string" ? id.trim().replace(/^video\//, "") : "";
117
+ if (/^\w[\w~.-]*$/.test(ref)) return `https://video.wixstatic.com/video/${ref}/file`;
118
+ if (/^\w[\w~.-]*\/[\w~./-]+$/.test(ref)) return `https://video.wixstatic.com/video/${ref}`;
119
+ return "";
120
+ }
121
+
122
+ // ../../stdlib/wix-sdk/rich-content/src/index.ts
123
+ var RICH_CONTENT_LIMITS = { maxBytes: 262144, maxNodes: 5e3, maxDepth: 16 };
124
+ var isObj = (v) => !!v && typeof v === "object" && !Array.isArray(v);
125
+ function parseRicosJson(value) {
126
+ let v = value;
127
+ if (typeof v === "string") {
128
+ if (v.trim() === "") return null;
129
+ try {
130
+ v = JSON.parse(v);
131
+ } catch {
132
+ return null;
133
+ }
134
+ }
135
+ return isObj(v) && Array.isArray(v.nodes) ? v : null;
136
+ }
137
+ function ricosToPlainText(doc) {
138
+ const kids = (v) => Array.isArray(v) ? v.filter(isObj) : [];
139
+ const inline = (node) => typeof node.textData?.text === "string" ? node.textData.text : kids(node.nodes).map(inline).join("");
140
+ const blocks = (nodes) => nodes.flatMap((node) => node.type === "PARAGRAPH" || node.type === "HEADING" || node.type === "TEXT" ? [inline(node)] : blocks(kids(node.nodes)));
141
+ return blocks(kids(doc?.nodes)).join("\n\n");
142
+ }
143
+ function plainTextToRicos(text) {
144
+ return { nodes: text.split("\n\n").map((t) => ({ type: "PARAGRAPH", nodes: [{ type: "TEXT", textData: { text: t, decorations: [] } }] })) };
145
+ }
146
+ var onlyKeys = (o, allowed) => Object.keys(o).every((k) => allowed.includes(k));
147
+ var emptyObject = (v) => v === void 0 || v === null || typeof v === "object" && Object.keys(v).length === 0;
148
+ function defaultParagraphData(pd) {
149
+ if (pd === void 0) return true;
150
+ if (!pd || typeof pd !== "object" || !onlyKeys(pd, ["textStyle", "indentation"])) return false;
151
+ const { textStyle, indentation } = pd;
152
+ if (indentation !== void 0 && indentation !== 0) return false;
153
+ if (textStyle === void 0) return true;
154
+ if (!textStyle || typeof textStyle !== "object" || !onlyKeys(textStyle, ["textAlignment"])) return false;
155
+ const align = textStyle.textAlignment;
156
+ return align === void 0 || align === "AUTO";
157
+ }
158
+ function plainRun(raw) {
159
+ if (!raw || typeof raw !== "object") return false;
160
+ const t = raw;
161
+ return t.type === "TEXT" && onlyKeys(t, ["type", "id", "textData", "nodes"]) && (t.nodes === void 0 || Array.isArray(t.nodes) && t.nodes.length === 0) && !(Array.isArray(t.textData?.decorations) && t.textData.decorations.length > 0);
162
+ }
163
+ function isPlainRicos(doc) {
164
+ if (doc === null || doc === void 0) return true;
165
+ if (typeof doc !== "object" || Array.isArray(doc)) return false;
166
+ if (!emptyObject(doc.documentStyle)) return false;
167
+ if (doc.nodes !== void 0 && !Array.isArray(doc.nodes)) return false;
168
+ const nodes = Array.isArray(doc.nodes) ? doc.nodes : [];
169
+ return nodes.every((raw) => {
170
+ if (!raw || typeof raw !== "object") return false;
171
+ const n = raw;
172
+ if (n.nodes !== void 0 && !Array.isArray(n.nodes)) return false;
173
+ return n.type === "PARAGRAPH" && onlyKeys(n, ["type", "id", "nodes", "paragraphData"]) && defaultParagraphData(n.paragraphData) && (Array.isArray(n.nodes) ? n.nodes : []).every(plainRun);
174
+ });
175
+ }
176
+ var HTML_TAG = /<[a-z!/?]/i;
177
+ function htmlIsTrivial(html) {
178
+ const s = (html ?? "").trim();
179
+ return !s || !HTML_TAG.test(s) || /^<p>[^<>]*<\/p>$/.test(s);
180
+ }
181
+ function encodeRichContent(doc, opts = {}) {
182
+ if (doc === null || doc === void 0) return { json: "" };
183
+ if (!isObj(doc) || !Array.isArray(doc.nodes)) return { json: "", rejected: "not_a_document" };
184
+ const w = opts.imageWidth;
185
+ const imageWidth = typeof w === "number" && Number.isInteger(w) && w > 0 ? Math.min(w, WIX_DETAIL_IMAGE.width) : WIX_DETAIL_IMAGE.width;
186
+ const ctx = {
187
+ imageWidth,
188
+ // Gallery tiles and video posters are half-width at most, so the list budget caps them.
189
+ tileWidth: Math.min(imageWidth, WIX_LIST_IMAGE.width),
190
+ // Serialized nesting allowed: each node level is a node and its `nodes` array, plus generous room for type
191
+ // data. Past it the document is rejected rather than overflowing the worker's stack.
192
+ maxJsonDepth: RICH_CONTENT_LIMITS.maxDepth * 2 + 64,
193
+ ids: /* @__PURE__ */ new Set()
194
+ };
195
+ let nodes;
196
+ let json;
197
+ try {
198
+ nodes = cleanNodes(doc.nodes, "", 1, ctx, void 0);
199
+ if (nodes.length === 0) return { json: "" };
200
+ const out = { nodes };
201
+ if (doc.documentStyle !== void 0) out.documentStyle = doc.documentStyle;
202
+ if (doc.metadata !== void 0) out.metadata = doc.metadata;
203
+ json = canonicalJson(out, 0, ctx.maxJsonDepth);
204
+ } catch (e) {
205
+ if (e === TOO_DEEP) return { json: "", rejected: "too_deep" };
206
+ throw e;
207
+ }
208
+ if (utf8Length(json) > RICH_CONTENT_LIMITS.maxBytes) return { json: "", rejected: "too_large" };
209
+ if (countNodes(nodes) > RICH_CONTENT_LIMITS.maxNodes) return { json: "", rejected: "too_many_nodes" };
210
+ return { json };
211
+ }
212
+ var TOO_DEEP = { reason: "too_deep" };
213
+ var PATH_SHAPED = /^[0-9.]+$/;
214
+ var isWrapper = (t) => t === "COLLAPSIBLE_LIST" || t === "COLLAPSIBLE_ITEM" || t === "COLLAPSIBLE_ITEM_TITLE" || t === "COLLAPSIBLE_ITEM_BODY";
215
+ var holdsBlocks = (t) => t === void 0 || t === "BULLETED_LIST" || t === "ORDERED_LIST" || t === "LIST_ITEM" || t === "BLOCKQUOTE" || isWrapper(t);
216
+ var LINK_FIELDS = {
217
+ EMBED: [["embedData", "oembed", "url"], ["embedData", "src"]],
218
+ HTML: [["htmlData", "url"]],
219
+ APP_EMBED: [["appEmbedData", "url"]],
220
+ LINK_PREVIEW: [["linkPreviewData", "link", "url"]],
221
+ FILE: [["fileData", "src", "url"]],
222
+ AUDIO: [["audioData", "audio", "src", "url"]],
223
+ GIF: [["gifData", "original", "gif"]],
224
+ IMAGE: [["imageData", "link", "url"]]
225
+ };
226
+ function rewriteAt(v, path, fix) {
227
+ if (!isObj(v) || !(path[0] in v)) return v;
228
+ const [k, ...rest] = path;
229
+ if (rest.length > 0) return { ...v, [k]: rewriteAt(v[k], rest, fix) };
230
+ const next = fix(v[k]);
231
+ if (next === v[k]) return v;
232
+ const { [k]: _old, ...kept } = v;
233
+ return next === void 0 ? kept : { ...kept, [k]: next };
234
+ }
235
+ function getAt(v, path) {
236
+ let cur = v;
237
+ for (const k of path) cur = isObj(cur) ? cur[k] : void 0;
238
+ return cur;
239
+ }
240
+ var drop = () => void 0;
241
+ var LINK_DECORATION_URL = ["linkData", "link", "url"];
242
+ var BUTTON_URL = ["link", "url"];
243
+ function cleanNodes(nodes, base, depth, ctx, parentType) {
244
+ const out = [];
245
+ for (const raw of nodes) {
246
+ if (!isObj(raw)) continue;
247
+ if (depth > RICH_CONTENT_LIMITS.maxDepth) throw TOO_DEEP;
248
+ const path = base === "" ? String(out.length) : `${base}.${out.length}`;
249
+ const node = cleanNode({ ...raw }, path, depth, ctx, parentType);
250
+ if (node) out.push(node);
251
+ }
252
+ return out;
253
+ }
254
+ function cleanNode(node, path, depth, ctx, parentType) {
255
+ if (node.type === "TEXT") {
256
+ const decorations = node.textData?.decorations;
257
+ if (Array.isArray(decorations)) {
258
+ const kept = decorations.flatMap((d) => {
259
+ if (!(isObj(d) && d.type === "LINK")) return [d];
260
+ const next = rewriteAt(d, LINK_DECORATION_URL, cleanLink);
261
+ return getAt(next, LINK_DECORATION_URL) === void 0 ? [] : [next];
262
+ });
263
+ node.textData = { ...node.textData, decorations: kept };
264
+ }
265
+ } else if (node.type === "IMAGE") {
266
+ const data = isObj(node.imageData) ? node.imageData : {};
267
+ const url = ricosImageUrl(data, ctx.imageWidth);
268
+ if (!url) return null;
269
+ node.imageData = { ...data, image: { ...isObj(data.image) ? data.image : {}, src: { url } } };
270
+ } else if (node.type === "GALLERY") {
271
+ const data = isObj(node.galleryData) ? node.galleryData : {};
272
+ const items = (Array.isArray(data.items) ? data.items : []).flatMap((item) => {
273
+ if (!isObj(item) || !isObj(item.image)) return [];
274
+ const media = isObj(item.image.media) ? item.image.media : {};
275
+ const url = ricosImageUrl({ image: media }, ctx.tileWidth);
276
+ return url ? [{ ...item, image: { ...item.image, media: { ...media, src: { url } } } }] : [];
277
+ });
278
+ if (items.length === 0) return null;
279
+ node.galleryData = { ...data, items };
280
+ } else if (node.type === "VIDEO") {
281
+ const data = isObj(node.videoData) ? { ...node.videoData } : {};
282
+ const video = isObj(data.video) ? data.video : {};
283
+ const url = ricosVideoUrl(video.src);
284
+ if (!url) return null;
285
+ data.video = { ...video, src: { url } };
286
+ const poster = ricosImageUrl({ image: data.thumbnail }, ctx.tileWidth);
287
+ if (poster) data.thumbnail = { ...data.thumbnail, src: { url: poster } };
288
+ else delete data.thumbnail;
289
+ node.videoData = data;
290
+ } else if (node.type === "BUTTON" || node.type === "LINK_BUTTON") {
291
+ node.buttonData = rewriteAt(node.buttonData, BUTTON_URL, cleanLink);
292
+ if (getAt(node.buttonData, BUTTON_URL) === void 0) return null;
293
+ } else if (node.type === "HTML") {
294
+ node.htmlData = rewriteAt(node.htmlData, ["html"], drop);
295
+ } else if (node.type === "EMBED") {
296
+ node.embedData = rewriteAt(node.embedData, ["oembed", "html"], drop);
297
+ }
298
+ for (const [field, ...rest] of (typeof node.type === "string" ? LINK_FIELDS[node.type] : void 0) ?? []) {
299
+ if (field in node) node[field] = rewriteAt(node[field], rest, cleanLink);
300
+ }
301
+ const inBlocks = holdsBlocks(parentType);
302
+ if (node.type !== "TEXT" || inBlocks) {
303
+ const own = typeof node.id === "string" ? node.id : "";
304
+ const usable = own !== "" && !PATH_SHAPED.test(own);
305
+ if (inBlocks && !isWrapper(node.type)) {
306
+ if (usable && !ctx.ids.has(own)) ctx.ids.add(own);
307
+ else node.id = path;
308
+ } else if (!usable) node.id = path;
309
+ }
310
+ if (Array.isArray(node.nodes)) node.nodes = cleanNodes(node.nodes, path, depth + 1, ctx, typeof node.type === "string" ? node.type : "");
311
+ return node;
312
+ }
313
+ function countNodes(nodes) {
314
+ return nodes.reduce((n, node) => isObj(node) ? n + 1 + (Array.isArray(node.nodes) ? countNodes(node.nodes) : 0) : n, 0);
315
+ }
316
+ function canonicalJson(v, depth, max) {
317
+ if (depth > max) throw TOO_DEEP;
318
+ if (Array.isArray(v)) return `[${v.map((x) => x === void 0 ? "null" : canonicalJson(x, depth + 1, max)).join(",")}]`;
319
+ if (isObj(v)) return `{${Object.keys(v).sort().filter((k) => v[k] !== void 0).map((k) => `${JSON.stringify(k)}:${canonicalJson(v[k], depth + 1, max)}`).join(",")}}`;
320
+ return JSON.stringify(v) ?? "null";
321
+ }
322
+ function utf8Length(s) {
323
+ let bytes = 0;
324
+ for (let i = 0; i < s.length; i++) {
325
+ const c = s.charCodeAt(i);
326
+ if (c < 128) bytes += 1;
327
+ else if (c < 2048) bytes += 2;
328
+ else if (c >= 55296 && c <= 56319 && i + 1 < s.length && s.charCodeAt(i + 1) >= 56320 && s.charCodeAt(i + 1) <= 57343) {
329
+ bytes += 4;
330
+ i++;
331
+ } else bytes += 3;
332
+ }
333
+ return bytes;
334
+ }
335
+ export {
336
+ RICH_CONTENT_LIMITS,
337
+ encodeRichContent,
338
+ htmlIsTrivial,
339
+ isPlainRicos,
340
+ parseRicosJson,
341
+ plainTextToRicos,
342
+ ricosToPlainText
343
+ };
344
+ //# sourceMappingURL=wix-rich-content.mjs.map
@@ -434,6 +434,10 @@
434
434
  "types": "./dist/_types/stdlib/wix-sdk/reviews/src/index.d.ts",
435
435
  "import": "./dist/wix-reviews.mjs"
436
436
  },
437
+ "./wix-rich-content": {
438
+ "types": "./dist/_types/stdlib/wix-sdk/rich-content/src/index.d.ts",
439
+ "import": "./dist/wix-rich-content.mjs"
440
+ },
437
441
  "./wix-seo": {
438
442
  "types": "./dist/_types/stdlib/wix-sdk/seo-v1/src/index.d.ts",
439
443
  "import": "./dist/wix-seo.mjs"
package/dist/cli.mjs CHANGED
@@ -4964,6 +4964,7 @@ var init_build_lib = __esm({
4964
4964
  // Cross-vertical media sizing. Not a generated domain client — the one place a
4965
4965
  // Wix media handle becomes a fetchable URL, so no vertical re-derives it.
4966
4966
  "@himalaya/wix-media": SDK("media"),
4967
+ "@himalaya/wix-rich-content": SDK("rich-content"),
4967
4968
  "@himalaya/wix-stores": SDK("stores-v1"),
4968
4969
  "@himalaya/wix-ecom": SDK("ecom"),
4969
4970
  "@himalaya/wix-redirects": SDK("redirects-v1"),
@@ -7592,9 +7593,17 @@ var init_validator = __esm({
7592
7593
  hideHostedSiteHeader: { type: "boolean" },
7593
7594
  immersive: { type: "boolean" },
7594
7595
  showCloseButton: { type: "boolean" },
7595
- // Keep the native WebView instance warm across re-presentations (covers reload cold
7596
- // otherwise). iOS-implemented; Android ignores it (cold-loads) for now.
7597
- keepAlive: { type: "boolean" }
7596
+ // Keep the native WebView instance warm across re-presentations and tab switches
7597
+ // (per screen id, LRU — WebViewKeepAliveStore on both platforms).
7598
+ keepAlive: { type: "boolean" },
7599
+ // Hosted-site polish — native hosts honoured these before the validator knew them.
7600
+ pinHostedHeader: { type: "boolean" },
7601
+ internalLinksAsScreens: { type: "boolean" },
7602
+ respectHttpCache: { type: "boolean" },
7603
+ coverBandColor: { type: "string" },
7604
+ // RFC 0062 — binary-shipped chrome hiding for a hosted site (no page script over the air).
7605
+ hideWixAds: { type: "boolean" },
7606
+ hideHostedSiteFooter: { type: "boolean" }
7598
7607
  }
7599
7608
  }
7600
7609
  }
@@ -17090,6 +17099,79 @@ struct GeneratedLiveActivityBundle: WidgetBundle {
17090
17099
  }
17091
17100
  });
17092
17101
 
17102
+ // ../native-config/localweb.ts
17103
+ function resourcesDirOf(projectYml) {
17104
+ const m = /^\s*-\s*path:\s*(\S+)\/Resources\/seed\s*$/m.exec(projectYml);
17105
+ return m ? `${m[1]}/Resources` : null;
17106
+ }
17107
+ function renderLocalWebYaml(resourcesDir, declared) {
17108
+ return (indent) => declared && resourcesDir ? [`${indent}- path: ${resourcesDir}/localweb`, `${indent} type: folder`, `${indent} optional: true`] : [];
17109
+ }
17110
+ function assertLocalWebBlockLanded(app, declared, path2, outcome) {
17111
+ if (!declared || outcome !== "skipped") return;
17112
+ throw new Error(
17113
+ `${app}: config.ts declares richContentEditor: true, but ${path2} has no "# >>> ${LABEL_LOCALWEB}" markers. Add the markers and a "- Resources/localweb" exclude (core/rich-content-editor/README.md, "Opting an app in"); otherwise gen.sh copies the engine page into Resources/ and the .app never contains it.`
17114
+ );
17115
+ }
17116
+ var LABEL_LOCALWEB;
17117
+ var init_localweb = __esm({
17118
+ "../native-config/localweb.ts"() {
17119
+ LABEL_LOCALWEB = "himalaya:localweb";
17120
+ }
17121
+ });
17122
+
17123
+ // ../../core/rich-content-editor/prebuild.mjs
17124
+ function codeOnly(src) {
17125
+ let out2 = "";
17126
+ let i = 0;
17127
+ const n = src.length;
17128
+ while (i < n) {
17129
+ const c = src[i], d = src[i + 1];
17130
+ if (c === "/" && d === "/") {
17131
+ while (i < n && src[i] !== "\n") i++;
17132
+ continue;
17133
+ }
17134
+ if (c === "/" && d === "*") {
17135
+ i += 2;
17136
+ while (i < n && !(src[i] === "*" && src[i + 1] === "/")) {
17137
+ if (src[i] === "\n") out2 += "\n";
17138
+ i++;
17139
+ }
17140
+ i += 2;
17141
+ continue;
17142
+ }
17143
+ if (c === '"' || c === "'" || c === "`") {
17144
+ out2 += c;
17145
+ i++;
17146
+ while (i < n && src[i] !== c) {
17147
+ if (src[i] === "\\") {
17148
+ i += 2;
17149
+ continue;
17150
+ }
17151
+ if (c !== "`" && src[i] === "\n") break;
17152
+ out2 += src[i] === "\n" ? "\n" : " ";
17153
+ i++;
17154
+ }
17155
+ if (i < n && src[i] === c) {
17156
+ out2 += c;
17157
+ i++;
17158
+ }
17159
+ continue;
17160
+ }
17161
+ out2 += c;
17162
+ i++;
17163
+ }
17164
+ return out2;
17165
+ }
17166
+ function declaresRichContentEditor(configTs) {
17167
+ return /^\s*richContentEditor\s*:\s*true\s*,?\s*$/m.test(codeOnly(String(configTs ?? "")));
17168
+ }
17169
+ var init_prebuild = __esm({
17170
+ "../../core/rich-content-editor/prebuild.mjs"() {
17171
+ "use strict";
17172
+ }
17173
+ });
17174
+
17093
17175
  // ../native-config/gen-native-config.ts
17094
17176
  var gen_native_config_exports = {};
17095
17177
  __export(gen_native_config_exports, {
@@ -17396,6 +17478,13 @@ function genNativeConfig(app, opts = {}) {
17396
17478
  // apps that hand-author their own launch screen are untouched.
17397
17479
  applyToFile(iosProjectYml(app), "yaml", LABEL_IOS_SPLASH, renderSplashYaml, check)
17398
17480
  ];
17481
+ const rce = declaresRichContentEditor(configTs);
17482
+ for (const yml of [iosYml, macosProjectYml(app)]) {
17483
+ const text6 = existsSync26(yml) ? readFileSync26(yml, "utf8") : "";
17484
+ const r = applyToFile(yml, "yaml", LABEL_LOCALWEB, renderLocalWebYaml(resourcesDirOf(text6), rce), check);
17485
+ if (existsSync26(yml)) assertLocalWebBlockLanded(app, rce, yml, r.outcome);
17486
+ files.push(r);
17487
+ }
17399
17488
  if (targetManaged) {
17400
17489
  const plan = live2;
17401
17490
  files.push(applyToFile(iosYml, "yaml", LABEL_LIVE_TARGET, (i) => plan.target.map((line) => i + line), check));
@@ -17425,6 +17514,8 @@ var init_gen_native_config = __esm({
17425
17514
  init_icon2();
17426
17515
  init_live_activity();
17427
17516
  init_car();
17517
+ init_localweb();
17518
+ init_prebuild();
17428
17519
  init_src2();
17429
17520
  LABEL_IOS_INFO = "himalaya:capabilities:info";
17430
17521
  LABEL_IOS_ENTITLEMENTS = "himalaya:capabilities:entitlements";
@@ -23946,7 +24037,6 @@ function shouldRevealError(args) {
23946
24037
  var EMAIL_RE, URL_HOST_RE, INTEGER_RE, NUMBER_RE;
23947
24038
  var init_validation = __esm({
23948
24039
  "../../core/ts/src/validation.ts"() {
23949
- "use strict";
23950
24040
  EMAIL_RE = /^[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,}$/;
23951
24041
  URL_HOST_RE = /^[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*(:[0-9]+)?$/;
23952
24042
  INTEGER_RE = /^[+-]?[0-9]+$/;
@@ -27567,7 +27657,6 @@ function validateWorkerSubtree(raw, slotId, policy, actionCatalog) {
27567
27657
  var WORKER_SUBTREE_CEILINGS, ID_PART, ACTION_ID;
27568
27658
  var init_worker_subtree = __esm({
27569
27659
  "../../core/ts/src/worker-subtree.ts"() {
27570
- "use strict";
27571
27660
  init_worker_subtree_safe_types_generated();
27572
27661
  WORKER_SUBTREE_CEILINGS = Object.freeze({
27573
27662
  maxEncodedBytes: 65536,
@@ -54113,10 +54202,16 @@ function previewResponse(pathname, assets, mount = "/preview", creds, handoverAt
54113
54202
  headers: { "content-type": "text/html; charset=utf-8", "cache-control": "public, max-age=31536000, immutable", "content-security-policy": T5_FRAME_CSP }
54114
54203
  });
54115
54204
  }
54205
+ if (key2 === RICOS_EDITOR_KEY) {
54206
+ return new Response(assetBytes(hit), {
54207
+ status: 200,
54208
+ headers: { "content-type": "text/html; charset=utf-8", "cache-control": "no-cache", "content-security-policy": RICOS_EDITOR_CSP, "x-content-type-options": "nosniff" }
54209
+ });
54210
+ }
54116
54211
  const immutable = key2.startsWith("assets/");
54117
54212
  return bytes(hit, immutable ? "public, max-age=31536000, immutable" : "no-cache");
54118
54213
  }
54119
- if (key2.startsWith("assets/")) {
54214
+ if (key2.startsWith("assets/") || key2.startsWith("__himi/")) {
54120
54215
  return new Response(JSON.stringify({ error: "preview_asset_not_found", key: key2 }), {
54121
54216
  status: 404,
54122
54217
  headers: { "content-type": "application/json; charset=utf-8" }
@@ -54129,10 +54224,12 @@ function previewResponse(pathname, assets, mount = "/preview", creds, handoverAt
54129
54224
  headers: { "content-type": "application/json; charset=utf-8" }
54130
54225
  });
54131
54226
  }
54132
- var T5_FRAME_CSP, PREVIEW_BASE_JS, PREVIEW_ENTRY_RECOVERY_JS, MOUNT_STRIP;
54227
+ var T5_FRAME_CSP, RICOS_EDITOR_KEY, RICOS_EDITOR_CSP, PREVIEW_BASE_JS, PREVIEW_ENTRY_RECOVERY_JS, MOUNT_STRIP;
54133
54228
  var init_preview3 = __esm({
54134
54229
  "../../packages/serve/src/preview.ts"() {
54135
54230
  T5_FRAME_CSP = "default-src 'none'; script-src 'unsafe-inline' 'unsafe-eval'; connect-src 'none'; img-src 'none'; media-src 'none'; style-src 'unsafe-inline'; base-uri 'none'; form-action 'none'; sandbox allow-scripts";
54231
+ RICOS_EDITOR_KEY = "__himi/ricos/editor.html";
54232
+ RICOS_EDITOR_CSP = "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; img-src https: data: blob:; media-src https: blob:";
54136
54233
  PREVIEW_BASE_JS = // Both serve mounts (/preview framed + /app unframed — RFC 0051 track D) serve the SAME
54137
54234
  // embedded artifact, so one shim derives whichever mount the browser is on. Non-greedy:
54138
54235
  // the EARLIEST mount segment wins, mirroring the SPA's own deployBase (an app literally
@@ -111,6 +111,7 @@ direction the platform is heading — recommended, not required). Usage is unifo
111
111
  - `@himalaya/wix-redirects` — Wix redirects — typed REST client
112
112
  - `@himalaya/wix-restaurants` — Restaurants — menus and orders
113
113
  - `@himalaya/wix-reviews` — Product and site reviews
114
+ - `@himalaya/wix-rich-content` — Ricos rich content — encode a post body for the RichContent viewer; plain-text helpers
114
115
  - `@himalaya/wix-seo` — Wix seo — typed REST client
115
116
  - `@himalaya/wix-site-list` — The user's Wix sites
116
117
  - `@himalaya/wix-site-media` — Wix site media — typed REST client
@@ -907,7 +907,7 @@
907
907
  "name": "SplashConfig",
908
908
  "kind": "interface",
909
909
  "jsdoc": "/**\n * The IN-APP splash — the brand surface between the OS splash handing off and the\n * app being ready. The *OS* splash is generated at build time from the same\n * `splash` block in config.ts and can never be OTA (iOS reads `UILaunchScreen`\n * before any app code runs); this layer is OTA. Artwork stays baked in the binary\n * — `logoAsset` / `backgroundImageAsset` name a baked asset, so only the\n * composition travels.\n */",
910
- "decl": "export interface SplashConfig {\n /** Master switch / kill-switch. Absent or false ⇒ no surface. */\n enabled?: boolean;\n /** Background color TOKEN name (e.g. \"accentPrimary\"). */\n backgroundColor?: TokenName;\n /** Gradient token name; wins over `backgroundColor`. */\n backgroundGradient?: TokenName;\n /** BAKED asset name for a full-bleed background image; wins over color/gradient. */\n backgroundImageAsset?: string;\n /** BAKED asset name for the centered logo (e.g. \"LaunchLogo\"). */\n logoAsset?: string;\n /** Logo width in pt/dp. 0 / absent ⇒ 96. */\n logoWidth?: number;\n /** Optional wordmark line. NOTE: a literal string, so an OTA edit bypasses\n * localization (same caveat as `NavTabItem.label`). */\n caption?: string;\n /** Typography token for the caption. Absent ⇒ \"title1\". */\n captionStyle?: TokenName;\n /** Color token for the caption. Absent ⇒ \"textOnAccent\". */\n captionColor?: TokenName;\n /** Absent / unknown ⇒ \"centered\". */\n layout?: SplashLayout;\n /** Anti-flash floor, ms. Clamped client-side to [0, 2000]. */\n minVisibleMs?: number;\n /** Hard ceiling on the readiness hold, ms — a stuck boot can never wedge the\n * UI. 0 / absent ⇒ 3000. Clamped client-side to [0, 8000]. */\n maxHoldMs?: number;\n}"
910
+ "decl": "export interface SplashConfig {\n /** Master switch / kill-switch. Absent or false ⇒ no surface. */\n enabled?: boolean;\n /** Background color TOKEN name (e.g. \"accentPrimary\"). */\n backgroundColor?: TokenName;\n /** Gradient token name; wins over `backgroundColor`. */\n backgroundGradient?: TokenName;\n /** BAKED asset name for a full-bleed background image; wins over color/gradient. */\n backgroundImageAsset?: string;\n /** BAKED asset name for the centered logo (e.g. \"LaunchLogo\"). */\n logoAsset?: string;\n /** Logo width in pt/dp. 0 / absent ⇒ 96. */\n logoWidth?: number;\n /** Optional wordmark line. NOTE: a literal string, so an OTA edit bypasses\n * localization (same caveat as `NavTabItem.label`). */\n caption?: string;\n /** Typography token for the caption. Absent ⇒ \"title1\". */\n captionStyle?: TokenName;\n /** Color token for the caption. Absent ⇒ \"textOnAccent\". */\n captionColor?: TokenName;\n /** Absent / unknown ⇒ \"centered\". */\n layout?: SplashLayout;\n /** Anti-flash floor, ms. Clamped client-side to [0, 2000]. */\n minVisibleMs?: number;\n /** Hard ceiling on the readiness hold, ms — a stuck boot can never wedge the\n * UI. 0 / absent ⇒ 3000. Clamped client-side to [0, 8000]. */\n maxHoldMs?: number;\n /** What readiness waits for beyond the seed. Absent / \"\" ⇒ seeded is\n * enough. \"first_content\" ⇒ also the first WebView page (a site shell), still\n * under `maxHoldMs`. Unknown coalesces to \"\" on device. */\n readySignal?: SplashReadySignal;\n}"
911
911
  },
912
912
  {
913
913
  "name": "OrientationConfig",
@@ -20943,6 +20943,79 @@
20943
20943
  }
20944
20944
  ]
20945
20945
  },
20946
+ {
20947
+ "name": "@himalaya/wix-rich-content",
20948
+ "source": "stdlib/wix-sdk/rich-content/src/index.ts",
20949
+ "description": "Ricos rich content — encode a post body for the RichContent viewer; plain-text helpers",
20950
+ "api": [
20951
+ {
20952
+ "name": "RicosNode",
20953
+ "kind": "type",
20954
+ "jsdoc": "/** One Ricos node: a block (PARAGRAPH, HEADING, IMAGE, …) or an inline TEXT run. Type-specific data\n * (`imageData`, `headingData`, …) rides along as extra keys. */",
20955
+ "decl": "export type RicosNode = { type?: string; id?: string; nodes?: RicosNode[]; textData?: { text?: string; decorations?: { type: string; linkData?: { link?: { url?: string } } }[] }; [k: string]: unknown };"
20956
+ },
20957
+ {
20958
+ "name": "RicosDocument",
20959
+ "kind": "type",
20960
+ "jsdoc": "/** A Ricos document with its `nodes` checked to be an array (what parseRicosJson and plainTextToRicos return). */",
20961
+ "decl": "export type RicosDocument = { nodes: RicosNode[]; metadata?: unknown; documentStyle?: unknown };"
20962
+ },
20963
+ {
20964
+ "name": "RicosInput",
20965
+ "kind": "type",
20966
+ "jsdoc": "/** Any Ricos-shaped value, as Wix APIs return it (a blog post's `richContent`, an event's description) — their\n * generated types declare `nodes` loosely, so the helpers accept it as is and check the shape at runtime. */",
20967
+ "decl": "export type RicosInput = { nodes?: unknown; metadata?: unknown; documentStyle?: unknown };"
20968
+ },
20969
+ {
20970
+ "name": "RejectReason",
20971
+ "kind": "type",
20972
+ "jsdoc": "/** Why a document is not shown: the viewer draws its fallback instead and reports only this code. */",
20973
+ "decl": "export type RejectReason = \"invalid_json\" | \"too_large\" | \"too_many_nodes\" | \"too_deep\" | \"not_a_document\";"
20974
+ },
20975
+ {
20976
+ "name": "RICH_CONTENT_LIMITS",
20977
+ "kind": "const",
20978
+ "jsdoc": "/** The RichContent viewer's ceilings; every renderer rejects a document past any of them. Kept equal to the platform limits file by a test. */",
20979
+ "decl": "export const RICH_CONTENT_LIMITS = { maxBytes: 262144, maxNodes: 5000, maxDepth: 16 } as const;"
20980
+ },
20981
+ {
20982
+ "name": "parseRicosJson",
20983
+ "kind": "function",
20984
+ "jsdoc": "/** Reads a Ricos document from a JSON string or an already-parsed object (page messages arrive as either,\n * depending on the platform). Returns null for empty input, invalid JSON, or anything without a `nodes` array. */",
20985
+ "decl": "export function parseRicosJson(value: unknown): RicosDocument | null;"
20986
+ },
20987
+ {
20988
+ "name": "ricosToPlainText",
20989
+ "kind": "function",
20990
+ "jsdoc": "/** Plain text of a document. Paragraphs, headings and loose text runs are blocks joined by a blank line; runs\n * inside a block join with nothing between them, so a word split across bold and plain runs stays one word.\n * Media and other nodes contribute only the text nested inside them. Malformed parts (a non-object node, a\n * `nodes` that is not an array) contribute nothing — it never throws. */",
20991
+ "decl": "export function ricosToPlainText(doc: RicosInput | null | undefined): string;"
20992
+ },
20993
+ {
20994
+ "name": "plainTextToRicos",
20995
+ "kind": "function",
20996
+ "jsdoc": "/** A document of undecorated paragraphs, one per blank-line-separated block of `text` — the inverse of\n * ricosToPlainText for plain text. An empty string gives one empty paragraph. */",
20997
+ "decl": "export function plainTextToRicos(text: string): RicosDocument;"
20998
+ },
20999
+ {
21000
+ "name": "isPlainRicos",
21001
+ "kind": "function",
21002
+ "jsdoc": "/** True when a plain-text editor can rewrite the document without losing anything: no document styling, and\n * only paragraphs of undecorated text runs whose paragraph settings are the defaults a plain paragraph carries\n * (`{ textStyle: { textAlignment: \"AUTO\" }, indentation: 0 }`, or none). A heading, list, link, bold run,\n * media node, alignment or indent makes it rich. A missing or empty document (no `nodes`, or `[]`) is plain —\n * there is nothing in it to lose. Anything malformed is not: a value that is not a document object (a JSON\n * string, an array), or `nodes` that is not an array, so a caller holding the wrong shape never overwrites it. */",
21003
+ "decl": "export function isPlainRicos(doc: RicosInput | null | undefined): boolean;"
21004
+ },
21005
+ {
21006
+ "name": "htmlIsTrivial",
21007
+ "kind": "function",
21008
+ "jsdoc": "/** True when an HTML description has no formatting to protect: empty, text with no tag in it (a lone `<` in\n * prose is text), or exactly one attribute-free `<p>` around text with no inner tags. A form that edits plain\n * text may overwrite only these. */",
21009
+ "decl": "export function htmlIsTrivial(html: string | null | undefined): boolean;"
21010
+ },
21011
+ {
21012
+ "name": "encodeRichContent",
21013
+ "kind": "function",
21014
+ "jsdoc": "/** Prepares a Ricos document for the RichContent viewer; bind the returned `json` as `documentJsonPath`.\n * Wix media ids become sized https URLs (`imageWidth`, default and maximum 1400 px; galleries and posters at most\n * 1000). Block ids follow the viewer's own rule on the encoded document — a block's missing, all-digits-and-dots\n * or repeated id becomes its path index there (\"0.2.1\") — so every renderer shows the same ids and encoding twice\n * changes nothing. Images, galleries and videos without https media (an http YouTube or Vimeo link is kept: the\n * viewer shows it as a card), buttons without an http(s)/mailto/tel link, any other link url with a disallowed\n * scheme (link decorations, card and image links) and inline HTML (`htmlData.html`, an embed's `oembed.html`) are\n * removed; an allowed link is emitted trimmed of surrounding whitespace, as the viewer emits it. Text is never\n * changed. Keys are sorted, so equal documents encode to equal strings. The input is not\n * modified. A missing or empty document gives `{ json: \"\" }`; a non-document or one past the viewer's limits gives\n * `{ json: \"\", rejected }` (checked in the order not_a_document, too_deep, too_large, too_many_nodes). */",
21015
+ "decl": "export function encodeRichContent(doc: RicosInput | null | undefined, opts: { imageWidth?: number } = {}): { json: string; rejected?: RejectReason };"
21016
+ }
21017
+ ]
21018
+ },
20946
21019
  {
20947
21020
  "name": "@himalaya/wix-seo",
20948
21021
  "source": "stdlib/wix-sdk/seo-v1/src/index.ts",