@voltro/cms 0.85.0 → 0.86.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 (80) hide show
  1. package/CHANGELOG.md +666 -0
  2. package/THIRD-PARTY-NOTICES.md +5 -33
  3. package/dist/ContentForm.js +282 -0
  4. package/dist/RichDocumentEditor.js +550 -0
  5. package/dist/RichDocumentView.js +132 -0
  6. package/dist/RichTextSurface.js +135 -0
  7. package/dist/aiCandidates.js +199 -0
  8. package/dist/aiOperations.js +152 -0
  9. package/dist/audiences.js +31 -0
  10. package/dist/availability.js +121 -0
  11. package/dist/blueprint.js +166 -0
  12. package/dist/bulk.js +281 -0
  13. package/dist/cacheIdentity.js +152 -0
  14. package/dist/changes.js +90 -0
  15. package/dist/cmsContext.js +229 -0
  16. package/dist/collections.js +224 -0
  17. package/dist/consent.js +29 -0
  18. package/dist/contentType.js +191 -0
  19. package/dist/contentfulImport.js +162 -0
  20. package/dist/copies.js +89 -0
  21. package/dist/cutover.js +202 -0
  22. package/dist/deliveryChecks.js +138 -0
  23. package/dist/domains.js +145 -0
  24. package/dist/draftTexts.js +164 -0
  25. package/dist/duplicates.js +78 -0
  26. package/dist/edgePurge.js +69 -0
  27. package/dist/editHistory.js +113 -0
  28. package/dist/effectForm.js +11 -0
  29. package/dist/environments.js +109 -0
  30. package/dist/errors.js +67 -0
  31. package/dist/experiments.js +528 -0
  32. package/dist/exposure.js +28 -0
  33. package/dist/extensionManifest.js +81 -0
  34. package/dist/extensions.js +314 -0
  35. package/dist/fieldSchema.js +199 -0
  36. package/dist/formStrings.js +74 -0
  37. package/dist/glossary.js +73 -0
  38. package/dist/history.js +54 -0
  39. package/dist/htmlImport.js +297 -0
  40. package/dist/index.d.ts +11 -7
  41. package/dist/index.js +73 -6082
  42. package/dist/media.js +29 -0
  43. package/dist/metrics.js +46 -0
  44. package/dist/migration.js +193 -0
  45. package/dist/migrationStages.js +13 -0
  46. package/dist/presenceAnchors.js +68 -0
  47. package/dist/preview.js +31 -0
  48. package/dist/promotion.js +107 -0
  49. package/dist/quality.js +188 -0
  50. package/dist/recurrence.js +78 -0
  51. package/dist/redirects.js +99 -0
  52. package/dist/referenceGraph.js +223 -0
  53. package/dist/references.js +173 -0
  54. package/dist/release.js +205 -0
  55. package/dist/rest.js +52 -0
  56. package/dist/review.js +160 -0
  57. package/dist/richDocument.js +491 -0
  58. package/dist/richInline.js +100 -0
  59. package/dist/schedule.js +80 -0
  60. package/dist/search.js +148 -0
  61. package/dist/selectionIntent.js +164 -0
  62. package/dist/seo.js +31 -0
  63. package/dist/series.js +105 -0
  64. package/dist/share.js +112 -0
  65. package/dist/stewardship.js +146 -0
  66. package/dist/taxonomy.js +36 -0
  67. package/dist/team.js +103 -0
  68. package/dist/templates.js +106 -0
  69. package/dist/trackChanges.js +197 -0
  70. package/dist/translation.js +64 -0
  71. package/dist/tree.js +87 -0
  72. package/dist/usage.js +50 -0
  73. package/dist/validation.js +192 -0
  74. package/dist/visualEditing.js +60 -0
  75. package/dist/web.js +33 -2
  76. package/dist/workflow.js +322 -0
  77. package/dist/write.js +394 -0
  78. package/dist/xliff.js +325 -0
  79. package/package.json +5 -5
  80. package/dist/presenceAnchors-4iHAVQB3.js +0 -4367
package/dist/search.js ADDED
@@ -0,0 +1,148 @@
1
+ import { normalizeRichDocument as e, plainTextOf as t } from "./richDocument.js";
2
+ import { asTyped as n } from "./effectForm.js";
3
+ import { and as r, eq as i, id as a, inSet as o, table as s, text as c } from "@voltro/database";
4
+ import { tenant as l } from "@voltro/plugin-multitenancy/mixin";
5
+ //#region src/search.ts
6
+ var u = "cms_search", d = "cms_search_text", f = s(u, {
7
+ id: a({ prefix: "csrch" }),
8
+ site: c().maxLength(64),
9
+ environment: c().maxLength(64),
10
+ locale: c().maxLength(64),
11
+ contentType: c().maxLength(64),
12
+ documentId: c().maxLength(64),
13
+ variantId: c().maxLength(64),
14
+ stage: c().oneOf(["draft", "published"]),
15
+ title: c(),
16
+ body: c()
17
+ }).with(l()).index("cms_search_by_variant", ["variantId", "stage"]).fullTextIndex(d, ["title", "body"], {
18
+ config: "simple",
19
+ weights: {
20
+ title: "A",
21
+ body: "B"
22
+ }
23
+ }), p = (e, t, n) => {
24
+ if (t[n.title]?.kind !== "string") throw Error(`defineContentType('${e}'): search.title '${n.title}' is not a string field of this content type.`);
25
+ }, m = (e) => typeof e == "object" && !!e && e.type === "doc" && Array.isArray(e.blocks), h = (n, r) => {
26
+ if (r == null) return [];
27
+ switch (n.kind) {
28
+ case "string": return typeof r == "string" && r !== "" ? [r] : [];
29
+ case "richText": {
30
+ let n = e(r);
31
+ return m(n) ? [t(n)] : [];
32
+ }
33
+ case "array": return Array.isArray(r) && n.element !== void 0 ? r.flatMap((e) => h(n.element, e)) : [];
34
+ case "struct": return typeof r == "object" && n.struct !== void 0 ? Object.entries(n.struct).flatMap(([e, t]) => h(t, r[e])) : [];
35
+ case "components": return Array.isArray(r) ? r.flatMap((e) => {
36
+ let t = e, r = n.components?.find((e) => e.id === t.componentId);
37
+ if (r === void 0 || typeof t.props != "object" || t.props === null) return [];
38
+ let i = t.props;
39
+ return Object.entries(r.props).flatMap(([e, t]) => h(t, i[e]));
40
+ }) : [];
41
+ default: return [];
42
+ }
43
+ }, g = (e, t) => {
44
+ let n = e.search?.title ?? "";
45
+ return {
46
+ title: typeof t[n] == "string" ? t[n] : "",
47
+ body: Object.entries(e.fields).filter(([t]) => t !== n && !e.derivedFields.includes(t)).flatMap(([e, n]) => h(n, t[e])).join("\n")
48
+ };
49
+ }, _ = async (e, t, n) => (await e.query({
50
+ table: u,
51
+ predicate: r(i("variantId", t), i("stage", n)),
52
+ order: [],
53
+ take: 1,
54
+ skip: void 0,
55
+ projection: void 0
56
+ }))[0], v = async (e, t, n, r, i) => {
57
+ if (t.search === void 0) return;
58
+ let a = g(t, n), o = String(n.id), s = await _(e, o, i);
59
+ if (s !== void 0) {
60
+ await e.update(u, String(s.id), a);
61
+ return;
62
+ }
63
+ let c = n.tenantId;
64
+ await e.insert(u, {
65
+ site: r.site,
66
+ environment: r.environment,
67
+ locale: r.locale,
68
+ contentType: t.name,
69
+ documentId: String(n.documentId),
70
+ variantId: o,
71
+ stage: i,
72
+ ...a,
73
+ ...c == null ? {} : { tenantId: c }
74
+ });
75
+ }, y = async (e, t, n, r) => {
76
+ if (t.search !== void 0) for (let t of r) {
77
+ let r = await _(e, n, t);
78
+ r !== void 0 && await e.delete(u, String(r.id));
79
+ }
80
+ }, b = async (e, t) => {
81
+ if (t.search === void 0) return 0;
82
+ let n = 0;
83
+ for (let r of ["draft", "published"]) {
84
+ let i = await e.query({
85
+ table: `${t.name}_${r === "draft" ? "drafts" : "published"}`,
86
+ predicate: void 0,
87
+ order: [],
88
+ take: void 0,
89
+ skip: void 0,
90
+ projection: void 0
91
+ });
92
+ for (let a of i) {
93
+ let i = {
94
+ site: String(a.site),
95
+ environment: String(a.environment),
96
+ locale: String(a.locale)
97
+ };
98
+ a.status === "archived" ? await y(e, t, String(a.id), [r]) : (await v(e, t, a, i, r), n += 1);
99
+ }
100
+ }
101
+ return n;
102
+ }, x = (e) => e.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((e) => e !== ""), S = 160, C = (e, t) => {
103
+ let n = x(t), r = [...e.matchAll(/[\p{L}\p{N}]+/gu)].find((e) => n.some((t) => e[0].toLowerCase().startsWith(t))), i = r === void 0 ? 0 : Math.max(0, (r.index ?? 0) - S / 3), a = i === 0 ? 0 : e.slice(i).search(/\s/) + i + 1, o = Math.min(e.length, a + S), s = o < e.length ? e.slice(a, o).replace(/\s+\S*$/, "") : e.slice(a, o), c = `${a > 0 ? "…" : ""}${s.replace(/\s+/g, " ")}${a + s.length < e.length ? "…" : ""}`;
104
+ return {
105
+ text: c,
106
+ marks: [...c.matchAll(/[\p{L}\p{N}]+/gu)].filter((e) => n.some((t) => e[0].toLowerCase().startsWith(t))).map((e) => [e.index ?? 0, (e.index ?? 0) + e[0].length])
107
+ };
108
+ }, w = async (e, t, n, a) => {
109
+ let s = n.trim();
110
+ if (x(s).length === 0) return [];
111
+ let c = Math.max(1, Math.min(100, Math.floor(a.limit ?? 20))), l = a.types ?? [];
112
+ return (await e.query({
113
+ table: u,
114
+ predicate: r(i("site", t.site), i("environment", t.environment), i("stage", a.stage), ...a.locale === void 0 ? [] : [i("locale", a.locale)], ...l.length > 0 ? [o("contentType", l)] : [], ...Object.entries(a.filter ?? {}).map(([e, t]) => i(e, t))),
115
+ order: [{
116
+ column: "id",
117
+ direction: "asc"
118
+ }],
119
+ take: c,
120
+ skip: void 0,
121
+ projection: void 0,
122
+ fullTextSearch: {
123
+ indexName: d,
124
+ query: s,
125
+ columns: ["title", "body"],
126
+ config: "simple",
127
+ weights: {
128
+ title: "A",
129
+ body: "B"
130
+ },
131
+ rank: {
132
+ alias: "rank",
133
+ order: !0
134
+ },
135
+ prefix: !0
136
+ }
137
+ })).map((e) => ({
138
+ contentType: String(e.contentType),
139
+ documentId: String(e.documentId),
140
+ variantId: String(e.variantId),
141
+ locale: String(e.locale),
142
+ title: String(e.title),
143
+ snippet: C(String(e.body ?? ""), s),
144
+ rank: Number(e.rank ?? 0)
145
+ }));
146
+ }, T = (...e) => n(() => y(...e)), E = (...e) => n(() => v(...e)), D = (...e) => n(() => b(...e)), O = (...e) => n(() => w(...e));
147
+ //#endregion
148
+ export { u as CMS_SEARCH_TABLE, p as checkSearch, f as cmsSearchTable, y as dropFromSearch, T as dropFromSearchEffect, v as indexForSearch, E as indexForSearchEffect, b as rebuildSearch, D as rebuildSearchEffect, w as searchContent, O as searchContentEffect, g as searchTextOf, C as snippetOf };
@@ -0,0 +1,164 @@
1
+ import { normalizeRichDocument as e } from "./richDocument.js";
2
+ import { inlineText as t, mergeInline as n, sliceInline as r } from "./richInline.js";
3
+ //#region src/selectionIntent.ts
4
+ var i = /^[A-Za-z0-9_.:-]{1,120}$/, a = (e) => typeof e == "object" && !!e && !Array.isArray(e), o = (e) => typeof e == "string" && i.test(e), s = (e) => Number.isInteger(e) && e >= 0 && e <= 1e6, c = (e) => typeof e == "string" && /^\/(?![/\\])[^\s]*$/.test(e) && e.length <= 2e3, l = (e) => {
5
+ if (!a(e) || !o(e.id) || !o(e.pick) || !c(e.returnTo) || !a(e.target)) return null;
6
+ let t = e.target;
7
+ if (!o(t.type) || !o(t.field)) return null;
8
+ let n = t.documentId !== void 0 || t.revisionId !== void 0;
9
+ if ((n ? !(o(t.documentId) && o(t.revisionId)) || t.formId !== void 0 : !o(t.formId)) || t.instanceId !== void 0 != (t.prop !== void 0) || t.instanceId !== void 0 && (!o(t.instanceId) || !o(t.prop) || t.blockId !== void 0) || t.locale !== void 0 && !o(t.locale) || t.blockId !== void 0 && !o(t.blockId)) return null;
10
+ let r = t.selection;
11
+ return r !== void 0 && !(a(r) && s(r.start) && s(r.end) && r.end > r.start && t.blockId !== void 0) || e.label !== void 0 && (typeof e.label != "string" || e.label.length > 200) || e.kind !== void 0 && !o(e.kind) ? null : {
12
+ id: e.id,
13
+ pick: e.pick,
14
+ returnTo: e.returnTo,
15
+ ...typeof e.label == "string" ? { label: e.label } : {},
16
+ ...typeof e.kind == "string" ? { kind: e.kind } : {},
17
+ target: {
18
+ type: t.type,
19
+ field: t.field,
20
+ ...n ? {
21
+ documentId: t.documentId,
22
+ revisionId: t.revisionId
23
+ } : { formId: t.formId },
24
+ ...t.instanceId === void 0 ? {} : {
25
+ instanceId: t.instanceId,
26
+ prop: t.prop
27
+ },
28
+ ...t.locale === void 0 ? {} : { locale: t.locale },
29
+ ...t.blockId === void 0 ? {} : { blockId: t.blockId },
30
+ ...a(r) ? { selection: {
31
+ start: r.start,
32
+ end: r.end
33
+ } } : {}
34
+ }
35
+ };
36
+ }, u = (e) => {
37
+ let t = new TextEncoder().encode(e), n = "";
38
+ for (let e of t) n += String.fromCharCode(e);
39
+ return btoa(n).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
40
+ }, d = (e) => {
41
+ try {
42
+ let t = atob(e.replace(/-/g, "+").replace(/_/g, "/"));
43
+ return new TextDecoder("utf-8", { fatal: !0 }).decode(Uint8Array.from(t, (e) => e.charCodeAt(0)));
44
+ } catch {
45
+ return null;
46
+ }
47
+ }, f = (e) => u(JSON.stringify(e)), p = (e) => {
48
+ if (e == null || e === "" || e.length > 6e3) return null;
49
+ let t = d(e);
50
+ if (t === null) return null;
51
+ try {
52
+ return l(JSON.parse(t));
53
+ } catch {
54
+ return null;
55
+ }
56
+ }, m = (e, i, a, o) => {
57
+ if (e.type !== "paragraph" && e.type !== "heading") return null;
58
+ let s = e.content, c = t(s).length;
59
+ if (a === void 0 || a.end > c) {
60
+ if (o === void 0 || o === "") return null;
61
+ let r = c === 0 || /\s$/.test(t(s)) ? [] : [{
62
+ type: "text",
63
+ text: " "
64
+ }];
65
+ return {
66
+ ...e,
67
+ content: n([
68
+ ...s,
69
+ ...r,
70
+ {
71
+ type: "link",
72
+ target: i,
73
+ text: o
74
+ }
75
+ ])
76
+ };
77
+ }
78
+ let l = t(s).slice(a.start, a.end);
79
+ return {
80
+ ...e,
81
+ content: n([
82
+ ...r(s, 0, a.start),
83
+ {
84
+ type: "link",
85
+ target: i,
86
+ text: l
87
+ },
88
+ ...r(s, a.end, c)
89
+ ])
90
+ };
91
+ }, h = (t, n, r, i) => {
92
+ if (r.intentId !== n.id) return {
93
+ ok: !1,
94
+ reason: "otherIntent"
95
+ };
96
+ let { target: a } = n;
97
+ if (a.formId !== void 0) {
98
+ if (i.formId !== a.formId) return {
99
+ ok: !1,
100
+ reason: "otherDocument"
101
+ };
102
+ } else {
103
+ if (i.documentId !== a.documentId) return {
104
+ ok: !1,
105
+ reason: "otherDocument"
106
+ };
107
+ if (i.revisionId !== a.revisionId) return {
108
+ ok: !1,
109
+ reason: "revisionMoved"
110
+ };
111
+ }
112
+ if (a.instanceId !== void 0 && a.prop !== void 0) {
113
+ let e = Array.isArray(t[a.field]) ? t[a.field] : [], n = e.findIndex((e) => e.instanceId === a.instanceId);
114
+ if (n < 0) return {
115
+ ok: !1,
116
+ reason: "targetGone"
117
+ };
118
+ let i = a.prop;
119
+ return {
120
+ ok: !0,
121
+ values: {
122
+ ...t,
123
+ [a.field]: e.map((e, t) => t === n ? {
124
+ ...e,
125
+ props: {
126
+ ...e.props,
127
+ [i]: r.documentId
128
+ }
129
+ } : e)
130
+ }
131
+ };
132
+ }
133
+ if (a.blockId === void 0) return {
134
+ ok: !0,
135
+ values: {
136
+ ...t,
137
+ [a.field]: r.documentId
138
+ }
139
+ };
140
+ let o = e(t[a.field] ?? ""), s = Array.isArray(o.blocks) ? o.blocks.findIndex((e) => e.id === a.blockId) : -1;
141
+ if (s < 0) return {
142
+ ok: !1,
143
+ reason: "targetGone"
144
+ };
145
+ let c = o.blocks[s], l = c.type === "image" || c.type === "file" ? {
146
+ ...c,
147
+ asset: r.documentId
148
+ } : m(c, r.documentId, a.selection, r.title);
149
+ return l === null ? {
150
+ ok: !1,
151
+ reason: "targetGone"
152
+ } : {
153
+ ok: !0,
154
+ values: {
155
+ ...t,
156
+ [a.field]: {
157
+ ...o,
158
+ blocks: o.blocks.map((e, t) => t === s ? l : e)
159
+ }
160
+ }
161
+ };
162
+ };
163
+ //#endregion
164
+ export { h as applySelection, p as decodeSelectionIntent, f as encodeSelectionIntent, l as parseSelectionIntent };
package/dist/seo.js ADDED
@@ -0,0 +1,31 @@
1
+ //#region src/seo.ts
2
+ var e = (e, t) => e.nodes.find((e) => e.documentId === t && !e.fallback), t = (t, n) => t.flatMap((t) => {
3
+ let r = e(t.tree, n);
4
+ return r === void 0 ? [] : [{
5
+ locale: t.locale,
6
+ path: r.path
7
+ }];
8
+ }), n = (e) => {
9
+ let t = e instanceof Date ? e : typeof e == "string" || typeof e == "number" ? new Date(e) : null;
10
+ return t === null || Number.isNaN(t.getTime()) ? null : t.toISOString();
11
+ }, r = (e, r = () => !0) => e.flatMap((i) => i.tree.nodes.filter((e) => !e.fallback && r(e)).map((a) => ({
12
+ locale: i.locale,
13
+ path: a.path,
14
+ documentId: a.documentId,
15
+ lastmod: n(a.row.updatedAt),
16
+ alternates: t(e, a.documentId).filter((t) => {
17
+ let n = e.find((e) => e.locale === t.locale)?.tree.nodes.find((e) => e.documentId === a.documentId);
18
+ return n !== void 0 && r(n);
19
+ })
20
+ }))), i = (e) => e.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;"), a = (e, t, n) => `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">\n${e.map((e) => {
21
+ let r = e.alternates.length > 1 ? [...e.alternates.map((e) => ` <xhtml:link rel="alternate" hreflang="${i(e.locale)}" href="${i(t(e.locale, e.path))}" />`), ...e.alternates.filter((e) => e.locale === n).map((e) => ` <xhtml:link rel="alternate" hreflang="x-default" href="${i(t(e.locale, e.path))}" />`)] : [], a = e.lastmod === null ? [] : [` <lastmod>${e.lastmod}</lastmod>`];
22
+ return [
23
+ " <url>",
24
+ ` <loc>${i(t(e.locale, e.path))}</loc>`,
25
+ ...a,
26
+ ...r,
27
+ " </url>"
28
+ ].join("\n");
29
+ }).join("\n")}\n</urlset>\n`;
30
+ //#endregion
31
+ export { t as alternatesOf, r as sitemapUrls, a as sitemapXml };
package/dist/series.js ADDED
@@ -0,0 +1,105 @@
1
+ import { asTyped as e } from "./effectForm.js";
2
+ import { ContentNotFound as t, ContentValidationFailed as n } from "./errors.js";
3
+ import { scopeColumns as r } from "./write.js";
4
+ import { occurrencesOf as i, recurrenceProblems as a } from "./recurrence.js";
5
+ import { and as o, eq as s, id as c, integer as l, json as u, table as d, text as f } from "@voltro/database";
6
+ import { tenant as p } from "@voltro/plugin-multitenancy/mixin";
7
+ //#region src/series.ts
8
+ var m = "cms_publish_series", h = d(m, {
9
+ id: c({ prefix: "cser" }),
10
+ contentType: f().maxLength(64),
11
+ draftId: f(),
12
+ rule: u(),
13
+ armed: l().default(-1),
14
+ state: f().oneOf(["running", "done"]).default("running")
15
+ }).with(p()).unique("cms_publish_series_uq_draft", ["tenantId", "draftId"]), g = (e, t, n) => e.query({
16
+ table: t,
17
+ predicate: n,
18
+ order: [],
19
+ take: void 0,
20
+ skip: void 0,
21
+ projection: void 0
22
+ }), _ = (e) => `${e.name}_drafts`, v = (e) => {
23
+ let t = e.rule;
24
+ return {
25
+ id: String(e.id),
26
+ rule: t,
27
+ occurrences: i(t),
28
+ armed: Number(e.armed),
29
+ state: e.state === "done" ? "done" : "running"
30
+ };
31
+ }, y = async (e, t) => {
32
+ let [n] = await g(e, m, s("draftId", t));
33
+ return n === void 0 ? null : v(n);
34
+ }, b = async (e, t, n, r, i, a) => {
35
+ let o = r.findIndex((e, t) => t > i && e.endsAt.getTime() > a.getTime());
36
+ if (o === -1) return -1;
37
+ let s = r[o];
38
+ return await e.update(_(t), n, {
39
+ publishAt: s.startsAt,
40
+ unpublishAt: s.endsAt
41
+ }), o;
42
+ }, x = async (e, c, l, u, d, f = /* @__PURE__ */ new Date()) => {
43
+ let p = a(d);
44
+ if (p.length > 0) throw new n({
45
+ contentType: c.name,
46
+ violations: p.map((e) => ({
47
+ field: "repeat",
48
+ rule: "recurrence",
49
+ message: e
50
+ }))
51
+ });
52
+ let [h] = await g(e, _(c), o(s("id", l), ...Object.entries(r(u)).map(([e, t]) => s(e, t))));
53
+ if (h === void 0) throw new t({
54
+ contentType: c.name,
55
+ id: l,
56
+ stage: "draft"
57
+ });
58
+ let y = await b(e, c, l, i(d), -1, f);
59
+ if (y === -1) throw new n({
60
+ contentType: c.name,
61
+ violations: [{
62
+ field: "repeat",
63
+ rule: "recurrence",
64
+ message: "every occurrence of this series is over"
65
+ }]
66
+ });
67
+ for (let t of await g(e, m, s("draftId", l))) await e.delete(m, String(t.id));
68
+ let x = h.tenantId !== void 0 && h.tenantId !== null ? { tenantId: h.tenantId } : {};
69
+ return v(await e.insert(m, {
70
+ contentType: c.name,
71
+ draftId: l,
72
+ rule: d,
73
+ armed: y,
74
+ state: "running",
75
+ ...x
76
+ }));
77
+ }, S = async (e, t, n) => {
78
+ let r = await g(e, m, s("draftId", n));
79
+ if (r.length === 0) return !1;
80
+ for (let t of r) await e.delete(m, String(t.id));
81
+ let [i] = await g(e, _(t), s("id", n));
82
+ return i !== void 0 && await e.update(_(t), n, {
83
+ publishAt: null,
84
+ unpublishAt: null
85
+ }), !0;
86
+ }, C = async (e, t, n = /* @__PURE__ */ new Date()) => {
87
+ let r = [];
88
+ for (let a of await g(e, m, o(s("contentType", t.name), s("state", "running")))) {
89
+ let o = String(a.draftId);
90
+ await e.transactional(async (e) => {
91
+ let [c] = await g(e, _(t), s("id", o));
92
+ if (c === void 0) {
93
+ await e.delete(m, String(a.id));
94
+ return;
95
+ }
96
+ let l = (e) => e != null;
97
+ if (l(c.publishAt) || l(c.unpublishAt)) return;
98
+ let u = await b(e, t, o, i(a.rule), Number(a.armed), n);
99
+ await e.update(m, String(a.id), u === -1 ? { state: "done" } : { armed: u }), u !== -1 && r.push(o);
100
+ });
101
+ }
102
+ return r;
103
+ }, w = [t, n], T = (...t) => e(() => C(...t), ...w), E = (...t) => e(() => S(...t), ...w), D = (...t) => e(() => x(...t), ...w), O = (...t) => e(() => y(...t), ...w);
104
+ //#endregion
105
+ export { m as CMS_PUBLISH_SERIES_TABLE, C as advanceSeries, T as advanceSeriesEffect, S as cancelSeries, E as cancelSeriesEffect, h as cmsPublishSeriesTable, x as scheduleSeries, D as scheduleSeriesEffect, y as seriesOf, O as seriesOfEffect };
package/dist/share.js ADDED
@@ -0,0 +1,112 @@
1
+ import { asTyped as e } from "./effectForm.js";
2
+ import { ContentNotFound as t, PreviewShareRejected as n } from "./errors.js";
3
+ import { CMS_REVISIONS_TABLE as r } from "./contentType.js";
4
+ import { and as i, eq as a, id as o, table as s, text as c, timestamp as l } from "@voltro/database";
5
+ import { tenant as u } from "@voltro/plugin-multitenancy/mixin";
6
+ import { createHash as d, randomBytes as f } from "node:crypto";
7
+ //#region src/share.ts
8
+ var p = "cms_preview_shares", m = 30, h = s(p, {
9
+ id: o({ prefix: "cshr" }),
10
+ contentType: c().maxLength(64),
11
+ variantId: c().maxLength(64),
12
+ documentId: c().maxLength(64),
13
+ site: c().maxLength(64),
14
+ environment: c().maxLength(64),
15
+ locale: c().maxLength(64),
16
+ revisionId: c().nullable(),
17
+ tokenHash: c().unique(),
18
+ label: c().nullable(),
19
+ expiresAt: l(),
20
+ revokedAt: l().nullable()
21
+ }).with(u()), g = (e) => d("sha256").update(e, "utf8").digest("hex"), _ = async (e, t, n, r = !1) => (await e.query({
22
+ table: t,
23
+ predicate: n,
24
+ order: [],
25
+ take: 1,
26
+ skip: void 0,
27
+ projection: void 0,
28
+ ...r ? { crossTenant: !0 } : {}
29
+ }))[0], v = async (e, r, o, s, c) => {
30
+ let l = c.now ?? /* @__PURE__ */ new Date();
31
+ if (c.expiresAt.getTime() <= l.getTime()) throw new n({ reason: "expiryInPast" });
32
+ if (c.expiresAt.getTime() > l.getTime() + 2592e6) throw new n({ reason: "expiryTooFar" });
33
+ let u = await _(e, `${r.name}_drafts`, i(a("id", o), a("site", s.site), a("environment", s.environment), a("locale", s.locale)));
34
+ if (u === void 0) throw new t({
35
+ contentType: r.name,
36
+ id: o,
37
+ stage: "draft"
38
+ });
39
+ let d = f(32).toString("base64url");
40
+ return {
41
+ share: await e.insert(p, {
42
+ contentType: r.name,
43
+ variantId: o,
44
+ documentId: u.documentId,
45
+ site: s.site,
46
+ environment: s.environment,
47
+ locale: s.locale,
48
+ revisionId: c.revision === "pinned" ? u.revisionId : null,
49
+ tokenHash: g(d),
50
+ label: c.label ?? null,
51
+ expiresAt: c.expiresAt,
52
+ revokedAt: null
53
+ }),
54
+ token: d
55
+ };
56
+ }, y = async (e, t, n = /* @__PURE__ */ new Date()) => {
57
+ let o = await _(e, p, a("tokenHash", g(t)), !0);
58
+ if (o === void 0) return {
59
+ ok: !1,
60
+ reason: "unknown"
61
+ };
62
+ if (o.revokedAt !== null && o.revokedAt !== void 0) return {
63
+ ok: !1,
64
+ reason: "revoked"
65
+ };
66
+ if (new Date(o.expiresAt).getTime() <= n.getTime()) return {
67
+ ok: !1,
68
+ reason: "expired"
69
+ };
70
+ let s = o.tenantId, c = (e, t) => i(a(e, t), a("tenantId", s)), l = o.revisionId;
71
+ if (l === null) {
72
+ let t = await _(e, `${String(o.contentType)}_drafts`, c("id", o.variantId), !0);
73
+ if (t === void 0) return {
74
+ ok: !1,
75
+ reason: "unknown"
76
+ };
77
+ l = t.revisionId;
78
+ }
79
+ let u = await _(e, r, i(c("id", l), a("documentId", o.documentId), a("contentType", o.contentType)), !0);
80
+ return u === void 0 ? {
81
+ ok: !1,
82
+ reason: "unknown"
83
+ } : {
84
+ ok: !0,
85
+ share: o,
86
+ contentType: o.contentType,
87
+ locale: o.locale,
88
+ revisionId: l,
89
+ revision: u.number,
90
+ values: u.values ?? {}
91
+ };
92
+ }, b = async (e, n, r = /* @__PURE__ */ new Date()) => {
93
+ let i = await _(e, p, a("id", n));
94
+ if (i === void 0) throw new t({
95
+ contentType: p,
96
+ id: n,
97
+ stage: "share"
98
+ });
99
+ (i.revokedAt === null || i.revokedAt === void 0) && await e.update(p, n, { revokedAt: r });
100
+ }, x = (e, t, n) => e.query({
101
+ table: p,
102
+ predicate: i(a("contentType", t.name), a("documentId", n)),
103
+ order: [{
104
+ column: "createdAt",
105
+ direction: "desc"
106
+ }],
107
+ take: void 0,
108
+ skip: void 0,
109
+ projection: void 0
110
+ }), S = [t, n], C = (...t) => e(() => v(...t), ...S), w = (...t) => e(() => x(...t), ...S), T = (...t) => e(() => y(...t), ...S), E = (...t) => e(() => b(...t), ...S);
111
+ //#endregion
112
+ export { p as CMS_PREVIEW_SHARES_TABLE, m as MAX_PREVIEW_SHARE_DAYS, h as cmsPreviewSharesTable, v as createPreviewShare, C as createPreviewShareEffect, x as listPreviewShares, w as listPreviewSharesEffect, y as resolvePreviewShare, T as resolvePreviewShareEffect, b as revokePreviewShare, E as revokePreviewShareEffect };