@relyio/sdk 0.11.0 → 0.12.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 (37) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/dist/chunk-3DRDHXLY.js +680 -0
  3. package/dist/{chunk-PO7CUR5U.cjs → chunk-3MSFWXQL.cjs} +37 -65
  4. package/dist/{chunk-4HTIU5YE.cjs → chunk-DXCVO6M5.cjs} +46 -59
  5. package/dist/chunk-FI5VIF4M.cjs +686 -0
  6. package/dist/{chunk-7GLDVHIH.js → chunk-FRJEUAAF.js} +46 -59
  7. package/dist/{chunk-2TIJLV2X.js → chunk-POEEDYFM.js} +38 -65
  8. package/dist/client/index.cjs +3 -3
  9. package/dist/client/index.d.cts +5 -4
  10. package/dist/client/index.d.ts +5 -4
  11. package/dist/client/index.js +1 -1
  12. package/dist/{define-schema-CVi8nwc7.d.ts → define-schema-DgctHlI2.d.cts} +35 -220
  13. package/dist/{define-schema-DqpipEHv.d.cts → define-schema-mrEZbY1h.d.ts} +35 -220
  14. package/dist/{define-content-type-ENAod5Ve.d.cts → include-paths-CL4gHv6I.d.cts} +1673 -734
  15. package/dist/{define-content-type-ENAod5Ve.d.ts → include-paths-CrJNTsMl.d.ts} +1673 -734
  16. package/dist/{index-C73cK2Tt.d.ts → index-B9RfZVF1.d.ts} +3 -2
  17. package/dist/{index-MLAFUuco.d.cts → index-BrvEg6-A.d.cts} +107 -46
  18. package/dist/{index-BKEAYvvz.d.ts → index-Pw0onkJe.d.ts} +107 -46
  19. package/dist/{index-BM42r4yg.d.cts → index-b-AkfTUv.d.cts} +3 -2
  20. package/dist/index.cjs +102 -85
  21. package/dist/index.d.cts +14 -10
  22. package/dist/index.d.ts +14 -10
  23. package/dist/index.js +4 -3
  24. package/dist/rich-text/index.cjs +29 -0
  25. package/dist/rich-text/index.d.cts +148 -0
  26. package/dist/rich-text/index.d.ts +148 -0
  27. package/dist/rich-text/index.js +4 -0
  28. package/dist/rich-text.d-rKmpgdGd.d.cts +200 -0
  29. package/dist/rich-text.d-rKmpgdGd.d.ts +200 -0
  30. package/dist/schema/index.cjs +34 -38
  31. package/dist/schema/index.d.cts +84 -37
  32. package/dist/schema/index.d.ts +84 -37
  33. package/dist/schema/index.js +1 -1
  34. package/dist/types/index.d.cts +3 -2
  35. package/dist/types/index.d.ts +3 -2
  36. package/package.json +8 -2
  37. package/dist/.tsbuildinfo +0 -1
@@ -1,3 +1,5 @@
1
+ import { w as RichTextValue, t as RichTextTable, c as RichTextCodeGroup, s as RichTextStructure, n as RichTextMarkType } from './rich-text.d-rKmpgdGd.js';
2
+
1
3
  /**
2
4
  * Generated by scripts/emit-openapi-types.mjs from @relyio/api's committed
3
5
  * openapi-spec.json. Do not edit: run `pnpm codegen:openapi` in this package, which
@@ -1070,6 +1072,8 @@ interface components {
1070
1072
  localeFallbacksApplied?: {
1071
1073
  [key: string]: string;
1072
1074
  };
1075
+ /** @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. */
1076
+ emptyRequiredFields?: string[];
1073
1077
  /** @description Every locale the entry has content in, the default first. */
1074
1078
  availableLocales: components['schemas']['EntryLocale'][];
1075
1079
  /** @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. */
@@ -1103,7 +1107,7 @@ interface components {
1103
1107
  };
1104
1108
  /** @description One outgoing reference. */
1105
1109
  EntryRef: {
1106
- /** @description The declaring field’s path — `hero.link` for a reference inside a component. */
1110
+ /** @description The declaring field’s path, spelt as the include path that expands it: `sections.customers` for a reference inside a page builder’s blocks, `sections.media.image` for one inside an object inside a block — no shape, index or key. Two block types that declare one field id share a path; each row still names its target. */
1107
1111
  path: string;
1108
1112
  /** @description The referenced entry’s id. */
1109
1113
  entryUid: string;
@@ -1111,7 +1115,7 @@ interface components {
1111
1115
  ErrorResponse: {
1112
1116
  error: {
1113
1117
  /** @enum {string} */
1114
- code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_DELETE_BLOCKED' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | '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';
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';
1115
1119
  messages: string[];
1116
1120
  details?: {
1117
1121
  [key: string]: unknown;
@@ -1230,6 +1234,17 @@ interface components {
1230
1234
  };
1231
1235
  };
1232
1236
  };
1237
+ RefusalProjectInAnotherCell: {
1238
+ error: {
1239
+ /** @enum {string} */
1240
+ code: 'PROJECT_IN_ANOTHER_CELL';
1241
+ messages: string[];
1242
+ details: {
1243
+ /** @description The data region whose cell holds the Project, as `us` or `eu`. */
1244
+ region: string;
1245
+ };
1246
+ };
1247
+ };
1233
1248
  RefusalRateLimitExceeded: {
1234
1249
  error: {
1235
1250
  /** @enum {string} */
@@ -1300,6 +1315,88 @@ interface components {
1300
1315
  };
1301
1316
  };
1302
1317
  };
1318
+ /** @description The entry after a restore: its fields at the top level and `_metadata`, which also lists what the restore left out. */
1319
+ RestoredEntry: {
1320
+ _metadata: components['schemas']['RestoredEntryMetadata'];
1321
+ } & {
1322
+ [key: string]: unknown;
1323
+ };
1324
+ /** @description What this service reports about an entry beside its fields, and what a restore left out of it. */
1325
+ RestoredEntryMetadata: {
1326
+ id: string;
1327
+ /** @description The content type. */
1328
+ type: string;
1329
+ /** @enum {string} */
1330
+ entryType: 'asset' | 'content' | 'settings' | 'singleton';
1331
+ /** @description The slug field’s value at `locale`, or null when the type declares none. */
1332
+ slug: string | null;
1333
+ /**
1334
+ * @description Container lifecycle only. Publication is per locale: `localeStatus`.
1335
+ * @enum {string}
1336
+ */
1337
+ status: 'active' | 'archived' | 'proposed';
1338
+ /** @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. */
1339
+ version: number;
1340
+ /** @description The locale the fields beside this object were composed for. */
1341
+ locale: string;
1342
+ /** @description How many versions `locale` has. Sent on a single-entry read; a list leaves it out. */
1343
+ versionCount?: number;
1344
+ /** @description `locale`’s version numbers, newest first, at most 25. Sent on a single-entry read; a list leaves it out. */
1345
+ versions?: number[];
1346
+ /**
1347
+ * @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.
1348
+ * @enum {string}
1349
+ */
1350
+ localeStatus?: 'archived' | 'draft' | 'published';
1351
+ /** @description Whether `locale` has unpublished changes of its own. */
1352
+ localeHasDraft: boolean;
1353
+ /** @description Every locale holding unpublished content of its own, sorted. A shared-field draft is not listed: it is `hasDraft`. */
1354
+ draftLocales: string[];
1355
+ /** @description Whether the shared (non-localized) fields have unpublished changes. Publishing any locale makes them live, so they are unpublished work in every locale. */
1356
+ hasDraft: boolean;
1357
+ /** @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=*`. */
1358
+ requestedLocale?: string;
1359
+ /** @description The schema’s default locale. */
1360
+ defaultLocale: string;
1361
+ /** @description Each field whose value came from another locale, mapped to that locale. Absent when none did. */
1362
+ localeFallbacksApplied?: {
1363
+ [key: string]: string;
1364
+ };
1365
+ /** @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. */
1366
+ emptyRequiredFields?: string[];
1367
+ /** @description Every locale the entry has content in, the default first. */
1368
+ availableLocales: components['schemas']['EntryLocale'][];
1369
+ /** @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. */
1370
+ localizations?: {
1371
+ [key: string]: {
1372
+ [key: string]: unknown;
1373
+ };
1374
+ };
1375
+ /**
1376
+ * Format: date-time
1377
+ * @description When the entry was created.
1378
+ */
1379
+ createdAt: string;
1380
+ /**
1381
+ * Format: date-time
1382
+ * @description When the entry was last written.
1383
+ */
1384
+ updatedAt: string;
1385
+ /**
1386
+ * Format: date-time
1387
+ * @description When the entry was last published. Absent until it is.
1388
+ */
1389
+ publishedAt?: string;
1390
+ /**
1391
+ * Format: date-time
1392
+ * @description When the entry was first published. Absent until it is.
1393
+ */
1394
+ firstPublishedAt?: string;
1395
+ /** @description The entry’s outgoing references, across every locale, each once. */
1396
+ 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. */
1398
+ leftOut?: string[];
1399
+ };
1303
1400
  /** @description How a hit’s relevance was reached. Sent on a search that asked for `explain`. */
1304
1401
  ScoreBreakdown: {
1305
1402
  keyword: number;
@@ -1510,13 +1607,15 @@ interface components {
1510
1607
  * @description When the singleton was first published. Absent until it is.
1511
1608
  */
1512
1609
  firstPublishedAt?: string;
1610
+ /** @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. */
1611
+ emptyRequiredFields?: string[];
1513
1612
  };
1514
1613
  SubFailure: {
1515
1614
  index: number;
1516
1615
  id?: string;
1517
1616
  error: {
1518
1617
  /** @enum {string} */
1519
- code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | 'ORGANIZATION_DELETE_BLOCKED' | 'PAYLOAD_TOO_LARGE' | 'PLAN_DOWNGRADE_BLOCKED' | 'PLAN_FEATURE_UNAVAILABLE' | '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';
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';
1520
1619
  messages: string[];
1521
1620
  details?: {
1522
1621
  [key: string]: unknown;
@@ -2286,6 +2385,15 @@ interface operations {
2286
2385
  'application/json': components['schemas']['RefusalResourceNotFound'];
2287
2386
  };
2288
2387
  };
2388
+ /** @description PROJECT_IN_ANOTHER_CELL */
2389
+ 421: {
2390
+ headers: {
2391
+ [name: string]: unknown;
2392
+ };
2393
+ content: {
2394
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
2395
+ };
2396
+ };
2289
2397
  /** @description RATE_LIMIT_EXCEEDED */
2290
2398
  429: {
2291
2399
  headers: {
@@ -2394,6 +2502,15 @@ interface operations {
2394
2502
  'application/json': components['schemas']['RefusalResourceExpired'];
2395
2503
  };
2396
2504
  };
2505
+ /** @description PROJECT_IN_ANOTHER_CELL */
2506
+ 421: {
2507
+ headers: {
2508
+ [name: string]: unknown;
2509
+ };
2510
+ content: {
2511
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
2512
+ };
2513
+ };
2397
2514
  /** @description RATE_LIMIT_EXCEEDED */
2398
2515
  429: {
2399
2516
  headers: {
@@ -2490,6 +2607,15 @@ interface operations {
2490
2607
  'application/json': components['schemas']['RefusalResourceNotFound'];
2491
2608
  };
2492
2609
  };
2610
+ /** @description PROJECT_IN_ANOTHER_CELL */
2611
+ 421: {
2612
+ headers: {
2613
+ [name: string]: unknown;
2614
+ };
2615
+ content: {
2616
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
2617
+ };
2618
+ };
2493
2619
  /** @description RATE_LIMIT_EXCEEDED */
2494
2620
  429: {
2495
2621
  headers: {
@@ -2595,6 +2721,15 @@ interface operations {
2595
2721
  'application/json': components['schemas']['RefusalResourceExpired'];
2596
2722
  };
2597
2723
  };
2724
+ /** @description PROJECT_IN_ANOTHER_CELL */
2725
+ 421: {
2726
+ headers: {
2727
+ [name: string]: unknown;
2728
+ };
2729
+ content: {
2730
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
2731
+ };
2732
+ };
2598
2733
  /** @description RATE_LIMIT_EXCEEDED */
2599
2734
  429: {
2600
2735
  headers: {
@@ -2705,6 +2840,15 @@ interface operations {
2705
2840
  'application/json': components['schemas']['RefusalResourceExpired'];
2706
2841
  };
2707
2842
  };
2843
+ /** @description PROJECT_IN_ANOTHER_CELL */
2844
+ 421: {
2845
+ headers: {
2846
+ [name: string]: unknown;
2847
+ };
2848
+ content: {
2849
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
2850
+ };
2851
+ };
2708
2852
  /** @description RATE_LIMIT_EXCEEDED */
2709
2853
  429: {
2710
2854
  headers: {
@@ -2801,6 +2945,15 @@ interface operations {
2801
2945
  'application/json': components['schemas']['RefusalResourceNotFound'];
2802
2946
  };
2803
2947
  };
2948
+ /** @description PROJECT_IN_ANOTHER_CELL */
2949
+ 421: {
2950
+ headers: {
2951
+ [name: string]: unknown;
2952
+ };
2953
+ content: {
2954
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
2955
+ };
2956
+ };
2804
2957
  /** @description RATE_LIMIT_EXCEEDED */
2805
2958
  429: {
2806
2959
  headers: {
@@ -2889,6 +3042,15 @@ interface operations {
2889
3042
  'application/json': components['schemas']['RefusalResourceNotFound'];
2890
3043
  };
2891
3044
  };
3045
+ /** @description PROJECT_IN_ANOTHER_CELL */
3046
+ 421: {
3047
+ headers: {
3048
+ [name: string]: unknown;
3049
+ };
3050
+ content: {
3051
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
3052
+ };
3053
+ };
2892
3054
  /** @description RATE_LIMIT_EXCEEDED */
2893
3055
  429: {
2894
3056
  headers: {
@@ -2991,6 +3153,15 @@ interface operations {
2991
3153
  'application/json': components['schemas']['RefusalResourceExpired'];
2992
3154
  };
2993
3155
  };
3156
+ /** @description PROJECT_IN_ANOTHER_CELL */
3157
+ 421: {
3158
+ headers: {
3159
+ [name: string]: unknown;
3160
+ };
3161
+ content: {
3162
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
3163
+ };
3164
+ };
2994
3165
  /** @description RATE_LIMIT_EXCEEDED */
2995
3166
  429: {
2996
3167
  headers: {
@@ -3098,6 +3269,15 @@ interface operations {
3098
3269
  'application/json': components['schemas']['RefusalResourceExpired'];
3099
3270
  };
3100
3271
  };
3272
+ /** @description PROJECT_IN_ANOTHER_CELL */
3273
+ 421: {
3274
+ headers: {
3275
+ [name: string]: unknown;
3276
+ };
3277
+ content: {
3278
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
3279
+ };
3280
+ };
3101
3281
  /** @description RATE_LIMIT_EXCEEDED */
3102
3282
  429: {
3103
3283
  headers: {
@@ -3205,6 +3385,15 @@ interface operations {
3205
3385
  'application/json': components['schemas']['RefusalResourceExpired'];
3206
3386
  };
3207
3387
  };
3388
+ /** @description PROJECT_IN_ANOTHER_CELL */
3389
+ 421: {
3390
+ headers: {
3391
+ [name: string]: unknown;
3392
+ };
3393
+ content: {
3394
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
3395
+ };
3396
+ };
3208
3397
  /** @description RATE_LIMIT_EXCEEDED */
3209
3398
  429: {
3210
3399
  headers: {
@@ -3312,6 +3501,15 @@ interface operations {
3312
3501
  'application/json': components['schemas']['RefusalResourceExpired'];
3313
3502
  };
3314
3503
  };
3504
+ /** @description PROJECT_IN_ANOTHER_CELL */
3505
+ 421: {
3506
+ headers: {
3507
+ [name: string]: unknown;
3508
+ };
3509
+ content: {
3510
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
3511
+ };
3512
+ };
3315
3513
  /** @description RATE_LIMIT_EXCEEDED */
3316
3514
  429: {
3317
3515
  headers: {
@@ -3419,6 +3617,15 @@ interface operations {
3419
3617
  'application/json': components['schemas']['RefusalResourceExpired'];
3420
3618
  };
3421
3619
  };
3620
+ /** @description PROJECT_IN_ANOTHER_CELL */
3621
+ 421: {
3622
+ headers: {
3623
+ [name: string]: unknown;
3624
+ };
3625
+ content: {
3626
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
3627
+ };
3628
+ };
3422
3629
  /** @description RATE_LIMIT_EXCEEDED */
3423
3630
  429: {
3424
3631
  headers: {
@@ -3526,6 +3733,15 @@ interface operations {
3526
3733
  'application/json': components['schemas']['RefusalResourceExpired'];
3527
3734
  };
3528
3735
  };
3736
+ /** @description PROJECT_IN_ANOTHER_CELL */
3737
+ 421: {
3738
+ headers: {
3739
+ [name: string]: unknown;
3740
+ };
3741
+ content: {
3742
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
3743
+ };
3744
+ };
3529
3745
  /** @description RATE_LIMIT_EXCEEDED */
3530
3746
  429: {
3531
3747
  headers: {
@@ -3633,6 +3849,15 @@ interface operations {
3633
3849
  'application/json': components['schemas']['RefusalResourceExpired'];
3634
3850
  };
3635
3851
  };
3852
+ /** @description PROJECT_IN_ANOTHER_CELL */
3853
+ 421: {
3854
+ headers: {
3855
+ [name: string]: unknown;
3856
+ };
3857
+ content: {
3858
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
3859
+ };
3860
+ };
3636
3861
  /** @description RATE_LIMIT_EXCEEDED */
3637
3862
  429: {
3638
3863
  headers: {
@@ -3740,6 +3965,15 @@ interface operations {
3740
3965
  'application/json': components['schemas']['RefusalResourceExpired'];
3741
3966
  };
3742
3967
  };
3968
+ /** @description PROJECT_IN_ANOTHER_CELL */
3969
+ 421: {
3970
+ headers: {
3971
+ [name: string]: unknown;
3972
+ };
3973
+ content: {
3974
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
3975
+ };
3976
+ };
3743
3977
  /** @description RATE_LIMIT_EXCEEDED */
3744
3978
  429: {
3745
3979
  headers: {
@@ -3847,6 +4081,15 @@ interface operations {
3847
4081
  'application/json': components['schemas']['RefusalResourceExpired'];
3848
4082
  };
3849
4083
  };
4084
+ /** @description PROJECT_IN_ANOTHER_CELL */
4085
+ 421: {
4086
+ headers: {
4087
+ [name: string]: unknown;
4088
+ };
4089
+ content: {
4090
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
4091
+ };
4092
+ };
3850
4093
  /** @description RATE_LIMIT_EXCEEDED */
3851
4094
  429: {
3852
4095
  headers: {
@@ -3936,6 +4179,15 @@ interface operations {
3936
4179
  'application/json': components['schemas']['RefusalResourceNotFound'];
3937
4180
  };
3938
4181
  };
4182
+ /** @description PROJECT_IN_ANOTHER_CELL */
4183
+ 421: {
4184
+ headers: {
4185
+ [name: string]: unknown;
4186
+ };
4187
+ content: {
4188
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
4189
+ };
4190
+ };
3939
4191
  /** @description RATE_LIMIT_EXCEEDED */
3940
4192
  429: {
3941
4193
  headers: {
@@ -4025,6 +4277,15 @@ interface operations {
4025
4277
  'application/json': components['schemas']['RefusalResourceNotFound'];
4026
4278
  };
4027
4279
  };
4280
+ /** @description PROJECT_IN_ANOTHER_CELL */
4281
+ 421: {
4282
+ headers: {
4283
+ [name: string]: unknown;
4284
+ };
4285
+ content: {
4286
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
4287
+ };
4288
+ };
4028
4289
  /** @description RATE_LIMIT_EXCEEDED */
4029
4290
  429: {
4030
4291
  headers: {
@@ -4115,6 +4376,15 @@ interface operations {
4115
4376
  'application/json': components['schemas']['RefusalResourceNotFound'];
4116
4377
  };
4117
4378
  };
4379
+ /** @description PROJECT_IN_ANOTHER_CELL */
4380
+ 421: {
4381
+ headers: {
4382
+ [name: string]: unknown;
4383
+ };
4384
+ content: {
4385
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
4386
+ };
4387
+ };
4118
4388
  /** @description RATE_LIMIT_EXCEEDED */
4119
4389
  429: {
4120
4390
  headers: {
@@ -4167,8 +4437,7 @@ interface operations {
4167
4437
  };
4168
4438
  content: {
4169
4439
  'application/json': {
4170
- /** @description The payload itself. */
4171
- data: unknown;
4440
+ data: components['schemas']['RestoredEntry'];
4172
4441
  };
4173
4442
  };
4174
4443
  };
@@ -4226,6 +4495,15 @@ interface operations {
4226
4495
  'application/json': components['schemas']['RefusalResourceExpired'];
4227
4496
  };
4228
4497
  };
4498
+ /** @description PROJECT_IN_ANOTHER_CELL */
4499
+ 421: {
4500
+ headers: {
4501
+ [name: string]: unknown;
4502
+ };
4503
+ content: {
4504
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
4505
+ };
4506
+ };
4229
4507
  /** @description RATE_LIMIT_EXCEEDED */
4230
4508
  429: {
4231
4509
  headers: {
@@ -4329,6 +4607,15 @@ interface operations {
4329
4607
  'application/json': components['schemas']['RefusalResourceExpired'];
4330
4608
  };
4331
4609
  };
4610
+ /** @description PROJECT_IN_ANOTHER_CELL */
4611
+ 421: {
4612
+ headers: {
4613
+ [name: string]: unknown;
4614
+ };
4615
+ content: {
4616
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
4617
+ };
4618
+ };
4332
4619
  /** @description RATE_LIMIT_EXCEEDED */
4333
4620
  429: {
4334
4621
  headers: {
@@ -4455,6 +4742,21 @@ interface operations {
4455
4742
  };
4456
4743
  };
4457
4744
  };
4745
+ /** @description PROJECT_IN_ANOTHER_CELL */
4746
+ 421: {
4747
+ headers: {
4748
+ [name: string]: unknown;
4749
+ };
4750
+ content: {
4751
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
4752
+ 'text/event-stream': {
4753
+ /** @enum {string} */
4754
+ type: 'change' | 'complete' | 'error' | 'heartbeat';
4755
+ } & {
4756
+ [key: string]: unknown;
4757
+ };
4758
+ };
4759
+ };
4458
4760
  /** @description RATE_LIMIT_EXCEEDED */
4459
4761
  429: {
4460
4762
  headers: {
@@ -4552,6 +4854,15 @@ interface operations {
4552
4854
  'application/json': components['schemas']['RefusalAccessDeniedOrPlanFeatureUnavailableOrUsageQuotaExceeded'];
4553
4855
  };
4554
4856
  };
4857
+ /** @description PROJECT_IN_ANOTHER_CELL */
4858
+ 421: {
4859
+ headers: {
4860
+ [name: string]: unknown;
4861
+ };
4862
+ content: {
4863
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
4864
+ };
4865
+ };
4555
4866
  /** @description RATE_LIMIT_EXCEEDED */
4556
4867
  429: {
4557
4868
  headers: {
@@ -4640,6 +4951,15 @@ interface operations {
4640
4951
  'application/json': components['schemas']['RefusalResourceNotFound'];
4641
4952
  };
4642
4953
  };
4954
+ /** @description PROJECT_IN_ANOTHER_CELL */
4955
+ 421: {
4956
+ headers: {
4957
+ [name: string]: unknown;
4958
+ };
4959
+ content: {
4960
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
4961
+ };
4962
+ };
4643
4963
  /** @description RATE_LIMIT_EXCEEDED */
4644
4964
  429: {
4645
4965
  headers: {
@@ -4719,6 +5039,15 @@ interface operations {
4719
5039
  'application/json': components['schemas']['RefusalAccessDeniedOrPlanFeatureUnavailableOrUsageQuotaExceeded'];
4720
5040
  };
4721
5041
  };
5042
+ /** @description PROJECT_IN_ANOTHER_CELL */
5043
+ 421: {
5044
+ headers: {
5045
+ [name: string]: unknown;
5046
+ };
5047
+ content: {
5048
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5049
+ };
5050
+ };
4722
5051
  /** @description RATE_LIMIT_EXCEEDED */
4723
5052
  429: {
4724
5053
  headers: {
@@ -4807,6 +5136,15 @@ interface operations {
4807
5136
  'application/json': components['schemas']['RefusalResourceNotFound'];
4808
5137
  };
4809
5138
  };
5139
+ /** @description PROJECT_IN_ANOTHER_CELL */
5140
+ 421: {
5141
+ headers: {
5142
+ [name: string]: unknown;
5143
+ };
5144
+ content: {
5145
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5146
+ };
5147
+ };
4810
5148
  /** @description RATE_LIMIT_EXCEEDED */
4811
5149
  429: {
4812
5150
  headers: {
@@ -4897,6 +5235,15 @@ interface operations {
4897
5235
  'application/json': components['schemas']['RefusalResourceNotFound'];
4898
5236
  };
4899
5237
  };
5238
+ /** @description PROJECT_IN_ANOTHER_CELL */
5239
+ 421: {
5240
+ headers: {
5241
+ [name: string]: unknown;
5242
+ };
5243
+ content: {
5244
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5245
+ };
5246
+ };
4900
5247
  /** @description RATE_LIMIT_EXCEEDED */
4901
5248
  429: {
4902
5249
  headers: {
@@ -4987,6 +5334,15 @@ interface operations {
4987
5334
  'application/json': components['schemas']['RefusalResourceNotFound'];
4988
5335
  };
4989
5336
  };
5337
+ /** @description PROJECT_IN_ANOTHER_CELL */
5338
+ 421: {
5339
+ headers: {
5340
+ [name: string]: unknown;
5341
+ };
5342
+ content: {
5343
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5344
+ };
5345
+ };
4990
5346
  /** @description RATE_LIMIT_EXCEEDED */
4991
5347
  429: {
4992
5348
  headers: {
@@ -5073,6 +5429,15 @@ interface operations {
5073
5429
  'application/json': components['schemas']['RefusalResourceNotFound'];
5074
5430
  };
5075
5431
  };
5432
+ /** @description PROJECT_IN_ANOTHER_CELL */
5433
+ 421: {
5434
+ headers: {
5435
+ [name: string]: unknown;
5436
+ };
5437
+ content: {
5438
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5439
+ };
5440
+ };
5076
5441
  /** @description RATE_LIMIT_EXCEEDED */
5077
5442
  429: {
5078
5443
  headers: {
@@ -5173,6 +5538,15 @@ interface operations {
5173
5538
  'application/json': components['schemas']['RefusalRequestTimeout'];
5174
5539
  };
5175
5540
  };
5541
+ /** @description PROJECT_IN_ANOTHER_CELL */
5542
+ 421: {
5543
+ headers: {
5544
+ [name: string]: unknown;
5545
+ };
5546
+ content: {
5547
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5548
+ };
5549
+ };
5176
5550
  /** @description RATE_LIMIT_EXCEEDED */
5177
5551
  429: {
5178
5552
  headers: {
@@ -5267,6 +5641,15 @@ interface operations {
5267
5641
  'application/json': components['schemas']['RefusalResourceNotFound'];
5268
5642
  };
5269
5643
  };
5644
+ /** @description PROJECT_IN_ANOTHER_CELL */
5645
+ 421: {
5646
+ headers: {
5647
+ [name: string]: unknown;
5648
+ };
5649
+ content: {
5650
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5651
+ };
5652
+ };
5270
5653
  /** @description RATE_LIMIT_EXCEEDED */
5271
5654
  429: {
5272
5655
  headers: {
@@ -5352,6 +5735,15 @@ interface operations {
5352
5735
  'application/json': components['schemas']['RefusalAccessDeniedOrPlanFeatureUnavailableOrUsageQuotaExceeded'];
5353
5736
  };
5354
5737
  };
5738
+ /** @description PROJECT_IN_ANOTHER_CELL */
5739
+ 421: {
5740
+ headers: {
5741
+ [name: string]: unknown;
5742
+ };
5743
+ content: {
5744
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5745
+ };
5746
+ };
5355
5747
  /** @description RATE_LIMIT_EXCEEDED */
5356
5748
  429: {
5357
5749
  headers: {
@@ -5446,6 +5838,15 @@ interface operations {
5446
5838
  'application/json': components['schemas']['RefusalResourceNotFound'];
5447
5839
  };
5448
5840
  };
5841
+ /** @description PROJECT_IN_ANOTHER_CELL */
5842
+ 421: {
5843
+ headers: {
5844
+ [name: string]: unknown;
5845
+ };
5846
+ content: {
5847
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5848
+ };
5849
+ };
5449
5850
  /** @description RATE_LIMIT_EXCEEDED */
5450
5851
  429: {
5451
5852
  headers: {
@@ -5529,6 +5930,15 @@ interface operations {
5529
5930
  'application/json': components['schemas']['RefusalAccessDeniedOrPlanFeatureUnavailableOrUsageQuotaExceeded'];
5530
5931
  };
5531
5932
  };
5933
+ /** @description PROJECT_IN_ANOTHER_CELL */
5934
+ 421: {
5935
+ headers: {
5936
+ [name: string]: unknown;
5937
+ };
5938
+ content: {
5939
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
5940
+ };
5941
+ };
5532
5942
  /** @description RATE_LIMIT_EXCEEDED */
5533
5943
  429: {
5534
5944
  headers: {
@@ -5624,6 +6034,15 @@ interface operations {
5624
6034
  'application/json': components['schemas']['RefusalResourceNotFound'];
5625
6035
  };
5626
6036
  };
6037
+ /** @description PROJECT_IN_ANOTHER_CELL */
6038
+ 421: {
6039
+ headers: {
6040
+ [name: string]: unknown;
6041
+ };
6042
+ content: {
6043
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6044
+ };
6045
+ };
5627
6046
  /** @description RATE_LIMIT_EXCEEDED */
5628
6047
  429: {
5629
6048
  headers: {
@@ -5733,6 +6152,15 @@ interface operations {
5733
6152
  'application/json': components['schemas']['RefusalResourceExpired'];
5734
6153
  };
5735
6154
  };
6155
+ /** @description PROJECT_IN_ANOTHER_CELL */
6156
+ 421: {
6157
+ headers: {
6158
+ [name: string]: unknown;
6159
+ };
6160
+ content: {
6161
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6162
+ };
6163
+ };
5736
6164
  /** @description RATE_LIMIT_EXCEEDED */
5737
6165
  429: {
5738
6166
  headers: {
@@ -5821,6 +6249,15 @@ interface operations {
5821
6249
  'application/json': components['schemas']['RefusalResourceNotFound'];
5822
6250
  };
5823
6251
  };
6252
+ /** @description PROJECT_IN_ANOTHER_CELL */
6253
+ 421: {
6254
+ headers: {
6255
+ [name: string]: unknown;
6256
+ };
6257
+ content: {
6258
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6259
+ };
6260
+ };
5824
6261
  /** @description RATE_LIMIT_EXCEEDED */
5825
6262
  429: {
5826
6263
  headers: {
@@ -5930,6 +6367,15 @@ interface operations {
5930
6367
  'application/json': components['schemas']['RefusalResourceExpired'];
5931
6368
  };
5932
6369
  };
6370
+ /** @description PROJECT_IN_ANOTHER_CELL */
6371
+ 421: {
6372
+ headers: {
6373
+ [name: string]: unknown;
6374
+ };
6375
+ content: {
6376
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6377
+ };
6378
+ };
5933
6379
  /** @description RATE_LIMIT_EXCEEDED */
5934
6380
  429: {
5935
6381
  headers: {
@@ -6018,6 +6464,15 @@ interface operations {
6018
6464
  'application/json': components['schemas']['RefusalResourceNotFound'];
6019
6465
  };
6020
6466
  };
6467
+ /** @description PROJECT_IN_ANOTHER_CELL */
6468
+ 421: {
6469
+ headers: {
6470
+ [name: string]: unknown;
6471
+ };
6472
+ content: {
6473
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6474
+ };
6475
+ };
6021
6476
  /** @description RATE_LIMIT_EXCEEDED */
6022
6477
  429: {
6023
6478
  headers: {
@@ -6107,6 +6562,15 @@ interface operations {
6107
6562
  'application/json': components['schemas']['RefusalResourceNotFound'];
6108
6563
  };
6109
6564
  };
6565
+ /** @description PROJECT_IN_ANOTHER_CELL */
6566
+ 421: {
6567
+ headers: {
6568
+ [name: string]: unknown;
6569
+ };
6570
+ content: {
6571
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6572
+ };
6573
+ };
6110
6574
  /** @description RATE_LIMIT_EXCEEDED */
6111
6575
  429: {
6112
6576
  headers: {
@@ -6202,6 +6666,15 @@ interface operations {
6202
6666
  'application/json': components['schemas']['RefusalResourceNotFound'];
6203
6667
  };
6204
6668
  };
6669
+ /** @description PROJECT_IN_ANOTHER_CELL */
6670
+ 421: {
6671
+ headers: {
6672
+ [name: string]: unknown;
6673
+ };
6674
+ content: {
6675
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6676
+ };
6677
+ };
6205
6678
  /** @description RATE_LIMIT_EXCEEDED */
6206
6679
  429: {
6207
6680
  headers: {
@@ -6311,6 +6784,15 @@ interface operations {
6311
6784
  'application/json': components['schemas']['RefusalResourceExpired'];
6312
6785
  };
6313
6786
  };
6787
+ /** @description PROJECT_IN_ANOTHER_CELL */
6788
+ 421: {
6789
+ headers: {
6790
+ [name: string]: unknown;
6791
+ };
6792
+ content: {
6793
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6794
+ };
6795
+ };
6314
6796
  /** @description RATE_LIMIT_EXCEEDED */
6315
6797
  429: {
6316
6798
  headers: {
@@ -6399,6 +6881,15 @@ interface operations {
6399
6881
  'application/json': components['schemas']['RefusalResourceNotFound'];
6400
6882
  };
6401
6883
  };
6884
+ /** @description PROJECT_IN_ANOTHER_CELL */
6885
+ 421: {
6886
+ headers: {
6887
+ [name: string]: unknown;
6888
+ };
6889
+ content: {
6890
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6891
+ };
6892
+ };
6402
6893
  /** @description RATE_LIMIT_EXCEEDED */
6403
6894
  429: {
6404
6895
  headers: {
@@ -6487,6 +6978,15 @@ interface operations {
6487
6978
  'application/json': components['schemas']['RefusalResourceNotFound'];
6488
6979
  };
6489
6980
  };
6981
+ /** @description PROJECT_IN_ANOTHER_CELL */
6982
+ 421: {
6983
+ headers: {
6984
+ [name: string]: unknown;
6985
+ };
6986
+ content: {
6987
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
6988
+ };
6989
+ };
6490
6990
  /** @description RATE_LIMIT_EXCEEDED */
6491
6991
  429: {
6492
6992
  headers: {
@@ -6576,6 +7076,15 @@ interface operations {
6576
7076
  'application/json': components['schemas']['RefusalResourceNotFound'];
6577
7077
  };
6578
7078
  };
7079
+ /** @description PROJECT_IN_ANOTHER_CELL */
7080
+ 421: {
7081
+ headers: {
7082
+ [name: string]: unknown;
7083
+ };
7084
+ content: {
7085
+ 'application/json': components['schemas']['RefusalProjectInAnotherCell'];
7086
+ };
7087
+ };
6579
7088
  /** @description RATE_LIMIT_EXCEEDED */
6580
7089
  429: {
6581
7090
  headers: {
@@ -6608,458 +7117,178 @@ interface operations {
6608
7117
  }
6609
7118
 
6610
7119
  /**
6611
- * Field type definitions matching @relyio/schema package
7120
+ * Workflow definition for content approval pipelines
6612
7121
  *
6613
- * Every config option here is spelled as `@relyio/schema`'s field config schema spells it, because
6614
- * the CLI sends a field's `config` to deploy verbatim, and deploy — and `relyio validate` before it —
6615
- * refuses an option the field's type does not declare, naming its path (REL-1480). This package does
6616
- * not depend on `@relyio/schema`, so the
6617
- * options are pinned from `@relyio/codegen-typescript`, which depends on both: its
6618
- * `src/__tests__/sdk-field-config.types.ts` fails to compile when a key, whether it is required, or
6619
- * the values it accepts differs between the two (REL-1408).
6620
- */
6621
- /**
6622
- * AI configuration. A single prompt — `instructions` — describes what the
6623
- * element is and how AI should produce its value. Attaches to fields, content
6624
- * types, components, fieldsets, and (extended) asset types.
7122
+ * Workflows define approval stages that content must pass through before
7123
+ * publication. They can be configured globally and per content type.
6625
7124
  *
6626
7125
  * @example
6627
- * ```typescript
6628
- * fields.richText('body', {
6629
- * ai: {
6630
- * instructions: `
6631
- * Write in a conversational tone.
6632
- * Use short paragraphs (2-3 sentences).
6633
- * Target grade 8 reading level.
6634
- * `
6635
- * }
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
+ * })
7136
+ *
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']
7145
+ * }),
7146
+ * defineWorkflowStage('legal-approval', {
7147
+ * displayName: 'Legal Approval',
7148
+ * requiredApprovals: 1,
7149
+ * allowedRoles: ['legal-reviewer']
7150
+ * }),
7151
+ * defineWorkflowStage('final-approval', {
7152
+ * displayName: 'Final Approval',
7153
+ * requiredApprovals: 2,
7154
+ * allowedRoles: ['publisher', 'admin']
7155
+ * })
7156
+ * ]
6636
7157
  * })
6637
- * ```
6638
7158
  */
6639
- interface AIConfig {
6640
- /**
6641
- * AI brief for this element: what it should contain and how to produce it.
6642
- *
6643
- * Used by the Studio authoring agent and — on asset types with
6644
- * `ai.autoGenerate` — by the automatic post-upload run.
6645
- *
6646
- * The fallback chain for AI guidance is:
6647
- * 1. ai.instructions (most specific)
6648
- * 2. ui.description (general field description)
6649
- * 3. Field displayName + type (inferred from semantics)
6650
- */
6651
- instructions?: string;
6652
- }
6653
7159
  /**
6654
- * Field-level AI config. `inputs` names the fields this instruction reads.
6655
- * Unknown ids and cycles are refused when the schema is parsed.
7160
+ * Escalation configuration when a workflow stage times out
6656
7161
  */
6657
- interface FieldAIConfig extends AIConfig {
6658
- /** Field ids this instruction reads. Never inferred from instruction text. */
6659
- inputs?: string[];
7162
+ interface WorkflowEscalation {
7163
+ /** Roles to notify when stage times out */
7164
+ notifyRoles?: string[];
7165
+ /** Roles to escalate to if still pending after another timeout period */
7166
+ escalateToRoles?: string[];
6660
7167
  }
6661
7168
  /**
6662
- * Asset-type AI configuration. Extends {@link AIConfig} with `autoGenerate`,
6663
- * the single switch that turns on automatic field generation after upload.
7169
+ * Auto-assignment configuration for workflow stages
6664
7170
  */
6665
- interface AssetAIConfig extends AIConfig {
6666
- /**
6667
- * Master switch for automatic, post-upload field generation. When `true`, the
6668
- * derived analysis agent fills every field that declares `ai.instructions`,
6669
- * applied as a review proposal. Only meaningful for image asset types in v1.
6670
- */
6671
- autoGenerate?: boolean;
6672
- }
6673
- interface BaseFieldConfig {
6674
- /** Whether the field is required */
6675
- required?: boolean;
6676
- /** Whether the field value must be unique */
6677
- unique?: boolean;
6678
- /** Default value for the field. Each field type narrows it to the values its schema accepts. */
6679
- defaultValue?: unknown;
7171
+ interface WorkflowAutoAssign {
7172
+ /** Roles whose users should be notified when content enters this stage */
7173
+ roles: string[];
6680
7174
  }
6681
- interface FieldUIConfig {
6682
- /** Display name shown in the UI */
7175
+ /**
7176
+ * Workflow stage configuration
7177
+ */
7178
+ interface WorkflowStageConfig {
7179
+ /** Human-readable name shown in Studio */
6683
7180
  displayName: string;
6684
- /** Field description/help text */
7181
+ /** Optional description for reviewers */
6685
7182
  description?: string;
6686
- /** Widget-specific options */
6687
- options?: Record<string, unknown>;
7183
+ /** Number of approvals needed to pass this stage (default: 1) */
7184
+ requiredApprovals?: number;
7185
+ /** Roles that can approve this stage */
7186
+ allowedRoles?: string[];
7187
+ /** Auto-assignment configuration */
7188
+ autoAssign?: WorkflowAutoAssign;
7189
+ /** Days before escalation triggers (optional) */
7190
+ timeoutDays?: number;
7191
+ /** Escalation configuration when stage times out */
7192
+ escalation?: WorkflowEscalation;
6688
7193
  }
6689
- interface RuleCondition {
6690
- field: string;
6691
- operator: 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'greater_than' | 'less_than' | 'is_empty' | 'is_not_empty';
6692
- value?: unknown;
7194
+ /**
7195
+ * Complete workflow stage definition
7196
+ */
7197
+ interface WorkflowStageDefinition {
7198
+ readonly _tag: 'workflowStage';
7199
+ readonly id: string;
7200
+ readonly displayName: string;
7201
+ readonly description?: string;
7202
+ /** Absent means the schema's default of 1 */
7203
+ readonly requiredApprovals?: number;
7204
+ readonly allowedRoles?: string[];
7205
+ readonly autoAssign?: WorkflowAutoAssign;
7206
+ readonly timeoutDays?: number;
7207
+ readonly escalation?: WorkflowEscalation;
6693
7208
  }
6694
- interface RuleConditions {
6695
- mode: 'all' | 'any' | 'none';
6696
- conditions: RuleCondition[];
6697
- }
6698
- interface VisibilityRule {
6699
- type: 'visibility';
6700
- action: 'show' | 'hide';
6701
- conditions: RuleConditions;
6702
- }
6703
- interface RequirementRule {
6704
- type: 'requirement';
6705
- action: 'require' | 'optional';
6706
- conditions: RuleConditions;
6707
- }
6708
- interface ValidationRule {
6709
- type: 'validation';
6710
- action: 'validate' | 'skip';
6711
- message?: string;
6712
- conditions: RuleConditions;
6713
- }
6714
- interface ReadOnlyRule {
6715
- type: 'readOnly';
6716
- action: 'enable' | 'disable';
6717
- conditions: RuleConditions;
6718
- }
6719
- type FieldRule = VisibilityRule | RequirementRule | ValidationRule | ReadOnlyRule;
6720
- type LocalizationConfig = boolean | string[] | {
6721
- enabled: boolean;
6722
- requiredLocales?: string[];
6723
- fallback?: boolean;
6724
- };
6725
- interface FieldDefinition<TId extends string = string, TType extends string = string, TConfig = unknown> {
6726
- /** Unique field identifier - preserves literal type for type inference */
6727
- readonly id: TId;
6728
- /** Field type */
6729
- readonly type: TType;
6730
- /** Type-specific configuration */
6731
- config?: TConfig;
6732
- /** UI display configuration */
6733
- ui?: FieldUIConfig;
6734
- /** AI configuration: generation/review guidance for this field */
6735
- ai?: FieldAIConfig;
6736
- /** Dynamic field rules */
6737
- rules?: FieldRule[];
6738
- /** Localization settings */
6739
- localization?: LocalizationConfig;
6740
- /** Fallback value when field is empty */
6741
- fallback?: unknown;
6742
- /** Whether this field is deprecated */
6743
- deprecated?: boolean;
6744
- }
6745
- /**
6746
- * Any field definition - used in arrays where we need to preserve specific field types
6747
- */
6748
- type AnyFieldDefinition = FieldDefinition<string, string, unknown>;
6749
- interface ShortTextConfig extends BaseFieldConfig {
6750
- /** Maximum character length */
6751
- maxLength?: number;
6752
- /** Regex pattern for validation */
6753
- pattern?: string;
6754
- defaultValue?: string;
6755
- }
6756
- interface LongTextConfig extends BaseFieldConfig {
6757
- minLength?: number;
6758
- maxLength?: number;
6759
- defaultValue?: string;
6760
- }
6761
- interface RichTextConfig extends BaseFieldConfig {
6762
- /** Maximum character length for the rich text content */
6763
- maxLength?: number;
6764
- /** Allowed formatting options (e.g., bold, italic, underline) */
6765
- allowedFormats?: string[];
6766
- /** Allowed embed types (e.g., image, video, code) */
6767
- embedTypes?: string[];
6768
- defaultValue?: string;
6769
- }
6770
- interface SlugConfig extends BaseFieldConfig {
6771
- /** Source field to generate slug from */
6772
- sourceField?: string;
6773
- /** Maximum character length */
6774
- maxLength?: number;
6775
- defaultValue?: string;
6776
- }
6777
- interface UrlConfig extends BaseFieldConfig {
6778
- /** Allowed URL protocols */
6779
- allowedProtocols?: ('http' | 'https' | 'ftp' | 'ftps')[];
6780
- /** Maximum character length */
6781
- maxLength?: number;
6782
- defaultValue?: string;
6783
- }
6784
- interface EmailConfig extends BaseFieldConfig {
6785
- /** Maximum character length */
6786
- maxLength?: number;
6787
- /** Whitelist of allowed email domains */
6788
- domainWhitelist?: string[];
6789
- defaultValue?: string;
6790
- }
6791
- interface IntegerConfig extends BaseFieldConfig {
6792
- min?: number;
6793
- max?: number;
6794
- defaultValue?: number;
6795
- }
6796
- interface DecimalConfig extends BaseFieldConfig {
6797
- min?: number;
6798
- max?: number;
6799
- decimalPlaces?: number;
6800
- roundingMode?: 'HALF_UP' | 'FLOOR' | 'CEILING' | 'ROUND' | 'TRUNCATE';
6801
- defaultValue?: number;
6802
- }
6803
- interface BooleanConfig extends BaseFieldConfig {
6804
- /** The editor's word for `true` (e.g. `'Published'`). */
6805
- labelTrue?: string;
6806
- /** The editor's word for `false` (e.g. `'Draft'`). */
6807
- labelFalse?: string;
6808
- defaultValue?: boolean;
6809
- }
6810
- /**
6811
- * `TValue` is the union of the option values and `TMulti` whether the field holds a list of them.
6812
- * `fields.enum()` infers both from the declaration, so a read of the field is typed by its options
6813
- * (`INV-SS-TYPES-INFERRED`); the defaults describe any enum field.
6814
- */
6815
- interface EnumConfig<TValue extends string = string, TMulti extends boolean = boolean> extends BaseFieldConfig {
6816
- /** The values the field may hold, each with the `label` an editor shows. Deploy refuses an option without one. */
6817
- options: Array<{
6818
- value: TValue;
6819
- label: string;
6820
- }>;
6821
- multi?: TMulti;
6822
- /** One option's value, or a list of them when `multi` is true. */
6823
- defaultValue?: string | string[];
6824
- }
6825
- /** A display format is not config: it is `ui.options.format`, where the schema declares it. */
6826
- interface DateConfig extends BaseFieldConfig {
6827
- minDate?: string;
6828
- maxDate?: string;
6829
- /** `YYYY-MM-DD` */
6830
- defaultValue?: string;
6831
- }
6832
- /** A display format is not config: it is `ui.options.format`, where the schema declares it. */
6833
- interface DateTimeConfig extends BaseFieldConfig {
6834
- minDateTime?: string;
6835
- maxDateTime?: string;
6836
- /**
6837
- * Show the instant in UTC (`'UTC'`) or in the author's local time (`'local'`) in the editor. The
6838
- * instant is stored in UTC either way.
6839
- */
6840
- timeZoneHandling?: 'UTC' | 'local';
6841
- defaultValue?: string;
7209
+ /**
7210
+ * Workflow configuration
7211
+ */
7212
+ interface WorkflowConfig {
7213
+ /** Enable/disable workflow for the branch (default: false) */
7214
+ enabled?: boolean;
7215
+ /** Array of approval stage definitions */
7216
+ stages?: WorkflowStageDefinition[];
6842
7217
  }
6843
7218
  /**
6844
- * `TTo` is the union of the target type ids and `TMulti` whether the field holds a list.
6845
- * `fields.reference()` infers both, so a read of the field is typed by what it points at
6846
- * (`INV-SS-TYPES-INFERRED`); the defaults describe any reference field.
7219
+ * Complete workflow definition
6847
7220
  */
6848
- interface ReferenceConfig<TTo extends string = string, TMulti extends boolean = boolean> extends BaseFieldConfig {
6849
- /**
6850
- * Target entry type id(s) — content type or asset type ids. Pass a single id
6851
- * for one target or an array for several. All ids must belong to the same
6852
- * family (all content types or all asset types).
6853
- */
6854
- to: TTo | TTo[];
6855
- /** Allow multiple references (the field value is a list). */
6856
- multi?: TMulti;
6857
- /** Reference strength for publish/unpublish behavior. */
6858
- referenceStrength?: 'strong' | 'weak';
6859
- /** Behavior when a referenced entry is deleted. */
6860
- onTargetDelete?: 'block' | 'nullify';
6861
- /** A target entry's id, or a list of them when `multi` is true. */
6862
- defaultValue?: string | string[];
6863
- }
6864
- interface TagsConfig extends BaseFieldConfig {
6865
- allowCustom?: boolean;
6866
- predefinedTags?: string[];
6867
- maxTags?: number;
7221
+ interface WorkflowDefinition {
7222
+ readonly _tag: 'workflow';
7223
+ /** Absent means the schema's default, disabled */
7224
+ readonly enabled?: boolean;
7225
+ readonly stages?: WorkflowStageDefinition[];
6868
7226
  }
6869
7227
  /**
6870
- * `TSubfields` is the declared subfields, which `fields.list()` infers so a read types each item by
6871
- * them (`INV-SS-TYPES-INFERRED`); the default describes any list field.
7228
+ * Per-content-type workflow configuration
6872
7229
  */
6873
- interface ListConfig<TSubfields extends readonly AnyFieldDefinition[] = FieldDefinition[]> extends BaseFieldConfig {
6874
- dragAndDrop?: boolean;
6875
- minItems?: number;
6876
- maxItems?: number;
6877
- /** Subfields for list items */
6878
- subfields?: TSubfields;
7230
+ interface ContentTypeWorkflowConfig {
7231
+ /** Enable workflow for this content type (inherits from global if not set) */
7232
+ enabled?: boolean;
7233
+ /** Which global stages apply to this content type (subset of global stages) */
7234
+ stages?: string[];
7235
+ /** Publish automatically after all stages are approved */
7236
+ autoPublish?: boolean;
7237
+ /** Require all locales to be approved before publishing */
7238
+ requireAllLocales?: boolean;
6879
7239
  }
6880
7240
  /**
6881
- * A component field's config: the options every field type takes, and no more — what the schema
6882
- * declares for a `component(<id>)` field, which has no config of its own. The validation document
6883
- * reads `required` from it as it does from any field's.
7241
+ * Define a workflow stage
7242
+ *
7243
+ * @param id - Unique identifier for the stage (kebab-case or camelCase)
7244
+ * @param config - Stage configuration
7245
+ *
7246
+ * @example
7247
+ * const editorialReview = defineWorkflowStage('editorial-review', {
7248
+ * displayName: 'Editorial Review',
7249
+ * description: 'Content quality and style check',
7250
+ * requiredApprovals: 1,
7251
+ * allowedRoles: ['editor', 'senior-editor']
7252
+ * })
7253
+ *
7254
+ * @example
7255
+ * // Stage with auto-assignment and timeout
7256
+ * const legalApproval = defineWorkflowStage('legal-approval', {
7257
+ * displayName: 'Legal Approval',
7258
+ * allowedRoles: ['legal-reviewer'],
7259
+ * autoAssign: { roles: ['legal-reviewer'] },
7260
+ * timeoutDays: 3,
7261
+ * escalation: {
7262
+ * notifyRoles: ['legal-reviewer'],
7263
+ * escalateToRoles: ['admin']
7264
+ * }
7265
+ * })
6884
7266
  */
6885
- type ComponentFieldConfig = BaseFieldConfig;
6886
- type FieldType = 'shortText' | 'longText' | 'richText' | 'slug' | 'url' | 'email' | 'integer' | 'decimal' | 'boolean' | 'enum' | 'date' | 'dateTime' | 'reference' | 'tags' | 'list';
6887
- type ComponentFieldType = `component(${string})`;
6888
- type AllFieldTypes = FieldType | ComponentFieldType;
6889
-
7267
+ declare function defineWorkflowStage(id: string, config: WorkflowStageConfig): WorkflowStageDefinition;
6890
7268
  /**
6891
- * Workflow definition for content approval pipelines
7269
+ * Define a workflow configuration
6892
7270
  *
6893
- * Workflows define approval stages that content must pass through before
6894
- * publication. They can be configured globally and per content type.
7271
+ * @param config - Workflow configuration with enabled flag and stages
6895
7272
  *
6896
7273
  * @example
6897
- * // Simple workflow with one approval stage
7274
+ * // Simple workflow
6898
7275
  * const workflow = defineWorkflow({
6899
7276
  * enabled: true,
6900
7277
  * stages: [
6901
7278
  * defineWorkflowStage('review', {
6902
- * displayName: 'Editorial Review',
6903
- * allowedRoles: ['editor', 'admin']
7279
+ * displayName: 'Review',
7280
+ * allowedRoles: ['editor']
6904
7281
  * })
6905
7282
  * ]
6906
7283
  * })
6907
7284
  *
6908
7285
  * @example
6909
- * // Multi-stage workflow
7286
+ * // Disabled workflow (direct publish)
6910
7287
  * const workflow = defineWorkflow({
6911
- * enabled: true,
6912
- * stages: [
6913
- * defineWorkflowStage('editorial-review', {
6914
- * displayName: 'Editorial Review',
6915
- * allowedRoles: ['editor']
6916
- * }),
6917
- * defineWorkflowStage('legal-approval', {
6918
- * displayName: 'Legal Approval',
6919
- * requiredApprovals: 1,
6920
- * allowedRoles: ['legal-reviewer']
6921
- * }),
6922
- * defineWorkflowStage('final-approval', {
6923
- * displayName: 'Final Approval',
6924
- * requiredApprovals: 2,
6925
- * allowedRoles: ['publisher', 'admin']
6926
- * })
6927
- * ]
7288
+ * enabled: false
6928
7289
  * })
6929
7290
  */
6930
- /**
6931
- * Escalation configuration when a workflow stage times out
6932
- */
6933
- interface WorkflowEscalation {
6934
- /** Roles to notify when stage times out */
6935
- notifyRoles?: string[];
6936
- /** Roles to escalate to if still pending after another timeout period */
6937
- escalateToRoles?: string[];
6938
- }
6939
- /**
6940
- * Auto-assignment configuration for workflow stages
6941
- */
6942
- interface WorkflowAutoAssign {
6943
- /** Roles whose users should be notified when content enters this stage */
6944
- roles: string[];
6945
- }
6946
- /**
6947
- * Workflow stage configuration
6948
- */
6949
- interface WorkflowStageConfig {
6950
- /** Human-readable name shown in Studio */
6951
- displayName: string;
6952
- /** Optional description for reviewers */
6953
- description?: string;
6954
- /** Number of approvals needed to pass this stage (default: 1) */
6955
- requiredApprovals?: number;
6956
- /** Roles that can approve this stage */
6957
- allowedRoles?: string[];
6958
- /** Auto-assignment configuration */
6959
- autoAssign?: WorkflowAutoAssign;
6960
- /** Days before escalation triggers (optional) */
6961
- timeoutDays?: number;
6962
- /** Escalation configuration when stage times out */
6963
- escalation?: WorkflowEscalation;
6964
- }
6965
- /**
6966
- * Complete workflow stage definition
6967
- */
6968
- interface WorkflowStageDefinition {
6969
- readonly _tag: 'workflowStage';
6970
- readonly id: string;
6971
- readonly displayName: string;
6972
- readonly description?: string;
6973
- /** Absent means the schema's default of 1 */
6974
- readonly requiredApprovals?: number;
6975
- readonly allowedRoles?: string[];
6976
- readonly autoAssign?: WorkflowAutoAssign;
6977
- readonly timeoutDays?: number;
6978
- readonly escalation?: WorkflowEscalation;
6979
- }
6980
- /**
6981
- * Workflow configuration
6982
- */
6983
- interface WorkflowConfig {
6984
- /** Enable/disable workflow for the branch (default: false) */
6985
- enabled?: boolean;
6986
- /** Array of approval stage definitions */
6987
- stages?: WorkflowStageDefinition[];
6988
- }
6989
- /**
6990
- * Complete workflow definition
6991
- */
6992
- interface WorkflowDefinition {
6993
- readonly _tag: 'workflow';
6994
- /** Absent means the schema's default, disabled */
6995
- readonly enabled?: boolean;
6996
- readonly stages?: WorkflowStageDefinition[];
6997
- }
6998
- /**
6999
- * Per-content-type workflow configuration
7000
- */
7001
- interface ContentTypeWorkflowConfig {
7002
- /** Enable workflow for this content type (inherits from global if not set) */
7003
- enabled?: boolean;
7004
- /** Which global stages apply to this content type (subset of global stages) */
7005
- stages?: string[];
7006
- /** Publish automatically after all stages are approved */
7007
- autoPublish?: boolean;
7008
- /** Require all locales to be approved before publishing */
7009
- requireAllLocales?: boolean;
7010
- }
7011
- /**
7012
- * Define a workflow stage
7013
- *
7014
- * @param id - Unique identifier for the stage (kebab-case or camelCase)
7015
- * @param config - Stage configuration
7016
- *
7017
- * @example
7018
- * const editorialReview = defineWorkflowStage('editorial-review', {
7019
- * displayName: 'Editorial Review',
7020
- * description: 'Content quality and style check',
7021
- * requiredApprovals: 1,
7022
- * allowedRoles: ['editor', 'senior-editor']
7023
- * })
7024
- *
7025
- * @example
7026
- * // Stage with auto-assignment and timeout
7027
- * const legalApproval = defineWorkflowStage('legal-approval', {
7028
- * displayName: 'Legal Approval',
7029
- * allowedRoles: ['legal-reviewer'],
7030
- * autoAssign: { roles: ['legal-reviewer'] },
7031
- * timeoutDays: 3,
7032
- * escalation: {
7033
- * notifyRoles: ['legal-reviewer'],
7034
- * escalateToRoles: ['admin']
7035
- * }
7036
- * })
7037
- */
7038
- declare function defineWorkflowStage(id: string, config: WorkflowStageConfig): WorkflowStageDefinition;
7039
- /**
7040
- * Define a workflow configuration
7041
- *
7042
- * @param config - Workflow configuration with enabled flag and stages
7043
- *
7044
- * @example
7045
- * // Simple workflow
7046
- * const workflow = defineWorkflow({
7047
- * enabled: true,
7048
- * stages: [
7049
- * defineWorkflowStage('review', {
7050
- * displayName: 'Review',
7051
- * allowedRoles: ['editor']
7052
- * })
7053
- * ]
7054
- * })
7055
- *
7056
- * @example
7057
- * // Disabled workflow (direct publish)
7058
- * const workflow = defineWorkflow({
7059
- * enabled: false
7060
- * })
7061
- */
7062
- declare function defineWorkflow(config: WorkflowConfig): WorkflowDefinition;
7291
+ declare function defineWorkflow(config: WorkflowConfig): WorkflowDefinition;
7063
7292
  /**
7064
7293
  * Define content-type specific workflow configuration
7065
7294
  *
@@ -7117,6 +7346,65 @@ declare function getFirstWorkflowStage(workflow: WorkflowDefinition): WorkflowSt
7117
7346
  */
7118
7347
  declare function isFinalWorkflowStage(workflow: WorkflowDefinition, stageId: string): boolean;
7119
7348
 
7349
+ /**
7350
+ * Each field kind, declared once, with every facet the other packages decide by it — P0's field
7351
+ * contract (REL-1783 declared it, REL-1788 made it the only list; `docs/design/structured-fields/README.md`,
7352
+ * "What every package has to agree on").
7353
+ *
7354
+ * **Every consumer reads it.** Deploy's config verdict, the migration analyzer's change facts, entry
7355
+ * validation's document and entry-writes' date-time paths read `change`, `locale`, `value` and
7356
+ * `./rules` (REL-1784); the live document's projection and the Studio's field bindings read `live`
7357
+ * (REL-1785, `@relyio/entry-projection/document-shape`'s `liveHoldingOf`); the SDK and both code
7358
+ * generators key their tables by the union (REL-1786); the entry filter paths and the View
7359
+ * capabilities (`FIELD_CAPABILITIES`) read `filter`, the search mapping and embed set `search`,
7360
+ * settings' synthesized defaults `synthesized`, the read's fill of an empty required field and the
7361
+ * write core's required-from-creation refusal `empty` (REL-1795, through `./empty`), every
7362
+ * reference finder `references`
7363
+ * ({@link holdsReferenceValue}), the content-adaptation tasks `change` and the seeds `value`
7364
+ * (REL-1787). REL-1788 deleted the per-package tables these replaced (`FIELD_TYPE_KINDS`,
7365
+ * `FIELD_TYPE_OPERATORS`, `FIELD_TYPE_CATEGORIES`, the reader's `FIELD_TYPE_ICONS`).
7366
+ *
7367
+ * **The rule for a consumer:** index by the union, never by a `string` with a fallback. A decision
7368
+ * every kind takes part in is a facet here or a table in its own layer typed
7369
+ * `EveryFieldKind<Row>` (or `OverEveryFieldKind<…>` for a type), so a kind this union gains is a compile error in
7370
+ * every consumer that has not said what it does with it; a decision about one kind is
7371
+ * {@link isKind}; where references are is {@link holdsReferenceValue}. A `type` string is read with
7372
+ * {@link parseFieldType} first, and its `null` arm — a type the language does not declare — is
7373
+ * named, never folded into a kind's row.
7374
+ *
7375
+ * **This module has no runtime dependency at all**, so a browser, the live Worker and a
7376
+ * build-inlined customer package can each take it whole: every import below is `import type`,
7377
+ * and `__tests__/dependency-free.test.ts` refuses any other. The facets that need Zod (a kind's
7378
+ * config declaration) or the AJV fragment builders (its value validation) are in `./rules`, keyed by
7379
+ * the same {@link FieldKind}. The facets that belong to a fenced layer — the SDK's type and the
7380
+ * Python type (customer packages), the Studio field hook (headless Studio packages) — are named in
7381
+ * {@link FIELD_KIND_FACETS} and built in their layers, as a {@link EveryFieldKind} table, so a
7382
+ * missing row there is a compile error there.
7383
+ *
7384
+ * Nested kinds compose rather than declare per shape: an object's facets, and a list item's, are its
7385
+ * shape's fields' facets under `<field>.$<shape>` (`./walk`'s item segment). `./walk` is that
7386
+ * composition.
7387
+ *
7388
+ * Every declaration key is a kind (REL-1799, ADR 0012): a group of fields is an `object` with
7389
+ * `of`, so a table over the kinds is {@link EveryFieldKind}.
7390
+ */
7391
+
7392
+ /**
7393
+ * Every field kind, in the order the schema language has always listed them. The one definition of
7394
+ * the union in `@relyio/schema`: `FIELD_TYPES` in `types/base/constants.ts` is this tuple.
7395
+ */
7396
+ declare const FIELD_KINDS: readonly ['shortText', 'longText', 'richText', 'table', 'code', 'email', 'url', 'slug', 'integer', 'decimal', 'boolean', 'enum', 'date', 'dateTime', 'reference', 'tags', 'list', 'object'];
7397
+ /** A field kind: what a field's `type` names. The declaration is keyed by it and by nothing else. */
7398
+ type FieldKind = (typeof FIELD_KINDS)[number];
7399
+ /**
7400
+ * Holds a type-level table to one member per kind — for a facet that is a type rather than a value,
7401
+ * such as the SDK's value types: `type ValueByKind = OverEveryFieldKind<{ shortText: string; … }>`
7402
+ * fails to compile when a kind has no member.
7403
+ */
7404
+ type OverEveryFieldKind<T extends {
7405
+ readonly [K in FieldKind]: unknown;
7406
+ }> = T;
7407
+
7120
7408
  /**
7121
7409
  * Singleton content type definition matching @relyio/schema
7122
7410
  *
@@ -7127,28 +7415,19 @@ declare function isFinalWorkflowStage(workflow: WorkflowDefinition, stageId: str
7127
7415
  * the type system, enabling full autocomplete in SDK methods.
7128
7416
  */
7129
7417
 
7130
- /**
7131
- * Type alias for a fieldset with any fields.
7132
- */
7133
- type AnyFieldset$2 = Fieldset<any>;
7134
7418
  /**
7135
7419
  * What a singleton takes: a content type's settings, since the schema declares a singleton with the
7136
- * same `ContentTypeSchema` — except `hierarchical`, which is `false` or absent. A singleton is one
7137
- * entry, with no parent and no children, and deploy refuses `true` for one
7138
- * (`SINGLETON_CANNOT_BE_HIERARCHICAL`). It used to take a content type's `boolean` and write `false`
7139
- * whatever it was given.
7420
+ * same `ContentTypeSchema` — fields and fieldsets side by side (REL-1794) — except `hierarchical`,
7421
+ * which is `false` or absent. A singleton is one entry, with no parent and no children, and deploy
7422
+ * refuses `true` for one (`SINGLETON_CANNOT_BE_HIERARCHICAL`).
7140
7423
  */
7141
- interface SingletonConfigWithFields<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> extends Omit<ContentTypeConfigWithFields<TFields>, 'hierarchical'> {
7142
- hierarchical?: false;
7143
- }
7144
- /** {@link SingletonConfigWithFields}, with its fields organised into fieldsets. */
7145
- interface SingletonConfigWithFieldsets<TFieldsets extends readonly AnyFieldset$2[] = readonly AnyFieldset$2[]> extends Omit<ContentTypeConfigWithFieldsets<TFieldsets>, 'hierarchical'> {
7424
+ interface SingletonConfig<TFields extends readonly FieldMember[] = readonly FieldMember[]> extends Omit<ContentTypeConfig<TFields>, 'hierarchical'> {
7146
7425
  hierarchical?: false;
7147
7426
  }
7148
7427
  /**
7149
7428
  * Singleton content type definition - preserves field types for inference
7150
7429
  */
7151
- interface SingletonContentTypeDefinition<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset$2[] = readonly AnyFieldset$2[]> {
7430
+ interface SingletonContentTypeDefinition<TFields extends readonly FieldMember[] = readonly FieldMember[]> {
7152
7431
  readonly _tag: 'singletonContentType';
7153
7432
  readonly name: string;
7154
7433
  readonly displayName: string;
@@ -7162,8 +7441,7 @@ interface SingletonContentTypeDefinition<TFields extends readonly AnyFieldDefini
7162
7441
  readonly accessTags?: string[];
7163
7442
  /** Workflow configuration for this singleton */
7164
7443
  readonly workflow?: ContentTypeWorkflowConfig;
7165
- readonly fields?: TFields;
7166
- readonly fieldsets?: TFieldsets;
7444
+ readonly fields: TFields;
7167
7445
  }
7168
7446
  /**
7169
7447
  * Define a singleton content type
@@ -7183,8 +7461,7 @@ interface SingletonContentTypeDefinition<TFields extends readonly AnyFieldDefini
7183
7461
  * ]
7184
7462
  * })
7185
7463
  */
7186
- declare function defineSingletonContentType<TFields extends readonly AnyFieldDefinition[], _TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: SingletonConfigWithFields<TFields>): SingletonContentTypeDefinition<TFields, readonly []>;
7187
- declare function defineSingletonContentType<_TFields extends readonly AnyFieldDefinition[], TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: SingletonConfigWithFieldsets<TFieldsets>): SingletonContentTypeDefinition<readonly [], TFieldsets>;
7464
+ declare function defineSingletonContentType<TFields extends readonly FieldMember[]>(name: string, config: SingletonConfig<TFields>): SingletonContentTypeDefinition<TFields>;
7188
7465
  declare const defineSingleton: typeof defineSingletonContentType;
7189
7466
  /**
7190
7467
  * What a read reports about a singleton beside its fields: the committed document's
@@ -7198,15 +7475,15 @@ type SingletonMetadata = components['schemas']['SingletonMetadata'];
7198
7475
  /**
7199
7476
  * Type alias for any singleton content type definition.
7200
7477
  */
7201
- type AnySingletonContentTypeDefinition = SingletonContentTypeDefinition<any, any>;
7478
+ type AnySingletonContentTypeDefinition = SingletonContentTypeDefinition<any>;
7202
7479
  /**
7203
7480
  * Infer the TypeScript type from a singleton definition: every field typed as a read returns it
7204
7481
  * (`schema/infer-fields.ts`), plus `_metadata`. `S` is the schema, as for `InferContentType`.
7205
7482
  */
7206
- type InferSingletonContentType<T extends AnySingletonContentTypeDefinition, S extends FieldSchemaContext | undefined = undefined> = FieldValues<DeclaredFields<T>, S> & {
7483
+ type InferSingletonContentType<T extends AnySingletonContentTypeDefinition, S extends FieldSchemaContext | undefined = undefined, I extends string = never> = FieldValues<DeclaredFields<T>, S, 'required', I> & {
7207
7484
  _metadata: SingletonMetadata;
7208
7485
  };
7209
- type InferSingleton<T extends AnySingletonContentTypeDefinition, S extends FieldSchemaContext | undefined = undefined> = InferSingletonContentType<T, S>;
7486
+ type InferSingleton<T extends AnySingletonContentTypeDefinition, S extends FieldSchemaContext | undefined = undefined, I extends string = never> = InferSingletonContentType<T, S, I>;
7210
7487
 
7211
7488
  /**
7212
7489
  * Asset type definition matching @relyio/schema AssetTypeSchema
@@ -7366,35 +7643,16 @@ interface AssetTypeBaseConfig {
7366
7643
  file?: FileKindConfig;
7367
7644
  }
7368
7645
  /**
7369
- * Type alias for a fieldset with any fields.
7370
- */
7371
- type AnyFieldset$1 = Fieldset<any>;
7372
- /** Asset type configuration using direct fields. */
7373
- interface AssetTypeConfigWithFields<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> extends AssetTypeBaseConfig {
7374
- /** Direct field definitions - preserves literal types */
7375
- fields: TFields;
7376
- /** Cannot have fieldsets when using fields */
7377
- fieldsets?: never;
7378
- }
7379
- /** Asset type configuration using fieldsets. */
7380
- interface AssetTypeConfigWithFieldsets<TFieldsets extends readonly AnyFieldset$1[] = readonly AnyFieldset$1[]> extends AssetTypeBaseConfig {
7381
- /** Field organization via fieldsets - preserves literal types */
7382
- fieldsets: TFieldsets;
7383
- /** Cannot have direct fields when using fieldsets */
7384
- fields?: never;
7385
- }
7386
- /**
7387
- * Asset type configuration with no metadata fields: the asset is its file. `AssetTypeSchema` makes
7388
- * `fields` and `fieldsets` both optional, so this is an asset type deploy accepts (REL-1454).
7646
+ * Asset type configuration. Metadata fields are optional — an asset type with none is its file
7647
+ * (REL-1454) — and when declared, its `fields` hold fields and fieldsets side by side, as a content
7648
+ * type's do (REL-1794).
7389
7649
  */
7390
- interface AssetTypeConfigWithoutFields extends AssetTypeBaseConfig {
7391
- fields?: never;
7392
- fieldsets?: never;
7650
+ interface AssetTypeConfig<TFields extends readonly FieldMember[] = readonly FieldMember[]> extends AssetTypeBaseConfig {
7651
+ /** Fields and fieldsets, side by side - preserves literal types */
7652
+ fields?: TFields;
7393
7653
  }
7394
- /** Asset type configuration: direct fields, fieldsets, or neither. */
7395
- type AssetTypeConfig<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset$1[] = readonly AnyFieldset$1[]> = AssetTypeConfigWithFields<TFields> | AssetTypeConfigWithFieldsets<TFieldsets> | AssetTypeConfigWithoutFields;
7396
7654
  /** Asset type definition - preserves field types for inference. */
7397
- interface AssetTypeDefinition<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset$1[] = readonly AnyFieldset$1[]> {
7655
+ interface AssetTypeDefinition<TFields extends readonly FieldMember[] = readonly FieldMember[]> {
7398
7656
  readonly _tag: 'assetType';
7399
7657
  readonly name: string;
7400
7658
  readonly displayName: string;
@@ -7408,15 +7666,13 @@ interface AssetTypeDefinition<TFields extends readonly AnyFieldDefinition[] = re
7408
7666
  readonly video?: VideoKindConfig;
7409
7667
  readonly file?: FileKindConfig;
7410
7668
  readonly fields?: TFields;
7411
- readonly fieldsets?: TFieldsets;
7412
7669
  }
7413
7670
  /**
7414
7671
  * Define an asset type.
7415
7672
  *
7416
7673
  * Exactly one kind key (`image`, `video`, or `file`) must be supplied. Metadata
7417
- * fields are optional: declare `fields`, `fieldsets`, or neither. The generic
7418
- * type parameters preserve literal field IDs for inference, mirroring
7419
- * `defineContentType`.
7674
+ * fields are optional. The generic type parameter preserves literal field IDs for
7675
+ * inference, mirroring `defineContentType`.
7420
7676
  *
7421
7677
  * @example
7422
7678
  * const productPhoto = defineAssetType('productPhoto', {
@@ -7430,23 +7686,21 @@ interface AssetTypeDefinition<TFields extends readonly AnyFieldDefinition[] = re
7430
7686
  * ],
7431
7687
  * })
7432
7688
  */
7433
- declare function defineAssetType(name: string, config: AssetTypeConfigWithoutFields): AssetTypeDefinition<readonly [], readonly []>;
7434
- declare function defineAssetType<TFields extends readonly AnyFieldDefinition[], _TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: AssetTypeConfigWithFields<TFields>): AssetTypeDefinition<TFields, readonly []>;
7435
- declare function defineAssetType<_TFields extends readonly AnyFieldDefinition[], TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: AssetTypeConfigWithFieldsets<TFieldsets>): AssetTypeDefinition<readonly [], TFieldsets>;
7689
+ declare function defineAssetType<TFields extends readonly FieldMember[] = readonly []>(name: string, config: AssetTypeConfig<TFields>): AssetTypeDefinition<TFields>;
7436
7690
  /**
7437
7691
  * Type alias for any asset type definition.
7438
7692
  */
7439
- type AnyAssetTypeDefinition = AssetTypeDefinition<any, any>;
7693
+ type AnyAssetTypeDefinition = AssetTypeDefinition<any>;
7440
7694
  /**
7441
7695
  * Infer the TypeScript type from an asset type definition.
7442
7696
  *
7443
- * Mirrors {@link InferContentType}: produces the (optional) metadata field shape
7697
+ * Mirrors {@link InferContentType}: produces the metadata field shape (a required field present)
7444
7698
  * plus `_metadata`, so it is assignable to `BaseContent` and can parametrize
7445
7699
  * `AssetClient<T>`. The runtime `file`/`urls` blocks are layered on by the
7446
7700
  * client's `AssetEntryResponse<T>` return type, not here, to keep the schema
7447
7701
  * layer free of any dependency on the client layer.
7448
7702
  */
7449
- type InferAssetType<T extends AnyAssetTypeDefinition, S extends FieldSchemaContext | undefined = undefined> = FieldValues<DeclaredFields<T>, S> & {
7703
+ type InferAssetType<T extends AnyAssetTypeDefinition, S extends FieldSchemaContext | undefined = undefined, I extends string = never> = FieldValues<DeclaredFields<T>, S, 'required', I> & {
7450
7704
  _metadata: EntryMetadata;
7451
7705
  };
7452
7706
 
@@ -7454,34 +7708,47 @@ type InferAssetType<T extends AnyAssetTypeDefinition, S extends FieldSchemaConte
7454
7708
  * What a read returns for each field, derived from the field's declaration (`INV-SS-TYPES-INFERRED`).
7455
7709
  *
7456
7710
  * Every `Infer*` in this package — content types, singletons, asset types, settings groups — types
7457
- * its fields here and nowhere else, so an entry, a referenced entry, a component and a list item are
7458
- * typed by one table. The types describe **what a read returns**, which is not always what a write
7711
+ * its fields here and nowhere else, so an entry, a referenced entry, an object's value and a list item
7712
+ * are typed by one table. The types describe **what a read returns**, which is not always what a write
7459
7713
  * accepts:
7460
7714
  *
7461
- * - `richText` is the stored HTML string; `date` is `YYYY-MM-DD` and `dateTime` an ISO 8601 string
7715
+ * - `richText` is the version-1 rich-text tree (`RichTextValue`, ADR 0013, REL-1803); a `table` is a
7716
+ * `RichTextTable` and a `code` field a `RichTextCodeGroup` — exactly the value of the same block
7717
+ * inside a tree (REL-1806); `date` is
7718
+ * `YYYY-MM-DD` and `dateTime` an ISO 8601 string
7462
7719
  * in UTC at millisecond precision (`2026-10-01T04:30:00.000Z`), whatever offset it was written in
7463
7720
  * — the client does not revive dates.
7464
- * - A `reference` is the target's id until `include` names it, and then the target entry itself.
7465
- * The type cannot see `include`, so it is both: `string | <entry>`. A single reference whose target
7466
- * was deleted with `onTargetDelete: 'nullify'` is `null`.
7721
+ * - A `reference` is the target's id, and the target entry itself where the read's include paths
7722
+ * expand it (REL-1801, `./include-paths.ts`): a path naming it, crossing it, or stopping at a list
7723
+ * or object that holds it. A path that picks fields (`features(name,slug)`) narrows the entry to
7724
+ * those and its `_metadata`. An include set the type cannot see — a `string[]` — types every
7725
+ * reference as either, `string | <entry>`. An optional single reference whose target was deleted
7726
+ * with its references nullified is `null`; a **required** one is never `null`, because its target
7727
+ * cannot be deleted while it holds it (REL-1795).
7467
7728
  * - A localized field is the value for the one locale the read composed, like any other field; the
7468
7729
  * other locales of a `locales=` read sit under `_metadata.localizations`, not here.
7469
- * - Every field is optional. The wire omits a field with no value — a draft, a `fields` projection, a
7470
- * locale with nothing to fall back to, an entry older than a field — so `required` does not make
7471
- * one present.
7730
+ * - **A required field is always present** (design decision 9, REL-1795); every other field is
7731
+ * optional. A required text, rich text, list or boolean a draft leaves empty is read as its kind's
7732
+ * empty value — `''`, the empty tree, `[]`, `false` — and named in
7733
+ * `_metadata.emptyRequiredFields`; a required number, date, choice, single reference, object,
7734
+ * table or code group has no empty value, so an entry holds it from
7735
+ * the moment it is created. An optional field the entry has no value for is omitted.
7736
+ * - An `object` is one value of its shape — `_type`, `_key` and the shape's fields — and of several,
7737
+ * their union told apart by `_type` (REL-1799). A **required** object is given a shape and that
7738
+ * shape's required values when the entry is created (REL-2034), so even a draft read holds its
7739
+ * `_type` and `_key`.
7472
7740
  */
7473
7741
 
7474
7742
  /**
7475
- * The parts of a schema a field's value type reads: the types a reference may expand to and the
7476
- * components a component field names. Structural, so every `defineSchema()` result fits.
7743
+ * The parts of a schema a field's value type reads: the types a reference may expand to.
7744
+ * Structural, so every `defineSchema()` result fits. A list's or an object's shapes are not here:
7745
+ * a field carries its fieldsets itself.
7477
7746
  *
7478
7747
  * Without one in view — `InferContentType<typeof post>` with no second argument — a reference
7479
- * expands to an {@link UnresolvedEntry} and a component to an {@link UnresolvedComponent}: the field
7480
- * is still typed, but what it names is not.
7748
+ * expands to an {@link UnresolvedEntry}: the field is still typed, but what it names is not.
7481
7749
  */
7482
7750
  interface FieldSchemaContext {
7483
7751
  readonly contentTypes: object;
7484
- readonly components: object;
7485
7752
  readonly singletonContentTypes: object;
7486
7753
  readonly assetTypes?: object;
7487
7754
  }
@@ -7492,21 +7759,20 @@ interface UnresolvedEntry {
7492
7759
  _metadata: EntryMetadata;
7493
7760
  [field: string]: unknown;
7494
7761
  }
7495
- /** A component whose definition is not in view: an object, with fields nothing declared. */
7496
- type UnresolvedComponent = Record<string, unknown>;
7497
7762
  /**
7498
- * One row per field type the schema declares. `OverEveryFieldType` makes the table exhaustive by
7499
- * construction: a field type added to `FieldType` without a row here fails to compile, rather than
7500
- * reading as `unknown`.
7763
+ * One row per field kind the schema declares. `OverEveryFieldKind`, from the field-kind declaration,
7764
+ * makes the table exhaustive by construction: a kind the declaration gains without a row here fails
7765
+ * to compile, rather than reading as `unknown`.
7501
7766
  */
7502
- type OverEveryFieldType<T extends {
7503
- [K in FieldType]: unknown;
7504
- }> = T;
7505
- type FieldValueByType<C, S extends Context> = OverEveryFieldType<{
7767
+ type FieldValueByType<C, S extends Context, K extends string, I extends string, A extends boolean> = OverEveryFieldKind<{
7506
7768
  shortText: string;
7507
7769
  longText: string;
7508
- /** The stored HTML. */
7509
- richText: string;
7770
+ /** The version-1 tree (REL-1803): `{ _type: 'richText', version: 1, children }`. */
7771
+ richText: RichTextValue;
7772
+ /** Exactly a rich-text table block's value (REL-1806). */
7773
+ table: RichTextTable;
7774
+ /** Exactly a rich-text code group's value: code with tabs (REL-1806). */
7775
+ code: RichTextCodeGroup;
7510
7776
  email: string;
7511
7777
  url: string;
7512
7778
  slug: string;
@@ -7518,304 +7784,977 @@ type FieldValueByType<C, S extends Context> = OverEveryFieldType<{
7518
7784
  date: string;
7519
7785
  /** ISO 8601 in UTC at millisecond precision: `2026-10-01T04:30:00.000Z`. */
7520
7786
  dateTime: string;
7521
- reference: ReferenceValue<C, S>;
7787
+ reference: ReferenceValue<C, S, K, I, A>;
7522
7788
  tags: string[];
7523
- list: ListValue<C, S>;
7789
+ list: ListValue<C, S, IncludesUnder<I, K>, CoversBelow<I, K, A>>;
7790
+ object: ObjectValue<C, S, IncludesUnder<I, K>, CoversBelow<I, K, A>>;
7524
7791
  }>;
7525
7792
  /**
7526
- * The value a read returns for field `F`.
7793
+ * The value a read returns for field `F`, under the include paths `I` of the record it sits in —
7794
+ * relative to that record, so `features` inside `sections` — and `A`, whether a path stopping at a
7795
+ * list or object above it expands every reference below (`./include-paths.ts`).
7527
7796
  *
7528
7797
  * The last arm is the one `unknown` in this module, and it is deliberate: a field whose `type` is not
7529
7798
  * a declared literal — a definition built from a plain `string` rather than through `fields.*` — has
7530
7799
  * no row to read.
7531
7800
  */
7532
- type FieldValue<F extends AnyFieldDefinition, S extends Context = undefined> = F['type'] extends `component(${infer Id})` ? ComponentValue<Id, S> : F['type'] extends FieldType ? FieldValueByType<NonNullable<F['config']>, S>[F['type']] : unknown;
7533
- /** The fields `F` (a union of field definitions) as an object, each optional — see the module note. */
7534
- type FieldValues<F extends AnyFieldDefinition, S extends Context = undefined> = {
7535
- [K in F['id']]?: FieldValue<Extract<F, {
7801
+ type FieldValue<F extends AnyFieldDefinition, S extends Context = undefined, I extends string = never, A extends boolean = false> = F['type'] extends FieldType ? FieldValueByType<NonNullable<F['config']>, S, F['id'], I, A>[F['type']] : unknown;
7802
+ /**
7803
+ * `true` when a config declares `required: true` — a builder keeps the literal it was written as —
7804
+ * and `false` for `false`, `boolean`, or no `required` at all.
7805
+ */
7806
+ type RequiredIn<C> = C extends {
7807
+ readonly required?: infer R;
7808
+ } ? [Exclude<R, undefined>] extends [never] ? false : [Exclude<R, undefined>] extends [true] ? true : false : false;
7809
+ /** Whether `F` declares `config.required: true`. */
7810
+ type IsRequired<F extends AnyFieldDefinition> = RequiredIn<NonNullable<F['config']>>;
7811
+ /** The ids of the required fields among `F` — each always present in a read (the module note). */
7812
+ type RequiredIds<F extends AnyFieldDefinition> = F extends AnyFieldDefinition ? IsRequired<F> extends true ? F['id'] : never : never;
7813
+ /** One object type from an intersection, so a read's type prints as one object. */
7814
+ type Flatten<T> = {
7815
+ [K in keyof T]: T[K];
7816
+ } & {};
7817
+ /**
7818
+ * Whether a read holds a record's required fields present: `required` for an entry, a singleton, an
7819
+ * asset and every value nested in one; `none` for a settings group, whose read starts from the
7820
+ * declared and synthesized defaults and leaves a required field with neither absent (the Content
7821
+ * API does not fill a settings group's empty required fields — REL-1795 left settings as they were).
7822
+ */
7823
+ type Presence = 'required' | 'none';
7824
+ /**
7825
+ * The fields `F` (a union of field definitions) as an object: a required field present, every other
7826
+ * one optional — see the module note. With `P` `none`, every field optional.
7827
+ */
7828
+ type FieldValues<F extends AnyFieldDefinition, S extends Context = undefined, P extends Presence = 'required', I extends string = never, A extends boolean = false> = Flatten<{
7829
+ [K in PresentIds<F, P>]: FieldValue<Extract<F, {
7536
7830
  readonly id: K;
7537
- }>, S>;
7538
- };
7831
+ }>, S, I, A>;
7832
+ } & {
7833
+ [K in Exclude<F['id'], PresentIds<F, P>>]?: FieldValue<Extract<F, {
7834
+ readonly id: K;
7835
+ }>, S, I, A>;
7836
+ }>;
7837
+ type PresentIds<F extends AnyFieldDefinition, P extends Presence> = P extends 'required' ? RequiredIds<F> : never;
7838
+ /**
7839
+ * Every field a definition declares, beside its sections or inside one at any depth, as one union —
7840
+ * the one walk over `fields` every `Infer*` shares. A section's fields join the record it sits in
7841
+ * (REL-1794), so a section leaves no key of its own: its fields read flat.
7842
+ */
7843
+ type DeclaredFields<T extends {
7844
+ readonly fields?: unknown;
7845
+ }> = Extract<NonNullable<T['fields']> extends readonly (infer Member)[] ? FieldsOfMember<Member> : never, AnyFieldDefinition>;
7846
+ /** A member's fields: a field is itself; a section is the fields of its own members. */
7847
+ type FieldsOfMember<Member> = Member extends AnyFieldDefinition ? Member : Member extends {
7848
+ readonly fields: readonly (infer Inner)[];
7849
+ } ? FieldsOfMember<Inner> : never;
7850
+ /** `multi` as declared: `true`, `false`, or `boolean` when the declaration does not say. */
7851
+ type Multiplicity<C> = C extends {
7852
+ readonly multi?: infer M;
7853
+ } ? M : false;
7854
+ /** One `V`, a list of them, or — when `multi` is not a literal — either. */
7855
+ type OneOrMany<C, V> = [Multiplicity<C>] extends [true] ? V[] : [Multiplicity<C>] extends [false | undefined] ? V : V | V[];
7856
+ type EnumValue<C> = OneOrMany<C, C extends {
7857
+ readonly options: ReadonlyArray<{
7858
+ readonly value: infer V;
7859
+ }>;
7860
+ } ? V : string>;
7861
+ type ReferenceTarget<C> = C extends {
7862
+ readonly to: infer T;
7863
+ } ? T extends readonly (infer E)[] ? E : T : string;
7864
+ /** `R[K]` where `R` declares `K`. A `Record<string, never>` default declares nothing. */
7865
+ type Declared<R, K> = K extends keyof R ? R[K] : never;
7866
+ 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;
7870
+ /**
7871
+ * What `include` expands a reference to `Target` into: that type's entry, typed by the schema, under
7872
+ * `I`, the include paths that continue past the reference (`customers.logo` → `logo` inside the
7873
+ * customer).
7874
+ */
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;
7876
+ /**
7877
+ * What a single reference reads as once its target is gone: `null` for an optional one, whose
7878
+ * referrers a delete may nullify, and nothing for a required one, whose target cannot be deleted
7879
+ * while it holds it (REL-1795).
7880
+ */
7881
+ type Nullified<C> = RequiredIn<C> extends true ? never : null;
7882
+ /**
7883
+ * A reference field `K` under the include paths `I` of its record (REL-1801): the target's id, or —
7884
+ * where a path expands it — the target's entry, narrowed to the fields a path picked. Under an include
7885
+ * set the type cannot see (`string`), either.
7886
+ */
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>;
7888
+ /** One reference value `V`, as the field holds it: alone, nullable unless required, or a list. */
7889
+ type ReferenceAs<C, V> = [Multiplicity<C>] extends [true] ? V[] : [Multiplicity<C>] extends [false | undefined] ? V | Nullified<C> : V | Nullified<C> | V[];
7890
+ /**
7891
+ * A list of a shape (`of`, REL-1796) is a list of items, each its shape's values — a section's
7892
+ * fields read flat — plus `_type`, the shape's id as a literal, and `_key`, its item key. A list of
7893
+ * several shapes, a page builder (REL-1798), is a list of their union, told apart by `_type`. A list
7894
+ * without one is a list of strings, which is what the validation document enforces for it.
7895
+ */
7896
+ type ListValue<C, S extends Context, I extends string, A extends boolean> = C extends {
7897
+ readonly of?: infer Shape;
7898
+ } ? [ShapesIn<Exclude<Shape, undefined>>] extends [never] ? string[] : Array<ShapeItem<ShapesIn<Exclude<Shape, undefined>>, S, I, A>> : string[];
7899
+ /** The shapes an `of` names: the one fieldset, or each of a list of them. Distributes. */
7900
+ type ShapesIn<Of> = Of extends readonly (infer Shape)[] ? Shape : Of;
7901
+ /**
7902
+ * An object (`of`, REL-1799) is one value of its shape: the shape's values — a section's fields read
7903
+ * flat — plus `_type` and `_key`, as a list item is. Of several shapes, their union, told apart by
7904
+ * `_type`, so `media._type === 'video'` narrows it. `of` is required, so an object always has one.
7905
+ */
7906
+ type ObjectValue<C, S extends Context, I extends string, A extends boolean> = C extends {
7907
+ readonly of: infer Shape;
7908
+ } ? ShapeItem<ShapesIn<Shape>, S, I, A> : never;
7909
+ /**
7910
+ * What every structured item carries (design decision 6): `_type`, the fieldset it takes, and
7911
+ * `_key`, its identity in its list for life. A list of shapes reads as an array of these.
7912
+ */
7913
+ interface Keyed {
7914
+ readonly _type: string;
7915
+ readonly _key: string;
7916
+ }
7917
+ /**
7918
+ * One block of a page builder (REL-1798): the item of `List` — a list field's value as a read types
7919
+ * it, optional or not — whose `_type` is `Type`. What a site's component for that block receives:
7920
+ * `BlockOf<Page['sections'], 'hero'>`. An object's value (REL-1799) is one such item rather than a
7921
+ * list of them, so `BlockOf<Hero['media'], 'video'>` is the arm of the value whose `_type` is `video`.
7922
+ */
7923
+ type BlockOf<List, Type extends string> = Extract<NonNullable<List> extends ReadonlyArray<infer Item> ? Item : NonNullable<List>, {
7924
+ readonly _type: Type;
7925
+ }>;
7926
+ /**
7927
+ * One item of a shape: `_type` and `_key` beside its values, under the include paths `I` that reach
7928
+ * into the list or object (a path names fields, never shapes, so every shape reads the same `I`).
7929
+ * Distributes over a union of shapes.
7930
+ */
7931
+ type ShapeItem<Shape, S extends Context, I extends string = never, A extends boolean = false> = Shape extends {
7932
+ readonly id: infer Id;
7933
+ readonly fields: readonly unknown[];
7934
+ } ? Flatten<{
7935
+ readonly _type: Id;
7936
+ readonly _key: string;
7937
+ } & FieldValues<DeclaredFields<Shape>, S, 'required', I, A>> : never;
7938
+ /**
7939
+ * The value a fieldset holds wherever it is a shape — an object's value, or one item of a list —
7940
+ * typed by schema `S`: `_type`, `_key` and its fields. `relyio generate-types` writes one alias per
7941
+ * fieldset id with it (`export type HeroFieldset = ShapeValue<typeof heroFieldset, SchemaTypes>`),
7942
+ * so a site names a shape's value without reaching through the field that holds it.
7943
+ */
7944
+ type ShapeValue<Shape extends AnyFieldset, S extends Context = undefined> = ShapeItem<Shape, S>;
7945
+
7946
+ /**
7947
+ * Content type definition matching @relyio/schema ContentTypeSchema
7948
+ *
7949
+ * Uses advanced TypeScript generics to preserve each field's declaration through the type system,
7950
+ * so `InferContentType` types every field by what a read returns and `where()` autocompletes.
7951
+ */
7952
+
7953
+ /**
7954
+ * A fieldset: a named group of fields and fieldsets. Where it is placed decides what it is (ADR
7955
+ * 0012). Among a type's (or another fieldset's) `fields` it is a **section** of the form, and its
7956
+ * fields join the record it sits in: a read returns them beside the type's other fields, so
7957
+ * grouping the form never changes a read (REL-1794).
7958
+ *
7959
+ * A fieldset id names one shape across the whole schema. Reuse one by passing the same value
7960
+ * wherever it is wanted; deploy refuses two different fieldsets under one id.
7961
+ */
7962
+ interface Fieldset<TMembers extends readonly FieldMember[] = readonly FieldMember[], TId extends string = string> {
7963
+ /** The fieldset's id — one shape across the schema, and what each item of a list of it names in `_type` */
7964
+ readonly id: TId;
7965
+ /** Display name shown in the UI */
7966
+ readonly displayName: string;
7967
+ /** Optional description */
7968
+ readonly description?: string;
7969
+ /** Whether an editing surface shows this section collapsed to begin with */
7970
+ readonly collapsedByDefault?: boolean;
7971
+ /** AI configuration for content generation and review */
7972
+ readonly ai?: AIConfig;
7973
+ /** Fields and fieldsets, in the order the form shows them - preserves literal types */
7974
+ readonly fields: TMembers;
7975
+ }
7976
+ /**
7977
+ * Type alias for a fieldset with any members.
7978
+ * Used in generic constraints where we need to accept any fieldset type.
7979
+ */
7980
+ type AnyFieldset = Fieldset<any>;
7981
+ /** One entry of a `fields` list: a field, or a fieldset placed there as a section. */
7982
+ type FieldMember = AnyFieldDefinition | AnyFieldset;
7983
+ /**
7984
+ * Create a fieldset. Place it among a type's fields to make a section of the form, or pass it as a
7985
+ * list's `of` to make it the shape each item takes (REL-1796). Generic to preserve its id and the
7986
+ * specific field types for type inference: a list item's `_type` is this id.
7987
+ *
7988
+ * @example
7989
+ * export const seo = fieldset('seo', {
7990
+ * displayName: 'SEO Settings',
7991
+ * fields: [
7992
+ * fields.shortText('metaTitle', { config: { maxLength: 60 } }),
7993
+ * fields.longText('metaDescription', { config: { maxLength: 160 } }),
7994
+ * ]
7995
+ * })
7996
+ */
7997
+ declare function fieldset<TId extends string, TMembers extends readonly FieldMember[]>(id: TId, config: {
7998
+ displayName: string;
7999
+ description?: string;
8000
+ /** Show the section collapsed until an editor opens it */
8001
+ collapsedByDefault?: boolean;
8002
+ ai?: AIConfig;
8003
+ fields: TMembers;
8004
+ }): Fieldset<TMembers, TId>;
8005
+ /**
8006
+ * Content type configuration. Its `fields` hold fields and fieldsets side by side, in the order the
8007
+ * form shows them (REL-1794). Generic to preserve literal field IDs for type inference.
8008
+ */
8009
+ interface ContentTypeConfig<TFields extends readonly FieldMember[] = readonly FieldMember[]> {
8010
+ /** Display name shown in the UI */
8011
+ displayName: string;
8012
+ /** Plural display name shown in the UI (e.g., "Products" for "Product") */
8013
+ displayNamePlural?: string;
8014
+ /** Description of the content type */
8015
+ description?: string;
8016
+ /** AI configuration: generation/review guidance */
8017
+ ai?: AIConfig;
8018
+ /**
8019
+ * Field ID to use as entry display title in lists, references, and editor header.
8020
+ * If not set, falls back to: title → name → slug → first shortText field → entryUid
8021
+ */
8022
+ displayField?: string;
8023
+ /** Whether this content type supports hierarchical (parent-child) relationships */
8024
+ hierarchical?: boolean;
8025
+ /** Access tags for role-based access control */
8026
+ accessTags?: string[];
8027
+ /** Workflow configuration for this content type */
8028
+ workflow?: ContentTypeWorkflowConfig;
8029
+ /** Fields and fieldsets, side by side - preserves literal types */
8030
+ fields: TFields;
8031
+ }
7539
8032
  /**
7540
- * Every field a definition declares, directly or through its fieldsets, as one union — the one walk
7541
- * over `fields` / `fieldsets` every `Infer*` shares.
8033
+ * Content type definition - preserves field types for inference
8034
+ */
8035
+ interface ContentTypeDefinition<TFields extends readonly FieldMember[] = readonly FieldMember[]> {
8036
+ readonly _tag: 'contentType';
8037
+ readonly name: string;
8038
+ readonly displayName: string;
8039
+ readonly displayNamePlural?: string;
8040
+ readonly description?: string;
8041
+ /** AI configuration: generation/review guidance */
8042
+ readonly ai?: AIConfig;
8043
+ /** Field ID to use as entry display title */
8044
+ readonly displayField?: string;
8045
+ readonly hierarchical?: boolean;
8046
+ readonly accessTags?: string[];
8047
+ readonly workflow?: ContentTypeWorkflowConfig;
8048
+ readonly fields: TFields;
8049
+ }
8050
+ /**
8051
+ * Define a content type with type-safe fields
8052
+ *
8053
+ * The generic type parameters preserve the literal field IDs through the type
8054
+ * system, enabling autocomplete in SDK methods like where(), select(), etc.
8055
+ *
8056
+ * @example
8057
+ * // Fields, and a fieldset placed among them as a section of the form
8058
+ * const product = defineContentType('product', {
8059
+ * displayName: 'Product',
8060
+ * fields: [
8061
+ * fields.shortText('title', { config: { required: true } }),
8062
+ * fieldset('pricing', {
8063
+ * displayName: 'Pricing',
8064
+ * fields: [
8065
+ * fields.decimal('price', { config: { min: 0, decimalPlaces: 2 } }),
8066
+ * ]
8067
+ * }),
8068
+ * fields.richText('description'),
8069
+ * ]
8070
+ * })
8071
+ * // A read returns { title, price, description }: a section's fields are the entry's own
8072
+ */
8073
+ declare function defineContentType<TFields extends readonly FieldMember[]>(name: string, config: ContentTypeConfig<TFields>): ContentTypeDefinition<TFields>;
8074
+ /**
8075
+ * Type alias for any content type definition.
8076
+ */
8077
+ type AnyContentTypeDefinition = ContentTypeDefinition<any>;
8078
+ /**
8079
+ * What a read reports about an entry beside its fields: the committed document's `EntryMetadata`
8080
+ * (`apps/services/api/openapi-spec.json`), read through `http/api-schema.ts`, its one derivation in
8081
+ * this package — not declared a second time here.
8082
+ *
8083
+ * It used to be written out by hand, and the copy had drifted from the wire: it declared a
8084
+ * `parentId` no read sends, typed `createdAt` and `updatedAt` as `Date` where the wire sends ISO 8601
8085
+ * strings, and left out what a reader most needs — `availableLocales`, `defaultLocale`, `slug`,
8086
+ * `refs` — so the preview toolbar took them through a structural type of its own. A field the
8087
+ * service adds or changes now reaches this type when `api-schema.ts` is regenerated, and
8088
+ * `__tests__/read-metadata.types.ts` fails `type:check` if a read stops declaring it.
8089
+ *
8090
+ * Every entry-shaped value carries it — a single read, each item of a list or of `children()`, and
8091
+ * an entry an `include` expanded — because the service builds each of them with one transform.
8092
+ * `versionCount` and `versions` are sent on a single read only, so they are optional.
8093
+ */
8094
+ type EntryMetadata = components['schemas']['EntryMetadata'];
8095
+ /**
8096
+ * The per-locale publication facts every one-document read reports, an entry's, a singleton's and a
8097
+ * settings group's alike (`INV-LM-PUBLICATION-IS-REPORTED-PER-LOCALE`): a `Pick` of the document's
8098
+ * {@link EntryMetadata}, so this package holds no copy of them. `localeStatus` is absent when the
8099
+ * locale has no content of its own.
8100
+ *
8101
+ * Unpublished work comes in two kinds, reported apart: `draftLocales` names the locales with edits
8102
+ * of their own, and `hasDraft` is a change to the shared (non-localized) fields. Publishing any
8103
+ * locale makes a shared change live, so it is pending in every locale and no locale code is listed
8104
+ * for it. A locale has unpublished work when `draftLocales` names it or `hasDraft` is `true`.
8105
+ */
8106
+ type LocalePublicationFields = Pick<EntryMetadata, 'localeStatus' | 'localeHasDraft' | 'draftLocales' | 'hasDraft'>;
8107
+ /**
8108
+ * Infer the TypeScript type of an entry from a content type definition: every field it declares,
8109
+ * beside its sections or inside one — a section's fields read flat — typed as a read returns it (`INV-SS-TYPES-INFERRED`), plus
8110
+ * `_metadata`. A required field is always present and every other one optional —
8111
+ * `schema/infer-fields.ts` says why, and what each field type reads as.
8112
+ *
8113
+ * `S` is the schema the type belongs to. With it, a reference expanded by `include` is typed as the
8114
+ * entry it points at; without it, as an entry whose fields are not known. A client typed by a schema
8115
+ * passes it.
8116
+ *
8117
+ * @example
8118
+ * const product = defineContentType('product', {
8119
+ * displayName: 'Product',
8120
+ * fields: [
8121
+ * fields.shortText('title', { config: { required: true } }),
8122
+ * fields.decimal('price'),
8123
+ * fields.enum('status', {
8124
+ * config: {
8125
+ * options: [
8126
+ * { value: 'draft', label: 'Draft' },
8127
+ * { value: 'live', label: 'Live' },
8128
+ * ],
8129
+ * },
8130
+ * }),
8131
+ * ]
8132
+ * })
8133
+ *
8134
+ * type Product = InferContentType<typeof product>
8135
+ * // { title: string; price?: number; status?: 'draft' | 'live'; _metadata: EntryMetadata }
8136
+ */
8137
+ type InferContentType<T extends AnyContentTypeDefinition, S extends FieldSchemaContext | undefined = undefined, I extends string = never> = FieldValues<DeclaredFields<T>, S, 'required', I> & {
8138
+ _metadata: EntryMetadata;
8139
+ };
8140
+
8141
+ /**
8142
+ * Field type definitions matching @relyio/schema package
8143
+ *
8144
+ * Every config option here is spelled as `@relyio/schema`'s field config schema spells it, because
8145
+ * the CLI sends a field's `config` to deploy verbatim, and deploy — and `relyio validate` before it —
8146
+ * refuses an option the field's type does not declare, naming its path (REL-1480). This package has
8147
+ * no runtime dependency on `@relyio/schema`, so the
8148
+ * options are pinned from `@relyio/codegen-typescript`, which depends on both: its
8149
+ * `src/__tests__/sdk-field-config.types.ts` fails to compile when a key, whether it is required, or
8150
+ * the values it accepts differs between the two (REL-1408).
8151
+ *
8152
+ * The field kinds themselves are not restated: {@link FieldType} is the declaration's union, taken
8153
+ * as a type (REL-1786). The import is erased from the JavaScript, and `dts.resolve` in
8154
+ * `tsup.config.ts` rolls the union into the published `.d.ts`, as it does `@relyio/api-contract`'s
8155
+ * types, so a customer installs nothing more for it. `@relyio/schema` is a devDependency for that
8156
+ * reason: a build-time input, like the contract.
8157
+ */
8158
+
8159
+ /**
8160
+ * AI configuration. A single prompt — `instructions` — describes what the
8161
+ * element is and how AI should produce its value. Attaches to fields, content
8162
+ * types, fieldsets, and (extended) asset types.
8163
+ *
8164
+ * @example
8165
+ * ```typescript
8166
+ * fields.richText('body', {
8167
+ * ai: {
8168
+ * instructions: `
8169
+ * Write in a conversational tone.
8170
+ * Use short paragraphs (2-3 sentences).
8171
+ * Target grade 8 reading level.
8172
+ * `
8173
+ * }
8174
+ * })
8175
+ * ```
8176
+ */
8177
+ interface AIConfig {
8178
+ /**
8179
+ * AI brief for this element: what it should contain and how to produce it.
8180
+ *
8181
+ * Used by the Studio authoring agent and — on asset types with
8182
+ * `ai.autoGenerate` — by the automatic post-upload run.
8183
+ *
8184
+ * The fallback chain for AI guidance is:
8185
+ * 1. ai.instructions (most specific)
8186
+ * 2. ui.description (general field description)
8187
+ * 3. Field displayName + type (inferred from semantics)
8188
+ */
8189
+ instructions?: string;
8190
+ }
8191
+ /**
8192
+ * Field-level AI config. `inputs` names the fields this instruction reads.
8193
+ * Unknown ids and cycles are refused when the schema is parsed.
8194
+ */
8195
+ interface FieldAIConfig extends AIConfig {
8196
+ /** Field ids this instruction reads. Never inferred from instruction text. */
8197
+ inputs?: string[];
8198
+ }
8199
+ /**
8200
+ * Asset-type AI configuration. Extends {@link AIConfig} with `autoGenerate`,
8201
+ * the single switch that turns on automatic field generation after upload.
8202
+ */
8203
+ interface AssetAIConfig extends AIConfig {
8204
+ /**
8205
+ * Master switch for automatic, post-upload field generation. When `true`, the
8206
+ * derived analysis agent fills every field that declares `ai.instructions`,
8207
+ * applied as a review proposal. Only meaningful for image asset types in v1.
8208
+ */
8209
+ autoGenerate?: boolean;
8210
+ }
8211
+ interface BaseFieldConfig {
8212
+ /** Whether the field is required */
8213
+ required?: boolean;
8214
+ /** Whether the field value must be unique */
8215
+ unique?: boolean;
8216
+ /** Default value for the field. Each field type narrows it to the values its schema accepts. */
8217
+ defaultValue?: unknown;
8218
+ }
8219
+ interface FieldUIConfig {
8220
+ /** Display name shown in the UI */
8221
+ displayName: string;
8222
+ /** Field description/help text */
8223
+ description?: string;
8224
+ /** Widget-specific options */
8225
+ options?: Record<string, unknown>;
8226
+ }
8227
+ interface RuleCondition {
8228
+ field: string;
8229
+ operator: 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'greater_than' | 'less_than' | 'is_empty' | 'is_not_empty';
8230
+ value?: unknown;
8231
+ }
8232
+ interface RuleConditions {
8233
+ mode: 'all' | 'any' | 'none';
8234
+ conditions: RuleCondition[];
8235
+ }
8236
+ interface VisibilityRule {
8237
+ type: 'visibility';
8238
+ action: 'show' | 'hide';
8239
+ conditions: RuleConditions;
8240
+ }
8241
+ interface RequirementRule {
8242
+ type: 'requirement';
8243
+ action: 'require' | 'optional';
8244
+ conditions: RuleConditions;
8245
+ }
8246
+ interface ValidationRule {
8247
+ type: 'validation';
8248
+ action: 'validate' | 'skip';
8249
+ message?: string;
8250
+ conditions: RuleConditions;
8251
+ }
8252
+ interface ReadOnlyRule {
8253
+ type: 'readOnly';
8254
+ action: 'enable' | 'disable';
8255
+ conditions: RuleConditions;
8256
+ }
8257
+ type FieldRule = VisibilityRule | RequirementRule | ValidationRule | ReadOnlyRule;
8258
+ type LocalizationConfig = boolean | string[] | {
8259
+ enabled: boolean;
8260
+ requiredLocales?: string[];
8261
+ fallback?: boolean;
8262
+ };
8263
+ interface FieldDefinition<TId extends string = string, TType extends string = string, TConfig = unknown> {
8264
+ /** Unique field identifier - preserves literal type for type inference */
8265
+ readonly id: TId;
8266
+ /** Field type */
8267
+ readonly type: TType;
8268
+ /** Type-specific configuration */
8269
+ config?: TConfig;
8270
+ /** UI display configuration */
8271
+ ui?: FieldUIConfig;
8272
+ /** AI configuration: generation/review guidance for this field */
8273
+ ai?: FieldAIConfig;
8274
+ /** Dynamic field rules */
8275
+ rules?: FieldRule[];
8276
+ /** Localization settings */
8277
+ localization?: LocalizationConfig;
8278
+ /** Fallback value when field is empty */
8279
+ fallback?: unknown;
8280
+ /** Whether this field is deprecated */
8281
+ deprecated?: boolean;
8282
+ }
8283
+ /**
8284
+ * Any field definition - used in arrays where we need to preserve specific field types
8285
+ */
8286
+ type AnyFieldDefinition = FieldDefinition<string, string, unknown>;
8287
+ interface ShortTextConfig extends BaseFieldConfig {
8288
+ /** Maximum character length */
8289
+ maxLength?: number;
8290
+ /** Regex pattern for validation */
8291
+ pattern?: string;
8292
+ defaultValue?: string;
8293
+ }
8294
+ interface LongTextConfig extends BaseFieldConfig {
8295
+ minLength?: number;
8296
+ maxLength?: number;
8297
+ defaultValue?: string;
8298
+ }
8299
+ /**
8300
+ * A rich-text field's config. With none of `structure`, `marks` and `multiline` the field has the
8301
+ * 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.
8304
+ */
8305
+ interface RichTextConfig extends BaseFieldConfig {
8306
+ /** Maximum count of the value's text characters, its markup not counted (default 50,000) */
8307
+ maxLength?: number;
8308
+ /**
8309
+ * The built-in blocks the field allows besides paragraphs. Absent allows them all; `[]` allows
8310
+ * paragraphs only.
8311
+ */
8312
+ structure?: readonly RichTextStructure[];
8313
+ /** The marks the field allows. Absent allows them all; `[]` allows none. */
8314
+ marks?: readonly RichTextMarkType[];
8315
+ /** `false` makes a one-line field: one paragraph, no line break, no other block. Default `true`. */
8316
+ 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;
8323
+ /** A version-1 rich-text tree, every node but a text run keyed (REL-1803) */
8324
+ defaultValue?: RichTextValue;
8325
+ }
8326
+ /**
8327
+ * A `table` field's config (REL-1806). Its value is exactly a rich-text table block's
8328
+ * (`RichTextTable`): rows of cells, each cell formatted text, an optional header row and per-cell
8329
+ * alignment — the same value a table inside rich text holds, so one copied from either is accepted
8330
+ * by the other.
8331
+ */
8332
+ interface TableConfig extends BaseFieldConfig {
8333
+ /** A table, every node but a text run keyed */
8334
+ defaultValue?: RichTextTable;
8335
+ }
8336
+ /**
8337
+ * A `code` field's config (REL-1806). Its value is exactly a rich-text code group's
8338
+ * (`RichTextCodeGroup`): one tab or more, each a code block with its text and an optional label,
8339
+ * language, filename and line range.
8340
+ */
8341
+ interface CodeConfig extends BaseFieldConfig {
8342
+ /** The languages a tab may be written in; set, every tab names one of them */
8343
+ languages?: readonly string[];
8344
+ /** The most tabs the group may hold */
8345
+ maxTabs?: number;
8346
+ /** A code group, every node keyed, held to `languages` and `maxTabs` */
8347
+ defaultValue?: RichTextCodeGroup;
8348
+ }
8349
+ interface SlugConfig extends BaseFieldConfig {
8350
+ /** Source field to generate slug from */
8351
+ sourceField?: string;
8352
+ /** Maximum character length */
8353
+ maxLength?: number;
8354
+ defaultValue?: string;
8355
+ }
8356
+ /**
8357
+ * A url field's value is an absolute URL (`https://relyio.com/docs`) or a site-relative path
8358
+ * (`/sign-up`) — every url field takes both. A bare word, a path with no leading slash and a
8359
+ * protocol-relative `//host` are refused `URL_INVALID`.
8360
+ */
8361
+ interface UrlConfig extends BaseFieldConfig {
8362
+ /** The protocols an absolute URL may use; a site-relative path is accepted whatever they are. */
8363
+ allowedProtocols?: ('http' | 'https' | 'ftp' | 'ftps')[];
8364
+ /** Maximum character length */
8365
+ maxLength?: number;
8366
+ defaultValue?: string;
8367
+ }
8368
+ interface EmailConfig extends BaseFieldConfig {
8369
+ /** Maximum character length */
8370
+ maxLength?: number;
8371
+ /** Whitelist of allowed email domains */
8372
+ domainWhitelist?: string[];
8373
+ defaultValue?: string;
8374
+ }
8375
+ interface IntegerConfig extends BaseFieldConfig {
8376
+ min?: number;
8377
+ max?: number;
8378
+ defaultValue?: number;
8379
+ }
8380
+ interface DecimalConfig extends BaseFieldConfig {
8381
+ min?: number;
8382
+ max?: number;
8383
+ decimalPlaces?: number;
8384
+ roundingMode?: 'HALF_UP' | 'FLOOR' | 'CEILING' | 'ROUND' | 'TRUNCATE';
8385
+ defaultValue?: number;
8386
+ }
8387
+ interface BooleanConfig extends BaseFieldConfig {
8388
+ /** The editor's word for `true` (e.g. `'Published'`). */
8389
+ labelTrue?: string;
8390
+ /** The editor's word for `false` (e.g. `'Draft'`). */
8391
+ labelFalse?: string;
8392
+ defaultValue?: boolean;
8393
+ }
8394
+ /**
8395
+ * `TValue` is the union of the option values and `TMulti` whether the field holds a list of them.
8396
+ * `fields.enum()` infers both from the declaration, so a read of the field is typed by its options
8397
+ * (`INV-SS-TYPES-INFERRED`); the defaults describe any enum field.
7542
8398
  */
7543
- type DeclaredFields<T extends {
7544
- readonly fields?: unknown;
7545
- readonly fieldsets?: unknown;
7546
- }> = Extract<(NonNullable<T['fields']> extends readonly (infer F)[] ? F : never) | (NonNullable<T['fieldsets']> extends readonly (infer FS)[] ? FS extends {
7547
- readonly fields: readonly (infer F)[];
7548
- } ? F : never : never), AnyFieldDefinition>;
7549
- /** `multi` as declared: `true`, `false`, or `boolean` when the declaration does not say. */
7550
- type Multiplicity<C> = C extends {
7551
- readonly multi?: infer M;
7552
- } ? M : false;
7553
- /** One `V`, a list of them, or — when `multi` is not a literal — either. */
7554
- type OneOrMany<C, V> = [Multiplicity<C>] extends [true] ? V[] : [Multiplicity<C>] extends [false | undefined] ? V : V | V[];
7555
- type EnumValue<C> = OneOrMany<C, C extends {
7556
- readonly options: ReadonlyArray<{
7557
- readonly value: infer V;
8399
+ interface EnumConfig<TValue extends string = string, TMulti extends boolean = boolean> extends BaseFieldConfig {
8400
+ /** The values the field may hold, each with the `label` an editor shows. Deploy refuses an option without one. */
8401
+ options: Array<{
8402
+ value: TValue;
8403
+ label: string;
7558
8404
  }>;
7559
- } ? V : string>;
7560
- type ReferenceTarget<C> = C extends {
7561
- readonly to: infer T;
7562
- } ? T extends readonly (infer E)[] ? E : T : string;
7563
- /** `R[K]` where `R` declares `K`. A `Record<string, never>` default declares nothing. */
7564
- type Declared<R, K> = K extends keyof R ? R[K] : never;
7565
- type ContentEntryOf<D, S extends Context> = D extends ContentTypeDefinition ? InferContentType<D, S> : never;
7566
- type SingletonEntryOf<D, S extends Context> = D extends SingletonContentTypeDefinition ? InferSingletonContentType<D, S> : never;
7567
- type AssetEntryOf<D, S extends Context> = D extends AssetTypeDefinition ? InferAssetType<D, S> : never;
7568
- type OrUnresolved<T> = [T] extends [never] ? UnresolvedEntry : T;
7569
- /** What `include` expands a reference to `Target` into: that type's entry, typed by the schema. */
7570
- type ExpandedEntry<Target, S extends Context> = S extends FieldSchemaContext ? OrUnresolved<ContentEntryOf<Declared<S['contentTypes'], Target>, S> | SingletonEntryOf<Declared<S['singletonContentTypes'], Target>, S> | AssetEntryOf<Declared<NonNullable<S['assetTypes']>, Target>, S>> : UnresolvedEntry;
7571
- type ReferenceValue<C, S extends Context> = [Multiplicity<C>] extends [true] ? Array<string | ExpandedEntry<ReferenceTarget<C>, S>> : [Multiplicity<C>] extends [false | undefined] ? string | null | ExpandedEntry<ReferenceTarget<C>, S> : string | null | Array<string | ExpandedEntry<ReferenceTarget<C>, S>> | ExpandedEntry<ReferenceTarget<C>, S>;
7572
- type ComponentFields<D, S extends Context> = [D] extends [never] ? UnresolvedComponent : D extends {
7573
- readonly fields: readonly (infer F)[];
7574
- } ? FieldValues<Extract<F, AnyFieldDefinition>, S> : UnresolvedComponent;
7575
- type ComponentValue<Id extends string, S extends Context> = S extends FieldSchemaContext ? ComponentFields<Declared<S['components'], Id>, S> : UnresolvedComponent;
8405
+ multi?: TMulti;
8406
+ /** One option's value, or a list of them when `multi` is true. */
8407
+ defaultValue?: string | string[];
8408
+ }
8409
+ /** A display format is not config: it is `ui.options.format`, where the schema declares it. */
8410
+ interface DateConfig extends BaseFieldConfig {
8411
+ minDate?: string;
8412
+ maxDate?: string;
8413
+ /** `YYYY-MM-DD` */
8414
+ defaultValue?: string;
8415
+ }
8416
+ /** A display format is not config: it is `ui.options.format`, where the schema declares it. */
8417
+ interface DateTimeConfig extends BaseFieldConfig {
8418
+ minDateTime?: string;
8419
+ maxDateTime?: string;
8420
+ /**
8421
+ * Show the instant in UTC (`'UTC'`) or in the author's local time (`'local'`) in the editor. The
8422
+ * instant is stored in UTC either way.
8423
+ */
8424
+ timeZoneHandling?: 'UTC' | 'local';
8425
+ defaultValue?: string;
8426
+ }
7576
8427
  /**
7577
- * A list with subfields is a list of objects typed by them; a list without is a list of strings,
7578
- * which is what the validation document enforces for it.
8428
+ * `TTo` is the union of the target type ids and `TMulti` whether the field holds a list.
8429
+ * `fields.reference()` infers both, so a read of the field is typed by what it points at
8430
+ * (`INV-SS-TYPES-INFERRED`); the defaults describe any reference field.
7579
8431
  */
7580
- type ListValue<C, S extends Context> = C extends {
7581
- readonly subfields?: infer Sub;
7582
- } ? Sub extends readonly (infer F)[] ? [F] extends [never] ? string[] : Array<FieldValues<Extract<F, AnyFieldDefinition>, S>> : string[] : string[];
7583
-
8432
+ interface ReferenceConfig<TTo extends string = string, TMulti extends boolean = boolean> extends BaseFieldConfig {
8433
+ /**
8434
+ * Target entry type id(s) — content type or asset type ids. Pass a single id
8435
+ * for one target or an array for several. All ids must belong to the same
8436
+ * family (all content types or all asset types).
8437
+ */
8438
+ to: TTo | TTo[];
8439
+ /** Allow multiple references (the field value is a list). */
8440
+ multi?: TMulti;
8441
+ /**
8442
+ * The fewest and the most entries a multi reference holds, as a list's: your limit, enforced on
8443
+ * every write and publish (`LIST_TOO_FEW_ITEMS`, `LIST_TOO_MANY_ITEMS`). A single reference
8444
+ * takes neither.
8445
+ */
8446
+ minItems?: number;
8447
+ maxItems?: number;
8448
+ /** Reference strength for publish/unpublish behavior. */
8449
+ referenceStrength?: 'strong' | 'weak';
8450
+ /** Behavior when a referenced entry is deleted. */
8451
+ onTargetDelete?: 'block' | 'nullify';
8452
+ /** A target entry's id, or a list of them when `multi` is true. */
8453
+ defaultValue?: string | string[];
8454
+ }
8455
+ interface TagsConfig extends BaseFieldConfig {
8456
+ allowCustom?: boolean;
8457
+ predefinedTags?: string[];
8458
+ maxTags?: number;
8459
+ }
7584
8460
  /**
7585
- * Content type definition matching @relyio/schema ContentTypeSchema
7586
- *
7587
- * Uses advanced TypeScript generics to preserve each field's declaration through the type system,
7588
- * so `InferContentType` types every field by what a read returns and `where()` autocompletes.
8461
+ * `TShape` is the fieldset each item takes — or the union of the several a page builder's items
8462
+ * may take — which `fields.list()` infers so a read types each item by it (`INV-SS-TYPES-INFERRED`);
8463
+ * the default describes any list field. A list without one holds strings.
7589
8464
  */
7590
-
8465
+ interface ListConfig<TShape extends AnyFieldset = AnyFieldset> extends BaseFieldConfig {
8466
+ dragAndDrop?: boolean;
8467
+ minItems?: number;
8468
+ maxItems?: number;
8469
+ /**
8470
+ * The fieldset each item takes (REL-1796): every item holds its fields — a section's read flat —
8471
+ * plus `_type`, the fieldset's id, and `_key`, the item key that stays with it for life. Or
8472
+ * several, a page builder (REL-1798): `of: [hero, featureGrid, ctaBanner]`, each item naming in
8473
+ * `_type` the one it takes, in whatever order an editor puts them.
8474
+ */
8475
+ of?: TShape | readonly TShape[];
8476
+ }
7591
8477
  /**
7592
- * Fieldset for organizing related fields
7593
- * Generic over fields to preserve literal field IDs
8478
+ * `TShape` is the fieldset an object's one value takes — or the union of the several it may take —
8479
+ * which `fields.object()` infers so a read types the value by it (`INV-SS-TYPES-INFERRED`). Unlike a
8480
+ * list's, `of` is required: an object without a shape holds nothing it could declare.
7594
8481
  */
7595
- interface Fieldset<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
7596
- /** Unique fieldset identifier */
7597
- readonly id: string;
7598
- /** Display name shown in the UI */
7599
- readonly displayName: string;
7600
- /** Optional description */
7601
- readonly description?: string;
7602
- /** Whether an editing surface shows this fieldset collapsed to begin with */
7603
- readonly collapsedByDefault?: boolean;
7604
- /** AI configuration for content generation and review */
7605
- readonly ai?: AIConfig;
7606
- /** Fields within this fieldset - preserves literal types */
7607
- readonly fields: TFields;
8482
+ interface ObjectConfig<TShape extends AnyFieldset = AnyFieldset> extends BaseFieldConfig {
8483
+ /**
8484
+ * The fieldset the value takes (REL-1799, ADR 0012): it holds that fieldset's fields — a section's
8485
+ * read flat — plus `_type`, the fieldset's id, and `_key`, its key. Or several: `of: [screenshot,
8486
+ * video]`, the value naming in `_type` the one it takes. `_type` names the fieldset even where
8487
+ * only one is allowed, so a second shape later changes no stored value.
8488
+ */
8489
+ of: TShape | readonly TShape[];
7608
8490
  }
7609
8491
  /**
7610
- * Type alias for a fieldset with any fields.
7611
- * Used in generic constraints where we need to accept any fieldset type.
8492
+ * Every field kind: the one union, `FieldKind` in `@relyio/schema`'s field-kind declaration
8493
+ * (REL-1783). A kind the declaration gains is a kind here, and every table this package keys by it
8494
+ * stops compiling until it has a row: the read types (`OverEveryFieldKind` in `infer-fields.ts`) and
8495
+ * the builders (`fields` in `schema/index.ts`).
7612
8496
  */
7613
- type AnyFieldset = Fieldset<any>;
8497
+ type FieldType = FieldKind;
8498
+
7614
8499
  /**
7615
- * Create a fieldset for organizing fields
7616
- * Generic to preserve the specific field types for type inference
8500
+ * Settings group definition matching @relyio/schema SettingsGroupSchema
7617
8501
  *
7618
- * @example
7619
- * const seoFieldset = fieldset('seo', {
7620
- * displayName: 'SEO Settings',
7621
- * fields: [
7622
- * fields.shortText('metaTitle', { config: { maxLength: 60 } }),
7623
- * fields.longText('metaDescription', { config: { maxLength: 160 } }),
7624
- * ]
7625
- * })
8502
+ * Settings groups are for project-level configuration that doesn't fit
8503
+ * into content types (e.g., API keys, feature flags, integrations).
8504
+ *
8505
+ * Uses advanced TypeScript generics to preserve literal field IDs through
8506
+ * the type system, enabling full autocomplete in SDK methods.
7626
8507
  */
7627
- declare function fieldset<TFields extends readonly AnyFieldDefinition[]>(id: string, config: {
7628
- displayName: string;
7629
- description?: string;
7630
- /** Show the fieldset collapsed until an editor opens it */
7631
- collapsedByDefault?: boolean;
7632
- ai?: AIConfig;
7633
- fields: TFields;
7634
- }): Fieldset<TFields>;
8508
+
7635
8509
  /**
7636
- * Content type configuration using direct fields
7637
- * Generic to preserve literal field IDs for type inference
8510
+ * Settings group configuration - generic to preserve field types
7638
8511
  */
7639
- interface ContentTypeConfigWithFields<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
8512
+ interface SettingsGroupConfig<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
7640
8513
  /** Display name shown in the UI */
7641
8514
  displayName: string;
7642
- /** Plural display name shown in the UI (e.g., "Products" for "Product") */
7643
- displayNamePlural?: string;
7644
- /** Description of the content type */
8515
+ /** Description of the settings group */
7645
8516
  description?: string;
7646
- /** AI configuration: generation/review guidance */
8517
+ /** AI configuration for content generation and review */
7647
8518
  ai?: AIConfig;
7648
- /**
7649
- * Field ID to use as entry display title in lists, references, and editor header.
7650
- * If not set, falls back to: title → name → slug → first shortText field → entryUid
7651
- */
7652
- displayField?: string;
7653
- /** Whether this content type supports hierarchical (parent-child) relationships */
7654
- hierarchical?: boolean;
7655
8519
  /** Access tags for role-based access control */
7656
8520
  accessTags?: string[];
7657
- /** Workflow configuration for this content type */
7658
- workflow?: ContentTypeWorkflowConfig;
7659
- /** Direct field definitions - preserves literal types */
8521
+ /** Settings fields - preserves literal types */
7660
8522
  fields: TFields;
7661
- /** Cannot have fieldsets when using fields */
7662
- fieldsets?: never;
7663
- }
7664
- /**
7665
- * Content type configuration using fieldsets
7666
- * Generic to preserve fieldset field types
7667
- */
7668
- interface ContentTypeConfigWithFieldsets<TFieldsets extends readonly AnyFieldset[] = readonly AnyFieldset[]> {
7669
- /** Display name shown in the UI */
7670
- displayName: string;
7671
- /** Plural display name shown in the UI (e.g., "Products" for "Product") */
7672
- displayNamePlural?: string;
7673
- /** Description of the content type */
7674
- description?: string;
7675
- /** AI configuration: generation/review guidance */
7676
- ai?: AIConfig;
7677
- /**
7678
- * Field ID to use as entry display title in lists, references, and editor header.
7679
- * If not set, falls back to: title → name → slug → first shortText field → entryUid
7680
- */
7681
- displayField?: string;
7682
- /** Access tags for role-based access control */
7683
- accessTags?: string[];
7684
- /** Whether this content type supports hierarchical (parent-child) relationships */
7685
- hierarchical?: boolean;
7686
- /** Workflow configuration for this content type */
7687
- workflow?: ContentTypeWorkflowConfig;
7688
- /** Field organization via fieldsets - preserves literal types */
7689
- fieldsets: TFieldsets;
7690
- /** Cannot have direct fields when using fieldsets */
7691
- fields?: never;
7692
8523
  }
7693
8524
  /**
7694
- * Content type configuration (either fields OR fieldsets, not both)
7695
- */
7696
- type ContentTypeConfig<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset[] = readonly AnyFieldset[]> = ContentTypeConfigWithFields<TFields> | ContentTypeConfigWithFieldsets<TFieldsets>;
7697
- /**
7698
- * Content type definition - preserves field types for inference
8525
+ * Settings group definition - preserves field types for inference
7699
8526
  */
7700
- interface ContentTypeDefinition<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset[] = readonly AnyFieldset[]> {
7701
- readonly _tag: 'contentType';
8527
+ interface SettingsGroupDefinition<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
8528
+ readonly _tag: 'settingsGroup';
7702
8529
  readonly name: string;
7703
8530
  readonly displayName: string;
7704
- readonly displayNamePlural?: string;
7705
8531
  readonly description?: string;
7706
- /** AI configuration: generation/review guidance */
8532
+ /** AI configuration for content generation and review */
7707
8533
  readonly ai?: AIConfig;
7708
- /** Field ID to use as entry display title */
7709
- readonly displayField?: string;
7710
- readonly hierarchical?: boolean;
7711
8534
  readonly accessTags?: string[];
7712
- readonly workflow?: ContentTypeWorkflowConfig;
7713
- readonly fields?: TFields;
7714
- readonly fieldsets?: TFieldsets;
8535
+ readonly fields: TFields;
7715
8536
  }
7716
8537
  /**
7717
- * Define a content type with type-safe fields
8538
+ * Define a settings group
7718
8539
  *
7719
- * The generic type parameters preserve the literal field IDs through the type
7720
- * system, enabling autocomplete in SDK methods like where(), select(), etc.
8540
+ * The generic type parameter preserves the literal field IDs through the type
8541
+ * system, enabling autocomplete in SDK methods.
7721
8542
  *
7722
8543
  * @example
7723
- * // Using direct fields
7724
- * const product = defineContentType('product', {
7725
- * displayName: 'Product',
8544
+ * const integrations = defineSettingsGroup('integrations', {
8545
+ * displayName: 'Integrations',
8546
+ * description: 'Third-party service integrations',
7726
8547
  * fields: [
7727
- * fields.shortText('title', { config: { required: true } }),
7728
- * fields.decimal('price', { config: { min: 0, decimalPlaces: 2 } }),
7729
- * ]
7730
- * })
7731
- *
7732
- * @example
7733
- * // Using fieldsets for organization
7734
- * const product = defineContentType('product', {
7735
- * displayName: 'Product',
7736
- * fieldsets: [
7737
- * fieldset('basic', {
7738
- * displayName: 'Basic Info',
7739
- * fields: [
7740
- * fields.shortText('title', { config: { required: true } }),
7741
- * ]
8548
+ * fields.shortText('stripeApiKey', {
8549
+ * config: { required: true },
8550
+ * ui: { displayName: 'Stripe API Key' }
7742
8551
  * }),
7743
- * fieldset('pricing', {
7744
- * displayName: 'Pricing',
7745
- * fields: [
7746
- * fields.decimal('price', { config: { min: 0, decimalPlaces: 2 } }),
7747
- * ]
8552
+ * fields.shortText('sendgridApiKey', {
8553
+ * ui: { displayName: 'SendGrid API Key' }
8554
+ * }),
8555
+ * fields.boolean('enableAnalytics', {
8556
+ * config: { defaultValue: true },
8557
+ * ui: { displayName: 'Enable Analytics' }
7748
8558
  * }),
7749
8559
  * ]
7750
8560
  * })
7751
8561
  */
7752
- declare function defineContentType<TFields extends readonly AnyFieldDefinition[], _TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: ContentTypeConfigWithFields<TFields>): ContentTypeDefinition<TFields, readonly []>;
7753
- declare function defineContentType<_TFields extends readonly AnyFieldDefinition[], TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: ContentTypeConfigWithFieldsets<TFieldsets>): ContentTypeDefinition<readonly [], TFieldsets>;
8562
+ declare function defineSettingsGroup<TFields extends readonly AnyFieldDefinition[]>(name: string, config: SettingsGroupConfig<TFields>): SettingsGroupDefinition<TFields>;
7754
8563
  /**
7755
- * Type alias for any content type definition.
8564
+ * Type alias for any settings group definition.
7756
8565
  */
7757
- type AnyContentTypeDefinition = ContentTypeDefinition<any, any>;
8566
+ type AnySettingsGroupDefinition = SettingsGroupDefinition<any>;
7758
8567
  /**
7759
- * What a read reports about an entry beside its fields: the committed document's `EntryMetadata`
7760
- * (`apps/services/api/openapi-spec.json`), read through `http/api-schema.ts`, its one derivation in
7761
- * this package — not declared a second time here.
7762
- *
7763
- * It used to be written out by hand, and the copy had drifted from the wire: it declared a
7764
- * `parentId` no read sends, typed `createdAt` and `updatedAt` as `Date` where the wire sends ISO 8601
7765
- * strings, and left out what a reader most needs — `availableLocales`, `defaultLocale`, `slug`,
7766
- * `refs` — so the preview toolbar took them through a structural type of its own. A field the
7767
- * service adds or changes now reaches this type when `api-schema.ts` is regenerated, and
7768
- * `__tests__/read-metadata.types.ts` fails `type:check` if a read stops declaring it.
8568
+ * What a read reports about a settings group beside its fields: the committed document's
8569
+ * `SettingsGroupMetadata`, read through `http/api-schema.ts` rather than declared again here.
7769
8570
  *
7770
- * Every entry-shaped value carries it — a single read, each item of a list or of `children()`, and
7771
- * an entry an `include` expanded — because the service builds each of them with one transform.
7772
- * `versionCount` and `versions` are sent on a single read only, so they are optional.
8571
+ * It names the group by `id` and `groupId`, carries the per-locale facts and the version history
8572
+ * of `locale`, and says when the group was last written — there is no `createdAt`. The hand-written
8573
+ * type this replaces declared a `key`, a `groupType` and a `createdAt` the wire does not carry, and
8574
+ * `Date` timestamps where it sends ISO 8601 strings.
7773
8575
  */
7774
- type EntryMetadata = components['schemas']['EntryMetadata'];
8576
+ type SettingsGroupMetadata = components['schemas']['SettingsGroupMetadata'];
7775
8577
  /**
7776
- * The per-locale publication facts every one-document read reports, an entry's, a singleton's and a
7777
- * settings group's alike (`INV-LM-PUBLICATION-IS-REPORTED-PER-LOCALE`): a `Pick` of the document's
7778
- * {@link EntryMetadata}, so this package holds no copy of them. `localeStatus` is absent when the
7779
- * locale has no content of its own.
7780
- *
7781
- * Unpublished work comes in two kinds, reported apart: `draftLocales` names the locales with edits
7782
- * of their own, and `hasDraft` is a change to the shared (non-localized) fields. Publishing any
7783
- * locale makes a shared change live, so it is pending in every locale and no locale code is listed
7784
- * for it. A locale has unpublished work when `draftLocales` names it or `hasDraft` is `true`.
8578
+ * Infer the TypeScript type from a settings group definition: every field typed as a read returns it
8579
+ * (`schema/infer-fields.ts`), plus `_metadata`. `S` is the schema, as for `InferContentType`. Every
8580
+ * field is optional, required or not: a group reads as its declared and synthesized defaults until
8581
+ * it is written, and a required field with neither is absent (`Presence`).
7785
8582
  */
7786
- type LocalePublicationFields = Pick<EntryMetadata, 'localeStatus' | 'localeHasDraft' | 'draftLocales' | 'hasDraft'>;
8583
+ type InferSettingsGroup<T extends AnySettingsGroupDefinition, S extends FieldSchemaContext | undefined = undefined, I extends string = never> = FieldValues<DeclaredFields<T>, S, 'none', I> & {
8584
+ _metadata: SettingsGroupMetadata;
8585
+ };
8586
+
7787
8587
  /**
7788
- * Infer the TypeScript type of an entry from a content type definition: every field it declares,
7789
- * directly or through fieldsets, typed as a read returns it (`INV-SS-TYPES-INFERRED`), plus
7790
- * `_metadata`. Each field is optional — `schema/infer-fields.ts` says why, and what each field type
7791
- * reads as.
8588
+ * Include paths, typed (REL-1801, design decision 12): a read's type follows the paths it names.
7792
8589
  *
7793
- * `S` is the schema the type belongs to. With it, a reference expanded by `include` is typed as the
7794
- * entry it points at and a component field by the component's fields; without it, those two are
7795
- * typed as an entry or an object whose fields are not known. A client typed by a schema passes it.
8590
+ * ```ts
8591
+ * const home = await relyio
8592
+ * .content('page')
8593
+ * .findById('home')
8594
+ * .include(['sections.features(name,slug)', 'sections.customers.logo', 'ogImage'])
8595
+ * .execute()
8596
+ * ```
7796
8597
  *
7797
- * @example
7798
- * const product = defineContentType('product', {
7799
- * displayName: 'Product',
7800
- * fields: [
7801
- * fields.shortText('title'),
7802
- * fields.decimal('price'),
7803
- * fields.enum('status', {
7804
- * config: {
7805
- * options: [
7806
- * { value: 'draft', label: 'Draft' },
7807
- * { value: 'live', label: 'Live' },
7808
- * ],
7809
- * },
7810
- * }),
7811
- * ]
7812
- * })
8598
+ * - **A path names fields, joined by dots**, through lists, page builders, objects and references:
8599
+ * `sections.features` reaches `features` in whichever block declares it. Each hop across a
8600
+ * reference is written out — `sections.customers.logo` expands each customer and its logo — and
8601
+ * nothing expands past where a path stops, so a read costs what it names. A path that stops at a
8602
+ * list or an object expands every reference it holds.
8603
+ * - **Parentheses pick fields**: `sections.features(name,slug)` returns each feature with its `name`,
8604
+ * its `slug` and its `_metadata`, and is typed so.
8605
+ * - **A reference a path expands is typed as the entry; every other one as its id.** One path is one
8606
+ * element of the array; a path that holds no reference does not compile, and the error lists the
8607
+ * paths that do.
7813
8608
  *
7814
- * type Product = InferContentType<typeof product>
7815
- * // { title?: string; price?: number; status?: 'draft' | 'live'; _metadata: EntryMetadata }
8609
+ * The grammar is `@relyio/schema`'s `readIncludePaths`, which the Content API reads `?include=` with;
8610
+ * the API holds each path to the deployed schema and refuses one it does not hold, naming the ones it
8611
+ * does.
7816
8612
  */
7817
- type InferContentType<T extends AnyContentTypeDefinition, S extends FieldSchemaContext | undefined = undefined> = FieldValues<DeclaredFields<T>, S> & {
7818
- _metadata: EntryMetadata;
8613
+
8614
+ /**
8615
+ * The include paths that continue below field `K`, relative to it: `sections.features` → `features`
8616
+ * under `sections`. An include set the type cannot see (`string`) continues everywhere.
8617
+ */
8618
+ type IncludesUnder<I extends string, K extends string> = string extends I ? string : I extends `${K}.${infer Rest}` ? Rest : never;
8619
+ /**
8620
+ * The paths that stop at field `K`: `''` for one that picks no fields, and what the parentheses hold
8621
+ * for one that does (`'name,slug'`). `never` when none stops here.
8622
+ */
8623
+ type StopsAt<I extends string, K extends string> = string extends I ? never : I extends K ? '' : I extends `${K}(${infer Picked})` ? Picked : never;
8624
+ /** Whether the reference at `K` is expanded: a path names it or crosses it, or one above covers it. */
8625
+ type ExpandsHere<I extends string, K extends string, A extends boolean> = A extends true ? true : [StopsAt<I, K> | IncludesUnder<I, K>] extends [never] ? false : true;
8626
+ /** Whether every reference below the list or object `K` is expanded: a path stops at it, or above. */
8627
+ type CoversBelow<I extends string, K extends string, A extends boolean> = A extends true ? true : '' extends StopsAt<I, K> ? true : false;
8628
+ /** Every field of an entry: what a reference a path picks nothing of returns. */
8629
+ interface EveryField {
8630
+ readonly __everyField: true;
8631
+ }
8632
+ type Trim<S extends string> = S extends ` ${infer R}` ? Trim<R> : S extends `${infer R} ` ? Trim<R> : S;
8633
+ /** `'name, slug'` → `'name' | 'slug'`. */
8634
+ type Split<S extends string> = S extends `${infer Head},${infer Rest}` ? Trim<Head> | Split<Rest> : Trim<S>;
8635
+ /** The field a path below a reference crosses first: `logo(alt)` and `logo.credit` → `logo`. */
8636
+ type FirstField<P extends string> = P extends `${infer Head}.${string}` ? FirstField<Head> : P extends `${infer Head}(${string}` ? Head : P;
8637
+ /**
8638
+ * The fields the entry a reference reaches returns: every field, unless every path stopping at it
8639
+ * picks — then the picked fields and the fields deeper paths cross.
8640
+ */
8641
+ type SelectionAt<I extends string, K extends string> = [StopsAt<I, K>] extends [never] ? EveryField : '' extends StopsAt<I, K> ? EveryField : Split<StopsAt<I, K>> | FirstField<IncludesUnder<I, K>>;
8642
+ /** An entry cut down to a selection, beside its `_metadata`. Distributes over a union of entries. */
8643
+ type Selected<E, Fields> = [Fields] extends [EveryField] ? E : E extends unknown ? {
8644
+ [Key in keyof E as Key extends Fields | '_metadata' ? Key : never]: E[Key];
8645
+ } : never;
8646
+ type ReferenceKind = Extract<FieldType, 'reference'>;
8647
+ type IsReference<F> = F extends {
8648
+ readonly type: ReferenceKind;
8649
+ } ? true : false;
8650
+ /** The fields of the shapes a list's items or an object's value take; `never` for any other field. */
8651
+ type ShapeFields<F> = F extends {
8652
+ readonly config?: infer C;
8653
+ } ? NonNullable<C> extends {
8654
+ readonly of?: infer Of;
8655
+ } ? FieldsOfShapes<ShapesIn<Exclude<Of, undefined>>> : never : never;
8656
+ type FieldsOfShapes<Shape> = Shape extends {
8657
+ readonly fields: readonly unknown[];
8658
+ } ? DeclaredFields<Shape> : never;
8659
+ /** The fields of every type a reference may point at, sections read flat. */
8660
+ type TargetFields<F, S> = F extends {
8661
+ readonly config?: infer C;
8662
+ } ? S extends FieldSchemaContext ? FieldsOfDefinition<Declared<S['contentTypes'], ReferenceTarget<NonNullable<C>>> | Declared<S['singletonContentTypes'], ReferenceTarget<NonNullable<C>>> | Declared<NonNullable<S['assetTypes']>, ReferenceTarget<NonNullable<C>>>> : never : never;
8663
+ type FieldsOfDefinition<D> = D extends {
8664
+ readonly fields: readonly unknown[];
8665
+ } ? DeclaredFields<D> : never;
8666
+ /** `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;
8668
+ /**
8669
+ * Every path a record can include, below `Prefix`: each reference, and each list or object holding
8670
+ * one, then the paths inside it. Distributes over the record's fields.
8671
+ */
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;
8673
+ /** The path part of a written path, and what its parentheses pick. */
8674
+ type PathOf<X extends string> = X extends `${infer Path}(${string})` ? Path : X;
8675
+ type PickedOf<X extends string> = X extends `${string}(${infer Picked})` ? Picked : never;
8676
+ /**
8677
+ * `X` when it is a path the record `Root` can include; otherwise the paths it can include at the
8678
+ * point `X` went wrong, which is what the compiler names: `Type '"sections.title"' is not
8679
+ * assignable to type '"ogImage" | "sections" | "sections.features" | …'`.
8680
+ */
8681
+ type CheckInclude<Root, S, X extends string> = Walk<Root, Root, S, PathOf<X>, PickedOf<X>, '', ''> extends true ? X : Walk<Root, Root, S, PathOf<X>, PickedOf<X>, '', ''>;
8682
+ /** The paths `Root` can include, written after `Entry` — the path up to the entry they belong to. */
8683
+ type Suggest<Root, Entry extends string> = IncludablePaths<Root, Entry>;
8684
+ type Walk<Fields, Root, S, Rest extends string, Picked extends string, Done extends string, Entry extends string> = Rest extends `${infer Segment}.${infer Tail}` ? Step<Extract<Fields, {
8685
+ readonly id: Segment;
8686
+ }>, Root, S, Segment, Tail, Picked, Done, Entry> : Step<Extract<Fields, {
8687
+ readonly id: Rest;
8688
+ }>, Root, S, Rest, '', Picked, Done, Entry>;
8689
+ type Step<F, Root, S, Segment extends string, Tail extends string, Picked extends string, Done extends string, Entry extends string> = [F] extends [never] ? Suggest<Root, Entry> : true extends IsReference<F> ? Tail extends '' ? [Picked] extends [never] ? true : CheckPicked<TargetFields<Extract<F, {
8690
+ readonly type: ReferenceKind;
8691
+ }>, S>, Picked, `${Done}${Segment}`> : Walk<TargetFields<Extract<F, {
8692
+ readonly type: ReferenceKind;
8693
+ }>, S>, TargetFields<Extract<F, {
8694
+ 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>;
8696
+ /** `true` when every picked field is one the reached entry declares; otherwise each pick it could. */
8697
+ type CheckPicked<Target, Picked extends string, Path extends string> = [
8698
+ Exclude<Split<Picked>, Target extends AnyFieldDefinition ? Target['id'] : never>
8699
+ ] extends [never] ? true : `${Path}(${Target extends AnyFieldDefinition ? Target['id'] : never})`;
8700
+ /**
8701
+ * How one read is typed by the include paths it names — a type-level function, applied with
8702
+ * {@link ReadWith} and {@link CheckedInclude}. Each typed client carries the one for its type.
8703
+ */
8704
+ interface Reading {
8705
+ /** The include paths the read names (set by {@link ReadWith}). */
8706
+ readonly include: string;
8707
+ /** One path to check (set by {@link CheckedInclude}). */
8708
+ readonly path: string;
8709
+ /** What the read returns under `include`. */
8710
+ readonly read: unknown;
8711
+ /** `path` when it holds, or the paths that would. */
8712
+ readonly checked: unknown;
8713
+ }
8714
+ /** What a read typed by `R` returns under the include paths `I`. */
8715
+ type ReadWith<R extends Reading, I extends string> = (R & {
8716
+ readonly include: I;
8717
+ })['read'];
8718
+ /** `X` when `R`'s type can include it, or the paths it can. */
8719
+ type CheckedInclude<R extends Reading, X extends string> = (R & {
8720
+ readonly path: X;
8721
+ })['checked'];
8722
+ /**
8723
+ * A path as written: inferred from the argument, never from what checking it answers. TypeScript's
8724
+ * own `NoInfer` does this from 5.4; this is the form every version the package supports reads.
8725
+ */
8726
+ type Written<X> = [X][X extends unknown ? 0 : never];
8727
+ /**
8728
+ * An `include()` argument, each path checked against the type. A path the type cannot see — a
8729
+ * `string` — is taken as written, and the read typed as if it may expand anything.
8730
+ */
8731
+ type CheckedIncludes<R extends Reading, P extends readonly string[]> = {
8732
+ readonly [K in keyof P]: string extends P[K] ? P[K] : CheckedInclude<R, Written<P[K]>>;
7819
8733
  };
8734
+ /** A read no schema types: it returns `T` whatever it includes, and any path is taken as written. */
8735
+ interface UntypedReading<T> extends Reading {
8736
+ readonly read: T;
8737
+ readonly checked: this['path'];
8738
+ }
8739
+ /** A read of the content type `D` defines, in schema `S`. */
8740
+ interface ContentReading<D extends AnyContentTypeDefinition, S extends FieldSchemaContext | undefined> extends Reading {
8741
+ readonly read: InferContentType<D, S, this['include']>;
8742
+ readonly checked: CheckInclude<FieldsOfDefinition<D>, S, this['path']>;
8743
+ }
8744
+ /** A read of the singleton `D` defines, in schema `S`. */
8745
+ interface SingletonReading<D extends AnySingletonContentTypeDefinition, S extends FieldSchemaContext | undefined> extends Reading {
8746
+ readonly read: InferSingletonContentType<D, S, this['include']>;
8747
+ readonly checked: CheckInclude<FieldsOfDefinition<D>, S, this['path']>;
8748
+ }
8749
+ /** A read of the asset type `D` defines, in schema `S`. */
8750
+ interface AssetReading<D extends AnyAssetTypeDefinition, S extends FieldSchemaContext | undefined> extends Reading {
8751
+ readonly read: InferAssetType<D, S, this['include']>;
8752
+ readonly checked: CheckInclude<FieldsOfDefinition<D>, S, this['path']>;
8753
+ }
8754
+ /** A read of the settings group `D` defines, in schema `S`. */
8755
+ interface SettingsReading<D extends AnySettingsGroupDefinition, S extends FieldSchemaContext | undefined> extends Reading {
8756
+ readonly read: InferSettingsGroup<D, S, this['include']>;
8757
+ readonly checked: CheckInclude<FieldsOfDefinition<D>, S, this['path']>;
8758
+ }
7820
8759
 
7821
- export { type SingletonConfigWithFieldsets as $, type AnyFieldDefinition as A, type BooleanConfig as B, type ComponentFieldConfig as C, type DecimalConfig as D, type EmailConfig as E, type FieldUIConfig as F, type UnresolvedComponent as G, defineContentType as H, type IntegerConfig as I, fieldset as J, type Fieldset as K, type LocalizationConfig as L, type ContentTypeConfig as M, type ContentTypeConfigWithFields as N, type ContentTypeConfigWithFieldsets as O, type ContentTypeDefinition as P, type EntryMetadata as Q, type RichTextConfig as R, type ShortTextConfig as S, type TagsConfig as T, type UrlConfig as U, type ValidationRule as V, type InferContentType as W, type LocalePublicationFields as X, defineSingletonContentType as Y, defineSingleton as Z, type SingletonConfigWithFields as _, type FieldAIConfig as a, type SingletonContentTypeDefinition as a0, type SingletonMetadata as a1, type InferSingletonContentType as a2, type InferSingleton as a3, defineAssetType as a4, type AssetTypeConfig as a5, type AssetTypeConfigWithFields as a6, type AssetTypeConfigWithFieldsets as a7, type AssetTypeConfigWithoutFields as a8, type AssetTypeDefinition as a9, getFirstWorkflowStage as aA, isFinalWorkflowStage as aB, type WorkflowEscalation as aC, type WorkflowAutoAssign as aD, type WorkflowStageConfig as aE, type WorkflowStageDefinition as aF, type WorkflowConfig as aG, type WorkflowDefinition as aH, type ContentTypeWorkflowConfig as aI, type paths as aJ, type components as aK, type InferAssetType as aa, type ImageKindConfig as ab, type VideoKindConfig as ac, type FileKindConfig as ad, type ImageTransform as ae, type ImageFitMode as af, type ImageOutputFormat as ag, type ImageUploadConfig as ah, type ImageSourceConfig as ai, type ImageExifConfig as aj, type VariantDefinition as ak, type VideoUploadConfig as al, type VideoPosterConfig as am, type VideoCaptionsConfig as an, type VideoDownloadConfig as ao, type VideoWatermarkConfig as ap, type FileUploadConfig as aq, type FileScanConfig as ar, defineWorkflow as as, defineWorkflowStage as at, defineContentTypeWorkflow as au, isWorkflowDefinition as av, isWorkflowStageDefinition as aw, getWorkflowStageIds as ax, findWorkflowStage as ay, getNextWorkflowStage 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 ListConfig as j, type AIConfig as k, type AllFieldTypes as l, type AssetAIConfig as m, type BaseFieldConfig as n, type ComponentFieldType 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 };
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 };