@relyio/sdk 0.12.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/CHANGELOG.md +84 -0
  2. package/dist/{chunk-3DRDHXLY.js → chunk-3NPPMGB6.js} +435 -23
  3. package/dist/{chunk-FRJEUAAF.js → chunk-6NGJXLOR.js} +22 -11
  4. package/dist/{chunk-DXCVO6M5.cjs → chunk-DEDIJKHY.cjs} +22 -11
  5. package/dist/{chunk-POEEDYFM.js → chunk-EW23SZPX.js} +7 -2
  6. package/dist/{chunk-3MSFWXQL.cjs → chunk-FOSM4LMM.cjs} +7 -2
  7. package/dist/{chunk-FI5VIF4M.cjs → chunk-Z6GLWSSD.cjs} +442 -22
  8. package/dist/client/index.cjs +3 -3
  9. package/dist/client/index.d.cts +4 -5
  10. package/dist/client/index.d.ts +4 -5
  11. package/dist/client/index.js +1 -1
  12. package/dist/{define-schema-mrEZbY1h.d.ts → define-schema-UHViXKiv.d.ts} +2 -219
  13. package/dist/{define-schema-DgctHlI2.d.cts → define-schema-sWJ8Zn7C.d.cts} +2 -219
  14. package/dist/{include-paths-CL4gHv6I.d.cts → include-paths-Bs5FhNw2.d.cts} +2191 -108
  15. package/dist/{include-paths-CrJNTsMl.d.ts → include-paths-Cb7iPCW2.d.ts} +2191 -108
  16. package/dist/index--_u1nPHv.d.cts +507 -0
  17. package/dist/index-8DozAWsA.d.ts +507 -0
  18. package/dist/{index-BrvEg6-A.d.cts → index-BT0L8xJj.d.cts} +41 -53
  19. package/dist/{index-Pw0onkJe.d.ts → index-CPjJ25R4.d.ts} +41 -53
  20. package/dist/index.cjs +119 -112
  21. package/dist/index.d.cts +39 -70
  22. package/dist/index.d.ts +39 -70
  23. package/dist/index.js +5 -29
  24. package/dist/markdown/index.cjs +13750 -0
  25. package/dist/markdown/index.d.cts +111 -0
  26. package/dist/markdown/index.d.ts +111 -0
  27. package/dist/markdown/index.js +13742 -0
  28. package/dist/rich-text/index.cjs +26 -6
  29. package/dist/rich-text/index.d.cts +3 -148
  30. package/dist/rich-text/index.d.ts +3 -148
  31. package/dist/rich-text/index.js +1 -1
  32. package/dist/rich-text.d-BWc-5gX1.d.cts +326 -0
  33. package/dist/rich-text.d-BWc-5gX1.d.ts +326 -0
  34. package/dist/schema/index.cjs +34 -34
  35. package/dist/schema/index.d.cts +9 -178
  36. package/dist/schema/index.d.ts +9 -178
  37. package/dist/schema/index.js +1 -1
  38. package/dist/types/index.d.cts +2 -3
  39. package/dist/types/index.d.ts +2 -3
  40. package/package.json +14 -3
  41. package/dist/index-B9RfZVF1.d.ts +0 -861
  42. package/dist/index-b-AkfTUv.d.cts +0 -861
  43. package/dist/rich-text.d-rKmpgdGd.d.cts +0 -200
  44. package/dist/rich-text.d-rKmpgdGd.d.ts +0 -200
@@ -1,4 +1,4 @@
1
- import { w as RichTextValue, t as RichTextTable, c as RichTextCodeGroup, s as RichTextStructure, n as RichTextMarkType } from './rich-text.d-rKmpgdGd.cjs';
1
+ import { b as RichTextValue, c as RichTextShapeValue, d as RichTextEntryLinkMark, y as RichTextTable, h as RichTextCodeGroup, x as RichTextStructure, s as RichTextMarkType } from './rich-text.d-BWc-5gX1.cjs';
2
2
 
3
3
  /**
4
4
  * Generated by scripts/emit-openapi-types.mjs from @relyio/api's committed
@@ -986,6 +986,21 @@ interface components {
986
986
  retriable?: boolean;
987
987
  };
988
988
  };
989
+ /** @description An asset entry’s `urls`, sent beside its `file` once `file.status` is `ready`: an image’s `original` and `variants`, a file’s `original`, a video’s `playback`, `poster` and `download`. Every URL is on the delivery gateway; a protected or private asset’s carries a short-lived token minted for this request. */
990
+ AssetUrls: {
991
+ /** @description An image or a file: its original bytes. */
992
+ original?: string;
993
+ /** @description An image: each delivery variant’s id, mapped to its URL. */
994
+ variants?: {
995
+ [key: string]: string;
996
+ };
997
+ /** @description A video: its HLS/DASH manifest. */
998
+ playback?: string;
999
+ /** @description A video: its poster image. */
1000
+ poster?: string;
1001
+ /** @description A video: its downloadable MP4, when enabled. */
1002
+ download?: string;
1003
+ };
989
1004
  /** @description One distinct value of the field, and the entry it was first found in. */
990
1005
  AutocompleteSuggestion: {
991
1006
  /** @description The suggested value. */
@@ -997,6 +1012,19 @@ interface components {
997
1012
  /** @description The value with its matched part wrapped in `<em>`, when Atlas highlighted it. */
998
1013
  highlight?: string;
999
1014
  };
1015
+ /** @description An entry link left pointing nowhere: who holds it, where, and the heading anchor it names. */
1016
+ BrokenEntryLink: {
1017
+ /** @description The linking entry’s id. */
1018
+ entryUid: string;
1019
+ /** @description The linking entry’s content type. */
1020
+ contentType: string;
1021
+ /** @description The rich-text field holding the link, spelt as the include path that names it: `body`, `sections.body`. */
1022
+ field: string;
1023
+ /** @description The heading anchor the link names, which this entry no longer has. */
1024
+ anchor: string;
1025
+ /** @description The locale the link is published in. */
1026
+ locale: string;
1027
+ };
1000
1028
  /** @description One change to one entry, ids only. Refetch the entry through the ordinary read path to see it. */
1001
1029
  Change: {
1002
1030
  entryId: string;
@@ -1012,7 +1040,7 @@ interface components {
1012
1040
  nextCursor: string | null;
1013
1041
  hasMore: boolean;
1014
1042
  };
1015
- /** @description One entry: its fields at the top level, as the content type declares them, and `_metadata`. An asset entry also carries `file`, an `AssetFile`, and `urls` once the file is ready. */
1043
+ /** @description One entry: its fields at the top level, as the content type declares them, and `_metadata`. An asset entry also carries `file`, an `AssetFile`, and `urls`, an `AssetUrls`, once the file is ready. */
1016
1044
  Entry: {
1017
1045
  _metadata: components['schemas']['EntryMetadata'];
1018
1046
  } & {
@@ -1115,7 +1143,7 @@ interface components {
1115
1143
  ErrorResponse: {
1116
1144
  error: {
1117
1145
  /** @enum {string} */
1118
- code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_BEING_DELETED' | 'ORGANIZATION_DELETE_BLOCKED' | 'ORGANIZATION_IN_ANOTHER_CELL' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | 'PROJECT_IN_ANOTHER_CELL' | 'RATE_LIMIT_EXCEEDED' | 'READ_ONLY_KEY' | 'REQUEST_INVALID' | 'REQUEST_TIMEOUT' | 'RESOURCE_CONFLICT' | 'RESOURCE_EXPIRED' | 'RESOURCE_NOT_FOUND' | 'REVERIFICATION_REQUIRED' | 'SERVICE_INDETERMINATE' | 'TRANSACTION_ROLLED_BACK' | 'USAGE_QUOTA_EXCEEDED' | 'USER_NOT_PROVISIONED';
1146
+ code: 'ACCESS_DENIED' | 'AI_UNAVAILABLE_IN_REGION' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_BEING_DELETED' | 'ORGANIZATION_DELETE_BLOCKED' | 'ORGANIZATION_IN_ANOTHER_CELL' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | 'PROJECT_IN_ANOTHER_CELL' | 'RATE_LIMIT_EXCEEDED' | 'READ_ONLY_KEY' | 'REQUEST_INVALID' | 'REQUEST_TIMEOUT' | 'RESOURCE_CONFLICT' | 'RESOURCE_EXPIRED' | 'RESOURCE_NOT_FOUND' | 'REVERIFICATION_REQUIRED' | 'SERVICE_INDETERMINATE' | 'TRANSACTION_ROLLED_BACK' | 'USAGE_QUOTA_EXCEEDED' | 'USER_NOT_PROVISIONED';
1119
1147
  messages: string[];
1120
1148
  details?: {
1121
1149
  [key: string]: unknown;
@@ -1315,7 +1343,7 @@ interface components {
1315
1343
  };
1316
1344
  };
1317
1345
  };
1318
- /** @description The entry after a restore: its fields at the top level and `_metadata`, which also lists what the restore left out. */
1346
+ /** @description The entry after a restore: its fields at the top level and `_metadata`, which also lists what the restore left out and the links other entries publish that it left pointing nowhere. */
1319
1347
  RestoredEntry: {
1320
1348
  _metadata: components['schemas']['RestoredEntryMetadata'];
1321
1349
  } & {
@@ -1394,8 +1422,190 @@ interface components {
1394
1422
  firstPublishedAt?: string;
1395
1423
  /** @description The entry’s outgoing references, across every locale, each once. */
1396
1424
  refs: components['schemas']['EntryRef'][];
1397
- /** @description Each value of the restored version the active schema no longer declares, by path (`legacy`, `seo.note`, `faq[_key=="k1"].note` — an item named by its key). A restore writes what the schema still declares and is never refused for the rest; empty when the version held nothing removed. A replay of the restore under the same `Idempotency-Key` answers the entry as it stands and leaves this out. */
1425
+ /** @description Each value of the restored version the active schema no longer declares, by path (`legacy`, `seo.note`, `faq[_key=="k1"].note` — an item named by its key). A restore writes what the schema still declares and is never refused for the rest; empty when the version held nothing removed. A replay of the restore under the same `Idempotency-Key` answers the list the restore did. */
1398
1426
  leftOut?: string[];
1427
+ /** @description Each entry link another entry publishes whose `anchor` names a heading this restore took away from the content its reader lands on, as a revision lists them. A restore of a published locale lands on its draft, so it takes none away and this is empty. A replay of the restore under the same `Idempotency-Key` answers the list the restore did. */
1428
+ brokenLinks?: components['schemas']['BrokenEntryLink'][];
1429
+ };
1430
+ /** @description The entry after a revision: its fields at the top level and `_metadata`, which also lists the links other entries publish that the revision left pointing nowhere. */
1431
+ RevisedEntry: {
1432
+ _metadata: components['schemas']['RevisedEntryMetadata'];
1433
+ } & {
1434
+ [key: string]: unknown;
1435
+ };
1436
+ /** @description What this service reports about an entry beside its fields, and the links a revision left pointing nowhere. */
1437
+ RevisedEntryMetadata: {
1438
+ id: string;
1439
+ /** @description The content type. */
1440
+ type: string;
1441
+ /** @enum {string} */
1442
+ entryType: 'asset' | 'content' | 'settings' | 'singleton';
1443
+ /** @description The slug field’s value at `locale`, or null when the type declares none. */
1444
+ slug: string | null;
1445
+ /**
1446
+ * @description Container lifecycle only. Publication is per locale: `localeStatus`.
1447
+ * @enum {string}
1448
+ */
1449
+ status: 'active' | 'archived' | 'proposed';
1450
+ /** @description The reported locale’s own version counter — not the entry’s shared-field counter. `0` when that locale has no content of its own. With `id` and `locale`, it is what `X-Entity-Tag` is minted from. */
1451
+ version: number;
1452
+ /** @description The locale the fields beside this object were composed for. */
1453
+ locale: string;
1454
+ /** @description How many versions `locale` has. Sent on a single-entry read; a list leaves it out. */
1455
+ versionCount?: number;
1456
+ /** @description `locale`’s version numbers, newest first, at most 25. Sent on a single-entry read; a list leaves it out. */
1457
+ versions?: number[];
1458
+ /**
1459
+ * @description Publication state of `locale`. Absent when that locale has no content of its own: what is visible in it is inherited through the fallback chain.
1460
+ * @enum {string}
1461
+ */
1462
+ localeStatus?: 'archived' | 'draft' | 'published';
1463
+ /** @description Whether `locale` has unpublished changes of its own. */
1464
+ localeHasDraft: boolean;
1465
+ /** @description Every locale holding unpublished content of its own, sorted. A shared-field draft is not listed: it is `hasDraft`. */
1466
+ draftLocales: string[];
1467
+ /** @description Whether the shared (non-localized) fields have unpublished changes. Publishing any locale makes them live, so they are unpublished work in every locale. */
1468
+ hasDraft: boolean;
1469
+ /** @description The locale the request named, when it named one other than the default. On `?locales=a,b,c` it is always sent: the primary, or `*` when the list names as many locales as the entry has — as on `?locale=*`. */
1470
+ requestedLocale?: string;
1471
+ /** @description The schema’s default locale. */
1472
+ defaultLocale: string;
1473
+ /** @description Each field whose value came from another locale, mapped to that locale. Absent when none did. */
1474
+ localeFallbacksApplied?: {
1475
+ [key: string]: string;
1476
+ };
1477
+ /** @description Each required field the entry holds no value for, which this read filled with its kind’s empty value — `""` for text, the tree holding nothing (`{ _type: "richText", version: 1, children: [] }`) for rich text, `[]` for a list, `false` for a boolean — so a required field is always present. A draft may leave these empty; publishing refuses it. Each is a value path, a list item named by its key: `title`, `seo.title`, `faq[_key=="k1"].question` — the spelling a validation error’s path uses, so a path still finds its item after a reorder. Absent when none was filled. */
1478
+ emptyRequiredFields?: string[];
1479
+ /** @description Every locale the entry has content in, the default first. */
1480
+ availableLocales: components['schemas']['EntryLocale'][];
1481
+ /** @description The fields of every other locale asked for, keyed by locale — on `?locales=a,b` and `?locale=*`. A locale with no visible fields is left out. */
1482
+ localizations?: {
1483
+ [key: string]: {
1484
+ [key: string]: unknown;
1485
+ };
1486
+ };
1487
+ /**
1488
+ * Format: date-time
1489
+ * @description When the entry was created.
1490
+ */
1491
+ createdAt: string;
1492
+ /**
1493
+ * Format: date-time
1494
+ * @description When the entry was last written.
1495
+ */
1496
+ updatedAt: string;
1497
+ /**
1498
+ * Format: date-time
1499
+ * @description When the entry was last published. Absent until it is.
1500
+ */
1501
+ publishedAt?: string;
1502
+ /**
1503
+ * Format: date-time
1504
+ * @description When the entry was first published. Absent until it is.
1505
+ */
1506
+ firstPublishedAt?: string;
1507
+ /** @description The entry’s outgoing references, across every locale, each once. */
1508
+ refs: components['schemas']['EntryRef'][];
1509
+ /** @description Each entry link another entry publishes whose `anchor` names a heading this revision took away from the content its reader lands on — in the link’s locale, or the first locale of its fallback chain this entry publishes. The revision is never refused for them; the linking entry’s own next publish is (`ENTRY_LINK_ANCHOR_NOT_FOUND`). Only what this revision took away is listed, and empty when it took none. A replay of the revision under the same `Idempotency-Key` answers the list the revision did. */
1510
+ brokenLinks?: components['schemas']['BrokenEntryLink'][];
1511
+ };
1512
+ /** @description The settings group after a write or a reset: its fields at the top level and `_metadata`, which also lists the links other entries publish that the write left pointing nowhere. */
1513
+ RevisedSettingsGroup: {
1514
+ _metadata: components['schemas']['RevisedSettingsGroupMetadata'];
1515
+ } & {
1516
+ [key: string]: unknown;
1517
+ };
1518
+ /** @description What this service reports about a settings group beside its fields, and the links a write left pointing nowhere. */
1519
+ RevisedSettingsGroupMetadata: {
1520
+ id: string;
1521
+ /** @description The settings group. */
1522
+ groupId: string;
1523
+ /** @description The reported locale’s own version counter — not the entry’s shared-field counter. `0` when that locale has no content of its own. With `id` and `locale`, it is what `X-Entity-Tag` is minted from. */
1524
+ version: number;
1525
+ /** @description The locale the fields beside this object were composed for. */
1526
+ locale: string;
1527
+ /** @description How many versions `locale` has. */
1528
+ versionCount: number;
1529
+ /** @description `locale`’s version numbers, newest first, at most 25. */
1530
+ versions: number[];
1531
+ /**
1532
+ * @description Publication state of `locale`. Absent when that locale has no content of its own: what is visible in it is inherited through the fallback chain.
1533
+ * @enum {string}
1534
+ */
1535
+ localeStatus?: 'archived' | 'draft' | 'published';
1536
+ /** @description Whether `locale` has unpublished changes of its own. */
1537
+ localeHasDraft: boolean;
1538
+ /** @description Every locale holding unpublished content of its own, sorted. A shared-field draft is not listed: it is `hasDraft`. */
1539
+ draftLocales: string[];
1540
+ /** @description Whether the shared (non-localized) fields have unpublished changes. Publishing any locale makes them live, so they are unpublished work in every locale. */
1541
+ hasDraft: boolean;
1542
+ /**
1543
+ * Format: date-time
1544
+ * @description When the group was last written.
1545
+ */
1546
+ updatedAt: string;
1547
+ /** @description Each entry link another entry publishes whose `anchor` names a heading this write took away from the settings group’s content, as an entry revision lists them. The write is never refused for them; the linking entry’s own next publish is (`ENTRY_LINK_ANCHOR_NOT_FOUND`). Empty when it took none away. A replay of the write under the same `Idempotency-Key` answers the list the write did. */
1548
+ brokenLinks?: components['schemas']['BrokenEntryLink'][];
1549
+ };
1550
+ /** @description The singleton after a write: its fields at the top level and `_metadata`, which also lists the links other entries publish that the write left pointing nowhere. */
1551
+ RevisedSingleton: {
1552
+ _metadata: components['schemas']['RevisedSingletonMetadata'];
1553
+ } & {
1554
+ [key: string]: unknown;
1555
+ };
1556
+ /** @description What this service reports about a singleton beside its fields, and the links a write left pointing nowhere. */
1557
+ RevisedSingletonMetadata: {
1558
+ id: string;
1559
+ /** @description The singleton type. */
1560
+ type: string;
1561
+ /**
1562
+ * @description Container lifecycle only. Publication is per locale: `localeStatus`.
1563
+ * @enum {string}
1564
+ */
1565
+ status: 'active' | 'archived' | 'proposed';
1566
+ /** @description The reported locale’s own version counter — not the entry’s shared-field counter. `0` when that locale has no content of its own. With `id` and `locale`, it is what `X-Entity-Tag` is minted from. */
1567
+ version: number;
1568
+ /** @description The locale the fields beside this object were composed for. */
1569
+ locale: string;
1570
+ /** @description How many versions `locale` has. */
1571
+ versionCount: number;
1572
+ /** @description `locale`’s version numbers, newest first, at most 25. */
1573
+ versions: number[];
1574
+ /**
1575
+ * @description Publication state of `locale`. Absent when that locale has no content of its own: what is visible in it is inherited through the fallback chain.
1576
+ * @enum {string}
1577
+ */
1578
+ localeStatus?: 'archived' | 'draft' | 'published';
1579
+ /** @description Whether `locale` has unpublished changes of its own. */
1580
+ localeHasDraft: boolean;
1581
+ /** @description Every locale holding unpublished content of its own, sorted. A shared-field draft is not listed: it is `hasDraft`. */
1582
+ draftLocales: string[];
1583
+ /** @description Whether the shared (non-localized) fields have unpublished changes. Publishing any locale makes them live, so they are unpublished work in every locale. */
1584
+ hasDraft: boolean;
1585
+ /**
1586
+ * Format: date-time
1587
+ * @description When the singleton was created.
1588
+ */
1589
+ createdAt: string;
1590
+ /**
1591
+ * Format: date-time
1592
+ * @description When the singleton was last written.
1593
+ */
1594
+ updatedAt: string;
1595
+ /**
1596
+ * Format: date-time
1597
+ * @description When the singleton was last published. Absent until it is.
1598
+ */
1599
+ publishedAt?: string;
1600
+ /**
1601
+ * Format: date-time
1602
+ * @description When the singleton was first published. Absent until it is.
1603
+ */
1604
+ firstPublishedAt?: string;
1605
+ /** @description Each required field the singleton holds no value for, which this read filled with its kind’s empty value, as a value path naming a list item by its key — as on an entry. Absent when none was. */
1606
+ emptyRequiredFields?: string[];
1607
+ /** @description Each entry link another entry publishes whose `anchor` names a heading this write took away from the singleton’s content, as an entry revision lists them. The write is never refused for them; the linking entry’s own next publish is (`ENTRY_LINK_ANCHOR_NOT_FOUND`). Empty when it took none away. A replay of the write under the same `Idempotency-Key` answers the list the write did. */
1608
+ brokenLinks?: components['schemas']['BrokenEntryLink'][];
1399
1609
  };
1400
1610
  /** @description How a hit’s relevance was reached. Sent on a search that asked for `explain`. */
1401
1611
  ScoreBreakdown: {
@@ -1417,7 +1627,7 @@ interface components {
1417
1627
  } & {
1418
1628
  [key: string]: unknown;
1419
1629
  };
1420
- /** @description One hit: the entry’s fields at the top level — at `_metadata.locale`, or only the aliases a `fields` projection names — its `_metadata`, and the score annotations the request asked for. Not an entry read: see `SearchHitMetadata`. */
1630
+ /** @description One hit: the entry’s fields at the top level — at `_metadata.locale`, or only the aliases a `fields` projection names — its `_metadata`, and the score annotations the request asked for. A hit of an asset type also carries `file`, an `AssetFile`, and `urls`, an `AssetUrls`, once the file is ready. Not an entry read: see `SearchHitMetadata`. */
1421
1631
  SearchHit: {
1422
1632
  _metadata: components['schemas']['SearchHitMetadata'];
1423
1633
  /** @description Relevance. Sent on a search that asked for `includeScore`, and on every similar hit. */
@@ -1615,7 +1825,7 @@ interface components {
1615
1825
  id?: string;
1616
1826
  error: {
1617
1827
  /** @enum {string} */
1618
- code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_BEING_DELETED' | 'ORGANIZATION_DELETE_BLOCKED' | 'ORGANIZATION_IN_ANOTHER_CELL' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | 'PROJECT_IN_ANOTHER_CELL' | 'RATE_LIMIT_EXCEEDED' | 'READ_ONLY_KEY' | 'REQUEST_INVALID' | 'REQUEST_TIMEOUT' | 'RESOURCE_CONFLICT' | 'RESOURCE_EXPIRED' | 'RESOURCE_NOT_FOUND' | 'REVERIFICATION_REQUIRED' | 'SERVICE_INDETERMINATE' | 'TRANSACTION_ROLLED_BACK' | 'USAGE_QUOTA_EXCEEDED' | 'USER_NOT_PROVISIONED';
1828
+ code: 'ACCESS_DENIED' | 'AI_UNAVAILABLE_IN_REGION' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_BEING_DELETED' | 'ORGANIZATION_DELETE_BLOCKED' | 'ORGANIZATION_IN_ANOTHER_CELL' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | 'PROJECT_IN_ANOTHER_CELL' | 'RATE_LIMIT_EXCEEDED' | 'READ_ONLY_KEY' | 'REQUEST_INVALID' | 'REQUEST_TIMEOUT' | 'RESOURCE_CONFLICT' | 'RESOURCE_EXPIRED' | 'RESOURCE_NOT_FOUND' | 'REVERIFICATION_REQUIRED' | 'SERVICE_INDETERMINATE' | 'TRANSACTION_ROLLED_BACK' | 'USAGE_QUOTA_EXCEEDED' | 'USER_NOT_PROVISIONED';
1619
1829
  messages: string[];
1620
1830
  details?: {
1621
1831
  [key: string]: unknown;
@@ -2199,6 +2409,15 @@ interface operations {
2199
2409
  'application/json': components['schemas']['RefusalInternalError'];
2200
2410
  };
2201
2411
  };
2412
+ /** @description SERVICE_INDETERMINATE */
2413
+ 503: {
2414
+ headers: {
2415
+ [name: string]: unknown;
2416
+ };
2417
+ content: {
2418
+ 'application/json': components['schemas']['RefusalServiceIndeterminate'];
2419
+ };
2420
+ };
2202
2421
  };
2203
2422
  };
2204
2423
  ingestUsage: {
@@ -2781,8 +3000,7 @@ interface operations {
2781
3000
  };
2782
3001
  content: {
2783
3002
  'application/json': {
2784
- /** @description The payload itself. */
2785
- data: unknown;
3003
+ data: components['schemas']['RevisedEntry'];
2786
3004
  };
2787
3005
  };
2788
3006
  };
@@ -4727,6 +4945,21 @@ interface operations {
4727
4945
  };
4728
4946
  };
4729
4947
  };
4948
+ /** @description RESOURCE_NOT_FOUND */
4949
+ 404: {
4950
+ headers: {
4951
+ [name: string]: unknown;
4952
+ };
4953
+ content: {
4954
+ 'application/json': components['schemas']['RefusalResourceNotFound'];
4955
+ 'text/event-stream': {
4956
+ /** @enum {string} */
4957
+ type: 'change' | 'complete' | 'error' | 'heartbeat';
4958
+ } & {
4959
+ [key: string]: unknown;
4960
+ };
4961
+ };
4962
+ };
4730
4963
  /** @description RESOURCE_EXPIRED */
4731
4964
  410: {
4732
4965
  headers: {
@@ -4854,6 +5087,15 @@ interface operations {
4854
5087
  'application/json': components['schemas']['RefusalAccessDeniedOrPlanFeatureUnavailableOrUsageQuotaExceeded'];
4855
5088
  };
4856
5089
  };
5090
+ /** @description RESOURCE_NOT_FOUND */
5091
+ 404: {
5092
+ headers: {
5093
+ [name: string]: unknown;
5094
+ };
5095
+ content: {
5096
+ 'application/json': components['schemas']['RefusalResourceNotFound'];
5097
+ };
5098
+ };
4857
5099
  /** @description PROJECT_IN_ANOTHER_CELL */
4858
5100
  421: {
4859
5101
  headers: {
@@ -5039,6 +5281,15 @@ interface operations {
5039
5281
  'application/json': components['schemas']['RefusalAccessDeniedOrPlanFeatureUnavailableOrUsageQuotaExceeded'];
5040
5282
  };
5041
5283
  };
5284
+ /** @description RESOURCE_NOT_FOUND */
5285
+ 404: {
5286
+ headers: {
5287
+ [name: string]: unknown;
5288
+ };
5289
+ content: {
5290
+ 'application/json': components['schemas']['RefusalResourceNotFound'];
5291
+ };
5292
+ };
5042
5293
  /** @description PROJECT_IN_ANOTHER_CELL */
5043
5294
  421: {
5044
5295
  headers: {
@@ -5735,6 +5986,15 @@ interface operations {
5735
5986
  'application/json': components['schemas']['RefusalAccessDeniedOrPlanFeatureUnavailableOrUsageQuotaExceeded'];
5736
5987
  };
5737
5988
  };
5989
+ /** @description RESOURCE_NOT_FOUND */
5990
+ 404: {
5991
+ headers: {
5992
+ [name: string]: unknown;
5993
+ };
5994
+ content: {
5995
+ 'application/json': components['schemas']['RefusalResourceNotFound'];
5996
+ };
5997
+ };
5738
5998
  /** @description PROJECT_IN_ANOTHER_CELL */
5739
5999
  421: {
5740
6000
  headers: {
@@ -5930,6 +6190,15 @@ interface operations {
5930
6190
  'application/json': components['schemas']['RefusalAccessDeniedOrPlanFeatureUnavailableOrUsageQuotaExceeded'];
5931
6191
  };
5932
6192
  };
6193
+ /** @description RESOURCE_NOT_FOUND */
6194
+ 404: {
6195
+ headers: {
6196
+ [name: string]: unknown;
6197
+ };
6198
+ content: {
6199
+ 'application/json': components['schemas']['RefusalResourceNotFound'];
6200
+ };
6201
+ };
5933
6202
  /** @description PROJECT_IN_ANOTHER_CELL */
5934
6203
  421: {
5935
6204
  headers: {
@@ -6093,8 +6362,7 @@ interface operations {
6093
6362
  };
6094
6363
  content: {
6095
6364
  'application/json': {
6096
- /** @description The payload itself. */
6097
- data: unknown;
6365
+ data: components['schemas']['RevisedSettingsGroup'];
6098
6366
  };
6099
6367
  };
6100
6368
  };
@@ -6308,8 +6576,7 @@ interface operations {
6308
6576
  };
6309
6577
  content: {
6310
6578
  'application/json': {
6311
- /** @description The payload itself. */
6312
- data: unknown;
6579
+ data: components['schemas']['RevisedSettingsGroup'];
6313
6580
  };
6314
6581
  };
6315
6582
  };
@@ -6725,8 +6992,7 @@ interface operations {
6725
6992
  };
6726
6993
  content: {
6727
6994
  'application/json': {
6728
- /** @description The payload itself. */
6729
- data: unknown;
6995
+ data: components['schemas']['RevisedSingleton'];
6730
6996
  };
6731
6997
  };
6732
6998
  };
@@ -7117,31 +7383,483 @@ interface operations {
7117
7383
  }
7118
7384
 
7119
7385
  /**
7120
- * Workflow definition for content approval pipelines
7386
+ * Where the SDK's transport gets its truth.
7121
7387
  *
7122
- * Workflows define approval stages that content must pass through before
7123
- * publication. They can be configured globally and per content type.
7388
+ * Every route this client calls is named by its **path template as the
7389
+ * committed document spells it**, and the body type it expects is read out of
7390
+ * that document rather than written down here. `api-schema.ts` beside this file
7391
+ * is generated by `pnpm api:types` from `apps/services/api/openapi-spec.json`,
7392
+ * which is itself generated from that service's `RouteContract`s
7393
+ * (`INV-API-DOCUMENT-IS-DERIVED`). So the chain is: one declaration in
7394
+ * `routes.ts` → the serializer that produces the body → the document → these
7395
+ * types → the method that reads it.
7124
7396
  *
7125
- * @example
7126
- * // Simple workflow with one approval stage
7127
- * const workflow = defineWorkflow({
7128
- * enabled: true,
7129
- * stages: [
7130
- * defineWorkflowStage('review', {
7131
- * displayName: 'Editorial Review',
7132
- * allowedRoles: ['editor', 'admin']
7133
- * })
7134
- * ]
7135
- * })
7397
+ * That chain is the answer to the question this phase exists to close. Before
7398
+ * it, six SDK methods read a key the server does not send; each had no caller
7399
+ * and no test, so nothing could see them. Now:
7136
7400
  *
7137
- * @example
7138
- * // Multi-stage workflow
7139
- * const workflow = defineWorkflow({
7140
- * enabled: true,
7141
- * stages: [
7142
- * defineWorkflowStage('editorial-review', {
7143
- * displayName: 'Editorial Review',
7144
- * allowedRoles: ['editor']
7401
+ * - A route that changes **kind** — `collection` to `object`, say — changes
7402
+ * whether the document's 200 body carries `page` and whether `data` is an
7403
+ * array. `Wire<…>` follows, `readPayload` follows, and the method's declared
7404
+ * return type stops matching. `tsc` names the method.
7405
+ * - A route that changes **path** or is deleted stops being a `keyof paths`, so
7406
+ * the call site fails on the literal.
7407
+ * - A route that changes **dialect** changes `page` from `CursorPage` to
7408
+ * `OffsetPage`, and anything reading `nextCursor` fails.
7409
+ *
7410
+ * `/v1` lives in these templates because it lives in the document
7411
+ * (`INV-API-VERSION-IS-DECIDED-ONCE`). Before this phase the SDK's base URL was
7412
+ * `https://api.relyio.com` and its paths were `/{contentType}`, so every
7413
+ * versioned request went to a path the router does not serve.
7414
+ *
7415
+ * Spec: `devtools/docs/guide/engineering/api-contract-spec.md`,
7416
+ * `INV-API-CLIENT-IS-DERIVED`.
7417
+ */
7418
+
7419
+ /** Every path the committed document declares. */
7420
+ type ApiPath = keyof paths;
7421
+ type Verb = 'get' | 'post' | 'put' | 'patch' | 'delete';
7422
+ /** The verbs the document declares on this path — not the seven HTTP has. */
7423
+ type ApiMethod<P extends ApiPath> = {
7424
+ [M in Verb]: M extends keyof paths[P] ? paths[P][M] extends {
7425
+ responses: unknown;
7426
+ } ? M : never : never;
7427
+ }[Verb];
7428
+ type Operation<P extends ApiPath, M extends ApiMethod<P>> = M extends keyof paths[P] ? paths[P][M] : never;
7429
+ type JsonBody<R> = R extends {
7430
+ content: {
7431
+ 'application/json': infer B;
7432
+ };
7433
+ } ? B : never;
7434
+ /**
7435
+ * The success body the document declares, preferring 200 where a route serves
7436
+ * both. A route with neither — `kind: 'empty'`, which serves 204 — resolves to
7437
+ * `never`, and `readPayload` cannot be called on it.
7438
+ */
7439
+ type ApiSuccessBody<P extends ApiPath, M extends ApiMethod<P>> = Operation<P, M> extends {
7440
+ responses: infer R;
7441
+ } ? 200 extends keyof R ? JsonBody<R[200]> : 201 extends keyof R ? JsonBody<R[201]> : never : never;
7442
+ /**
7443
+ * The document's success body with the payload typed as the caller's `T`.
7444
+ *
7445
+ * The array arm is tested **first** on purpose: `{ data: unknown[] }` also
7446
+ * satisfies `{ data: unknown }`, so the object arm would swallow every
7447
+ * collection and hand a list route's caller a single entity — which is the
7448
+ * exact defect class (`ContentClient.children` reading `.data.items` from an
7449
+ * object route) that this phase makes unrepresentable.
7450
+ */
7451
+ type Wire<P extends ApiPath, M extends ApiMethod<P>, T> = ApiSuccessBody<P, M> extends {
7452
+ data: unknown[];
7453
+ } ? Omit<ApiSuccessBody<P, M>, 'data'> & {
7454
+ data: T[];
7455
+ } : ApiSuccessBody<P, M> extends {
7456
+ data: unknown;
7457
+ } ? Omit<ApiSuccessBody<P, M>, 'data'> & {
7458
+ data: T;
7459
+ } : ApiSuccessBody<P, M>;
7460
+ /**
7461
+ * The path parameters the document declares for this operation, or `never`
7462
+ * where it declares none.
7463
+ *
7464
+ * `never` rather than `{}`: a route with no segments must **forbid** a `path`
7465
+ * argument, not merely tolerate an empty one, and `keyof Record<string, never>`
7466
+ * is `string`, so an empty-object encoding cannot be told apart from a real
7467
+ * one at the type level.
7468
+ */
7469
+ type PathParamsOf<P extends ApiPath, M extends ApiMethod<P>> = Operation<P, M> extends {
7470
+ parameters: {
7471
+ path?: infer X;
7472
+ };
7473
+ } ? [X] extends [undefined] ? never : NonNullable<X> : never;
7474
+ /** What {@link matchRoute} recovers from a URL the client emitted. */
7475
+ interface RouteMatch {
7476
+ /** The document's path template — the value a tag translator switches on. */
7477
+ path: ApiPath;
7478
+ /** The template's `{name}` segments, decoded: the inverse of {@link fillPath}. */
7479
+ params: Record<string, string>;
7480
+ /** The query string; a key that appears more than once comes back as an array. */
7481
+ query: Record<string, string | string[]>;
7482
+ }
7483
+ interface MatchRouteOptions {
7484
+ /**
7485
+ * The client's `baseUrl`, when it carries a path prefix of its own
7486
+ * (`https://example.com/relyio`). Its path is removed before the template is
7487
+ * matched. Unneeded for the default `https://api.relyio.com`.
7488
+ */
7489
+ baseUrl?: string;
7490
+ }
7491
+ /**
7492
+ * Recover the route a URL names: the inverse of {@link fillPath}, over the same
7493
+ * committed document (`INV-API-CLIENT-IS-DERIVED`).
7494
+ *
7495
+ * `matchRoute(url).path` is an `ApiPath`, so anything that keys behaviour on a
7496
+ * request — a cache-tag translator, say — switches on the document's templates
7497
+ * and never on a route table of its own.
7498
+ *
7499
+ * Returns `null` for a URL no declared template matches — a presigned storage
7500
+ * URL, or a path outside `baseUrl` — rather than a guess.
7501
+ */
7502
+ declare function matchRoute(url: string | URL, options?: MatchRouteOptions): RouteMatch | null;
7503
+
7504
+ /**
7505
+ * Configuration types for the RelyIO SDK
7506
+ */
7507
+
7508
+ interface RelyIOConfig {
7509
+ /**
7510
+ * API key for authentication, sent as `X-API-Key`.
7511
+ *
7512
+ * Required by every request, not by construction: a client built without one — a module-scope
7513
+ * client whose `process.env` variable is unset during a build — constructs, and each request it
7514
+ * makes rejects with `MissingApiKeyError` before anything is sent. Under `relyio dev` the
7515
+ * sandbox's key is used instead, so none need be configured.
7516
+ */
7517
+ apiKey: string;
7518
+ /** Base URL for the RelyIO API */
7519
+ baseUrl?: string;
7520
+ /** Dataset to use */
7521
+ dataset?: string;
7522
+ /**
7523
+ * Default locale for all content queries
7524
+ * Can be overridden per-query using .locale() or .withLocale()
7525
+ *
7526
+ * @example
7527
+ * const client = createClient({
7528
+ * apiKey: '...',
7529
+ * locale: 'en-US', // All queries default to English
7530
+ * })
7531
+ */
7532
+ locale?: string;
7533
+ /**
7534
+ * How long one request may take, in milliseconds, before it ends as a `TimeoutError` (defaults
7535
+ * to 30000). A number from 1 to 2147483647, the longest a timer waits; `0`, `NaN`, `Infinity` or
7536
+ * anything larger is refused, and no value turns the timeout off.
7537
+ */
7538
+ timeout?: number;
7539
+ /**
7540
+ * The most attempts one request makes, the first included (defaults to 3). `1` turns retrying
7541
+ * off; a value that is not a whole number of at least 1 is refused. Only a failure a later attempt
7542
+ * can change is retried, and only where sending the request twice cannot apply it twice.
7543
+ */
7544
+ retryAttempts?: number;
7545
+ /** Whether to use HTTPS (defaults to true) */
7546
+ useSsl?: boolean;
7547
+ /** Environment mode */
7548
+ environment?: 'development' | 'staging' | 'production';
7549
+ /**
7550
+ * Cache configuration.
7551
+ *
7552
+ * Declarative only: the client keeps no response cache, and nothing in it reads
7553
+ * these values, so every call goes to `fetch`. There is no SDK-side cache to
7554
+ * turn off under a framework that caches `fetch` itself (Next.js).
7555
+ */
7556
+ cache?: CacheConfig;
7557
+ /** Real-time configuration */
7558
+ realtime?: RealtimeConfig;
7559
+ /** Debug configuration */
7560
+ debug?: DebugConfig;
7561
+ /** Custom headers to include with requests */
7562
+ headers?: Record<string, string>;
7563
+ /**
7564
+ * The function every request to the RelyIO API is sent through. Omit it and the
7565
+ * client calls the runtime's `globalThis.fetch`, looked up per request. File
7566
+ * bytes an asset upload PUTs straight to a presigned storage URL do not pass
7567
+ * through it.
7568
+ *
7569
+ * The client still builds every request — URL, method, headers, body, signal —
7570
+ * and hands this function that `RequestInit` unchanged, retries included, so an
7571
+ * `Idempotency-Key` minted for a write is the same on every attempt. Supply one
7572
+ * to add what your framework reads off the `RequestInit`, for example Next.js
7573
+ * cache tags:
7574
+ *
7575
+ * @example
7576
+ * const client = createClient({
7577
+ * apiKey: '...',
7578
+ * fetch: (input, init) => fetch(input, { ...init, next: { tags: ['posts'] } }),
7579
+ * })
7580
+ */
7581
+ fetch?: typeof globalThis.fetch;
7582
+ /**
7583
+ * RelyIO's live edge, which `liveChanges()` — and `<RelyIOProvider live>` from `@relyio/react`
7584
+ * with a publishable key — follows a dataset's published changes at. An `https:` or `wss:` URL
7585
+ * (`http:` or `ws:` for a local one); the socket and the poll each use the scheme they need.
7586
+ *
7587
+ * Omitted, it is derived from `baseUrl` for RelyIO's own API only: `https://api.relyio.com`
7588
+ * (the default) follows `https://live.relyio.com`. For any other `baseUrl` there is no address to
7589
+ * derive, so set this, or `liveChanges()` ends at once with a `LiveEdgeError` naming it and sends
7590
+ * nothing.
7591
+ *
7592
+ * @example
7593
+ * const relyio = createClient({
7594
+ * apiKey: 'rly_pub_…',
7595
+ * baseUrl: 'http://localhost:3000',
7596
+ * liveUrl: 'http://localhost:8787',
7597
+ * })
7598
+ */
7599
+ liveUrl?: string;
7600
+ /**
7601
+ * The `WebSocket` class `liveChanges()` opens its socket with. Omit it and the client uses the
7602
+ * runtime's global `WebSocket` — every browser, and Node 22 or later — looked up per connection.
7603
+ * Where there is none, as in Node 18 and 20, it polls the edge instead, about every fifteen
7604
+ * seconds.
7605
+ *
7606
+ * Supply one to use a library's socket where the runtime has none, or to add what your runtime
7607
+ * lets a socket carry.
7608
+ */
7609
+ webSocket?: LiveWebSocketConstructor;
7610
+ /** Browser-specific configuration */
7611
+ browser?: BrowserConfig;
7612
+ /**
7613
+ * `relyio dev` sandbox detection.
7614
+ *
7615
+ * When developing under `relyio dev`, the CLI injects an ephemeral sandbox's dataset + scoped
7616
+ * preview API key (via env vars or a local `.relyio/dev.json`). The SDK then transparently
7617
+ * targets that sandbox instead of production — no code changes required.
7618
+ *
7619
+ * - Omit (default): detection runs automatically unless `NODE_ENV === 'production'`, so
7620
+ * `relyio dev -- pnpm dev` "just works" while production builds stay untouched.
7621
+ * - `false`: disable detection entirely (force production targeting even in a dev shell).
7622
+ * - `true`: force detection even when `NODE_ENV === 'production'`.
7623
+ */
7624
+ dev?: boolean;
7625
+ }
7626
+ /**
7627
+ * The part of a `WebSocket` the live edge transport uses. A browser's `WebSocket` and Node's (22 and
7628
+ * later) are assignable as they are; `src/__tests__/changes.types.ts` holds the platform's to it.
7629
+ * Each event reaches its listener as `unknown` and is read field by field.
7630
+ */
7631
+ interface LiveWebSocket {
7632
+ /** `0` connecting, `1` open, `2` closing, `3` closed. */
7633
+ readonly readyState: number;
7634
+ send(data: string): void;
7635
+ close(code?: number, reason?: string): void;
7636
+ addEventListener(type: 'open' | 'message' | 'close' | 'error', listener: (event: unknown) => void): void;
7637
+ }
7638
+ type LiveWebSocketConstructor = new (url: string) => LiveWebSocket;
7639
+ /**
7640
+ * What `updateConfig()` takes: any option of {@link RelyIOConfig}, each laid over the value the
7641
+ * client holds rather than over its default.
7642
+ *
7643
+ * An option left out or given as `undefined` keeps the value the client holds, and a bag of options
7644
+ * you name keeps every field you do not name. `null` removes — "`undefined` keeps, `null` removes" —
7645
+ * and the types accept it only where a value can go: an option with no default (`locale`,
7646
+ * `dataset`, `fetch`, `browser.onCorsError`, `debug.logger`, …), which is then absent, and a header,
7647
+ * which is then no longer sent. An option with a default takes no `null`: removed, it would leave
7648
+ * nothing but that default. `createClient()` has nothing to remove, so its options take no `null`.
7649
+ *
7650
+ * Which options have no default is read off {@link UndefaultedOption} and {@link UndefaultedField} —
7651
+ * the names {@link ConfigDefaults} leaves optional — so an option that gains or loses a default
7652
+ * changes what `null` can clear with no edit here.
7653
+ */
7654
+ type RelyIOConfigUpdate = Update<Omit<RelyIOConfig, OptionBag | 'headers'>, UndefaultedOption> & {
7655
+ browser?: Update<BrowserConfig, UndefaultedField['browser']>;
7656
+ cache?: Update<CacheConfig, UndefaultedField['cache']>;
7657
+ realtime?: Update<RealtimeConfig, UndefaultedField['realtime']>;
7658
+ debug?: Update<DebugConfig, UndefaultedField['debug']>;
7659
+ /** Headers to add or replace, each kept until named again; `null` stops sending that header. */
7660
+ headers?: Record<string, string | null>;
7661
+ };
7662
+ /** `T`'s options, each one optional, with `null` accepted for the ones named in `Clearable`. */
7663
+ type Update<T, Clearable extends keyof T> = {
7664
+ [K in keyof T]?: K extends Clearable ? T[K] | null : T[K];
7665
+ };
7666
+ interface CacheConfig {
7667
+ /** Whether caching is enabled (defaults to true) */
7668
+ enabled?: boolean;
7669
+ /** Cache TTL in milliseconds (defaults to 5 minutes) */
7670
+ ttl?: number;
7671
+ /** Maximum number of cache entries (defaults to 1000) */
7672
+ maxEntries?: number;
7673
+ /** Maximum cache size in bytes (defaults to 50MB) */
7674
+ maxSize?: number;
7675
+ /** Cache strategies to use */
7676
+ strategies?: CacheStrategy[];
7677
+ }
7678
+ interface RealtimeConfig {
7679
+ /** Whether real-time features are enabled (defaults to true) */
7680
+ enabled?: boolean;
7681
+ /** WebSocket URL for real-time connections */
7682
+ wsUrl?: string;
7683
+ /** Maximum number of reconnection attempts (defaults to 10) */
7684
+ maxReconnectAttempts?: number;
7685
+ /** Reconnection delay in milliseconds (defaults to 1000) */
7686
+ reconnectDelay?: number;
7687
+ /** Heartbeat interval in milliseconds (defaults to 30000) */
7688
+ heartbeatInterval?: number;
7689
+ }
7690
+ interface DebugConfig {
7691
+ /** Whether debug mode is enabled (defaults to false) */
7692
+ enabled?: boolean;
7693
+ /** Whether to log network requests (defaults to false) */
7694
+ logRequests?: boolean;
7695
+ /** Whether to log cache operations (defaults to false) */
7696
+ logCache?: boolean;
7697
+ /** Whether to log WebSocket events (defaults to false) */
7698
+ logWebSocket?: boolean;
7699
+ /** Custom logger function */
7700
+ logger?: (_level: LogLevel, _message: string, _data?: unknown) => void;
7701
+ }
7702
+ /**
7703
+ * The numbers the retry backoff is computed from.
7704
+ *
7705
+ * There is no `retryCondition` here any more. It was a predicate over
7706
+ * `(error, attempt)`, which is structurally unable to see the request — so the
7707
+ * only rule it could express is "is this error retryable", and the rule that
7708
+ * matters is "may this request be sent twice". That question, and the answer,
7709
+ * live in `RetryPolicy` (`http/retry-policy.ts`).
7710
+ */
7711
+ interface RetryConfig {
7712
+ /** Maximum number of attempts, including the first. */
7713
+ maxAttempts: number;
7714
+ /** Base delay between retries in milliseconds */
7715
+ baseDelay: number;
7716
+ /** Maximum delay between retries in milliseconds */
7717
+ maxDelay: number;
7718
+ /** Backoff factor for exponential backoff */
7719
+ backoffFactor: number;
7720
+ /** Whether to add jitter to retry delays */
7721
+ jitter: boolean;
7722
+ }
7723
+ interface RequestConfig {
7724
+ /** HTTP method */
7725
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
7726
+ /** Request URL */
7727
+ url: string;
7728
+ /** Request headers */
7729
+ headers?: Record<string, string>;
7730
+ /** Request body */
7731
+ body?: unknown;
7732
+ /** Query parameters */
7733
+ params?: Record<string, unknown>;
7734
+ /** Request timeout in milliseconds */
7735
+ timeout?: number;
7736
+ /** Whether to retry this request on failure */
7737
+ retryable?: boolean;
7738
+ /** Abort signal for canceling requests */
7739
+ signal?: AbortSignal;
7740
+ /** Additional metadata for the request */
7741
+ metadata?: Record<string, unknown>;
7742
+ }
7743
+ interface ApiResponse<T = unknown> {
7744
+ /**
7745
+ * The response body exactly as the route's contract declares it —
7746
+ * `{ data }`, `{ data, page }`, `{ data, page, meta }` or `{ empty }`.
7747
+ *
7748
+ * Named `body`, not `data`, because the envelope's own key is `data`: the
7749
+ * incumbent `response.data.data` read like a typo and was one 33 times, in
7750
+ * six methods that read a key the server never sent. One `data` in the
7751
+ * spelling means `readPayload(response.body)` is the only way to reach a
7752
+ * payload (`INV-API-CLIENT-IS-DERIVED`).
7753
+ */
7754
+ body: T;
7755
+ /** HTTP status code */
7756
+ status: number;
7757
+ /** HTTP status text */
7758
+ statusText: string;
7759
+ /** Response headers */
7760
+ headers: Record<string, string>;
7761
+ /** Request configuration that generated this response */
7762
+ config: RequestConfig;
7763
+ /** Whether this response came from cache */
7764
+ fromCache?: boolean;
7765
+ /** Cache metadata */
7766
+ cacheMetadata?: {
7767
+ key: string;
7768
+ timestamp: number;
7769
+ ttl: number;
7770
+ };
7771
+ }
7772
+ interface BrowserConfig {
7773
+ /**
7774
+ * Whether requests the client sends from a web page carry the browser's cookies to another
7775
+ * origin (defaults to `false`).
7776
+ *
7777
+ * `false` — and leaving it out, or writing `undefined` — sends every request with
7778
+ * `credentials: 'same-origin'`: nothing to another origin, and a same-origin request — the API
7779
+ * behind a proxy on your own host — sent as the platform's own `fetch` would send it. `true`
7780
+ * sends it with `credentials: 'include'`, which a browser completes only when the answer names
7781
+ * your page's origin in `Access-Control-Allow-Origin` (not `*`) and carries
7782
+ * `Access-Control-Allow-Credentials: true`. The RelyIO API authenticates with your API key and
7783
+ * reads no cookie, so set `true` only for a server of your own in front of it that does.
7784
+ *
7785
+ * Applied only in a web page. On a server, in an edge runtime or in a Web Worker the client sets
7786
+ * no `credentials` mode at all, whatever this says.
7787
+ */
7788
+ includeCredentials?: boolean;
7789
+ /** Whether to use relative URLs for same-origin requests (defaults to false) */
7790
+ useRelativeUrls?: boolean;
7791
+ /** Custom CORS error handling */
7792
+ onCorsError?: (_error: Error, _context: unknown) => void;
7793
+ }
7794
+ type CacheStrategy = 'memory' | 'persistent' | 'network-first' | 'cache-first' | 'stale-while-revalidate';
7795
+ type LogLevel = 'debug' | 'info' | 'warn' | 'error';
7796
+ type Environment = 'development' | 'staging' | 'production';
7797
+ /**
7798
+ * `T` once its defaults are applied: every field present, except the ones named in `NoDefault`,
7799
+ * which stay as optional as `T` declares them because nothing stands in for them.
7800
+ */
7801
+ type WithDefaults<T, NoDefault extends keyof T = never> = Required<Omit<T, NoDefault>> & Pick<T, NoDefault>;
7802
+ /**
7803
+ * The options with no default, absent from a merged configuration until the caller gives one.
7804
+ * `fetch` and `webSocket` among them: absent means the runtime's own, and that is read per request
7805
+ * or per connection rather than captured here. `liveUrl` too: absent is derived from `baseUrl` when
7806
+ * the live transport opens, where RelyIO's own API names its edge, and is otherwise no address.
7807
+ */
7808
+ type UndefaultedOption = 'apiKey' | 'dataset' | 'locale' | 'dev' | 'fetch' | 'liveUrl' | 'webSocket';
7809
+ /** The options that are themselves bags of options, each merged field by field. */
7810
+ type OptionBag = 'browser' | 'cache' | 'realtime' | 'debug';
7811
+ /**
7812
+ * The fields of each bag with no default, absent from a merged configuration until the caller gives
7813
+ * one — and the fields of a bag `updateConfig()` can clear with `null`.
7814
+ */
7815
+ interface UndefaultedField {
7816
+ browser: 'onCorsError';
7817
+ cache: never;
7818
+ realtime: 'wsUrl';
7819
+ debug: 'logger';
7820
+ }
7821
+ /**
7822
+ * The value each option takes when the caller gives none, down to each field of each bag — so a
7823
+ * field of a merged configuration that has a default is never `undefined`, and a reader does not
7824
+ * restate the default. A field with no default (`onCorsError`, `wsUrl`, `logger`) is named in
7825
+ * {@link UndefaultedField}; a field added to a bag without one fails to compile at
7826
+ * {@link DEFAULT_CONFIG} until it gets a default or a name there.
7827
+ */
7828
+ type ConfigDefaults = WithDefaults<Omit<RelyIOConfig, UndefaultedOption | OptionBag>> & {
7829
+ browser: WithDefaults<BrowserConfig, UndefaultedField['browser']>;
7830
+ cache: WithDefaults<CacheConfig, UndefaultedField['cache']>;
7831
+ realtime: WithDefaults<RealtimeConfig, UndefaultedField['realtime']>;
7832
+ debug: WithDefaults<DebugConfig, UndefaultedField['debug']>;
7833
+ };
7834
+ /** The configuration a client runs on: each option the caller gave, and its default where not. */
7835
+ type MergedRelyIOConfig = ConfigDefaults & Pick<RelyIOConfig, UndefaultedOption>;
7836
+
7837
+ /**
7838
+ * Workflow definition for content approval pipelines
7839
+ *
7840
+ * Workflows define approval stages that content must pass through before
7841
+ * publication. They can be configured globally and per content type.
7842
+ *
7843
+ * @example
7844
+ * // Simple workflow with one approval stage
7845
+ * const workflow = defineWorkflow({
7846
+ * enabled: true,
7847
+ * stages: [
7848
+ * defineWorkflowStage('review', {
7849
+ * displayName: 'Editorial Review',
7850
+ * allowedRoles: ['editor', 'admin']
7851
+ * })
7852
+ * ]
7853
+ * })
7854
+ *
7855
+ * @example
7856
+ * // Multi-stage workflow
7857
+ * const workflow = defineWorkflow({
7858
+ * enabled: true,
7859
+ * stages: [
7860
+ * defineWorkflowStage('editorial-review', {
7861
+ * displayName: 'Editorial Review',
7862
+ * allowedRoles: ['editor']
7145
7863
  * }),
7146
7864
  * defineWorkflowStage('legal-approval', {
7147
7865
  * displayName: 'Legal Approval',
@@ -7393,7 +8111,7 @@ declare function isFinalWorkflowStage(workflow: WorkflowDefinition, stageId: str
7393
8111
  * Every field kind, in the order the schema language has always listed them. The one definition of
7394
8112
  * the union in `@relyio/schema`: `FIELD_TYPES` in `types/base/constants.ts` is this tuple.
7395
8113
  */
7396
- declare const FIELD_KINDS: readonly ['shortText', 'longText', 'richText', 'table', 'code', 'email', 'url', 'slug', 'integer', 'decimal', 'boolean', 'enum', 'date', 'dateTime', 'reference', 'tags', 'list', 'object'];
8114
+ declare const FIELD_KINDS: readonly ['shortText', 'longText', 'richText', 'table', 'code', 'email', 'url', 'slug', 'integer', 'decimal', 'boolean', 'enum', 'date', 'dateTime', 'reference', 'tags', 'list', 'object', 'json'];
7397
8115
  /** A field kind: what a field's `type` names. The declaration is keyed by it and by nothing else. */
7398
8116
  type FieldKind = (typeof FIELD_KINDS)[number];
7399
8117
  /**
@@ -7405,6 +8123,167 @@ type OverEveryFieldKind<T extends {
7405
8123
  readonly [K in FieldKind]: unknown;
7406
8124
  }> = T;
7407
8125
 
8126
+ /**
8127
+ * A `json` field's value and its JSON Schema (REL-1811, design decision 18): data nobody models in
8128
+ * RelyIO still has a place.
8129
+ *
8130
+ * - **The value** is any JSON value — an object, an array, a string, a finite number, a boolean or
8131
+ * `null` — stored and served parsed. {@link jsonValueProblems} names what keeps a value from being
8132
+ * one, and the validation document's `x-json` keyword refuses it (`JSON_INVALID`) under every
8133
+ * write profile, a draft's included: a value that is not JSON, or that its field's JSON Schema
8134
+ * refuses, is never stored.
8135
+ * - **The source** a person edits is collaborative text in the live document (ADR 0014), parsed on
8136
+ * save by {@link parseJsonSource}. While it does not parse, or the field's schema refuses what it
8137
+ * parses to, the live save leaves the field out — its stored value stands — and names it, so every
8138
+ * open editor shows it not saving until it does (`@relyio/entry-projection`'s `extractYDocData`,
8139
+ * `leftOut`).
8140
+ * - **The JSON Schema** is the field's optional `config.schema`, written in the vocabulary
8141
+ * {@link JSON_SCHEMA_KEYWORDS} names: a subset of draft-07 that the validation document enforces,
8142
+ * the SDK infers a read's type from and both code generators emit a type from. Deploy refuses any
8143
+ * other keyword by name (`types/fields/data/json.ts`), so the three never disagree about a schema.
8144
+ *
8145
+ * Dependency-free like the rest of `./field-kinds` (`__tests__/dependency-free.test.ts`).
8146
+ */
8147
+ /** A JSON value: what a `json` field holds. */
8148
+ type JsonValue = string | number | boolean | null | readonly JsonValue[] | {
8149
+ readonly [key: string]: JsonValue;
8150
+ };
8151
+ /** The types a JSON Schema's `type` may name (draft-07's simple types). */
8152
+ declare const JSON_SCHEMA_TYPES: readonly ['string', 'number', 'integer', 'boolean', 'object', 'array', 'null'];
8153
+ type JsonSchemaType = (typeof JSON_SCHEMA_TYPES)[number];
8154
+ /**
8155
+ * The `format`s a json field's schema may name: those the validation document's AJV instance knows
8156
+ * (`ajv-formats`). A format it did not know would be ignored, and a constraint nothing enforces is
8157
+ * not one to accept.
8158
+ */
8159
+ declare const JSON_SCHEMA_FORMATS: readonly ['date', 'time', 'date-time', 'email', 'hostname', 'ipv4', 'ipv6', 'uri', 'uuid'];
8160
+ type JsonSchemaFormat = (typeof JSON_SCHEMA_FORMATS)[number];
8161
+ /** A json field's JSON Schema: one node of the vocabulary {@link JSON_SCHEMA_KEYWORDS} names. */
8162
+ interface JsonFieldSchema {
8163
+ readonly type?: JsonSchemaType | readonly JsonSchemaType[];
8164
+ readonly properties?: {
8165
+ readonly [key: string]: JsonFieldSchema;
8166
+ };
8167
+ readonly required?: readonly string[];
8168
+ readonly additionalProperties?: boolean | JsonFieldSchema;
8169
+ readonly items?: JsonFieldSchema;
8170
+ readonly enum?: readonly JsonValue[];
8171
+ readonly const?: JsonValue;
8172
+ readonly anyOf?: readonly JsonFieldSchema[];
8173
+ readonly oneOf?: readonly JsonFieldSchema[];
8174
+ readonly minLength?: number;
8175
+ readonly maxLength?: number;
8176
+ readonly pattern?: string;
8177
+ readonly format?: JsonSchemaFormat;
8178
+ readonly minimum?: number;
8179
+ readonly maximum?: number;
8180
+ readonly exclusiveMinimum?: number;
8181
+ readonly exclusiveMaximum?: number;
8182
+ readonly multipleOf?: number;
8183
+ readonly minItems?: number;
8184
+ readonly maxItems?: number;
8185
+ readonly uniqueItems?: boolean;
8186
+ readonly minProperties?: number;
8187
+ readonly maxProperties?: number;
8188
+ readonly title?: string;
8189
+ readonly description?: string;
8190
+ readonly default?: JsonValue;
8191
+ readonly examples?: readonly JsonValue[];
8192
+ }
8193
+
8194
+ /**
8195
+ * What a read returns for a `json` field (REL-1811): the value its JSON Schema describes, inferred
8196
+ * from the schema literal at the type level, and any JSON value when it gives none — `JsonValue`,
8197
+ * never `any`.
8198
+ *
8199
+ * **The subset that types a value** is the schema's structure, as `@relyio/schema`'s
8200
+ * `JSON_SCHEMA_KEYWORDS` names it — the vocabulary deploy accepts, so a schema that deploys is one
8201
+ * this reads:
8202
+ *
8203
+ * - `const` — that value; `enum` — the union of its members.
8204
+ * - `anyOf` / `oneOf` — the union of each branch.
8205
+ * - `type` — `string`, `number` and `integer` (a `number`), `boolean`, `null`, an `array` of its
8206
+ * `items` (any JSON value without them), an `object`; a list of types, their union.
8207
+ * - An object's `properties`, each a property of its own type — present when `required` names it,
8208
+ * optional otherwise — and its other keys by `additionalProperties`: none when it is `false`,
8209
+ * each of its schema's type when it is a schema and the object declares no `properties` (a map),
8210
+ * and `unknown` otherwise.
8211
+ *
8212
+ * The constraint keywords (`minLength`, `pattern`, `minimum`, `maxItems` …) narrow the values of a
8213
+ * type without changing it, and the annotations say nothing about it. **Anything the subset cannot
8214
+ * say is `JsonValue`**: a schema with none of these keywords, and one whose literal was widened —
8215
+ * `type: string` rather than `'object'` — since a literal the compiler did not keep names nothing.
8216
+ * Write the schema `as const` to keep every literal: without it `required` widens to `string[]` and
8217
+ * every property reads as optional, and an `enum` or a `const` as the type of its members — wider
8218
+ * than the value, never narrower. `relyio generate-types` writes it `as const`.
8219
+ */
8220
+
8221
+ /** A json field's JSON Schema: the vocabulary deploy accepts (`@relyio/schema`'s `JsonFieldSchema`). */
8222
+ type JsonSchema = JsonFieldSchema;
8223
+ /** `true` for `any`, which every conditional would otherwise answer both ways. */
8224
+ type IsAny<T> = 0 extends 1 & T ? true : false;
8225
+ /** One object type from an intersection, so a read's type prints as one object. */
8226
+ type Flatten$1<T> = {
8227
+ [K in keyof T]: T[K];
8228
+ } & {};
8229
+ /**
8230
+ * The value a JSON Schema literal `S` describes — see the module note for the subset. Distributes
8231
+ * over a union of schemas, which is what an `anyOf`'s branches are.
8232
+ */
8233
+ type InferJsonSchema<S> = IsAny<S> extends true ? JsonValue : S extends {
8234
+ readonly const: infer C;
8235
+ } ? C : S extends {
8236
+ readonly enum: ReadonlyArray<infer E>;
8237
+ } ? E : S extends {
8238
+ readonly anyOf: ReadonlyArray<infer A>;
8239
+ } ? InferJsonSchema<A> : S extends {
8240
+ readonly oneOf: ReadonlyArray<infer O>;
8241
+ } ? InferJsonSchema<O> : S extends {
8242
+ readonly type: infer T;
8243
+ } ? T extends ReadonlyArray<infer Each> ? OfType<S, Each> : OfType<S, T> : JsonValue;
8244
+ /** The value of type `T` (one of a schema's `type`s) that `S` describes. Distributes over `T`. */
8245
+ type OfType<S, T> = T extends 'string' ? string : T extends 'number' | 'integer' ? number : T extends 'boolean' ? boolean : T extends 'null' ? null : T extends 'array' ? ArrayOf<S> : T extends 'object' ? ObjectOf<S> : JsonValue;
8246
+ type ArrayOf<S> = S extends {
8247
+ readonly items: infer I;
8248
+ } ? Array<InferJsonSchema<I>> : JsonValue[];
8249
+ type PropertiesOf<S> = S extends {
8250
+ readonly properties: infer P;
8251
+ } ? P : {};
8252
+ /** The property names `required` lists; none when its literal was widened to `string`. */
8253
+ type RequiredOf<S> = S extends {
8254
+ readonly required: ReadonlyArray<infer R>;
8255
+ } ? string extends R ? never : R : never;
8256
+ type ObjectOf<S> = Flatten$1<{
8257
+ [K in keyof PropertiesOf<S> & RequiredOf<S>]: InferJsonSchema<PropertiesOf<S>[K]>;
8258
+ } & {
8259
+ [K in Exclude<keyof PropertiesOf<S>, RequiredOf<S>>]?: InferJsonSchema<PropertiesOf<S>[K]>;
8260
+ } & AdditionalOf<S>>;
8261
+ /**
8262
+ * The keys an object holds beyond its `properties`: none when `additionalProperties` is `false`;
8263
+ * each of its schema's type when the object declares no `properties` (a map); `unknown` otherwise,
8264
+ * since a declared property and an index signature of another type cannot both be read precisely.
8265
+ */
8266
+ type AdditionalOf<S> = S extends {
8267
+ readonly additionalProperties: false;
8268
+ } ? {} : keyof PropertiesOf<S> extends never ? S extends {
8269
+ readonly additionalProperties: infer A;
8270
+ } ? A extends true ? {
8271
+ [key: string]: JsonValue;
8272
+ } : {
8273
+ [key: string]: InferJsonSchema<A>;
8274
+ } : {
8275
+ [key: string]: JsonValue;
8276
+ } : {
8277
+ [key: string]: unknown;
8278
+ };
8279
+ /**
8280
+ * A json field's read: `JsonValue` without a schema, the schema's value with one. `C` is the field's
8281
+ * config, as a builder keeps it.
8282
+ */
8283
+ type JsonFieldValue<C> = C extends {
8284
+ readonly schema?: infer S;
8285
+ } ? [Exclude<S, undefined>] extends [never] ? JsonValue : InferJsonSchema<Exclude<S, undefined>> : JsonValue;
8286
+
7408
8287
  /**
7409
8288
  * Singleton content type definition matching @relyio/schema
7410
8289
  *
@@ -7696,13 +8575,44 @@ type AnyAssetTypeDefinition = AssetTypeDefinition<any>;
7696
8575
  *
7697
8576
  * Mirrors {@link InferContentType}: produces the metadata field shape (a required field present)
7698
8577
  * plus `_metadata`, so it is assignable to `BaseContent` and can parametrize
7699
- * `AssetClient<T>`. The runtime `file`/`urls` blocks are layered on by the
7700
- * client's `AssetEntryResponse<T>` return type, not here, to keep the schema
7701
- * layer free of any dependency on the client layer.
8578
+ * `AssetClient<T>` — whose writes and `where` name exactly these fields. What a **read** returns
8579
+ * adds the {@link AssetServedBlocks}: {@link InferAssetEntry}.
7702
8580
  */
7703
8581
  type InferAssetType<T extends AnyAssetTypeDefinition, S extends FieldSchemaContext | undefined = undefined, I extends string = never> = FieldValues<DeclaredFields<T>, S, 'required', I> & {
7704
8582
  _metadata: EntryMetadata;
7705
8583
  };
8584
+ /**
8585
+ * Customer-facing file binding block on an asset entry: the document's `AssetFile` — status,
8586
+ * backend, file name, MIME type, size, advisory hash, visibility, extracted metadata, focal point,
8587
+ * enrichment and scan status, processing stage/progress/error, and video playback readiness.
8588
+ */
8589
+ type AssetFileBlock = components['schemas']['AssetFile'];
8590
+ /**
8591
+ * Computed gateway delivery URLs (the reserved `urls` key): the document's `AssetUrls` — an image's
8592
+ * `original` and `variants`, a file's `original`, a video's `playback`, `poster` and `download`.
8593
+ * Present only when `file.status` is `ready` — otherwise the response omits `urls` and callers read
8594
+ * `file.status`. Read from the committed document (REL-2194), which declared none until then, so this
8595
+ * was written here by hand.
8596
+ */
8597
+ type AssetUrls = components['schemas']['AssetUrls'];
8598
+ /**
8599
+ * What every read of an asset carries beside its fields and `_metadata`, wherever the asset is read:
8600
+ * `file`, its binding, once one is bound, and `urls`, signed once the file is ready. The Content API
8601
+ * composes an asset's `file` into every entry it serves, an included reference at any depth among
8602
+ * them, and keeps it when an include path picks fields; its entry routes stamp `urls` onto every asset
8603
+ * the payload holds (REL-1812). A read's blocks, not fields: nothing writes or filters by them.
8604
+ */
8605
+ interface AssetServedBlocks {
8606
+ file?: AssetFileBlock;
8607
+ urls?: AssetUrls;
8608
+ }
8609
+ /**
8610
+ * An asset as a read returns it (REL-1812): its fields and `_metadata` ({@link InferAssetType}) and
8611
+ * the {@link AssetServedBlocks}. What `asset(name)` reads, and what a reference to the asset type
8612
+ * reads as once an include path expands it — through a list, an object, rich text or a singleton
8613
+ * alike. `relyio generate-types` writes each asset type's alias with it.
8614
+ */
8615
+ type InferAssetEntry<T extends AnyAssetTypeDefinition, S extends FieldSchemaContext | undefined = undefined, I extends string = never> = InferAssetType<T, S, I> & AssetServedBlocks;
7706
8616
 
7707
8617
  /**
7708
8618
  * What a read returns for each field, derived from the field's declaration (`INV-SS-TYPES-INFERRED`).
@@ -7737,6 +8647,8 @@ type InferAssetType<T extends AnyAssetTypeDefinition, S extends FieldSchemaConte
7737
8647
  * their union told apart by `_type` (REL-1799). A **required** object is given a shape and that
7738
8648
  * shape's required values when the entry is created (REL-2034), so even a draft read holds its
7739
8649
  * `_type` and `_key`.
8650
+ * - A `json` field is the value its JSON Schema describes, inferred from the schema literal, and
8651
+ * `JsonValue` — any JSON value — without one (REL-1811, `./json-schema.ts`).
7740
8652
  */
7741
8653
 
7742
8654
  /**
@@ -7767,8 +8679,14 @@ interface UnresolvedEntry {
7767
8679
  type FieldValueByType<C, S extends Context, K extends string, I extends string, A extends boolean> = OverEveryFieldKind<{
7768
8680
  shortText: string;
7769
8681
  longText: string;
7770
- /** The version-1 tree (REL-1803): `{ _type: 'richText', version: 1, children }`. */
7771
- richText: RichTextValue;
8682
+ /**
8683
+ * The version-1 tree (REL-1803): `{ _type: 'richText', version: 1, children }`, holding the
8684
+ * field's declared Blocks and Inline elements, each its fieldset's value (REL-1807), and — where it
8685
+ * declares `links` — its entry links (REL-1808). The field is one include path: included, every
8686
+ * entry link's `to` is the entry it links to and every reference inside a declared node its entry;
8687
+ * not included, each is its id.
8688
+ */
8689
+ richText: RichTextValue<DeclaredIn<BlocksIn<C>, S, InsideRichText<I, K, BlocksIn<C>>, ExpandsHere<I, K, A>>, DeclaredIn<InlineIn<C>, S, InsideRichText<I, K, InlineIn<C>>, ExpandsHere<I, K, A>>, EntryLinkIn<C, S, K, I, A>>;
7772
8690
  /** Exactly a rich-text table block's value (REL-1806). */
7773
8691
  table: RichTextTable;
7774
8692
  /** Exactly a rich-text code group's value: code with tabs (REL-1806). */
@@ -7788,6 +8706,11 @@ type FieldValueByType<C, S extends Context, K extends string, I extends string,
7788
8706
  tags: string[];
7789
8707
  list: ListValue<C, S, IncludesUnder<I, K>, CoversBelow<I, K, A>>;
7790
8708
  object: ObjectValue<C, S, IncludesUnder<I, K>, CoversBelow<I, K, A>>;
8709
+ /**
8710
+ * The value its JSON Schema describes, and any JSON value without one — `JsonValue`, never `any`
8711
+ * (REL-1811, `./json-schema.ts`).
8712
+ */
8713
+ json: JsonFieldValue<C>;
7791
8714
  }>;
7792
8715
  /**
7793
8716
  * The value a read returns for field `F`, under the include paths `I` of the record it sits in —
@@ -7864,15 +8787,31 @@ type ReferenceTarget<C> = C extends {
7864
8787
  /** `R[K]` where `R` declares `K`. A `Record<string, never>` default declares nothing. */
7865
8788
  type Declared<R, K> = K extends keyof R ? R[K] : never;
7866
8789
  type ContentEntryOf<D, S extends Context, I extends string> = D extends ContentTypeDefinition ? InferContentType<D, S, I> : never;
7867
- type SingletonEntryOf<D, S extends Context, I extends string> = D extends SingletonContentTypeDefinition ? InferSingletonContentType<D, S, I> : never;
7868
- type AssetEntryOf<D, S extends Context, I extends string> = D extends AssetTypeDefinition ? InferAssetType<D, S, I> : never;
7869
- type OrUnresolved<T> = [T] extends [never] ? UnresolvedEntry : T;
8790
+ /**
8791
+ * An expanded singleton: its fields, as a singleton read types them, beside the `_metadata` every
8792
+ * expanded entry carries — {@link EntryMetadata}, not the singleton read's `SingletonMetadata`. The
8793
+ * Content API builds every record an include expands with the entry transform, a singleton's too
8794
+ * (REL-2195), so it reports `entryType`, `slug`, `refs` and the rest, and no version history.
8795
+ */
8796
+ type SingletonEntryOf<D, S extends Context, I extends string> = D extends SingletonContentTypeDefinition ? Omit<InferSingletonContentType<D, S, I>, '_metadata'> & {
8797
+ _metadata: EntryMetadata;
8798
+ } : never;
8799
+ /**
8800
+ * An expanded asset: the fields a path picked of it beside `_metadata`, and the
8801
+ * {@link AssetServedBlocks} — `file` and `urls` — picked or not, as the Content API serves every asset
8802
+ * an include expands, at any depth (REL-1812). With every field, exactly what `asset(name)` reads
8803
+ * (`InferAssetEntry`).
8804
+ */
8805
+ type AssetEntryOf<D, S extends Context, I extends string, Fields> = D extends AssetTypeDefinition ? Selected<InferAssetType<D, S, I>, Fields> & AssetServedBlocks : never;
8806
+ type OrUnresolved<T, Fields> = [T] extends [never] ? Selected<UnresolvedEntry, Fields> : T;
7870
8807
  /**
7871
8808
  * What `include` expands a reference to `Target` into: that type's entry, typed by the schema, under
7872
8809
  * `I`, the include paths that continue past the reference (`customers.logo` → `logo` inside the
7873
- * customer).
8810
+ * customer), cut down to `Fields`, the fields a path picked (`./include-paths.ts`'s `Selected`). The
8811
+ * one place every expansion is typed — a reference at any depth, an entry link, a singleton's or a
8812
+ * settings group's include — so an asset reads as the API serves it wherever it is reached.
7874
8813
  */
7875
- type ExpandedEntry<Target, S extends Context, I extends string = never> = S extends FieldSchemaContext ? OrUnresolved<ContentEntryOf<Declared<S['contentTypes'], Target>, S, I> | SingletonEntryOf<Declared<S['singletonContentTypes'], Target>, S, I> | AssetEntryOf<Declared<NonNullable<S['assetTypes']>, Target>, S, I>> : UnresolvedEntry;
8814
+ type ExpandedEntry<Target, S extends Context, I extends string = never, Fields = EveryField> = S extends FieldSchemaContext ? OrUnresolved<Selected<ContentEntryOf<Declared<S['contentTypes'], Target>, S, I>, Fields> | Selected<SingletonEntryOf<Declared<S['singletonContentTypes'], Target>, S, I>, Fields> | AssetEntryOf<Declared<NonNullable<S['assetTypes']>, Target>, S, I, Fields>, Fields> : Selected<UnresolvedEntry, Fields>;
7876
8815
  /**
7877
8816
  * What a single reference reads as once its target is gone: `null` for an optional one, whose
7878
8817
  * referrers a delete may nullify, and nothing for a required one, whose target cannot be deleted
@@ -7884,7 +8823,7 @@ type Nullified<C> = RequiredIn<C> extends true ? never : null;
7884
8823
  * where a path expands it — the target's entry, narrowed to the fields a path picked. Under an include
7885
8824
  * set the type cannot see (`string`), either.
7886
8825
  */
7887
- type ReferenceValue<C, S extends Context, K extends string, I extends string, A extends boolean> = string extends I ? ReferenceAs<C, string | ExpandedEntry<ReferenceTarget<C>, S, string>> : ReferenceAs<C, ExpandsHere<I, K, A> extends true ? Selected<ExpandedEntry<ReferenceTarget<C>, S, IncludesUnder<I, K>>, SelectionAt<I, K>> : string>;
8826
+ type ReferenceValue<C, S extends Context, K extends string, I extends string, A extends boolean> = string extends I ? ReferenceAs<C, string | ExpandedEntry<ReferenceTarget<C>, S, string>> : ReferenceAs<C, ExpandsHere<I, K, A> extends true ? ExpandedEntry<ReferenceTarget<C>, S, IncludesUnder<I, K>, SelectionAt<I, K>> : string>;
7888
8827
  /** One reference value `V`, as the field holds it: alone, nullable unless required, or a list. */
7889
8828
  type ReferenceAs<C, V> = [Multiplicity<C>] extends [true] ? V[] : [Multiplicity<C>] extends [false | undefined] ? V | Nullified<C> : V | Nullified<C> | V[];
7890
8829
  /**
@@ -7896,6 +8835,54 @@ type ReferenceAs<C, V> = [Multiplicity<C>] extends [true] ? V[] : [Multiplicity<
7896
8835
  type ListValue<C, S extends Context, I extends string, A extends boolean> = C extends {
7897
8836
  readonly of?: infer Shape;
7898
8837
  } ? [ShapesIn<Exclude<Shape, undefined>>] extends [never] ? string[] : Array<ShapeItem<ShapesIn<Exclude<Shape, undefined>>, S, I, A>> : string[];
8838
+ /**
8839
+ * A declared shape's value inside rich text: its item, as a page builder's is — every reference in it
8840
+ * expanded when `A`, the field being included, says so (a rich-text field is one include path).
8841
+ */
8842
+ type DeclaredIn<Shape, S extends Context, I extends string, A extends boolean> = Extract<ShapeItem<Shape, S, I, A>, RichTextShapeValue>;
8843
+ /**
8844
+ * The include paths a rich-text field `K`'s declared nodes `Shape` are read under. Rich text has no
8845
+ * path inside it: the field is one include path, so what a path does at `K` it does to every
8846
+ * reference the nodes hold, at any depth — the server picks each one's fields by `K(…)`'s
8847
+ * parentheses and continues each by `K.…`'s rest (REL-1808). So each path stopping at or past `K` is
8848
+ * re-spelt at every path the shape can include (`body(slug)` → `see(slug)`, `items.ref(slug)`),
8849
+ * and every reference reads the selection and the hops the field was given. An include set the type
8850
+ * cannot see (`string`) may expand anything.
8851
+ */
8852
+ type InsideRichText<I extends string, K extends string, Shape> = string extends I ? string : `${IncludablePaths<FieldsOfShapes$1<Shape>>}${SuffixAt<I, K>}`;
8853
+ /** What each path does at `K`, as a suffix: `''` stops there, `(slug)` picks, `.author` continues. */
8854
+ type SuffixAt<I extends string, K extends string> = I extends K ? '' : I extends `${K}(${infer Picked})` ? `(${Picked})` : I extends `${K}.${infer Rest}` ? `.${Rest}` : never;
8855
+ /** The fields of the fieldsets `Shape` names, sections read flat. */
8856
+ type FieldsOfShapes$1<Shape> = Shape extends {
8857
+ readonly fields: readonly unknown[];
8858
+ } ? DeclaredFields<Shape> : never;
8859
+ /**
8860
+ * The content types a rich-text config's `links` names (REL-1808), as a union; `never` for a field
8861
+ * that declares none — and for a config the type cannot read `links` from.
8862
+ */
8863
+ type LinkTargetsIn<C> = C extends {
8864
+ readonly links?: {
8865
+ readonly to: infer To;
8866
+ } | undefined;
8867
+ } ? unknown extends To ? never : ReferenceTarget<{
8868
+ readonly to: To;
8869
+ }> : never;
8870
+ /**
8871
+ * A rich-text field's entry link (REL-1808): `never` for a field declaring no `links`; otherwise the
8872
+ * mark, its `to` the target's id — or, where the field is included, the target's entry, narrowed to
8873
+ * the fields a path picked and holding the paths that continue past the field.
8874
+ */
8875
+ type EntryLinkIn<C, S extends Context, K extends string, I extends string, A extends boolean> = [
8876
+ LinkTargetsIn<C>
8877
+ ] extends [never] ? never : RichTextEntryLinkMark<string extends I ? string | ExpandedEntry<LinkTargetsIn<C>, S, string> : ExpandsHere<I, K, A> extends true ? ExpandedEntry<LinkTargetsIn<C>, S, IncludesUnder<I, K>, SelectionAt<I, K>> : string>;
8878
+ /** The fieldsets a rich-text config declares as Blocks (REL-1807), as a union; `never` for none. */
8879
+ type BlocksIn<C> = C extends {
8880
+ readonly blocks?: ReadonlyArray<infer Shape>;
8881
+ } ? Shape : never;
8882
+ /** The fieldsets a rich-text config declares as Inline elements (REL-1807), as a union. */
8883
+ type InlineIn<C> = C extends {
8884
+ readonly inline?: ReadonlyArray<infer Shape>;
8885
+ } ? Shape : never;
7899
8886
  /** The shapes an `of` names: the one fieldset, or each of a list of them. Distributes. */
7900
8887
  type ShapesIn<Of> = Of extends readonly (infer Shape)[] ? Shape : Of;
7901
8888
  /**
@@ -8243,7 +9230,7 @@ interface RequirementRule {
8243
9230
  action: 'require' | 'optional';
8244
9231
  conditions: RuleConditions;
8245
9232
  }
8246
- interface ValidationRule {
9233
+ interface ValidationRule$1 {
8247
9234
  type: 'validation';
8248
9235
  action: 'validate' | 'skip';
8249
9236
  message?: string;
@@ -8254,13 +9241,13 @@ interface ReadOnlyRule {
8254
9241
  action: 'enable' | 'disable';
8255
9242
  conditions: RuleConditions;
8256
9243
  }
8257
- type FieldRule = VisibilityRule | RequirementRule | ValidationRule | ReadOnlyRule;
9244
+ type FieldRule = VisibilityRule | RequirementRule | ValidationRule$1 | ReadOnlyRule;
8258
9245
  type LocalizationConfig = boolean | string[] | {
8259
9246
  enabled: boolean;
8260
9247
  requiredLocales?: string[];
8261
9248
  fallback?: boolean;
8262
9249
  };
8263
- interface FieldDefinition<TId extends string = string, TType extends string = string, TConfig = unknown> {
9250
+ interface FieldDefinition$1<TId extends string = string, TType extends string = string, TConfig = unknown> {
8264
9251
  /** Unique field identifier - preserves literal type for type inference */
8265
9252
  readonly id: TId;
8266
9253
  /** Field type */
@@ -8283,7 +9270,7 @@ interface FieldDefinition<TId extends string = string, TType extends string = st
8283
9270
  /**
8284
9271
  * Any field definition - used in arrays where we need to preserve specific field types
8285
9272
  */
8286
- type AnyFieldDefinition = FieldDefinition<string, string, unknown>;
9273
+ type AnyFieldDefinition = FieldDefinition$1<string, string, unknown>;
8287
9274
  interface ShortTextConfig extends BaseFieldConfig {
8288
9275
  /** Maximum character length */
8289
9276
  maxLength?: number;
@@ -8299,10 +9286,17 @@ interface LongTextConfig extends BaseFieldConfig {
8299
9286
  /**
8300
9287
  * A rich-text field's config. With none of `structure`, `marks` and `multiline` the field has the
8301
9288
  * whole docs set of built-ins; each narrows it, and the Studio's editor and every write hold the
8302
- * field to the narrowing (REL-1805). `blocks`, `inline` and `links` are reserved for declared blocks
8303
- * and entry links, and a deploy that sets one now is refused.
9289
+ * field to the narrowing (REL-1805). `blocks` and `inline` declare the fieldsets an editor inserts
9290
+ * between paragraphs and inside a sentence (REL-1807) — `TBlock` and `TInline`, which
9291
+ * `fields.richText()` infers so a read types each one by its fieldset — and `links` the content types
9292
+ * its text may link to (REL-1808), `TLinks`, so a read types each entry link's target.
8304
9293
  */
8305
- interface RichTextConfig extends BaseFieldConfig {
9294
+ /** A rich-text field's `links` (REL-1808): the content types its entry links may point at. */
9295
+ interface RichTextLinks<TTo extends string = string> {
9296
+ /** As a reference field's `to` is written: one content type's id, or several */
9297
+ to: TTo | TTo[];
9298
+ }
9299
+ interface RichTextConfig<TBlock extends AnyFieldset = AnyFieldset, TInline extends AnyFieldset = AnyFieldset, TLinks extends string = string> extends BaseFieldConfig {
8306
9300
  /** Maximum count of the value's text characters, its markup not counted (default 50,000) */
8307
9301
  maxLength?: number;
8308
9302
  /**
@@ -8314,12 +9308,25 @@ interface RichTextConfig extends BaseFieldConfig {
8314
9308
  marks?: readonly RichTextMarkType[];
8315
9309
  /** `false` makes a one-line field: one paragraph, no line break, no other block. Default `true`. */
8316
9310
  multiline?: boolean;
8317
- /** Reserved for declared blocks (REL-1807): a deploy that sets it is refused. */
8318
- blocks?: never;
8319
- /** Reserved for inline elements (REL-1807): a deploy that sets it is refused. */
8320
- inline?: never;
8321
- /** Reserved for entry links (REL-1808): a deploy that sets it is refused. */
8322
- links?: never;
9311
+ /**
9312
+ * The fieldsets an editor may insert between paragraphs (REL-1807): each is a node of the tree
9313
+ * wherever blocks go, `{ _type, _key, …its fields }` — exactly a page builder's item of the same
9314
+ * fieldset. `<RichText>` needs a component for each. Not in a one-line field.
9315
+ */
9316
+ blocks?: readonly TBlock[];
9317
+ /**
9318
+ * The fieldsets an editor may insert inside a sentence (REL-1807): each stands beside a
9319
+ * paragraph's text as `{ _type, _key, …its fields }`. `<RichText>` needs a component for each.
9320
+ */
9321
+ inline?: readonly TInline[];
9322
+ /**
9323
+ * The content types the text may link to (REL-1808): `{ to }`, one type or several, as a
9324
+ * reference names them. Each entry link is a reference — checked on publish, blocking or unwrapped
9325
+ * on its target's delete, expanded when the field is included — with an optional heading anchor.
9326
+ * `<RichText>` needs an `entryLink` component wherever it is set: only your site knows its URLs.
9327
+ * Absent allows no entry link.
9328
+ */
9329
+ links?: RichTextLinks<TLinks>;
8323
9330
  /** A version-1 rich-text tree, every node but a text run keyed (REL-1803) */
8324
9331
  defaultValue?: RichTextValue;
8325
9332
  }
@@ -8346,6 +9353,11 @@ interface CodeConfig extends BaseFieldConfig {
8346
9353
  /** A code group, every node keyed, held to `languages` and `maxTabs` */
8347
9354
  defaultValue?: RichTextCodeGroup;
8348
9355
  }
9356
+ /**
9357
+ * A slug field's value is lowercase letters, numbers and hyphens, and may have segments separated by
9358
+ * a slash (`guide/schema/text-fields`), each segment a slug on its own. A leading, a trailing and a
9359
+ * doubled slash are refused `SLUG_INVALID_FORMAT`, the message naming which. Unique as a whole.
9360
+ */
8349
9361
  interface SlugConfig extends BaseFieldConfig {
8350
9362
  /** Source field to generate slug from */
8351
9363
  sourceField?: string;
@@ -8488,6 +9500,27 @@ interface ObjectConfig<TShape extends AnyFieldset = AnyFieldset> extends BaseFie
8488
9500
  */
8489
9501
  of: TShape | readonly TShape[];
8490
9502
  }
9503
+ /**
9504
+ * A `json` field's config (REL-1811): any JSON value, held to `schema` when it is given — on every
9505
+ * write, a draft included, since a value its schema refuses is never stored. `TSchema` is the schema
9506
+ * literal, which `fields.json()` keeps so a read is typed by it (`InferJsonSchema`); write it
9507
+ * `as const` to keep `required`, `enum` and `const` exact. A json field takes no `defaultValue`.
9508
+ */
9509
+ interface JsonConfig<TSchema extends JsonSchema = JsonSchema> {
9510
+ /** Whether the field is required: required from creation, since no value is every schema's */
9511
+ required?: boolean;
9512
+ /** Whether the field value must be unique */
9513
+ unique?: boolean;
9514
+ /**
9515
+ * The JSON Schema every value is held to: `type`, `properties`, `required`,
9516
+ * `additionalProperties`, `items`, `enum`, `const`, `anyOf` and `oneOf` say what a value is;
9517
+ * `minLength`, `maxLength`, `pattern`, `format`, `minimum`, `maximum`, `exclusiveMinimum`,
9518
+ * `exclusiveMaximum`, `multipleOf`, `minItems`, `maxItems`, `uniqueItems`, `minProperties` and
9519
+ * `maxProperties` narrow it; `title`, `description`, `default` and `examples` annotate it. Any
9520
+ * other keyword — `$ref`, `$id`, `allOf`, `not` — is refused at deploy by name.
9521
+ */
9522
+ schema?: TSchema;
9523
+ }
8491
9524
  /**
8492
9525
  * Every field kind: the one union, `FieldKind` in `@relyio/schema`'s field-kind declaration
8493
9526
  * (REL-1783). A kind the declaration gains is a kind here, and every table this package keys by it
@@ -8497,57 +9530,268 @@ interface ObjectConfig<TShape extends AnyFieldset = AnyFieldset> extends BaseFie
8497
9530
  type FieldType = FieldKind;
8498
9531
 
8499
9532
  /**
8500
- * Settings group definition matching @relyio/schema SettingsGroupSchema
8501
- *
8502
- * Settings groups are for project-level configuration that doesn't fit
8503
- * into content types (e.g., API keys, feature flags, integrations).
9533
+ * Field builders for defining schema fields
9534
+ * Matches the @relyio/schema FieldSchema structure
8504
9535
  *
8505
- * Uses advanced TypeScript generics to preserve literal field IDs through
8506
- * the type system, enabling full autocomplete in SDK methods.
9536
+ * All builders are generic over the ID to preserve literal types for type inference. `enum`,
9537
+ * `reference` and `list` are generic over the parts of their config a read's type depends on too —
9538
+ * the option values, the targets, `multi` and the list's shape — each through a type parameter with a
9539
+ * primitive or field constraint, which is what keeps a literal from widening without a `const`
9540
+ * type parameter (the package supports TypeScript 4.9, which has none).
8507
9541
  */
8508
9542
 
9543
+ interface FieldOptions$1<TConfig, TLocalization extends LocalizationConfig = LocalizationConfig> {
9544
+ /** Type-specific configuration */
9545
+ config?: TConfig;
9546
+ /** UI display configuration */
9547
+ ui?: FieldUIConfig;
9548
+ /** AI configuration: generation/review guidance (`instructions`) for this field. */
9549
+ ai?: FieldAIConfig;
9550
+ /** Dynamic field rules */
9551
+ rules?: FieldRule[];
9552
+ /** Localization settings */
9553
+ localization?: TLocalization;
9554
+ /** Fallback value */
9555
+ fallback?: unknown;
9556
+ /** Whether this field is deprecated */
9557
+ deprecated?: boolean;
9558
+ }
8509
9559
  /**
8510
- * Settings group configuration - generic to preserve field types
9560
+ * `required`, kept as the literal it was written as, so a read's type knows which fields are always
9561
+ * present (`schema/infer-fields.ts`, REL-1795) — through a type parameter with a primitive
9562
+ * constraint, as `multi` is, so `true` does not widen to `boolean`.
8511
9563
  */
8512
- interface SettingsGroupConfig<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
8513
- /** Display name shown in the UI */
8514
- displayName: string;
8515
- /** Description of the settings group */
8516
- description?: string;
8517
- /** AI configuration for content generation and review */
8518
- ai?: AIConfig;
8519
- /** Access tags for role-based access control */
8520
- accessTags?: string[];
8521
- /** Settings fields - preserves literal types */
8522
- fields: TFields;
8523
- }
9564
+ type RequiredAs<TRequired extends boolean> = {
9565
+ required?: TRequired;
9566
+ };
9567
+ /** The key a field definition's type keeps its `localization` literal under. Types only. */
9568
+ declare const localizedAs: unique symbol;
8524
9569
  /**
8525
- * Settings group definition - preserves field types for inference
9570
+ * `localization`, kept as the literal it was written as — `true`, `{ enabled: true }` — by the
9571
+ * builders of the kinds whose translation decides what a filter may name (REL-2136): a reference and
9572
+ * rich text, and the list or object they sit in. A reference or rich text a shared list translates
9573
+ * item by item has no stored path a filter names, so a typed `where` refuses it
9574
+ * (`schema/include-paths.ts`'s `FilterPaths`). `never` where none is written.
9575
+ *
9576
+ * Kept under a key of its own, which holds nothing at runtime: kept under `localization`, a field
9577
+ * inside a `fieldset()` or a type's `fields` widened `true` to `boolean`, inferred from the
9578
+ * `localization` every field definition declares (measured, REL-2136), as `required` is not, which
9579
+ * sits in a `config` the surrounding list does not type.
8526
9580
  */
8527
- interface SettingsGroupDefinition<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
8528
- readonly _tag: 'settingsGroup';
8529
- readonly name: string;
8530
- readonly displayName: string;
8531
- readonly description?: string;
8532
- /** AI configuration for content generation and review */
8533
- readonly ai?: AIConfig;
8534
- readonly accessTags?: string[];
8535
- readonly fields: TFields;
9581
+ interface LocalizedAs<TLocalization extends LocalizationConfig> {
9582
+ readonly [localizedAs]?: TLocalization;
8536
9583
  }
9584
+ /** The `localization` a field definition's type kept ({@link LocalizedAs}); `never` where none. */
9585
+ type LocalizationOf<F> = F extends LocalizedAs<infer L> ? L : never;
8537
9586
  /**
8538
- * Define a settings group
8539
- *
8540
- * The generic type parameter preserves the literal field IDs through the type
8541
- * system, enabling autocomplete in SDK methods.
8542
- *
8543
- * @example
8544
- * const integrations = defineSettingsGroup('integrations', {
8545
- * displayName: 'Integrations',
8546
- * description: 'Third-party service integrations',
8547
- * fields: [
8548
- * fields.shortText('stripeApiKey', {
8549
- * config: { required: true },
8550
- * ui: { displayName: 'Stripe API Key' }
9587
+ * Short text field (single line)
9588
+ * @example fields.shortText('title', { config: { required: true, maxLength: 200 } })
9589
+ */
9590
+ declare function shortText<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<ShortTextConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'shortText', ShortTextConfig & RequiredAs<TRequired>>;
9591
+ /**
9592
+ * Long text field (multi-line textarea)
9593
+ * @example fields.longText('description', { config: { maxLength: 5000 } })
9594
+ */
9595
+ declare function longText<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<LongTextConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'longText', LongTextConfig & RequiredAs<TRequired>>;
9596
+ /**
9597
+ * Rich text: the docs set of built-ins, narrowed by `structure`, `marks` and `multiline`, the
9598
+ * fieldsets an editor inserts between paragraphs (`blocks`) and inside a sentence (`inline`), and the
9599
+ * content types its entry links point at (`links`)
9600
+ * @example fields.richText('content', { config: { structure: ['heading', 'bulletList'], marks: ['bold', 'italic', 'link'] } })
9601
+ * @example fields.richText('body', { config: { blocks: [{ id: 'callout', displayName: 'Callout', fields: [fields.shortText('title')] }] } })
9602
+ * @example fields.richText('body', { config: { links: { to: 'docPage' } } })
9603
+ */
9604
+ declare function richText<TId extends string, TBlock extends AnyFieldset = never, TInline extends AnyFieldset = never, TLinks extends string = never, TRequired extends boolean = false, TLocalization extends LocalizationConfig = never>(id: TId, options?: FieldOptions$1<RichTextConfig<TBlock, TInline, TLinks> & RequiredAs<TRequired>, TLocalization>): FieldDefinition$1<TId, 'richText', RichTextConfig<TBlock, TInline, TLinks> & RequiredAs<TRequired>> & LocalizedAs<TLocalization>;
9605
+ /**
9606
+ * A table: exactly a rich-text table block's value — rows of formatted cells, an optional header row
9607
+ * and per-cell alignment — so a comparison table on a page and a table in a doc are one thing
9608
+ * (REL-1806). Read as `RichTextTable`; `<RichText>` and `richTextToHtml` render it.
9609
+ * @example fields.table('comparison', { config: { required: true } })
9610
+ */
9611
+ declare function table<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<TableConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'table', TableConfig & RequiredAs<TRequired>>;
9612
+ /**
9613
+ * Code with tabs: exactly a rich-text code group's value — one tab or more, each with its label,
9614
+ * language, filename and line range (REL-1806). Read as `RichTextCodeGroup`; `<RichText>` and
9615
+ * `richTextToHtml` render it.
9616
+ * @example fields.code('snippet', { config: { languages: ['typescript', 'bash'], maxTabs: 4 } })
9617
+ */
9618
+ declare function code<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<CodeConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'code', CodeConfig & RequiredAs<TRequired>>;
9619
+ /**
9620
+ * Slug field (URL-friendly identifier)
9621
+ * @example fields.slug('slug', { config: { sourceField: 'title' } })
9622
+ */
9623
+ declare function slug<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<SlugConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'slug', SlugConfig & RequiredAs<TRequired>>;
9624
+ /**
9625
+ * URL field with validation
9626
+ * @example fields.url('website', { config: { allowedProtocols: ['https'] } })
9627
+ */
9628
+ declare function url<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<UrlConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'url', UrlConfig & RequiredAs<TRequired>>;
9629
+ /**
9630
+ * Email field with validation
9631
+ * @example fields.email('contactEmail', { config: { required: true } })
9632
+ */
9633
+ declare function email<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<EmailConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'email', EmailConfig & RequiredAs<TRequired>>;
9634
+ /**
9635
+ * Integer field
9636
+ * @example fields.integer('quantity', { config: { min: 0, max: 100 } })
9637
+ */
9638
+ declare function integer<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<IntegerConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'integer', IntegerConfig & RequiredAs<TRequired>>;
9639
+ /**
9640
+ * Decimal field with precision
9641
+ * @example fields.decimal('weight', { config: { decimalPlaces: 2, min: 0 } })
9642
+ */
9643
+ declare function decimal<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<DecimalConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'decimal', DecimalConfig & RequiredAs<TRequired>>;
9644
+ /**
9645
+ * Boolean field (true/false toggle)
9646
+ * @example fields.boolean('isActive', { config: { defaultValue: false } })
9647
+ */
9648
+ declare function boolean<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<BooleanConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'boolean', BooleanConfig & RequiredAs<TRequired>>;
9649
+ /**
9650
+ * Enum field with predefined options
9651
+ * @example fields.enum('status', {
9652
+ * config: {
9653
+ * options: [
9654
+ * { value: 'draft', label: 'Draft' },
9655
+ * { value: 'published', label: 'Published' },
9656
+ * ]
9657
+ * }
9658
+ * })
9659
+ */
9660
+ declare function enumField<TId extends string, TValue extends string = string, TMulti extends boolean = false, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<EnumConfig<TValue, TMulti> & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'enum', EnumConfig<TValue, TMulti> & RequiredAs<TRequired>>;
9661
+ /**
9662
+ * Date field (no time)
9663
+ * @example fields.date('publishDate', { config: { minDate: '2024-01-01' } })
9664
+ */
9665
+ declare function date<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<DateConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'date', DateConfig & RequiredAs<TRequired>>;
9666
+ /**
9667
+ * DateTime field: an instant, stored and read back in UTC whatever offset it is written in.
9668
+ * `timeZoneHandling` says whether the editor shows it in UTC or in the author's local time.
9669
+ * @example fields.dateTime('createdAt', { config: { timeZoneHandling: 'UTC' } })
9670
+ */
9671
+ declare function dateTime<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<DateTimeConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'dateTime', DateTimeConfig & RequiredAs<TRequired>>;
9672
+ /**
9673
+ * Reference to other entries (content types or asset types)
9674
+ * @example fields.reference('category', { config: { to: 'category' } })
9675
+ * @example fields.reference('relatedItems', { config: { to: ['product', 'service'], multi: true } })
9676
+ * @example fields.reference('heroImage', { config: { to: 'productPhoto' } })
9677
+ */
9678
+ declare function reference<TId extends string, TTo extends string = string, TMulti extends boolean = false, TRequired extends boolean = false, TLocalization extends LocalizationConfig = never>(id: TId, options?: FieldOptions$1<ReferenceConfig<TTo, TMulti> & RequiredAs<TRequired>, TLocalization>): FieldDefinition$1<TId, 'reference', ReferenceConfig<TTo, TMulti> & RequiredAs<TRequired>> & LocalizedAs<TLocalization>;
9679
+ /**
9680
+ * Tags field (array of strings with autocomplete)
9681
+ * @example fields.tags('keywords', { config: { predefinedTags: ['featured', 'sale'], maxTags: 10 } })
9682
+ */
9683
+ declare function tags<TId extends string, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<TagsConfig & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'tags', TagsConfig & RequiredAs<TRequired>>;
9684
+ /**
9685
+ * List field: a repeatable group of one shape. Each item holds the fields of the fieldset `of`
9686
+ * names — usually a `fieldset()` value, declared once and passed wherever it is wanted — plus
9687
+ * `_type` (that fieldset's id) and `_key` (its item key). Without `of`, a list of strings.
9688
+ * @example fields.list('specifications', {
9689
+ * config: {
9690
+ * minItems: 1,
9691
+ * maxItems: 20,
9692
+ * of: {
9693
+ * id: 'spec',
9694
+ * displayName: 'Specification',
9695
+ * fields: [
9696
+ * fields.shortText('name', { config: { required: true } }),
9697
+ * fields.shortText('value', { config: { required: true } }),
9698
+ * ],
9699
+ * },
9700
+ * },
9701
+ * })
9702
+ */
9703
+ declare function list<TId extends string, TShape extends AnyFieldset = never, TRequired extends boolean = false, TLocalization extends LocalizationConfig = never>(id: TId, options?: FieldOptions$1<ListConfig<TShape> & RequiredAs<TRequired>, TLocalization>): FieldDefinition$1<TId, 'list', ListConfig<TShape> & RequiredAs<TRequired>> & LocalizedAs<TLocalization>;
9704
+ /**
9705
+ * Object field: one value of a shape. It holds the fields of the fieldset `of` names — usually a
9706
+ * `fieldset()` value, declared once and passed wherever it is wanted — plus `_type` (that
9707
+ * fieldset's id) and `_key`. Or of one of several shapes, `_type` saying which (REL-1799).
9708
+ * @example fields.object('seo', {
9709
+ * config: {
9710
+ * of: { id: 'seo', displayName: 'SEO', fields: [fields.shortText('metaTitle')] },
9711
+ * },
9712
+ * })
9713
+ * @example fields.object('media', {
9714
+ * config: {
9715
+ * required: true,
9716
+ * of: [
9717
+ * { id: 'screenshot', displayName: 'Screenshot', fields: [fields.reference('image', { config: { to: 'image' } })] },
9718
+ * { id: 'video', displayName: 'Video', fields: [fields.url('src', { config: { required: true } })] },
9719
+ * ],
9720
+ * },
9721
+ * })
9722
+ */
9723
+ declare function object<TId extends string, TShape extends AnyFieldset, TRequired extends boolean = false, TLocalization extends LocalizationConfig = never>(id: TId, options: Omit<FieldOptions$1<ObjectConfig<TShape> & RequiredAs<TRequired>, TLocalization>, 'config'> & {
9724
+ config: ObjectConfig<TShape> & RequiredAs<TRequired>;
9725
+ }): FieldDefinition$1<TId, 'object', ObjectConfig<TShape> & RequiredAs<TRequired>> & LocalizedAs<TLocalization>;
9726
+ /**
9727
+ * JSON field: data nobody models, any JSON value — held to `schema`, a JSON Schema, when it is given
9728
+ * (REL-1811). A read is typed by the schema (`InferJsonSchema`), and is `JsonValue` without one.
9729
+ * Write the schema `as const` so `required`, `enum` and `const` keep their literals. Its source is
9730
+ * edited in the Studio as text, and saved when it parses to a value the schema admits.
9731
+ * @example fields.json('chart', {
9732
+ * config: {
9733
+ * schema: {
9734
+ * type: 'object',
9735
+ * properties: { points: { type: 'array', items: { type: 'number' } } },
9736
+ * required: ['points'],
9737
+ * } as const,
9738
+ * },
9739
+ * })
9740
+ */
9741
+ declare function json<TId extends string, TSchema extends JsonSchema = never, TRequired extends boolean = false>(id: TId, options?: FieldOptions$1<JsonConfig<TSchema> & RequiredAs<TRequired>>): FieldDefinition$1<TId, 'json', JsonConfig<TSchema> & RequiredAs<TRequired>>;
9742
+
9743
+ /**
9744
+ * Settings group definition matching @relyio/schema SettingsGroupSchema
9745
+ *
9746
+ * Settings groups are for project-level configuration that doesn't fit
9747
+ * into content types (e.g., API keys, feature flags, integrations).
9748
+ *
9749
+ * Uses advanced TypeScript generics to preserve literal field IDs through
9750
+ * the type system, enabling full autocomplete in SDK methods.
9751
+ */
9752
+
9753
+ /**
9754
+ * Settings group configuration - generic to preserve field types
9755
+ */
9756
+ interface SettingsGroupConfig<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
9757
+ /** Display name shown in the UI */
9758
+ displayName: string;
9759
+ /** Description of the settings group */
9760
+ description?: string;
9761
+ /** AI configuration for content generation and review */
9762
+ ai?: AIConfig;
9763
+ /** Access tags for role-based access control */
9764
+ accessTags?: string[];
9765
+ /** Settings fields - preserves literal types */
9766
+ fields: TFields;
9767
+ }
9768
+ /**
9769
+ * Settings group definition - preserves field types for inference
9770
+ */
9771
+ interface SettingsGroupDefinition<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
9772
+ readonly _tag: 'settingsGroup';
9773
+ readonly name: string;
9774
+ readonly displayName: string;
9775
+ readonly description?: string;
9776
+ /** AI configuration for content generation and review */
9777
+ readonly ai?: AIConfig;
9778
+ readonly accessTags?: string[];
9779
+ readonly fields: TFields;
9780
+ }
9781
+ /**
9782
+ * Define a settings group
9783
+ *
9784
+ * The generic type parameter preserves the literal field IDs through the type
9785
+ * system, enabling autocomplete in SDK methods.
9786
+ *
9787
+ * @example
9788
+ * const integrations = defineSettingsGroup('integrations', {
9789
+ * displayName: 'Integrations',
9790
+ * description: 'Third-party service integrations',
9791
+ * fields: [
9792
+ * fields.shortText('stripeApiKey', {
9793
+ * config: { required: true },
9794
+ * ui: { displayName: 'Stripe API Key' }
8551
9795
  * }),
8552
9796
  * fields.shortText('sendgridApiKey', {
8553
9797
  * ui: { displayName: 'SendGrid API Key' }
@@ -8584,6 +9828,659 @@ type InferSettingsGroup<T extends AnySettingsGroupDefinition, S extends FieldSch
8584
9828
  _metadata: SettingsGroupMetadata;
8585
9829
  };
8586
9830
 
9831
+ /**
9832
+ * Base error class for all RelyIO SDK errors
9833
+ * Provides consistent error handling, context tracking, and retry logic
9834
+ */
9835
+ declare abstract class SDKError extends Error {
9836
+ /** Unique error code for programmatic error handling */
9837
+ abstract readonly code: string;
9838
+ /** Whether this error is retryable */
9839
+ abstract readonly retryable: boolean;
9840
+ /** HTTP status code if applicable */
9841
+ readonly statusCode?: number;
9842
+ /** Original error that caused this error */
9843
+ readonly cause?: Error;
9844
+ /** Additional context about the error */
9845
+ readonly context?: Record<string, unknown>;
9846
+ /** Timestamp when the error occurred */
9847
+ readonly timestamp: number;
9848
+ constructor(message: string, statusCode?: number, cause?: Error, context?: Record<string, unknown>);
9849
+ /**
9850
+ * Convert error to JSON for logging and debugging
9851
+ */
9852
+ toJSON(): {
9853
+ name: string;
9854
+ message: string;
9855
+ code: string;
9856
+ statusCode: number | undefined;
9857
+ retryable: boolean;
9858
+ context: Record<string, unknown> | undefined;
9859
+ timestamp: number;
9860
+ stack: string | undefined;
9861
+ };
9862
+ /**
9863
+ * Get a user-friendly error message
9864
+ */
9865
+ getUserMessage(): string;
9866
+ /**
9867
+ * Get detailed error information for debugging
9868
+ */
9869
+ getDebugInfo(): string;
9870
+ /**
9871
+ * Check if this error is of a specific type
9872
+ */
9873
+ isType(errorType: string): boolean;
9874
+ /**
9875
+ * Create a new error with additional context
9876
+ */
9877
+ withContext(context: Record<string, unknown>): this;
9878
+ }
9879
+
9880
+ /**
9881
+ * Validation errors and related interfaces.
9882
+ *
9883
+ * `SchemaValidationError`, `RequiredFieldError` and `InvalidFieldTypeError` were deleted by
9884
+ * REL-1471: nothing constructed them. The API refuses content the schema does not accept with one
9885
+ * code, `CONTENT_INVALID`, whose `details.issues` name each field and its problem — the mapper
9886
+ * throws `ValidationError` for it, and a missing required field or a value of the wrong type is a
9887
+ * `violations` entry whose `code` says which.
9888
+ */
9889
+ interface ValidationViolation {
9890
+ field: string;
9891
+ message: string;
9892
+ code: string;
9893
+ value?: unknown;
9894
+ path?: string[];
9895
+ }
9896
+ declare abstract class BaseValidationError extends SDKError {
9897
+ readonly retryable = false;
9898
+ readonly violations: ValidationViolation[];
9899
+ /**
9900
+ * @param context - Carried beside `violations`. The mapper passes the refusal body as
9901
+ * `context.response`, as it does for every other contract code, so a consumer that hands the
9902
+ * service's own words on can read them here too.
9903
+ */
9904
+ constructor(message?: string, violations?: ValidationViolation[], statusCode?: number, cause?: Error, context?: Record<string, unknown>);
9905
+ getUserMessage(): string;
9906
+ /**
9907
+ * Get violations for a specific field
9908
+ */
9909
+ getViolationsForField(fieldName: string): ValidationViolation[];
9910
+ /**
9911
+ * Check if a specific field has validation errors
9912
+ */
9913
+ hasFieldError(fieldName: string): boolean;
9914
+ /**
9915
+ * Get all validation messages as a formatted string
9916
+ */
9917
+ getFormattedMessages(): string;
9918
+ }
9919
+ declare class ValidationError extends BaseValidationError {
9920
+ readonly code = "VALIDATION_ERROR";
9921
+ }
9922
+ declare class InvalidPayloadError extends BaseValidationError {
9923
+ readonly code = "INVALID_PAYLOAD";
9924
+ constructor(message?: string, violations?: ValidationViolation[], cause?: Error, context?: Record<string, unknown>);
9925
+ getUserMessage(): string;
9926
+ }
9927
+
9928
+ /**
9929
+ * View definitions for SDK schema
9930
+ *
9931
+ * Views define pre-configured entry list configurations with filters,
9932
+ * columns, and metadata display settings.
9933
+ */
9934
+ /**
9935
+ * View scope defines which content types a view applies to.
9936
+ *
9937
+ * When using `contentTypes` (plural) or `all`, the view displays entries
9938
+ * from multiple content types. In this case:
9939
+ *
9940
+ * - Columns/fields may only exist on some content types
9941
+ * - For entries where a field doesn't exist, the UI displays "—"
9942
+ * - System fields (id, status, createdAt, updatedAt) exist on all entries
9943
+ * - Filters on non-existent fields are skipped for that entry type
9944
+ *
9945
+ * Example display:
9946
+ * | Content Type | title | author | productCode |
9947
+ * |--------------|-------|--------|-------------|
9948
+ * | post | ✓ | ✓ | — |
9949
+ * | product | ✓ | — | ✓ |
9950
+ */
9951
+ /**
9952
+ * Scope for a single content type
9953
+ */
9954
+ interface ContentTypeScopeConfig {
9955
+ type: 'contentType';
9956
+ contentType: string;
9957
+ }
9958
+ /**
9959
+ * Scope for multiple content types
9960
+ *
9961
+ * Fields not present on all content types will show "—" in the UI
9962
+ */
9963
+ interface ContentTypesScopeConfig {
9964
+ type: 'contentTypes';
9965
+ contentTypes: string[];
9966
+ }
9967
+ /**
9968
+ * Scope for an entry type (content, singleton, settings, asset)
9969
+ */
9970
+ interface EntryTypeScopeConfig {
9971
+ type: 'entryType';
9972
+ entryType: 'content' | 'singleton' | 'settings' | 'asset';
9973
+ }
9974
+ /**
9975
+ * Scope for all content
9976
+ *
9977
+ * Fields not present on all content types will show "—" in the UI
9978
+ */
9979
+ interface AllScopeConfig {
9980
+ type: 'all';
9981
+ }
9982
+ /**
9983
+ * View scope options
9984
+ */
9985
+ type ViewScopeConfig = ContentTypeScopeConfig | ContentTypesScopeConfig | EntryTypeScopeConfig | AllScopeConfig;
9986
+ /**
9987
+ * The operators a view filter may name: the schema's `FILTER_OPERATORS`, which deploy parses a view
9988
+ * with and the read core compiles every one of.
9989
+ *
9990
+ * This list used to be its own: ten of its names — `doesNotContain`, `isNotEmpty`, `isOnOrBefore`,
9991
+ * `isOnOrAfter`, `tomorrow`, `lastWeek`, `lastMonth`, `includesAll`, `includesAny`, `excludes` —
9992
+ * are none the schema declares, so a view naming one was refused at deploy, and six the schema does
9993
+ * declare — `notContains`, `notIncludes`, `isOn`, `isBetween`, `thisYear`, `hasValue` — could not be
9994
+ * written here, so a view pulled by `relyio generate-types` that named one did not compile.
9995
+ * `@relyio/codegen-typescript`'s `src/__tests__/sdk-definition-config.types.ts` holds the two to each
9996
+ * other (REL-1457).
9997
+ */
9998
+ type ViewFilterOperator = 'is' | 'isNot' | 'contains' | 'notContains' | 'startsWith' | 'endsWith' | 'isAnyOf' | 'isNoneOf' | 'includes' | 'notIncludes' | 'isTrue' | 'isFalse' | 'equals' | 'notEquals' | 'greaterThan' | 'lessThan' | 'greaterThanOrEqual' | 'lessThanOrEqual' | 'between' | 'isOn' | 'isBefore' | 'isAfter' | 'isBetween' | 'inTheLast' | 'inTheNext' | 'today' | 'yesterday' | 'thisWeek' | 'thisMonth' | 'thisYear' | 'isEmpty' | 'hasValue';
9999
+ /** A span of time back or forward from now, for `inTheLast` and `inTheNext`. */
10000
+ interface ViewFilterRelativeDate {
10001
+ amount: number;
10002
+ unit: 'minutes' | 'hours' | 'days' | 'weeks' | 'months' | 'years';
10003
+ }
10004
+ /** What a filter compares against: the schema's `FilterValueSchema`. */
10005
+ type ViewFilterValue = string | number | boolean | null | (string | number)[] | {
10006
+ from: string | number | Date;
10007
+ to: string | number | Date;
10008
+ } | ViewFilterRelativeDate | Date;
10009
+ /**
10010
+ * One filter of a view: a field, an operator and the value it compares with.
10011
+ */
10012
+ interface ViewFilterCondition {
10013
+ /**
10014
+ * The Property to filter on, as the Studio's entry list names it: `fields.<id>` for a field your
10015
+ * schema declares (`fields.seo.title` for a field of an object's value), `_metadata.<id>` for a system
10016
+ * field — `_metadata.status`, `_metadata.createdAt`, `_metadata.updatedAt`. So a field called
10017
+ * `status` (`fields.status`) and the entry's own lifecycle (`_metadata.status`) are both
10018
+ * filterable.
10019
+ */
10020
+ field: string;
10021
+ /**
10022
+ * Filter operator
10023
+ */
10024
+ operator: ViewFilterOperator;
10025
+ /**
10026
+ * Filter value (optional for some operators like isEmpty)
10027
+ */
10028
+ value?: ViewFilterValue;
10029
+ }
10030
+ /**
10031
+ * A view's filter. A view's filters are a flat list joined by AND — the Filters the Studio's entry
10032
+ * list takes, each drawn as a Chip — so there is no filter group: an OR within one field is
10033
+ * `isAnyOf`. RelyIO refuses a group by name when you deploy.
10034
+ */
10035
+ type ViewFilter = ViewFilterCondition;
10036
+ /**
10037
+ * View definition configuration
10038
+ */
10039
+ interface ViewConfig {
10040
+ /**
10041
+ * Display name for the view
10042
+ */
10043
+ name: string;
10044
+ /**
10045
+ * URL-friendly slug for the view, used in Studio URLs like /studio/views/:slug. Absent, the
10046
+ * platform derives one from the id when it reads the schema.
10047
+ */
10048
+ slug?: string;
10049
+ /**
10050
+ * Optional description for the view
10051
+ */
10052
+ description?: string;
10053
+ /**
10054
+ * Icon (emoji or icon name) for the view
10055
+ */
10056
+ icon?: string;
10057
+ /**
10058
+ * Color for the view in the sidebar
10059
+ */
10060
+ color?: string;
10061
+ /**
10062
+ * View scope - what content types this view applies to
10063
+ */
10064
+ scope: ViewScopeConfig;
10065
+ /**
10066
+ * Filter conditions (optional), combined with AND. A flat list: an OR within one field is
10067
+ * `isAnyOf`, and there is no filter group.
10068
+ *
10069
+ * Deploy judges each against the entries the view lists: the field must be one they can be
10070
+ * narrowed by, and it must offer the operator — a boolean field takes `is` with `true` or
10071
+ * `false`, for example, not `isTrue`.
10072
+ */
10073
+ filters?: ViewFilter[];
10074
+ /**
10075
+ * Column field IDs to display (optional)
10076
+ * If not specified, uses default columns
10077
+ */
10078
+ columns?: string[];
10079
+ /**
10080
+ * Metadata field IDs to show under title (max 3)
10081
+ */
10082
+ metadataFields?: string[];
10083
+ /**
10084
+ * Default sort (optional). `field` names the Property to sort by, as a filter names one —
10085
+ * `fields.<id>` or `_metadata.<id>` — and deploy refuses one the view's entries cannot be sorted
10086
+ * by. `columns` and `metadataFields` are display settings and name field IDs as written.
10087
+ */
10088
+ sort?: {
10089
+ field: string;
10090
+ direction: 'asc' | 'desc';
10091
+ };
10092
+ /**
10093
+ * Sort order in the sidebar (lower = higher priority)
10094
+ */
10095
+ sortOrder?: number;
10096
+ }
10097
+ /**
10098
+ * Complete view definition with ID
10099
+ */
10100
+ interface ViewDefinition extends ViewConfig {
10101
+ /**
10102
+ * Internal tag for type discrimination
10103
+ */
10104
+ readonly _tag: 'view';
10105
+ /**
10106
+ * Unique view ID (must start with a letter)
10107
+ */
10108
+ readonly id: string;
10109
+ }
10110
+ /**
10111
+ * Define a schema view
10112
+ *
10113
+ * Views are pre-configured entry list displays with filters,
10114
+ * columns, and metadata settings.
10115
+ *
10116
+ * @example
10117
+ * const featuredPosts = defineView('featuredPosts', {
10118
+ * name: 'Featured Posts',
10119
+ * description: 'Blog posts marked as featured',
10120
+ * icon: '📝',
10121
+ * scope: { type: 'contentType', contentType: 'post' },
10122
+ * filters: [
10123
+ * { field: 'fields.featured', operator: 'is', value: true }
10124
+ * ],
10125
+ * columns: ['title', 'author', 'publishedAt'],
10126
+ * metadataFields: ['category', 'views'],
10127
+ * sort: { field: '_metadata.publishedAt', direction: 'desc' }
10128
+ * })
10129
+ *
10130
+ * @example
10131
+ * const archivedContent = defineView('archivedContent', {
10132
+ * name: 'Archived',
10133
+ * scope: { type: 'all' },
10134
+ * filters: [
10135
+ * { field: '_metadata.status', operator: 'is', value: 'archived' }
10136
+ * ]
10137
+ * })
10138
+ *
10139
+ * @param id - Unique view ID (must start with a letter)
10140
+ * @param config - View configuration
10141
+ * @returns View definition object
10142
+ */
10143
+ declare function defineView(id: string, config: ViewConfig): ViewDefinition;
10144
+
10145
+ /**
10146
+ * Core type definitions for the RelyIO SDK
10147
+ */
10148
+
10149
+ /**
10150
+ * Base interface for all content items
10151
+ * Matches the actual RelyIO API structure with _metadata object
10152
+ */
10153
+ interface BaseContent {
10154
+ /**
10155
+ * What the read reports about the entry beside its fields: the committed document's
10156
+ * `EntryMetadata`, and nothing added to it. A `sourceDatasetId` was declared here for an entry
10157
+ * inherited from a linked dataset's source; no read sends one.
10158
+ */
10159
+ _metadata: EntryMetadata;
10160
+ }
10161
+ /**
10162
+ * Whether `T` declares no field: `BaseContent`, the entry of a client with no schema registered.
10163
+ *
10164
+ * Every input that names fields — a condition, a sort, a selection, a write — takes any name then,
10165
+ * because nothing declares which exist; the API checks them against the deployed schema. Before
10166
+ * REL-1406 only `where` asked, so the others took no field at all from an unregistered client.
10167
+ */
10168
+ type DeclaresNoField<T> = [Exclude<keyof T, '_metadata'>] extends [never] ? true : false;
10169
+ /**
10170
+ * The value a `where` condition compares a field against: one of the values the field holds.
10171
+ *
10172
+ * Not the field's read type. The REST dialect (`fromRestWhere` in `@relyio/entry-reads`) reads a
10173
+ * bare value as `eq`, an array as `in` and an object as operators — refusing an object with none —
10174
+ * and drops `null`. So a list field (`tags`) is matched by one of its items, a reference by the
10175
+ * target's id, and an object's value or an expanded entry is never a value to send.
10176
+ */
10177
+ type WhereScalar<V> = Exclude<V extends readonly (infer Item)[] ? Item : V, null | undefined | object>;
10178
+ /** One field's condition: a value (`eq`), a list of values (`in`), or operators. */
10179
+ type WhereFieldCondition<V> = WhereScalar<V> | WhereScalar<V>[] | WhereOperator<WhereScalar<V>>;
10180
+ /**
10181
+ * Query conditions for filtering content: conditions on the fields the content type declares.
10182
+ *
10183
+ * Typed by the content type's fields where a schema types the client: each key is a declared field
10184
+ * and each value one of that field's values. Untyped (`BaseContent`, which declares no fields), any
10185
+ * field name is accepted — nothing declares which exist.
10186
+ *
10187
+ * Nothing under `_metadata` is a field. This type used to accept `{ _metadata: { status } }`, and
10188
+ * the API filters on no `_metadata` key: measured through a real request (REL-1413), that condition
10189
+ * answered `500 INTERNAL_ERROR` and a dotted `_metadata.status` an empty page. A typed client is now
10190
+ * refused at compile time, and every client before sending (`refuseMetadataConditions`).
10191
+ */
10192
+ type WhereClause<T extends BaseContent = BaseContent> = DeclaresNoField<T> extends true ? {
10193
+ [field: string]: unknown;
10194
+ } : {
10195
+ [K in Exclude<keyof T, '_metadata'>]?: WhereFieldCondition<T[K]>;
10196
+ };
10197
+ /**
10198
+ * Query operators for advanced filtering: the REST dialect's spellings (`@relyio/entry-reads`'
10199
+ * `REST_PREFIXED_OPERATOR_TO_ID`). `$regex` was here and is no spelling the API reads: alone it was
10200
+ * refused, beside another operator dropped (REL-2136).
10201
+ */
10202
+ interface WhereOperator<T = unknown> {
10203
+ /** Equals */
10204
+ $eq?: T;
10205
+ /** Not equals */
10206
+ $ne?: T;
10207
+ /** Greater than */
10208
+ $gt?: T;
10209
+ /** Greater than or equal */
10210
+ $gte?: T;
10211
+ /** Less than */
10212
+ $lt?: T;
10213
+ /** Less than or equal */
10214
+ $lte?: T;
10215
+ /** In array */
10216
+ $in?: T[];
10217
+ /** Not in array */
10218
+ $nin?: T[];
10219
+ /** Contains (for strings) */
10220
+ $contains?: string;
10221
+ /** Starts with (for strings) */
10222
+ $startsWith?: string;
10223
+ /** Ends with (for strings) */
10224
+ $endsWith?: string;
10225
+ /** Exists (field is not null/undefined) */
10226
+ $exists?: boolean;
10227
+ /**
10228
+ * `true`: the value is empty — no value, or no block or tree holding a reference there; `false`:
10229
+ * it has one. Taken by every path a filter names (REL-2136).
10230
+ */
10231
+ $isNull?: boolean;
10232
+ /**
10233
+ * Within the span back from the moment of the read, both ends included, counted in UTC: `{ amount:
10234
+ * 7, unit: 'days' }`. Asked of a field that holds a date — `date` or `dateTime` — only; the API
10235
+ * refuses it on any other (REL-1817), and a typed read does not offer it there (REL-2195).
10236
+ */
10237
+ $inTheLast?: ViewFilterRelativeDate;
10238
+ /** Within the span forward from the moment of the read, as {@link WhereOperator.$inTheLast}. */
10239
+ $inTheNext?: ViewFilterRelativeDate;
10240
+ }
10241
+ /** The operators the API asks only of a field that holds a date (`NotADateError` elsewhere). */
10242
+ type DateOnlyOperator = '$inTheLast' | '$inTheNext';
10243
+ /**
10244
+ * Sort options for query results: by a key `T` declares, or by any field where it declares none.
10245
+ */
10246
+ type SortOptions<T extends BaseContent = BaseContent> = {
10247
+ [K in DeclaresNoField<T> extends true ? string : keyof T]?: 'asc' | 'desc';
10248
+ };
10249
+ /**
10250
+ * Query options for content requests
10251
+ *
10252
+ * `F` is the shape whose fields a condition or a sort names, which is the read's own except for an
10253
+ * asset: its read adds the `file` and `urls` blocks beside the fields, and a condition on those
10254
+ * would name no field — and would make an unregistered asset client refuse every field it was given.
10255
+ */
10256
+ interface QueryOptions<T extends BaseContent = BaseContent, F extends BaseContent = T> {
10257
+ /** Conditions to filter by */
10258
+ where?: WhereClause<F>;
10259
+ /** Fields to include in response: any, where nothing declares them */
10260
+ select?: (DeclaresNoField<F> extends true ? string : keyof T)[];
10261
+ /** Related content to include */
10262
+ include?: string[];
10263
+ /** Sort options */
10264
+ sort?: SortOptions<F>;
10265
+ /** Limit number of results */
10266
+ limit?: number;
10267
+ /** Offset for pagination */
10268
+ offset?: number;
10269
+ /** Cursor for cursor-based pagination */
10270
+ cursor?: string;
10271
+ }
10272
+ /**
10273
+ * The fields a write sends: the ones the content type declares, as it declares them — or, where
10274
+ * nothing declares any (`BaseContent`, the entry of a client with no schema registered), any field.
10275
+ * The API validates the body against the deployed schema, the only place those names exist.
10276
+ *
10277
+ * `Omit<BaseContent, '_metadata'>` declares no key at all, so before this every write from an
10278
+ * unregistered client — `relyio.content('post').create({ title })`, the SDK without codegen — was
10279
+ * TS2353, and so was every `batch()` operation, whose `content` is untyped for every client.
10280
+ */
10281
+ type WriteFields<T extends BaseContent> = DeclaresNoField<T> extends true ? {
10282
+ [field: string]: unknown;
10283
+ } : Omit<T, '_metadata'>;
10284
+ /**
10285
+ * Content creation input - excludes metadata fields that are managed by the system
10286
+ */
10287
+ type CreateInput<T extends BaseContent> = WriteFields<T> & {
10288
+ /** Optional metadata that can be set during creation */
10289
+ _metadata?: {
10290
+ /** Parent ID for hierarchical content */
10291
+ parentId?: string | null;
10292
+ /** Content locale */
10293
+ locale?: string;
10294
+ };
10295
+ };
10296
+ /**
10297
+ * What a revision answers: the entry, its `_metadata` also listing the entry links other entries
10298
+ * publish that the revision left pointing nowhere — the document's `RevisedEntryMetadata`
10299
+ * (REL-2110, REL-2130). The write is never refused for them; the linking entry's next publish is.
10300
+ */
10301
+ type RevisedContent<T extends BaseContent> = Omit<T, '_metadata'> & {
10302
+ _metadata: T['_metadata'] & Pick<components['schemas']['RevisedEntryMetadata'], 'brokenLinks'>;
10303
+ };
10304
+ /**
10305
+ * What a version restore answers: the entry, its `_metadata` also listing what the restore left out
10306
+ * and the links it left pointing nowhere — the document's `RestoredEntryMetadata` (REL-1793,
10307
+ * REL-2130).
10308
+ */
10309
+ type RestoredContent<T extends BaseContent> = Omit<T, '_metadata'> & {
10310
+ _metadata: T['_metadata'] & Pick<components['schemas']['RestoredEntryMetadata'], 'leftOut' | 'brokenLinks'>;
10311
+ };
10312
+ /**
10313
+ * Content update input - excludes system-managed metadata fields
10314
+ */
10315
+ type UpdateInput<T extends BaseContent> = Partial<WriteFields<T>> & {
10316
+ /** Optional metadata that can be updated */
10317
+ _metadata?: {
10318
+ /** Parent ID for hierarchical content */
10319
+ parentId?: string | null;
10320
+ /** Content locale */
10321
+ locale?: string;
10322
+ };
10323
+ };
10324
+ /**
10325
+ * What the entry list serves — **read from the committed document**, not
10326
+ * written down here.
10327
+ *
10328
+ * It used to be a hand-written `{ items, total?, hasMore, nextCursor }`, and
10329
+ * every field of it was wrong after API2: the route is the cursor dialect, so
10330
+ * the body is `{ data, page: { nextCursor, hasMore } }` and there is no total
10331
+ * at all. `execute()` therefore resolved `result.items` — `undefined` — for
10332
+ * every caller of the SDK's most-used method, and nothing could see it because
10333
+ * the type said otherwise.
10334
+ *
10335
+ * Deriving it means the next dialect change is a compile error in user code
10336
+ * rather than an `undefined` at runtime (`INV-API-CLIENT-IS-DERIVED`).
10337
+ */
10338
+ type ContentQueryResult<T extends BaseContent = BaseContent> = Wire<'/v1/{contentType}', 'get', T>;
10339
+ /**
10340
+ * A singleton as `GET /v1/singletons/{key}` serves it: its fields at the top level and
10341
+ * `_metadata`, the document's `Singleton` rather than a second declaration of it.
10342
+ */
10343
+ type SingletonContent = components['schemas']['Singleton'];
10344
+ /**
10345
+ * Custom query definition
10346
+ */
10347
+ interface CustomQuery<TVariables = unknown, TResponse = unknown> {
10348
+ /** Query name */
10349
+ name: string;
10350
+ /** Query variables */
10351
+ variables?: TVariables;
10352
+ /** Expected response type */
10353
+ response?: TResponse;
10354
+ }
10355
+ /**
10356
+ * Content type schema information
10357
+ */
10358
+ interface ContentTypeSchema {
10359
+ /** Content type name */
10360
+ name: string;
10361
+ /** Display name */
10362
+ displayName: string;
10363
+ /** Description */
10364
+ description?: string;
10365
+ /** Field definitions */
10366
+ fields: FieldDefinition[];
10367
+ /** Whether this content type is hierarchical */
10368
+ hierarchical?: boolean;
10369
+ /** Preview configuration */
10370
+ preview?: {
10371
+ select?: Record<string, string>;
10372
+ prepare?: (_selection: Record<string, unknown>) => Record<string, unknown>;
10373
+ };
10374
+ }
10375
+ /**
10376
+ * Field definition for content types
10377
+ */
10378
+ interface FieldDefinition {
10379
+ /** Field name */
10380
+ name: string;
10381
+ /** Field type */
10382
+ type: FieldTypeName;
10383
+ /** Display title */
10384
+ title?: string;
10385
+ /** Field description */
10386
+ description?: string;
10387
+ /** Whether field is required */
10388
+ required?: boolean;
10389
+ /** Default value */
10390
+ default?: unknown;
10391
+ /** Validation rules */
10392
+ validation?: ValidationRule[];
10393
+ /** Field options */
10394
+ options?: FieldOptions;
10395
+ }
10396
+ /**
10397
+ * Supported field type names (string identifiers)
10398
+ */
10399
+ type FieldTypeName = 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'text' | 'markdown' | 'richtext' | 'slug' | 'url' | 'email' | 'image' | 'file' | 'reference' | 'array' | 'object' | 'geopoint' | 'color';
10400
+ /**
10401
+ * Field validation rules
10402
+ */
10403
+ interface ValidationRule {
10404
+ /** Rule type */
10405
+ type: 'required' | 'min' | 'max' | 'pattern' | 'custom';
10406
+ /** Rule value */
10407
+ value?: unknown;
10408
+ /** Error message */
10409
+ message?: string;
10410
+ }
10411
+ /**
10412
+ * Field-specific options
10413
+ */
10414
+ interface FieldOptions {
10415
+ /** For array fields */
10416
+ of?: FieldDefinition;
10417
+ /** For reference fields */
10418
+ to?: string | string[];
10419
+ /** For string fields */
10420
+ list?: string[];
10421
+ /** For number fields */
10422
+ min?: number;
10423
+ max?: number;
10424
+ /** For image/file fields */
10425
+ accept?: string[];
10426
+ /** For rich text fields */
10427
+ marks?: string[];
10428
+ blocks?: string[];
10429
+ }
10430
+ /**
10431
+ * Real-time event types
10432
+ */
10433
+ type RealtimeEventType = 'created' | 'updated' | 'deleted' | 'published' | 'unpublished';
10434
+ /**
10435
+ * Real-time event payload
10436
+ */
10437
+ interface RealtimeEvent<T extends BaseContent = BaseContent> {
10438
+ /** Event type */
10439
+ type: RealtimeEventType;
10440
+ /** Content type */
10441
+ contentType: string;
10442
+ /** Content item (for created/updated events) */
10443
+ item?: T;
10444
+ /** Content ID (for deleted events) */
10445
+ id?: string;
10446
+ /** Timestamp */
10447
+ timestamp: number;
10448
+ /** Event metadata */
10449
+ metadata?: Record<string, unknown>;
10450
+ }
10451
+ /**
10452
+ * Subscription options
10453
+ */
10454
+ interface SubscriptionOptions<T extends BaseContent = BaseContent> {
10455
+ /** Content type to subscribe to */
10456
+ contentType: string;
10457
+ /** Filter conditions */
10458
+ where?: WhereClause<T>;
10459
+ /** Events to listen for */
10460
+ events?: RealtimeEventType[];
10461
+ /** Subscription metadata */
10462
+ metadata?: Record<string, unknown>;
10463
+ }
10464
+ /**
10465
+ * Performance metrics
10466
+ */
10467
+ interface PerformanceMetrics {
10468
+ /** Request duration in milliseconds */
10469
+ duration: number;
10470
+ /** Request timestamp */
10471
+ timestamp: number;
10472
+ /** Request URL */
10473
+ url: string;
10474
+ /** HTTP method */
10475
+ method: string;
10476
+ /** Response status code */
10477
+ statusCode: number;
10478
+ /** Whether response came from cache */
10479
+ fromCache: boolean;
10480
+ /** Cache hit ratio */
10481
+ cacheHitRatio?: number;
10482
+ }
10483
+
8587
10484
  /**
8588
10485
  * Include paths, typed (REL-1801, design decision 12): a read's type follows the paths it names.
8589
10486
  *
@@ -8664,12 +10561,190 @@ type FieldsOfDefinition<D> = D extends {
8664
10561
  readonly fields: readonly unknown[];
8665
10562
  } ? DeclaredFields<D> : never;
8666
10563
  /** `true` when a field is a reference, or a list or object holding one at any depth. */
8667
- type HoldsReference<F> = F extends AnyFieldDefinition ? IsReference<F> extends true ? true : true extends HoldsReference<ShapeFields<F>> ? true : false : false;
10564
+ type HoldsReference<F> = F extends AnyFieldDefinition ? IsReference<F> extends true ? true : true extends HoldsReference<ShapeFields<F>> ? true : true extends IsLinkingRichText<F> ? true : false : false;
10565
+ type RichTextKind = Extract<FieldType, 'richText'>;
10566
+ /** The fields of a rich-text field's declared Blocks and Inline elements (REL-1807). */
10567
+ type DeclaredNodeFields<F> = F extends {
10568
+ readonly config?: infer C;
10569
+ } ? NonNullable<C> extends {
10570
+ readonly blocks?: ReadonlyArray<infer B>;
10571
+ readonly inline?: ReadonlyArray<infer N>;
10572
+ } ? FieldsOfShapes<B | N> : never : never;
10573
+ /**
10574
+ * `true` for a rich-text field holding references (REL-1808): its entry links, where it declares
10575
+ * `links`, or a reference among its declared nodes' fields. Such a field is **one** include path —
10576
+ * nothing inside rich text is a path — and including it expands every reference in it.
10577
+ */
10578
+ type IsLinkingRichText<F> = F extends {
10579
+ readonly type: RichTextKind;
10580
+ readonly config?: infer C;
10581
+ } ? [LinkTargetsIn<NonNullable<C>>] extends [never] ? true extends HoldsReference<DeclaredNodeFields<F>> ? true : false : true : false;
10582
+ /**
10583
+ * The fields of every entry a rich-text field's references reach — its entry links' targets and
10584
+ * those of the references its declared nodes declare directly — what a pick or a hop past it names.
10585
+ */
10586
+ type RichTextTargetFields<F, S> = F extends {
10587
+ readonly config?: infer C;
10588
+ } ? S extends FieldSchemaContext ? FieldsOfDefinition<Declared<S['contentTypes'], RichTextTargets<NonNullable<C>, F>> | Declared<S['singletonContentTypes'], RichTextTargets<NonNullable<C>, F>>> : never : never;
10589
+ type RichTextTargets<C, F> = LinkTargetsIn<C> | (Extract<DeclaredNodeFields<F>, {
10590
+ readonly type: ReferenceKind;
10591
+ }> extends {
10592
+ readonly config?: infer R;
10593
+ } ? ReferenceTarget<NonNullable<R>> : never);
8668
10594
  /**
8669
10595
  * Every path a record can include, below `Prefix`: each reference, and each list or object holding
8670
10596
  * one, then the paths inside it. Distributes over the record's fields.
8671
10597
  */
8672
- type IncludablePaths<Fields, Prefix extends string = ''> = Fields extends AnyFieldDefinition ? IsReference<Fields> extends true ? `${Prefix}${Fields['id']}` : true extends HoldsReference<ShapeFields<Fields>> ? `${Prefix}${Fields['id']}` | IncludablePaths<ShapeFields<Fields>, `${Prefix}${Fields['id']}.`> : never : never;
10598
+ type IncludablePaths<Fields, Prefix extends string = ''> = Fields extends AnyFieldDefinition ? IsReference<Fields> extends true ? `${Prefix}${Fields['id']}` : true extends IsLinkingRichText<Fields> ? `${Prefix}${Fields['id']}` : true extends HoldsReference<ShapeFields<Fields>> ? `${Prefix}${Fields['id']}` | IncludablePaths<ShapeFields<Fields>, `${Prefix}${Fields['id']}.`> : never : never;
10599
+ type ListKind = Extract<FieldType, 'list'>;
10600
+ type ObjectKind = Extract<FieldType, 'object'>;
10601
+ type JsonKind = Extract<FieldType, 'json'>;
10602
+ /**
10603
+ * The kinds a filter reads as dates, which alone take `$inTheLast` and `$inTheNext`: those whose
10604
+ * field-kind declaration gives a `filter` facet of kind `date`. `__tests__/where-paths.types.ts`
10605
+ * holds the two to one answer, as it does {@link FiltersByValue}.
10606
+ */
10607
+ type DateKind = Extract<FieldType, 'date' | 'dateTime'>;
10608
+ /**
10609
+ * Whether a filter names a field of each kind by its own value: `true` where `@relyio/schema`'s
10610
+ * field-kind declaration gives the kind a `filter` facet, `false` where it says `NOT_FILTERED`.
10611
+ * Restated as a type, because the declaration object is not rolled into this package's `.d.ts`;
10612
+ * `__tests__/where-paths.types.ts` holds the two to one answer, so a kind whose facet changes fails
10613
+ * to compile there.
10614
+ */
10615
+ type FiltersByValue = OverEveryFieldKind<{
10616
+ shortText: true;
10617
+ longText: true;
10618
+ richText: false;
10619
+ table: false;
10620
+ code: false;
10621
+ email: true;
10622
+ url: true;
10623
+ slug: true;
10624
+ integer: true;
10625
+ decimal: true;
10626
+ boolean: true;
10627
+ enum: true;
10628
+ date: true;
10629
+ dateTime: true;
10630
+ reference: true;
10631
+ tags: true;
10632
+ list: false;
10633
+ object: false;
10634
+ json: false;
10635
+ }>;
10636
+ /**
10637
+ * Whether a field says `localization` the API reads as translated (`isFieldLocalized`): `true`, a
10638
+ * list of locales, or `{ enabled: true }`. A builder keeps what was written (`LocalizedAs`,
10639
+ * REL-2136); a definition whose type does not — one written without a builder, or `LocalizationConfig`
10640
+ * as a whole — reads as shared, which is how the API answers a field that says nothing.
10641
+ */
10642
+ type SaysLocalized<F> = [Exclude<LocalizationOf<F>, undefined>] extends [never] ? false : [Exclude<LocalizationOf<F>, undefined>] extends [
10643
+ true | readonly string[] | {
10644
+ readonly enabled: true;
10645
+ }
10646
+ ] ? true : false;
10647
+ /**
10648
+ * Where a value's translation is held, walking a path down from the record: `shared` while no field
10649
+ * on it is translated, `root` once the field at its root is (the whole value, a list's items and all,
10650
+ * held per locale), `deep` once a field below the root is — inside a block, the item-by-item
10651
+ * translation no stored path names.
10652
+ */
10653
+ type Translation = 'shared' | 'root' | 'deep';
10654
+ /** The translation below field `F`, which `Prefix` reaches, under the translation `T` above it. */
10655
+ type TranslationBelow<F, T extends Translation, Prefix extends string> = T extends 'shared' ? true extends SaysLocalized<F> ? Prefix extends '' ? 'root' : 'deep' : 'shared' : T;
10656
+ /**
10657
+ * One stored path a field's declaration holds, with what it is to a filter and the condition it
10658
+ * takes. A path several shapes declare is held once by each, and {@link FilterPaths} reads them
10659
+ * together, as the API does.
10660
+ *
10661
+ * - `field`: a value a filter compares, outside every block — at the top level or in an object.
10662
+ * - `reference`: a reference inside a block — named by the API's one path resolver, or, where a
10663
+ * shared list translates it item by item, by each locale's per-item resolution the write derives
10664
+ * (`itemRefs`, REL-2134).
10665
+ * - `richText`, `plainRichText`: rich text whose tree a filter asks for the entries it points at —
10666
+ * one that can point at an entry, or one that cannot.
10667
+ * - `blockValue`: any other value inside a block. `whole`: a list, an object, a table, code, or rich
10668
+ * text whose tree no stored path names, as a whole. `json`: a json field.
10669
+ */
10670
+ interface Held<P extends string, Role extends string, Condition> {
10671
+ readonly path: P;
10672
+ readonly role: Role;
10673
+ readonly condition: Condition;
10674
+ }
10675
+ /**
10676
+ * A condition on a value that holds no date: {@link WhereFieldCondition} without `$inTheLast` and
10677
+ * `$inTheNext`, which the API asks of a date alone (`NotADateError`, REL-2195).
10678
+ */
10679
+ type UndatedCondition<V> = WhereScalar<V> | WhereScalar<V>[] | Omit<WhereOperator<WhereScalar<V>>, DateOnlyOperator>;
10680
+ /** A reference, or rich text pointing at entries, compared with an entry id. */
10681
+ type EntryIdCondition = UndatedCondition<string>;
10682
+ /** What a record's fields hold, path by path, below `Prefix`. Distributes over the fields. */
10683
+ type HeldPaths<Fields, S, Prefix extends string = '', InItems extends boolean = false, T extends Translation = 'shared'> = Fields extends AnyFieldDefinition ? HeldBy<Fields, S, `${Prefix}${Fields['id']}`, InItems, T, TranslationBelow<Fields, T, Prefix>> : never;
10684
+ type HeldBy<F extends AnyFieldDefinition, S, Path extends string, InItems extends boolean, Above extends Translation, Below extends Translation> = F extends {
10685
+ readonly type: JsonKind;
10686
+ } ? Held<Path, 'json', never> : F extends {
10687
+ readonly type: ListKind;
10688
+ } ? Held<Path, 'whole', never> | HeldPaths<ShapeFields<F>, S, `${Path}.`, true, Below> : F extends {
10689
+ readonly type: ObjectKind;
10690
+ } ? Held<Path, 'whole', never> | HeldPaths<ShapeFields<F>, S, `${Path}.`, InItems, Below> : F extends {
10691
+ readonly type: RichTextKind;
10692
+ } ? RichTextNamed<F, InItems, Above, Below> extends true ? Held<Path, true extends IsLinkingRichText<F> ? 'richText' : 'plainRichText', EntryIdCondition> : Held<Path, 'whole', never> : F extends {
10693
+ readonly type: ReferenceKind;
10694
+ } ? InItems extends true ? Held<Path, 'reference', EntryIdCondition> : Held<Path, 'field', FieldCondition<F, S>> : F['type'] extends FieldType ? FiltersByValue[F['type']] extends true ? InItems extends true ? Held<Path, 'blockValue', never> : Held<Path, 'field', FieldCondition<F, S>> : Held<Path, 'whole', never> : Held<Path, 'field', unknown>;
10695
+ /**
10696
+ * A field's own condition: one of the values it holds (`WhereScalar`), as its read types them — and,
10697
+ * where it holds a date, a span back or forward from the read (`$inTheLast`, `$inTheNext`).
10698
+ */
10699
+ type FieldCondition<F extends AnyFieldDefinition, S> = F extends {
10700
+ readonly type: DateKind;
10701
+ } ? WhereFieldCondition<FieldValue<F, S extends FieldSchemaContext ? S : undefined>> : UndatedCondition<FieldValue<F, S extends FieldSchemaContext ? S : undefined>>;
10702
+ /**
10703
+ * Whether a filter names rich text's trees: shared, translated with the field at the root of the
10704
+ * path, translated itself outside every block, or translated item by item inside a list, which each
10705
+ * locale's per-item resolution names (`itemRefs`, REL-2134) — never translated by an object between
10706
+ * the root and it outside every list, which nothing names (`nameableRichText`).
10707
+ */
10708
+ type RichTextNamed<F, InItems extends boolean, Above extends Translation, Below extends Translation> = Below extends 'shared' | 'root' ? true : InItems extends true ? true : Above extends 'shared' ? true extends SaysLocalized<F> ? true : false : false;
10709
+ /**
10710
+ * Whether a filter names a path its declarations hold as `Roles` — the API's one filter check
10711
+ * (`assertFilterableInBlocks`, REL-1810, REL-1811, REL-2135), read in its order: a json field
10712
+ * anywhere at the path refuses it; rich text every declaration of which a stored path names, one of
10713
+ * them pointing at entries, is filtered by them; a reference inside a block that no other value there
10714
+ * shares the path with is; outside every block, a value a filter compares is, unless a whole value
10715
+ * shares the path.
10716
+ */
10717
+ type Admits<Roles> = 'json' extends Roles ? false : [Roles] extends ['richText' | 'plainRichText'] ? 'richText' extends Roles ? true : false : 'reference' extends Roles ? 'blockValue' extends Roles ? false : true : [Roles] extends ['field'] ? true : false;
10718
+ type PathsOf<H> = H extends Held<infer P, string, unknown> ? P : never;
10719
+ type RolesAt<H, P extends string> = H extends Held<P, infer Role, unknown> ? Role : never;
10720
+ type AdmittedPaths<H, P = PathsOf<H>> = P extends string ? Admits<RolesAt<H, P>> extends true ? P : never : never;
10721
+ /**
10722
+ * The conditions a typed read's `where` takes, by path (REL-2136): exactly the keys the API filters
10723
+ * by, each taking the condition the value at it does.
10724
+ *
10725
+ * - A field a filter compares, at the top level or in an object, by its path — `title`,
10726
+ * `'pricing.basePrice'` — taking one of the values it holds, a list of them, or operators.
10727
+ * - A reference inside a block, at any depth (`'sections.features'`, REL-1810), and rich text that
10728
+ * can point at an entry, at the top level or inside one (`body`, `'sections.text'`), each compared
10729
+ * with an entry id: some block or tree points at it.
10730
+ *
10731
+ * And no other key: a json field or a key inside one, a list, an object, a table, code, rich text
10732
+ * that points at nothing, any value inside a block but a reference, a reference or rich text a shared
10733
+ * list translates item by item, or `_metadata` — each refused by the API by name, and here by the
10734
+ * compiler. A read no schema types names any key, and the API holds it to the deployed schema.
10735
+ */
10736
+ type FilterPaths<Fields, S> = {
10737
+ [P in AdmittedPaths<HeldPaths<Fields, S>>]?: Extract<HeldPaths<Fields, S>, {
10738
+ readonly path: P;
10739
+ }>['condition'];
10740
+ };
10741
+ /**
10742
+ * A read's `where`: {@link FilterPaths} where a schema types the read (`R['where']`), and `W`, the
10743
+ * conditions its record's own keys take, where none does.
10744
+ */
10745
+ type ReadWhere<W, R> = R extends {
10746
+ readonly where: infer C;
10747
+ } ? C : W;
8673
10748
  /** The path part of a written path, and what its parentheses pick. */
8674
10749
  type PathOf<X extends string> = X extends `${infer Path}(${string})` ? Path : X;
8675
10750
  type PickedOf<X extends string> = X extends `${string}(${infer Picked})` ? Picked : never;
@@ -8692,7 +10767,7 @@ type Step<F, Root, S, Segment extends string, Tail extends string, Picked extend
8692
10767
  readonly type: ReferenceKind;
8693
10768
  }>, S>, TargetFields<Extract<F, {
8694
10769
  readonly type: ReferenceKind;
8695
- }>, S>, S, Tail, Picked, `${Done}${Segment}.`, `${Done}${Segment}.`> : true extends HoldsReference<ShapeFields<F>> ? Tail extends '' ? [Picked] extends [never] ? true : Suggest<Root, Entry> : Walk<ShapeFields<F>, Root, S, Tail, Picked, `${Done}${Segment}.`, Entry> : Suggest<Root, Entry>;
10770
+ }>, S>, S, Tail, Picked, `${Done}${Segment}.`, `${Done}${Segment}.`> : true extends IsLinkingRichText<F> ? Tail extends '' ? [Picked] extends [never] ? true : CheckPicked<RichTextTargetFields<F, S>, Picked, `${Done}${Segment}`> : Walk<RichTextTargetFields<F, S>, RichTextTargetFields<F, S>, S, Tail, Picked, `${Done}${Segment}.`, `${Done}${Segment}.`> : true extends HoldsReference<ShapeFields<F>> ? Tail extends '' ? [Picked] extends [never] ? true : Suggest<Root, Entry> : Walk<ShapeFields<F>, Root, S, Tail, Picked, `${Done}${Segment}.`, Entry> : Suggest<Root, Entry>;
8696
10771
  /** `true` when every picked field is one the reached entry declares; otherwise each pick it could. */
8697
10772
  type CheckPicked<Target, Picked extends string, Path extends string> = [
8698
10773
  Exclude<Split<Picked>, Target extends AnyFieldDefinition ? Target['id'] : never>
@@ -8740,6 +10815,8 @@ interface UntypedReading<T> extends Reading {
8740
10815
  interface ContentReading<D extends AnyContentTypeDefinition, S extends FieldSchemaContext | undefined> extends Reading {
8741
10816
  readonly read: InferContentType<D, S, this['include']>;
8742
10817
  readonly checked: CheckInclude<FieldsOfDefinition<D>, S, this['path']>;
10818
+ /** What its `where` takes: every key the API filters it by ({@link FilterPaths}, REL-2136). */
10819
+ readonly where: FilterPaths<FieldsOfDefinition<D>, S>;
8743
10820
  }
8744
10821
  /** A read of the singleton `D` defines, in schema `S`. */
8745
10822
  interface SingletonReading<D extends AnySingletonContentTypeDefinition, S extends FieldSchemaContext | undefined> extends Reading {
@@ -8750,6 +10827,12 @@ interface SingletonReading<D extends AnySingletonContentTypeDefinition, S extend
8750
10827
  interface AssetReading<D extends AnyAssetTypeDefinition, S extends FieldSchemaContext | undefined> extends Reading {
8751
10828
  readonly read: InferAssetType<D, S, this['include']>;
8752
10829
  readonly checked: CheckInclude<FieldsOfDefinition<D>, S, this['path']>;
10830
+ /**
10831
+ * What its `where` takes: every key the API filters its fields by, as a content type's
10832
+ * ({@link FilterPaths}) — an asset is an entry on the same routes, held to the same check (REL-2195).
10833
+ * Its `fields` are optional, so they are read with `DeclaredFields`, which takes them so.
10834
+ */
10835
+ readonly where: FilterPaths<DeclaredFields<D>, S>;
8753
10836
  }
8754
10837
  /** A read of the settings group `D` defines, in schema `S`. */
8755
10838
  interface SettingsReading<D extends AnySettingsGroupDefinition, S extends FieldSchemaContext | undefined> extends Reading {
@@ -8757,4 +10840,4 @@ interface SettingsReading<D extends AnySettingsGroupDefinition, S extends FieldS
8757
10840
  readonly checked: CheckInclude<FieldsOfDefinition<D>, S, this['path']>;
8758
10841
  }
8759
10842
 
8760
- export { defineContentType as $, type AnyFieldset as A, type BooleanConfig as B, type CodeConfig as C, type DecimalConfig as D, type EmailConfig as E, type FieldUIConfig as F, type BlockOf as G, type ShapeValue as H, type IntegerConfig as I, type AssetReading as J, type Keyed as K, type LocalizationConfig as L, type CheckedIncludes as M, type CheckInclude as N, type ObjectConfig as O, type ContentReading as P, type IncludablePaths as Q, type RichTextConfig as R, type ShortTextConfig as S, type TableConfig as T, type UrlConfig as U, type ValidationRule as V, type Reading as W, type ReadWith as X, type SettingsReading as Y, type SingletonReading as Z, type UntypedReading as _, type FieldAIConfig as a, fieldset as a0, type Fieldset as a1, type FieldMember as a2, type ContentTypeConfig as a3, type ContentTypeDefinition as a4, type EntryMetadata as a5, type InferContentType as a6, type LocalePublicationFields as a7, defineSingletonContentType as a8, defineSingleton as a9, type VideoCaptionsConfig as aA, type VideoDownloadConfig as aB, type VideoWatermarkConfig as aC, type FileUploadConfig as aD, type FileScanConfig as aE, defineWorkflow as aF, defineWorkflowStage as aG, defineContentTypeWorkflow as aH, isWorkflowDefinition as aI, isWorkflowStageDefinition as aJ, getWorkflowStageIds as aK, findWorkflowStage as aL, getNextWorkflowStage as aM, getFirstWorkflowStage as aN, isFinalWorkflowStage as aO, type WorkflowEscalation as aP, type WorkflowAutoAssign as aQ, type WorkflowStageConfig as aR, type WorkflowStageDefinition as aS, type WorkflowConfig as aT, type WorkflowDefinition as aU, type ContentTypeWorkflowConfig as aV, type paths as aW, type components as aX, type CheckedInclude as aY, type SingletonConfig as aa, type SingletonContentTypeDefinition as ab, type SingletonMetadata as ac, type InferSingletonContentType as ad, type InferSingleton as ae, defineSettingsGroup as af, type SettingsGroupConfig as ag, type SettingsGroupDefinition as ah, type SettingsGroupMetadata as ai, type InferSettingsGroup as aj, defineAssetType as ak, type AssetTypeConfig as al, type AssetTypeDefinition as am, type InferAssetType as an, type ImageKindConfig as ao, type VideoKindConfig as ap, type FileKindConfig as aq, type ImageTransform as ar, type ImageFitMode as as, type ImageOutputFormat as at, type ImageUploadConfig as au, type ImageSourceConfig as av, type ImageExifConfig as aw, type VariantDefinition as ax, type VideoUploadConfig as ay, type VideoPosterConfig as az, type FieldRule as b, type FieldDefinition as c, type LongTextConfig as d, type SlugConfig as e, type EnumConfig as f, type DateConfig as g, type DateTimeConfig as h, type ReferenceConfig as i, type TagsConfig as j, type ListConfig as k, type AIConfig as l, type AnyFieldDefinition as m, type AssetAIConfig as n, type BaseFieldConfig as o, type FieldType as p, type ReadOnlyRule as q, type RequirementRule as r, type RuleCondition as s, type RuleConditions as t, type VisibilityRule as u, type FieldSchemaContext as v, type FieldValue as w, type FieldValues as x, type DeclaredFields as y, type UnresolvedEntry as z };
10843
+ export { tags as $, type AIConfig as A, type BaseFieldConfig as B, type CodeConfig as C, type DateConfig as D, type EmailConfig as E, type FieldAIConfig as F, email as G, enumField as H, type IntegerConfig as I, type JsonConfig as J, integer as K, type ListConfig as L, json as M, list as N, type ObjectConfig as O, longText as P, object as Q, type ReadOnlyRule as R, type ShortTextConfig as S, type TableConfig as T, type UrlConfig as U, type ValidationRule$1 as V, reference as W, richText as X, shortText as Y, slug as Z, table as _, type AnyFieldDefinition as a, defineWorkflow as a$, url as a0, type FieldSchemaContext as a1, type FieldValue as a2, type FieldValues as a3, type DeclaredFields as a4, type UnresolvedEntry as a5, type Keyed as a6, type BlockOf as a7, type ShapeValue as a8, type AssetReading as a9, type SettingsGroupConfig as aA, type SettingsGroupDefinition as aB, type SettingsGroupMetadata as aC, type InferSettingsGroup as aD, defineAssetType as aE, type AssetTypeConfig as aF, type AssetTypeDefinition as aG, type InferAssetType as aH, type InferAssetEntry as aI, type AssetServedBlocks as aJ, type ImageKindConfig as aK, type VideoKindConfig as aL, type FileKindConfig as aM, type ImageTransform as aN, type ImageFitMode as aO, type ImageOutputFormat as aP, type ImageUploadConfig as aQ, type ImageSourceConfig as aR, type ImageExifConfig as aS, type VariantDefinition as aT, type VideoUploadConfig as aU, type VideoPosterConfig as aV, type VideoCaptionsConfig as aW, type VideoDownloadConfig as aX, type VideoWatermarkConfig as aY, type FileUploadConfig as aZ, type FileScanConfig as a_, type CheckedIncludes as aa, type CheckInclude as ab, type ContentReading as ac, type IncludablePaths as ad, type Reading as ae, type ReadWith as af, type SettingsReading as ag, type SingletonReading as ah, type UntypedReading as ai, defineContentType as aj, fieldset as ak, type Fieldset as al, type FieldMember as am, type ContentTypeConfig as an, type ContentTypeDefinition as ao, type EntryMetadata as ap, type InferContentType as aq, type LocalePublicationFields as ar, defineSingletonContentType as as, defineSingleton as at, type SingletonConfig as au, type SingletonContentTypeDefinition as av, type SingletonMetadata as aw, type InferSingletonContentType as ax, type InferSingleton as ay, defineSettingsGroup as az, type AssetAIConfig as b, type FieldTypeName as b$, defineWorkflowStage as b0, defineContentTypeWorkflow as b1, isWorkflowDefinition as b2, isWorkflowStageDefinition as b3, getWorkflowStageIds as b4, findWorkflowStage as b5, getNextWorkflowStage as b6, getFirstWorkflowStage as b7, isFinalWorkflowStage as b8, type WorkflowEscalation as b9, type LiveWebSocket as bA, type LiveWebSocketConstructor as bB, type ApiPath as bC, type ApiMethod as bD, type ApiSuccessBody as bE, type Wire as bF, matchRoute as bG, type RouteMatch as bH, type MatchRouteOptions as bI, type AssetFileBlock as bJ, type AssetUrls as bK, type BaseContent as bL, type WhereScalar as bM, type WhereFieldCondition as bN, type WhereClause as bO, type WhereOperator as bP, type DateOnlyOperator as bQ, type SortOptions as bR, type QueryOptions as bS, type CreateInput as bT, type RevisedContent as bU, type RestoredContent as bV, type UpdateInput as bW, type ContentQueryResult as bX, type SingletonContent as bY, type CustomQuery as bZ, type ContentTypeSchema as b_, type WorkflowAutoAssign as ba, type WorkflowStageConfig as bb, type WorkflowStageDefinition as bc, type WorkflowConfig as bd, type WorkflowDefinition as be, type ContentTypeWorkflowConfig as bf, defineView as bg, type ViewScopeConfig as bh, type ContentTypeScopeConfig as bi, type ContentTypesScopeConfig as bj, type EntryTypeScopeConfig as bk, type AllScopeConfig as bl, type ViewFilterOperator as bm, type ViewFilterValue as bn, type ViewFilterRelativeDate as bo, type ViewFilterCondition as bp, type ViewFilter as bq, type ViewConfig as br, type ViewDefinition as bs, type InferJsonSchema as bt, type JsonFieldValue as bu, type JsonSchema as bv, type JsonValue as bw, SDKError as bx, type RelyIOConfig as by, type RelyIOConfigUpdate as bz, type BooleanConfig as c, type ValidationRule as c0, type FieldOptions as c1, type RealtimeEventType as c2, type RealtimeEvent as c3, type SubscriptionOptions as c4, type PerformanceMetrics as c5, type CacheConfig as c6, type RealtimeConfig as c7, type DebugConfig as c8, type RequestConfig as c9, type ApiResponse as ca, type RetryConfig as cb, type CacheStrategy as cc, type LogLevel as cd, type Environment as ce, type ValidationViolation as cf, BaseValidationError as cg, ValidationError as ch, InvalidPayloadError as ci, type MergedRelyIOConfig as cj, type PathParamsOf as ck, type ReadWhere as cl, type CheckedInclude as cm, type components as cn, type paths as co, type FieldDefinition as cp, type DateTimeConfig as d, type DecimalConfig as e, type EnumConfig as f, type FieldDefinition$1 as g, type FieldRule as h, type FieldType as i, type FieldUIConfig as j, type LocalizationConfig as k, type LongTextConfig as l, type ReferenceConfig as m, type RequirementRule as n, type RichTextConfig as o, type RichTextLinks as p, type RuleCondition as q, type RuleConditions as r, type SlugConfig as s, type TagsConfig as t, type VisibilityRule as u, boolean as v, code as w, date as x, dateTime as y, decimal as z };