@voltro/cms 0.81.0 → 0.83.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,10 +1,171 @@
1
1
  import { DataStore } from '@voltro/database';
2
- import { Effect } from 'effect';
2
+ import { Effect } from 'effect/Effect';
3
+ import { Effect as Effect_2 } from 'effect';
3
4
  import { ReactNode } from 'react';
4
5
  import { Row } from '@voltro/database';
5
6
  import { Schema as Schema_2 } from 'effect';
6
7
  import { TableLike } from '@voltro/database';
7
8
 
9
+ /** Effect form of {@link addRedirect}. */
10
+ export declare const addRedirect: (...args: Parameters<typeof addRedirect_2>) => Effect<void, never, never>;
11
+
12
+ /**
13
+ * Point a former address at a document — an address from before an import, a
14
+ * vanity path. Replaces an earlier redirect from the same path. A live page at
15
+ * `fromPath` still wins over it (`cms.route` tries the tree first). In the
16
+ * caller's transaction.
17
+ */
18
+ declare const addRedirect_2: (tx: DataStore, type: ContentType, scope: CmsScope, fromPath: string, documentId: string, tenantId?: unknown) => Promise<void>;
19
+
20
+ /** Effect form of {@link addToRelease}. */
21
+ export declare const addToRelease: (...args: Parameters<typeof addToRelease_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound | ReleaseNotEditable, never>;
22
+
23
+ /**
24
+ * Put one variant into a draft release: `publish` pins a revision (default:
25
+ * the variant's current revision), `unpublish` takes it down. A variant is in
26
+ * a release at most once — adding it again replaces its entry. Throws
27
+ * `ReleaseNotEditable` unless the release is still a draft, and
28
+ * `ContentNotFound` when the variant is not the caller's.
29
+ */
30
+ declare const addToRelease_2: (store: DataStore, releaseId: string, item: {
31
+ readonly type: ContentType;
32
+ readonly id: string;
33
+ readonly locale: string;
34
+ readonly action?: "publish" | "unpublish";
35
+ readonly revisionId?: string;
36
+ }) => Promise<Row>;
37
+
38
+ /** Effect form of {@link adoptWinner}. */
39
+ export declare const adoptWinner: (...args: Parameters<typeof adoptWinner_2>) => Effect<AdoptWinnerResult, ContentValidationFailed | ContentNotFound | ContentIdConflict | RevisionMismatch | ReleaseNotEditable, never>;
40
+
41
+ /**
42
+ * Take version B live the way every change goes live: stop the experiment
43
+ * (if it still runs), save B's text over the page's draft as a new draft
44
+ * revision, and pin that revision in a new draft release named after the
45
+ * experiment. Nothing is published here — the release is, by whoever may,
46
+ * through the review gate, a schedule, or by hand; and it rolls back like any
47
+ * other. Runs in the caller's transaction.
48
+ */
49
+ declare const adoptWinner_2: (tx: DataStore, type: ContentType, experimentId: string, now?: Date) => Promise<AdoptWinnerResult>;
50
+
51
+ export declare type AdoptWinnerResult = {
52
+ readonly ok: true;
53
+ readonly releaseId: string;
54
+ readonly revisionId: string;
55
+ } | {
56
+ readonly ok: false;
57
+ readonly reason: 'notFound' | 'alreadyAdopted' | 'noDraft';
58
+ };
59
+
60
+ /** Effect form of {@link advanceSeries}. */
61
+ export declare const advanceSeries: (...args: Parameters<typeof advanceSeries_2>) => Effect<readonly string[], ContentValidationFailed | ContentNotFound, never>;
62
+
63
+ /**
64
+ * Arm the next occurrence of every running series of `type` whose draft has
65
+ * nothing pending any more (the armed occurrence went live and came down), and
66
+ * end the series after its last. Returns the draft ids that were armed. Run it
67
+ * after `publishDue` and `unpublishDue` in the same schedule; a store outside a
68
+ * transaction sweeps every tenant.
69
+ */
70
+ declare const advanceSeries_2: (store: DataStore, type: ContentType, now?: Date) => Promise<ReadonlyArray<string>>;
71
+
72
+ export declare const AI_OUTCOMES: readonly ["suggested", "failed", "applied", "discarded"];
73
+
74
+ /** Effect form of {@link aiBudgetLeft}. */
75
+ export declare const aiBudgetLeft: (...args: Parameters<typeof aiBudgetLeft_2>) => Effect<number | null, never, never>;
76
+
77
+ /** What is left of the workspace's monthly budget: a number of tokens, or null (no limit). */
78
+ declare const aiBudgetLeft_2: (store: DataStore, tenantId: string, now?: Date) => Promise<number | null>;
79
+
80
+ export declare interface AiOperation {
81
+ readonly id: string;
82
+ readonly operation: string;
83
+ readonly version: string;
84
+ readonly provider: string;
85
+ readonly model: string;
86
+ readonly field: string | null;
87
+ readonly revisionId: string | null;
88
+ readonly outcome: AiOutcome;
89
+ readonly inputTokens: number | null;
90
+ readonly outputTokens: number | null;
91
+ readonly at: number;
92
+ }
93
+
94
+ export declare interface AiOperationInput {
95
+ readonly operation: string;
96
+ readonly version: string;
97
+ readonly provider: string;
98
+ readonly model: string;
99
+ readonly contentType: string;
100
+ readonly variantId: string;
101
+ readonly revisionId?: string | null;
102
+ readonly field?: string | null;
103
+ readonly prompt: string;
104
+ readonly usage?: {
105
+ readonly inputTokens?: number;
106
+ readonly outputTokens?: number;
107
+ };
108
+ readonly outcome: 'suggested' | 'failed';
109
+ readonly error?: string | null;
110
+ readonly actor?: string | null;
111
+ }
112
+
113
+ /** Effect form of {@link aiOperationsFor}. */
114
+ export declare const aiOperationsFor: (...args: Parameters<typeof aiOperationsFor_2>) => Effect<readonly AiOperation[], never, never>;
115
+
116
+ /** A variant's AI operations, newest first. */
117
+ declare const aiOperationsFor_2: (store: DataStore, contentType: string, variantId: string) => Promise<ReadonlyArray<AiOperation>>;
118
+
119
+ export declare type AiOutcome = (typeof AI_OUTCOMES)[number];
120
+
121
+ export declare interface AiSettings {
122
+ /** Null: the deployment's provider and model (only a budget is set). */
123
+ readonly provider: string | null;
124
+ readonly model: string | null;
125
+ /** The workspace's own key — for the server's call only. */
126
+ readonly apiKey: string | null;
127
+ /** Tokens per calendar month (UTC), or null: no limit. */
128
+ readonly monthlyTokens: number | null;
129
+ }
130
+
131
+ /** Effect form of {@link aiSettings}. */
132
+ export declare const aiSettings: (...args: Parameters<typeof aiSettings_2>) => Effect<AiSettings | null, never, never>;
133
+
134
+ /** How the workspace reaches a model, or null: the deployment's default. */
135
+ declare const aiSettings_2: (store: DataStore, tenantId: string) => Promise<AiSettings | null>;
136
+
137
+ /** Effect form of {@link aiTokensUsed}. */
138
+ export declare const aiTokensUsed: (...args: Parameters<typeof aiTokensUsed_2>) => Effect<number, never, never>;
139
+
140
+ /** Tokens (in + out) the workspace's AI calls used since `since` (default: this month). */
141
+ declare const aiTokensUsed_2: (store: DataStore, tenantId: string, since?: Date) => Promise<number>;
142
+
143
+ /** A document's address in every language it has its own variant in. */
144
+ export declare const alternatesOf: (trees: ReadonlyArray<LocalizedTree>, documentId: string) => ReadonlyArray<PageAlternate>;
145
+
146
+ /** Effect form of {@link applyBlueprint}. */
147
+ export declare const applyBlueprint: (...args: Parameters<typeof applyBlueprint_2>) => Effect<BlueprintPlan, ContentValidationFailed | ContentNotFound | ContentIdConflict | RevisionMismatch | ReviewRequired | ReferenceUnavailable | BlueprintInvalid, never>;
148
+
149
+ /**
150
+ * Provision `blueprint` into `target`: every step the plan calls `create` is
151
+ * saved (and published unless the entry says otherwise or its type needs a
152
+ * review); present documents stay exactly as they are. Running it again
153
+ * creates nothing. Runs in the caller's transaction — all of it or none;
154
+ * a save's `ContentValidationFailed` or a publish's `ReferenceUnavailable`
155
+ * (a referenced document that is not live) aborts it.
156
+ */
157
+ declare const applyBlueprint_2: (tx: DataStore, types: ReadonlyArray<ContentType>, blueprint: Blueprint, target: BlueprintTarget) => Promise<BlueprintPlan>;
158
+
159
+ /** Effect form of {@link applyBlueprintTeam}. */
160
+ export declare const applyBlueprintTeam: (...args: Parameters<typeof applyBlueprintTeam_2>) => Effect<TeamPlan, never, never>;
161
+
162
+ /**
163
+ * Provision the team, in the caller's transaction: a default role only where
164
+ * the workspace has none, an invitation only for an address not invited yet —
165
+ * running it again changes nothing, and nothing an admin changed is undone.
166
+ */
167
+ declare const applyBlueprintTeam_2: (tx: DataStore, tenantId: string, team: BlueprintTeam) => Promise<TeamPlan>;
168
+
8
169
  /**
9
170
  * Compute every `derivedFrom` field from its source value. Returns a NEW
10
171
  * row — the input is not mutated. A caller-provided value for a derived
@@ -13,24 +174,359 @@ import { TableLike } from '@voltro/database';
13
174
  * declaration order against the progressively-updated row, so a derived
14
175
  * field may source another, earlier-declared derived field.
15
176
  */
16
- export declare const applyDerivations: (type: Pick<ContentType, "fields" | "derivedFields">, row: Readonly<Record<string, unknown>>) => Record<string, unknown>;
177
+ export declare const applyDerivations: (type: Pick<ContentType, "fields" | "derivedFields"> & Partial<Pick<ContentType, "taxonomy">>, row: Readonly<Record<string, unknown>>) => Record<string, unknown>;
178
+
179
+ /**
180
+ * The source values with each unit's target in place — what a translation
181
+ * draft saves. A unit without a target keeps the source text; an id that
182
+ * names no text in the source is ignored (see `missing` from `matchUnits`).
183
+ */
184
+ export declare const applyTranslation: (fields: Readonly<Record<string, FieldSchema>>, source: Readonly<Record<string, unknown>>, units: ReadonlyArray<TranslationUnit>) => Record<string, unknown>;
185
+
186
+ /** The values a reader of `variant` sees: version B's text over the published values. */
187
+ export declare const applyVariant: (values: Readonly<Record<string, unknown>>, experiment: Pick<Experiment, "overrides">, variant: Variant) => Readonly<Record<string, unknown>>;
188
+
189
+ /** Effect form of {@link approveReview}. */
190
+ export declare const approveReview: (...args: Parameters<typeof approveReview_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound | RevisionMismatch | ReviewStepRefused, never>;
17
191
 
18
192
  /**
19
- * Archive a content row: set `status: 'archived'` on the draft AND the
20
- * published copy (whichever exist). Archived rows stay in their tables
21
- * but disappear from the read surface (`ctx.cms` excludes `archived`).
22
- * Atomic per row. Throws `ContentNotFound` when the id exists in neither
23
- * table within the caller's scope.
193
+ * Approve the revision in review. Throws `RevisionMismatch` when the draft
194
+ * moved on since the reviewer looked, `ReviewStepRefused` when nothing is in
195
+ * review for that revision, the approver asked for it themselves, or existing
196
+ * unsequenced history has ambiguous timestamps. Use the caller's transaction.
24
197
  */
25
- export declare const archive: (store: DataStore, type: ContentType, id: string) => Promise<void>;
198
+ declare const approveReview_2: (store: DataStore, type: ContentType, variantId: string, scope: CmsScope, options: DecideOptions) => Promise<Row>;
26
199
 
27
200
  /** Effect-native `archive` (see {@link saveDraftEffect}). */
28
- export declare const archiveEffect: (store: DataStore, type: ContentType, id: string) => Effect.Effect<void, ContentNotFound>;
201
+ export declare const archive: (store: DataStore, type: ContentType, id: string, scope: CmsScope) => Effect_2.Effect<void, ContentNotFound>;
202
+
203
+ /** Effect form of {@link assertApproved}. */
204
+ export declare const assertApproved: (...args: Parameters<typeof assertApproved_2>) => Effect<void, ReviewRequired, never>;
205
+
206
+ /**
207
+ * The publish gate: for a type that requires review, `revisionId` must carry
208
+ * an approval. Called by `publishRevision` — so single publishes, releases,
209
+ * rollbacks and scheduled publishing all pass the same gate.
210
+ */
211
+ declare const assertApproved_2: (store: DataStore, type: ContentType, variantId: string, scope: CmsScope, revisionId: string) => Promise<void>;
212
+
213
+ /** Effect form of {@link assertReferencesAvailable}. */
214
+ export declare const assertReferencesAvailable: (...args: Parameters<typeof assertReferencesAvailable_2>) => Effect<void, ReferenceUnavailable, never>;
215
+
216
+ /**
217
+ * The publish gate: a revision whose values reference an unavailable
218
+ * document is refused with `ReferenceUnavailable`, naming each one.
219
+ */
220
+ declare const assertReferencesAvailable_2: (tx: DataStore, type: ContentType, variantId: string, values: Readonly<Record<string, unknown>>, scope: CmsScope, now?: Date) => Promise<void>;
221
+
222
+ /** The version a reader is shown: the same reader, the same version, every time. */
223
+ export declare const assignVariant: (experimentId: string, readerId: string, share: number) => Variant;
224
+
225
+ export declare interface Audience {
226
+ readonly id: string;
227
+ /** Raise it when the rule changes meaning; a variant records the version it was written for. */
228
+ readonly version: number;
229
+ readonly displayName: string;
230
+ readonly rule: AudienceRule;
231
+ }
232
+
233
+ /** A rule: every condition given must hold. */
234
+ export declare interface AudienceRule {
235
+ /** The preferred language starts with one of these (`de` matches `de-AT`). */
236
+ readonly languages?: ReadonlyArray<string>;
237
+ /** The request comes from one of these countries. */
238
+ readonly countries?: ReadonlyArray<string>;
239
+ /** The reader has (true) or has not (false) been here before. */
240
+ readonly returning?: boolean;
241
+ }
242
+
243
+ /** What the server knows about the request, declared — nothing else is consulted. */
244
+ export declare interface AudienceSignals {
245
+ /** Accept-Language, in order of preference (`de-AT`, `de`, `en`). */
246
+ readonly languages?: ReadonlyArray<string>;
247
+ /** ISO 3166-1 alpha-2, from a proxy the app trusts to set it. */
248
+ readonly country?: string | null;
249
+ /** The reader allowed being recognised, and was here before. */
250
+ readonly returning?: boolean;
251
+ }
252
+
253
+ /** Which fields carry a type's availability. Validated by `defineContentType`. */
254
+ export declare interface AvailabilityConfig {
255
+ /** A date or datetime field: usable up to (excluding) this moment. */
256
+ readonly until?: string;
257
+ /** A boolean field: `true` withdraws the document at once. */
258
+ readonly blocked?: string;
259
+ }
260
+
261
+ /** Effect form of {@link bindExtensionSecret}. */
262
+ export declare const bindExtensionSecret: (...args: Parameters<typeof bindExtensionSecret_2>) => Effect<SecretBinding, never, never>;
263
+
264
+ /**
265
+ * Set (or, with `value: null`, remove) the secret `name` for an extension.
266
+ * Only a secret its running or waiting version asks for (`secret:<name>`).
267
+ */
268
+ declare const bindExtensionSecret_2: (tx: DataStore, extensionId: string, name: string, value: string | null) => Promise<SecretBinding>;
269
+
270
+ export declare type BlockReason = 'notFound' | 'reviewRequired' | 'incomplete' | 'referenceUnavailable' | 'notPublished' | 'unknownType' | 'invalid' | 'revisionMoved';
271
+
272
+ export declare interface Blueprint {
273
+ readonly id: string;
274
+ readonly displayName: string;
275
+ /** The language `values` are written in. */
276
+ readonly locale: string;
277
+ readonly entries: ReadonlyArray<BlueprintEntry>;
278
+ /** The team the workspace starts with: the default role and people invited with a role (team.ts). */
279
+ readonly team?: BlueprintTeam;
280
+ }
281
+
282
+ /** One document a blueprint provisions. */
283
+ export declare interface BlueprintEntry {
284
+ /** Unique within the blueprint; another entry points at this one with `blueprintRef(key)`. */
285
+ readonly key: string;
286
+ /** The content type's name. */
287
+ readonly type: string;
288
+ /**
289
+ * The field that says the workspace already has this document (e.g. `slug`),
290
+ * compared after derivations. Omitted: any document of the type counts — for
291
+ * a type a workspace holds one of, like its site document.
292
+ */
293
+ readonly match?: string;
294
+ /** A template of the type the document is built from; `values` go over it. */
295
+ readonly template?: string;
296
+ /** Field values in the blueprint's language. `blueprintRef(key)` anywhere stands for that entry's document id. */
297
+ readonly values: Readonly<Record<string, unknown>>;
298
+ /** The same document in further languages: the values that differ from `values`. */
299
+ readonly translations?: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
300
+ /** Publish what is created (default true). A type that needs review stays a draft. */
301
+ readonly publish?: boolean;
302
+ }
303
+
304
+ /** The declaration or its target does not fit: an unknown key, type, field, template or a cycle. */
305
+ export declare class BlueprintInvalid extends Error {
306
+ readonly reason: string;
307
+ readonly _tag = "BlueprintInvalid";
308
+ constructor(reason: string);
309
+ }
310
+
311
+ export declare interface BlueprintPlan {
312
+ readonly blueprint: string;
313
+ readonly steps: ReadonlyArray<BlueprintStep>;
314
+ /** New documents a create would start (translations of them not counted). */
315
+ readonly documents: number;
316
+ }
317
+
318
+ /** A value that stands for another entry's document id. */
319
+ export declare const blueprintRef: (key: string) => {
320
+ readonly $entry: string;
321
+ };
322
+
323
+ /** One language variant of one entry. */
324
+ export declare interface BlueprintStep {
325
+ readonly key: string;
326
+ readonly type: string;
327
+ readonly locale: string;
328
+ /** What the step is about: the document's title (the one there already, for a present step), else its `match` value, else the key. */
329
+ readonly label: string;
330
+ readonly action: 'create' | 'present';
331
+ /** The document: the one there already, or (after applying) the one created. Null for a planned create. */
332
+ readonly documentId: string | null;
333
+ /** Its variant in `locale`, likewise. */
334
+ readonly variantId: string | null;
335
+ /** For a create: `live` is published, `draft` is not meant to be, `review` needs an approval first. */
336
+ readonly outcome: 'live' | 'draft' | 'review' | null;
337
+ }
338
+
339
+ /** Where a blueprint is provisioned: a site and environment of the caller's tenant. */
340
+ export declare interface BlueprintTarget {
341
+ readonly site: string;
342
+ readonly environment: string;
343
+ }
344
+
345
+ /** A blueprint's team: the default role and the people invited with a role. */
346
+ export declare interface BlueprintTeam {
347
+ readonly defaultRole?: string;
348
+ readonly members?: ReadonlyArray<{
349
+ readonly email: string;
350
+ readonly role: string;
351
+ }>;
352
+ /** Content types (with `review.required: 'workspace'`) whose publishing needs a review in the workspace. */
353
+ readonly reviewRequired?: ReadonlyArray<string>;
354
+ }
355
+
356
+ /**
357
+ * Arrange one variant per document into a tree. `entries` holds at most one
358
+ * entry per `documentId` (the first one wins). A node without a segment is
359
+ * not routable and counts as an orphan, and so does everything below it.
360
+ */
361
+ export declare const buildTree: (entries: ReadonlyArray<TreeEntry>, config: TreeConfig) => CmsTree;
362
+
363
+ /** What to do to every item. */
364
+ export declare type BulkAction = {
365
+ readonly kind: 'publish';
366
+ } | {
367
+ readonly kind: 'unpublish';
368
+ } | {
369
+ readonly kind: 'setOwner';
370
+ readonly owner: string | null;
371
+ }
372
+ /** Save a new draft revision of each item with one field changed (null
373
+ * clears it) — a field a person edits: not derived, not rich text or components. */
374
+ | {
375
+ readonly kind: 'setField';
376
+ readonly field: string;
377
+ readonly value: unknown;
378
+ };
379
+
380
+ /** One locale variant (a draft id) of a document. */
381
+ export declare interface BulkItem {
382
+ readonly type: string;
383
+ readonly id: string;
384
+ readonly locale: string;
385
+ }
386
+
387
+ export declare interface BulkResult extends BulkItem {
388
+ readonly title: string;
389
+ readonly outcome: 'done' | 'unchanged' | 'failed';
390
+ readonly reason: BlockReason | 'failed' | null;
391
+ readonly detail: ReadonlyArray<string>;
392
+ }
393
+
394
+ /** Effect form of {@link cancelSeries}. */
395
+ export declare const cancelSeries: (...args: Parameters<typeof cancelSeries_2>) => Effect<boolean, ContentValidationFailed | ContentNotFound, never>;
396
+
397
+ /** End a draft's series and clear what it armed. True when there was one. In the caller's transaction. */
398
+ declare const cancelSeries_2: (tx: DataStore, type: ContentType, draftId: string) => Promise<boolean>;
399
+
400
+ /** The declared fields whose values differ between `before` and `after`, in declaration order. */
401
+ export declare const changedFields: (fields: Readonly<Record<string, unknown>>, before: Readonly<Record<string, unknown>>, after: Readonly<Record<string, unknown>>) => ReadonlyArray<string>;
402
+
403
+ export declare interface ChangeEntry {
404
+ readonly id: string;
405
+ /** Epoch milliseconds. */
406
+ readonly at: number;
407
+ readonly locale: string;
408
+ readonly contentType: string;
409
+ readonly documentId: string;
410
+ readonly variantId: string;
411
+ readonly action: 'published' | 'unpublished';
412
+ readonly revision: number | null;
413
+ readonly releaseId: string | null;
414
+ }
415
+
416
+ export declare interface ChangeOrigin {
417
+ /** The release applying this change. */
418
+ readonly releaseId?: string;
419
+ }
420
+
421
+ /** Throws when a declaration cannot work: fields missing or of the wrong kind, a component the field does not allow. */
422
+ export declare const checkTemplates: (name: string, fields: Readonly<Record<string, FieldSchema>>, config: TemplatesConfig) => void;
423
+
424
+ export declare const CMS_AI_OPERATIONS_TABLE = "cms_ai_operations";
425
+
426
+ export declare const CMS_AI_SETTINGS_TABLE = "cms_ai_settings";
427
+
428
+ /** The system table holding the availability of published documents. */
429
+ export declare const CMS_AVAILABILITY_TABLE = "cms_availability";
430
+
431
+ export declare const CMS_CHANGES_TABLE = "cms_changes";
432
+
433
+ export declare const CMS_DRAFT_TEXTS_TABLE = "cms_draft_texts";
434
+
435
+ export declare const CMS_EXPERIMENT_EVENTS_TABLE = "cms_experiment_events";
436
+
437
+ export declare const CMS_EXPERIMENTS_TABLE = "cms_experiments";
438
+
439
+ export declare const CMS_EXTENSION_DATA_TABLE = "cms_extension_data";
440
+
441
+ export declare const CMS_EXTENSION_SECRETS_TABLE = "cms_extension_secrets";
442
+
443
+ export declare const CMS_EXTENSIONS_TABLE = "cms_extensions";
444
+
445
+ export declare const CMS_GLOSSARY_TABLE = "cms_glossary";
446
+
447
+ export declare const CMS_PATHS_TABLE = "cms_paths";
448
+
449
+ /** The system table holding preview shares. */
450
+ export declare const CMS_PREVIEW_SHARES_TABLE = "cms_preview_shares";
451
+
452
+ export declare const CMS_PUBLISH_SERIES_TABLE = "cms_publish_series";
453
+
454
+ export declare const CMS_QUALITY_EXCEPTIONS_TABLE = "cms_quality_exceptions";
455
+
456
+ export declare const CMS_REDIRECTS_TABLE = "cms_redirects";
457
+
458
+ /** The system table holding the reference edges of every published variant. */
459
+ export declare const CMS_REFERENCES_TABLE = "cms_references";
460
+
461
+ export declare const CMS_RELEASE_ITEMS_TABLE = "cms_release_items";
462
+
463
+ export declare const CMS_RELEASES_TABLE = "cms_releases";
464
+
465
+ /** The system table holding every review step. */
466
+ export declare const CMS_REVIEWS_TABLE = "cms_reviews";
467
+
468
+ /** The system table holding every saved revision of every content type. */
469
+ export declare const CMS_REVISIONS_TABLE = "cms_revisions";
470
+
471
+ /** The scope columns, in the order they lead every scoped key. */
472
+ export declare const CMS_SCOPE_COLUMNS: readonly ["site", "environment", "locale"];
473
+
474
+ export declare const CMS_SEARCH_TABLE = "cms_search";
475
+
476
+ export declare const CMS_STEWARDSHIP_TABLE = "cms_stewardship";
477
+
478
+ export declare const CMS_TEAM_INVITATIONS_TABLE = "cms_team_invitations";
479
+
480
+ export declare const CMS_TEAM_TABLE = "cms_team";
481
+
482
+ /** One AI call on a document, and what became of it. */
483
+ export declare const cmsAiOperationsTable: TableLike;
484
+
485
+ /** One row per workspace: how it reaches a model. */
486
+ export declare const cmsAiSettingsTable: TableLike;
29
487
 
30
488
  /** The CMS read surface attached to `ctx.cms` (and the standalone client). */
31
489
  export declare interface CmsApi {
32
490
  /** Open a query over a content type's PUBLISHED rows (archived excluded). */
33
491
  contentType(name: string): ContentQuery;
492
+ /**
493
+ * Find one published entry in the surface's locale, else along `fallback`
494
+ * (ADR-CMS-002). A key found in a fallback locale whose document DOES have a
495
+ * variant in the requested locale resolves to that variant — so the result
496
+ * may carry a different key value (its canonical address). Otherwise the
497
+ * fallback variant is returned with `fallback: true`. Null when nothing
498
+ * matches in any locale.
499
+ */
500
+ resolve(type: string, options: ResolveOptions): Promise<ResolvedEntry | null>;
501
+ /**
502
+ * The type's published documents as a tree (the type must declare
503
+ * `tree`), one variant per document: the surface's locale, else the first
504
+ * `fallback` locale that has one. Reads every published row of the type in
505
+ * those locales.
506
+ */
507
+ tree(type: string, options?: TreeOptions): Promise<CmsTree>;
508
+ /**
509
+ * Find the document at `path` (segments joined with `/`) in the tree. A
510
+ * path that only exists in a fallback locale's tree answers with the
511
+ * requested locale's node of the same document. A path no live page has
512
+ * but a published page had before it moved answers with that page at its
513
+ * current address (ADR-CMS-023). Null when none of these match.
514
+ */
515
+ route(type: string, path: string, options?: TreeOptions): Promise<RouteMatch | null>;
516
+ /**
517
+ * Whether `path` is GONE: no live page answers it ({@link CmsApi.route}
518
+ * finds nothing), but a published page had it — its address before it was
519
+ * taken down or archived, or a former address pointing at such a page — in
520
+ * the surface's locale or along `fallback`. A site answers it with 410
521
+ * rather than 404.
522
+ */
523
+ gone(type: string, path: string, options?: TreeOptions): Promise<boolean>;
524
+ /**
525
+ * Where a document is used by published content in the surface's site and
526
+ * environment, across locales (the `cms_references` edges publishing
527
+ * writes). A draft that references it is not a use until it is published.
528
+ */
529
+ usedBy(type: string, documentId: string): Promise<ReadonlyArray<ReferenceUse>>;
34
530
  /**
35
531
  * Resolve a single row honouring a preview token. With a valid token
36
532
  * for `{type, id}`, reads the DRAFT row; otherwise reads the published
@@ -40,13 +536,92 @@ export declare interface CmsApi {
40
536
  }
41
537
 
42
538
  /**
43
- * Build the `ctx.cms` surface over a request-scoped store. Attach the
44
- * result to your `AppContext` slot (or read it via `useCms(ctx)`).
539
+ * One row per published document of a type that declares `availability`.
540
+ * Register it in the app's `databaseHandle` when any type declares it.
45
541
  */
46
- export declare const cmsContext: (store: DataStore, types: ReadonlyArray<ContentType>, options?: {
47
- secret?: string;
542
+ export declare const cmsAvailabilityTable: TableLike;
543
+
544
+ export declare const cmsChangesTable: TableLike;
545
+
546
+ /**
547
+ * Build the `ctx.cms` surface over a request-scoped store, confined to one
548
+ * `scope` (site, environment, locale). Attach the result to your
549
+ * `AppContext` slot (or read it via `useCms(ctx)`).
550
+ */
551
+ export declare const cmsContext: (store: DataStore, types: ReadonlyArray<ContentType>, options: {
552
+ readonly scope: CmsScope;
553
+ readonly secret?: string;
48
554
  }) => CmsApi;
49
555
 
556
+ /** One text field of one draft (a document in one language), as a CRDT text. */
557
+ export declare const cmsDraftTextsTable: TableLike;
558
+
559
+ export declare const cmsExperimentEventsTable: TableLike;
560
+
561
+ export declare const cmsExperimentsTable: TableLike;
562
+
563
+ /** An extension's own data, by key, in its namespace. */
564
+ export declare const cmsExtensionDataTable: TableLike;
565
+
566
+ export declare interface CmsExtensionManifest {
567
+ /** Lowercase letters, digits and dashes: `reading-time`. */
568
+ readonly id: string;
569
+ readonly name: string;
570
+ /** `major.minor.patch`. */
571
+ readonly version: string;
572
+ readonly publisher: string;
573
+ readonly capabilities: ReadonlyArray<ExtensionCapability>;
574
+ readonly slots: ReadonlyArray<ExtensionSlot>;
575
+ /** With the `fieldWidget` slot: the fields it shows beside (field names of the content types). */
576
+ readonly fields?: ReadonlyArray<string>;
577
+ /** What an admin can set for it (the `settings` slot): each setting's key, kind, bounds and default. */
578
+ readonly settings?: ReadonlyArray<ExtensionSetting>;
579
+ }
580
+
581
+ /** The secrets an admin bound for an extension: encrypted at rest, never sent to a client. */
582
+ export declare const cmsExtensionSecretsTable: TableLike;
583
+
584
+ /** One row per installed extension: its version, what it was granted, and a newer version waiting for consent. */
585
+ export declare const cmsExtensionsTable: TableLike;
586
+
587
+ /** One entry per workspace, term (lower case) and target language. */
588
+ export declare const cmsGlossaryTable: TableLike;
589
+
590
+ /** The address each published document of a tree type had at its last publish, per locale. */
591
+ export declare const cmsPathsTable: TableLike;
592
+
593
+ /**
594
+ * One preview share: which variant, which revision (null = always the
595
+ * latest), until when, and whether it was revoked. Register it in the app's
596
+ * `databaseHandle` beside `cmsRevisionsTable`.
597
+ */
598
+ export declare const cmsPreviewSharesTable: TableLike;
599
+
600
+ /** One repeating live window per draft: its rule, and the occurrence armed last (-1: none yet). */
601
+ export declare const cmsPublishSeriesTable: TableLike;
602
+
603
+ export declare const cmsQualityExceptionsTable: TableLike;
604
+
605
+ /** A former address and the document now answering it. */
606
+ export declare const cmsRedirectsTable: TableLike;
607
+
608
+ /**
609
+ * One row per reference a published variant makes: the source (type,
610
+ * document, variant, scope), where in its values the reference sits (`path`)
611
+ * and the target document. Tenant-scoped. Register it in the app's
612
+ * `databaseHandle` beside `cmsRevisionsTable`.
613
+ */
614
+ export declare const cmsReferencesTable: TableLike;
615
+
616
+ /** One variant in a release: publish its pinned revision, or unpublish it. */
617
+ export declare const cmsReleaseItemsTable: TableLike;
618
+
619
+ /**
620
+ * A named set of pinned revisions for ONE site and environment. Register it
621
+ * (with `cmsReleaseItemsTable`) in the app's `databaseHandle`.
622
+ */
623
+ export declare const cmsReleasesTable: TableLike;
624
+
50
625
  export declare interface CmsRestOptions {
51
626
  readonly cms: CmsApi;
52
627
  readonly types: ReadonlyArray<ContentType>;
@@ -80,8 +655,123 @@ export declare interface CmsRestResponse {
80
655
  readonly body: unknown;
81
656
  }
82
657
 
658
+ /**
659
+ * One review step on one variant and revision. `actorId` is who took the
660
+ * step. Register it in the app's `databaseHandle` beside `cmsRevisionsTable`
661
+ * when a content type requires review.
662
+ */
663
+ export declare const cmsReviewsTable: TableLike;
664
+
665
+ /**
666
+ * Every successful save of a draft writes ONE immutable row here: the
667
+ * validated field values, the content type, the document, the variant's scope
668
+ * and a number per variant (document + scope) starting at 1. Rows are never updated or
669
+ * deleted — a restore or a later edit writes a new revision. Tenant-scoped
670
+ * with the audit columns, like the content tables; the unique key makes a
671
+ * second writer of the same number fail instead of forking the history.
672
+ *
673
+ * Register it in the app's `databaseHandle` beside the content tables.
674
+ */
675
+ export declare const cmsRevisionsTable: TableLike;
676
+
677
+ /**
678
+ * Where a content row lives besides its tenant: the site it belongs to, the
679
+ * content environment (e.g. `production`, `staging`) and its locale. Three
680
+ * separate axes, stored on every draft, published row and revision, and
681
+ * required by every write and read — never taken from a caller's free-form
682
+ * filter. The tenant comes from the request subject (`tenant()`).
683
+ */
684
+ export declare interface CmsScope {
685
+ readonly site: string;
686
+ readonly environment: string;
687
+ /** A BCP 47 tag, e.g. `en-GB`. */
688
+ readonly locale: string;
689
+ }
690
+
691
+ export declare const cmsSearchTable: TableLike;
692
+
693
+ export declare const cmsStewardshipTable: TableLike;
694
+
695
+ /** Who is invited with which role. */
696
+ export declare const cmsTeamInvitationsTable: TableLike;
697
+
698
+ /** One row per workspace: the role a new editor gets, and the types whose publishing needs a review here. */
699
+ export declare const cmsTeamTable: TableLike;
700
+
701
+ /** A built tree: every routable node, depth-first, siblings in order. */
702
+ export declare interface CmsTree {
703
+ readonly nodes: ReadonlyArray<TreeNode>;
704
+ /**
705
+ * Documents whose chain never reaches the root — the parent is not
706
+ * published in any locale the reader accepts, or the parents form a
707
+ * cycle. They are not routable; they are never hung under the root.
708
+ */
709
+ readonly orphans: ReadonlyArray<string>;
710
+ }
711
+
83
712
  /** Everything the write pipeline can fail with on the typed channel. */
84
- export declare type CmsWriteError = ContentValidationFailed | ContentNotFound | ContentIdConflict;
713
+ export declare type CmsWriteError = ContentValidationFailed | ContentNotFound | ContentIdConflict | RevisionMismatch;
714
+
715
+ /**
716
+ * The fields two editors can type in together: plain text (`text` or
717
+ * `textarea`) the editor writes itself — not a derived or unique field (a
718
+ * slug), not a choice (a template), not rich text.
719
+ */
720
+ export declare const collaborativeFields: (type: ContentType) => ReadonlyArray<string>;
721
+
722
+ /** Effect form of {@link compareEnvironments}. */
723
+ export declare const compareEnvironments: (...args: Parameters<typeof compareEnvironments_2>) => Effect<readonly EnvironmentDifference[], never, never>;
724
+
725
+ /** How `to` differs from `from`, type by type. */
726
+ declare const compareEnvironments_2: (store: DataStore, types: ReadonlyArray<ContentType>, pair: EnvironmentPair) => Promise<ReadonlyArray<EnvironmentDifference>>;
727
+
728
+ /** Order of two `major.minor.patch` versions: negative, 0 or positive. */
729
+ export declare const compareVersions: (a: string, b: string) => number;
730
+
731
+ /**
732
+ * A component editors compose pages from (ADR-CMS-015): a stable `id`, a
733
+ * display name and typed props. The frontend renders it; the CMS validates
734
+ * and stores instances of it. `fingerprint` changes whenever the prop contract
735
+ * does, so a stored instance can tell which definition it was written against.
736
+ */
737
+ export declare interface ComponentDefinition {
738
+ readonly id: string;
739
+ readonly displayName: string;
740
+ readonly props: Readonly<Record<string, FieldSchema>>;
741
+ readonly fingerprint: string;
742
+ /** The consent purpose a reader must grant before this component's props reach them (`gateConsent`). */
743
+ readonly consent?: string;
744
+ }
745
+
746
+ /** One placed component in a `components` field, as stored. */
747
+ export declare interface ComponentInstance {
748
+ /** Stable across saves, reorders and translations of the same placement. */
749
+ readonly instanceId: string;
750
+ readonly componentId: string;
751
+ /** The definition's fingerprint when this instance was last saved. */
752
+ readonly fingerprint: string;
753
+ readonly props: Readonly<Record<string, unknown>>;
754
+ }
755
+
756
+ /** A reader's choices: purpose id → the version they allowed. */
757
+ export declare type ConsentChoices = Readonly<Record<string, number>>;
758
+
759
+ /** Something a reader can allow or refuse. */
760
+ export declare interface ConsentPurpose {
761
+ readonly id: string;
762
+ /** Raise it when what the reader agrees to changes. */
763
+ readonly version: number;
764
+ readonly displayName: string;
765
+ readonly description: string;
766
+ }
767
+
768
+ /** Effect form of {@link consentToUpgrade}. */
769
+ export declare const consentToUpgrade: (...args: Parameters<typeof consentToUpgrade_2>) => Effect<ExtensionChange, never, never>;
770
+
771
+ /** Consent to what the waiting version adds, and move to it. */
772
+ declare const consentToUpgrade_2: (tx: DataStore, extensionId: string, consent: ReadonlyArray<ExtensionCapability>) => Promise<ExtensionChange>;
773
+
774
+ export declare const CONTENT_FORM_STRINGS: ContentFormStrings;
85
775
 
86
776
  /** The lifecycle states a content row moves through. */
87
777
  export declare const CONTENT_STATUSES: readonly ["draft", "published", "archived"];
@@ -103,28 +793,168 @@ export declare interface ContentFormProps {
103
793
  readonly contentType: ContentFormType;
104
794
  readonly value: ContentValue;
105
795
  readonly onChange: (next: ContentValue) => void;
796
+ /**
797
+ * Override the widget of one field by its name — a select for a string
798
+ * field only some values make sense in. Wins over `widgets`.
799
+ */
800
+ readonly fieldWidgets?: Readonly<Record<string, Widget>>;
106
801
  /** Override the widget for one or more editor hints (e.g. a TipTap richText). */
107
802
  readonly widgets?: Partial<Record<EditorHint, Widget>>;
803
+ /**
804
+ * Renders a control that picks one document of a type — how the rich-text
805
+ * editor inserts an image asset or a link target. Without it, rich text
806
+ * offers neither.
807
+ */
808
+ readonly renderPicker?: RichDocumentPicker;
809
+ /**
810
+ * Renders beside one field, after its control — what the app keeps about
811
+ * that field (its comments, a hint, who is editing it). `null` renders
812
+ * nothing. Called once per field on every render.
813
+ */
814
+ readonly renderFieldAside?: (name: string) => ReactNode;
815
+ /**
816
+ * Renders inside one block of a rich-text field (the built-in editor), after
817
+ * its actions: `blockId` is the block's stable id, `label` its legend.
818
+ */
819
+ readonly renderBlockAside?: (field: string, blockId: string, label: string) => ReactNode;
820
+ /**
821
+ * The label a person reads for a field, instead of its name in code: `path`
822
+ * is the field's name (`title`), or for a component's prop the component id
823
+ * and the prop (`hero.heading`). `undefined` keeps the name. An app answers
824
+ * from its message catalog, so the labels follow the editor's language.
825
+ */
826
+ readonly fieldLabel?: (path: string) => string | undefined;
827
+ /** The words of the form's own controls (block and component actions, the
828
+ * block editor); English by default. Pass the editor's language. */
829
+ readonly strings?: ContentFormStringsInput;
830
+ /** How rich text's paragraphs and headings are edited — see `RichDocumentEditorProps.surface`. */
831
+ readonly richTextSurface?: 'markup' | 'visual';
108
832
  }
109
833
 
834
+ export declare interface ContentFormStrings {
835
+ /** A block's kind, in its legend (`Paragraph 2`) and the "add" picker. */
836
+ readonly blockNames: Readonly<Record<RichBlock['type'], string>>;
837
+ readonly moveUp: string;
838
+ readonly moveDown: string;
839
+ readonly remove: string;
840
+ /** The accessible names of the three actions, naming what they act on (`Paragraph 2`). */
841
+ readonly moveUpLabel: (label: string) => string;
842
+ readonly moveDownLabel: (label: string) => string;
843
+ readonly removeLabel: (label: string) => string;
844
+ readonly add: string;
845
+ readonly addBlock: string;
846
+ readonly addComponent: string;
847
+ readonly unknownComponent: (componentId: string) => string;
848
+ readonly level: string;
849
+ readonly numbered: string;
850
+ /** A nested depth of a list numbered on its own (`depth` 2: the lists one level in). */
851
+ readonly numberedAt: (depth: number) => string;
852
+ readonly headerRow: string;
853
+ readonly image: string;
854
+ readonly caption: string;
855
+ readonly text: string;
856
+ readonly listItems: string;
857
+ readonly tableRows: string;
858
+ readonly linkTo: string;
859
+ readonly linkText: string;
860
+ readonly insertLink: string;
861
+ /** A list field's entry, in its legend: the field's label and the position (`Categories 2`). */
862
+ readonly item: (label: string, position: number) => string;
863
+ /** The button adding an entry to a list field. */
864
+ readonly addItem: string;
865
+ /** The accessible names of the mark buttons of visual text editing. */
866
+ readonly bold: string;
867
+ readonly italic: string;
868
+ readonly underline: string;
869
+ }
870
+
871
+ /** The defaults with an app's words over them. */
872
+ export declare const contentFormStrings: (strings?: ContentFormStringsInput) => ContentFormStrings;
873
+
874
+ /** What an app passes: any of the words, and any of the block names. */
875
+ export declare type ContentFormStringsInput = Partial<Omit<ContentFormStrings, 'blockNames'>> & {
876
+ readonly blockNames?: Partial<ContentFormStrings['blockNames']>;
877
+ };
878
+
110
879
  /** The content-type shape ContentForm reads (structural — avoids a value import). */
111
880
  export declare interface ContentFormType {
112
881
  readonly fields: Readonly<Record<string, FieldSchema>>;
113
882
  }
114
883
 
115
- /**
116
- * Raised by `saveDraft` when the caller supplies an explicit `id` that
117
- * already exists OUTSIDE the caller's scope (another tenant's row).
118
- * Refusing here keeps a caller-pinned id from ever updating — or, on a
119
- * store without DB-enforced PKs, overwriting — a foreign row.
120
- */
121
- export declare class ContentIdConflict extends ContentIdConflict_base {
884
+ export declare interface ContentfulImportOptions {
885
+ /** The document an entry id became, or null. */
886
+ readonly resolveEntry?: (entryId: string) => string | null;
887
+ /** The image asset document an asset id became, or null. */
888
+ readonly resolveAsset?: (assetId: string) => string | null;
889
+ readonly newId?: () => string;
122
890
  }
123
891
 
124
- declare const ContentIdConflict_base: Schema_2.TaggedErrorClass<ContentIdConflict, "ContentIdConflict", {
125
- readonly _tag: Schema_2.tag<"ContentIdConflict">;
126
- } & {
127
- contentType: typeof Schema_2.String;
892
+ export declare interface ContentfulImportResult {
893
+ readonly document: RichDocument;
894
+ readonly findings: ReadonlyArray<HtmlImportFinding>;
895
+ }
896
+
897
+ /** A node of Contentful's rich-text document, as the export writes it. */
898
+ export declare interface ContentfulNode {
899
+ readonly nodeType: string;
900
+ readonly value?: string;
901
+ readonly marks?: ReadonlyArray<{
902
+ readonly type: string;
903
+ }>;
904
+ readonly data?: {
905
+ readonly uri?: string;
906
+ readonly target?: {
907
+ readonly sys?: {
908
+ readonly id?: string;
909
+ readonly linkType?: string;
910
+ };
911
+ };
912
+ };
913
+ readonly content?: ReadonlyArray<ContentfulNode>;
914
+ }
915
+
916
+ /**
917
+ * A published document had this address and is no longer live — taken down
918
+ * or archived, with no live page at the address now. A site answers it with
919
+ * 410 Gone rather than 404, so the address is dropped rather than retried.
920
+ */
921
+ export declare class ContentGone extends ContentGone_base {
922
+ }
923
+
924
+ declare const ContentGone_base: Schema_2.TaggedErrorClass<ContentGone, "ContentGone", {
925
+ readonly _tag: Schema_2.tag<"ContentGone">;
926
+ } & {
927
+ contentType: typeof Schema_2.String;
928
+ /** The address asked for. */
929
+ path: typeof Schema_2.String;
930
+ }>;
931
+
932
+ /** Effect form of {@link contentHealth}. */
933
+ export declare const contentHealth: (...args: Parameters<typeof contentHealth_2>) => Effect<readonly HealthFinding[], never, never>;
934
+
935
+ /**
936
+ * What needs attention among the PUBLISHED documents of `types` in a site and
937
+ * environment: documents without an owner, reviews that are due, live
938
+ * variants linking to a document that is not live in that language, and
939
+ * languages missing or behind the source. Read through the caller's store, so
940
+ * a request store answers for its tenant. Reads every published row of the
941
+ * types — a report, not a hot path.
942
+ */
943
+ declare const contentHealth_2: (store: DataStore, types: ReadonlyArray<ContentType>, place: Place_2, options: HealthOptions) => Promise<ReadonlyArray<HealthFinding>>;
944
+
945
+ /**
946
+ * Raised by `saveDraft` when the caller supplies an explicit `id` that
947
+ * already exists OUTSIDE the caller's scope (another tenant's row).
948
+ * Refusing here keeps a caller-pinned id from ever updating — or, on a
949
+ * store without DB-enforced PKs, overwriting — a foreign row.
950
+ */
951
+ export declare class ContentIdConflict extends ContentIdConflict_base {
952
+ }
953
+
954
+ declare const ContentIdConflict_base: Schema_2.TaggedErrorClass<ContentIdConflict, "ContentIdConflict", {
955
+ readonly _tag: Schema_2.tag<"ContentIdConflict">;
956
+ } & {
957
+ contentType: typeof Schema_2.String;
128
958
  id: typeof Schema_2.String;
129
959
  }>;
130
960
 
@@ -142,8 +972,10 @@ declare const ContentNotFound_base: Schema_2.TaggedErrorClass<ContentNotFound, "
142
972
  } & {
143
973
  contentType: typeof Schema_2.String;
144
974
  id: typeof Schema_2.String;
145
- /** Which lifecycle table the id was looked up in. */
146
- stage: Schema_2.Literal<["draft", "published"]>;
975
+ /** Which lifecycle table the id was looked up in (`revision`: the
976
+ * revision to publish is not one of this variant's; `share`: a preview
977
+ * share of the caller's). */
978
+ stage: Schema_2.Literal<["draft", "published", "revision", "share"]>;
147
979
  }>;
148
980
 
149
981
  /** A chainable read over one content type's published rows. */
@@ -156,6 +988,17 @@ export declare interface ContentQuery {
156
988
  all(): Promise<ReadonlyArray<Row>>;
157
989
  /** Resolve the first matching row, or null. */
158
990
  one(): Promise<Row | null>;
991
+ /**
992
+ * One page of matching rows in `id` order, after the row whose id is
993
+ * `after`. `next` is the id to pass for the following page, null on the
994
+ * last. Keyset, not offset: a row published or taken down between two
995
+ * requests neither repeats nor skips another. Replaces any `orderBy`,
996
+ * `limit` and `offset` on the query.
997
+ */
998
+ page(limit: number, after?: string): Promise<{
999
+ readonly items: ReadonlyArray<Row>;
1000
+ readonly next: string | null;
1001
+ }>;
159
1002
  }
160
1003
 
161
1004
  export declare type ContentStatus = (typeof CONTENT_STATUSES)[number];
@@ -168,9 +1011,31 @@ export declare interface ContentType {
168
1011
  readonly fields: Readonly<Record<string, FieldSchema>>;
169
1012
  readonly list?: ListConfig;
170
1013
  readonly idPrefix?: string;
171
- /** Declared ISR revalidations fired on publish/unpublish — see
1014
+ /** Declared ISR revalidations fired by `revalidateContent` — see
172
1015
  * `ContentTypeSpec.revalidate`. */
173
1016
  readonly revalidate?: ContentTypeSpec['revalidate'];
1017
+ /** How the documents form a tree — see `ContentTypeSpec.tree`. */
1018
+ readonly tree?: TreeConfig;
1019
+ /** The field a document outside a tree is addressed by — see `ContentTypeSpec.address`. */
1020
+ readonly address?: string;
1021
+ /** Whether publishing needs an approved revision — see `ContentTypeSpec.review`. */
1022
+ readonly review?: {
1023
+ readonly required: boolean | 'workspace';
1024
+ };
1025
+ /** When documents may be used — see `ContentTypeSpec.availability`. */
1026
+ readonly availability?: AvailabilityConfig;
1027
+ /** The review cycle — see `ContentTypeSpec.lifecycle`. */
1028
+ readonly lifecycle?: LifecycleConfig;
1029
+ /** Templates and their rules — see `ContentTypeSpec.templates`. */
1030
+ readonly templates?: TemplatesConfig;
1031
+ /** Whether publishes land in the change feed — see `ContentTypeSpec.changeFeed`. */
1032
+ readonly changeFeed?: boolean;
1033
+ /** What makes a document findable — see `ContentTypeSpec.search`. */
1034
+ readonly search?: SearchConfig;
1035
+ /** What its documents are checked for — see `ContentTypeSpec.quality`. */
1036
+ readonly quality?: ReadonlyArray<QualityRule>;
1037
+ /** The vocabulary of a list field — see `ContentTypeSpec.taxonomy`. */
1038
+ readonly taxonomy?: TaxonomyConfig;
174
1039
  /** Field names whose value is computed-on-save (derivedFrom). */
175
1040
  readonly derivedFields: ReadonlyArray<string>;
176
1041
  /** Field names marked unique-per-tenant (composite `(tenantId, field)` UNIQUE). */
@@ -186,11 +1051,86 @@ export declare interface ContentTypeSpec {
186
1051
  readonly list?: ListConfig;
187
1052
  /** Override the TypeID prefix for awkward plurals / long names. */
188
1053
  readonly idPrefix?: string;
1054
+ /**
1055
+ * Arrange this type's documents in a tree (pages under pages): `parent` is
1056
+ * an optional `Schema.Reference` to this same type, `order` an optional
1057
+ * number field ordering siblings, `segment` the string field that forms the
1058
+ * path (the slug). Read it with `cms.tree` / `cms.route`.
1059
+ */
1060
+ readonly tree?: TreeConfig;
1061
+ /**
1062
+ * For a type outside a tree whose documents have an address of their own
1063
+ * (a blog post's slug): the string field that is it. Every publish records
1064
+ * it, and a changed address leaves a redirect to the document — as moving a
1065
+ * page in a tree does. Read it with `redirectTarget(store, type, path, scope)`.
1066
+ */
1067
+ readonly address?: string;
1068
+ /**
1069
+ * `required: true` publishes only revisions another editor approved
1070
+ * (`approveReview`) — for every path that publishes: single, release,
1071
+ * rollback, schedule. Register `cmsReviewsTable` when set. `'workspace'`:
1072
+ * each workspace decides (team.ts `setReviewRequired`, or a blueprint's
1073
+ * `team.reviewRequired`) — register `cmsTeamTable` too.
1074
+ */
1075
+ readonly review?: {
1076
+ readonly required: boolean | 'workspace';
1077
+ };
1078
+ /**
1079
+ * When this type's documents may be used (`until`: a date/datetime field,
1080
+ * `blocked`: a boolean field). Publishing one records it; publishing
1081
+ * anything referencing a blocked or expired one is refused
1082
+ * (`ReferenceUnavailable`), and readers can leave it out
1083
+ * (`unavailableAmong`). Register `cmsAvailabilityTable` when set.
1084
+ */
1085
+ readonly availability?: AvailabilityConfig;
1086
+ /**
1087
+ * How often a published document is checked again: its first publish sets
1088
+ * a review date `reviewEveryDays` ahead, `recertify` moves it on. Register
1089
+ * `cmsStewardshipTable` (it also holds each document's owner).
1090
+ */
1091
+ readonly lifecycle?: LifecycleConfig;
1092
+ /**
1093
+ * Templates a new document can start from, and the rules a document built
1094
+ * from one keeps on every save (required components, the first one, at
1095
+ * most N of one). `field` stores the template id.
1096
+ */
1097
+ readonly templates?: TemplatesConfig;
1098
+ /**
1099
+ * Append every publish and take-down of this type to the change feed
1100
+ * (`cms_changes`, read with `readChanges`), in the same transaction. Register
1101
+ * `cmsChangesTable` when set.
1102
+ */
1103
+ readonly changeFeed?: boolean;
1104
+ /**
1105
+ * Make this type findable (`searchContent`): every save and publish writes
1106
+ * the variant's text to `cms_search` in the same transaction — `title`
1107
+ * ranked first, all other text (strings, rich text, component props) as the
1108
+ * body. Register `cmsSearchTable` when set.
1109
+ */
1110
+ readonly search?: SearchConfig;
1111
+ /**
1112
+ * Quality rules (quality.ts): each names the causing field, the words an
1113
+ * editor reads, and whether publishing waits for it (`blocking`, default
1114
+ * true). A blocking finding is repaired at its field or excepted — one rule,
1115
+ * one variant, a reason, an end date, approved by someone else
1116
+ * (`requestQualityException` / `decideQualityException`). Register
1117
+ * `cmsQualityExceptionsTable` when set.
1118
+ */
1119
+ readonly quality?: ReadonlyArray<QualityRule>;
1120
+ /**
1121
+ * A controlled vocabulary for one `Schema.Array(Schema.String)` field
1122
+ * (taxonomy.ts): every save folds case and spacing, maps synonyms to their
1123
+ * term and drops repeats; a term outside the vocabulary fails the save
1124
+ * (`unknown: 'keep'` keeps it).
1125
+ */
1126
+ readonly taxonomy?: TaxonomyConfig;
189
1127
  /**
190
1128
  * ISR routes to drop when content of this type is published or
191
- * unpublished — `publish()`/`unpublish()` call `revalidatePath` /
192
- * `revalidateTag` (from `@voltro/runtime`) for each entry after the
193
- * write commits, reaching every `voltro start` replica.
1129
+ * unpublished. `revalidateContent(type)` calls `revalidatePath` /
1130
+ * `revalidateTag` (from `@voltro/runtime`) for each entry, reaching every
1131
+ * `voltro start` replica — `publishDue` after its commits, a mutation from
1132
+ * a post-commit subscriber on `<type>_published` (the write ops run inside
1133
+ * the caller's transaction, so they cannot know when it commits).
194
1134
  *
195
1135
  * You DON'T need this on postgres for the plain publish case: a route
196
1136
  * declaring `cacheInvalidatesOn: ['<type>_published']` is already dropped
@@ -212,12 +1152,24 @@ export declare interface ContentTypeSpec {
212
1152
  * published table (the one the rest of the app reads). Both carry the
213
1153
  * lifecycle `status` column + audit timestamps and are reactive so
214
1154
  * a publish wakes live consumer subscriptions. The draft table also
215
- * carries a nullable `publishAt` (scheduled publishing). A field marked
1155
+ * carries nullable `publishAt` and `unpublishAt` (scheduled publishing and
1156
+ * take-down). A field marked
216
1157
  * `unique()` adds a composite `(tenantId, field)` DB UNIQUE to BOTH
217
1158
  * tables — per-tenant uniqueness enforced by the database.
218
1159
  */
219
1160
  export declare const contentTypeToEntities: (ct: ContentType) => ContentEntities;
220
1161
 
1162
+ export declare interface ContentUsage {
1163
+ readonly documents: number;
1164
+ readonly documentsByType: Readonly<Record<string, number>>;
1165
+ readonly environments: ReadonlyArray<string>;
1166
+ }
1167
+
1168
+ /** Effect form of {@link contentUsage}. */
1169
+ export declare const contentUsage: (...args: Parameters<typeof contentUsage_2>) => Effect<ContentUsage, never, never>;
1170
+
1171
+ declare const contentUsage_2: (store: DataStore, types: ReadonlyArray<ContentType>, site: string) => Promise<ContentUsage>;
1172
+
221
1173
  /**
222
1174
  * Raised by `validateContent` / `saveDraft` when a row violates the
223
1175
  * content type's field rules (pattern / maxLength / typed kinds /
@@ -243,9 +1195,9 @@ export declare type ContentValue = Record<string, unknown>;
243
1195
  /**
244
1196
  * Collect every save-time rule violation for `row` against `type` —
245
1197
  * required presence, per-kind type checks, `maxLength`, `pattern`,
246
- * `Literal` value sets, and the rich-text content policy
247
- * (`allowImages` / `allowEmbeds: false` reject image/embed nodes or the
248
- * `<img>` / `<iframe>` / `<embed>` markers in string values).
1198
+ * `Literal` value sets, component instances, and rich documents (their
1199
+ * structure, and image / link nodes only where the field names a type for
1200
+ * them).
249
1201
  *
250
1202
  * Pure and never throws — usable in a browser form ("annotate every
251
1203
  * invalid field") as well as on the server. `id` is allowed (must be a
@@ -258,7 +1210,27 @@ export declare type ContentValue = Record<string, unknown>;
258
1210
  * that is about to be written — a derived field's rules apply to the
259
1211
  * derived value, not to a caller value that's about to be overwritten.
260
1212
  */
261
- export declare const contentViolations: (type: Pick<ContentType, "name" | "fields">, row: Readonly<Record<string, unknown>>) => ReadonlyArray<FieldViolation>;
1213
+ export declare const contentViolations: (type: Pick<ContentType, "name" | "fields"> & Partial<Pick<ContentType, "taxonomy">>, row: Readonly<Record<string, unknown>>) => ReadonlyArray<FieldViolation>;
1214
+
1215
+ /** Effect form of {@link copyEnvironment}. */
1216
+ export declare const copyEnvironment: (...args: Parameters<typeof copyEnvironment_2>) => Effect<CopyEnvironmentResult, never, never>;
1217
+
1218
+ /**
1219
+ * Fill `to` from `from`, within one site. Refused unless `to` holds no variant
1220
+ * of these types yet — a copy never merges into, or overwrites, content that
1221
+ * is already there.
1222
+ */
1223
+ declare const copyEnvironment_2: (tx: DataStore, types: ReadonlyArray<ContentType>, pair: EnvironmentPair) => Promise<CopyEnvironmentResult>;
1224
+
1225
+ export declare type CopyEnvironmentResult = {
1226
+ readonly ok: true;
1227
+ readonly variants: number;
1228
+ readonly published: number;
1229
+ } | {
1230
+ readonly ok: false;
1231
+ readonly reason: 'targetNotEmpty' | 'sameEnvironment';
1232
+ readonly variants: number;
1233
+ };
262
1234
 
263
1235
  /**
264
1236
  * A standalone CMS client for build-time consumption (the blog
@@ -268,9 +1240,101 @@ export declare const contentViolations: (type: Pick<ContentType, "name" | "field
268
1240
  export declare const createCmsClient: (config: {
269
1241
  store: DataStore;
270
1242
  types: ReadonlyArray<ContentType>;
1243
+ scope: CmsScope;
271
1244
  secret?: string;
272
1245
  }) => CmsApi;
273
1246
 
1247
+ /** Effect form of {@link createPreviewShare}. */
1248
+ export declare const createPreviewShare: (...args: Parameters<typeof createPreviewShare_2>) => Effect<{
1249
+ readonly share: Row;
1250
+ readonly token: string;
1251
+ }, ContentNotFound | PreviewShareRejected, never>;
1252
+
1253
+ /**
1254
+ * Share one of the caller's drafts. Returns the stored share and the link
1255
+ * token — the only time the token exists in the clear; hand it to the visitor
1256
+ * as part of a URL. Throws `ContentNotFound` when the draft is not the
1257
+ * caller's in `scope`, and `PreviewShareRejected` for an expiry that is not in
1258
+ * the future or lies more than `MAX_PREVIEW_SHARE_DAYS` ahead.
1259
+ */
1260
+ declare const createPreviewShare_2: (store: DataStore, type: ContentType, variantId: string, scope: CmsScope, options: CreatePreviewShareOptions) => Promise<{
1261
+ readonly share: Row;
1262
+ readonly token: string;
1263
+ }>;
1264
+
1265
+ export declare interface CreatePreviewShareOptions {
1266
+ /** `pinned` shows the revision the draft has now; `latest` follows every save. */
1267
+ readonly revision: 'pinned' | 'latest';
1268
+ readonly expiresAt: Date;
1269
+ readonly label?: string;
1270
+ /** The clock (tests). */
1271
+ readonly now?: Date;
1272
+ }
1273
+
1274
+ /** Effect form of {@link createRelease}. */
1275
+ export declare const createRelease: (...args: Parameters<typeof createRelease_2>) => Effect<Readonly<Record<string, unknown>>, never, never>;
1276
+
1277
+ /** Create an empty release for one site and environment. */
1278
+ declare const createRelease_2: (store: DataStore, input: {
1279
+ readonly name: string;
1280
+ readonly site: string;
1281
+ readonly environment: string;
1282
+ }) => Promise<Row>;
1283
+
1284
+ export declare type DecideExceptionResult = {
1285
+ readonly ok: true;
1286
+ readonly state: 'approved' | 'rejected' | 'withdrawn';
1287
+ } | {
1288
+ readonly ok: false;
1289
+ readonly reason: 'notFound' | 'notOpen' | 'selfApproval' | 'notRequester';
1290
+ };
1291
+
1292
+ export declare interface DecideOptions {
1293
+ /** The revision the reviewer looked at. */
1294
+ readonly revisionId: string;
1295
+ readonly actorId: string;
1296
+ readonly note?: string;
1297
+ /** Let the person who asked approve their own request. Off by default. */
1298
+ readonly allowSelfApproval?: boolean;
1299
+ }
1300
+
1301
+ /** Effect form of {@link decideQualityException}. */
1302
+ export declare const decideQualityException: (...args: Parameters<typeof decideQualityException_2>) => Effect<DecideExceptionResult, never, never>;
1303
+
1304
+ /**
1305
+ * Decide on an exception: approve or reject an open request (never your own),
1306
+ * or withdraw one — the requester their open request, anyone an approved one
1307
+ * (the finding blocks again at once).
1308
+ */
1309
+ declare const decideQualityException_2: (tx: DataStore, exceptionId: string, input: {
1310
+ readonly decision: "approve" | "reject" | "withdraw";
1311
+ readonly actorId: string;
1312
+ readonly note?: string;
1313
+ }, now?: Date) => Promise<DecideExceptionResult>;
1314
+
1315
+ /** Decode character references (`&amp;`, `&#8217;`, `&#x2014;`). */
1316
+ export declare const decodeEntities: (text: string) => string;
1317
+
1318
+ /** Define an audience; a rule with no condition would match everyone and is refused. */
1319
+ export declare const defineAudience: (audience: Audience) => Audience;
1320
+
1321
+ /**
1322
+ * Check a blueprint and order its entries so every referenced entry comes
1323
+ * before the entries that reference it. Throws `BlueprintInvalid` for a key
1324
+ * used twice, a reference to no entry, or entries that reference each other
1325
+ * in a circle.
1326
+ */
1327
+ export declare const defineBlueprint: (spec: Blueprint) => Blueprint;
1328
+
1329
+ /** Declare a component editors can place in a `Schema.Components` field. */
1330
+ export declare const defineComponent: (spec: {
1331
+ readonly id: string;
1332
+ readonly displayName: string;
1333
+ readonly props: Readonly<Record<string, FieldSchema | PipeableField>>;
1334
+ /** A consent purpose the reader must grant first — an embed that loads a third party. */
1335
+ readonly consent?: string;
1336
+ }) => ComponentDefinition;
1337
+
274
1338
  export declare const defineContentType: (spec: ContentTypeSpec) => ContentType;
275
1339
 
276
1340
  /**
@@ -292,11 +1356,404 @@ export declare interface DerivedSpec {
292
1356
  readonly transform: (value: unknown, row: Record<string, unknown>) => unknown;
293
1357
  }
294
1358
 
1359
+ /**
1360
+ * Name the change from `before` to `after`, or null when nothing declared
1361
+ * changed. A component or block list names the item added, removed, moved or
1362
+ * edited; any other field is "edit <field>".
1363
+ */
1364
+ export declare const describeEdit: (fields: Readonly<Record<string, FieldSchema>>, before: Readonly<Record<string, unknown>>, after: Readonly<Record<string, unknown>>, words: EditWords) => EditDescription | null;
1365
+
1366
+ export declare const describeFailure: (err: unknown) => string;
1367
+
1368
+ /** One run of a word diff: text both sides share, or text only one side has. */
1369
+ export declare interface DiffSegment {
1370
+ readonly op: 'same' | 'removed' | 'added';
1371
+ readonly text: string;
1372
+ }
1373
+
1374
+ /**
1375
+ * The word diff of two texts: the longest common run of words kept as `same`,
1376
+ * the rest as `removed` (only before) and `added` (only after), adjacent runs
1377
+ * of one kind merged. Two very long texts come back as one removed and one
1378
+ * added run.
1379
+ */
1380
+ export declare const diffWords: (before: string, after: string) => ReadonlyArray<DiffSegment>;
1381
+
1382
+ /** Effect form of {@link dropFromSearch}. */
1383
+ export declare const dropFromSearch: (...args: Parameters<typeof dropFromSearch_2>) => Effect<void, never, never>;
1384
+
1385
+ /** Remove a variant from the search, for the given stages. */
1386
+ declare const dropFromSearch_2: (tx: DataStore, type: ContentType, variantId: string, stages: ReadonlyArray<"draft" | "published">) => Promise<void>;
1387
+
1388
+ export declare interface DuplicateDocument {
1389
+ readonly id: string;
1390
+ readonly documentId: string;
1391
+ readonly title: string;
1392
+ readonly status: string;
1393
+ }
1394
+
1395
+ export declare interface DuplicateGroup {
1396
+ readonly fingerprint: string;
1397
+ /** Oldest first: the first is the one to keep unless someone decides otherwise. */
1398
+ readonly documents: ReadonlyArray<DuplicateDocument>;
1399
+ }
1400
+
1401
+ /** Effect form of {@link duplicateGroups}. */
1402
+ export declare const duplicateGroups: (...args: Parameters<typeof duplicateGroups_2>) => Effect<readonly DuplicateGroup[], never, never>;
1403
+
1404
+ /** The drafts of `type` in `scope` whose `field` holds the same file, grouped. Archived drafts are left out. */
1405
+ declare const duplicateGroups_2: (store: DataStore, type: ContentType, scope: CmsScope, options: {
1406
+ readonly field: string;
1407
+ readonly fingerprint: Fingerprint;
1408
+ readonly titleField?: string;
1409
+ }) => Promise<ReadonlyArray<DuplicateGroup>>;
1410
+
1411
+ /** What one change did, and a key that tells whether the next change continues it. */
1412
+ export declare interface EditDescription {
1413
+ readonly label: string;
1414
+ /** Changes with the same key in quick succession are one step (typing). */
1415
+ readonly key: string;
1416
+ }
1417
+
1418
+ export declare interface EditHistory {
1419
+ /** Oldest first; the last one is undone next. */
1420
+ readonly past: ReadonlyArray<EditStep>;
1421
+ /** Next first: what redo does. */
1422
+ readonly future: ReadonlyArray<EditStep>;
1423
+ }
1424
+
295
1425
  /** The widget the editor renders for a field — drives ContentForm. */
296
- export declare type EditorHint = 'text' | 'textarea' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' | 'richText' | 'media' | 'reference' | 'array' | 'struct';
1426
+ export declare type EditorHint = 'text' | 'textarea' | 'number' | 'boolean' | 'date' | 'datetime' | 'select' | 'richText' | 'media' | 'reference' | 'array' | 'struct' | 'components';
1427
+
1428
+ /** What the editor sends the preview. */
1429
+ export declare interface EditorMessage {
1430
+ readonly protocol: typeof VISUAL_EDITING_PROTOCOL;
1431
+ readonly nonce: string;
1432
+ readonly kind: 'values';
1433
+ readonly values: Readonly<Record<string, unknown>>;
1434
+ }
1435
+
1436
+ /** One step: the form as it was before it, and its name. */
1437
+ export declare interface EditStep {
1438
+ readonly values: Readonly<Record<string, unknown>>;
1439
+ readonly label: string;
1440
+ readonly key: string;
1441
+ readonly at: number;
1442
+ }
1443
+
1444
+ /** The words a step is named with, in the editor's language. */
1445
+ export declare interface EditWords {
1446
+ readonly fieldLabel: (name: string) => string;
1447
+ readonly componentLabel: (componentId: string) => string;
1448
+ readonly blockLabel: (type: RichBlock['type']) => string;
1449
+ readonly edit: (what: string) => string;
1450
+ readonly add: (what: string) => string;
1451
+ readonly remove: (what: string) => string;
1452
+ readonly moveUp: (what: string) => string;
1453
+ readonly moveDown: (what: string) => string;
1454
+ /** Two neighbours that changed places — which of them was moved cannot be told from the result. */
1455
+ readonly swap: (first: string, second: string) => string;
1456
+ }
1457
+
1458
+ /** The tools on for the last step of `chain`, and why each tool is as it is. */
1459
+ export declare const effectiveExposure: (input: ExposureInput) => ExposureResult;
1460
+
1461
+ export declare const EMPTY_EDIT_HISTORY: EditHistory;
1462
+
1463
+ /** An empty document. */
1464
+ export declare const emptyRichDocument: () => RichDocument;
1465
+
1466
+ export declare interface EnvironmentDifference {
1467
+ readonly contentType: string;
1468
+ /** Documents (with a variant) in `from` only, and in `to` only. */
1469
+ readonly onlyInFrom: number;
1470
+ readonly onlyInTo: number;
1471
+ /** Live in both, with different published values. */
1472
+ readonly differing: ReadonlyArray<{
1473
+ readonly documentId: string;
1474
+ readonly locale: string;
1475
+ readonly title: string;
1476
+ }>;
1477
+ }
1478
+
1479
+ export declare interface EnvironmentPair {
1480
+ readonly site: string;
1481
+ readonly from: string;
1482
+ readonly to: string;
1483
+ }
1484
+
1485
+ export declare type ExceptionState = 'requested' | 'approved' | 'rejected' | 'withdrawn' | 'expired';
1486
+
1487
+ export declare interface Experiment {
1488
+ readonly id: string;
1489
+ readonly name: string;
1490
+ readonly contentType: string;
1491
+ readonly documentId: string;
1492
+ readonly locale: string;
1493
+ readonly status: 'running' | 'stopped';
1494
+ readonly share: number;
1495
+ readonly overrides: Readonly<Record<string, string>>;
1496
+ readonly goal: string;
1497
+ /** Null for an experiment started before hypotheses were asked for. */
1498
+ readonly hypothesis: string | null;
1499
+ readonly guardrailMaxDrop: number | null;
1500
+ readonly startedAt: Date;
1501
+ readonly stoppedAt: Date | null;
1502
+ /** Version A: the published revision it was started on (null before lineage was recorded). */
1503
+ readonly revisionId: string | null;
1504
+ readonly adoptedReleaseId: string | null;
1505
+ readonly adoptedRevisionId: string | null;
1506
+ }
1507
+
1508
+ /** Effect form of {@link experimentById}. */
1509
+ export declare const experimentById: (...args: Parameters<typeof experimentById_2>) => Effect<Experiment | null, never, never>;
1510
+
1511
+ /** One experiment by id, or null. */
1512
+ declare const experimentById_2: (store: DataStore, experimentId: string) => Promise<Experiment | null>;
1513
+
1514
+ /** Fields version B may override: the type's own text fields, not derived ones (a slug follows its title). */
1515
+ export declare const experimentFields: (type: ContentType) => ReadonlyArray<string>;
1516
+
1517
+ export declare interface ExperimentLineage {
1518
+ /** Version A: the published revision the experiment was started on. */
1519
+ readonly startedOn: string | null;
1520
+ /** Version B: that revision with these fields replaced. */
1521
+ readonly overrides: Readonly<Record<string, string>>;
1522
+ /** Per delivered revision and version, the readers counted (a publish during the experiment adds a row). */
1523
+ readonly delivered: ReadonlyArray<{
1524
+ readonly revisionId: string | null;
1525
+ readonly variant: Variant;
1526
+ readonly readers: number;
1527
+ }>;
1528
+ /** The adoption, when version B went into a release; `releaseStatus` follows the release. */
1529
+ readonly adopted: {
1530
+ readonly releaseId: string;
1531
+ readonly revisionId: string;
1532
+ readonly releaseStatus: string;
1533
+ } | null;
1534
+ }
1535
+
1536
+ /** Effect form of {@link experimentLineage}. */
1537
+ export declare const experimentLineage: (...args: Parameters<typeof experimentLineage_2>) => Effect<ExperimentLineage | null, never, never>;
1538
+
1539
+ /** Where every delivery of an experiment came from — revision, version, adoption. */
1540
+ declare const experimentLineage_2: (store: DataStore, experimentId: string) => Promise<ExperimentLineage | null>;
1541
+
1542
+ export declare interface ExperimentResults {
1543
+ readonly A: VariantResult;
1544
+ readonly B: VariantResult;
1545
+ /** B's rate relative to A's (0.25 = a quarter more); null while A has no conversions. */
1546
+ readonly lift: number | null;
1547
+ /** Two-sided p-value of the difference in rates (two-proportion z-test); null without readers in both. */
1548
+ readonly pValue: number | null;
1549
+ /** At least `MIN_READERS` per version and p below 0.05 — before that the difference may be noise. */
1550
+ readonly conclusive: boolean;
1551
+ /** The guardrail, and whether B fell below it (judged from `MIN_READERS` per version on). */
1552
+ readonly guardrail: {
1553
+ readonly maxDrop: number | null;
1554
+ readonly breached: boolean;
1555
+ };
1556
+ }
1557
+
1558
+ /** Effect form of {@link experimentResults}. */
1559
+ export declare const experimentResults: (...args: Parameters<typeof experimentResults_2>) => Effect<ExperimentResults, never, never>;
1560
+
1561
+ /** Per version: readers, conversions and rate, the lift of B, and whether the difference is yet more than noise. */
1562
+ declare const experimentResults_2: (store: DataStore, experimentId: string) => Promise<ExperimentResults>;
1563
+
1564
+ export declare interface ExposureInput {
1565
+ readonly ceiling: ReadonlyArray<string>;
1566
+ readonly defaults: ReadonlyArray<string>;
1567
+ /** From the root down to the page. */
1568
+ readonly chain: ReadonlyArray<ExposureStep>;
1569
+ }
1570
+
1571
+ export declare interface ExposureResult {
1572
+ /** The tools on here, in the ceiling's order. */
1573
+ readonly tools: ReadonlyArray<string>;
1574
+ /** Every tool of the ceiling and why it is as it is. */
1575
+ readonly explained: ReadonlyArray<ToolExposure>;
1576
+ }
1577
+
1578
+ /** One level of the tree: tool names turned on, off, or locked off here. A value that is not a list of names counts as unset. */
1579
+ export declare interface ExposureStep {
1580
+ readonly on?: unknown;
1581
+ readonly off?: unknown;
1582
+ readonly locked?: unknown;
1583
+ }
1584
+
1585
+ /** The places in the editor an extension can show itself. */
1586
+ export declare const EXTENSION_SLOTS: readonly ["dashboard", "sidebar", "fieldWidget", "entryTab", "releaseCheck", "assetAction", "settings"];
1587
+
1588
+ /** An extension reached for a capability it was not granted. */
1589
+ export declare class ExtensionAccessDenied extends ExtensionAccessDenied_base {
1590
+ }
1591
+
1592
+ declare const ExtensionAccessDenied_base: Schema_2.TaggedErrorClass<ExtensionAccessDenied, "ExtensionAccessDenied", {
1593
+ readonly _tag: Schema_2.tag<"ExtensionAccessDenied">;
1594
+ } & {
1595
+ extensionId: typeof Schema_2.String;
1596
+ capability: typeof Schema_2.String;
1597
+ }>;
1598
+
1599
+ /**
1600
+ * What an extension may do; everything else is refused.
1601
+ *
1602
+ * content:read / content:write — documents, through the CMS, never its tables;
1603
+ * egress:<host> — HTTPS requests to exactly that host;
1604
+ * secret:<NAME> — that one secret, as the host binds it.
1605
+ *
1606
+ * Its own data (`data` in the sandbox) needs no capability: it lives in the
1607
+ * extension's namespace and leaves with it.
1608
+ */
1609
+ export declare type ExtensionCapability = 'content:read' | 'content:write' | `egress:${string}` | `secret:${string}`;
1610
+
1611
+ export declare type ExtensionChange = {
1612
+ readonly ok: true;
1613
+ readonly installed: InstalledExtension;
1614
+ } | {
1615
+ readonly ok: false;
1616
+ readonly reason: 'invalidManifest';
1617
+ readonly problems: ReadonlyArray<string>;
1618
+ } | {
1619
+ readonly ok: false;
1620
+ readonly reason: 'consentIncomplete';
1621
+ readonly missing: ReadonlyArray<ExtensionCapability>;
1622
+ } | {
1623
+ readonly ok: false;
1624
+ readonly reason: 'alreadyInstalled' | 'notInstalled' | 'notNewer' | 'nothingPending' | 'nothingToRollBack';
1625
+ };
1626
+
1627
+ /** What the host lends an extension; the sandbox decides whether it may use it. */
1628
+ export declare interface ExtensionHost {
1629
+ readonly readContent: (type: string, id: string) => Promise<Readonly<Record<string, unknown>> | null>;
1630
+ /** A type's drafts as the host lends them (it decides how many). */
1631
+ readonly listContent: (type: string) => Promise<ReadonlyArray<Readonly<Record<string, unknown>>>>;
1632
+ /** How many drafts a type has — all of them, where `listContent` may lend only some. */
1633
+ readonly countContent: (type: string) => Promise<number>;
1634
+ /** The values a revision holds (what a release publishes), or null. */
1635
+ readonly readRevision: (revisionId: string) => Promise<Readonly<Record<string, unknown>> | null>;
1636
+ readonly writeContent: (type: string, id: string, values: Readonly<Record<string, unknown>>) => Promise<void>;
1637
+ readonly fetch: (url: string, init?: RequestInit) => Promise<Response>;
1638
+ /** The secret bound under `name`, or undefined. */
1639
+ readonly secret: (name: string) => Promise<string | undefined>;
1640
+ }
1641
+
1642
+ /** A manifest on the wire — for a descriptor's input or output. */
1643
+ export declare const ExtensionManifestSchema: Schema_2.Struct<{
1644
+ id: typeof Schema_2.String;
1645
+ name: typeof Schema_2.String;
1646
+ version: typeof Schema_2.String;
1647
+ publisher: typeof Schema_2.String;
1648
+ capabilities: Schema_2.Array$<typeof Schema_2.String>;
1649
+ slots: Schema_2.Array$<typeof Schema_2.String>;
1650
+ fields: Schema_2.optional<Schema_2.Array$<typeof Schema_2.String>>;
1651
+ settings: Schema_2.optional<Schema_2.Array$<Schema_2.Union<[Schema_2.Struct<{
1652
+ key: typeof Schema_2.String;
1653
+ label: typeof Schema_2.String;
1654
+ kind: Schema_2.Literal<["number"]>;
1655
+ default: typeof Schema_2.Number;
1656
+ min: Schema_2.optional<typeof Schema_2.Number>;
1657
+ max: Schema_2.optional<typeof Schema_2.Number>;
1658
+ }>, Schema_2.Struct<{
1659
+ key: typeof Schema_2.String;
1660
+ label: typeof Schema_2.String;
1661
+ kind: Schema_2.Literal<["boolean"]>;
1662
+ default: typeof Schema_2.Boolean;
1663
+ }>, Schema_2.Struct<{
1664
+ key: typeof Schema_2.String;
1665
+ label: typeof Schema_2.String;
1666
+ kind: Schema_2.Literal<["choice"]>;
1667
+ default: typeof Schema_2.String;
1668
+ options: Schema_2.Array$<typeof Schema_2.String>;
1669
+ }>]>>>;
1670
+ }>;
1671
+
1672
+ export declare type ExtensionRemoval = {
1673
+ readonly ok: true;
1674
+ readonly data: ReadonlyArray<{
1675
+ readonly key: string;
1676
+ readonly value: unknown;
1677
+ }>;
1678
+ } | {
1679
+ readonly ok: false;
1680
+ readonly reason: 'notInstalled';
1681
+ };
1682
+
1683
+ /** What an installed extension's code gets. */
1684
+ export declare interface ExtensionSandbox {
1685
+ readonly extensionId: string;
1686
+ readonly readContent: ExtensionHost['readContent'];
1687
+ readonly listContent: ExtensionHost['listContent'];
1688
+ readonly countContent: ExtensionHost['countContent'];
1689
+ readonly readRevision: ExtensionHost['readRevision'];
1690
+ readonly writeContent: ExtensionHost['writeContent'];
1691
+ readonly fetch: ExtensionHost['fetch'];
1692
+ readonly secret: (name: string) => Promise<string | undefined>;
1693
+ /** Its settings as the admin set them (defaults for the rest). */
1694
+ readonly settings: () => Promise<Readonly<Record<string, ExtensionSettingValue>>>;
1695
+ /** Its own data. */
1696
+ readonly data: {
1697
+ readonly get: (key: string) => Promise<unknown>;
1698
+ readonly set: (key: string, value: unknown) => Promise<void>;
1699
+ };
1700
+ }
1701
+
1702
+ /**
1703
+ * The sandbox for `installed`: content, the network and secrets through the
1704
+ * host, each only when granted; every refusal is `ExtensionAccessDenied`
1705
+ * (thrown). Egress is HTTPS to a granted host only.
1706
+ */
1707
+ export declare const extensionSandbox: (store: DataStore, installed: InstalledExtension, host: ExtensionHost) => ExtensionSandbox;
1708
+
1709
+ /** Effect form of {@link extensionSecret}. */
1710
+ export declare const extensionSecret: (...args: Parameters<typeof extensionSecret_2>) => Effect<string | undefined, never, never>;
1711
+
1712
+ /** The value of a bound secret, for the host — never for a client. */
1713
+ declare const extensionSecret_2: (store: DataStore, extensionId: string, name: string) => Promise<string | undefined>;
1714
+
1715
+ /** One setting of an extension. A number may have bounds; a choice lists its options. */
1716
+ export declare type ExtensionSetting = {
1717
+ readonly key: string;
1718
+ readonly label: string;
1719
+ readonly kind: 'number';
1720
+ readonly default: number;
1721
+ readonly min?: number;
1722
+ readonly max?: number;
1723
+ } | {
1724
+ readonly key: string;
1725
+ readonly label: string;
1726
+ readonly kind: 'boolean';
1727
+ readonly default: boolean;
1728
+ } | {
1729
+ readonly key: string;
1730
+ readonly label: string;
1731
+ readonly kind: 'choice';
1732
+ readonly default: string;
1733
+ readonly options: ReadonlyArray<string>;
1734
+ };
1735
+
1736
+ /** Effect form of {@link extensionSettings}. */
1737
+ export declare const extensionSettings: (...args: Parameters<typeof extensionSettings_2>) => Effect<Readonly<Record<string, ExtensionSettingValue>> | null, never, never>;
1738
+
1739
+ /** An installed extension's settings, with defaults for what was never set. */
1740
+ declare const extensionSettings_2: (store: DataStore, extensionId: string) => Promise<Readonly<Record<string, ExtensionSettingValue>> | null>;
1741
+
1742
+ export declare type ExtensionSettingValue = number | boolean | string;
1743
+
1744
+ export declare type ExtensionSlot = (typeof EXTENSION_SLOTS)[number];
1745
+
1746
+ /** One changed field, as a word diff of its text before and after. */
1747
+ export declare interface FieldDiff {
1748
+ readonly field: string;
1749
+ readonly segments: ReadonlyArray<DiffSegment>;
1750
+ }
1751
+
1752
+ /** How each declared field that changed between `before` and `after` changed, in declaration order. */
1753
+ export declare const fieldDiffs: (fields: Readonly<Record<string, unknown>>, before: Readonly<Record<string, unknown>>, after: Readonly<Record<string, unknown>>) => ReadonlyArray<FieldDiff>;
297
1754
 
298
1755
  /** Discriminator for how a field compiles to a column + serialises. */
299
- export declare type FieldKind = 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'literal' | 'richText' | 'media' | 'reference' | 'array' | 'struct';
1756
+ export declare type FieldKind = 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'literal' | 'richText' | 'media' | 'reference' | 'array' | 'struct' | 'components';
300
1757
 
301
1758
  /** A refinement applied through `.pipe(...)`. */
302
1759
  export declare type FieldRefinement = (field: FieldSchema) => FieldSchema;
@@ -307,12 +1764,20 @@ export declare interface FieldSchema {
307
1764
  readonly editorHint: EditorHint;
308
1765
  /** When true the field is nullable in the DB + optional in the editor. */
309
1766
  readonly isOptional: boolean;
1767
+ /**
1768
+ * Set by `.requiredToPublish()`: a draft may leave it empty; publishing
1769
+ * needs it (`publishViolations`, checked by every publish). Implies
1770
+ * `isOptional` — the column is nullable.
1771
+ */
1772
+ readonly publishRequired?: boolean;
310
1773
  /** Max string length — drives textarea-vs-input + save-time validation. */
311
1774
  readonly maxLength?: number;
312
1775
  /** Source-form regex (string) for save-time validation. */
313
1776
  readonly pattern?: string;
314
1777
  /** Closed value set for `literal` fields → `<select>` + CHECK constraint. */
315
1778
  readonly literals?: ReadonlyArray<string>;
1779
+ /** A `number` field that takes fractions (a `real` column); without it a number is whole. */
1780
+ readonly fraction?: boolean;
316
1781
  /**
317
1782
  * When true, the field is unique PER TENANT — the derived tables carry a
318
1783
  * composite `(tenantId, <field>)` DB UNIQUE constraint (see contentType.ts).
@@ -327,10 +1792,29 @@ export declare interface FieldSchema {
327
1792
  readonly element?: FieldSchema;
328
1793
  /** Nested field map for `struct` fields. */
329
1794
  readonly struct?: Readonly<Record<string, FieldSchema>>;
1795
+ /** The components a `components` field may hold, in the order editors see them. */
1796
+ readonly components?: ReadonlyArray<ComponentDefinition>;
330
1797
  /** Computed-on-save derivation (set via `derivedFrom`). */
331
1798
  readonly derived?: DerivedSpec;
332
1799
  }
333
1800
 
1801
+ /** One value a field held, from the revision that introduced it. */
1802
+ export declare interface FieldVersion {
1803
+ readonly value: unknown;
1804
+ readonly revisionId: string;
1805
+ readonly number: number;
1806
+ readonly createdAt: unknown;
1807
+ readonly createdBy: unknown;
1808
+ }
1809
+
1810
+ /**
1811
+ * The versions of one field across a document's revisions, newest first: a
1812
+ * new entry wherever the value changed. For an image asset's `file` it is the
1813
+ * file history — a revision that only fixed the alt text adds no version.
1814
+ * `revisions` are `cms_revisions` rows (e.g. from `listRevisions`), in any order.
1815
+ */
1816
+ export declare const fieldVersions: (revisions: ReadonlyArray<Readonly<Record<string, unknown>>>, field: string) => ReadonlyArray<FieldVersion>;
1817
+
334
1818
  /** One save-time rule violation, addressed to a field path. */
335
1819
  export declare interface FieldViolation {
336
1820
  /** Dotted/indexed field path, e.g. `title`, `meta.ogTitle`, `tags[2]`. */
@@ -340,6 +1824,75 @@ export declare interface FieldViolation {
340
1824
  readonly message: string;
341
1825
  }
342
1826
 
1827
+ /** How to fingerprint a stored value (a media key); null when it cannot be read. */
1828
+ export declare type Fingerprint = (value: string) => Promise<string | null>;
1829
+
1830
+ /**
1831
+ * The part of a `ContentForm` a path names — a field's container, or one
1832
+ * placed component of a components field — or null.
1833
+ */
1834
+ export declare const formPartOf: (form: ParentNode, path: string) => Element | null;
1835
+
1836
+ /**
1837
+ * The values with every component that needs an ungranted purpose replaced
1838
+ * by a {@link WithheldInstance}. Values without such components come back
1839
+ * unchanged. Apply it wherever content leaves for a reader.
1840
+ */
1841
+ export declare const gateConsent: (type: {
1842
+ readonly fields: Readonly<Record<string, FieldSchema>>;
1843
+ }, values: Readonly<Record<string, unknown>>, granted: ReadonlySet<string>) => Record<string, unknown>;
1844
+
1845
+ /** Effect form of {@link glossary}. */
1846
+ export declare const glossary: (...args: Parameters<typeof glossary_2>) => Effect<readonly GlossaryEntry[], never, never>;
1847
+
1848
+ /** The workspace's entries, by term; for one target language when given. */
1849
+ declare const glossary_2: (store: DataStore, tenantId: string, locale?: string) => Promise<ReadonlyArray<GlossaryEntry>>;
1850
+
1851
+ export declare interface GlossaryEntry {
1852
+ readonly id: string;
1853
+ /** The term as written in the source language. */
1854
+ readonly term: string;
1855
+ /** The target language. */
1856
+ readonly locale: string;
1857
+ /** How it is written there; null: it stays as it is (a brand name). */
1858
+ readonly translation: string | null;
1859
+ /** Translations that must not be used. */
1860
+ readonly forbidden: ReadonlyArray<string>;
1861
+ readonly note: string | null;
1862
+ }
1863
+
1864
+ export declare interface GlossaryInput {
1865
+ readonly term: string;
1866
+ readonly locale: string;
1867
+ readonly translation?: string | null;
1868
+ readonly forbidden?: ReadonlyArray<string>;
1869
+ readonly note?: string | null;
1870
+ }
1871
+
1872
+ /** What is wrong with an entry; empty when nothing is. */
1873
+ export declare const glossaryInputProblems: (input: GlossaryInput) => ReadonlyArray<string>;
1874
+
1875
+ /** The forbidden translations `text` (in the target language) uses, per term. */
1876
+ export declare const glossaryProblems: (text: string, entries: ReadonlyArray<GlossaryEntry>) => ReadonlyArray<{
1877
+ readonly term: string;
1878
+ readonly found: string;
1879
+ readonly use: string | null;
1880
+ }>;
1881
+
1882
+ /** The purposes whose current version the reader allowed. */
1883
+ export declare const grantedPurposes: (purposes: ReadonlyArray<ConsentPurpose>, choices: ConsentChoices) => ReadonlySet<string>;
1884
+
1885
+ /** Effect form of {@link hadAddress}. */
1886
+ export declare const hadAddress: (...args: Parameters<typeof hadAddress_2>) => Effect<boolean, never, never>;
1887
+
1888
+ /**
1889
+ * Whether `path` was an address of a document of `type` in `scope` — its last
1890
+ * published address, or one a redirect points from — whatever answers it now.
1891
+ * Ask it once `cms.route` found no live page: then the document is no longer
1892
+ * live and the address is gone.
1893
+ */
1894
+ declare const hadAddress_2: (store: DataStore, type: string, path: string, scope: CmsScope, tenantId?: unknown) => Promise<boolean>;
1895
+
343
1896
  /**
344
1897
  * Handle one CMS REST request. Returns 401 on a missing/unknown key,
345
1898
  * 403 when the key isn't scoped to the requested type, 404 for unknown
@@ -348,152 +1901,1482 @@ export declare interface FieldViolation {
348
1901
  */
349
1902
  export declare const handleCmsRest: (req: CmsRestRequest, options: CmsRestOptions) => Promise<CmsRestResponse>;
350
1903
 
351
- /**
352
- * List-view configuration for the consuming editor/template: which
353
- * columns its list page shows and the default sort. Validated by
354
- * `defineContentType` — every referenced name must be a declared field
355
- * or a lifecycle column, so a typo fails at definition time instead of
356
- * rendering an empty column.
357
- */
358
- export declare interface ListConfig {
359
- readonly columns: ReadonlyArray<string>;
360
- readonly defaultSort?: {
361
- readonly field: string;
362
- readonly dir: 'asc' | 'desc';
363
- };
1904
+ /** Whether every character of text in `[start, end)` carries `mark` (links never do). */
1905
+ export declare const hasMark: (content: ReadonlyArray<RichInline>, start: number, end: number, mark: RichMark) => boolean;
1906
+
1907
+ /** One thing that needs attention. */
1908
+ export declare interface HealthFinding {
1909
+ readonly kind: 'noOwner' | 'reviewDue' | 'linksToUnpublished' | 'translationMissing' | 'translationOutdated';
1910
+ readonly contentType: string;
1911
+ readonly documentId: string;
1912
+ /** The language it concerns; null when it concerns the whole document. */
1913
+ readonly locale: string | null;
1914
+ /** The document's title in the source language (else any), for a list. */
1915
+ readonly title: string;
1916
+ /** `linksToUnpublished`: the fields holding the links; `translationOutdated`: the source fields changed since. */
1917
+ readonly detail: ReadonlyArray<string>;
364
1918
  }
365
1919
 
366
- /** Cap a string field's length. Past `value` the editor renders a textarea. */
367
- export declare const maxLength: (value: number) => FieldRefinement;
1920
+ export declare interface HealthOptions {
1921
+ readonly sourceLocale: string;
1922
+ /** Every language the site has, the source included. */
1923
+ readonly locales: ReadonlyArray<string>;
1924
+ readonly now?: Date;
1925
+ }
368
1926
 
369
- /** The media field names on a content type (top level) — handy for a
370
- * consumer that wants to know whether resolution is even needed. */
371
- export declare const mediaFields: (type: Pick<ContentType, "fields">) => ReadonlyArray<string>;
1927
+ export declare interface HtmlImportFinding {
1928
+ readonly kind: 'unsupportedTag' | 'externalLink' | 'image';
1929
+ /** The tag, the link's address or the image's source. */
1930
+ readonly detail: string;
1931
+ }
372
1932
 
373
- /**
374
- * Resolve a stored media KEY to a served URL. The app builds this from its
375
- * storage layer, e.g. `(key) => Effect.runPromise(storage.getUrl(key, { tenantId }))`
376
- * or, for an access-checked URL, `(key) => Effect.runPromise(storage.mintUrl(key, subject))`.
377
- * Returning `null` leaves the field as its stored key (unresolved).
378
- */
379
- export declare type MediaResolver = (key: string) => Promise<string | null>;
1933
+ export declare interface HtmlImportOptions {
1934
+ /** The document an address points to, or null when it is not one of ours. */
1935
+ readonly resolveLink?: (href: string) => string | null;
1936
+ /** The image asset document an image source became (an import that brought the file in), or null. */
1937
+ readonly resolveImage?: (src: string) => string | null;
1938
+ /** Block ids; defaults to a counter, so a test reads stable ids. */
1939
+ readonly newId?: () => string;
1940
+ }
380
1941
 
381
- /** Constrain a string field to a regex (source form, validated on save). */
382
- export declare const pattern: (re: RegExp) => FieldRefinement;
1942
+ export declare interface HtmlImportResult {
1943
+ readonly document: RichDocument;
1944
+ readonly findings: ReadonlyArray<HtmlImportFinding>;
1945
+ }
1946
+
1947
+ /** Effect form of {@link indexForSearch}. */
1948
+ export declare const indexForSearch: (...args: Parameters<typeof indexForSearch_2>) => Effect<void, never, never>;
1949
+
1950
+ /** Write a variant's text for one stage, in the caller's transaction. A type without `search` writes nothing. */
1951
+ declare const indexForSearch_2: (tx: DataStore, type: ContentType, row: Row, scope: CmsScope, stage: "draft" | "published") => Promise<void>;
1952
+
1953
+ /** Where an inherited value came from. */
1954
+ export declare interface Inherited {
1955
+ /** The value; undefined when neither the page nor an ancestor sets it. */
1956
+ readonly value: unknown;
1957
+ /** The document that set it: the page itself, an ancestor, or null for none. */
1958
+ readonly from: string | null;
1959
+ }
1960
+
1961
+ /**
1962
+ * The value of an inherited field for `node`: its own when set, else the
1963
+ * nearest ancestor's in `tree` (the same locale's variants the tree was built
1964
+ * from). Pass `{ ancestorsOnly: true }` for what the page would show without
1965
+ * its own value — the "reset to inherited" preview.
1966
+ */
1967
+ export declare const inheritedValue: (tree: CmsTree, node: TreeNode, field: string, options?: {
1968
+ readonly ancestorsOnly?: boolean;
1969
+ }) => Inherited;
1970
+
1971
+ /** How one inherited field may be set. */
1972
+ export declare interface InheritRule {
1973
+ /** No page may set the field; saving one that does is refused (`locked`). */
1974
+ readonly locked?: boolean;
1975
+ }
1976
+
1977
+ /** The minimal DOM a surface is read from (a browser element, or jsdom's). */
1978
+ export declare interface InlineDomNode {
1979
+ readonly nodeType: number;
1980
+ readonly nodeName: string;
1981
+ readonly textContent: string | null;
1982
+ readonly childNodes: ArrayLike<InlineDomNode>;
1983
+ getAttribute?(name: string): string | null;
1984
+ }
1985
+
1986
+ /**
1987
+ * Read a surface's DOM back into a run: text, `strong`/`b` as bold, `em`/`i` as
1988
+ * italic, `a[data-target]` as a link to that document, `br` as a line break.
1989
+ * Anything else a browser or a paste put there contributes its text only.
1990
+ */
1991
+ export declare const inlineFromDom: (root: InlineDomNode) => ReadonlyArray<RichInline>;
1992
+
1993
+ /** A run as the HTML a visual surface shows: `strong`, `em`, `u`, `a[data-target]`, escaped text. */
1994
+ export declare const inlineHtml: (content: ReadonlyArray<RichInline>) => string;
1995
+
1996
+ /** Inline nodes back to the editor's markup (the inverse of `parseInlineMarkup`). */
1997
+ export declare const inlineMarkupOf: (content: ReadonlyArray<RichInline>) => string;
1998
+
1999
+ /** The plain text of a run. */
2000
+ export declare const inlineText: (content: ReadonlyArray<RichInline>) => string;
2001
+
2002
+ /** An installed extension as the editor shows it. */
2003
+ export declare interface InstalledExtension {
2004
+ readonly extensionId: string;
2005
+ /** The version running now. */
2006
+ readonly manifest: CmsExtensionManifest;
2007
+ readonly granted: ReadonlyArray<ExtensionCapability>;
2008
+ /** A newer version waiting for consent, and what it would add. */
2009
+ readonly pending: {
2010
+ readonly manifest: CmsExtensionManifest;
2011
+ readonly adds: ReadonlyArray<ExtensionCapability>;
2012
+ } | null;
2013
+ /** The version a rollback returns to, or null. */
2014
+ readonly previous: CmsExtensionManifest | null;
2015
+ }
2016
+
2017
+ /** Effect form of {@link installedExtension}. */
2018
+ export declare const installedExtension: (...args: Parameters<typeof installedExtension_2>) => Effect<InstalledExtension | null, never, never>;
2019
+
2020
+ /** One installed extension, or null. */
2021
+ declare const installedExtension_2: (store: DataStore, extensionId: string) => Promise<InstalledExtension | null>;
2022
+
2023
+ /** Effect form of {@link installedExtensions}. */
2024
+ export declare const installedExtensions: (...args: Parameters<typeof installedExtensions_2>) => Effect<readonly InstalledExtension[], never, never>;
2025
+
2026
+ /** Every installed extension, by id. */
2027
+ declare const installedExtensions_2: (store: DataStore) => Promise<ReadonlyArray<InstalledExtension>>;
2028
+
2029
+ /** Effect form of {@link installExtension}. */
2030
+ export declare const installExtension: (...args: Parameters<typeof installExtension_2>) => Effect<ExtensionChange, never, never>;
2031
+
2032
+ /** Install `manifest`, granting it `consent` — which must cover every capability it asks for. */
2033
+ declare const installExtension_2: (tx: DataStore, manifest: CmsExtensionManifest, consent: ReadonlyArray<ExtensionCapability>) => Promise<ExtensionChange>;
2034
+
2035
+ /** Effect form of {@link invitedRole}. */
2036
+ export declare const invitedRole: (...args: Parameters<typeof invitedRole_2>) => Effect<string | null, never, never>;
2037
+
2038
+ /** The role `email` was invited with, or null. */
2039
+ declare const invitedRole_2: (store: DataStore, tenantId: string, email: string) => Promise<string | null>;
2040
+
2041
+ /** Effect form of {@link inviteToTeam}. */
2042
+ export declare const inviteToTeam: (...args: Parameters<typeof inviteToTeam_2>) => Effect<"present" | "changed" | "invited", never, never>;
2043
+
2044
+ /**
2045
+ * Invite `email` with `role`, in the caller's transaction: `invited` for a new
2046
+ * address, `changed` when it was invited with another role, `present` when
2047
+ * nothing changed. Check it with `teamProblems({ members: [{ email, role }] })` first.
2048
+ */
2049
+ declare const inviteToTeam_2: (tx: DataStore, tenantId: string, email: string, role: string) => Promise<"invited" | "changed" | "present">;
2050
+
2051
+ /** Whether `value` is a capability an extension can ask for. */
2052
+ export declare const isExtensionCapability: (value: string) => value is ExtensionCapability;
2053
+
2054
+ /** Whether `zone` is an IANA zone this runtime knows. */
2055
+ export declare const isKnownZone: (zone: string) => boolean;
2056
+
2057
+ /** Accept-Language → languages in order of preference (quality factors honoured). */
2058
+ export declare const languagesOf: (acceptLanguage: string | undefined) => ReadonlyArray<string>;
2059
+
2060
+ /** How often a type's documents are checked again, declared on the type. */
2061
+ export declare interface LifecycleConfig {
2062
+ /** Days from a publish or a recertification to the next review. */
2063
+ readonly reviewEveryDays: number;
2064
+ }
2065
+
2066
+ /**
2067
+ * List-view configuration for the consuming editor/template: which
2068
+ * columns its list page shows and the default sort. Validated by
2069
+ * `defineContentType` — every referenced name must be a declared field
2070
+ * or a lifecycle column, so a typo fails at definition time instead of
2071
+ * rendering an empty column.
2072
+ */
2073
+ export declare interface ListConfig {
2074
+ readonly columns: ReadonlyArray<string>;
2075
+ readonly defaultSort?: {
2076
+ readonly field: string;
2077
+ readonly dir: 'asc' | 'desc';
2078
+ };
2079
+ }
2080
+
2081
+ /** Effect form of {@link listExperiments}. */
2082
+ export declare const listExperiments: (...args: Parameters<typeof listExperiments_2>) => Effect<readonly Experiment[], never, never>;
2083
+
2084
+ /** Every experiment of the caller's tenant, newest first. */
2085
+ declare const listExperiments_2: (store: DataStore) => Promise<ReadonlyArray<Experiment>>;
2086
+
2087
+ /** Whether a (nested) list is numbered. */
2088
+ export declare type ListKind = 'ordered' | 'unordered';
2089
+
2090
+ /** Whether the list's items at `depth` (0: the top) are numbered. */
2091
+ export declare const listNumberedAt: (block: {
2092
+ readonly ordered: boolean;
2093
+ readonly sublists?: ReadonlyArray<ListKind>;
2094
+ }, depth: number) => boolean;
2095
+
2096
+ /** Effect form of {@link listPreviewShares}. */
2097
+ export declare const listPreviewShares: (...args: Parameters<typeof listPreviewShares_2>) => Effect<readonly Readonly<Record<string, unknown>>[], ContentNotFound | PreviewShareRejected, never>;
2098
+
2099
+ /** The caller's shares of one document (every variant), newest first. */
2100
+ declare const listPreviewShares_2: (store: DataStore, type: ContentType, documentId: string) => Promise<ReadonlyArray<Row>>;
2101
+
2102
+ /** Effect form of {@link listRedirects}. */
2103
+ export declare const listRedirects: (...args: Parameters<typeof listRedirects_2>) => Effect<readonly Readonly<Record<string, unknown>>[], never, never>;
2104
+
2105
+ /** Every redirect in `scope`, for inspection. */
2106
+ declare const listRedirects_2: (store: DataStore, type: string, scope: CmsScope) => Promise<ReadonlyArray<Row>>;
2107
+
2108
+ /** Effect form of {@link listReleaseItems}. */
2109
+ export declare const listReleaseItems: (...args: Parameters<typeof listReleaseItems_2>) => Effect<readonly Readonly<Record<string, unknown>>[], never, never>;
2110
+
2111
+ /** A release's entries in the order they apply. */
2112
+ declare const listReleaseItems_2: (store: DataStore, releaseId: string) => Promise<ReadonlyArray<Row>>;
2113
+
2114
+ /** Effect form of {@link listReleases}. */
2115
+ export declare const listReleases: (...args: Parameters<typeof listReleases_2>) => Effect<readonly Readonly<Record<string, unknown>>[], never, never>;
2116
+
2117
+ /** The releases of one site and environment, newest first. */
2118
+ declare const listReleases_2: (store: DataStore, where: {
2119
+ readonly site: string;
2120
+ readonly environment: string;
2121
+ }) => Promise<ReadonlyArray<Row>>;
2122
+
2123
+ /** Effect form of {@link listRevisions}. */
2124
+ export declare const listRevisions: (...args: Parameters<typeof listRevisions_2>) => Effect_2.Effect<readonly Readonly<Record<string, unknown>>[], never, never>;
2125
+
2126
+ /**
2127
+ * Every saved revision of one document's variant in `scope`, newest first.
2128
+ * Revisions are immutable: a later save or a restore appends, it never
2129
+ * rewrites.
2130
+ */
2131
+ declare const listRevisions_2: (store: DataStore, type: ContentType, documentId: string, scope: CmsScope) => Promise<ReadonlyArray<Row>>;
2132
+
2133
+ /** The texts a save materializes: those belonging to the draft's current revision. */
2134
+ export declare interface LiveDraftTexts {
2135
+ /** Field → the merged text. */
2136
+ readonly values: ReadonlyMap<string, string>;
2137
+ readonly rows: ReadonlyArray<Row>;
2138
+ }
2139
+
2140
+ /** Effect form of {@link liveDraftTexts}. */
2141
+ export declare const liveDraftTexts: (...args: Parameters<typeof liveDraftTexts_2>) => Effect<LiveDraftTexts, ContentNotFound, never>;
2142
+
2143
+ declare const liveDraftTexts_2: (store: DataStore, draft: Row) => Promise<LiveDraftTexts>;
2144
+
2145
+ /** One language's published page tree. */
2146
+ export declare interface LocalizedTree {
2147
+ readonly locale: string;
2148
+ readonly tree: CmsTree;
2149
+ }
2150
+
2151
+ /** What is wrong with a manifest; empty when nothing is. */
2152
+ export declare const manifestProblems: (manifest: CmsExtensionManifest) => ReadonlyArray<string>;
2153
+
2154
+ /** Whether the request's signals meet the rule. */
2155
+ export declare const matchesAudience: (rule: AudienceRule, signals: AudienceSignals) => boolean;
2156
+
2157
+ /** How a returned file's units line up with the source's: translated, left as source, unknown, and missing. */
2158
+ export declare const matchUnits: (source: ReadonlyArray<TranslationUnit>, returned: ReadonlyArray<TranslationUnit>) => {
2159
+ readonly translated: number;
2160
+ readonly untranslated: number;
2161
+ readonly unknown: ReadonlyArray<string>;
2162
+ readonly missing: ReadonlyArray<string>;
2163
+ };
2164
+
2165
+ /** The longest an exception may run. */
2166
+ export declare const MAX_EXCEPTION_DAYS = 90;
2167
+
2168
+ /** The deepest a list item may sit (0 is the top). */
2169
+ export declare const MAX_LIST_LEVEL = 3;
2170
+
2171
+ export declare const MAX_OCCURRENCES = 100;
2172
+
2173
+ /** The longest a preview link may live. */
2174
+ export declare const MAX_PREVIEW_SHARE_DAYS = 30;
2175
+
2176
+ /** Cap a string field's length. Past `value` the editor renders a textarea. */
2177
+ export declare const maxLength: (value: number) => FieldRefinement;
2178
+
2179
+ /** The media field names on a content type (top level) — handy for a
2180
+ * consumer that wants to know whether resolution is even needed. */
2181
+ export declare const mediaFields: (type: Pick<ContentType, "fields">) => ReadonlyArray<string>;
2182
+
2183
+ /**
2184
+ * Resolve a stored media KEY to a served URL. The app builds this from its
2185
+ * storage layer, e.g. `(key) => Effect.runPromise(storage.getUrl(key, { tenantId }))`
2186
+ * or, for an access-checked URL, `(key) => Effect.runPromise(storage.mintUrl(key, subject))`.
2187
+ * Returning `null` leaves the field as its stored key (unresolved).
2188
+ */
2189
+ export declare type MediaResolver = (key: string) => Promise<string | null>;
2190
+
2191
+ /** Adjacent text runs with the same marks become one; empty text runs go. */
2192
+ export declare const mergeInline: (content: ReadonlyArray<RichInline>) => ReadonlyArray<RichInline>;
2193
+
2194
+ /** Readers per version before a result is called at all. */
2195
+ export declare const MIN_READERS = 100;
2196
+
2197
+ /** Where this calendar month (UTC) began. */
2198
+ export declare const monthStart: (now?: Date) => Date;
2199
+
2200
+ /**
2201
+ * The fields a draft typed in together may have moved on in without anyone
2202
+ * losing an edit: the texts in `shared`, and every field derived from one of
2203
+ * them (a slug from its title).
2204
+ */
2205
+ export declare const movedTogether: (type: ContentType, shared: ReadonlySet<string>) => ReadonlySet<string>;
2206
+
2207
+ /** `list` with the entry at `from` moved to `to` (clamped); the same list when nothing moves. */
2208
+ export declare const moveEntry: <T>(list: ReadonlyArray<T>, from: number, to: number) => ReadonlyArray<T>;
2209
+
2210
+ /** A fresh block id. */
2211
+ export declare const newBlockId: () => string;
2212
+
2213
+ /** The capabilities `requested` asks for beyond `granted` — what needs a new consent. */
2214
+ export declare const newCapabilities: (granted: ReadonlyArray<ExtensionCapability>, requested: ReadonlyArray<ExtensionCapability>) => ReadonlyArray<ExtensionCapability>;
2215
+
2216
+ /** A nonce for one editing session (unguessable; 128 bits). */
2217
+ export declare const newVisualNonce: () => string;
2218
+
2219
+ /**
2220
+ * The canonical form of a stored value: a plain string becomes paragraphs (a
2221
+ * blank line starts a new one), a document keeps its blocks and gets an id on
2222
+ * every block that lacks one, anything else is returned as is for the
2223
+ * validator to reject.
2224
+ */
2225
+ export declare const normalizeRichDocument: (value: unknown) => unknown;
2226
+
2227
+ /** The vocabulary's terms for `input`, in first-seen order, and what it does not know. */
2228
+ export declare const normalizeTerms: (config: Pick<TaxonomyConfig, "terms">, input: ReadonlyArray<unknown>) => {
2229
+ readonly terms: ReadonlyArray<string>;
2230
+ readonly unknown: ReadonlyArray<string>;
2231
+ };
2232
+
2233
+ export declare interface Occurrence {
2234
+ /** Its position in the series, from 0 (counting excepted ones). */
2235
+ readonly index: number;
2236
+ /** The local wall time it was meant for. */
2237
+ readonly local: string;
2238
+ readonly startsAt: Date;
2239
+ readonly endsAt: Date;
2240
+ /** `gap`: the wall time did not exist, moved after it; `fold`: it existed twice, the first; `clamped`: the month had no such day. */
2241
+ readonly adjusted?: 'gap' | 'fold' | 'clamped';
2242
+ }
2243
+
2244
+ /** The occurrences of a rule, in order; throws `RangeError` for a rule with problems. */
2245
+ export declare const occurrencesOf: (rule: RecurrenceRule) => ReadonlyArray<Occurrence>;
2246
+
2247
+ /** Effect form of {@link openDraftTexts}. */
2248
+ export declare const openDraftTexts: (...args: Parameters<typeof openDraftTexts_2>) => Effect<readonly Readonly<Record<string, unknown>>[], ContentNotFound, never>;
2249
+
2250
+ /**
2251
+ * Start typing together in a draft: every collaborative field gets a text
2252
+ * that belongs to the draft's current revision — kept where there is one,
2253
+ * started from the draft's value where there is none or where the draft moved
2254
+ * on without it. Idempotent; two editors opening at once end with one text per
2255
+ * field. `ContentNotFound` for a draft the caller cannot see. In the caller's
2256
+ * transaction.
2257
+ */
2258
+ declare const openDraftTexts_2: (tx: DataStore, type: ContentType, draftId: string) => Promise<ReadonlyArray<Row>>;
2259
+
2260
+ /** Where a document lives in one language. */
2261
+ export declare interface PageAlternate {
2262
+ readonly locale: string;
2263
+ readonly path: string;
2264
+ }
2265
+
2266
+ /** One template a content type offers. */
2267
+ export declare interface PageTemplate {
2268
+ /** Stable id, stored on the document. */
2269
+ readonly id: string;
2270
+ readonly displayName: string;
2271
+ /** Field values a new document starts with (e.g. a layout). */
2272
+ readonly values?: Readonly<Record<string, unknown>>;
2273
+ /** The components a new document starts with, in order. */
2274
+ readonly sections?: ReadonlyArray<{
2275
+ readonly component: ComponentDefinition;
2276
+ readonly props?: Readonly<Record<string, unknown>>;
2277
+ }>;
2278
+ /** Components the document must always hold at least once. */
2279
+ readonly required?: ReadonlyArray<ComponentDefinition>;
2280
+ /** The component that must come first. */
2281
+ readonly first?: ComponentDefinition;
2282
+ /** The most of one component the document may hold. */
2283
+ readonly max?: ReadonlyArray<{
2284
+ readonly component: ComponentDefinition;
2285
+ readonly count: number;
2286
+ }>;
2287
+ }
2288
+
2289
+ /** Parse the editor's inline markup into inline nodes. Unclosed markers stay text. */
2290
+ export declare const parseInlineMarkup: (input: string) => ReadonlyArray<RichInline>;
2291
+
2292
+ /** `sections.2` → `{ field: 'sections', index: 2 }`; `title` → `{ field: 'title' }`. */
2293
+ export declare const parseSourcePath: (path: string) => {
2294
+ readonly field: string;
2295
+ readonly index?: number;
2296
+ };
2297
+
2298
+ /** Read an XLIFF 2.x file with one `<file>`: languages, notes and each unit's source and target. */
2299
+ export declare const parseXliff: (xml: string) => XliffExchange;
2300
+
2301
+ /** Constrain a string field to a regex (source form, validated on save). */
2302
+ export declare const pattern: (re: RegExp) => FieldRefinement;
2303
+
2304
+ /** The first variant whose audience matches, or null for the original. Variants naming an unknown audience never match. */
2305
+ export declare const pickVariant: <V extends {
2306
+ readonly audience: string;
2307
+ }>(variants: ReadonlyArray<V>, audiences: ReadonlyArray<Audience>, signals: AudienceSignals) => V | null;
2308
+
2309
+ export declare interface PipeableField extends FieldSchema {
2310
+ readonly isOptional: boolean;
2311
+ pipe(...refinements: ReadonlyArray<FieldRefinement>): PipeableField;
2312
+ /** Mark the field optional → nullable column + non-required editor input. */
2313
+ optional(): PipeableField;
2314
+ /**
2315
+ * Let a draft be saved without it, and refuse to publish until it is set —
2316
+ * an image uploaded in bulk before anyone wrote its alt text. The column is
2317
+ * nullable, like `optional()`.
2318
+ */
2319
+ requiredToPublish(): PipeableField;
2320
+ }
2321
+
2322
+ declare type Place = Pick<CmsScope, 'site' | 'environment'>;
2323
+
2324
+ declare type Place_2 = Pick<CmsScope, 'site' | 'environment'>;
2325
+
2326
+ /** The document's text, one line per block — for excerpts and search. */
2327
+ export declare const plainTextOf: (doc: RichDocument) => string;
2328
+
2329
+ /** Effect form of {@link planBlueprint}. */
2330
+ export declare const planBlueprint: (...args: Parameters<typeof planBlueprint_2>) => Effect<BlueprintPlan, ContentValidationFailed | ContentNotFound | ContentIdConflict | RevisionMismatch | ReviewRequired | ReferenceUnavailable | BlueprintInvalid, never>;
2331
+
2332
+ /**
2333
+ * What provisioning `blueprint` into `target` would do, step by step: which
2334
+ * documents the workspace has already and which would be created (and
2335
+ * whether published). Reads only. Throws `BlueprintInvalid` when an entry
2336
+ * names a type, field or template the app does not have.
2337
+ */
2338
+ declare const planBlueprint_2: (store: DataStore, types: ReadonlyArray<ContentType>, blueprint: Blueprint, target: BlueprintTarget) => Promise<BlueprintPlan>;
2339
+
2340
+ /** Effect form of {@link planBlueprintTeam}. */
2341
+ export declare const planBlueprintTeam: (...args: Parameters<typeof planBlueprintTeam_2>) => Effect<TeamPlan, never, never>;
2342
+
2343
+ /** What provisioning the team would do. Reads only. */
2344
+ declare const planBlueprintTeam_2: (store: DataStore, tenantId: string, team: BlueprintTeam) => Promise<TeamPlan>;
2345
+
2346
+ /** Effect form of {@link planBulk}. */
2347
+ export declare const planBulk: (...args: Parameters<typeof planBulk_2>) => Effect<readonly PlannedItem[], ContentValidationFailed | ContentNotFound | ContentIdConflict | RevisionMismatch | ReviewRequired | ReferenceUnavailable, never>;
2348
+
2349
+ /** The dry run: what `action` would do to each item, changing nothing. */
2350
+ declare const planBulk_2: (store: DataStore, types: ReadonlyArray<ContentType>, place: Place, action: BulkAction, items: ReadonlyArray<BulkItem>) => Promise<ReadonlyArray<PlannedItem>>;
2351
+
2352
+ export declare interface PlannedItem extends BulkItem {
2353
+ readonly documentId: string | null;
2354
+ readonly title: string;
2355
+ /** For a publish: the revision the dry run saw, which the run publishes. */
2356
+ readonly revisionId: string | null;
2357
+ readonly disposition: 'ready' | 'unchanged' | 'blocked';
2358
+ readonly reason: BlockReason | null;
2359
+ /** For `referenceUnavailable`: the fields and why (`sections[0].props.image: blocked`); for
2360
+ * `incomplete`: the empty fields publishing needs. */
2361
+ readonly detail: ReadonlyArray<string>;
2362
+ }
2363
+
2364
+ /** Effect form of {@link planPromotion}. */
2365
+ export declare const planPromotion: (...args: Parameters<typeof planPromotion_2>) => Effect<readonly PromotionItem[], ContentValidationFailed | ContentNotFound | ContentIdConflict | RevisionMismatch | ReleaseNotEditable | ReviewRequired | ReferenceUnavailable, never>;
2366
+
2367
+ /** What promoting `from` into `to` would change, per document and language. */
2368
+ declare const planPromotion_2: (store: DataStore, types: ReadonlyArray<ContentType>, pair: EnvironmentPair) => Promise<ReadonlyArray<PromotionItem>>;
2369
+
2370
+ /** A verified preview claim. */
2371
+ export declare interface PreviewClaim {
2372
+ readonly type: string;
2373
+ readonly id: string;
2374
+ }
2375
+
2376
+ /** What the preview sends the editor. `path` is a field (`title`) or a component (`sections.2`). */
2377
+ export declare type PreviewMessage = {
2378
+ readonly protocol: typeof VISUAL_EDITING_PROTOCOL;
2379
+ readonly nonce: string;
2380
+ readonly kind: 'ready';
2381
+ } | {
2382
+ readonly protocol: typeof VISUAL_EDITING_PROTOCOL;
2383
+ readonly nonce: string;
2384
+ readonly kind: 'select';
2385
+ readonly path: string;
2386
+ } | {
2387
+ readonly protocol: typeof VISUAL_EDITING_PROTOCOL;
2388
+ readonly nonce: string;
2389
+ readonly kind: 'move';
2390
+ readonly path: string;
2391
+ readonly to: number;
2392
+ };
2393
+
2394
+ /**
2395
+ * Raised by `createPreviewShare` when the requested expiry is not in the
2396
+ * future or lies beyond the longest a preview link may live.
2397
+ */
2398
+ export declare class PreviewShareRejected extends PreviewShareRejected_base {
2399
+ }
2400
+
2401
+ declare const PreviewShareRejected_base: Schema_2.TaggedErrorClass<PreviewShareRejected, "PreviewShareRejected", {
2402
+ readonly _tag: Schema_2.tag<"PreviewShareRejected">;
2403
+ } & {
2404
+ reason: Schema_2.Literal<["expiryInPast", "expiryTooFar"]>;
2405
+ }>;
2406
+
2407
+ /** Mint a signed preview token for a draft row. */
2408
+ export declare const previewToken: (type: string, id: string, options?: {
2409
+ ttlSeconds?: number;
2410
+ secret?: string;
2411
+ }) => string;
2412
+
2413
+ /** Effect form of {@link promote}. */
2414
+ export declare const promote: (...args: Parameters<typeof promote_2>) => Effect<PromotionResult, ContentValidationFailed | ContentNotFound | ContentIdConflict | RevisionMismatch | ReleaseNotEditable | ReviewRequired | ReferenceUnavailable, never>;
2415
+
2416
+ /**
2417
+ * Promote the chosen documents from `pair.from` into `pair.to` as one release
2418
+ * named `name`. Refuses (writing nothing) when an item is blocked, or not in
2419
+ * the plan (not live in `from`, or live there unchanged); a failing check inside the release (review, availability,
2420
+ * required fields) throws like any release publish — run it in a transaction.
2421
+ */
2422
+ declare const promote_2: (tx: DataStore, types: ReadonlyArray<ContentType>, pair: EnvironmentPair, selections: ReadonlyArray<PromotionSelection>, options: {
2423
+ readonly name: string;
2424
+ }) => Promise<PromotionResult>;
2425
+
2426
+ export declare interface PromotionItem {
2427
+ readonly contentType: string;
2428
+ readonly documentId: string;
2429
+ readonly locale: string;
2430
+ readonly title: string;
2431
+ readonly change: 'new' | 'changed' | 'blocked';
2432
+ }
2433
+
2434
+ export declare type PromotionResult = {
2435
+ readonly ok: true;
2436
+ readonly releaseId: string;
2437
+ readonly promoted: number;
2438
+ } | {
2439
+ readonly ok: false;
2440
+ readonly reason: 'nothingSelected' | 'blocked' | 'notInPlan';
2441
+ readonly items: ReadonlyArray<PromotionSelection>;
2442
+ };
2443
+
2444
+ export declare interface PromotionSelection {
2445
+ readonly contentType: string;
2446
+ readonly documentId: string;
2447
+ readonly locale: string;
2448
+ }
2449
+
2450
+ /** The hash an operation keeps of its prompt: enough to tell two prompts apart, nothing to read back. */
2451
+ export declare const promptHash: (prompt: string) => string;
2452
+
2453
+ /** Effect-native `publish` (see {@link saveDraftEffect}). */
2454
+ export declare const publish: (store: DataStore, type: ContentType, id: string, scope: CmsScope, options?: PublishOptions) => Effect_2.Effect<Row, ContentNotFound | RevisionMismatch | ReviewRequired | ReferenceUnavailable | ContentValidationFailed>;
2455
+
2456
+ /** Effect form of {@link publishDue}. */
2457
+ export declare const publishDue: (...args: Parameters<typeof publishDue_2>) => Effect<readonly string[], never, never>;
2458
+
2459
+ /**
2460
+ * Publish every draft of `type` whose scheduled `publishAt` has passed
2461
+ * (and that is still a draft). Returns the ids that were published. A
2462
+ * driver calls this on an interval from a `*.cron.tsx` schedule (see the
2463
+ * README/docs recipe) — it is idempotent: `publish` flips the draft
2464
+ * `status` to `'published'`, so a row is never double-published, and
2465
+ * `publishAt` is cleared so a later re-save doesn't spuriously re-fire.
2466
+ *
2467
+ * Runs over the store it is handed: a request-scoped store publishes one
2468
+ * tenant's due drafts; a background/root store sweeps every tenant. It opens
2469
+ * one transaction per row, so hand it a store that is NOT already inside a
2470
+ * transaction (a schedule's `app.store`, not a mutation's `ctx.store`).
2471
+ */
2472
+ declare const publishDue_2: (store: DataStore, type: ContentType, now?: Date) => Promise<ReadonlyArray<string>>;
2473
+
2474
+ /** Effect form of {@link publishDueReleases} — a failing release is marked `failed`, never an error. */
2475
+ export declare const publishDueReleases: (...args: Parameters<typeof publishDueReleases_2>) => Effect<readonly string[], never, never>;
2476
+
2477
+ /**
2478
+ * Take every scheduled release that is due live, each in its own transaction.
2479
+ * A release is CLAIMED by a conditional update (`scheduled` → a fresh fencing
2480
+ * token) inside that transaction, so a second scheduler run — another replica,
2481
+ * a retry — finds nothing to take. A release that fails is marked `failed`
2482
+ * with the reason and its pinned content stays as it was. Returns the ids
2483
+ * that went live. Hand it a store outside any transaction (a schedule's
2484
+ * `app.store`).
2485
+ */
2486
+ declare const publishDueReleases_2: (store: DataStore, types: ReadonlyArray<ContentType>, now?: Date) => Promise<ReadonlyArray<string>>;
2487
+
2488
+ /** Options for {@link publish}. */
2489
+ export declare interface PublishOptions {
2490
+ /** Publish only if the draft still points at THIS revision — the one the
2491
+ * editor reviewed. A newer save in between throws `RevisionMismatch`
2492
+ * instead of publishing content nobody looked at. */
2493
+ readonly revisionId?: string;
2494
+ }
2495
+
2496
+ /** Effect form of {@link publishRelease}. */
2497
+ export declare const publishRelease: (...args: Parameters<typeof publishRelease_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound | ReleaseNotEditable | ReviewRequired | ReferenceUnavailable, never>;
2498
+
2499
+ /**
2500
+ * Publish every entry of a release — in the CALLER'S transaction, so either
2501
+ * all of them go live or, when one fails, none does. Records what each variant
2502
+ * showed before (for rollback) and marks the release `published`. Throws
2503
+ * `ReleaseNotEditable` for a release that is already published or failed.
2504
+ */
2505
+ declare const publishRelease_2: (tx: DataStore, types: ReadonlyArray<ContentType>, releaseId: string, now?: Date) => Promise<Row>;
2506
+
2507
+ /** Effect-native `publishRevision` (see {@link saveDraftEffect}). */
2508
+ export declare const publishRevision: (tx: DataStore, type: ContentType, id: string, scope: CmsScope, revisionId: string, origin?: ChangeOrigin) => Effect_2.Effect<Row, ContentNotFound | RevisionMismatch | ReviewRequired | ReferenceUnavailable | ContentValidationFailed>;
2509
+
2510
+ /** A series as the editor shows it. */
2511
+ export declare interface PublishSeries {
2512
+ readonly id: string;
2513
+ readonly rule: RecurrenceRule;
2514
+ readonly occurrences: ReadonlyArray<Occurrence>;
2515
+ /** The index (into `occurrences`) armed on the draft now, or -1. */
2516
+ readonly armed: number;
2517
+ readonly state: 'running' | 'done';
2518
+ }
2519
+
2520
+ /**
2521
+ * What stops these values from being published: every `requiredToPublish()`
2522
+ * field that is empty (absent, null, or a blank string). Browser-safe, so an
2523
+ * editor can say so before the publish is refused.
2524
+ */
2525
+ export declare const publishViolations: (type: Pick<ContentType, "fields">, values: Readonly<Record<string, unknown>>) => ReadonlyArray<FieldViolation>;
2526
+
2527
+ /** The purposes the components of `type` need, for a banner to ask about. */
2528
+ export declare const purposesUsedBy: (type: {
2529
+ readonly fields: Readonly<Record<string, FieldSchema>>;
2530
+ }) => ReadonlySet<string>;
2531
+
2532
+ export declare interface QualityException {
2533
+ readonly id: string;
2534
+ readonly ruleId: string;
2535
+ readonly reason: string;
2536
+ readonly state: ExceptionState;
2537
+ readonly requestedBy: string;
2538
+ readonly requestedAt: Date;
2539
+ readonly decidedBy: string | null;
2540
+ readonly note: string | null;
2541
+ readonly expiresAt: Date;
2542
+ }
2543
+
2544
+ /** Effect form of {@link qualityExceptions}. */
2545
+ export declare const qualityExceptions: (...args: Parameters<typeof qualityExceptions_2>) => Effect<readonly QualityException[], never, never>;
2546
+
2547
+ /** Every exception asked for on a variant, newest first, with its state today. */
2548
+ declare const qualityExceptions_2: (store: DataStore, type: ContentType, variantId: string, scope: CmsScope, now?: Date) => Promise<ReadonlyArray<QualityException>>;
2549
+
2550
+ export declare interface QualityFinding {
2551
+ readonly ruleId: string;
2552
+ readonly field: string;
2553
+ readonly message: string;
2554
+ readonly blocking: boolean;
2555
+ }
2556
+
2557
+ /** What a type's rules find in these values — pure, for the editor as for the gate. */
2558
+ export declare const qualityFindings: (type: Pick<ContentType, "quality">, values: Readonly<Record<string, unknown>>) => ReadonlyArray<QualityFinding>;
2559
+
2560
+ /** One quality check of a type — see `ContentTypeSpec.quality`. */
2561
+ export declare interface QualityRule {
2562
+ /** Stable id (letters, digits, `.`, `-`), unique in the type — exceptions name it. */
2563
+ readonly id: string;
2564
+ /** The field that causes the finding and where it is repaired. */
2565
+ readonly field: string;
2566
+ /** What is wrong, in the editor's words. */
2567
+ readonly message: string;
2568
+ /** Whether publishing waits for a repair or an approved exception. Default true. */
2569
+ readonly blocking?: boolean;
2570
+ /** True when the values have the finding. Pure. */
2571
+ readonly check: (values: Readonly<Record<string, unknown>>) => boolean;
2572
+ }
2573
+
2574
+ /** Effect form of {@link qualityViolations}. */
2575
+ export declare const qualityViolations: (...args: Parameters<typeof qualityViolations_2>) => Effect<readonly FieldViolation[], never, never>;
2576
+
2577
+ /**
2578
+ * The publish gate: blocking findings in `values` without an approved,
2579
+ * unexpired exception, as violations (`rule: quality.<id>`). Empty for a type
2580
+ * without rules — no read at all.
2581
+ */
2582
+ declare const qualityViolations_2: (store: DataStore, type: ContentType, variantId: string, scope: CmsScope, values: Readonly<Record<string, unknown>>, now?: Date) => Promise<ReadonlyArray<FieldViolation>>;
2583
+
2584
+ /**
2585
+ * Raised when a create would take a tenant past a limit its app set — more
2586
+ * documents, keys or environments than it may hold. Nothing was written;
2587
+ * `used` is what the tenant holds now.
2588
+ */
2589
+ export declare class QuotaExceeded extends QuotaExceeded_base {
2590
+ }
2591
+
2592
+ declare const QuotaExceeded_base: Schema_2.TaggedErrorClass<QuotaExceeded, "QuotaExceeded", {
2593
+ readonly _tag: Schema_2.tag<"QuotaExceeded">;
2594
+ } & {
2595
+ quota: typeof Schema_2.String;
2596
+ limit: typeof Schema_2.Number;
2597
+ used: typeof Schema_2.Number;
2598
+ }>;
2599
+
2600
+ /** Effect form of {@link readChanges}. */
2601
+ export declare const readChanges: (...args: Parameters<typeof readChanges_2>) => Effect<{
2602
+ readonly items: ReadonlyArray<ChangeEntry>;
2603
+ readonly next: string | null;
2604
+ }, never, never>;
2605
+
2606
+ /**
2607
+ * The changes in a site and environment after `after`, oldest first. Keep
2608
+ * `next` and pass it as `after` next time; it stays put when nothing new has
2609
+ * settled, so polling with it never skips.
2610
+ */
2611
+ declare const readChanges_2: (store: DataStore, place: Pick<CmsScope, "site" | "environment">, options?: ReadChangesOptions) => Promise<{
2612
+ readonly items: ReadonlyArray<ChangeEntry>;
2613
+ readonly next: string | null;
2614
+ }>;
2615
+
2616
+ export declare interface ReadChangesOptions {
2617
+ /** The `next` of the previous read; omit to start at the beginning. */
2618
+ readonly after?: string;
2619
+ /** At most this many (default 100). */
2620
+ readonly limit?: number;
2621
+ /** Leave out changes younger than this (default 2000 ms) — see the file header. */
2622
+ readonly settleMs?: number;
2623
+ /** Equality filters, e.g. the tenant for a reader that carries none. */
2624
+ readonly filter?: Readonly<Record<string, unknown>>;
2625
+ readonly now?: number;
2626
+ }
2627
+
2628
+ /** Effect form of {@link readDraftTexts}. */
2629
+ export declare const readDraftTexts: (...args: Parameters<typeof readDraftTexts_2>) => Effect<readonly Readonly<Record<string, unknown>>[], ContentNotFound, never>;
2630
+
2631
+ /** The text rows of a draft, whatever revision they belong to. */
2632
+ declare const readDraftTexts_2: (store: DataStore, draftId: string) => Promise<ReadonlyArray<Row>>;
2633
+
2634
+ /** The editor's message, or null for anything else. */
2635
+ export declare const readEditorMessage: (event: VisualMessageEvent, session: VisualSession) => EditorMessage | null;
2636
+
2637
+ /** The preview's message, or null for anything else (another origin, another session, another shape). */
2638
+ export declare const readPreviewMessage: (event: VisualMessageEvent, session: VisualSession) => PreviewMessage | null;
2639
+
2640
+ /** Effect form of {@link rebaseDraftTexts}. */
2641
+ export declare const rebaseDraftTexts: (...args: Parameters<typeof rebaseDraftTexts_2>) => Effect<void, ContentNotFound, never>;
2642
+
2643
+ /** After a save: the texts belong to the new revision. In the caller's transaction. */
2644
+ declare const rebaseDraftTexts_2: (tx: DataStore, rows: ReadonlyArray<Row>, revisionId: string) => Promise<void>;
2645
+
2646
+ /** Effect form of {@link rebuildSearch}. */
2647
+ export declare const rebuildSearch: (...args: Parameters<typeof rebuildSearch_2>) => Effect<number, never, never>;
2648
+
2649
+ /**
2650
+ * Index every variant of a type again from its derived tables — for content
2651
+ * written before the type declared `search`, or after the search rules
2652
+ * changed. Runs over the store it is handed: a request store rebuilds one
2653
+ * tenant, the root store all of them. Returns how many rows it wrote.
2654
+ */
2655
+ declare const rebuildSearch_2: (store: DataStore, type: ContentType) => Promise<number>;
2656
+
2657
+ /** Effect form of {@link recertify}. */
2658
+ export declare const recertify: (...args: Parameters<typeof recertify_2>) => Effect<Stewardship, never, never>;
2659
+
2660
+ /**
2661
+ * Record that `by` checked `revisionId` of the document and it is still
2662
+ * right: the next review is `reviewEveryDays` from `now` (none when the type
2663
+ * declares no cycle).
2664
+ */
2665
+ declare const recertify_2: (store: DataStore, type: ContentType, documentId: string, place: Place_2, options: {
2666
+ readonly revisionId: string;
2667
+ readonly by: string;
2668
+ readonly now?: Date;
2669
+ }) => Promise<Stewardship>;
2670
+
2671
+ /** Effect form of {@link recordAiOperation}. */
2672
+ export declare const recordAiOperation: (...args: Parameters<typeof recordAiOperation_2>) => Effect<string, never, never>;
2673
+
2674
+ /** Record one call, in the caller's transaction; its id. */
2675
+ declare const recordAiOperation_2: (tx: DataStore, input: AiOperationInput) => Promise<string>;
2676
+
2677
+ /** Effect form of {@link recordChange}. */
2678
+ export declare const recordChange: (...args: Parameters<typeof recordChange_2>) => Effect<void, never, never>;
2679
+
2680
+ /** Append one change, in the caller's transaction. A type without `changeFeed` writes nothing. */
2681
+ declare const recordChange_2: (tx: DataStore, type: ContentType, row: Row, scope: CmsScope, action: "published" | "unpublished", origin?: ChangeOrigin) => Promise<void>;
2682
+
2683
+ /**
2684
+ * Record a change: `before` is the form as it was. A change with the same key
2685
+ * within `mergeMs` of the last step continues it (typing is one step). The
2686
+ * redo branch goes; at most `limit` steps are kept.
2687
+ */
2688
+ export declare const recordEdit: (history: EditHistory, before: Readonly<Record<string, unknown>>, edit: EditDescription, at: number, options?: {
2689
+ readonly mergeMs?: number;
2690
+ readonly limit?: number;
2691
+ }) => EditHistory;
2692
+
2693
+ /** Effect form of {@link recordExperimentEvent}. */
2694
+ export declare const recordExperimentEvent: (...args: Parameters<typeof recordExperimentEvent_2>) => Effect<boolean, never, never>;
2695
+
2696
+ /**
2697
+ * Count a reader once per kind: `exposure` when they were shown the page,
2698
+ * `conversion` when they reached the goal. Only while the experiment runs; a
2699
+ * conversion only after an exposure (a reader who never saw a version cannot
2700
+ * be converted by it). Returns whether this call counted.
2701
+ */
2702
+ declare const recordExperimentEvent_2: (store: DataStore, experiment: Experiment, readerId: string, kind: "exposure" | "conversion", now?: Date) => Promise<boolean>;
2703
+
2704
+ /** Effect form of {@link recordPaths}. */
2705
+ export declare const recordPaths: (...args: Parameters<typeof recordPaths_2>) => Effect<void, never, never>;
2706
+
2707
+ /**
2708
+ * Record the paths of a tree type's published documents in `scope` — or, for
2709
+ * a type with an `address` field, each document's address — turning every
2710
+ * changed one into a redirect. Runs after a publish or unpublish, in the
2711
+ * caller's transaction. A type with neither is left alone.
2712
+ */
2713
+ declare const recordPaths_2: (tx: DataStore, type: ContentType, scope: CmsScope, tenantId: unknown) => Promise<void>;
2714
+
2715
+ export declare type RecurrenceEvery = 'day' | 'week' | 'month';
2716
+
2717
+ /** What is wrong with a rule, in words; empty when it can be scheduled. */
2718
+ export declare const recurrenceProblems: (rule: RecurrenceRule) => ReadonlyArray<string>;
2719
+
2720
+ export declare interface RecurrenceRule {
2721
+ /** The first occurrence, as a local wall time: `YYYY-MM-DDTHH:mm`. */
2722
+ readonly start: string;
2723
+ /** The IANA zone the wall time is in (`Europe/Berlin`). */
2724
+ readonly zone: string;
2725
+ readonly every: RecurrenceEvery;
2726
+ /** Every how many days / weeks / months (default 1). */
2727
+ readonly interval?: number;
2728
+ /** How many positions the series has (1–100); an excepted one is left out. */
2729
+ readonly count: number;
2730
+ /** How long each occurrence is live, in minutes; shorter than one step. */
2731
+ readonly durationMinutes: number;
2732
+ /** Local dates (`YYYY-MM-DD`) that are left out. */
2733
+ readonly except?: ReadonlyArray<string>;
2734
+ }
2735
+
2736
+ /** Effect form of {@link redirectTarget}. */
2737
+ export declare const redirectTarget: (...args: Parameters<typeof redirectTarget_2>) => Effect<string | null, never, never>;
2738
+
2739
+ /** The document a former `path` now points at in `scope` (and `tenantId`, when given), or null. */
2740
+ declare const redirectTarget_2: (store: DataStore, type: string, path: string, scope: CmsScope, tenantId?: unknown) => Promise<string | null>;
2741
+
2742
+ /** Redo the step undone last; null when there is nothing to redo. */
2743
+ export declare const redoEdit: (history: EditHistory, current: Readonly<Record<string, unknown>>) => {
2744
+ readonly history: EditHistory;
2745
+ readonly values: Readonly<Record<string, unknown>>;
2746
+ readonly label: string;
2747
+ } | null;
2748
+
2749
+ /** A reference found in a variant's values. */
2750
+ export declare interface ReferenceOccurrence {
2751
+ readonly path: string;
2752
+ readonly targetType: string;
2753
+ readonly targetDocumentId: string;
2754
+ }
2755
+
2756
+ /** Every reference the values make, by the content type's declared fields. */
2757
+ export declare const referencesOf: (type: ContentType, values: Readonly<Record<string, unknown>>) => ReadonlyArray<ReferenceOccurrence>;
2758
+
2759
+ /**
2760
+ * Raised when a revision references documents that may not be used — blocked
2761
+ * or past their availability — naming each and where it is referenced.
2762
+ */
2763
+ export declare class ReferenceUnavailable extends ReferenceUnavailable_base {
2764
+ }
2765
+
2766
+ declare const ReferenceUnavailable_base: Schema_2.TaggedErrorClass<ReferenceUnavailable, "ReferenceUnavailable", {
2767
+ readonly _tag: Schema_2.tag<"ReferenceUnavailable">;
2768
+ } & {
2769
+ contentType: typeof Schema_2.String;
2770
+ id: typeof Schema_2.String;
2771
+ targets: Schema_2.Array$<Schema_2.Struct<{
2772
+ path: typeof Schema_2.String;
2773
+ contentType: typeof Schema_2.String;
2774
+ documentId: typeof Schema_2.String;
2775
+ reason: Schema_2.Literal<["blocked", "expired"]>;
2776
+ }>>;
2777
+ }>;
2778
+
2779
+ /** One live use of a document. */
2780
+ export declare interface ReferenceUse {
2781
+ readonly sourceType: string;
2782
+ readonly sourceDocumentId: string;
2783
+ readonly sourceVariantId: string;
2784
+ readonly locale: string;
2785
+ readonly path: string;
2786
+ }
2787
+
2788
+ /** Effect form of {@link regrantExtension}. */
2789
+ export declare const regrantExtension: (...args: Parameters<typeof regrantExtension_2>) => Effect<ExtensionChange, never, never>;
2790
+
2791
+ /** Grant a revoked extension again — `consent` must cover everything its version asks for. */
2792
+ declare const regrantExtension_2: (tx: DataStore, extensionId: string, consent: ReadonlyArray<ExtensionCapability>) => Promise<ExtensionChange>;
2793
+
2794
+ /** The lifecycle of a release. */
2795
+ export declare const RELEASE_STATUSES: readonly ["draft", "scheduled", "published", "failed"];
2796
+
2797
+ /**
2798
+ * Raised when a release is asked to change in a state that does not allow it:
2799
+ * adding to or scheduling a release that is no longer a draft, publishing one
2800
+ * that is already published or failed, rolling back one that is not published.
2801
+ */
2802
+ export declare class ReleaseNotEditable extends ReleaseNotEditable_base {
2803
+ }
2804
+
2805
+ declare const ReleaseNotEditable_base: Schema_2.TaggedErrorClass<ReleaseNotEditable, "ReleaseNotEditable", {
2806
+ readonly _tag: Schema_2.tag<"ReleaseNotEditable">;
2807
+ } & {
2808
+ id: typeof Schema_2.String;
2809
+ status: typeof Schema_2.String;
2810
+ }>;
2811
+
2812
+ export declare type ReleaseStatus = (typeof RELEASE_STATUSES)[number];
2813
+
2814
+ /** Effect form of {@link releaseStatusOf}. */
2815
+ export declare const releaseStatusOf: (...args: Parameters<typeof releaseStatusOf_2>) => Effect<string | null, never, never>;
2816
+
2817
+ /** A release's status (`draft`, `scheduled`, `published`, …), or null when there is none of that id. */
2818
+ declare const releaseStatusOf_2: (store: DataStore, releaseId: string) => Promise<string | null>;
2819
+
2820
+ /** Effect form of {@link removeGlossaryTerm}. */
2821
+ export declare const removeGlossaryTerm: (...args: Parameters<typeof removeGlossaryTerm_2>) => Effect<boolean, never, never>;
2822
+
2823
+ /** Remove an entry; false when there was none in this workspace. */
2824
+ declare const removeGlossaryTerm_2: (tx: DataStore, tenantId: string, entryId: string) => Promise<boolean>;
2825
+
2826
+ /** Effect form of {@link removeRedirect}. */
2827
+ export declare const removeRedirect: (...args: Parameters<typeof removeRedirect_2>) => Effect<boolean, never, never>;
2828
+
2829
+ /**
2830
+ * Remove the redirect from `fromPath` in `scope`. True when there was one. A
2831
+ * page that had the address and is no longer live still answers it as gone
2832
+ * (`goneAt`). In the caller's transaction.
2833
+ */
2834
+ declare const removeRedirect_2: (tx: DataStore, type: ContentType, scope: CmsScope, fromPath: string) => Promise<boolean>;
2835
+
2836
+ /**
2837
+ * Replace the text in `[start, end)` with `text` (a paste, a typed line
2838
+ * break). It takes the marks of the first character it replaces, or — where
2839
+ * nothing is selected — of the character before it.
2840
+ */
2841
+ export declare const replaceText: (content: ReadonlyArray<RichInline>, start: number, end: number, text: string) => ReadonlyArray<RichInline>;
2842
+
2843
+ /** Effect form of {@link requestChanges}. */
2844
+ export declare const requestChanges: (...args: Parameters<typeof requestChanges_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound | RevisionMismatch | ReviewStepRefused, never>;
2845
+
2846
+ /** Send the revision in review back with a note. Same checks as approving, minus self-approval. */
2847
+ declare const requestChanges_2: (store: DataStore, type: ContentType, variantId: string, scope: CmsScope, options: Omit<DecideOptions, "allowSelfApproval">) => Promise<Row>;
2848
+
2849
+ export declare type RequestExceptionResult = {
2850
+ readonly ok: true;
2851
+ readonly id: string;
2852
+ } | {
2853
+ readonly ok: false;
2854
+ readonly reason: 'unknownRule' | 'notBlocking' | 'noReason' | 'badExpiry' | 'alreadyOpen';
2855
+ };
2856
+
2857
+ /** Effect form of {@link requestQualityException}. */
2858
+ export declare const requestQualityException: (...args: Parameters<typeof requestQualityException_2>) => Effect<RequestExceptionResult, ContentNotFound, never>;
2859
+
2860
+ /** Ask for an exception to one blocking rule on one variant, until `expiresAt`. */
2861
+ declare const requestQualityException_2: (tx: DataStore, type: ContentType, variantId: string, scope: CmsScope, input: {
2862
+ readonly ruleId: string;
2863
+ readonly reason: string;
2864
+ readonly expiresAt: Date;
2865
+ readonly actorId: string;
2866
+ }, now?: Date) => Promise<RequestExceptionResult>;
2867
+
2868
+ /** Effect form of {@link requestReview}. */
2869
+ export declare const requestReview: (...args: Parameters<typeof requestReview_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound, never>;
2870
+
2871
+ /** Ask for review of the revision the draft shows now. Use the caller's transaction. */
2872
+ declare const requestReview_2: (store: DataStore, type: ContentType, variantId: string, scope: CmsScope, options: {
2873
+ readonly actorId: string;
2874
+ readonly note?: string;
2875
+ }) => Promise<Row>;
2876
+
2877
+ /** One published entry found by {@link CmsApi.resolve}, with where it came from. */
2878
+ export declare interface ResolvedEntry {
2879
+ /** The published row that answers the request. */
2880
+ readonly row: Row;
2881
+ /** The locale of `row`. */
2882
+ readonly locale: string;
2883
+ /** The locale the surface was asked for (its scope's locale). */
2884
+ readonly requestedLocale: string;
2885
+ /** True when `row` is a fallback locale's variant — the requested locale
2886
+ * has none for this document. Resolved at read time, never stored. */
2887
+ readonly fallback: boolean;
2888
+ }
2889
+
2890
+ /** What a preview link shows. */
2891
+ export declare type ResolvedPreviewShare = {
2892
+ readonly ok: true;
2893
+ readonly share: Row;
2894
+ readonly contentType: string;
2895
+ readonly locale: string;
2896
+ /** The revision shown, and its values. */
2897
+ readonly revisionId: string;
2898
+ readonly revision: number;
2899
+ readonly values: Readonly<Record<string, unknown>>;
2900
+ }
2901
+ /** `unknown` also answers a token that never existed — no oracle for guessing. */
2902
+ | {
2903
+ readonly ok: false;
2904
+ readonly reason: 'unknown' | 'expired' | 'revoked';
2905
+ };
2906
+
2907
+ /** Effect form of {@link resolveMedia}. */
2908
+ export declare const resolveMedia: (...args: Parameters<typeof resolveMedia_2>) => Effect<Record<string, unknown>, never, never>;
2909
+
2910
+ /**
2911
+ * Resolve every `media` field on ONE row (including media nested inside
2912
+ * `Array` / `Struct` fields) from its stored storage key to a served URL,
2913
+ * using the caller-supplied `resolve`. Returns a NEW row; the input is not
2914
+ * mutated. A key the resolver returns `null` for is left as-is.
2915
+ *
2916
+ * A content type with no media fields returns the row unchanged (no work).
2917
+ */
2918
+ declare const resolveMedia_2: (type: Pick<ContentType, "fields">, row: Readonly<Record<string, unknown>>, resolve: MediaResolver) => Promise<Record<string, unknown>>;
2919
+
2920
+ /** Effect form of {@link resolveMediaAll}. */
2921
+ export declare const resolveMediaAll: (...args: Parameters<typeof resolveMediaAll_2>) => Effect<readonly Record<string, unknown>[], never, never>;
2922
+
2923
+ /** Resolve media across MANY rows in one call (the list-read case). */
2924
+ declare const resolveMediaAll_2: (type: Pick<ContentType, "fields">, rows: ReadonlyArray<Readonly<Record<string, unknown>>>, resolve: MediaResolver) => Promise<ReadonlyArray<Record<string, unknown>>>;
2925
+
2926
+ /** What {@link CmsApi.resolve} looks up. */
2927
+ export declare interface ResolveOptions {
2928
+ /** The column and value that identify the entry, e.g. `{ field: 'slug', value }`. */
2929
+ readonly key: {
2930
+ readonly field: string;
2931
+ readonly value: unknown;
2932
+ };
2933
+ /** Equality filters applied to every lookup (e.g. the site's tenant). */
2934
+ readonly filter?: Readonly<Record<string, unknown>>;
2935
+ /** Locales to try, in order, when the requested one has no match. */
2936
+ readonly fallback?: ReadonlyArray<string>;
2937
+ }
2938
+
2939
+ /** Effect form of {@link resolvePreviewShare}. */
2940
+ export declare const resolvePreviewShare: (...args: Parameters<typeof resolvePreviewShare_2>) => Effect<ResolvedPreviewShare, ContentNotFound | PreviewShareRejected, never>;
2941
+
2942
+ /**
2943
+ * Resolve a preview link's token. The only cross-tenant read here: the token
2944
+ * is the authorization, and everything read is confined to the share's own
2945
+ * tenant and variant. A draft that no longer exists answers `unknown`.
2946
+ */
2947
+ declare const resolvePreviewShare_2: (store: DataStore, token: string, now?: Date) => Promise<ResolvedPreviewShare>;
2948
+
2949
+ /** Effect-native `restoreRevision` (see {@link saveDraftEffect}). */
2950
+ export declare const restoreRevision: (store: DataStore, type: ContentType, id: string, scope: CmsScope, revisionId: string) => Effect_2.Effect<Row, ContentValidationFailed | ContentNotFound>;
2951
+
2952
+ /** Effect form of {@link retireDuplicate}. */
2953
+ export declare const retireDuplicate: (...args: Parameters<typeof retireDuplicate_2>) => Effect<RetireDuplicateResult, ContentNotFound, never>;
2954
+
2955
+ /**
2956
+ * Retire `copyId` in favour of `keepId` — both drafts of `type` in `scope`
2957
+ * holding the same file. Archived when no published content references the
2958
+ * copy (`usedBy`); refused with those references otherwise.
2959
+ */
2960
+ declare const retireDuplicate_2: (tx: DataStore, type: ContentType, scope: CmsScope, input: {
2961
+ readonly copyId: string;
2962
+ readonly keepId: string;
2963
+ readonly field: string;
2964
+ readonly fingerprint: Fingerprint;
2965
+ }) => Promise<RetireDuplicateResult>;
2966
+
2967
+ export declare type RetireDuplicateResult = {
2968
+ readonly ok: true;
2969
+ } | {
2970
+ readonly ok: false;
2971
+ readonly reason: 'notDuplicate';
2972
+ } | {
2973
+ readonly ok: false;
2974
+ readonly reason: 'inUse';
2975
+ readonly usedBy: ReadonlyArray<ReferenceUse>;
2976
+ };
2977
+
2978
+ /** Effect form of {@link retryRelease}. */
2979
+ export declare const retryRelease: (...args: Parameters<typeof retryRelease_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound | ReleaseNotEditable | ReviewRequired | ReferenceUnavailable, never>;
2980
+
2981
+ /**
2982
+ * Take a failed release back to draft, so it can be published or scheduled
2983
+ * again once its cause is fixed (an approval given, a blocked asset
2984
+ * replaced). Its entries stay as they were; the failure is cleared. Throws
2985
+ * `ReleaseNotEditable` for a release that did not fail.
2986
+ */
2987
+ declare const retryRelease_2: (store: DataStore, releaseId: string) => Promise<Row>;
2988
+
2989
+ /**
2990
+ * Fire the content type's DECLARED revalidations (`revalidate: { paths,
2991
+ * tags }`). Call it AFTER the publish/unpublish has committed — a web replica
2992
+ * re-rendering on the purge must read the committed state, which is why the
2993
+ * write ops themselves never fire it (they run inside the caller's open
2994
+ * transaction). `publishDue` calls it after each of its commits; a mutation
2995
+ * fires it from a post-commit subscriber on `<type>_published`.
2996
+ * Best-effort by design (the entry also expires by its own TTL): a transport
2997
+ * failure is logged and never reaches the caller.
2998
+ */
2999
+ export declare const revalidateContent: (type: ContentType) => void;
3000
+
3001
+ export declare const REVIEW_ACTIONS: readonly ["requested", "approved", "changesRequested"];
3002
+
3003
+ export declare type ReviewAction = (typeof REVIEW_ACTIONS)[number];
3004
+
3005
+ /** Effect form of {@link reviewLog}. */
3006
+ export declare const reviewLog: (...args: Parameters<typeof reviewLog_2>) => Effect<readonly Readonly<Record<string, unknown>>[], never, never>;
3007
+
3008
+ /** The variant's review steps, newest first. */
3009
+ declare const reviewLog_2: (store: DataStore, type: ContentType, variantId: string, scope: CmsScope) => Promise<ReadonlyArray<Row>>;
3010
+
3011
+ /**
3012
+ * Raised when a revision of a content type that requires review is published
3013
+ * without an approval of exactly that revision.
3014
+ */
3015
+ export declare class ReviewRequired extends ReviewRequired_base {
3016
+ }
3017
+
3018
+ declare const ReviewRequired_base: Schema_2.TaggedErrorClass<ReviewRequired, "ReviewRequired", {
3019
+ readonly _tag: Schema_2.tag<"ReviewRequired">;
3020
+ } & {
3021
+ contentType: typeof Schema_2.String;
3022
+ id: typeof Schema_2.String;
3023
+ revisionId: typeof Schema_2.String;
3024
+ }>;
3025
+
3026
+ /** Effect form of {@link reviewRequiredFor}. */
3027
+ export declare const reviewRequiredFor: (...args: Parameters<typeof reviewRequiredFor_2>) => Effect<boolean, never, never>;
3028
+
3029
+ /**
3030
+ * Whether publishing `type` needs an approval: always, never, or — for a type
3031
+ * left to the workspace — when the workspace of `variantId` requires it.
3032
+ */
3033
+ declare const reviewRequiredFor_2: (store: DataStore, type: ContentType, variantId?: string) => Promise<boolean>;
3034
+
3035
+ /** `notRequired`: the type declares no review cycle, or the document was never published. */
3036
+ export declare type ReviewState = 'notRequired' | 'scheduled' | 'due';
3037
+
3038
+ /** Where a variant's review stands. */
3039
+ export declare interface ReviewStatus {
3040
+ /** `none` also when the last step concerns a revision the draft no longer shows. */
3041
+ readonly state: 'none' | 'inReview' | 'approved' | 'changesRequested';
3042
+ /** The revision the last step concerns (null without any step). */
3043
+ readonly revisionId: string | null;
3044
+ /** True when the draft moved on since the last step. */
3045
+ readonly stale: boolean;
3046
+ readonly lastStep: Row | null;
3047
+ }
3048
+
3049
+ /** Effect form of {@link reviewStatus}. */
3050
+ export declare const reviewStatus: (...args: Parameters<typeof reviewStatus_2>) => Effect<ReviewStatus, ContentNotFound | ReviewStepRefused, never>;
3051
+
3052
+ declare const reviewStatus_2: (store: DataStore, type: ContentType, variantId: string, scope: CmsScope) => Promise<ReviewStatus>;
3053
+
3054
+ /**
3055
+ * Raised by the review steps when the step does not fit the variant's review:
3056
+ * nothing is in review, or the approver is the person who asked for it.
3057
+ */
3058
+ export declare class ReviewStepRefused extends ReviewStepRefused_base {
3059
+ }
3060
+
3061
+ declare const ReviewStepRefused_base: Schema_2.TaggedErrorClass<ReviewStepRefused, "ReviewStepRefused", {
3062
+ readonly _tag: Schema_2.tag<"ReviewStepRefused">;
3063
+ } & {
3064
+ contentType: typeof Schema_2.String;
3065
+ id: typeof Schema_2.String;
3066
+ reason: Schema_2.Literal<["notInReview", "selfApproval", "ambiguousOrder"]>;
3067
+ }>;
3068
+
3069
+ /**
3070
+ * Raised by `publish` when the caller pinned a revision (`{ revisionId }`)
3071
+ * and the draft has moved on to another one — publishing would release
3072
+ * content that was not the reviewed revision.
3073
+ */
3074
+ export declare class RevisionMismatch extends RevisionMismatch_base {
3075
+ }
3076
+
3077
+ declare const RevisionMismatch_base: Schema_2.TaggedErrorClass<RevisionMismatch, "RevisionMismatch", {
3078
+ readonly _tag: Schema_2.tag<"RevisionMismatch">;
3079
+ } & {
3080
+ contentType: typeof Schema_2.String;
3081
+ id: typeof Schema_2.String;
3082
+ expected: typeof Schema_2.String;
3083
+ actual: typeof Schema_2.String;
3084
+ }>;
3085
+
3086
+ /** Effect form of {@link revokeExtension}. */
3087
+ export declare const revokeExtension: (...args: Parameters<typeof revokeExtension_2>) => Effect<ExtensionChange, never, never>;
3088
+
3089
+ /** Take every capability away; the install and its data stay. */
3090
+ declare const revokeExtension_2: (tx: DataStore, extensionId: string) => Promise<ExtensionChange>;
3091
+
3092
+ /** Effect form of {@link revokePreviewShare}. */
3093
+ export declare const revokePreviewShare: (...args: Parameters<typeof revokePreviewShare_2>) => Effect<void, ContentNotFound | PreviewShareRejected, never>;
3094
+
3095
+ /** Revoke one of the caller's shares; the link stops working at once. */
3096
+ declare const revokePreviewShare_2: (store: DataStore, shareId: string, now?: Date) => Promise<void>;
3097
+
3098
+ /** A top-level block. `id` is stable across edits, moves and translations. */
3099
+ export declare type RichBlock = {
3100
+ readonly id: string;
3101
+ readonly type: 'paragraph';
3102
+ readonly content: ReadonlyArray<RichInline>;
3103
+ } | {
3104
+ readonly id: string;
3105
+ readonly type: 'heading';
3106
+ readonly level: 2 | 3;
3107
+ readonly content: ReadonlyArray<RichInline>;
3108
+ } | {
3109
+ readonly id: string;
3110
+ readonly type: 'list';
3111
+ readonly ordered: boolean;
3112
+ readonly items: ReadonlyArray<ReadonlyArray<RichInline>>;
3113
+ /** How deep each item sits (0 at the top, at most `MAX_LIST_LEVEL`), one per item; absent: all at the top.
3114
+ * An item is at most one level deeper than the one before it. */
3115
+ readonly levels?: ReadonlyArray<number>;
3116
+ /** The kind of the lists nested in it, by depth — index 0 for the lists one level in. Absent (or
3117
+ * shorter than the depth): numbered like the list itself. At most `MAX_LIST_LEVEL` entries. */
3118
+ readonly sublists?: ReadonlyArray<ListKind>;
3119
+ } | {
3120
+ readonly id: string;
3121
+ readonly type: 'table';
3122
+ /** True when the first row holds the column headers. */
3123
+ readonly header: boolean;
3124
+ readonly rows: ReadonlyArray<ReadonlyArray<ReadonlyArray<RichInline>>>;
3125
+ }
3126
+ /** An image asset (by its documentId) with an optional caption. */
3127
+ | {
3128
+ readonly id: string;
3129
+ readonly type: 'image';
3130
+ readonly asset: string;
3131
+ readonly caption?: string;
3132
+ };
3133
+
3134
+ /** A rich document. */
3135
+ export declare interface RichDocument {
3136
+ readonly type: 'doc';
3137
+ readonly blocks: ReadonlyArray<RichBlock>;
3138
+ }
3139
+
3140
+ export declare const RichDocumentEditor: (props: RichDocumentEditorProps) => ReactNode;
3141
+
3142
+ export declare interface RichDocumentEditorProps extends WidgetProps {
3143
+ readonly renderPicker?: RichDocumentPicker;
3144
+ /** Renders inside one block's group, after its actions — its comments, say.
3145
+ * `blockId` is the block's stable id (it survives moves and new revisions);
3146
+ * `label` names it as its legend does (`Paragraph 2`). */
3147
+ readonly renderBlockAside?: (blockId: string, label: string) => ReactNode;
3148
+ /** The words of the controls; English by default (see `ContentFormStrings`). */
3149
+ readonly strings?: ContentFormStringsInput;
3150
+ /**
3151
+ * How a paragraph's or a heading's text is edited: `markup` (default) is a
3152
+ * text area with the small inline syntax; `visual` edits it as it looks —
3153
+ * bold as bold, links as links — with Bold and Italic buttons. Lists and
3154
+ * tables keep their lines either way.
3155
+ */
3156
+ readonly surface?: 'markup' | 'visual';
3157
+ }
3158
+
3159
+ /** Translate a Contentful rich-text document, and say what could not be translated. */
3160
+ export declare const richDocumentFromContentful: (root: ContentfulNode | null | undefined, options?: ContentfulImportOptions) => ContentfulImportResult;
3161
+
3162
+ /**
3163
+ * Translate HTML into a rich document, and say what could not be translated.
3164
+ * Links resolve through `resolveLink`; everything else is text or a finding.
3165
+ */
3166
+ export declare const richDocumentFromHtml: (html: string, options?: HtmlImportOptions) => HtmlImportResult;
3167
+
3168
+ /** Renders a control that picks one document of `type`. */
3169
+ export declare type RichDocumentPicker = (props: {
3170
+ readonly id: string;
3171
+ readonly type: string;
3172
+ readonly value: string;
3173
+ readonly onChange: (documentId: string) => void;
3174
+ }) => ReactNode;
3175
+
3176
+ /** One problem with a rich document, at a path below the field. */
3177
+ export declare interface RichDocumentProblem {
3178
+ readonly path: string;
3179
+ readonly rule: string;
3180
+ readonly message: string;
3181
+ }
3182
+
3183
+ /** Everything wrong with `value` as a rich document under `options`. */
3184
+ export declare const richDocumentProblems: (path: string, value: unknown, options: RichTextOptions) => ReadonlyArray<RichDocumentProblem>;
3185
+
3186
+ /** A document reference found in a rich document. */
3187
+ export declare interface RichDocumentReference {
3188
+ readonly path: string;
3189
+ readonly targetType: string;
3190
+ readonly targetDocumentId: string;
3191
+ }
3192
+
3193
+ /** Every image and link reference in a (valid) document, with its path. */
3194
+ export declare const richDocumentReferences: (path: string, doc: RichDocument, options: RichTextOptions) => ReadonlyArray<RichDocumentReference>;
383
3195
 
384
- export declare interface PipeableField extends FieldSchema {
385
- readonly isOptional: boolean;
386
- pipe(...refinements: ReadonlyArray<FieldRefinement>): PipeableField;
387
- /** Mark the field optional → nullable column + non-required editor input. */
388
- optional(): PipeableField;
3196
+ /** The document's blocks, in order. Renders nothing for a value that is not a rich document. */
3197
+ export declare const RichDocumentView: ({ document, hrefOf, renderImage }: RichDocumentViewProps) => ReactNode;
3198
+
3199
+ export declare interface RichDocumentViewProps {
3200
+ /** A stored `Schema.RichText()` value (a plain string renders as paragraphs). */
3201
+ readonly document: unknown;
3202
+ /** The address of a linked document, or undefined when it has none (not live). */
3203
+ readonly hrefOf?: (documentId: string) => string | undefined;
3204
+ /** Render an image block; without it, images are left out. */
3205
+ readonly renderImage?: (block: {
3206
+ readonly asset: string;
3207
+ readonly caption?: string;
3208
+ }) => ReactNode;
389
3209
  }
390
3210
 
391
- /** A verified preview claim. */
392
- export declare interface PreviewClaim {
393
- readonly type: string;
394
- readonly id: string;
3211
+ /** A run of text inside a block. */
3212
+ export declare type RichInline = {
3213
+ readonly type: 'text';
3214
+ readonly text: string;
3215
+ readonly marks?: ReadonlyArray<RichMark>;
395
3216
  }
3217
+ /** A link to a document (by its documentId) — the site resolves its address. */
3218
+ | {
3219
+ readonly type: 'link';
3220
+ readonly target: string;
3221
+ readonly text: string;
3222
+ };
396
3223
 
397
- /** Mint a signed preview token for a draft row. */
398
- export declare const previewToken: (type: string, id: string, options?: {
399
- ttlSeconds?: number;
400
- secret?: string;
401
- }) => string;
3224
+ /** An inline mark. */
3225
+ export declare type RichMark = 'bold' | 'italic' | 'underline';
402
3226
 
403
3227
  /**
404
- * Publish a draft: copy the draft row's declared fields into
405
- * `<type>_published` (insert on first publish, keyed update after — the
406
- * published row keeps the SAME id) and mark the draft `status:
407
- * 'published'`. Runs inside `store.transactional`, so the copy + the
408
- * draft status flip land atomically per row. Both tables are
409
- * reactive, so the publish wakes live consumer subscriptions.
410
- *
411
- * A missing draft id — including another tenant's draft, which a scoped
412
- * store reads as absent — throws `ContentNotFound`.
413
- *
414
- * Returns the published row.
3228
+ * Which resources a rich-text field may hold: `images` names the content type
3229
+ * an image block references (an asset type), `links` the type a link
3230
+ * references (a page type). Unset → that node is not allowed.
415
3231
  */
416
- export declare const publish: (store: DataStore, type: ContentType, id: string) => Promise<Row>;
3232
+ export declare interface RichTextOptions {
3233
+ readonly images?: string;
3234
+ readonly links?: string;
3235
+ }
417
3236
 
418
- /**
419
- * Publish every draft of `type` whose scheduled `publishAt` has passed
420
- * (and that is still a draft). Returns the ids that were published. A
421
- * driver calls this on an interval from a `*.cron.tsx` schedule (see the
422
- * README/docs recipe) — it is idempotent: `publish` flips the draft
423
- * `status` to `'published'`, so a row is never double-published, and
424
- * `publishAt` is cleared so a later re-save doesn't spuriously re-fire.
425
- *
426
- * Runs over the store it is handed: a request-scoped store publishes one
427
- * tenant's due drafts; a background/root store sweeps every tenant.
428
- */
429
- export declare const publishDue: (store: DataStore, type: ContentType, now?: Date) => Promise<ReadonlyArray<string>>;
3237
+ export declare const RichTextSurface: (props: RichTextSurfaceProps) => ReactNode;
430
3238
 
431
- /** Effect-native `publishDue` — the sweep never fails typed (a store/db error
432
- * is a defect), so it carries `never` on the error channel. */
433
- export declare const publishDueEffect: (store: DataStore, type: ContentType, now?: Date) => Effect.Effect<ReadonlyArray<string>, never>;
3239
+ export declare interface RichTextSurfaceProps {
3240
+ readonly id: string;
3241
+ /** The id of the element naming the text box (its label). */
3242
+ readonly labelledBy: string;
3243
+ readonly content: ReadonlyArray<RichInline>;
3244
+ readonly onChange: (content: ReadonlyArray<RichInline>) => void;
3245
+ /** The words of the mark buttons, and their accessible names. */
3246
+ readonly words: {
3247
+ readonly bold: string;
3248
+ readonly italic: string;
3249
+ readonly underline: string;
3250
+ };
3251
+ }
434
3252
 
435
- /** Effect-native `publish` (see {@link saveDraftEffect}). */
436
- export declare const publishEffect: (store: DataStore, type: ContentType, id: string) => Effect.Effect<Row, ContentNotFound>;
3253
+ /** Effect form of {@link rollbackExtension}. */
3254
+ export declare const rollbackExtension: (...args: Parameters<typeof rollbackExtension_2>) => Effect<ExtensionChange, never, never>;
437
3255
 
438
3256
  /**
439
- * Resolve every `media` field on ONE row (including media nested inside
440
- * `Array` / `Struct` fields) from its stored storage key to a served URL,
441
- * using the caller-supplied `resolve`. Returns a NEW row; the input is not
442
- * mutated. A key the resolver returns `null` for is left as-is.
443
- *
444
- * A content type with no media fields returns the row unchanged (no work).
3257
+ * Back to the version that ran before the last move, with the grant it had
3258
+ * then — one step; a waiting version is dropped. A rollback never widens the
3259
+ * grant beyond what was consented to for that version.
445
3260
  */
446
- export declare const resolveMedia: (type: Pick<ContentType, "fields">, row: Readonly<Record<string, unknown>>, resolve: MediaResolver) => Promise<Record<string, unknown>>;
3261
+ declare const rollbackExtension_2: (tx: DataStore, extensionId: string) => Promise<ExtensionChange>;
447
3262
 
448
- /** Resolve media across MANY rows in one call (the list-read case). */
449
- export declare const resolveMediaAll: (type: Pick<ContentType, "fields">, rows: ReadonlyArray<Readonly<Record<string, unknown>>>, resolve: MediaResolver) => Promise<ReadonlyArray<Record<string, unknown>>>;
3263
+ /** Effect form of {@link rollbackRelease}. */
3264
+ export declare const rollbackRelease: (...args: Parameters<typeof rollbackRelease_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound | ReleaseNotEditable | ReviewRequired | ReferenceUnavailable, never>;
450
3265
 
451
3266
  /**
452
- * Options carried by a RichText field, enforced at save time by
453
- * `validateContent`: an explicit `false` REJECTS the content class
454
- * (image/embed nodes in a structured document, or `<img>` / `<iframe>` /
455
- * `<embed>` markers in a string value); `true` or omitted allows it.
3267
+ * Roll a published release back: a NEW release that puts back what each of
3268
+ * its variants showed before it (unpublishing the ones that were not live),
3269
+ * published in the caller's transaction. The rolled-back release is left as it
3270
+ * was. Returns the new release.
456
3271
  */
457
- export declare interface RichTextOptions {
458
- readonly allowImages?: boolean;
459
- readonly allowEmbeds?: boolean;
3272
+ declare const rollbackRelease_2: (tx: DataStore, types: ReadonlyArray<ContentType>, releaseId: string, now?: Date) => Promise<Row>;
3273
+
3274
+ /** A path found by {@link CmsApi.route}. */
3275
+ export declare interface RouteMatch {
3276
+ /** The node for the path's document, in the requested locale's tree. Its
3277
+ * `path` is the canonical address — it differs from the path asked for
3278
+ * when that was a fallback locale's path of a translated page, or a
3279
+ * former address of a page that moved (redirect to `node.path`). */
3280
+ readonly node: TreeNode;
3281
+ /** The tree the node belongs to — for navigation and link resolution. */
3282
+ readonly tree: CmsTree;
3283
+ /** How the path was found: the page's own address, another locale's
3284
+ * address of it, or an address it had before it moved (answer that one
3285
+ * with a permanent redirect). */
3286
+ readonly via: 'path' | 'fallback' | 'redirect';
460
3287
  }
461
3288
 
3289
+ /** Effect form of {@link runBulk}. */
3290
+ export declare const runBulk: (...args: Parameters<typeof runBulk_2>) => Effect<readonly BulkResult[], ContentValidationFailed | ContentNotFound | ContentIdConflict | RevisionMismatch | ReviewRequired | ReferenceUnavailable, never>;
3291
+
462
3292
  /**
463
- * Save a row into `<type>_drafts`: apply the `derivedFrom` derivations
464
- * (caller-provided values for derived fields are overwritten), validate
465
- * the derived row against the field rules (throws
466
- * `ContentValidationFailed` with per-field violations), then write.
467
- *
468
- * Without `row.id` a new draft is inserted (the id scheme generates the
469
- * TypeID). With `row.id`, the caller's OWN draft is updated in place; an
470
- * id that exists only outside the caller's tenant scope throws
471
- * `ContentIdConflict` — it is never updated or overwritten. The row is
472
- * written with `status: 'draft'`; through a request-scoped `ctx.store`
473
- * the tenant/audit columns are stamped by the store spine.
474
- *
475
- * Returns the written draft row.
3293
+ * Execute a plan: each `ready` item in its own transaction (hand it a store
3294
+ * that is not already inside one), a publish with the revision the plan
3295
+ * pinned. A gate that closed since the dry run fails that item with its
3296
+ * reason; the others still go through.
476
3297
  */
477
- export declare const saveDraft: (store: DataStore, type: ContentType, row: Readonly<Record<string, unknown>>) => Promise<Row>;
3298
+ declare const runBulk_2: (store: DataStore, types: ReadonlyArray<ContentType>, place: Place, action: BulkAction, plan: ReadonlyArray<PlannedItem>) => Promise<ReadonlyArray<BulkResult>>;
3299
+
3300
+ /** Effect form of {@link runningExperiment}. */
3301
+ export declare const runningExperiment: (...args: Parameters<typeof runningExperiment_2>) => Effect<Experiment | null, never, never>;
3302
+
3303
+ /** The experiment running on a page in this place, or null. */
3304
+ declare const runningExperiment_2: (store: DataStore, type: ContentType, scope: CmsScope, documentId: string) => Promise<Experiment | null>;
478
3305
 
479
3306
  /** Effect-native `saveDraft` for handlers written in `Effect.gen` — the
480
3307
  * typed failures ride the error channel (`Effect.catchTag('ContentValidationFailed', …)`). */
481
- export declare const saveDraftEffect: (store: DataStore, type: ContentType, row: Readonly<Record<string, unknown>>) => Effect.Effect<Row, ContentValidationFailed | ContentIdConflict>;
3308
+ export declare const saveDraft: (store: DataStore, type: ContentType, row: Readonly<Record<string, unknown>>, scope: CmsScope, options?: SaveDraftOptions) => Effect_2.Effect<Row, ContentValidationFailed | ContentIdConflict | ContentNotFound | RevisionMismatch>;
3309
+
3310
+ export declare interface SaveDraftOptions {
3311
+ /** The revisionId the editor last saw; a draft that moved on is not overwritten. */
3312
+ readonly expectedRevision?: string;
3313
+ /**
3314
+ * For a translation: the source-language revision it now reflects. Omitted
3315
+ * on an update, the previous revision's basis carries over — fixing a typo
3316
+ * does not claim the translation caught up with its source.
3317
+ */
3318
+ readonly basedOn?: string;
3319
+ /**
3320
+ * The draft is typed in together (draftTexts.ts): its collaborative fields
3321
+ * are taken from the merged texts on the server, not from `row`, and a
3322
+ * draft that moved on since `expectedRevision` only in those fields is no
3323
+ * conflict.
3324
+ */
3325
+ readonly collaborative?: boolean;
3326
+ /**
3327
+ * With `collaborative`: the editor's own states of the shared texts (each an
3328
+ * encoded CRDT update, by text id), merged in before the save reads them — so
3329
+ * an edit still on its way to the server is not left out of the save.
3330
+ */
3331
+ readonly texts?: ReadonlyArray<{
3332
+ readonly id: string;
3333
+ readonly update: Uint8Array;
3334
+ }>;
3335
+ }
3336
+
3337
+ /** Effect form of {@link schedulePublish}. */
3338
+ export declare const schedulePublish: (...args: Parameters<typeof schedulePublish_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound, never>;
482
3339
 
483
3340
  /**
484
3341
  * Mark a draft to publish automatically at `at`. Sets the draft's
485
3342
  * `publishAt` timestamp WITHOUT publishing now — a later `publishDue`
486
- * sweep flips it live once `at` has passed. Keys off the caller's own
487
- * draft (a foreign / missing id throws `ContentNotFound`); the draft's
3343
+ * sweep flips it live once `at` has passed. `null` cancels the schedule. Keys off the caller's own
3344
+ * draft in `scope` (a foreign / missing id throws `ContentNotFound`); the draft's
488
3345
  * `status` stays `'draft'` until it goes live.
489
3346
  *
490
3347
  * Returns the updated draft row.
491
3348
  */
492
- export declare const schedulePublish: (store: DataStore, type: ContentType, id: string, at: Date) => Promise<Row>;
3349
+ declare const schedulePublish_2: (store: DataStore, type: ContentType, id: string, at: Date | null, scope: CmsScope) => Promise<Row>;
3350
+
3351
+ /** Effect form of {@link scheduleRelease}. */
3352
+ export declare const scheduleRelease: (...args: Parameters<typeof scheduleRelease_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound | ReleaseNotEditable | ReviewRequired | ReferenceUnavailable, never>;
3353
+
3354
+ /** Plan a draft release for `at`; `publishDueReleases` takes it live. */
3355
+ declare const scheduleRelease_2: (store: DataStore, releaseId: string, at: Date) => Promise<Row>;
3356
+
3357
+ /** Effect form of {@link scheduleSeries}. */
3358
+ export declare const scheduleSeries: (...args: Parameters<typeof scheduleSeries_2>) => Effect<PublishSeries, ContentValidationFailed | ContentNotFound, never>;
3359
+
3360
+ /**
3361
+ * Give a draft a repeating live window, replacing any series it had, and arm
3362
+ * its first occurrence that has not ended yet. `ContentValidationFailed`
3363
+ * (field `repeat`) for a rule with problems or with no occurrence left;
3364
+ * `ContentNotFound` for a draft the caller cannot see in `scope`. In the
3365
+ * caller's transaction.
3366
+ */
3367
+ declare const scheduleSeries_2: (tx: DataStore, type: ContentType, draftId: string, scope: CmsScope, rule: RecurrenceRule, now?: Date) => Promise<PublishSeries>;
493
3368
 
494
- /** Effect-native `schedulePublish` — the `ContentNotFound` failure rides the
495
- * error channel (`Effect.catchTag('ContentNotFound', …)`). */
496
- export declare const schedulePublishEffect: (store: DataStore, type: ContentType, id: string, at: Date) => Effect.Effect<Row, ContentNotFound>;
3369
+ /** Effect form of {@link scheduleUnpublish}. */
3370
+ export declare const scheduleUnpublish: (...args: Parameters<typeof scheduleUnpublish_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound, never>;
3371
+
3372
+ /**
3373
+ * Mark an entry to be taken down automatically at `at` — the end of a
3374
+ * campaign, an offer that expires. Stamps the draft's `unpublishAt`; a later
3375
+ * `unpublishDue` sweep unpublishes it once `at` has passed, if it is live
3376
+ * then. It may be set before the entry is live (publish at nine, take down at
3377
+ * five). `null` cancels it. A foreign / missing id throws `ContentNotFound`.
3378
+ */
3379
+ declare const scheduleUnpublish_2: (store: DataStore, type: ContentType, id: string, at: Date | null, scope: CmsScope) => Promise<Row>;
497
3380
 
498
3381
  /**
499
3382
  * The CMS field namespace. Scalars mirror the effect/Schema names the
@@ -505,7 +3388,10 @@ export declare const Schema: {
505
3388
  /** Single-line text. `.pipe(maxLength(N>120))` switches it to a textarea. */
506
3389
  readonly String: PipeableField;
507
3390
  /** Numeric input. */
3391
+ /** A whole number (an integer column); a fraction is refused on save. */
508
3392
  readonly Number: PipeableField;
3393
+ /** A number with a fractional part (a `real` column), e.g. a focal point's 0.25. */
3394
+ readonly Fraction: PipeableField;
509
3395
  /** Toggle. */
510
3396
  readonly Boolean: PipeableField;
511
3397
  /** Date-only picker. */
@@ -518,10 +3404,12 @@ export declare const Schema: {
518
3404
  /** Closed value set → `<select>` widget + a CHECK constraint. */
519
3405
  readonly Literal: (values_0: string, ...values: string[]) => PipeableField;
520
3406
  /**
521
- * Rich text, stored as a JSON document (e.g. a TipTap doc). The shipped
522
- * default widget is a plain textarea placeholder — swap in a real editor
523
- * via the `ContentForm` `widgets` override. `allowImages` /
524
- * `allowEmbeds: false` reject that content class at save time.
3407
+ * Rich text, stored as a `RichDocument` (see richDocument.ts): blocks with
3408
+ * stable ids — paragraph, heading, list, table, image — and inline text
3409
+ * with marks and links. `images` / `links` name the content types an image
3410
+ * block and a link reference; unset, that node is refused at save time. A
3411
+ * plain string is saved as paragraphs. The editor widget is
3412
+ * `RichDocumentEditor`.
525
3413
  */
526
3414
  readonly RichText: (options?: RichTextOptions) => PipeableField;
527
3415
  /**
@@ -538,11 +3426,492 @@ export declare const Schema: {
538
3426
  readonly Array: (element: FieldSchema) => PipeableField;
539
3427
  /** Nested object. Stored as a JSON document. */
540
3428
  readonly Struct: (fields: Readonly<Record<string, FieldSchema>>) => PipeableField;
3429
+ /**
3430
+ * An ordered list of placed components (ADR-CMS-015), stored as a JSON array
3431
+ * of `ComponentInstance`. Only the listed definitions may be placed; each
3432
+ * instance's props are validated against its definition on save.
3433
+ */
3434
+ readonly Components: (definitions: ReadonlyArray<ComponentDefinition>) => PipeableField;
3435
+ };
3436
+
3437
+ /** What makes a type findable. */
3438
+ export declare interface SearchConfig {
3439
+ /** The string field ranked first — usually the title. */
3440
+ readonly title: string;
3441
+ }
3442
+
3443
+ /** Effect form of {@link searchContent}. */
3444
+ export declare const searchContent: (...args: Parameters<typeof searchContent_2>) => Effect<readonly SearchHit[], never, never>;
3445
+
3446
+ /**
3447
+ * Find documents in a site and environment by the words of `query`, best
3448
+ * first; a hit in the title outranks one in the body. Every word must match,
3449
+ * as a word beginning — `tomato` finds `tomatoes` — on postgres, mysql,
3450
+ * sqlite and the in-memory store (mssql: the whole query as a substring).
3451
+ * An empty query finds nothing.
3452
+ */
3453
+ declare const searchContent_2: (store: DataStore, place: Pick<CmsScope, "site" | "environment">, query: string, options: SearchOptions) => Promise<ReadonlyArray<SearchHit>>;
3454
+
3455
+ export declare interface SearchHit {
3456
+ readonly contentType: string;
3457
+ readonly documentId: string;
3458
+ readonly variantId: string;
3459
+ readonly locale: string;
3460
+ readonly title: string;
3461
+ readonly snippet: SearchSnippet;
3462
+ /** Higher is more relevant; only comparable within one result. */
3463
+ readonly rank: number;
3464
+ }
3465
+
3466
+ export declare interface SearchOptions {
3467
+ /** `published` for readers, `draft` for editors (every document, in its newest state). */
3468
+ readonly stage: 'draft' | 'published';
3469
+ /** Only this language's variants. */
3470
+ readonly locale?: string;
3471
+ /** Only these content types. */
3472
+ readonly types?: ReadonlyArray<string>;
3473
+ /** At most this many hits (default 20, at most 100). */
3474
+ readonly limit?: number;
3475
+ /** Equality filters, e.g. the tenant for a reader that carries none. */
3476
+ readonly filter?: Readonly<Record<string, unknown>>;
3477
+ }
3478
+
3479
+ /** A passage of the body around the first hit, and where the hits are in it. */
3480
+ export declare interface SearchSnippet {
3481
+ readonly text: string;
3482
+ /** `[start, end)` offsets into `text` of each word that matched. */
3483
+ readonly marks: ReadonlyArray<readonly [number, number]>;
3484
+ }
3485
+
3486
+ /** The title and body a row is found by: the title field, and the text of every other field that is not derived. */
3487
+ export declare const searchTextOf: (type: ContentType, values: Readonly<Record<string, unknown>>) => {
3488
+ readonly title: string;
3489
+ readonly body: string;
3490
+ };
3491
+
3492
+ export declare type SecretBinding = {
3493
+ readonly ok: true;
3494
+ } | {
3495
+ readonly ok: false;
3496
+ readonly reason: 'notInstalled' | 'notAsked';
3497
+ };
3498
+
3499
+ /** Effect form of {@link seriesOf}. */
3500
+ export declare const seriesOf: (...args: Parameters<typeof seriesOf_2>) => Effect<PublishSeries | null, ContentValidationFailed | ContentNotFound, never>;
3501
+
3502
+ /** The series of a draft, or null. */
3503
+ declare const seriesOf_2: (store: DataStore, draftId: string) => Promise<PublishSeries | null>;
3504
+
3505
+ /** Effect form of {@link setAiBudget}. */
3506
+ export declare const setAiBudget: (...args: Parameters<typeof setAiBudget_2>) => Effect<void, never, never>;
3507
+
3508
+ /** Set the workspace's monthly token budget; null: no limit. */
3509
+ declare const setAiBudget_2: (tx: DataStore, tenantId: string, monthlyTokens: number | null) => Promise<void>;
3510
+
3511
+ /** Effect form of {@link setAiSettings}. */
3512
+ export declare const setAiSettings: (...args: Parameters<typeof setAiSettings_2>) => Effect<void, never, never>;
3513
+
3514
+ /**
3515
+ * Set the workspace's provider and model, and its own key: a string sets it,
3516
+ * `null` removes it (back to the deployment's), `undefined` keeps it.
3517
+ * `settings: null` goes back to the deployment's provider (a budget stays).
3518
+ */
3519
+ declare const setAiSettings_2: (tx: DataStore, tenantId: string, settings: {
3520
+ readonly provider: string;
3521
+ readonly model: string;
3522
+ readonly apiKey?: string | null;
3523
+ } | null) => Promise<void>;
3524
+
3525
+ /** Effect form of {@link setExtensionSettings}. */
3526
+ export declare const setExtensionSettings: (...args: Parameters<typeof setExtensionSettings_2>) => Effect<SettingsChange, never, never>;
3527
+
3528
+ /** Set some of an installed extension's settings; every value is checked against its manifest. */
3529
+ declare const setExtensionSettings_2: (tx: DataStore, extensionId: string, values: Readonly<Record<string, unknown>>) => Promise<SettingsChange>;
3530
+
3531
+ /** Effect form of {@link setGlossaryTerm}. */
3532
+ export declare const setGlossaryTerm: (...args: Parameters<typeof setGlossaryTerm_2>) => Effect<"added" | "replaced", never, never>;
3533
+
3534
+ /** Set the entry for a term and language, in the caller's transaction; `added` or `replaced`. */
3535
+ declare const setGlossaryTerm_2: (tx: DataStore, tenantId: string, input: GlossaryInput) => Promise<"added" | "replaced">;
3536
+
3537
+ /** Effect form of {@link setOwner}. */
3538
+ export declare const setOwner: (...args: Parameters<typeof setOwner_2>) => Effect<Stewardship, never, never>;
3539
+
3540
+ /** Make `owner` (an account id) responsible for the document, or nobody (`null`). */
3541
+ declare const setOwner_2: (store: DataStore, type: ContentType, documentId: string, place: Place_2, owner: string | null) => Promise<Stewardship>;
3542
+
3543
+ /** Effect form of {@link setReviewRequired}. */
3544
+ export declare const setReviewRequired: (...args: Parameters<typeof setReviewRequired_2>) => Effect<readonly string[], never, never>;
3545
+
3546
+ /** Turn the workspace's review requirement for `typeName` on or off, in the caller's transaction. */
3547
+ declare const setReviewRequired_2: (tx: DataStore, tenantId: string, typeName: string, required: boolean) => Promise<ReadonlyArray<string>>;
3548
+
3549
+ export declare type SettingsChange = {
3550
+ readonly ok: true;
3551
+ readonly settings: Readonly<Record<string, ExtensionSettingValue>>;
3552
+ } | {
3553
+ readonly ok: false;
3554
+ readonly reason: 'notInstalled';
3555
+ } | {
3556
+ readonly ok: false;
3557
+ readonly reason: 'invalid';
3558
+ readonly problems: ReadonlyArray<string>;
541
3559
  };
542
3560
 
543
- /** The canonical slug helper: lowercase, hyphenate, strip non-url chars. */
3561
+ /** What is wrong with values for a manifest's settings; empty when nothing is. Unknown keys are refused. */
3562
+ export declare const settingsProblems: (manifest: CmsExtensionManifest, values: Readonly<Record<string, unknown>>) => ReadonlyArray<string>;
3563
+
3564
+ /** The settings with their defaults filled in, dropping keys the manifest no longer has. */
3565
+ export declare const settingsWithDefaults: (manifest: CmsExtensionManifest, stored: Readonly<Record<string, unknown>>) => Readonly<Record<string, ExtensionSettingValue>>;
3566
+
3567
+ /** Effect form of {@link settleAiOperation}. */
3568
+ export declare const settleAiOperation: (...args: Parameters<typeof settleAiOperation_2>) => Effect<boolean, never, never>;
3569
+
3570
+ /** What the person did with a proposal; false when it is not a pending proposal. */
3571
+ declare const settleAiOperation_2: (tx: DataStore, operationId: string, outcome: "applied" | "discarded") => Promise<boolean>;
3572
+
3573
+ export declare interface SitemapUrl extends PageAlternate {
3574
+ readonly documentId: string;
3575
+ /** ISO date of the variant's last change, when known. */
3576
+ readonly lastmod: string | null;
3577
+ /** The document in every language it has its own variant in, this one included. */
3578
+ readonly alternates: ReadonlyArray<PageAlternate>;
3579
+ }
3580
+
3581
+ /**
3582
+ * Every page the sitemap lists: each language's own variants (never a
3583
+ * fallback), those `include` accepts (leave out pages not for search
3584
+ * engines), with their alternates.
3585
+ */
3586
+ export declare const sitemapUrls: (trees: ReadonlyArray<LocalizedTree>, include?: (node: TreeNode) => boolean) => ReadonlyArray<SitemapUrl>;
3587
+
3588
+ /**
3589
+ * The sitemap document. `href(locale, path)` makes a page's absolute URL;
3590
+ * `xDefault` names the language an unmatched reader gets.
3591
+ */
3592
+ export declare const sitemapXml: (urls: ReadonlyArray<SitemapUrl>, href: (locale: string, path: string) => string, xDefault?: string) => string;
3593
+
3594
+ /**
3595
+ * The canonical slug helper: lowercase, letters with accents folded to their
3596
+ * base letter (umlauts spelled out, `ß` as `ss`), hyphenate, strip every
3597
+ * other non-url character.
3598
+ */
544
3599
  export declare const slugify: (value: unknown) => string;
545
3600
 
3601
+ /** The passage of `body` around the first word that starts with a query word. */
3602
+ export declare const snippetOf: (body: string, query: string) => SearchSnippet;
3603
+
3604
+ /** Mark an element of the preview with the field path it renders. */
3605
+ export declare const sourceAttributes: (path: string) => {
3606
+ readonly "data-cms-source": string;
3607
+ };
3608
+
3609
+ /** The field path behind a clicked element of the preview, or null. */
3610
+ export declare const sourcePathOf: (target: unknown) => string | null;
3611
+
3612
+ /** Effect form of {@link startExperiment}. */
3613
+ export declare const startExperiment: (...args: Parameters<typeof startExperiment_2>) => Effect<StartExperimentResult, never, never>;
3614
+
3615
+ /** Start an experiment on a live page, in the caller's transaction. */
3616
+ declare const startExperiment_2: (tx: DataStore, type: ContentType, scope: CmsScope, input: StartExperimentInput, now?: Date) => Promise<StartExperimentResult>;
3617
+
3618
+ export declare interface StartExperimentInput {
3619
+ readonly documentId: string;
3620
+ readonly name: string;
3621
+ /** Percent of readers shown version B (1–99). */
3622
+ readonly share: number;
3623
+ readonly overrides: Readonly<Record<string, string>>;
3624
+ readonly goal: string;
3625
+ /** Required: what B is expected to change, and why (at most 500 characters). */
3626
+ readonly hypothesis: string;
3627
+ /** Optional guardrail, 1–50 percentage points. */
3628
+ readonly guardrailMaxDrop?: number | null;
3629
+ }
3630
+
3631
+ export declare type StartExperimentResult = {
3632
+ readonly ok: true;
3633
+ readonly id: string;
3634
+ } | {
3635
+ readonly ok: false;
3636
+ readonly reason: 'notLive' | 'alreadyRunning' | 'noOverrides' | 'badShare' | 'unknownField' | 'noHypothesis' | 'badGuardrail';
3637
+ readonly fields?: ReadonlyArray<string>;
3638
+ };
3639
+
3640
+ /** Effect form of {@link startStewardship}. */
3641
+ export declare const startStewardship: (...args: Parameters<typeof startStewardship_2>) => Effect<void, never, never>;
3642
+
3643
+ /**
3644
+ * On a publish, in the caller's transaction: for a type that declares a
3645
+ * review cycle, the document's first publish in this site and environment
3646
+ * starts it. Later publishes leave the date alone — a review is a decision,
3647
+ * not a side effect of saving. A type without `lifecycle` writes nothing.
3648
+ */
3649
+ declare const startStewardship_2: (tx: DataStore, type: ContentType, documentId: string, place: Place_2, tenantId: unknown, now?: Date) => Promise<void>;
3650
+
3651
+ export declare interface Stewardship {
3652
+ readonly owner: string | null;
3653
+ readonly reviewDue: Date | null;
3654
+ readonly reviewedAt: Date | null;
3655
+ readonly reviewedBy: string | null;
3656
+ readonly reviewedRevision: string | null;
3657
+ readonly review: ReviewState;
3658
+ }
3659
+
3660
+ /** Effect form of {@link stewardshipOf}. */
3661
+ export declare const stewardshipOf: (...args: Parameters<typeof stewardshipOf_2>) => Effect<Stewardship, never, never>;
3662
+
3663
+ /** The document's owner and review state. A document never published has neither. */
3664
+ declare const stewardshipOf_2: (store: DataStore, type: ContentType, documentId: string, place: Place_2, now?: Date) => Promise<Stewardship>;
3665
+
3666
+ /** Effect form of {@link stopExperiment}. */
3667
+ export declare const stopExperiment: (...args: Parameters<typeof stopExperiment_2>) => Effect<boolean, never, never>;
3668
+
3669
+ /** Stop a running experiment; its counts stay. False when there is none of that id running. */
3670
+ declare const stopExperiment_2: (tx: DataStore, experimentId: string, now?: Date) => Promise<boolean>;
3671
+
3672
+ /** A type's taxonomy — see `ContentTypeSpec.taxonomy`. */
3673
+ export declare interface TaxonomyConfig {
3674
+ /** A declared `Schema.Array(Schema.String)` field. */
3675
+ readonly field: string;
3676
+ readonly terms: ReadonlyArray<VocabularyTerm>;
3677
+ /** A term outside the vocabulary: `refuse` (default) fails the save, `keep` keeps it as typed. */
3678
+ readonly unknown?: 'refuse' | 'keep';
3679
+ }
3680
+
3681
+ /** The value a save stores: the normalised terms, then the unknown ones (refused by validation unless kept). */
3682
+ export declare const taxonomyValue: (config: Pick<TaxonomyConfig, "terms">, input: ReadonlyArray<unknown>) => ReadonlyArray<string>;
3683
+
3684
+ /** Effect form of {@link teamDefaultRole}. */
3685
+ export declare const teamDefaultRole: (...args: Parameters<typeof teamDefaultRole_2>) => Effect<string | null, never, never>;
3686
+
3687
+ /** The role a new editor of the workspace gets, or null (the app's own default). */
3688
+ declare const teamDefaultRole_2: (store: DataStore, tenantId: string) => Promise<string | null>;
3689
+
3690
+ /** Effect form of {@link teamInvitations}. */
3691
+ export declare const teamInvitations: (...args: Parameters<typeof teamInvitations_2>) => Effect<readonly {
3692
+ readonly email: string;
3693
+ readonly role: string;
3694
+ }[], never, never>;
3695
+
3696
+ /** Everyone invited to the workspace, by address. */
3697
+ declare const teamInvitations_2: (store: DataStore, tenantId: string) => Promise<ReadonlyArray<{
3698
+ readonly email: string;
3699
+ readonly role: string;
3700
+ }>>;
3701
+
3702
+ export declare interface TeamPlan {
3703
+ /** `set`: the workspace gets it; `kept`: it has one already; null: the blueprint names none. */
3704
+ readonly defaultRole: {
3705
+ readonly role: string;
3706
+ readonly action: 'set' | 'kept';
3707
+ } | null;
3708
+ readonly members: ReadonlyArray<{
3709
+ readonly email: string;
3710
+ readonly role: string;
3711
+ readonly action: 'invite' | 'present';
3712
+ }>;
3713
+ /** Types that need a review: `require` is new for the workspace, `present` it had already. */
3714
+ readonly reviewRequired: ReadonlyArray<{
3715
+ readonly type: string;
3716
+ readonly action: 'require' | 'present';
3717
+ }>;
3718
+ }
3719
+
3720
+ /** What is wrong with a blueprint's team; empty when nothing is. */
3721
+ export declare const teamProblems: (team: BlueprintTeam) => ReadonlyArray<string>;
3722
+
3723
+ /** The template a row names, if any (undefined for none, null for an unknown id). */
3724
+ export declare const templateOf: (type: Typed, row: Readonly<Record<string, unknown>>) => PageTemplate | null | undefined;
3725
+
3726
+ /** Declared on a content type as `templates`. */
3727
+ export declare interface TemplatesConfig {
3728
+ /** An optional string field that stores the template's id. */
3729
+ readonly field: string;
3730
+ /** The `Schema.Components` field the rules apply to. */
3731
+ readonly components: string;
3732
+ readonly list: ReadonlyArray<PageTemplate>;
3733
+ }
3734
+
3735
+ /**
3736
+ * The values a new document built from `templateId` starts with: the
3737
+ * template's id, its preset values and its components (the save stamps each
3738
+ * component's instance id). Null for an unknown template.
3739
+ */
3740
+ export declare const templateValues: (type: Typed, templateId: string) => Record<string, unknown> | null;
3741
+
3742
+ /** Where a row breaks the rules of the template it names. Empty when it keeps them. */
3743
+ export declare const templateViolations: (type: Typed, row: Readonly<Record<string, unknown>>) => ReadonlyArray<FieldViolation>;
3744
+
3745
+ /** The entries whose term `text` (in the source language) contains. */
3746
+ export declare const termsIn: (text: string, entries: ReadonlyArray<GlossaryEntry>) => ReadonlyArray<GlossaryEntry>;
3747
+
3748
+ /**
3749
+ * Put `mark` on the text in `[start, end)`, or take it off when all of it
3750
+ * already carries it. Text runs are split at the edges; a link is left as it
3751
+ * is (a link carries no marks).
3752
+ */
3753
+ export declare const toggleMark: (content: ReadonlyArray<RichInline>, start: number, end: number, mark: RichMark) => ReadonlyArray<RichInline>;
3754
+
3755
+ export declare interface ToolExposure {
3756
+ readonly tool: string;
3757
+ readonly state: 'on' | 'off' | 'locked';
3758
+ /** The step of the chain that decided it; null for the site's default. */
3759
+ readonly decidedAt: number | null;
3760
+ }
3761
+
3762
+ /** An XLIFF 2.1 core document for one file. */
3763
+ export declare const toXliff: (exchange: XliffExchange) => string;
3764
+
3765
+ /** Where one language stands against the source. */
3766
+ export declare interface TranslationState {
3767
+ readonly locale: string;
3768
+ /**
3769
+ * `missing` — no variant; `upToDate` — based on the source's current
3770
+ * revision; `outdated` — based on an older one (see `changed`);
3771
+ * `unknown` — the variant never said what it was based on.
3772
+ */
3773
+ readonly state: 'missing' | 'upToDate' | 'outdated' | 'unknown';
3774
+ readonly variantId: string | null;
3775
+ /** For `outdated`: the source fields that changed since its basis. */
3776
+ readonly changed: ReadonlyArray<string>;
3777
+ }
3778
+
3779
+ /** The source's variant and each target language's state. */
3780
+ export declare interface TranslationStatus {
3781
+ /** The source variant (null when the document has none in the source language). */
3782
+ readonly source: {
3783
+ readonly variantId: string;
3784
+ readonly revisionId: string;
3785
+ } | null;
3786
+ readonly targets: ReadonlyArray<TranslationState>;
3787
+ }
3788
+
3789
+ /** Effect form of {@link translationStatus}. */
3790
+ export declare const translationStatus: (...args: Parameters<typeof translationStatus_2>) => Effect<TranslationStatus, never, never>;
3791
+
3792
+ /** The translation status of one document; `translationStatuses` for many. */
3793
+ declare const translationStatus_2: (store: DataStore, type: ContentType, documentId: string, scope: Pick<CmsScope, "site" | "environment">, sourceLocale: string, targetLocales: ReadonlyArray<string>) => Promise<TranslationStatus>;
3794
+
3795
+ /** Effect form of {@link translationStatuses}. */
3796
+ export declare const translationStatuses: (...args: Parameters<typeof translationStatuses_2>) => Effect<ReadonlyMap<string, TranslationStatus>, never, never>;
3797
+
3798
+ /**
3799
+ * The translation status of each of `documentIds`, read together: three
3800
+ * reads per 500 documents (their variants, those revisions, the revisions
3801
+ * they were based on), not three per document.
3802
+ */
3803
+ declare const translationStatuses_2: (store: DataStore, type: ContentType, documentIds: ReadonlyArray<string>, scope: Pick<CmsScope, "site" | "environment">, sourceLocale: string, targetLocales: ReadonlyArray<string>) => Promise<ReadonlyMap<string, TranslationStatus>>;
3804
+
3805
+ export declare interface TranslationUnit {
3806
+ /** Where the text lives: `title`, `body/<blockId>`, `body/<blockId>/<item>`,
3807
+ * `body/<blockId>/<row>.<cell>`, `body/<blockId>/caption`,
3808
+ * `sections/<instanceId>/<prop>`. */
3809
+ readonly id: string;
3810
+ readonly source: string;
3811
+ /** The translation, when there is one. */
3812
+ readonly target?: string;
3813
+ /** XLIFF segment state. */
3814
+ readonly state?: 'initial' | 'translated' | 'reviewed' | 'final';
3815
+ }
3816
+
3817
+ /** The translatable text of a document's values, one unit per piece, in field order. Empty text is left out. */
3818
+ export declare const translationUnits: (fields: Readonly<Record<string, FieldSchema>>, values: Readonly<Record<string, unknown>>, prefix?: string) => ReadonlyArray<TranslationUnit>;
3819
+
3820
+ /** How a content type forms a tree. Validated by `defineContentType`. */
3821
+ export declare interface TreeConfig {
3822
+ /** An optional `Schema.Reference(<this type>)` field: the parent document. */
3823
+ readonly parent: string;
3824
+ /** An optional number field ordering siblings (ascending; unset sorts last). */
3825
+ readonly order?: string;
3826
+ /** The string field that is this node's path segment — usually the slug. */
3827
+ readonly segment: string;
3828
+ /**
3829
+ * Optional fields a page takes from the nearest ancestor that sets them
3830
+ * (a header, a footer): read with {@link inheritedValue}. `locked: true`
3831
+ * means no page may set it — only whatever the app supplies above the
3832
+ * tree (a site default).
3833
+ */
3834
+ readonly inherit?: Readonly<Record<string, InheritRule>>;
3835
+ }
3836
+
3837
+ /** One published variant offered to {@link buildTree}. */
3838
+ export declare interface TreeEntry {
3839
+ readonly row: Row;
3840
+ readonly locale: string;
3841
+ readonly fallback: boolean;
3842
+ }
3843
+
3844
+ /** One published document placed in the tree. */
3845
+ export declare interface TreeNode {
3846
+ readonly documentId: string;
3847
+ /** The parent's documentId; null at the root. */
3848
+ readonly parent: string | null;
3849
+ /** 0 at the root. */
3850
+ readonly depth: number;
3851
+ /** The segments from the root down to this node. */
3852
+ readonly segments: ReadonlyArray<string>;
3853
+ /** `segments` joined with `/`. */
3854
+ readonly path: string;
3855
+ /** The published variant that answers for this document. */
3856
+ readonly row: Row;
3857
+ /** The locale of `row`. */
3858
+ readonly locale: string;
3859
+ /** True when `row` is a fallback locale's variant. */
3860
+ readonly fallback: boolean;
3861
+ }
3862
+
3863
+ /** What {@link CmsApi.tree} and {@link CmsApi.route} read. */
3864
+ export declare interface TreeOptions {
3865
+ /** Locales to take a document's variant from, in order, when the requested
3866
+ * locale has none. */
3867
+ readonly fallback?: ReadonlyArray<string>;
3868
+ /** Equality filters applied to every row read (e.g. the site's tenant). */
3869
+ readonly filter?: Readonly<Record<string, unknown>>;
3870
+ }
3871
+
3872
+ declare type Typed = {
3873
+ readonly name: string;
3874
+ readonly fields: Readonly<Record<string, FieldSchema>>;
3875
+ readonly templates?: TemplatesConfig;
3876
+ };
3877
+
3878
+ /** Effect form of {@link typeDraftText}. */
3879
+ export declare const typeDraftText: (...args: Parameters<typeof typeDraftText_2>) => Effect<Readonly<Record<string, unknown>>, ContentNotFound, never>;
3880
+
3881
+ /**
3882
+ * Merge one editor's edit (an encoded CRDT update) into a text. The merge is
3883
+ * order-independent, so edits that cross on the wire both survive.
3884
+ * `ContentNotFound` for a text the caller cannot see. In the caller's
3885
+ * transaction.
3886
+ */
3887
+ declare const typeDraftText_2: (tx: DataStore, textId: string, update: Uint8Array) => Promise<Row>;
3888
+
3889
+ /** Effect form of {@link unavailableAmong}. */
3890
+ export declare const unavailableAmong: (...args: Parameters<typeof unavailableAmong_2>) => Effect<ReadonlyMap<string, UnavailableReason>, ReferenceUnavailable, never>;
3891
+
3892
+ /**
3893
+ * The documents among `documentIds` that may not be used at `now`, with why.
3894
+ * A document without a record (a type without availability, not published
3895
+ * yet) is not listed.
3896
+ */
3897
+ declare const unavailableAmong_2: (store: DataStore, documentIds: ReadonlyArray<string>, scope: Pick<CmsScope, "site" | "environment">, now?: Date) => Promise<ReadonlyMap<string, UnavailableReason>>;
3898
+
3899
+ /** Why a referenced document may not be used. */
3900
+ export declare type UnavailableReason = 'blocked' | 'expired';
3901
+
3902
+ /** Undo the last step: the form to show, and the history after it; null when there is nothing to undo. */
3903
+ export declare const undoEdit: (history: EditHistory, current: Readonly<Record<string, unknown>>) => {
3904
+ readonly history: EditHistory;
3905
+ readonly values: Readonly<Record<string, unknown>>;
3906
+ readonly label: string;
3907
+ } | null;
3908
+
3909
+ /** Effect form of {@link uninstallExtension}. */
3910
+ export declare const uninstallExtension: (...args: Parameters<typeof uninstallExtension_2>) => Effect<ExtensionRemoval, never, never>;
3911
+
3912
+ /** Remove an extension and its data; the data comes back as the export. */
3913
+ declare const uninstallExtension_2: (tx: DataStore, extensionId: string) => Promise<ExtensionRemoval>;
3914
+
546
3915
  /**
547
3916
  * Mark a string field unique PER TENANT. The derived `<type>_drafts` +
548
3917
  * `<type>_published` tables get a real composite `(tenantId, <field>)`
@@ -553,16 +3922,35 @@ export declare const slugify: (value: unknown) => string;
553
3922
  */
554
3923
  export declare const unique: () => FieldRefinement;
555
3924
 
3925
+ /** A stable fingerprint of the units' ids and source text — the import checks the source has not changed since. */
3926
+ export declare const unitsHash: (units: ReadonlyArray<TranslationUnit>) => string;
3927
+
3928
+ /** Effect-native `unpublish` (see {@link saveDraftEffect}). */
3929
+ export declare const unpublish: (store: DataStore, type: ContentType, id: string, scope: CmsScope) => Effect_2.Effect<void, ContentNotFound>;
3930
+
3931
+ /** Effect form of {@link unpublishDue}. */
3932
+ export declare const unpublishDue: (...args: Parameters<typeof unpublishDue_2>) => Effect<readonly string[], never, never>;
3933
+
556
3934
  /**
557
- * Take a published row down: delete it from `<type>_published` and flip
558
- * the draft (when present) back to `status: 'draft'`. Atomic per row via
559
- * `store.transactional`. Throws `ContentNotFound` when the id has no
560
- * published row in the caller's scope.
3935
+ * Take down every entry of `type` whose scheduled `unpublishAt` has passed.
3936
+ * Returns the ids that were unpublished. Each in its own transaction: the
3937
+ * published copy goes (with its references and search entry, as `unpublish`
3938
+ * does) and `unpublishAt` is cleared together. An entry that is not live when
3939
+ * its time comes only has the marker cleared — there is nothing to take down.
3940
+ * Idempotent; hand it a store outside any transaction (a schedule's
3941
+ * `app.store`), which sweeps every tenant, or a request store for one.
561
3942
  */
562
- export declare const unpublish: (store: DataStore, type: ContentType, id: string) => Promise<void>;
3943
+ declare const unpublishDue_2: (store: DataStore, type: ContentType, now?: Date) => Promise<ReadonlyArray<string>>;
563
3944
 
564
- /** Effect-native `unpublish` (see {@link saveDraftEffect}). */
565
- export declare const unpublishEffect: (store: DataStore, type: ContentType, id: string) => Effect.Effect<void, ContentNotFound>;
3945
+ /** Effect form of {@link upgradeExtension}. */
3946
+ export declare const upgradeExtension: (...args: Parameters<typeof upgradeExtension_2>) => Effect<ExtensionChange, never, never>;
3947
+
3948
+ /**
3949
+ * Move an installed extension to a newer `manifest`. Nothing new asked for:
3950
+ * applied now, and the grant becomes exactly what the new version asks for.
3951
+ * Anything new: it waits (`pending`), the installed version keeps running.
3952
+ */
3953
+ declare const upgradeExtension_2: (tx: DataStore, manifest: CmsExtensionManifest) => Promise<ExtensionChange>;
566
3954
 
567
3955
  /**
568
3956
  * Typed accessor for handlers — reads the `cms` slot the app attached to
@@ -574,13 +3962,42 @@ export declare const useCms: (ctx: {
574
3962
  readonly cms?: unknown;
575
3963
  }) => CmsApi;
576
3964
 
3965
+ /** Effect form of {@link usedBy}. */
3966
+ export declare const usedBy: (...args: Parameters<typeof usedBy_2>) => Effect<readonly ReferenceUse[], never, never>;
3967
+
3968
+ /**
3969
+ * Where a document is used by published content, in one site and
3970
+ * environment, across locales. The store's tenant scoping applies: a request
3971
+ * store sees its own tenant's uses only.
3972
+ */
3973
+ declare const usedBy_2: (store: DataStore, target: {
3974
+ readonly type: string;
3975
+ readonly documentId: string;
3976
+ }, scope: Pick<CmsScope, "site" | "environment">) => Promise<ReadonlyArray<ReferenceUse>>;
3977
+
577
3978
  /**
578
3979
  * Validate a row against a content type's save-time rules. Throws
579
3980
  * `ContentValidationFailed` carrying EVERY violation (per-field detail)
580
3981
  * when any rule breaks; returns nothing on success. The throwing face of
581
3982
  * `contentViolations` — `saveDraft` calls this after derivation.
582
3983
  */
583
- export declare const validateContent: (type: Pick<ContentType, "name" | "fields">, row: Readonly<Record<string, unknown>>) => void;
3984
+ export declare const validateContent: (type: Pick<ContentType, "name" | "fields"> & Partial<Pick<ContentType, "taxonomy">>, row: Readonly<Record<string, unknown>>) => void;
3985
+
3986
+ /**
3987
+ * A field's value as the text a person compares: a rich document's text (one
3988
+ * line per block), a component list one line per component with its text
3989
+ * props, a date as its ISO time, anything else structured as compact JSON.
3990
+ */
3991
+ export declare const valueText: (value: unknown) => string;
3992
+
3993
+ export declare type Variant = 'A' | 'B';
3994
+
3995
+ export declare interface VariantResult {
3996
+ readonly readers: number;
3997
+ readonly conversions: number;
3998
+ /** conversions / readers; 0 without readers. */
3999
+ readonly rate: number;
4000
+ }
584
4001
 
585
4002
  /**
586
4003
  * Verify a preview token. Returns the `{ type, id }` claim on success,
@@ -591,6 +4008,34 @@ export declare const verifyPreviewToken: (token: string, options?: {
591
4008
  secret?: string;
592
4009
  }) => PreviewClaim | null;
593
4010
 
4011
+ export declare const VISUAL_EDITING_PROTOCOL = "voltro.cms.visual/1";
4012
+
4013
+ /** A message for the other side of `session`. */
4014
+ export declare const visualMessage: <M extends {
4015
+ readonly kind: string;
4016
+ }>(session: VisualSession, message: M) => M & {
4017
+ protocol: typeof VISUAL_EDITING_PROTOCOL;
4018
+ nonce: string;
4019
+ };
4020
+
4021
+ /** A message event as far as these checks read it. */
4022
+ export declare interface VisualMessageEvent {
4023
+ readonly origin: string;
4024
+ readonly data: unknown;
4025
+ }
4026
+
4027
+ /** Who may talk: the one origin, with the nonce of this session. */
4028
+ export declare interface VisualSession {
4029
+ readonly origin: string;
4030
+ readonly nonce: string;
4031
+ }
4032
+
4033
+ /** One term and the spellings that mean it. */
4034
+ export declare interface VocabularyTerm {
4035
+ readonly term: string;
4036
+ readonly synonyms?: ReadonlyArray<string>;
4037
+ }
4038
+
594
4039
  /** Comparison operators accepted by `.where(field, op, value)`. */
595
4040
  export declare type WhereOp = '=' | '!=' | '<' | '<=' | '>' | '>=';
596
4041
 
@@ -601,10 +4046,66 @@ export declare const widgetFor: (hint: EditorHint, overrides?: Partial<Record<Ed
601
4046
 
602
4047
  /** Props for a single field widget. */
603
4048
  export declare interface WidgetProps {
4049
+ /** The control's element id — the field's `<label>` points at it, so a
4050
+ * widget that renders its own control must put it on that control. */
4051
+ readonly id: string;
604
4052
  readonly name: string;
605
4053
  readonly field: FieldSchema;
606
4054
  readonly value: unknown;
607
4055
  readonly onChange: (value: unknown) => void;
608
4056
  }
609
4057
 
4058
+ /** Effect form of {@link withdrawInvitation}. */
4059
+ export declare const withdrawInvitation: (...args: Parameters<typeof withdrawInvitation_2>) => Effect<boolean, never, never>;
4060
+
4061
+ /** Withdraw the invitation of `email`; false when there was none. */
4062
+ declare const withdrawInvitation_2: (tx: DataStore, tenantId: string, email: string) => Promise<boolean>;
4063
+
4064
+ /** A component withheld for want of consent: which purpose would release it. */
4065
+ export declare interface WithheldInstance {
4066
+ readonly instanceId: string;
4067
+ readonly componentId: string;
4068
+ readonly consentRequired: string;
4069
+ readonly props: Readonly<Record<string, never>>;
4070
+ }
4071
+
4072
+ /** Effect form of {@link workspaceReviewTypes}. */
4073
+ export declare const workspaceReviewTypes: (...args: Parameters<typeof workspaceReviewTypes_2>) => Effect<readonly string[], never, never>;
4074
+
4075
+ /** The content types whose publishing needs a review in the workspace (those left to it). */
4076
+ declare const workspaceReviewTypes_2: (store: DataStore, tenantId: string) => Promise<ReadonlyArray<string>>;
4077
+
4078
+ /** Effect form of {@link writeAvailability}. */
4079
+ export declare const writeAvailability: (...args: Parameters<typeof writeAvailability_2>) => Effect<void, ReferenceUnavailable, never>;
4080
+
4081
+ /** Record the availability a published document of `type` now has. */
4082
+ declare const writeAvailability_2: (tx: DataStore, type: ContentType, published: Row, scope: CmsScope) => Promise<void>;
4083
+
4084
+ export declare interface XliffExchange {
4085
+ readonly srcLang: string;
4086
+ readonly trgLang: string;
4087
+ /** The `<file id>` — which document and revision this is. */
4088
+ readonly fileId: string;
4089
+ /** `<note category>` → text: what the importer checks (source hash, type, revision). */
4090
+ readonly notes: Readonly<Record<string, string>>;
4091
+ readonly units: ReadonlyArray<TranslationUnit>;
4092
+ }
4093
+
4094
+ /** An XLIFF file that cannot be read, or would be unsafe to. */
4095
+ export declare class XliffInvalid extends Error {
4096
+ readonly reason: string;
4097
+ readonly _tag = "XliffInvalid";
4098
+ constructor(reason: string);
4099
+ }
4100
+
4101
+ /**
4102
+ * The instant a local wall time means in `zone`. A wall time in a gap moves
4103
+ * to the first moment after it (`gap`); one in a fold takes the earlier of
4104
+ * its two instants (`fold`).
4105
+ */
4106
+ export declare const zonedInstant: (local: string, zone: string) => {
4107
+ readonly instant: Date;
4108
+ readonly adjusted?: "gap" | "fold";
4109
+ };
4110
+
610
4111
  export { }