@voltro/cms 0.84.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 (81) hide show
  1. package/CHANGELOG.md +1215 -0
  2. package/THIRD-PARTY-NOTICES.md +118 -600
  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 +2266 -170
  41. package/dist/index.js +73 -3947
  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.d.ts +927 -131
  76. package/dist/web.js +33 -2
  77. package/dist/workflow.js +322 -0
  78. package/dist/write.js +394 -0
  79. package/dist/xliff.js +325 -0
  80. package/package.json +6 -6
  81. package/dist/extensionManifest-BK3ZcL2P.js +0 -2782
package/dist/errors.js ADDED
@@ -0,0 +1,67 @@
1
+ import { Schema as e } from "effect";
2
+ //#region src/errors.ts
3
+ var t = e.Struct({
4
+ field: e.String,
5
+ rule: e.String,
6
+ message: e.String
7
+ }), n = class extends e.TaggedError()("ContentValidationFailed", {
8
+ contentType: e.String,
9
+ violations: e.Array(t)
10
+ }) {}, r = class extends e.TaggedError()("ContentNotFound", {
11
+ contentType: e.String,
12
+ id: e.String,
13
+ stage: e.Literals([
14
+ "draft",
15
+ "published",
16
+ "revision",
17
+ "share"
18
+ ])
19
+ }) {}, i = class extends e.TaggedError()("ContentGone", {
20
+ contentType: e.String,
21
+ path: e.String
22
+ }) {}, a = class extends e.TaggedError()("ContentIdConflict", {
23
+ contentType: e.String,
24
+ id: e.String
25
+ }) {}, o = class extends e.TaggedError()("RevisionMismatch", {
26
+ contentType: e.String,
27
+ id: e.String,
28
+ expected: e.String,
29
+ actual: e.String
30
+ }) {}, s = class extends e.TaggedError()("ReleaseNotEditable", {
31
+ id: e.String,
32
+ status: e.String
33
+ }) {}, c = class extends e.TaggedError()("PreviewShareRejected", { reason: e.Literals(["expiryInPast", "expiryTooFar"]) }) {}, l = class extends e.TaggedError()("ReviewRequired", {
34
+ contentType: e.String,
35
+ id: e.String,
36
+ revisionId: e.String
37
+ }) {}, u = class extends e.TaggedError()("ReviewStepRefused", {
38
+ contentType: e.String,
39
+ id: e.String,
40
+ reason: e.Literals([
41
+ "notInReview",
42
+ "selfApproval",
43
+ "ambiguousOrder"
44
+ ])
45
+ }) {}, d = class extends e.TaggedError()("ReferenceUnavailable", {
46
+ contentType: e.String,
47
+ id: e.String,
48
+ targets: e.Array(e.Struct({
49
+ path: e.String,
50
+ contentType: e.String,
51
+ documentId: e.String,
52
+ reason: e.Literals([
53
+ "blocked",
54
+ "expired",
55
+ "notYet",
56
+ "territory",
57
+ "channel",
58
+ "purpose"
59
+ ])
60
+ }))
61
+ }) {}, f = class extends e.TaggedError()("QuotaExceeded", {
62
+ quota: e.String,
63
+ limit: e.Number,
64
+ used: e.Number
65
+ }) {};
66
+ //#endregion
67
+ export { i as ContentGone, a as ContentIdConflict, r as ContentNotFound, n as ContentValidationFailed, c as PreviewShareRejected, f as QuotaExceeded, d as ReferenceUnavailable, s as ReleaseNotEditable, l as ReviewRequired, u as ReviewStepRefused, o as RevisionMismatch };
@@ -0,0 +1,528 @@
1
+ import { asTyped as e } from "./effectForm.js";
2
+ import { ContentIdConflict as t, ContentNotFound as n, ContentValidationFailed as r, ReleaseNotEditable as i, RevisionMismatch as a } from "./errors.js";
3
+ import { saveDraft as o } from "./write.js";
4
+ import { CMS_RELEASE_ITEMS_TABLE as s, addToRelease as c, createRelease as l, releaseStatusOf as u } from "./release.js";
5
+ import { and as d, eq as f, id as p, integer as m, json as h, table as g, text as _, timestamp as v } from "@voltro/database";
6
+ import { tenant as y } from "@voltro/plugin-multitenancy/mixin";
7
+ //#region src/experiments.ts
8
+ var b = "cms_experiments", x = "cms_experiment_events", S = g(b, {
9
+ id: p({ prefix: "cexp" }),
10
+ site: _().maxLength(64),
11
+ environment: _().maxLength(64),
12
+ locale: _().maxLength(64),
13
+ contentType: _().maxLength(64),
14
+ documentId: _().maxLength(64),
15
+ name: _(),
16
+ status: _().oneOf([
17
+ "planned",
18
+ "running",
19
+ "stopped"
20
+ ]),
21
+ share: m(),
22
+ overrides: h(),
23
+ goal: _(),
24
+ hypothesis: _().nullable(),
25
+ guardrailMaxDrop: m().nullable(),
26
+ startedAt: v().nullable(),
27
+ stoppedAt: v().nullable(),
28
+ startReleaseId: _().maxLength(64).nullable(),
29
+ stopReason: _().oneOf([
30
+ "manual",
31
+ "replaced",
32
+ "rolledBack"
33
+ ]).nullable(),
34
+ revisionId: _().maxLength(64).nullable(),
35
+ adoptedReleaseId: _().maxLength(64).nullable(),
36
+ adoptedRevisionId: _().maxLength(64).nullable()
37
+ }).with(y()).index("cms_experiments_by_page", [
38
+ "contentType",
39
+ "documentId",
40
+ "status"
41
+ ]), C = g(x, {
42
+ id: p({ prefix: "cexe" }),
43
+ experimentId: _(),
44
+ variant: _().oneOf(["A", "B"]),
45
+ kind: _().oneOf(["exposure", "conversion"]),
46
+ reader: _(),
47
+ revisionId: _().maxLength(64).nullable(),
48
+ at: v()
49
+ }).with(y()).unique("cms_experiment_events_once", [
50
+ "experimentId",
51
+ "reader",
52
+ "kind"
53
+ ]), w = (e) => e instanceof Date ? e : new Date(String(e)), T = (e) => typeof e == "string" && e !== "" ? e : null, E = (e) => ({
54
+ id: String(e.id),
55
+ name: String(e.name),
56
+ contentType: String(e.contentType),
57
+ documentId: String(e.documentId),
58
+ locale: String(e.locale),
59
+ status: e.status === "running" || e.status === "planned" ? e.status : "stopped",
60
+ share: Number(e.share),
61
+ overrides: e.overrides ?? {},
62
+ goal: String(e.goal),
63
+ hypothesis: typeof e.hypothesis == "string" ? e.hypothesis : null,
64
+ guardrailMaxDrop: typeof e.guardrailMaxDrop == "number" ? e.guardrailMaxDrop : null,
65
+ startedAt: e.startedAt === null || e.startedAt === void 0 ? null : w(e.startedAt),
66
+ startReleaseId: T(e.startReleaseId),
67
+ stopReason: e.stopReason === "manual" || e.stopReason === "replaced" || e.stopReason === "rolledBack" ? e.stopReason : null,
68
+ stoppedAt: e.stoppedAt === null || e.stoppedAt === void 0 ? null : w(e.stoppedAt),
69
+ revisionId: T(e.revisionId),
70
+ adoptedReleaseId: T(e.adoptedReleaseId),
71
+ adoptedRevisionId: T(e.adoptedRevisionId)
72
+ }), D = (e) => {
73
+ let t = 2166136261;
74
+ for (let n = 0; n < e.length; n++) t ^= e.charCodeAt(n), t = Math.imul(t, 16777619) >>> 0;
75
+ return t >>> 0;
76
+ }, O = (e, t, n) => D(`${e}:${t}`) % 100 < n ? "B" : "A", k = /^([A-Za-z0-9_]+)\[([^\]]+)\]\.([A-Za-z0-9_]+)$/, A = (e, t, n) => {
77
+ if (n === "A") return e;
78
+ let r = { ...e };
79
+ for (let [e, n] of Object.entries(t.overrides)) {
80
+ let t = k.exec(e);
81
+ if (t === null) {
82
+ r[e] = n;
83
+ continue;
84
+ }
85
+ let [, i, a, o] = t, s = r[i];
86
+ Array.isArray(s) && (r[i] = s.map((e) => {
87
+ let t = e;
88
+ return t?.instanceId === a ? {
89
+ ...t,
90
+ props: {
91
+ ...t.props,
92
+ [o]: n
93
+ }
94
+ } : e;
95
+ }));
96
+ }
97
+ return r;
98
+ }, j = (e) => Object.entries(e.fields).filter(([t, n]) => n.kind === "string" && !e.derivedFields.includes(t)).map(([e]) => e), M = (e, t) => [...j(e), ...Object.entries(e.fields).filter(([, e]) => e.kind === "components").flatMap(([e, n]) => {
99
+ let r = t[e];
100
+ if (!Array.isArray(r)) return [];
101
+ let i = new Map((n.components ?? []).map((e) => [e.id, e]));
102
+ return r.flatMap((t) => {
103
+ let n = t, r = typeof n?.componentId == "string" ? i.get(n.componentId) : void 0;
104
+ return r === void 0 || typeof n.instanceId != "string" ? [] : Object.entries(r.props).filter(([, e]) => e.kind === "string").map(([t]) => `${e}[${n.instanceId}].${t}`);
105
+ });
106
+ })], N = (e) => {
107
+ if (!Number.isInteger(e.share) || e.share < 1 || e.share > 99) return {
108
+ ok: !1,
109
+ reason: "badShare"
110
+ };
111
+ if (e.hypothesis.trim() === "" || e.hypothesis.length > 500) return {
112
+ ok: !1,
113
+ reason: "noHypothesis"
114
+ };
115
+ let t = e.guardrailMaxDrop ?? null;
116
+ return t !== null && (!Number.isInteger(t) || t < 1 || t > 50) ? {
117
+ ok: !1,
118
+ reason: "badGuardrail"
119
+ } : Object.keys(e.overrides).length === 0 ? {
120
+ ok: !1,
121
+ reason: "noOverrides"
122
+ } : null;
123
+ }, P = async (e, t, n, r, i = /* @__PURE__ */ new Date()) => {
124
+ let a = N(r);
125
+ if (a !== null) return a;
126
+ let o = [
127
+ f("site", n.site),
128
+ f("environment", n.environment),
129
+ f("locale", n.locale),
130
+ f("documentId", r.documentId)
131
+ ], [s] = await e.query({
132
+ table: `${t.name}_published`,
133
+ predicate: d(...o),
134
+ order: [],
135
+ take: 1,
136
+ skip: void 0,
137
+ projection: void 0
138
+ });
139
+ if (s === void 0) return {
140
+ ok: !1,
141
+ reason: "notLive"
142
+ };
143
+ let c = F(t, s, r);
144
+ if (c !== null) return c;
145
+ if (await B(e, t, n, r.documentId) !== null) return {
146
+ ok: !1,
147
+ reason: "alreadyRunning"
148
+ };
149
+ let l = await e.insert(b, {
150
+ ...I(t, n, r, s.tenantId),
151
+ status: "running",
152
+ startedAt: i,
153
+ revisionId: T(s.revisionId)
154
+ });
155
+ return {
156
+ ok: !0,
157
+ id: String(l.id)
158
+ };
159
+ }, F = (e, t, n) => {
160
+ let r = new Set(M(e, t)), i = Object.keys(n.overrides).filter((e) => !r.has(e));
161
+ return i.length > 0 ? {
162
+ ok: !1,
163
+ reason: "unknownField",
164
+ fields: i
165
+ } : null;
166
+ }, I = (e, t, n, r) => ({
167
+ site: t.site,
168
+ environment: t.environment,
169
+ locale: t.locale,
170
+ contentType: e.name,
171
+ documentId: n.documentId,
172
+ name: n.name,
173
+ share: n.share,
174
+ overrides: { ...n.overrides },
175
+ goal: n.goal,
176
+ hypothesis: n.hypothesis.trim(),
177
+ guardrailMaxDrop: n.guardrailMaxDrop ?? null,
178
+ stoppedAt: null,
179
+ startReleaseId: null,
180
+ stopReason: null,
181
+ ...r == null ? {} : { tenantId: r }
182
+ }), L = async (e, t, n, r) => {
183
+ let i = N(r);
184
+ if (i !== null && !i.ok) return i;
185
+ let a = await u(e, r.releaseId).catch(() => null);
186
+ if (a !== "draft" && a !== "scheduled") return {
187
+ ok: !1,
188
+ reason: "releaseNotEditable"
189
+ };
190
+ let [o] = await e.query({
191
+ table: `${t.name}_drafts`,
192
+ predicate: d(f("documentId", r.documentId), f("site", n.site), f("environment", n.environment), f("locale", n.locale)),
193
+ order: [],
194
+ take: 1,
195
+ skip: void 0,
196
+ projection: void 0
197
+ });
198
+ if (o === void 0) return {
199
+ ok: !1,
200
+ reason: "notInRelease"
201
+ };
202
+ let [c] = await e.query({
203
+ table: s,
204
+ predicate: d(f("releaseId", r.releaseId), f("contentType", t.name), f("variantId", String(o.id)), f("action", "publish")),
205
+ order: [],
206
+ take: 1,
207
+ skip: void 0,
208
+ projection: void 0
209
+ });
210
+ if (c === void 0) return {
211
+ ok: !1,
212
+ reason: "notInRelease"
213
+ };
214
+ let l = F(t, o, r);
215
+ if (l !== null && !l.ok) return l;
216
+ let [p] = await e.query({
217
+ table: b,
218
+ predicate: d(f("contentType", t.name), f("documentId", r.documentId), f("status", "planned"), f("locale", n.locale), f("environment", n.environment)),
219
+ order: [],
220
+ take: 1,
221
+ skip: void 0,
222
+ projection: void 0
223
+ });
224
+ if (p !== void 0) return {
225
+ ok: !1,
226
+ reason: "alreadyPlanned"
227
+ };
228
+ let m = await e.insert(b, {
229
+ ...I(t, n, r, o.tenantId),
230
+ status: "planned",
231
+ startedAt: null,
232
+ revisionId: null,
233
+ startReleaseId: r.releaseId
234
+ });
235
+ return {
236
+ ok: !0,
237
+ id: String(m.id)
238
+ };
239
+ }, R = async (e, t, n) => {
240
+ let r = String(t.id), i = await e.query({
241
+ table: b,
242
+ predicate: d(f("startReleaseId", r), f("status", "planned")),
243
+ order: [],
244
+ take: void 0,
245
+ skip: void 0,
246
+ projection: void 0
247
+ });
248
+ for (let t of i) {
249
+ let r = [
250
+ f("site", t.site),
251
+ f("environment", t.environment),
252
+ f("locale", t.locale),
253
+ f("documentId", t.documentId)
254
+ ];
255
+ await e.updateMany(b, {
256
+ status: "stopped",
257
+ stoppedAt: n,
258
+ stopReason: "replaced"
259
+ }, { where: d(f("contentType", t.contentType), f("status", "running"), ...r) });
260
+ let [i] = await e.query({
261
+ table: `${String(t.contentType)}_published`,
262
+ predicate: d(...r),
263
+ order: [],
264
+ take: 1,
265
+ skip: void 0,
266
+ projection: void 0
267
+ });
268
+ await e.update(b, String(t.id), {
269
+ status: "running",
270
+ startedAt: n,
271
+ revisionId: T(i?.revisionId)
272
+ });
273
+ }
274
+ let a = T(t.rollbackOf);
275
+ a !== null && await e.updateMany(b, {
276
+ status: "stopped",
277
+ stoppedAt: n,
278
+ stopReason: "rolledBack"
279
+ }, { where: d(f("startReleaseId", a), f("status", "running")) });
280
+ }, z = async (e, t, n = /* @__PURE__ */ new Date()) => {
281
+ let [r] = await e.query({
282
+ table: b,
283
+ predicate: d(f("id", t), f("status", "running")),
284
+ order: [],
285
+ take: 1,
286
+ skip: void 0,
287
+ projection: void 0
288
+ });
289
+ return r !== void 0 && (await e.update(b, t, {
290
+ status: "stopped",
291
+ stoppedAt: n,
292
+ stopReason: "manual"
293
+ }), !0);
294
+ }, B = async (e, t, n, r) => {
295
+ let [i] = await e.query({
296
+ table: b,
297
+ predicate: d(f("contentType", t.name), f("documentId", r), f("status", "running"), f("site", n.site), f("environment", n.environment), f("locale", n.locale)),
298
+ order: [],
299
+ take: 1,
300
+ skip: void 0,
301
+ projection: void 0
302
+ });
303
+ return i === void 0 ? null : E(i);
304
+ }, V = async (e, t) => {
305
+ let [n] = await e.query({
306
+ table: b,
307
+ predicate: f("id", t),
308
+ order: [],
309
+ take: 1,
310
+ skip: void 0,
311
+ projection: void 0
312
+ });
313
+ return n === void 0 ? null : E(n);
314
+ }, H = async (e) => (await e.query({
315
+ table: b,
316
+ predicate: void 0,
317
+ order: [{
318
+ column: "startedAt",
319
+ direction: "desc"
320
+ }],
321
+ take: 200,
322
+ skip: void 0,
323
+ projection: void 0
324
+ })).map(E), U = async (e, t, n, r, i = /* @__PURE__ */ new Date()) => {
325
+ if (t.status !== "running" || n === "") return !1;
326
+ let a = D(`${t.id}|${n}`).toString(36) + D(`${n}|${t.id}`).toString(36);
327
+ if (r === "conversion") {
328
+ let [n] = await e.query({
329
+ table: x,
330
+ predicate: d(f("experimentId", t.id), f("reader", a), f("kind", "exposure")),
331
+ order: [],
332
+ take: 1,
333
+ skip: void 0,
334
+ projection: void 0
335
+ });
336
+ if (n === void 0) return !1;
337
+ }
338
+ let [o] = await e.query({
339
+ table: b,
340
+ predicate: f("id", t.id),
341
+ order: [],
342
+ take: 1,
343
+ skip: void 0,
344
+ projection: void 0
345
+ }), s = o?.tenantId, [c] = o === void 0 ? [] : await e.query({
346
+ table: `${t.contentType}_published`,
347
+ predicate: d(f("documentId", t.documentId), f("site", String(o.site)), f("environment", String(o.environment)), f("locale", t.locale)),
348
+ order: [],
349
+ take: 1,
350
+ skip: void 0,
351
+ projection: void 0
352
+ });
353
+ return (await e.insertIgnoreWithOutcome(x, {
354
+ experimentId: t.id,
355
+ variant: O(t.id, n, t.share),
356
+ kind: r,
357
+ reader: a,
358
+ revisionId: T(c?.revisionId),
359
+ at: i,
360
+ ...s == null ? {} : { tenantId: s }
361
+ }, { conflictColumns: [
362
+ "experimentId",
363
+ "reader",
364
+ "kind"
365
+ ] })).outcome === "inserted";
366
+ }, W = 100, G = (e) => {
367
+ let t = 1 / (1 + .3275911 * Math.abs(e) / Math.SQRT2), n = 1 - ((((1.061405429 * t - 1.453152027) * t + 1.421413741) * t - .284496736) * t + .254829592) * t * Math.exp(-(e * e) / 2);
368
+ return e >= 0 ? (1 + n) / 2 : (1 - n) / 2;
369
+ }, K = async (e, t) => {
370
+ let n = await e.query({
371
+ table: x,
372
+ predicate: f("experimentId", t),
373
+ order: [],
374
+ take: void 0,
375
+ skip: void 0,
376
+ projection: void 0,
377
+ groupBy: ["variant", "kind"],
378
+ aggregations: [
379
+ {
380
+ op: "column",
381
+ column: "variant",
382
+ alias: "variant"
383
+ },
384
+ {
385
+ op: "column",
386
+ column: "kind",
387
+ alias: "kind"
388
+ },
389
+ {
390
+ op: "count",
391
+ alias: "n"
392
+ }
393
+ ]
394
+ }), r = (e, t) => Number(n.find((n) => n.variant === e && n.kind === t)?.n ?? 0), i = (e) => {
395
+ let t = r(e, "exposure"), n = r(e, "conversion");
396
+ return {
397
+ readers: t,
398
+ conversions: n,
399
+ rate: t === 0 ? 0 : n / t
400
+ };
401
+ }, a = i("A"), o = i("B"), [s] = await e.query({
402
+ table: b,
403
+ predicate: f("id", t),
404
+ order: [],
405
+ take: 1,
406
+ skip: void 0,
407
+ projection: void 0
408
+ }), c = typeof s?.guardrailMaxDrop == "number" ? s.guardrailMaxDrop : null, l = c !== null && a.readers >= 100 && o.readers >= 100 && (a.rate - o.rate) * 100 > c, u = null;
409
+ if (a.readers > 0 && o.readers > 0) {
410
+ let e = (a.conversions + o.conversions) / (a.readers + o.readers), t = Math.sqrt(e * (1 - e) * (1 / a.readers + 1 / o.readers));
411
+ u = t === 0 ? 1 : 2 * (1 - G(Math.abs(o.rate - a.rate) / t));
412
+ }
413
+ return {
414
+ A: a,
415
+ B: o,
416
+ lift: a.rate === 0 ? null : (o.rate - a.rate) / a.rate,
417
+ pValue: u,
418
+ conclusive: a.readers >= 100 && o.readers >= 100 && u !== null && u < .05,
419
+ guardrail: {
420
+ maxDrop: c,
421
+ breached: l
422
+ }
423
+ };
424
+ }, q = async (e, t, n, r = /* @__PURE__ */ new Date()) => {
425
+ let [i] = await e.query({
426
+ table: b,
427
+ predicate: f("id", n),
428
+ order: [],
429
+ take: 1,
430
+ skip: void 0,
431
+ projection: void 0
432
+ });
433
+ if (i === void 0 || i.contentType !== t.name) return {
434
+ ok: !1,
435
+ reason: "notFound"
436
+ };
437
+ let a = E(i);
438
+ if (a.adoptedReleaseId !== null) return {
439
+ ok: !1,
440
+ reason: "alreadyAdopted"
441
+ };
442
+ let s = {
443
+ site: String(i.site),
444
+ environment: String(i.environment),
445
+ locale: a.locale
446
+ }, [u] = await e.query({
447
+ table: `${t.name}_drafts`,
448
+ predicate: d(f("documentId", a.documentId), f("site", s.site), f("environment", s.environment), f("locale", s.locale)),
449
+ order: [],
450
+ take: 1,
451
+ skip: void 0,
452
+ projection: void 0
453
+ });
454
+ if (u === void 0) return {
455
+ ok: !1,
456
+ reason: "noDraft"
457
+ };
458
+ a.status === "running" && await z(e, n, r);
459
+ let p = await o(e, t, { ...A(u, a, "B") }, s, { expectedRevision: String(u.revisionId) }), m = await l(e, {
460
+ name: `Adopt B: ${a.name}`.slice(0, 120),
461
+ site: s.site,
462
+ environment: s.environment
463
+ }), h = String(m.id), g = String(p.revisionId);
464
+ return await c(e, h, {
465
+ type: t,
466
+ id: String(p.id),
467
+ locale: s.locale,
468
+ action: "publish",
469
+ revisionId: g
470
+ }), await e.update(b, n, {
471
+ adoptedReleaseId: h,
472
+ adoptedRevisionId: g
473
+ }), {
474
+ ok: !0,
475
+ releaseId: h,
476
+ revisionId: g
477
+ };
478
+ }, J = async (e, t) => {
479
+ let n = await V(e, t);
480
+ if (n === null) return null;
481
+ let r = (await e.query({
482
+ table: x,
483
+ predicate: d(f("experimentId", t), f("kind", "exposure")),
484
+ order: [],
485
+ take: void 0,
486
+ skip: void 0,
487
+ projection: void 0,
488
+ groupBy: ["revisionId", "variant"],
489
+ aggregations: [
490
+ {
491
+ op: "column",
492
+ column: "revisionId",
493
+ alias: "revisionId"
494
+ },
495
+ {
496
+ op: "column",
497
+ column: "variant",
498
+ alias: "variant"
499
+ },
500
+ {
501
+ op: "count",
502
+ alias: "n"
503
+ }
504
+ ]
505
+ })).map((e) => ({
506
+ revisionId: T(e.revisionId),
507
+ variant: e.variant === "B" ? "B" : "A",
508
+ readers: Number(e.n)
509
+ })).sort((e, t) => String(e.revisionId).localeCompare(String(t.revisionId)) || e.variant.localeCompare(t.variant)), i = n.adoptedReleaseId === null || n.adoptedRevisionId === null ? null : {
510
+ releaseId: n.adoptedReleaseId,
511
+ revisionId: n.adoptedRevisionId,
512
+ releaseStatus: await u(e, n.adoptedReleaseId) ?? "gone"
513
+ };
514
+ return {
515
+ startedOn: n.revisionId,
516
+ overrides: n.overrides,
517
+ delivered: r,
518
+ adopted: i
519
+ };
520
+ }, Y = [
521
+ r,
522
+ t,
523
+ n,
524
+ a,
525
+ i
526
+ ], X = (...t) => e(() => V(...t)), Z = (...t) => e(() => K(...t)), Q = (...t) => e(() => H(...t)), $ = (...t) => e(() => U(...t)), ee = (...t) => e(() => B(...t)), te = (...t) => e(() => P(...t)), ne = (...t) => e(() => z(...t)), re = (...t) => e(() => q(...t), ...Y), ie = (...t) => e(() => L(...t)), ae = (...t) => e(() => J(...t));
527
+ //#endregion
528
+ export { b as CMS_EXPERIMENTS_TABLE, x as CMS_EXPERIMENT_EVENTS_TABLE, W as MIN_READERS, q as adoptWinner, re as adoptWinnerEffect, A as applyVariant, O as assignVariant, C as cmsExperimentEventsTable, S as cmsExperimentsTable, V as experimentById, X as experimentByIdEffect, j as experimentFields, J as experimentLineage, ae as experimentLineageEffect, M as experimentOverrideKeys, R as experimentReleaseHook, K as experimentResults, Z as experimentResultsEffect, H as listExperiments, Q as listExperimentsEffect, L as planExperiment, ie as planExperimentEffect, U as recordExperimentEvent, $ as recordExperimentEventEffect, B as runningExperiment, ee as runningExperimentEffect, P as startExperiment, te as startExperimentEffect, z as stopExperiment, ne as stopExperimentEffect };
@@ -0,0 +1,28 @@
1
+ //#region src/exposure.ts
2
+ var e = (e) => Array.isArray(e) ? e.filter((e) => typeof e == "string") : [], t = (t) => {
3
+ let n = new Map(t.ceiling.map((e) => [e, {
4
+ tool: e,
5
+ state: t.defaults.includes(e) ? "on" : "off",
6
+ decidedAt: null
7
+ }]));
8
+ t.chain.forEach((t, r) => {
9
+ let i = (e, t) => {
10
+ let i = n.get(e);
11
+ i !== void 0 && i.state !== "locked" && n.set(e, {
12
+ tool: e,
13
+ state: t,
14
+ decidedAt: r
15
+ });
16
+ };
17
+ for (let n of e(t.locked)) i(n, "locked");
18
+ for (let n of e(t.off)) i(n, "off");
19
+ for (let n of e(t.on)) i(n, "on");
20
+ });
21
+ let r = t.ceiling.map((e) => n.get(e));
22
+ return {
23
+ tools: r.filter((e) => e.state === "on").map((e) => e.tool),
24
+ explained: r
25
+ };
26
+ };
27
+ //#endregion
28
+ export { t as effectiveExposure };
@@ -0,0 +1,81 @@
1
+ import { Schema as e } from "effect";
2
+ //#region src/extensionManifest.ts
3
+ var t = [
4
+ "dashboard",
5
+ "sidebar",
6
+ "fieldWidget",
7
+ "entryTab",
8
+ "releaseCheck",
9
+ "assetAction",
10
+ "settings"
11
+ ], n = (e, t) => {
12
+ let n = new Map((e.settings ?? []).map((e) => [e.key, e])), r = [];
13
+ for (let [i, a] of Object.entries(t)) {
14
+ let t = n.get(i);
15
+ t === void 0 ? r.push(`"${i}" is not a setting of ${e.id}`) : t.kind === "number" ? typeof a != "number" || !Number.isFinite(a) ? r.push(`"${i}" is a number`) : (t.min !== void 0 && a < t.min || t.max !== void 0 && a > t.max) && r.push(`"${i}" is between ${t.min ?? "…"} and ${t.max ?? "…"}`) : t.kind === "boolean" ? typeof a != "boolean" && r.push(`"${i}" is true or false`) : (typeof a != "string" || !t.options.includes(a)) && r.push(`"${i}" is one of ${t.options.join(", ")}`);
16
+ }
17
+ return r;
18
+ }, r = (e, t) => Object.fromEntries((e.settings ?? []).map((r) => {
19
+ let i = t[r.key];
20
+ return [r.key, n(e, { [r.key]: i }).length === 0 && i !== void 0 ? i : r.default];
21
+ })), i = /* @__PURE__ */ new Set(["content:read", "content:write"]), a = /^(?=.{1,253}$)([a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z]{2,63}$/, o = /^[A-Z][A-Z0-9_]{0,63}$/, s = /^[a-z][a-z0-9-]{0,62}$/, c = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/, l = (e) => i.has(e) || e.startsWith("egress:") && a.test(e.slice(7)) || e.startsWith("secret:") && o.test(e.slice(7)), u = (e) => {
22
+ let r = [];
23
+ s.test(e.id) || r.push(`id "${e.id}": lowercase letters, digits and dashes, starting with a letter`), e.name.trim() === "" && r.push("name is empty"), e.publisher.trim() === "" && r.push("publisher is empty"), c.test(e.version) || r.push(`version "${e.version}": major.minor.patch`);
24
+ let i = /* @__PURE__ */ new Set();
25
+ for (let t of e.capabilities) l(t) ? i.has(t) && r.push(`capability "${t}" is listed twice`) : r.push(`capability "${t}" is not one an extension can ask for`), i.add(t);
26
+ for (let n of e.slots) t.includes(n) || r.push(`slot "${n}" is not a place in the editor`);
27
+ let a = e.slots.includes("fieldWidget");
28
+ a && (e.fields ?? []).length === 0 && r.push("a field widget names the fields it shows beside"), !a && e.fields !== void 0 && r.push("fields belong to the fieldWidget slot");
29
+ for (let t of e.fields ?? []) /^[A-Za-z][A-Za-z0-9]*$/.test(t) || r.push(`field "${t}" is not a field name`);
30
+ let o = e.slots.includes("settings");
31
+ o && (e.settings ?? []).length === 0 && r.push("the settings slot lists its settings"), !o && e.settings !== void 0 && r.push("settings belong to the settings slot");
32
+ let u = /* @__PURE__ */ new Set();
33
+ for (let t of e.settings ?? []) /^[A-Za-z][A-Za-z0-9]*$/.test(t.key) || r.push(`setting "${t.key}" is not a key`), u.has(t.key) && r.push(`setting "${t.key}" is listed twice`), u.add(t.key), n({
34
+ ...e,
35
+ settings: [t]
36
+ }, { [t.key]: t.default }).length > 0 && r.push(`setting "${t.key}": its default is not a value it allows`);
37
+ return r;
38
+ }, d = (e, t) => {
39
+ let n = e.split(".").map(Number), r = t.split(".").map(Number);
40
+ for (let e = 0; e < 3; e++) {
41
+ let t = (n[e] ?? 0) - (r[e] ?? 0);
42
+ if (t !== 0) return t;
43
+ }
44
+ return 0;
45
+ }, f = (e, t) => t.filter((t) => !e.includes(t)), p = class extends e.TaggedError()("ExtensionAccessDenied", {
46
+ extensionId: e.String,
47
+ capability: e.String
48
+ }) {}, m = e.Struct({
49
+ id: e.String,
50
+ name: e.String,
51
+ version: e.String,
52
+ publisher: e.String,
53
+ capabilities: e.Array(e.String),
54
+ slots: e.Array(e.String),
55
+ fields: e.optional(e.Array(e.String)),
56
+ settings: e.optional(e.Array(e.Union([
57
+ e.Struct({
58
+ key: e.String,
59
+ label: e.String,
60
+ kind: e.Literal("number"),
61
+ default: e.Number,
62
+ min: e.optional(e.Number),
63
+ max: e.optional(e.Number)
64
+ }),
65
+ e.Struct({
66
+ key: e.String,
67
+ label: e.String,
68
+ kind: e.Literal("boolean"),
69
+ default: e.Boolean
70
+ }),
71
+ e.Struct({
72
+ key: e.String,
73
+ label: e.String,
74
+ kind: e.Literal("choice"),
75
+ default: e.String,
76
+ options: e.Array(e.String)
77
+ })
78
+ ])))
79
+ });
80
+ //#endregion
81
+ export { t as EXTENSION_SLOTS, p as ExtensionAccessDenied, m as ExtensionManifestSchema, d as compareVersions, l as isExtensionCapability, u as manifestProblems, f as newCapabilities, n as settingsProblems, r as settingsWithDefaults };