@relyio/sdk 0.5.0 → 0.7.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 +540 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/{chunk-HAQELDZN.cjs → chunk-72UK5U7T.cjs} +70 -60
  4. package/dist/{chunk-5AZUUV5B.js → chunk-GYHAVYND.js} +1086 -494
  5. package/dist/{chunk-I3ESNANB.js → chunk-H6IBQSMM.js} +2 -2
  6. package/dist/{chunk-HT6NFRM2.cjs → chunk-TZL374LS.cjs} +2 -2
  7. package/dist/{chunk-CIRT6TVT.cjs → chunk-VH2DE7HZ.cjs} +1088 -497
  8. package/dist/{chunk-XY5KFEFY.js → chunk-YEJUMW4X.js} +70 -60
  9. package/dist/client/index.cjs +4 -3
  10. package/dist/client/index.d.cts +4 -4
  11. package/dist/client/index.d.ts +4 -4
  12. package/dist/client/index.js +2 -1
  13. package/dist/{index-C5mRBb6t.d.cts → define-content-type-DiVpbwNs.d.cts} +1629 -665
  14. package/dist/{index-mXUx2H99.d.ts → define-content-type-DiVpbwNs.d.ts} +1629 -665
  15. package/dist/{define-schema-DzYXk4HL.d.ts → define-schema-C-5an28C.d.ts} +211 -429
  16. package/dist/{define-schema-2xbHgtK-.d.cts → define-schema-D7MButVt.d.cts} +211 -429
  17. package/dist/{index-Dzo-upNS.d.ts → index-1G97sNA8.d.ts} +677 -296
  18. package/dist/index-BOQIHnsh.d.ts +818 -0
  19. package/dist/index-DbsTUw3Q.d.cts +818 -0
  20. package/dist/{index-BozPz4n1.d.cts → index-M0X45k7J.d.cts} +677 -296
  21. package/dist/index.cjs +180 -103
  22. package/dist/index.d.cts +307 -32
  23. package/dist/index.d.ts +307 -32
  24. package/dist/index.js +95 -8
  25. package/dist/schema/index.cjs +35 -35
  26. package/dist/schema/index.d.cts +21 -15
  27. package/dist/schema/index.d.ts +21 -15
  28. package/dist/schema/index.js +1 -1
  29. package/dist/types/index.d.cts +2 -2
  30. package/dist/types/index.d.ts +2 -2
  31. package/dist/utils/index.cjs +19 -19
  32. package/dist/utils/index.d.cts +10 -1
  33. package/dist/utils/index.d.ts +10 -1
  34. package/dist/utils/index.js +1 -1
  35. package/package.json +4 -3
  36. package/dist/define-content-type-CBfnTWSS.d.cts +0 -716
  37. package/dist/define-content-type-CBfnTWSS.d.ts +0 -716
@@ -1,5 +1,3 @@
1
- import { H as EntryMetadata } from './define-content-type-CBfnTWSS.cjs';
2
-
3
1
  /**
4
2
  * Generated by scripts/emit-openapi-types.mjs from @relyio/api's committed
5
3
  * openapi-spec.json. Do not edit: run `pnpm codegen:openapi` in this package, which
@@ -237,7 +235,11 @@ interface paths {
237
235
  path?: never;
238
236
  cookie?: never;
239
237
  };
240
- get?: never;
238
+ /**
239
+ * Read a file binding's upload status
240
+ * @description Where the binding's upload got to — `status` and `processing` (stage, progress, error) — whatever the asset entry is published in. Takes the capability the upload routes take, so a key that could have uploaded the file can see whether it failed; the entry itself is read through the key's own lens.
241
+ */
242
+ get: operations['getFileStatus'];
241
243
  put?: never;
242
244
  post?: never;
243
245
  /** Delete a file binding */
@@ -837,6 +839,111 @@ interface paths {
837
839
  }
838
840
  interface components {
839
841
  schemas: {
842
+ /** @description An asset entry’s `file`: the binary’s lifecycle and what was read from it, at the locale the entry’s fields were composed for. Sent beside the asset’s fields on every read of it, with `urls` once `status` is `ready`. How storage addresses the bytes is not part of it. */
843
+ AssetFile: {
844
+ /**
845
+ * @description Where the binary is: `pending_upload` before any bytes, `uploading` once presigned, `processing` once the pipeline has it, then `ready` or `failed`. Independent of the entry’s publication.
846
+ * @enum {string}
847
+ */
848
+ status: 'failed' | 'pending_upload' | 'processing' | 'ready' | 'uploading';
849
+ /**
850
+ * @description `r2` for image and file kinds, `stream` for video.
851
+ * @enum {string}
852
+ */
853
+ backend: 'r2' | 'stream';
854
+ fileName: string;
855
+ mimeType?: string | null;
856
+ /** @description In bytes. */
857
+ size?: number | null;
858
+ /** @description The SHA-256 the client declared: advisory, for duplicate detection only. */
859
+ hash?: string | null;
860
+ /**
861
+ * @description Enforced by the delivery gateway; a `protected` or `private` URL carries a token.
862
+ * @enum {string}
863
+ */
864
+ visibility: 'private' | 'protected' | 'public';
865
+ /** @description What was read from the file. Enrichment adds keys as its stages finish, so the object is open beyond the ones named here. */
866
+ extracted?: {
867
+ width?: number;
868
+ height?: number;
869
+ format?: string;
870
+ duration?: number;
871
+ hasAlpha?: boolean;
872
+ isAnimated?: boolean;
873
+ orientation?: number;
874
+ placeholder?: string;
875
+ dominantColor?: string;
876
+ palette?: string[];
877
+ exif?: {
878
+ [key: string]: unknown;
879
+ };
880
+ video?: {
881
+ codec?: string;
882
+ bitrate?: number;
883
+ framerate?: number;
884
+ audioTracks?: unknown[];
885
+ } & {
886
+ [key: string]: unknown;
887
+ };
888
+ pageCount?: number;
889
+ text?: string;
890
+ safety?: {
891
+ nsfwScore?: number;
892
+ flagged?: boolean;
893
+ categories?: string[];
894
+ } & {
895
+ [key: string]: unknown;
896
+ };
897
+ } & {
898
+ [key: string]: unknown;
899
+ };
900
+ /** @description The smart-crop anchor, each axis `0`–`1`. */
901
+ focalPoint?: {
902
+ x: number;
903
+ y: number;
904
+ };
905
+ /** @description Where metadata enrichment got to. Independent of `status`. */
906
+ enrichment?: {
907
+ /** @enum {string} */
908
+ status: 'complete' | 'failed' | 'partial' | 'pending' | 'running';
909
+ };
910
+ /** @description The malware scan of a file-kind binding. */
911
+ scan?: {
912
+ /** @enum {string} */
913
+ status: 'clean' | 'error' | 'infected' | 'pending' | 'skipped';
914
+ };
915
+ processing?: components['schemas']['AssetFileProcessing'];
916
+ /** @description Whether a video can be played yet. */
917
+ playback?: {
918
+ ready?: boolean;
919
+ };
920
+ };
921
+ /** @description Where the pipeline got to with a file, and why it failed. Present when the pipeline recorded a stage, a progress or an error. */
922
+ AssetFileProcessing: {
923
+ /** @description The stage the pipeline last recorded. */
924
+ stage?: string;
925
+ /** @description How far the pipeline got, `0`–`100`, where it reports that (video encoding). */
926
+ progress?: number;
927
+ /** @description Why the file failed. Present exactly while `status` is `failed`. */
928
+ error?: {
929
+ /** @description The reason, e.g. `UNSUPPORTED_MIME`, `UPLOAD_TOO_LARGE` or `INTERNAL`. */
930
+ code?: string;
931
+ message?: string;
932
+ /** @description `true` only for `INTERNAL`, a failure no property of the file caused. */
933
+ retriable?: boolean;
934
+ };
935
+ };
936
+ /** @description One distinct value of the field, and the entry it was first found in. */
937
+ AutocompleteSuggestion: {
938
+ /** @description The suggested value. */
939
+ text: string;
940
+ /** @description The best relevance among the entries holding it. */
941
+ score: number;
942
+ /** @description An entry holding the value. */
943
+ id: string;
944
+ /** @description The value with its matched part wrapped in `<em>`, when Atlas highlighted it. */
945
+ highlight?: string;
946
+ };
840
947
  /** @description One change to one entry, ids only. Refetch the entry through the ordinary read path to see it. */
841
948
  Change: {
842
949
  entryId: string;
@@ -852,16 +959,123 @@ interface components {
852
959
  nextCursor: string | null;
853
960
  hasMore: boolean;
854
961
  };
962
+ /** @description One entry: its fields at the top level, as the content type declares them, and `_metadata`. An asset entry also carries `file`, an `AssetFile`, and `urls` once the file is ready. */
963
+ Entry: {
964
+ _metadata: components['schemas']['EntryMetadata'];
965
+ } & {
966
+ [key: string]: unknown;
967
+ };
968
+ /** @description One locale an entry has content in. */
969
+ EntryLocale: {
970
+ code: string;
971
+ /** @enum {string} */
972
+ status: 'archived' | 'draft' | 'published';
973
+ /** @description That locale’s own version counter. */
974
+ version: number;
975
+ /**
976
+ * Format: date-time
977
+ * @description When that locale was last published. Absent until it is.
978
+ */
979
+ publishedAt?: string;
980
+ };
981
+ /** @description What this service reports about an entry beside its fields. */
982
+ EntryMetadata: {
983
+ id: string;
984
+ /** @description The content type. */
985
+ type: string;
986
+ /** @enum {string} */
987
+ entryType: 'asset' | 'content' | 'settings' | 'singleton';
988
+ /** @description The slug field’s value at `locale`, or null when the type declares none. */
989
+ slug: string | null;
990
+ /**
991
+ * @description Container lifecycle only. Publication is per locale: `localeStatus`.
992
+ * @enum {string}
993
+ */
994
+ status: 'active' | 'archived' | 'proposed';
995
+ /** @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. */
996
+ version: number;
997
+ /** @description The locale the fields beside this object were composed for. */
998
+ locale: string;
999
+ /** @description How many versions `locale` has. Sent on a single-entry read; a list leaves it out. */
1000
+ versionCount?: number;
1001
+ /** @description `locale`’s version numbers, newest first, at most 25. Sent on a single-entry read; a list leaves it out. */
1002
+ versions?: number[];
1003
+ /**
1004
+ * @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.
1005
+ * @enum {string}
1006
+ */
1007
+ localeStatus?: 'archived' | 'draft' | 'published';
1008
+ /** @description Whether `locale` has unpublished changes of its own. */
1009
+ localeHasDraft: boolean;
1010
+ /** @description Every locale holding unpublished content, sorted. A shared-field draft is listed under the default locale. */
1011
+ draftLocales: string[];
1012
+ /** @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=*`. */
1013
+ requestedLocale?: string;
1014
+ /** @description The schema’s default locale. */
1015
+ defaultLocale: string;
1016
+ /** @description Whether the shared (non-localized) fields have unpublished changes. */
1017
+ hasDraft: boolean;
1018
+ /** @description Each field whose value came from another locale, mapped to that locale. Absent when none did. */
1019
+ localeFallbacksApplied?: {
1020
+ [key: string]: string;
1021
+ };
1022
+ /** @description Every locale the entry has content in, the default first. */
1023
+ availableLocales: components['schemas']['EntryLocale'][];
1024
+ /** @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. */
1025
+ localizations?: {
1026
+ [key: string]: {
1027
+ [key: string]: unknown;
1028
+ };
1029
+ };
1030
+ /**
1031
+ * Format: date-time
1032
+ * @description When the entry was created.
1033
+ */
1034
+ createdAt: string;
1035
+ /**
1036
+ * Format: date-time
1037
+ * @description When the entry was last written.
1038
+ */
1039
+ updatedAt: string;
1040
+ /**
1041
+ * Format: date-time
1042
+ * @description When the entry was last published. Absent until it is.
1043
+ */
1044
+ publishedAt?: string;
1045
+ /**
1046
+ * Format: date-time
1047
+ * @description When the entry was first published. Absent until it is.
1048
+ */
1049
+ firstPublishedAt?: string;
1050
+ /** @description The entry’s outgoing references, across every locale, each once. */
1051
+ refs: components['schemas']['EntryRef'][];
1052
+ };
1053
+ /** @description One outgoing reference. */
1054
+ EntryRef: {
1055
+ /** @description The declaring field’s path — `hero.link` for a reference inside a component. */
1056
+ path: string;
1057
+ /** @description The referenced entry’s id. */
1058
+ entryUid: string;
1059
+ };
855
1060
  ErrorResponse: {
856
1061
  error: {
857
1062
  /** @enum {string} */
858
- code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | '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';
1063
+ 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';
859
1064
  messages: string[];
860
1065
  details?: {
861
1066
  [key: string]: unknown;
862
1067
  };
863
1068
  };
864
1069
  };
1070
+ /** @description Where a binding’s upload got to — its lifecycle and nothing of the entry: no fields, no URL. */
1071
+ FileStatus: {
1072
+ /**
1073
+ * @description Where the binary is: `pending_upload` before any bytes, `uploading` once presigned, `processing` once the pipeline has it, then `ready` or `failed`. Independent of the entry’s publication.
1074
+ * @enum {string}
1075
+ */
1076
+ status: 'failed' | 'pending_upload' | 'processing' | 'ready' | 'uploading';
1077
+ processing?: components['schemas']['AssetFileProcessing'];
1078
+ };
865
1079
  MultiPayload: {
866
1080
  results: (components['schemas']['SubSuccess'] | components['schemas']['SubFailure'])[];
867
1081
  summary: components['schemas']['MultiSummary'];
@@ -1035,12 +1249,219 @@ interface components {
1035
1249
  };
1036
1250
  };
1037
1251
  };
1252
+ /** @description How a hit’s relevance was reached. Sent on a search that asked for `explain`. */
1253
+ ScoreBreakdown: {
1254
+ keyword: number;
1255
+ semantic: number;
1256
+ combined: number;
1257
+ };
1258
+ /** @description One highlighted match, as Atlas Search reports it: the path it matched on and the text around the match, split into `hit` and `text` runs. */
1259
+ SearchHighlight: {
1260
+ path: string;
1261
+ score: number;
1262
+ texts: ({
1263
+ value: string;
1264
+ /** @enum {string} */
1265
+ type: 'hit' | 'text';
1266
+ } & {
1267
+ [key: string]: unknown;
1268
+ })[];
1269
+ } & {
1270
+ [key: string]: unknown;
1271
+ };
1272
+ /** @description One hit: the entry’s fields at the top level — at `_metadata.locale`, or only the aliases a `fields` projection names — its `_metadata`, and the score annotations the request asked for. Not an entry read: see `SearchHitMetadata`. */
1273
+ SearchHit: {
1274
+ _metadata: components['schemas']['SearchHitMetadata'];
1275
+ /** @description Relevance. Sent on a search that asked for `includeScore`, and on every similar hit. */
1276
+ _score?: number;
1277
+ _scoreBreakdown?: components['schemas']['ScoreBreakdown'];
1278
+ /** @description Sent when the search asked for `highlight` and Atlas matched a highlighted path. */
1279
+ _highlights?: components['schemas']['SearchHighlight'][];
1280
+ } & {
1281
+ [key: string]: unknown;
1282
+ };
1283
+ /** @description What this service reports about a hit beside its fields. Narrower than an entry read’s `EntryMetadata`: a hit is built from the search row, so it carries no `entryType`, `defaultLocale`, `availableLocales`, `refs`, `firstPublishedAt` or version history — read the entry for those. */
1284
+ SearchHitMetadata: {
1285
+ id: string;
1286
+ /** @description The content type. */
1287
+ type: string;
1288
+ /** @description The slug field’s value at `locale`, or null when the type declares none. */
1289
+ slug: string | null;
1290
+ /**
1291
+ * @description Container lifecycle only. Publication is per locale: `localeStatus`.
1292
+ * @enum {string}
1293
+ */
1294
+ status: 'active' | 'archived' | 'proposed';
1295
+ /** @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. */
1296
+ version: number;
1297
+ /** @description The locale the fields beside this object were composed for. */
1298
+ locale: string;
1299
+ /**
1300
+ * @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.
1301
+ * @enum {string}
1302
+ */
1303
+ localeStatus?: 'archived' | 'draft' | 'published';
1304
+ /** @description Whether `locale` has unpublished changes of its own. */
1305
+ localeHasDraft: boolean;
1306
+ /** @description Every locale holding unpublished content, sorted. A shared-field draft is listed under the default locale. */
1307
+ draftLocales: string[];
1308
+ /** @description Whether the shared (non-localized) fields have unpublished changes. */
1309
+ hasDraft: boolean;
1310
+ /**
1311
+ * Format: date-time
1312
+ * @description When the entry was created.
1313
+ */
1314
+ createdAt: string;
1315
+ /**
1316
+ * Format: date-time
1317
+ * @description When the entry was last written.
1318
+ */
1319
+ updatedAt: string;
1320
+ /**
1321
+ * Format: date-time
1322
+ * @description When the entry was last published. Absent until it is.
1323
+ */
1324
+ publishedAt?: string;
1325
+ };
1326
+ /** @description One settings group: its fields at the top level, as the group declares them, and `_metadata`. */
1327
+ SettingsGroup: {
1328
+ _metadata: components['schemas']['SettingsGroupMetadata'];
1329
+ } & {
1330
+ [key: string]: unknown;
1331
+ };
1332
+ /** @description One group on the listing: its fields at the top level — its declared defaults until it is first written — and `_metadata`. */
1333
+ SettingsGroupListing: {
1334
+ _metadata: components['schemas']['SettingsGroupListingMetadata'];
1335
+ } & {
1336
+ [key: string]: unknown;
1337
+ };
1338
+ /** @description The group as the schema declares it, and — once the group has been written — what a single read reports about it, less the version history. */
1339
+ SettingsGroupListingMetadata: {
1340
+ /** @description The group’s name, as the schema declares it. */
1341
+ displayName: string;
1342
+ /** @description The group’s description, when the schema declares one. */
1343
+ description?: string;
1344
+ } | {
1345
+ id: string;
1346
+ /** @description The settings group. */
1347
+ groupId: string;
1348
+ /** @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. */
1349
+ version: number;
1350
+ /** @description The locale the fields beside this object were composed for. */
1351
+ locale: string;
1352
+ /**
1353
+ * @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.
1354
+ * @enum {string}
1355
+ */
1356
+ localeStatus?: 'archived' | 'draft' | 'published';
1357
+ /** @description Whether `locale` has unpublished changes of its own. */
1358
+ localeHasDraft: boolean;
1359
+ /** @description Every locale holding unpublished content, sorted. A shared-field draft is listed under the default locale. */
1360
+ draftLocales: string[];
1361
+ /**
1362
+ * Format: date-time
1363
+ * @description When the group was last written.
1364
+ */
1365
+ updatedAt: string;
1366
+ /** @description The group’s name, as the schema declares it. */
1367
+ displayName: string;
1368
+ /** @description The group’s description, when the schema declares one. */
1369
+ description?: string;
1370
+ };
1371
+ /** @description What this service reports about a settings group beside its fields: the group, the per-locale facts and when it was last written. */
1372
+ SettingsGroupMetadata: {
1373
+ id: string;
1374
+ /** @description The settings group. */
1375
+ groupId: string;
1376
+ /** @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. */
1377
+ version: number;
1378
+ /** @description The locale the fields beside this object were composed for. */
1379
+ locale: string;
1380
+ /** @description How many versions `locale` has. */
1381
+ versionCount: number;
1382
+ /** @description `locale`’s version numbers, newest first, at most 25. */
1383
+ versions: number[];
1384
+ /**
1385
+ * @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.
1386
+ * @enum {string}
1387
+ */
1388
+ localeStatus?: 'archived' | 'draft' | 'published';
1389
+ /** @description Whether `locale` has unpublished changes of its own. */
1390
+ localeHasDraft: boolean;
1391
+ /** @description Every locale holding unpublished content, sorted. A shared-field draft is listed under the default locale. */
1392
+ draftLocales: string[];
1393
+ /**
1394
+ * Format: date-time
1395
+ * @description When the group was last written.
1396
+ */
1397
+ updatedAt: string;
1398
+ };
1399
+ /** @description Every settings group the schema declares, keyed by group id, at the locale the request resolved to. */
1400
+ SettingsGroups: {
1401
+ [key: string]: components['schemas']['SettingsGroupListing'];
1402
+ };
1403
+ /** @description One singleton: its fields at the top level, as the singleton type declares them, and `_metadata`. */
1404
+ Singleton: {
1405
+ _metadata: components['schemas']['SingletonMetadata'];
1406
+ } & {
1407
+ [key: string]: unknown;
1408
+ };
1409
+ /** @description What this service reports about a singleton beside its fields. Narrower than an entry’s: no slug, no default locale, no available locales, no references. */
1410
+ SingletonMetadata: {
1411
+ id: string;
1412
+ /** @description The singleton type. */
1413
+ type: string;
1414
+ /**
1415
+ * @description Container lifecycle only. Publication is per locale: `localeStatus`.
1416
+ * @enum {string}
1417
+ */
1418
+ status: 'active' | 'archived' | 'proposed';
1419
+ /** @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. */
1420
+ version: number;
1421
+ /** @description The locale the fields beside this object were composed for. */
1422
+ locale: string;
1423
+ /** @description How many versions `locale` has. */
1424
+ versionCount: number;
1425
+ /** @description `locale`’s version numbers, newest first, at most 25. */
1426
+ versions: number[];
1427
+ /**
1428
+ * @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.
1429
+ * @enum {string}
1430
+ */
1431
+ localeStatus?: 'archived' | 'draft' | 'published';
1432
+ /** @description Whether `locale` has unpublished changes of its own. */
1433
+ localeHasDraft: boolean;
1434
+ /** @description Every locale holding unpublished content, sorted. A shared-field draft is listed under the default locale. */
1435
+ draftLocales: string[];
1436
+ /** @description Whether the shared (non-localized) fields have unpublished changes. */
1437
+ hasDraft: boolean;
1438
+ /**
1439
+ * Format: date-time
1440
+ * @description When the singleton was created.
1441
+ */
1442
+ createdAt: string;
1443
+ /**
1444
+ * Format: date-time
1445
+ * @description When the singleton was last written.
1446
+ */
1447
+ updatedAt: string;
1448
+ /**
1449
+ * Format: date-time
1450
+ * @description When the singleton was last published. Absent until it is.
1451
+ */
1452
+ publishedAt?: string;
1453
+ /**
1454
+ * Format: date-time
1455
+ * @description When the singleton was first published. Absent until it is.
1456
+ */
1457
+ firstPublishedAt?: string;
1458
+ };
1038
1459
  SubFailure: {
1039
1460
  index: number;
1040
1461
  id?: string;
1041
1462
  error: {
1042
1463
  /** @enum {string} */
1043
- code: 'ACCESS_DENIED' | 'CONTENT_INVALID' | 'INTERNAL_ERROR' | 'INVALID_API_KEY' | 'METHOD_NOT_ALLOWED' | 'MISSING_API_KEY' | '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';
1464
+ 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';
1044
1465
  messages: string[];
1045
1466
  details?: {
1046
1467
  [key: string]: unknown;
@@ -1572,7 +1993,6 @@ interface operations {
1572
1993
  ETag?: string;
1573
1994
  Vary?: string;
1574
1995
  'X-Cache'?: string;
1575
- 'X-Cache-Key'?: string;
1576
1996
  [name: string]: unknown;
1577
1997
  };
1578
1998
  content: {
@@ -1774,14 +2194,12 @@ interface operations {
1774
2194
  ETag?: string;
1775
2195
  Vary?: string;
1776
2196
  'X-Cache'?: string;
1777
- 'X-Cache-Key'?: string;
1778
2197
  'X-Entity-Tag'?: string;
1779
2198
  [name: string]: unknown;
1780
2199
  };
1781
2200
  content: {
1782
2201
  'application/json': {
1783
- /** @description The payload itself. */
1784
- data: unknown;
2202
+ data: components['schemas']['Entry'];
1785
2203
  };
1786
2204
  };
1787
2205
  };
@@ -2084,7 +2502,6 @@ interface operations {
2084
2502
  ETag?: string;
2085
2503
  Vary?: string;
2086
2504
  'X-Cache'?: string;
2087
- 'X-Cache-Key'?: string;
2088
2505
  [name: string]: unknown;
2089
2506
  };
2090
2507
  content: {
@@ -2159,6 +2576,94 @@ interface operations {
2159
2576
  };
2160
2577
  };
2161
2578
  };
2579
+ getFileStatus: {
2580
+ parameters: {
2581
+ query?: never;
2582
+ header?: never;
2583
+ path: {
2584
+ contentType: string;
2585
+ id: string;
2586
+ };
2587
+ cookie?: never;
2588
+ };
2589
+ requestBody?: never;
2590
+ responses: {
2591
+ /** @description Success. */
2592
+ 200: {
2593
+ headers: {
2594
+ [name: string]: unknown;
2595
+ };
2596
+ content: {
2597
+ 'application/json': {
2598
+ data: components['schemas']['FileStatus'];
2599
+ };
2600
+ };
2601
+ };
2602
+ /** @description CONTENT_INVALID, REQUEST_INVALID */
2603
+ 400: {
2604
+ headers: {
2605
+ [name: string]: unknown;
2606
+ };
2607
+ content: {
2608
+ 'application/json': components['schemas']['RefusalContentInvalidOrRequestInvalid'];
2609
+ };
2610
+ };
2611
+ /** @description INVALID_API_KEY, MISSING_API_KEY */
2612
+ 401: {
2613
+ headers: {
2614
+ [name: string]: unknown;
2615
+ };
2616
+ content: {
2617
+ 'application/json': components['schemas']['RefusalInvalidApiKeyOrMissingApiKey'];
2618
+ };
2619
+ };
2620
+ /** @description ACCESS_DENIED, PLAN_FEATURE_UNAVAILABLE, READ_ONLY_KEY, USAGE_QUOTA_EXCEEDED */
2621
+ 403: {
2622
+ headers: {
2623
+ [name: string]: unknown;
2624
+ };
2625
+ content: {
2626
+ 'application/json': components['schemas']['RefusalAccessDeniedOrPlanFeatureUnavailableOrReadOnlyKeyOrUsageQuotaExceeded'];
2627
+ };
2628
+ };
2629
+ /** @description RESOURCE_NOT_FOUND */
2630
+ 404: {
2631
+ headers: {
2632
+ [name: string]: unknown;
2633
+ };
2634
+ content: {
2635
+ 'application/json': components['schemas']['RefusalResourceNotFound'];
2636
+ };
2637
+ };
2638
+ /** @description RATE_LIMIT_EXCEEDED */
2639
+ 429: {
2640
+ headers: {
2641
+ [name: string]: unknown;
2642
+ };
2643
+ content: {
2644
+ 'application/json': components['schemas']['RefusalRateLimitExceeded'];
2645
+ };
2646
+ };
2647
+ /** @description INTERNAL_ERROR */
2648
+ 500: {
2649
+ headers: {
2650
+ [name: string]: unknown;
2651
+ };
2652
+ content: {
2653
+ 'application/json': components['schemas']['RefusalInternalError'];
2654
+ };
2655
+ };
2656
+ /** @description SERVICE_INDETERMINATE */
2657
+ 503: {
2658
+ headers: {
2659
+ [name: string]: unknown;
2660
+ };
2661
+ content: {
2662
+ 'application/json': components['schemas']['RefusalServiceIndeterminate'];
2663
+ };
2664
+ };
2665
+ };
2666
+ };
2162
2667
  deleteFileBinding: {
2163
2668
  parameters: {
2164
2669
  query?: never;
@@ -3757,8 +4262,6 @@ interface operations {
3757
4262
  headers: {
3758
4263
  'Cache-Control'?: string;
3759
4264
  Vary?: string;
3760
- 'X-Cache'?: string;
3761
- 'X-Cache-Key'?: string;
3762
4265
  [name: string]: unknown;
3763
4266
  };
3764
4267
  content: {
@@ -3838,8 +4341,6 @@ interface operations {
3838
4341
  headers: {
3839
4342
  'Cache-Control'?: string;
3840
4343
  Vary?: string;
3841
- 'X-Cache'?: string;
3842
- 'X-Cache-Key'?: string;
3843
4344
  [name: string]: unknown;
3844
4345
  };
3845
4346
  content: {
@@ -3928,8 +4429,6 @@ interface operations {
3928
4429
  headers: {
3929
4430
  'Cache-Control'?: string;
3930
4431
  Vary?: string;
3931
- 'X-Cache'?: string;
3932
- 'X-Cache-Key'?: string;
3933
4432
  [name: string]: unknown;
3934
4433
  };
3935
4434
  content: {
@@ -4009,8 +4508,6 @@ interface operations {
4009
4508
  headers: {
4010
4509
  'Cache-Control'?: string;
4011
4510
  Vary?: string;
4012
- 'X-Cache'?: string;
4013
- 'X-Cache-Key'?: string;
4014
4511
  [name: string]: unknown;
4015
4512
  };
4016
4513
  content: {
@@ -4101,8 +4598,6 @@ interface operations {
4101
4598
  headers: {
4102
4599
  'Cache-Control'?: string;
4103
4600
  Vary?: string;
4104
- 'X-Cache'?: string;
4105
- 'X-Cache-Key'?: string;
4106
4601
  [name: string]: unknown;
4107
4602
  };
4108
4603
  content: {
@@ -4193,8 +4688,6 @@ interface operations {
4193
4688
  headers: {
4194
4689
  'Cache-Control'?: string;
4195
4690
  Vary?: string;
4196
- 'X-Cache'?: string;
4197
- 'X-Cache-Key'?: string;
4198
4691
  [name: string]: unknown;
4199
4692
  };
4200
4693
  content: {
@@ -4367,6 +4860,8 @@ interface operations {
4367
4860
  /** @description Success. */
4368
4861
  200: {
4369
4862
  headers: {
4863
+ 'Cache-Control'?: string;
4864
+ 'X-Cache'?: string;
4370
4865
  [name: string]: unknown;
4371
4866
  };
4372
4867
  content: {
@@ -4462,11 +4957,13 @@ interface operations {
4462
4957
  /** @description Success. */
4463
4958
  200: {
4464
4959
  headers: {
4960
+ 'Cache-Control'?: string;
4961
+ 'X-Cache'?: string;
4465
4962
  [name: string]: unknown;
4466
4963
  };
4467
4964
  content: {
4468
4965
  'application/json': {
4469
- data: unknown[];
4966
+ data: components['schemas']['SearchHit'][];
4470
4967
  page: components['schemas']['OffsetPage'];
4471
4968
  meta: {
4472
4969
  [key: string]: unknown;
@@ -4551,11 +5048,13 @@ interface operations {
4551
5048
  /** @description Success. */
4552
5049
  200: {
4553
5050
  headers: {
5051
+ 'Cache-Control'?: string;
5052
+ 'X-Cache'?: string;
4554
5053
  [name: string]: unknown;
4555
5054
  };
4556
5055
  content: {
4557
5056
  'application/json': {
4558
- data: unknown[];
5057
+ data: components['schemas']['AutocompleteSuggestion'][];
4559
5058
  page: components['schemas']['OffsetPage'];
4560
5059
  meta: {
4561
5060
  [key: string]: unknown;
@@ -4631,11 +5130,13 @@ interface operations {
4631
5130
  /** @description Success. */
4632
5131
  200: {
4633
5132
  headers: {
5133
+ 'Cache-Control'?: string;
5134
+ 'X-Cache'?: string;
4634
5135
  [name: string]: unknown;
4635
5136
  };
4636
5137
  content: {
4637
5138
  'application/json': {
4638
- data: unknown[];
5139
+ data: components['schemas']['SearchHit'][];
4639
5140
  page: components['schemas']['OffsetPage'];
4640
5141
  meta: {
4641
5142
  [key: string]: unknown;
@@ -4724,13 +5225,11 @@ interface operations {
4724
5225
  ETag?: string;
4725
5226
  Vary?: string;
4726
5227
  'X-Cache'?: string;
4727
- 'X-Cache-Key'?: string;
4728
5228
  [name: string]: unknown;
4729
5229
  };
4730
5230
  content: {
4731
5231
  'application/json': {
4732
- /** @description The payload itself. */
4733
- data: unknown;
5232
+ data: components['schemas']['SettingsGroups'];
4734
5233
  };
4735
5234
  };
4736
5235
  };
@@ -4808,14 +5307,12 @@ interface operations {
4808
5307
  ETag?: string;
4809
5308
  Vary?: string;
4810
5309
  'X-Cache'?: string;
4811
- 'X-Cache-Key'?: string;
4812
5310
  'X-Entity-Tag'?: string;
4813
5311
  [name: string]: unknown;
4814
5312
  };
4815
5313
  content: {
4816
5314
  'application/json': {
4817
- /** @description The payload itself. */
4818
- data: unknown;
5315
+ data: components['schemas']['SettingsGroup'];
4819
5316
  };
4820
5317
  };
4821
5318
  };
@@ -5385,14 +5882,12 @@ interface operations {
5385
5882
  ETag?: string;
5386
5883
  Vary?: string;
5387
5884
  'X-Cache'?: string;
5388
- 'X-Cache-Key'?: string;
5389
5885
  'X-Entity-Tag'?: string;
5390
5886
  [name: string]: unknown;
5391
5887
  };
5392
5888
  content: {
5393
5889
  'application/json': {
5394
- /** @description The payload itself. */
5395
- data: unknown;
5890
+ data: components['schemas']['Singleton'];
5396
5891
  };
5397
5892
  };
5398
5893
  };
@@ -5838,736 +6333,1205 @@ interface operations {
5838
6333
  }
5839
6334
 
5840
6335
  /**
5841
- * Where the SDK's transport gets its truth.
5842
- *
5843
- * Every route this client calls is named by its **path template as the
5844
- * committed document spells it**, and the body type it expects is read out of
5845
- * that document rather than written down here. `api-schema.ts` beside this file
5846
- * is generated by `pnpm api:types` from `apps/services/api/openapi-spec.json`,
5847
- * which is itself generated from that service's `RouteContract`s
5848
- * (`INV-API-DOCUMENT-IS-DERIVED`). So the chain is: one declaration in
5849
- * `routes.ts` → the serializer that produces the body → the document → these
5850
- * types → the method that reads it.
5851
- *
5852
- * That chain is the answer to the question this phase exists to close. Before
5853
- * it, six SDK methods read a key the server does not send; each had no caller
5854
- * and no test, so nothing could see them. Now:
5855
- *
5856
- * - A route that changes **kind** — `collection` to `object`, say — changes
5857
- * whether the document's 200 body carries `page` and whether `data` is an
5858
- * array. `Wire<…>` follows, `readPayload` follows, and the method's declared
5859
- * return type stops matching. `tsc` names the method.
5860
- * - A route that changes **path** or is deleted stops being a `keyof paths`, so
5861
- * the call site fails on the literal.
5862
- * - A route that changes **dialect** changes `page` from `CursorPage` to
5863
- * `OffsetPage`, and anything reading `nextCursor` fails.
5864
- *
5865
- * `/v1` lives in these templates because it lives in the document
5866
- * (`INV-API-VERSION-IS-DECIDED-ONCE`). Before this phase the SDK's base URL was
5867
- * `https://api.relyio.com` and its paths were `/{contentType}`, so every
5868
- * versioned request went to a path the router does not serve.
5869
- *
5870
- * Spec: `devtools/docs/guide/engineering/api-contract-spec.md`,
5871
- * `INV-API-CLIENT-IS-DERIVED`.
5872
- */
5873
-
5874
- /** Every path the committed document declares. */
5875
- type ApiPath = keyof paths;
5876
- type Verb = 'get' | 'post' | 'put' | 'patch' | 'delete';
5877
- /** The verbs the document declares on this path — not the seven HTTP has. */
5878
- type ApiMethod<P extends ApiPath> = {
5879
- [M in Verb]: M extends keyof paths[P] ? paths[P][M] extends {
5880
- responses: unknown;
5881
- } ? M : never : never;
5882
- }[Verb];
5883
- type Operation<P extends ApiPath, M extends ApiMethod<P>> = M extends keyof paths[P] ? paths[P][M] : never;
5884
- type JsonBody<R> = R extends {
5885
- content: {
5886
- 'application/json': infer B;
5887
- };
5888
- } ? B : never;
5889
- /**
5890
- * The success body the document declares, preferring 200 where a route serves
5891
- * both. A route with neither — `kind: 'empty'`, which serves 204 — resolves to
5892
- * `never`, and `readPayload` cannot be called on it.
5893
- */
5894
- type ApiSuccessBody<P extends ApiPath, M extends ApiMethod<P>> = Operation<P, M> extends {
5895
- responses: infer R;
5896
- } ? 200 extends keyof R ? JsonBody<R[200]> : 201 extends keyof R ? JsonBody<R[201]> : never : never;
5897
- /**
5898
- * The document's success body with the payload typed as the caller's `T`.
6336
+ * Field type definitions matching @relyio/schema package
5899
6337
  *
5900
- * The array arm is tested **first** on purpose: `{ data: unknown[] }` also
5901
- * satisfies `{ data: unknown }`, so the object arm would swallow every
5902
- * collection and hand a list route's caller a single entity — which is the
5903
- * exact defect class (`ContentClient.children` reading `.data.items` from an
5904
- * object route) that this phase makes unrepresentable.
6338
+ * Every config option here is spelled as `@relyio/schema`'s field config schema spells it, because
6339
+ * the CLI sends a field's `config` to deploy verbatim, and deploy — and `relyio validate` before it —
6340
+ * refuses an option the field's type does not declare, naming its path (REL-1480). This package does
6341
+ * not depend on `@relyio/schema`, so the
6342
+ * options are pinned from `@relyio/codegen-typescript`, which depends on both: its
6343
+ * `src/__tests__/sdk-field-config.types.ts` fails to compile when a key, whether it is required, or
6344
+ * the values it accepts differs between the two (REL-1408).
5905
6345
  */
5906
- type Wire<P extends ApiPath, M extends ApiMethod<P>, T> = ApiSuccessBody<P, M> extends {
5907
- data: unknown[];
5908
- } ? Omit<ApiSuccessBody<P, M>, 'data'> & {
5909
- data: T[];
5910
- } : ApiSuccessBody<P, M> extends {
5911
- data: unknown;
5912
- } ? Omit<ApiSuccessBody<P, M>, 'data'> & {
5913
- data: T;
5914
- } : ApiSuccessBody<P, M>;
5915
6346
  /**
5916
- * The path parameters the document declares for this operation, or `never`
5917
- * where it declares none.
6347
+ * AI configuration. A single prompt — `instructions` — describes what the
6348
+ * element is and how AI should produce its value. Attaches to fields, content
6349
+ * types, components, fieldsets, and (extended) asset types.
5918
6350
  *
5919
- * `never` rather than `{}`: a route with no segments must **forbid** a `path`
5920
- * argument, not merely tolerate an empty one, and `keyof Record<string, never>`
5921
- * is `string`, so an empty-object encoding cannot be told apart from a real
5922
- * one at the type level.
6351
+ * @example
6352
+ * ```typescript
6353
+ * fields.richText('body', {
6354
+ * ai: {
6355
+ * instructions: `
6356
+ * Write in a conversational tone.
6357
+ * Use short paragraphs (2-3 sentences).
6358
+ * Target grade 8 reading level.
6359
+ * `
6360
+ * }
6361
+ * })
6362
+ * ```
5923
6363
  */
5924
- type PathParamsOf<P extends ApiPath, M extends ApiMethod<P>> = Operation<P, M> extends {
5925
- parameters: {
5926
- path?: infer X;
5927
- };
5928
- } ? [X] extends [undefined] ? never : NonNullable<X> : never;
5929
- /** What {@link matchRoute} recovers from a URL the client emitted. */
5930
- interface RouteMatch {
5931
- /** The document's path template — the value a tag translator switches on. */
5932
- path: ApiPath;
5933
- /** The template's `{name}` segments, decoded: the inverse of {@link fillPath}. */
5934
- params: Record<string, string>;
5935
- /** The query string; a key that appears more than once comes back as an array. */
5936
- query: Record<string, string | string[]>;
5937
- }
5938
- interface MatchRouteOptions {
6364
+ interface AIConfig {
5939
6365
  /**
5940
- * The client's `baseUrl`, when it carries a path prefix of its own
5941
- * (`https://example.com/relyio`). Its path is removed before the template is
5942
- * matched. Unneeded for the default `https://api.relyio.com`.
6366
+ * AI brief for this element: what it should contain and how to produce it.
6367
+ *
6368
+ * Used by the Studio authoring agent and — on asset types with
6369
+ * `ai.autoGenerate` — by the automatic post-upload run.
6370
+ *
6371
+ * The fallback chain for AI guidance is:
6372
+ * 1. ai.instructions (most specific)
6373
+ * 2. ui.description (general field description)
6374
+ * 3. Field displayName + type (inferred from semantics)
5943
6375
  */
5944
- baseUrl?: string;
6376
+ instructions?: string;
5945
6377
  }
5946
6378
  /**
5947
- * Recover the route a URL names: the inverse of {@link fillPath}, over the same
5948
- * committed document (`INV-API-CLIENT-IS-DERIVED`).
5949
- *
5950
- * `matchRoute(url).path` is an `ApiPath`, so anything that keys behaviour on a
5951
- * request — a cache-tag translator, say — switches on the document's templates
5952
- * and never on a route table of its own.
5953
- *
5954
- * Returns `null` for a URL no declared template matches — a presigned storage
5955
- * URL, or a path outside `baseUrl` — rather than a guess.
6379
+ * Field-level AI config. `inputs` names the fields this instruction reads.
6380
+ * Unknown ids and cycles are refused when the schema is parsed.
5956
6381
  */
5957
- declare function matchRoute(url: string | URL, options?: MatchRouteOptions): RouteMatch | null;
5958
-
6382
+ interface FieldAIConfig extends AIConfig {
6383
+ /** Field ids this instruction reads. Never inferred from instruction text. */
6384
+ inputs?: string[];
6385
+ }
5959
6386
  /**
5960
- * Configuration types for the RelyIO SDK
6387
+ * Asset-type AI configuration. Extends {@link AIConfig} with `autoGenerate`,
6388
+ * the single switch that turns on automatic field generation after upload.
5961
6389
  */
5962
-
5963
- interface RelyIOConfig {
5964
- /** API key for authentication */
5965
- apiKey: string;
5966
- /** Base URL for the RelyIO API */
5967
- baseUrl?: string;
5968
- /** Dataset to use */
5969
- dataset?: string;
5970
- /**
5971
- * Default locale for all content queries
5972
- * Can be overridden per-query using .locale() or .withLocale()
5973
- *
5974
- * @example
5975
- * const client = createClient({
5976
- * apiKey: '...',
5977
- * locale: 'en-US', // All queries default to English
5978
- * })
5979
- */
5980
- locale?: string;
5981
- /** Request timeout in milliseconds (defaults to 30000) */
5982
- timeout?: number;
5983
- /** Number of retry attempts for failed requests (defaults to 3) */
5984
- retryAttempts?: number;
5985
- /** Whether to use HTTPS (defaults to true) */
5986
- useSsl?: boolean;
5987
- /** Environment mode */
5988
- environment?: 'development' | 'staging' | 'production';
5989
- /**
5990
- * Cache configuration.
5991
- *
5992
- * Declarative only: the client keeps no response cache, and nothing in it reads
5993
- * these values, so every call goes to `fetch`. There is no SDK-side cache to
5994
- * turn off under a framework that caches `fetch` itself (Next.js).
5995
- */
5996
- cache?: CacheConfig;
5997
- /** Real-time configuration */
5998
- realtime?: RealtimeConfig;
5999
- /** Debug configuration */
6000
- debug?: DebugConfig;
6001
- /** Custom headers to include with requests */
6002
- headers?: Record<string, string>;
6390
+ interface AssetAIConfig extends AIConfig {
6003
6391
  /**
6004
- * The function every request to the RelyIO API is sent through. Omit it and the
6005
- * client calls the runtime's `globalThis.fetch`, looked up per request. File
6006
- * bytes an asset upload PUTs straight to a presigned storage URL do not pass
6007
- * through it.
6008
- *
6009
- * The client still builds every request — URL, method, headers, body, signal —
6010
- * and hands this function that `RequestInit` unchanged, retries included, so an
6011
- * `Idempotency-Key` minted for a write is the same on every attempt. Supply one
6012
- * to add what your framework reads off the `RequestInit`, for example Next.js
6013
- * cache tags:
6014
- *
6015
- * @example
6016
- * const client = createClient({
6017
- * apiKey: '...',
6018
- * fetch: (input, init) => fetch(input, { ...init, next: { tags: ['posts'] } }),
6019
- * })
6392
+ * Master switch for automatic, post-upload field generation. When `true`, the
6393
+ * derived analysis agent fills every field that declares `ai.instructions`,
6394
+ * applied as a review proposal. Only meaningful for image asset types in v1.
6020
6395
  */
6021
- fetch?: typeof globalThis.fetch;
6022
- /** Browser-specific configuration */
6023
- browser?: BrowserConfig;
6024
- /**
6025
- * `relyio dev` sandbox detection.
6026
- *
6027
- * When developing under `relyio dev`, the CLI injects an ephemeral sandbox's dataset + scoped
6028
- * preview API key (via env vars or a local `.relyio/dev.json`). The SDK then transparently
6029
- * targets that sandbox instead of production — no code changes required.
6030
- *
6031
- * - Omit (default): detection runs automatically unless `NODE_ENV === 'production'`, so
6032
- * `relyio dev -- pnpm dev` "just works" while production builds stay untouched.
6033
- * - `false`: disable detection entirely (force production targeting even in a dev shell).
6034
- * - `true`: force detection even when `NODE_ENV === 'production'`.
6035
- */
6036
- dev?: boolean;
6396
+ autoGenerate?: boolean;
6037
6397
  }
6038
- interface CacheConfig {
6039
- /** Whether caching is enabled (defaults to true) */
6040
- enabled?: boolean;
6041
- /** Cache TTL in milliseconds (defaults to 5 minutes) */
6042
- ttl?: number;
6043
- /** Maximum number of cache entries (defaults to 1000) */
6044
- maxEntries?: number;
6045
- /** Maximum cache size in bytes (defaults to 50MB) */
6046
- maxSize?: number;
6047
- /** Cache strategies to use */
6048
- strategies?: CacheStrategy[];
6398
+ interface BaseFieldConfig {
6399
+ /** Whether the field is required */
6400
+ required?: boolean;
6401
+ /** Whether the field value must be unique */
6402
+ unique?: boolean;
6403
+ /** Default value for the field. Each field type narrows it to the values its schema accepts. */
6404
+ defaultValue?: unknown;
6049
6405
  }
6050
- interface RealtimeConfig {
6051
- /** Whether real-time features are enabled (defaults to true) */
6052
- enabled?: boolean;
6053
- /** WebSocket URL for real-time connections */
6054
- wsUrl?: string;
6055
- /** Maximum number of reconnection attempts (defaults to 10) */
6056
- maxReconnectAttempts?: number;
6057
- /** Reconnection delay in milliseconds (defaults to 1000) */
6058
- reconnectDelay?: number;
6059
- /** Heartbeat interval in milliseconds (defaults to 30000) */
6060
- heartbeatInterval?: number;
6406
+ interface FieldUIConfig {
6407
+ /** Display name shown in the UI */
6408
+ displayName: string;
6409
+ /** Field description/help text */
6410
+ description?: string;
6411
+ /** Widget-specific options */
6412
+ options?: Record<string, unknown>;
6061
6413
  }
6062
- interface DebugConfig {
6063
- /** Whether debug mode is enabled (defaults to false) */
6064
- enabled?: boolean;
6065
- /** Whether to log network requests (defaults to false) */
6066
- logRequests?: boolean;
6067
- /** Whether to log cache operations (defaults to false) */
6068
- logCache?: boolean;
6069
- /** Whether to log WebSocket events (defaults to false) */
6070
- logWebSocket?: boolean;
6071
- /** Custom logger function */
6072
- logger?: (_level: LogLevel, _message: string, _data?: unknown) => void;
6414
+ interface RuleCondition {
6415
+ field: string;
6416
+ operator: 'equals' | 'not_equals' | 'contains' | 'not_contains' | 'greater_than' | 'less_than' | 'is_empty' | 'is_not_empty';
6417
+ value?: unknown;
6418
+ }
6419
+ interface RuleConditions {
6420
+ mode: 'all' | 'any' | 'none';
6421
+ conditions: RuleCondition[];
6422
+ }
6423
+ interface VisibilityRule {
6424
+ type: 'visibility';
6425
+ action: 'show' | 'hide';
6426
+ conditions: RuleConditions;
6427
+ }
6428
+ interface RequirementRule {
6429
+ type: 'requirement';
6430
+ action: 'require' | 'optional';
6431
+ conditions: RuleConditions;
6432
+ }
6433
+ interface ValidationRule {
6434
+ type: 'validation';
6435
+ action: 'validate' | 'skip';
6436
+ message?: string;
6437
+ conditions: RuleConditions;
6438
+ }
6439
+ interface ReadOnlyRule {
6440
+ type: 'readOnly';
6441
+ action: 'enable' | 'disable';
6442
+ conditions: RuleConditions;
6443
+ }
6444
+ type FieldRule = VisibilityRule | RequirementRule | ValidationRule | ReadOnlyRule;
6445
+ type LocalizationConfig = boolean | string[] | {
6446
+ enabled: boolean;
6447
+ requiredLocales?: string[];
6448
+ fallback?: boolean;
6449
+ };
6450
+ interface FieldDefinition<TId extends string = string, TType extends string = string, TConfig = unknown> {
6451
+ /** Unique field identifier - preserves literal type for type inference */
6452
+ readonly id: TId;
6453
+ /** Field type */
6454
+ readonly type: TType;
6455
+ /** Type-specific configuration */
6456
+ config?: TConfig;
6457
+ /** UI display configuration */
6458
+ ui?: FieldUIConfig;
6459
+ /** AI configuration: generation/review guidance for this field */
6460
+ ai?: FieldAIConfig;
6461
+ /** Dynamic field rules */
6462
+ rules?: FieldRule[];
6463
+ /** Localization settings */
6464
+ localization?: LocalizationConfig;
6465
+ /** Fallback value when field is empty */
6466
+ fallback?: unknown;
6467
+ /** Whether this field is deprecated */
6468
+ deprecated?: boolean;
6073
6469
  }
6074
6470
  /**
6075
- * The numbers the retry backoff is computed from.
6076
- *
6077
- * There is no `retryCondition` here any more. It was a predicate over
6078
- * `(error, attempt)`, which is structurally unable to see the request — so the
6079
- * only rule it could express is "is this error retryable", and the rule that
6080
- * matters is "may this request be sent twice". That question, and the answer,
6081
- * live in `RetryPolicy` (`http/retry-policy.ts`).
6471
+ * Any field definition - used in arrays where we need to preserve specific field types
6082
6472
  */
6083
- interface RetryConfig {
6084
- /** Maximum number of attempts, including the first. */
6085
- maxAttempts: number;
6086
- /** Base delay between retries in milliseconds */
6087
- baseDelay: number;
6088
- /** Maximum delay between retries in milliseconds */
6089
- maxDelay: number;
6090
- /** Backoff factor for exponential backoff */
6091
- backoffFactor: number;
6092
- /** Whether to add jitter to retry delays */
6093
- jitter: boolean;
6473
+ type AnyFieldDefinition = FieldDefinition<string, string, unknown>;
6474
+ interface ShortTextConfig extends BaseFieldConfig {
6475
+ /** Maximum character length */
6476
+ maxLength?: number;
6477
+ /** Regex pattern for validation */
6478
+ pattern?: string;
6479
+ defaultValue?: string;
6094
6480
  }
6095
- interface RequestConfig {
6096
- /** HTTP method */
6097
- method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
6098
- /** Request URL */
6099
- url: string;
6100
- /** Request headers */
6101
- headers?: Record<string, string>;
6102
- /** Request body */
6103
- body?: unknown;
6104
- /** Query parameters */
6105
- params?: Record<string, unknown>;
6106
- /** Request timeout in milliseconds */
6107
- timeout?: number;
6108
- /** Whether to retry this request on failure */
6109
- retryable?: boolean;
6110
- /** Abort signal for canceling requests */
6111
- signal?: AbortSignal;
6112
- /** Additional metadata for the request */
6113
- metadata?: Record<string, unknown>;
6481
+ interface LongTextConfig extends BaseFieldConfig {
6482
+ minLength?: number;
6483
+ maxLength?: number;
6484
+ defaultValue?: string;
6114
6485
  }
6115
- interface ApiResponse<T = unknown> {
6116
- /**
6117
- * The response body exactly as the route's contract declares it —
6118
- * `{ data }`, `{ data, page }`, `{ data, page, meta }` or `{ empty }`.
6119
- *
6120
- * Named `body`, not `data`, because the envelope's own key is `data`: the
6121
- * incumbent `response.data.data` read like a typo and was one 33 times, in
6122
- * six methods that read a key the server never sent. One `data` in the
6123
- * spelling means `readPayload(response.body)` is the only way to reach a
6124
- * payload (`INV-API-CLIENT-IS-DERIVED`).
6125
- */
6126
- body: T;
6127
- /** HTTP status code */
6128
- status: number;
6129
- /** HTTP status text */
6130
- statusText: string;
6131
- /** Response headers */
6132
- headers: Record<string, string>;
6133
- /** Request configuration that generated this response */
6134
- config: RequestConfig;
6135
- /** Whether this response came from cache */
6136
- fromCache?: boolean;
6137
- /** Cache metadata */
6138
- cacheMetadata?: {
6139
- key: string;
6140
- timestamp: number;
6141
- ttl: number;
6142
- };
6486
+ interface RichTextConfig extends BaseFieldConfig {
6487
+ /** Maximum character length for the rich text content */
6488
+ maxLength?: number;
6489
+ /** Allowed formatting options (e.g., bold, italic, underline) */
6490
+ allowedFormats?: string[];
6491
+ /** Allowed embed types (e.g., image, video, code) */
6492
+ embedTypes?: string[];
6493
+ defaultValue?: string;
6143
6494
  }
6144
- interface BrowserConfig {
6145
- /** Whether to include credentials in CORS requests (defaults to true) */
6146
- includeCredentials?: boolean;
6147
- /** Whether to use relative URLs for same-origin requests (defaults to false) */
6148
- useRelativeUrls?: boolean;
6149
- /** Custom CORS error handling */
6150
- onCorsError?: (_error: Error, _context: unknown) => void;
6495
+ interface SlugConfig extends BaseFieldConfig {
6496
+ /** Source field to generate slug from */
6497
+ sourceField?: string;
6498
+ /** Maximum character length */
6499
+ maxLength?: number;
6500
+ defaultValue?: string;
6501
+ }
6502
+ interface UrlConfig extends BaseFieldConfig {
6503
+ /** Allowed URL protocols */
6504
+ allowedProtocols?: ('http' | 'https' | 'ftp' | 'ftps')[];
6505
+ /** Maximum character length */
6506
+ maxLength?: number;
6507
+ defaultValue?: string;
6508
+ }
6509
+ interface EmailConfig extends BaseFieldConfig {
6510
+ /** Maximum character length */
6511
+ maxLength?: number;
6512
+ /** Whitelist of allowed email domains */
6513
+ domainWhitelist?: string[];
6514
+ defaultValue?: string;
6515
+ }
6516
+ interface IntegerConfig extends BaseFieldConfig {
6517
+ min?: number;
6518
+ max?: number;
6519
+ defaultValue?: number;
6520
+ }
6521
+ interface DecimalConfig extends BaseFieldConfig {
6522
+ min?: number;
6523
+ max?: number;
6524
+ decimalPlaces?: number;
6525
+ roundingMode?: 'HALF_UP' | 'FLOOR' | 'CEILING' | 'ROUND' | 'TRUNCATE';
6526
+ defaultValue?: number;
6527
+ }
6528
+ interface BooleanConfig extends BaseFieldConfig {
6529
+ /** The editor's word for `true` (e.g. `'Published'`). */
6530
+ labelTrue?: string;
6531
+ /** The editor's word for `false` (e.g. `'Draft'`). */
6532
+ labelFalse?: string;
6533
+ defaultValue?: boolean;
6151
6534
  }
6152
- type CacheStrategy = 'memory' | 'persistent' | 'network-first' | 'cache-first' | 'stale-while-revalidate';
6153
- type LogLevel = 'debug' | 'info' | 'warn' | 'error';
6154
- type Environment = 'development' | 'staging' | 'production';
6155
6535
  /**
6156
- * `fetch` stays optional after the merge: absent means the runtime's own, and
6157
- * that is read per request rather than captured here, so no default value
6158
- * stands in for it.
6536
+ * `TValue` is the union of the option values and `TMulti` whether the field holds a list of them.
6537
+ * `fields.enum()` infers both from the declaration, so a read of the field is typed by its options
6538
+ * (`INV-SS-TYPES-INFERRED`); the defaults describe any enum field.
6159
6539
  */
6160
- type MergedRelyIOConfig = Required<Omit<RelyIOConfig, 'dataset' | 'locale' | 'dev' | 'fetch'>> & Pick<RelyIOConfig, 'dataset' | 'locale' | 'dev' | 'fetch'>;
6161
-
6540
+ interface EnumConfig<TValue extends string = string, TMulti extends boolean = boolean> extends BaseFieldConfig {
6541
+ /** The values the field may hold, each with the `label` an editor shows. Deploy refuses an option without one. */
6542
+ options: Array<{
6543
+ value: TValue;
6544
+ label: string;
6545
+ }>;
6546
+ multi?: TMulti;
6547
+ /** One option's value, or a list of them when `multi` is true. */
6548
+ defaultValue?: string | string[];
6549
+ }
6550
+ /** A display format is not config: it is `ui.options.format`, where the schema declares it. */
6551
+ interface DateConfig extends BaseFieldConfig {
6552
+ minDate?: string;
6553
+ maxDate?: string;
6554
+ /** `YYYY-MM-DD` */
6555
+ defaultValue?: string;
6556
+ }
6557
+ /** A display format is not config: it is `ui.options.format`, where the schema declares it. */
6558
+ interface DateTimeConfig extends BaseFieldConfig {
6559
+ minDateTime?: string;
6560
+ maxDateTime?: string;
6561
+ /** Store the instant in UTC (`'UTC'`), or keep the author's local time (`'local'`). */
6562
+ timeZoneHandling?: 'UTC' | 'local';
6563
+ defaultValue?: string;
6564
+ }
6162
6565
  /**
6163
- * Base error class for all RelyIO SDK errors
6164
- * Provides consistent error handling, context tracking, and retry logic
6566
+ * `TTo` is the union of the target type ids and `TMulti` whether the field holds a list.
6567
+ * `fields.reference()` infers both, so a read of the field is typed by what it points at
6568
+ * (`INV-SS-TYPES-INFERRED`); the defaults describe any reference field.
6165
6569
  */
6166
- declare abstract class SDKError extends Error {
6167
- /** Unique error code for programmatic error handling */
6168
- abstract readonly code: string;
6169
- /** Whether this error is retryable */
6170
- abstract readonly retryable: boolean;
6171
- /** HTTP status code if applicable */
6172
- readonly statusCode?: number;
6173
- /** Original error that caused this error */
6174
- readonly cause?: Error;
6175
- /** Additional context about the error */
6176
- readonly context?: Record<string, unknown>;
6177
- /** Timestamp when the error occurred */
6178
- readonly timestamp: number;
6179
- constructor(message: string, statusCode?: number, cause?: Error, context?: Record<string, unknown>);
6180
- /**
6181
- * Convert error to JSON for logging and debugging
6182
- */
6183
- toJSON(): {
6184
- name: string;
6185
- message: string;
6186
- code: string;
6187
- statusCode: number | undefined;
6188
- retryable: boolean;
6189
- context: Record<string, unknown> | undefined;
6190
- timestamp: number;
6191
- stack: string | undefined;
6192
- };
6193
- /**
6194
- * Get a user-friendly error message
6195
- */
6196
- getUserMessage(): string;
6197
- /**
6198
- * Get detailed error information for debugging
6199
- */
6200
- getDebugInfo(): string;
6201
- /**
6202
- * Check if this error is of a specific type
6203
- */
6204
- isType(errorType: string): boolean;
6570
+ interface ReferenceConfig<TTo extends string = string, TMulti extends boolean = boolean> extends BaseFieldConfig {
6205
6571
  /**
6206
- * Create a new error with additional context
6572
+ * Target entry type id(s) — content type or asset type ids. Pass a single id
6573
+ * for one target or an array for several. All ids must belong to the same
6574
+ * family (all content types or all asset types).
6207
6575
  */
6208
- withContext(context: Record<string, unknown>): this;
6576
+ to: TTo | TTo[];
6577
+ /** Allow multiple references (the field value is a list). */
6578
+ multi?: TMulti;
6579
+ /** Reference strength for publish/unpublish behavior. */
6580
+ referenceStrength?: 'strong' | 'weak';
6581
+ /** Behavior when a referenced entry is deleted. */
6582
+ onTargetDelete?: 'block' | 'nullify';
6583
+ /** A target entry's id, or a list of them when `multi` is true. */
6584
+ defaultValue?: string | string[];
6585
+ }
6586
+ interface TagsConfig extends BaseFieldConfig {
6587
+ allowCustom?: boolean;
6588
+ predefinedTags?: string[];
6589
+ maxTags?: number;
6590
+ }
6591
+ /**
6592
+ * `TSubfields` is the declared subfields, which `fields.list()` infers so a read types each item by
6593
+ * them (`INV-SS-TYPES-INFERRED`); the default describes any list field.
6594
+ */
6595
+ interface ListConfig<TSubfields extends readonly AnyFieldDefinition[] = FieldDefinition[]> extends BaseFieldConfig {
6596
+ dragAndDrop?: boolean;
6597
+ minItems?: number;
6598
+ maxItems?: number;
6599
+ /** Subfields for list items */
6600
+ subfields?: TSubfields;
6209
6601
  }
6602
+ /**
6603
+ * A component field's config: the options every field type takes, and no more — what the schema
6604
+ * declares for a `component(<id>)` field, which has no config of its own. The validation document
6605
+ * reads `required` from it as it does from any field's.
6606
+ */
6607
+ type ComponentFieldConfig = BaseFieldConfig;
6608
+ type FieldType = 'shortText' | 'longText' | 'richText' | 'slug' | 'url' | 'email' | 'integer' | 'decimal' | 'boolean' | 'enum' | 'date' | 'dateTime' | 'reference' | 'tags' | 'list';
6609
+ type ComponentFieldType = `component(${string})`;
6610
+ type AllFieldTypes = FieldType | ComponentFieldType;
6210
6611
 
6211
6612
  /**
6212
- * Validation errors and related interfaces
6613
+ * Workflow definition for content approval pipelines
6614
+ *
6615
+ * Workflows define approval stages that content must pass through before
6616
+ * publication. They can be configured globally and per content type.
6617
+ *
6618
+ * @example
6619
+ * // Simple workflow with one approval stage
6620
+ * const workflow = defineWorkflow({
6621
+ * enabled: true,
6622
+ * stages: [
6623
+ * defineWorkflowStage('review', {
6624
+ * displayName: 'Editorial Review',
6625
+ * allowedRoles: ['editor', 'admin']
6626
+ * })
6627
+ * ]
6628
+ * })
6629
+ *
6630
+ * @example
6631
+ * // Multi-stage workflow
6632
+ * const workflow = defineWorkflow({
6633
+ * enabled: true,
6634
+ * stages: [
6635
+ * defineWorkflowStage('editorial-review', {
6636
+ * displayName: 'Editorial Review',
6637
+ * allowedRoles: ['editor']
6638
+ * }),
6639
+ * defineWorkflowStage('legal-approval', {
6640
+ * displayName: 'Legal Approval',
6641
+ * requiredApprovals: 1,
6642
+ * allowedRoles: ['legal-reviewer']
6643
+ * }),
6644
+ * defineWorkflowStage('final-approval', {
6645
+ * displayName: 'Final Approval',
6646
+ * requiredApprovals: 2,
6647
+ * allowedRoles: ['publisher', 'admin']
6648
+ * })
6649
+ * ]
6650
+ * })
6213
6651
  */
6214
- interface ValidationViolation {
6215
- field: string;
6216
- message: string;
6217
- code: string;
6218
- value?: unknown;
6219
- path?: string[];
6652
+ /**
6653
+ * Escalation configuration when a workflow stage times out
6654
+ */
6655
+ interface WorkflowEscalation {
6656
+ /** Roles to notify when stage times out */
6657
+ notifyRoles?: string[];
6658
+ /** Roles to escalate to if still pending after another timeout period */
6659
+ escalateToRoles?: string[];
6220
6660
  }
6221
- declare abstract class BaseValidationError extends SDKError {
6222
- readonly retryable = false;
6223
- readonly violations: ValidationViolation[];
6224
- constructor(message?: string, violations?: ValidationViolation[], statusCode?: number, cause?: Error);
6225
- getUserMessage(): string;
6226
- /**
6227
- * Get violations for a specific field
6228
- */
6229
- getViolationsForField(fieldName: string): ValidationViolation[];
6230
- /**
6231
- * Check if a specific field has validation errors
6232
- */
6233
- hasFieldError(fieldName: string): boolean;
6234
- /**
6235
- * Get all validation messages as a formatted string
6236
- */
6237
- getFormattedMessages(): string;
6661
+ /**
6662
+ * Auto-assignment configuration for workflow stages
6663
+ */
6664
+ interface WorkflowAutoAssign {
6665
+ /** Roles whose users should be notified when content enters this stage */
6666
+ roles: string[];
6238
6667
  }
6239
- declare class ValidationError extends BaseValidationError {
6240
- readonly code = "VALIDATION_ERROR";
6668
+ /**
6669
+ * Workflow stage configuration
6670
+ */
6671
+ interface WorkflowStageConfig {
6672
+ /** Human-readable name shown in Studio */
6673
+ displayName: string;
6674
+ /** Optional description for reviewers */
6675
+ description?: string;
6676
+ /** Number of approvals needed to pass this stage (default: 1) */
6677
+ requiredApprovals?: number;
6678
+ /** Roles that can approve this stage */
6679
+ allowedRoles?: string[];
6680
+ /** Auto-assignment configuration */
6681
+ autoAssign?: WorkflowAutoAssign;
6682
+ /** Days before escalation triggers (optional) */
6683
+ timeoutDays?: number;
6684
+ /** Escalation configuration when stage times out */
6685
+ escalation?: WorkflowEscalation;
6241
6686
  }
6242
- declare class InvalidPayloadError extends BaseValidationError {
6243
- readonly code = "INVALID_PAYLOAD";
6244
- constructor(message?: string, violations?: ValidationViolation[], cause?: Error);
6245
- getUserMessage(): string;
6687
+ /**
6688
+ * Complete workflow stage definition
6689
+ */
6690
+ interface WorkflowStageDefinition {
6691
+ readonly _tag: 'workflowStage';
6692
+ readonly id: string;
6693
+ readonly displayName: string;
6694
+ readonly description?: string;
6695
+ /** Absent means the schema's default of 1 */
6696
+ readonly requiredApprovals?: number;
6697
+ readonly allowedRoles?: string[];
6698
+ readonly autoAssign?: WorkflowAutoAssign;
6699
+ readonly timeoutDays?: number;
6700
+ readonly escalation?: WorkflowEscalation;
6246
6701
  }
6247
- declare class SchemaValidationError extends BaseValidationError {
6248
- readonly code = "SCHEMA_VALIDATION_ERROR";
6249
- constructor(message?: string, violations?: ValidationViolation[], cause?: Error);
6250
- getUserMessage(): string;
6702
+ /**
6703
+ * Workflow configuration
6704
+ */
6705
+ interface WorkflowConfig {
6706
+ /** Enable/disable workflow for the branch (default: false) */
6707
+ enabled?: boolean;
6708
+ /** Array of approval stage definitions */
6709
+ stages?: WorkflowStageDefinition[];
6251
6710
  }
6252
- declare class RequiredFieldError extends BaseValidationError {
6253
- readonly code = "REQUIRED_FIELD_ERROR";
6254
- constructor(fieldName: string, message?: string, cause?: Error);
6255
- getUserMessage(): string;
6711
+ /**
6712
+ * Complete workflow definition
6713
+ */
6714
+ interface WorkflowDefinition {
6715
+ readonly _tag: 'workflow';
6716
+ /** Absent means the schema's default, disabled */
6717
+ readonly enabled?: boolean;
6718
+ readonly stages?: WorkflowStageDefinition[];
6256
6719
  }
6257
- declare class InvalidFieldTypeError extends BaseValidationError {
6258
- readonly code = "INVALID_FIELD_TYPE";
6259
- constructor(fieldName: string, expectedType: string, actualType: string, value?: unknown, cause?: Error);
6260
- getUserMessage(): string;
6720
+ /**
6721
+ * Per-content-type workflow configuration
6722
+ */
6723
+ interface ContentTypeWorkflowConfig {
6724
+ /** Enable workflow for this content type (inherits from global if not set) */
6725
+ enabled?: boolean;
6726
+ /** Which global stages apply to this content type (subset of global stages) */
6727
+ stages?: string[];
6728
+ /** Publish automatically after all stages are approved */
6729
+ autoPublish?: boolean;
6730
+ /** Require all locales to be approved before publishing */
6731
+ requireAllLocales?: boolean;
6261
6732
  }
6733
+ /**
6734
+ * Define a workflow stage
6735
+ *
6736
+ * @param id - Unique identifier for the stage (kebab-case or camelCase)
6737
+ * @param config - Stage configuration
6738
+ *
6739
+ * @example
6740
+ * const editorialReview = defineWorkflowStage('editorial-review', {
6741
+ * displayName: 'Editorial Review',
6742
+ * description: 'Content quality and style check',
6743
+ * requiredApprovals: 1,
6744
+ * allowedRoles: ['editor', 'senior-editor']
6745
+ * })
6746
+ *
6747
+ * @example
6748
+ * // Stage with auto-assignment and timeout
6749
+ * const legalApproval = defineWorkflowStage('legal-approval', {
6750
+ * displayName: 'Legal Approval',
6751
+ * allowedRoles: ['legal-reviewer'],
6752
+ * autoAssign: { roles: ['legal-reviewer'] },
6753
+ * timeoutDays: 3,
6754
+ * escalation: {
6755
+ * notifyRoles: ['legal-reviewer'],
6756
+ * escalateToRoles: ['admin']
6757
+ * }
6758
+ * })
6759
+ */
6760
+ declare function defineWorkflowStage(id: string, config: WorkflowStageConfig): WorkflowStageDefinition;
6761
+ /**
6762
+ * Define a workflow configuration
6763
+ *
6764
+ * @param config - Workflow configuration with enabled flag and stages
6765
+ *
6766
+ * @example
6767
+ * // Simple workflow
6768
+ * const workflow = defineWorkflow({
6769
+ * enabled: true,
6770
+ * stages: [
6771
+ * defineWorkflowStage('review', {
6772
+ * displayName: 'Review',
6773
+ * allowedRoles: ['editor']
6774
+ * })
6775
+ * ]
6776
+ * })
6777
+ *
6778
+ * @example
6779
+ * // Disabled workflow (direct publish)
6780
+ * const workflow = defineWorkflow({
6781
+ * enabled: false
6782
+ * })
6783
+ */
6784
+ declare function defineWorkflow(config: WorkflowConfig): WorkflowDefinition;
6785
+ /**
6786
+ * Define content-type specific workflow configuration
6787
+ *
6788
+ * @param config - Content type workflow configuration
6789
+ *
6790
+ * @example
6791
+ * // Use specific stages from global workflow
6792
+ * const blogPostWorkflow = defineContentTypeWorkflow({
6793
+ * enabled: true,
6794
+ * stages: ['editorial-review', 'final-approval'], // Skip legal
6795
+ * autoPublish: false
6796
+ * })
6797
+ *
6798
+ * @example
6799
+ * // Disable workflow for this content type
6800
+ * const quickUpdateWorkflow = defineContentTypeWorkflow({
6801
+ * enabled: false
6802
+ * })
6803
+ *
6804
+ * @example
6805
+ * // Require all locales to be approved
6806
+ * const marketingPageWorkflow = defineContentTypeWorkflow({
6807
+ * enabled: true,
6808
+ * stages: ['translation-review', 'regional-approval'],
6809
+ * requireAllLocales: true
6810
+ * })
6811
+ */
6812
+ declare function defineContentTypeWorkflow(config: ContentTypeWorkflowConfig): ContentTypeWorkflowConfig;
6813
+ /**
6814
+ * Check if a value is a workflow stage definition
6815
+ */
6816
+ declare function isWorkflowStageDefinition(value: unknown): value is WorkflowStageDefinition;
6817
+ /**
6818
+ * Check if a value is a workflow definition
6819
+ */
6820
+ declare function isWorkflowDefinition(value: unknown): value is WorkflowDefinition;
6821
+ /**
6822
+ * Get all stage IDs from a workflow definition
6823
+ */
6824
+ declare function getWorkflowStageIds(workflow: WorkflowDefinition): string[];
6825
+ /**
6826
+ * Find a stage by ID in a workflow definition
6827
+ */
6828
+ declare function findWorkflowStage(workflow: WorkflowDefinition, stageId: string): WorkflowStageDefinition | undefined;
6829
+ /**
6830
+ * Get the next stage after a given stage ID (null if last stage)
6831
+ */
6832
+ declare function getNextWorkflowStage(workflow: WorkflowDefinition, currentStageId: string): WorkflowStageDefinition | null;
6833
+ /**
6834
+ * Get the first stage in the workflow (null if no stages)
6835
+ */
6836
+ declare function getFirstWorkflowStage(workflow: WorkflowDefinition): WorkflowStageDefinition | null;
6837
+ /**
6838
+ * Check if a stage is the final stage in the workflow
6839
+ */
6840
+ declare function isFinalWorkflowStage(workflow: WorkflowDefinition, stageId: string): boolean;
6262
6841
 
6263
6842
  /**
6264
- * Core type definitions for the RelyIO SDK
6843
+ * Singleton content type definition matching @relyio/schema
6844
+ *
6845
+ * In RelyIO, singletons are just content types with a special flag.
6846
+ * They share the same structure as regular content types.
6847
+ *
6848
+ * Uses advanced TypeScript generics to preserve literal field IDs through
6849
+ * the type system, enabling full autocomplete in SDK methods.
6265
6850
  */
6266
6851
 
6267
6852
  /**
6268
- * Base interface for all content items
6269
- * Matches the actual RelyIO API structure with _metadata object
6853
+ * Type alias for a fieldset with any fields.
6270
6854
  */
6271
- interface BaseContent {
6272
- /**
6273
- * RelyIO metadata object containing system fields.
6274
- *
6275
- * `EntryMetadata` rather than a second copy of it: this interface and
6276
- * `schema/define-content-type.ts` declared the same fifteen fields independently, so the
6277
- * per-locale publication half lived twice inside one package and a field added to one was
6278
- * silently absent from the other (`INV-LM-PUBLICATION-IS-REPORTED-PER-LOCALE`).
6279
- */
6280
- _metadata: EntryMetadata & {
6281
- /**
6282
- * Present when the entry is inherited from a source dataset (linked dataset CoW).
6283
- * If set, this entry was not modified in the linked dataset and comes from the source.
6284
- */
6285
- sourceDatasetId?: string;
6286
- };
6855
+ type AnyFieldset$2 = Fieldset<any>;
6856
+ /**
6857
+ * What a singleton takes: a content type's settings, since the schema declares a singleton with the
6858
+ * same `ContentTypeSchema` — except `hierarchical`, which is `false` or absent. A singleton is one
6859
+ * entry, with no parent and no children, and deploy refuses `true` for one
6860
+ * (`SINGLETON_CANNOT_BE_HIERARCHICAL`). It used to take a content type's `boolean` and write `false`
6861
+ * whatever it was given.
6862
+ */
6863
+ interface SingletonConfigWithFields<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> extends Omit<ContentTypeConfigWithFields<TFields>, 'hierarchical'> {
6864
+ hierarchical?: false;
6865
+ }
6866
+ /** {@link SingletonConfigWithFields}, with its fields organised into fieldsets. */
6867
+ interface SingletonConfigWithFieldsets<TFieldsets extends readonly AnyFieldset$2[] = readonly AnyFieldset$2[]> extends Omit<ContentTypeConfigWithFieldsets<TFieldsets>, 'hierarchical'> {
6868
+ hierarchical?: false;
6287
6869
  }
6288
6870
  /**
6289
- * Query conditions for filtering content
6290
- * Supports both content fields and metadata fields
6871
+ * Singleton content type definition - preserves field types for inference
6291
6872
  */
6292
- type WhereClause<T extends BaseContent = BaseContent> = {
6293
- [K in keyof Omit<T, '_metadata'>]?: T[K] | WhereOperator<T[K]>;
6294
- } & {
6295
- /** Metadata field conditions */
6296
- _metadata?: {
6297
- [K in keyof T['_metadata']]?: T['_metadata'][K] | WhereOperator<T['_metadata'][K]>;
6298
- };
6873
+ interface SingletonContentTypeDefinition<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset$2[] = readonly AnyFieldset$2[]> {
6874
+ readonly _tag: 'singletonContentType';
6875
+ readonly name: string;
6876
+ readonly displayName: string;
6877
+ readonly displayNamePlural?: string;
6878
+ readonly description?: string;
6879
+ /** AI configuration: generation guidance + entry intelligence */
6880
+ readonly ai?: AIConfig;
6881
+ /** Field ID to use as entry display title */
6882
+ readonly displayField?: string;
6883
+ readonly hierarchical?: false;
6884
+ readonly accessTags?: string[];
6885
+ /** Workflow configuration for this singleton */
6886
+ readonly workflow?: ContentTypeWorkflowConfig;
6887
+ readonly fields?: TFields;
6888
+ readonly fieldsets?: TFieldsets;
6889
+ }
6890
+ /**
6891
+ * Define a singleton content type
6892
+ *
6893
+ * Singletons are single-instance content types like homepage, site settings, etc.
6894
+ * They use the same field structure as regular content types.
6895
+ *
6896
+ * The generic type parameters preserve the literal field IDs through the type
6897
+ * system, enabling autocomplete in SDK methods.
6898
+ *
6899
+ * @example
6900
+ * const homepage = defineSingletonContentType('homepage', {
6901
+ * displayName: 'Homepage',
6902
+ * fields: [
6903
+ * fields.shortText('heroTitle', { config: { required: true } }),
6904
+ * fields.reference('heroImage', { config: { to: 'productPhoto' } }), // an asset type's entry
6905
+ * ]
6906
+ * })
6907
+ */
6908
+ declare function defineSingletonContentType<TFields extends readonly AnyFieldDefinition[], _TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: SingletonConfigWithFields<TFields>): SingletonContentTypeDefinition<TFields, readonly []>;
6909
+ declare function defineSingletonContentType<_TFields extends readonly AnyFieldDefinition[], TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: SingletonConfigWithFieldsets<TFieldsets>): SingletonContentTypeDefinition<readonly [], TFieldsets>;
6910
+ declare const defineSingleton: typeof defineSingletonContentType;
6911
+ /**
6912
+ * What a read reports about a singleton beside its fields: the committed document's
6913
+ * `SingletonMetadata`, read through `http/api-schema.ts` rather than declared again here.
6914
+ *
6915
+ * Narrower than an entry's — no slug, default locale, available locales or references — and it
6916
+ * names the singleton by `id` and `type`. The hand-written type this replaces declared a `key` and a
6917
+ * `singletonType` the wire does not carry, and `Date` timestamps where it sends ISO 8601 strings.
6918
+ */
6919
+ type SingletonMetadata = components['schemas']['SingletonMetadata'];
6920
+ /**
6921
+ * Type alias for any singleton content type definition.
6922
+ */
6923
+ type AnySingletonContentTypeDefinition = SingletonContentTypeDefinition<any, any>;
6924
+ /**
6925
+ * Infer the TypeScript type from a singleton definition: every field typed as a read returns it
6926
+ * (`schema/infer-fields.ts`), plus `_metadata`. `S` is the schema, as for `InferContentType`.
6927
+ */
6928
+ type InferSingletonContentType<T extends AnySingletonContentTypeDefinition, S extends FieldSchemaContext | undefined = undefined> = FieldValues<DeclaredFields<T>, S> & {
6929
+ _metadata: SingletonMetadata;
6299
6930
  };
6931
+ type InferSingleton<T extends AnySingletonContentTypeDefinition, S extends FieldSchemaContext | undefined = undefined> = InferSingletonContentType<T, S>;
6932
+
6300
6933
  /**
6301
- * Query operators for advanced filtering
6934
+ * Asset type definition matching @relyio/schema AssetTypeSchema
6935
+ *
6936
+ * Asset types are first-class entries (entryType: 'asset') that pair a binary
6937
+ * pipeline family (declared via exactly one kind key: `image`, `video`, or
6938
+ * `file`) with user-defined metadata fields that reuse the standard field
6939
+ * system — including fieldsets, workflow, access tags, and AI config.
6940
+ *
6941
+ * The kind config blocks are strongly typed below (mirroring the zod-inferred
6942
+ * `@relyio/schema` types), so authoring asset types in TypeScript gets full
6943
+ * autocomplete. The authoritative validation still lives in @relyio/schema's
6944
+ * `AssetTypesValidator` and runs on deploy.
6302
6945
  */
6303
- interface WhereOperator<T = unknown> {
6304
- /** Equals */
6305
- $eq?: T;
6306
- /** Not equals */
6307
- $ne?: T;
6308
- /** Greater than */
6309
- $gt?: T;
6310
- /** Greater than or equal */
6311
- $gte?: T;
6312
- /** Less than */
6313
- $lt?: T;
6314
- /** Less than or equal */
6315
- $lte?: T;
6316
- /** In array */
6317
- $in?: T[];
6318
- /** Not in array */
6319
- $nin?: T[];
6320
- /** Contains (for strings) */
6321
- $contains?: string;
6322
- /** Starts with (for strings) */
6323
- $startsWith?: string;
6324
- /** Ends with (for strings) */
6325
- $endsWith?: string;
6326
- /** Regular expression match */
6327
- $regex?: string;
6328
- /** Exists (field is not null/undefined) */
6329
- $exists?: boolean;
6946
+
6947
+ /** Resize fit modes supported by the Cloudflare Images binding. */
6948
+ type ImageFitMode = 'cover' | 'contain' | 'fill' | 'inside' | 'outside';
6949
+ /** Output formats the Cloudflare Images binding can produce (`heic` is input-only). */
6950
+ type ImageOutputFormat = 'avif' | 'webp' | 'jpeg' | 'png';
6951
+ /** Shared image transform props (CF Images vocabulary). */
6952
+ interface ImageTransform {
6953
+ width?: number;
6954
+ height?: number;
6955
+ fit?: ImageFitMode;
6956
+ format?: ImageOutputFormat;
6957
+ quality?: number;
6958
+ }
6959
+ /** Upload gate for the `image` kind (rejects bad files at the door). */
6960
+ interface ImageUploadConfig {
6961
+ allowedMimeTypes?: string[];
6962
+ maxFileSize?: number;
6963
+ minWidth?: number;
6964
+ maxWidth?: number;
6965
+ minHeight?: number;
6966
+ maxHeight?: number;
6967
+ /** `width:height`, e.g. `16:9`. */
6968
+ aspectRatio?: string;
6969
+ }
6970
+ /** Upload gate for the `video` kind. */
6971
+ interface VideoUploadConfig {
6972
+ allowedMimeTypes?: string[];
6973
+ maxFileSize?: number;
6974
+ maxDuration?: number;
6975
+ minWidth?: number;
6976
+ maxWidth?: number;
6977
+ minHeight?: number;
6978
+ maxHeight?: number;
6979
+ }
6980
+ /** Upload gate for the `file` kind (MIME + size only in v1). */
6981
+ interface FileUploadConfig {
6982
+ allowedMimeTypes?: string[];
6983
+ maxFileSize?: number;
6984
+ }
6985
+ /** Delivery rendition preset (max 20 per asset type), applied on the fly by the gateway. */
6986
+ interface VariantDefinition extends ImageTransform {
6987
+ /** Variant id; must start with a letter (codegen emits the `*Variant` union from these). */
6988
+ id: string;
6330
6989
  }
6331
6990
  /**
6332
- * Sort options for query results
6991
+ * Ingest normalization of the canonical stored original (image v1 only).
6992
+ * `true` expands to the platform default on deploy.
6333
6993
  */
6334
- type SortOptions<T extends BaseContent = BaseContent> = {
6335
- [K in keyof T]?: 'asc' | 'desc';
6336
- };
6994
+ type ImageSourceConfig = boolean | (ImageTransform & {
6995
+ stripMetadata?: boolean;
6996
+ });
6997
+ /** EXIF retention policy for the `image` kind (plan 15). */
6998
+ interface ImageExifConfig {
6999
+ /** Retain GPS in `extracted.exif` (default strips it for privacy). */
7000
+ keepGps?: boolean;
7001
+ }
7002
+ /** Image kind config (`upload`, `source`, `variants`, `localization`, `exif`). */
7003
+ interface ImageKindConfig {
7004
+ upload?: ImageUploadConfig;
7005
+ source?: ImageSourceConfig;
7006
+ /** Max 20 variants per asset type. */
7007
+ variants?: VariantDefinition[];
7008
+ localization?: LocalizationConfig;
7009
+ exif?: ImageExifConfig;
7010
+ }
7011
+ /** Poster/thumbnail strategy for the `video` kind. */
7012
+ interface VideoPosterConfig {
7013
+ /** 0.0–1.0 → Stream thumbnailTimestampPct. */
7014
+ defaultTimestampPct?: number;
7015
+ /** Enable an animated preview (gif/webp). */
7016
+ animated?: boolean;
7017
+ }
7018
+ /** Subtitle track strategy for the `video` kind. */
7019
+ interface VideoCaptionsConfig {
7020
+ enabled?: boolean;
7021
+ requiredLocales?: string[];
7022
+ /** Stream AI transcription when no track is uploaded. */
7023
+ autoGenerate?: boolean;
7024
+ }
7025
+ /** Downloadable-MP4 toggle for the `video` kind. */
7026
+ interface VideoDownloadConfig {
7027
+ enabled?: boolean;
7028
+ }
7029
+ /** Stream watermark profile for the `video` kind. */
7030
+ interface VideoWatermarkConfig {
7031
+ enabled?: boolean;
7032
+ /** Account-level Stream watermark profile uid. */
7033
+ profileId?: string;
7034
+ }
6337
7035
  /**
6338
- * Query options for content requests
7036
+ * Video kind config (`upload`, `poster`, `captions`, `download`, `watermark`,
7037
+ * `localization`). Stream auto-generates the ABR ladder — there is intentionally
7038
+ * NO `variants` and NO `encoding` block.
6339
7039
  */
6340
- interface QueryOptions<T extends BaseContent = BaseContent> {
6341
- /** Conditions to filter by */
6342
- where?: WhereClause<T>;
6343
- /** Fields to include in response */
6344
- select?: (keyof T)[];
6345
- /** Related content to include */
6346
- include?: string[];
6347
- /** Sort options */
6348
- sort?: SortOptions<T>;
6349
- /** Limit number of results */
6350
- limit?: number;
6351
- /** Offset for pagination */
6352
- offset?: number;
6353
- /** Cursor for cursor-based pagination */
6354
- cursor?: string;
7040
+ interface VideoKindConfig {
7041
+ upload?: VideoUploadConfig;
7042
+ poster?: VideoPosterConfig;
7043
+ captions?: VideoCaptionsConfig;
7044
+ download?: VideoDownloadConfig;
7045
+ watermark?: VideoWatermarkConfig;
7046
+ localization?: LocalizationConfig;
7047
+ }
7048
+ /** Malware scan config for the `file` kind (plan 19). */
7049
+ interface FileScanConfig {
7050
+ enabled?: boolean;
7051
+ blockUntilClean?: boolean;
7052
+ }
7053
+ /** File kind config (`upload`, `localization`, `scan`, `extractText`). */
7054
+ interface FileKindConfig {
7055
+ upload?: FileUploadConfig;
7056
+ localization?: LocalizationConfig;
7057
+ /** Malware scan (plan 19). */
7058
+ scan?: FileScanConfig;
7059
+ /** Extract searchable text + metadata for PDFs (plan 15). */
7060
+ extractText?: boolean;
7061
+ }
7062
+ interface AssetTypeBaseConfig {
7063
+ /** Display name shown in the UI */
7064
+ displayName: string;
7065
+ /** Plural display name (e.g., "Product Photos" for "Product Photo") */
7066
+ displayNamePlural?: string;
7067
+ /** Description of the asset type */
7068
+ description?: string;
7069
+ /**
7070
+ * AI configuration. `ai.instructions` is an optional global brief; per-field
7071
+ * `ai.instructions` describe individual fields. `ai.autoGenerate` (image
7072
+ * kind, v1) is the master switch: when true, the derived analysis agent runs
7073
+ * after upload and fills every field that declares `ai.instructions`, applied
7074
+ * as a review proposal.
7075
+ */
7076
+ ai?: AssetAIConfig;
7077
+ /** Field ID to use as the asset display title */
7078
+ displayField?: string;
7079
+ /** Access tags for role-based access control */
7080
+ accessTags?: string[];
7081
+ /** Workflow configuration for this asset type */
7082
+ workflow?: ContentTypeWorkflowConfig;
7083
+ /** Image pipeline config — mutually exclusive with `video`/`file` */
7084
+ image?: ImageKindConfig;
7085
+ /** Video pipeline config — mutually exclusive with `image`/`file` */
7086
+ video?: VideoKindConfig;
7087
+ /** File pipeline config — mutually exclusive with `image`/`video` */
7088
+ file?: FileKindConfig;
6355
7089
  }
6356
7090
  /**
6357
- * Content creation input - excludes metadata fields that are managed by the system
7091
+ * Type alias for a fieldset with any fields.
6358
7092
  */
6359
- type CreateInput<T extends BaseContent> = Omit<T, '_metadata'> & {
6360
- /** Optional metadata that can be set during creation */
6361
- _metadata?: {
6362
- /** Parent ID for hierarchical content */
6363
- parentId?: string | null;
6364
- /** Content locale */
6365
- locale?: string;
6366
- };
6367
- };
7093
+ type AnyFieldset$1 = Fieldset<any>;
7094
+ /** Asset type configuration using direct fields. */
7095
+ interface AssetTypeConfigWithFields<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> extends AssetTypeBaseConfig {
7096
+ /** Direct field definitions - preserves literal types */
7097
+ fields: TFields;
7098
+ /** Cannot have fieldsets when using fields */
7099
+ fieldsets?: never;
7100
+ }
7101
+ /** Asset type configuration using fieldsets. */
7102
+ interface AssetTypeConfigWithFieldsets<TFieldsets extends readonly AnyFieldset$1[] = readonly AnyFieldset$1[]> extends AssetTypeBaseConfig {
7103
+ /** Field organization via fieldsets - preserves literal types */
7104
+ fieldsets: TFieldsets;
7105
+ /** Cannot have direct fields when using fieldsets */
7106
+ fields?: never;
7107
+ }
6368
7108
  /**
6369
- * Content update input - excludes system-managed metadata fields
7109
+ * Asset type configuration with no metadata fields: the asset is its file. `AssetTypeSchema` makes
7110
+ * `fields` and `fieldsets` both optional, so this is an asset type deploy accepts (REL-1454).
6370
7111
  */
6371
- type UpdateInput<T extends BaseContent> = Partial<Omit<T, '_metadata'>> & {
6372
- /** Optional metadata that can be updated */
6373
- _metadata?: {
6374
- /** Parent ID for hierarchical content */
6375
- parentId?: string | null;
6376
- /** Content locale */
6377
- locale?: string;
6378
- };
7112
+ interface AssetTypeConfigWithoutFields extends AssetTypeBaseConfig {
7113
+ fields?: never;
7114
+ fieldsets?: never;
7115
+ }
7116
+ /** Asset type configuration: direct fields, fieldsets, or neither. */
7117
+ type AssetTypeConfig<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset$1[] = readonly AnyFieldset$1[]> = AssetTypeConfigWithFields<TFields> | AssetTypeConfigWithFieldsets<TFieldsets> | AssetTypeConfigWithoutFields;
7118
+ /** Asset type definition - preserves field types for inference. */
7119
+ interface AssetTypeDefinition<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset$1[] = readonly AnyFieldset$1[]> {
7120
+ readonly _tag: 'assetType';
7121
+ readonly name: string;
7122
+ readonly displayName: string;
7123
+ readonly displayNamePlural?: string;
7124
+ readonly description?: string;
7125
+ readonly ai?: AssetAIConfig;
7126
+ readonly displayField?: string;
7127
+ readonly accessTags?: string[];
7128
+ readonly workflow?: ContentTypeWorkflowConfig;
7129
+ readonly image?: ImageKindConfig;
7130
+ readonly video?: VideoKindConfig;
7131
+ readonly file?: FileKindConfig;
7132
+ readonly fields?: TFields;
7133
+ readonly fieldsets?: TFieldsets;
7134
+ }
7135
+ /**
7136
+ * Define an asset type.
7137
+ *
7138
+ * Exactly one kind key (`image`, `video`, or `file`) must be supplied. Metadata
7139
+ * fields are optional: declare `fields`, `fieldsets`, or neither. The generic
7140
+ * type parameters preserve literal field IDs for inference, mirroring
7141
+ * `defineContentType`.
7142
+ *
7143
+ * @example
7144
+ * const productPhoto = defineAssetType('productPhoto', {
7145
+ * displayName: 'Product Photo',
7146
+ * image: {
7147
+ * upload: { allowedMimeTypes: ['image/jpeg', 'image/png', 'image/webp'], maxFileSize: 10485760 },
7148
+ * variants: [{ id: 'thumb', width: 200, height: 200, fit: 'cover', format: 'webp' }],
7149
+ * },
7150
+ * fields: [
7151
+ * fields.shortText('altText', { ui: { displayName: 'Alt Text' } }),
7152
+ * ],
7153
+ * })
7154
+ */
7155
+ declare function defineAssetType(name: string, config: AssetTypeConfigWithoutFields): AssetTypeDefinition<readonly [], readonly []>;
7156
+ declare function defineAssetType<TFields extends readonly AnyFieldDefinition[], _TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: AssetTypeConfigWithFields<TFields>): AssetTypeDefinition<TFields, readonly []>;
7157
+ declare function defineAssetType<_TFields extends readonly AnyFieldDefinition[], TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: AssetTypeConfigWithFieldsets<TFieldsets>): AssetTypeDefinition<readonly [], TFieldsets>;
7158
+ /**
7159
+ * Type alias for any asset type definition.
7160
+ */
7161
+ type AnyAssetTypeDefinition = AssetTypeDefinition<any, any>;
7162
+ /**
7163
+ * Infer the TypeScript type from an asset type definition.
7164
+ *
7165
+ * Mirrors {@link InferContentType}: produces the (optional) metadata field shape
7166
+ * plus `_metadata`, so it is assignable to `BaseContent` and can parametrize
7167
+ * `AssetClient<T>`. The runtime `file`/`urls` blocks are layered on by the
7168
+ * client's `AssetEntryResponse<T>` return type, not here, to keep the schema
7169
+ * layer free of any dependency on the client layer.
7170
+ */
7171
+ type InferAssetType<T extends AnyAssetTypeDefinition, S extends FieldSchemaContext | undefined = undefined> = FieldValues<DeclaredFields<T>, S> & {
7172
+ _metadata: EntryMetadata;
6379
7173
  };
7174
+
6380
7175
  /**
6381
- * What the entry list serves — **read from the committed document**, not
6382
- * written down here.
7176
+ * What a read returns for each field, derived from the field's declaration (`INV-SS-TYPES-INFERRED`).
6383
7177
  *
6384
- * It used to be a hand-written `{ items, total?, hasMore, nextCursor }`, and
6385
- * every field of it was wrong after API2: the route is the cursor dialect, so
6386
- * the body is `{ data, page: { nextCursor, hasMore } }` and there is no total
6387
- * at all. `execute()` therefore resolved `result.items` — `undefined` — for
6388
- * every caller of the SDK's most-used method, and nothing could see it because
6389
- * the type said otherwise.
7178
+ * Every `Infer*` in this package — content types, singletons, asset types, settings groups — types
7179
+ * its fields here and nowhere else, so an entry, a referenced entry, a component and a list item are
7180
+ * typed by one table. The types describe **what a read returns**, which is not always what a write
7181
+ * accepts:
6390
7182
  *
6391
- * Deriving it means the next dialect change is a compile error in user code
6392
- * rather than an `undefined` at runtime (`INV-API-CLIENT-IS-DERIVED`).
7183
+ * - `richText` is the stored HTML string; `date` is `YYYY-MM-DD` and `dateTime` an ISO 8601 string —
7184
+ * the client does not revive dates.
7185
+ * - A `reference` is the target's id until `include` names it, and then the target entry itself.
7186
+ * The type cannot see `include`, so it is both: `string | <entry>`. A single reference whose target
7187
+ * was deleted with `onTargetDelete: 'nullify'` is `null`.
7188
+ * - A localized field is the value for the one locale the read composed, like any other field; the
7189
+ * other locales of a `locales=` read sit under `_metadata.localizations`, not here.
7190
+ * - Every field is optional. The wire omits a field with no value — a draft, a `fields` projection, a
7191
+ * locale with nothing to fall back to, an entry older than a field — so `required` does not make
7192
+ * one present.
6393
7193
  */
6394
- type ContentQueryResult<T extends BaseContent = BaseContent> = Wire<'/v1/{contentType}', 'get', T>;
7194
+
6395
7195
  /**
6396
- * Singleton content (single instance per type)
6397
- * Matches the actual RelyIO API structure
7196
+ * The parts of a schema a field's value type reads: the types a reference may expand to and the
7197
+ * components a component field names. Structural, so every `defineSchema()` result fits.
7198
+ *
7199
+ * Without one in view — `InferContentType<typeof post>` with no second argument — a reference
7200
+ * expands to an {@link UnresolvedEntry} and a component to an {@link UnresolvedComponent}: the field
7201
+ * is still typed, but what it names is not.
6398
7202
  */
6399
- interface SingletonContent {
6400
- /** Content fields at top level */
6401
- [key: string]: unknown;
6402
- /** RelyIO metadata object for singletons */
6403
- _metadata: {
6404
- /** Singleton key identifier */
6405
- key: string;
6406
- /** When the singleton was created */
6407
- createdAt: Date;
6408
- /** When the singleton was last updated */
6409
- updatedAt: Date;
6410
- /** Singleton type identifier */
6411
- singletonType: string;
6412
- /** Content version */
6413
- version: number;
6414
- /** Content locale */
6415
- locale: string;
6416
- };
7203
+ interface FieldSchemaContext {
7204
+ readonly contentTypes: object;
7205
+ readonly components: object;
7206
+ readonly singletonContentTypes: object;
7207
+ readonly assetTypes?: object;
7208
+ }
7209
+ /** A schema in view, or `undefined` when none is. */
7210
+ type Context = FieldSchemaContext | undefined;
7211
+ /** An expanded reference whose target type is not in view: an entry, with fields nothing declared. */
7212
+ interface UnresolvedEntry {
7213
+ _metadata: EntryMetadata;
7214
+ [field: string]: unknown;
6417
7215
  }
7216
+ /** A component whose definition is not in view: an object, with fields nothing declared. */
7217
+ type UnresolvedComponent = Record<string, unknown>;
6418
7218
  /**
6419
- * Settings group
7219
+ * One row per field type the schema declares. `OverEveryFieldType` makes the table exhaustive by
7220
+ * construction: a field type added to `FieldType` without a row here fails to compile, rather than
7221
+ * reading as `unknown`.
6420
7222
  */
6421
- interface SettingsGroup {
6422
- /** Unique identifier for the settings group */
6423
- id: string;
6424
- /** Settings group name */
6425
- name: string;
6426
- /** Settings data */
6427
- settings: Record<string, unknown>;
6428
- /** When the settings were created */
6429
- createdAt: string;
6430
- /** When the settings were last updated */
6431
- updatedAt: string;
6432
- }
7223
+ type OverEveryFieldType<T extends {
7224
+ [K in FieldType]: unknown;
7225
+ }> = T;
7226
+ type FieldValueByType<C, S extends Context> = OverEveryFieldType<{
7227
+ shortText: string;
7228
+ longText: string;
7229
+ /** The stored HTML. */
7230
+ richText: string;
7231
+ email: string;
7232
+ url: string;
7233
+ slug: string;
7234
+ integer: number;
7235
+ decimal: number;
7236
+ boolean: boolean;
7237
+ enum: EnumValue<C>;
7238
+ /** `YYYY-MM-DD`. */
7239
+ date: string;
7240
+ /** ISO 8601. */
7241
+ dateTime: string;
7242
+ reference: ReferenceValue<C, S>;
7243
+ tags: string[];
7244
+ list: ListValue<C, S>;
7245
+ }>;
7246
+ /**
7247
+ * The value a read returns for field `F`.
7248
+ *
7249
+ * The last arm is the one `unknown` in this module, and it is deliberate: a field whose `type` is not
7250
+ * a declared literal — a definition built from a plain `string` rather than through `fields.*` — has
7251
+ * no row to read.
7252
+ */
7253
+ 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;
7254
+ /** The fields `F` (a union of field definitions) as an object, each optional — see the module note. */
7255
+ type FieldValues<F extends AnyFieldDefinition, S extends Context = undefined> = {
7256
+ [K in F['id']]?: FieldValue<Extract<F, {
7257
+ readonly id: K;
7258
+ }>, S>;
7259
+ };
7260
+ /**
7261
+ * Every field a definition declares, directly or through its fieldsets, as one union — the one walk
7262
+ * over `fields` / `fieldsets` every `Infer*` shares.
7263
+ */
7264
+ type DeclaredFields<T extends {
7265
+ readonly fields?: unknown;
7266
+ readonly fieldsets?: unknown;
7267
+ }> = Extract<(NonNullable<T['fields']> extends readonly (infer F)[] ? F : never) | (NonNullable<T['fieldsets']> extends readonly (infer FS)[] ? FS extends {
7268
+ readonly fields: readonly (infer F)[];
7269
+ } ? F : never : never), AnyFieldDefinition>;
7270
+ /** `multi` as declared: `true`, `false`, or `boolean` when the declaration does not say. */
7271
+ type Multiplicity<C> = C extends {
7272
+ readonly multi?: infer M;
7273
+ } ? M : false;
7274
+ /** One `V`, a list of them, or — when `multi` is not a literal — either. */
7275
+ type OneOrMany<C, V> = [Multiplicity<C>] extends [true] ? V[] : [Multiplicity<C>] extends [false | undefined] ? V : V | V[];
7276
+ type EnumValue<C> = OneOrMany<C, C extends {
7277
+ readonly options: ReadonlyArray<{
7278
+ readonly value: infer V;
7279
+ }>;
7280
+ } ? V : string>;
7281
+ type ReferenceTarget<C> = C extends {
7282
+ readonly to: infer T;
7283
+ } ? T extends readonly (infer E)[] ? E : T : string;
7284
+ /** `R[K]` where `R` declares `K`. A `Record<string, never>` default declares nothing. */
7285
+ type Declared<R, K> = K extends keyof R ? R[K] : never;
7286
+ type ContentEntryOf<D, S extends Context> = D extends ContentTypeDefinition ? InferContentType<D, S> : never;
7287
+ type SingletonEntryOf<D, S extends Context> = D extends SingletonContentTypeDefinition ? InferSingletonContentType<D, S> : never;
7288
+ type AssetEntryOf<D, S extends Context> = D extends AssetTypeDefinition ? InferAssetType<D, S> : never;
7289
+ type OrUnresolved<T> = [T] extends [never] ? UnresolvedEntry : T;
7290
+ /** What `include` expands a reference to `Target` into: that type's entry, typed by the schema. */
7291
+ 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;
7292
+ 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>;
7293
+ type ComponentFields<D, S extends Context> = [D] extends [never] ? UnresolvedComponent : D extends {
7294
+ readonly fields: readonly (infer F)[];
7295
+ } ? FieldValues<Extract<F, AnyFieldDefinition>, S> : UnresolvedComponent;
7296
+ type ComponentValue<Id extends string, S extends Context> = S extends FieldSchemaContext ? ComponentFields<Declared<S['components'], Id>, S> : UnresolvedComponent;
7297
+ /**
7298
+ * A list with subfields is a list of objects typed by them; a list without is a list of strings,
7299
+ * which is what the validation document enforces for it.
7300
+ */
7301
+ type ListValue<C, S extends Context> = C extends {
7302
+ readonly subfields?: infer Sub;
7303
+ } ? Sub extends readonly (infer F)[] ? [F] extends [never] ? string[] : Array<FieldValues<Extract<F, AnyFieldDefinition>, S>> : string[] : string[];
7304
+
7305
+ /**
7306
+ * Content type definition matching @relyio/schema ContentTypeSchema
7307
+ *
7308
+ * Uses advanced TypeScript generics to preserve each field's declaration through the type system,
7309
+ * so `InferContentType` types every field by what a read returns and `where()` autocompletes.
7310
+ */
7311
+
6433
7312
  /**
6434
- * Custom query definition
7313
+ * Fieldset for organizing related fields
7314
+ * Generic over fields to preserve literal field IDs
6435
7315
  */
6436
- interface CustomQuery<TVariables = unknown, TResponse = unknown> {
6437
- /** Query name */
6438
- name: string;
6439
- /** Query variables */
6440
- variables?: TVariables;
6441
- /** Expected response type */
6442
- response?: TResponse;
7316
+ interface Fieldset<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
7317
+ /** Unique fieldset identifier */
7318
+ readonly id: string;
7319
+ /** Display name shown in the UI */
7320
+ readonly displayName: string;
7321
+ /** Optional description */
7322
+ readonly description?: string;
7323
+ /** Whether an editing surface shows this fieldset collapsed to begin with */
7324
+ readonly collapsedByDefault?: boolean;
7325
+ /** AI configuration for content generation and review */
7326
+ readonly ai?: AIConfig;
7327
+ /** Fields within this fieldset - preserves literal types */
7328
+ readonly fields: TFields;
6443
7329
  }
6444
7330
  /**
6445
- * Content type schema information
7331
+ * Type alias for a fieldset with any fields.
7332
+ * Used in generic constraints where we need to accept any fieldset type.
6446
7333
  */
6447
- interface ContentTypeSchema {
6448
- /** Content type name */
6449
- name: string;
6450
- /** Display name */
7334
+ type AnyFieldset = Fieldset<any>;
7335
+ /**
7336
+ * Create a fieldset for organizing fields
7337
+ * Generic to preserve the specific field types for type inference
7338
+ *
7339
+ * @example
7340
+ * const seoFieldset = fieldset('seo', {
7341
+ * displayName: 'SEO Settings',
7342
+ * fields: [
7343
+ * fields.shortText('metaTitle', { config: { maxLength: 60 } }),
7344
+ * fields.longText('metaDescription', { config: { maxLength: 160 } }),
7345
+ * ]
7346
+ * })
7347
+ */
7348
+ declare function fieldset<TFields extends readonly AnyFieldDefinition[]>(id: string, config: {
6451
7349
  displayName: string;
6452
- /** Description */
6453
7350
  description?: string;
6454
- /** Field definitions */
6455
- fields: FieldDefinition[];
6456
- /** Whether this content type is hierarchical */
7351
+ /** Show the fieldset collapsed until an editor opens it */
7352
+ collapsedByDefault?: boolean;
7353
+ ai?: AIConfig;
7354
+ fields: TFields;
7355
+ }): Fieldset<TFields>;
7356
+ /**
7357
+ * Content type configuration using direct fields
7358
+ * Generic to preserve literal field IDs for type inference
7359
+ */
7360
+ interface ContentTypeConfigWithFields<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[]> {
7361
+ /** Display name shown in the UI */
7362
+ displayName: string;
7363
+ /** Plural display name shown in the UI (e.g., "Products" for "Product") */
7364
+ displayNamePlural?: string;
7365
+ /** Description of the content type */
7366
+ description?: string;
7367
+ /** AI configuration: generation/review guidance */
7368
+ ai?: AIConfig;
7369
+ /**
7370
+ * Field ID to use as entry display title in lists, references, and editor header.
7371
+ * If not set, falls back to: title → name → slug → first shortText field → entryUid
7372
+ */
7373
+ displayField?: string;
7374
+ /** Whether this content type supports hierarchical (parent-child) relationships */
6457
7375
  hierarchical?: boolean;
6458
- /** Preview configuration */
6459
- preview?: {
6460
- select?: Record<string, string>;
6461
- prepare?: (_selection: Record<string, unknown>) => Record<string, unknown>;
6462
- };
7376
+ /** Access tags for role-based access control */
7377
+ accessTags?: string[];
7378
+ /** Workflow configuration for this content type */
7379
+ workflow?: ContentTypeWorkflowConfig;
7380
+ /** Direct field definitions - preserves literal types */
7381
+ fields: TFields;
7382
+ /** Cannot have fieldsets when using fields */
7383
+ fieldsets?: never;
6463
7384
  }
6464
7385
  /**
6465
- * Field definition for content types
7386
+ * Content type configuration using fieldsets
7387
+ * Generic to preserve fieldset field types
6466
7388
  */
6467
- interface FieldDefinition {
6468
- /** Field name */
6469
- name: string;
6470
- /** Field type */
6471
- type: FieldTypeName;
6472
- /** Display title */
6473
- title?: string;
6474
- /** Field description */
7389
+ interface ContentTypeConfigWithFieldsets<TFieldsets extends readonly AnyFieldset[] = readonly AnyFieldset[]> {
7390
+ /** Display name shown in the UI */
7391
+ displayName: string;
7392
+ /** Plural display name shown in the UI (e.g., "Products" for "Product") */
7393
+ displayNamePlural?: string;
7394
+ /** Description of the content type */
6475
7395
  description?: string;
6476
- /** Whether field is required */
6477
- required?: boolean;
6478
- /** Default value */
6479
- default?: unknown;
6480
- /** Validation rules */
6481
- validation?: ValidationRule[];
6482
- /** Field options */
6483
- options?: FieldOptions;
7396
+ /** AI configuration: generation/review guidance */
7397
+ ai?: AIConfig;
7398
+ /**
7399
+ * Field ID to use as entry display title in lists, references, and editor header.
7400
+ * If not set, falls back to: title → name → slug → first shortText field → entryUid
7401
+ */
7402
+ displayField?: string;
7403
+ /** Access tags for role-based access control */
7404
+ accessTags?: string[];
7405
+ /** Whether this content type supports hierarchical (parent-child) relationships */
7406
+ hierarchical?: boolean;
7407
+ /** Workflow configuration for this content type */
7408
+ workflow?: ContentTypeWorkflowConfig;
7409
+ /** Field organization via fieldsets - preserves literal types */
7410
+ fieldsets: TFieldsets;
7411
+ /** Cannot have direct fields when using fieldsets */
7412
+ fields?: never;
6484
7413
  }
6485
7414
  /**
6486
- * Supported field type names (string identifiers)
7415
+ * Content type configuration (either fields OR fieldsets, not both)
6487
7416
  */
6488
- type FieldTypeName = 'string' | 'number' | 'boolean' | 'date' | 'datetime' | 'text' | 'markdown' | 'richtext' | 'slug' | 'url' | 'email' | 'image' | 'file' | 'reference' | 'array' | 'object' | 'geopoint' | 'color';
7417
+ type ContentTypeConfig<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset[] = readonly AnyFieldset[]> = ContentTypeConfigWithFields<TFields> | ContentTypeConfigWithFieldsets<TFieldsets>;
6489
7418
  /**
6490
- * Field validation rules
7419
+ * Content type definition - preserves field types for inference
6491
7420
  */
6492
- interface ValidationRule {
6493
- /** Rule type */
6494
- type: 'required' | 'min' | 'max' | 'pattern' | 'custom';
6495
- /** Rule value */
6496
- value?: unknown;
6497
- /** Error message */
6498
- message?: string;
7421
+ interface ContentTypeDefinition<TFields extends readonly AnyFieldDefinition[] = readonly AnyFieldDefinition[], TFieldsets extends readonly AnyFieldset[] = readonly AnyFieldset[]> {
7422
+ readonly _tag: 'contentType';
7423
+ readonly name: string;
7424
+ readonly displayName: string;
7425
+ readonly displayNamePlural?: string;
7426
+ readonly description?: string;
7427
+ /** AI configuration: generation/review guidance */
7428
+ readonly ai?: AIConfig;
7429
+ /** Field ID to use as entry display title */
7430
+ readonly displayField?: string;
7431
+ readonly hierarchical?: boolean;
7432
+ readonly accessTags?: string[];
7433
+ readonly workflow?: ContentTypeWorkflowConfig;
7434
+ readonly fields?: TFields;
7435
+ readonly fieldsets?: TFieldsets;
6499
7436
  }
6500
7437
  /**
6501
- * Field-specific options
7438
+ * Define a content type with type-safe fields
7439
+ *
7440
+ * The generic type parameters preserve the literal field IDs through the type
7441
+ * system, enabling autocomplete in SDK methods like where(), select(), etc.
7442
+ *
7443
+ * @example
7444
+ * // Using direct fields
7445
+ * const product = defineContentType('product', {
7446
+ * displayName: 'Product',
7447
+ * fields: [
7448
+ * fields.shortText('title', { config: { required: true } }),
7449
+ * fields.decimal('price', { config: { min: 0, decimalPlaces: 2 } }),
7450
+ * ]
7451
+ * })
7452
+ *
7453
+ * @example
7454
+ * // Using fieldsets for organization
7455
+ * const product = defineContentType('product', {
7456
+ * displayName: 'Product',
7457
+ * fieldsets: [
7458
+ * fieldset('basic', {
7459
+ * displayName: 'Basic Info',
7460
+ * fields: [
7461
+ * fields.shortText('title', { config: { required: true } }),
7462
+ * ]
7463
+ * }),
7464
+ * fieldset('pricing', {
7465
+ * displayName: 'Pricing',
7466
+ * fields: [
7467
+ * fields.decimal('price', { config: { min: 0, decimalPlaces: 2 } }),
7468
+ * ]
7469
+ * }),
7470
+ * ]
7471
+ * })
6502
7472
  */
6503
- interface FieldOptions {
6504
- /** For array fields */
6505
- of?: FieldDefinition;
6506
- /** For reference fields */
6507
- to?: string | string[];
6508
- /** For string fields */
6509
- list?: string[];
6510
- /** For number fields */
6511
- min?: number;
6512
- max?: number;
6513
- /** For image/file fields */
6514
- accept?: string[];
6515
- /** For rich text fields */
6516
- marks?: string[];
6517
- blocks?: string[];
6518
- }
7473
+ declare function defineContentType<TFields extends readonly AnyFieldDefinition[], _TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: ContentTypeConfigWithFields<TFields>): ContentTypeDefinition<TFields, readonly []>;
7474
+ declare function defineContentType<_TFields extends readonly AnyFieldDefinition[], TFieldsets extends readonly Fieldset<AnyFieldDefinition[]>[]>(name: string, config: ContentTypeConfigWithFieldsets<TFieldsets>): ContentTypeDefinition<readonly [], TFieldsets>;
6519
7475
  /**
6520
- * Real-time event types
7476
+ * Type alias for any content type definition.
6521
7477
  */
6522
- type RealtimeEventType = 'created' | 'updated' | 'deleted' | 'published' | 'unpublished';
7478
+ type AnyContentTypeDefinition = ContentTypeDefinition<any, any>;
6523
7479
  /**
6524
- * Real-time event payload
7480
+ * What a read reports about an entry beside its fields: the committed document's `EntryMetadata`
7481
+ * (`apps/services/api/openapi-spec.json`), read through `http/api-schema.ts`, its one derivation in
7482
+ * this package — not declared a second time here.
7483
+ *
7484
+ * It used to be written out by hand, and the copy had drifted from the wire: it declared a
7485
+ * `parentId` no read sends, typed `createdAt` and `updatedAt` as `Date` where the wire sends ISO 8601
7486
+ * strings, and left out what a reader most needs — `availableLocales`, `defaultLocale`, `slug`,
7487
+ * `refs` — so the preview toolbar took them through a structural type of its own. A field the
7488
+ * service adds or changes now reaches this type when `api-schema.ts` is regenerated, and
7489
+ * `__tests__/read-metadata.types.ts` fails `type:check` if a read stops declaring it.
7490
+ *
7491
+ * Every entry-shaped value carries it — a single read, each item of a list or of `children()`, and
7492
+ * an entry an `include` expanded — because the service builds each of them with one transform.
7493
+ * `versionCount` and `versions` are sent on a single read only, so they are optional.
6525
7494
  */
6526
- interface RealtimeEvent<T extends BaseContent = BaseContent> {
6527
- /** Event type */
6528
- type: RealtimeEventType;
6529
- /** Content type */
6530
- contentType: string;
6531
- /** Content item (for created/updated events) */
6532
- item?: T;
6533
- /** Content ID (for deleted events) */
6534
- id?: string;
6535
- /** Timestamp */
6536
- timestamp: number;
6537
- /** Event metadata */
6538
- metadata?: Record<string, unknown>;
6539
- }
7495
+ type EntryMetadata = components['schemas']['EntryMetadata'];
6540
7496
  /**
6541
- * Subscription options
7497
+ * The per-locale publication facts every one-document read reports, an entry's, a singleton's and a
7498
+ * settings group's alike (`INV-LM-PUBLICATION-IS-REPORTED-PER-LOCALE`): a `Pick` of the document's
7499
+ * {@link EntryMetadata}, so this package holds no copy of them. `localeStatus` is absent when the
7500
+ * locale has no content of its own.
6542
7501
  */
6543
- interface SubscriptionOptions<T extends BaseContent = BaseContent> {
6544
- /** Content type to subscribe to */
6545
- contentType: string;
6546
- /** Filter conditions */
6547
- where?: WhereClause<T>;
6548
- /** Events to listen for */
6549
- events?: RealtimeEventType[];
6550
- /** Subscription metadata */
6551
- metadata?: Record<string, unknown>;
6552
- }
7502
+ type LocalePublicationFields = Pick<EntryMetadata, 'localeStatus' | 'localeHasDraft' | 'draftLocales'>;
6553
7503
  /**
6554
- * Performance metrics
7504
+ * Infer the TypeScript type of an entry from a content type definition: every field it declares,
7505
+ * directly or through fieldsets, typed as a read returns it (`INV-SS-TYPES-INFERRED`), plus
7506
+ * `_metadata`. Each field is optional — `schema/infer-fields.ts` says why, and what each field type
7507
+ * reads as.
7508
+ *
7509
+ * `S` is the schema the type belongs to. With it, a reference expanded by `include` is typed as the
7510
+ * entry it points at and a component field by the component's fields; without it, those two are
7511
+ * typed as an entry or an object whose fields are not known. A client typed by a schema passes it.
7512
+ *
7513
+ * @example
7514
+ * const product = defineContentType('product', {
7515
+ * displayName: 'Product',
7516
+ * fields: [
7517
+ * fields.shortText('title'),
7518
+ * fields.decimal('price'),
7519
+ * fields.enum('status', {
7520
+ * config: {
7521
+ * options: [
7522
+ * { value: 'draft', label: 'Draft' },
7523
+ * { value: 'live', label: 'Live' },
7524
+ * ],
7525
+ * },
7526
+ * }),
7527
+ * ]
7528
+ * })
7529
+ *
7530
+ * type Product = InferContentType<typeof product>
7531
+ * // { title?: string; price?: number; status?: 'draft' | 'live'; _metadata: EntryMetadata }
6555
7532
  */
6556
- interface PerformanceMetrics {
6557
- /** Request duration in milliseconds */
6558
- duration: number;
6559
- /** Request timestamp */
6560
- timestamp: number;
6561
- /** Request URL */
6562
- url: string;
6563
- /** HTTP method */
6564
- method: string;
6565
- /** Response status code */
6566
- statusCode: number;
6567
- /** Whether response came from cache */
6568
- fromCache: boolean;
6569
- /** Cache hit ratio */
6570
- cacheHitRatio?: number;
6571
- }
7533
+ type InferContentType<T extends AnyContentTypeDefinition, S extends FieldSchemaContext | undefined = undefined> = FieldValues<DeclaredFields<T>, S> & {
7534
+ _metadata: EntryMetadata;
7535
+ };
6572
7536
 
6573
- export { type ApiPath as A, type BaseContent as B, type CreateInput as C, type DebugConfig as D, type Environment as E, type FieldTypeName as F, RequiredFieldError as G, InvalidFieldTypeError as H, InvalidPayloadError as I, type MergedRelyIOConfig as J, type PathParamsOf as K, type LogLevel as L, type MatchRouteOptions as M, type components as N, type paths as O, type PerformanceMetrics as P, type QueryOptions as Q, type RelyIOConfig as R, SDKError as S, type FieldDefinition as T, type UpdateInput as U, type ValidationRule as V, type Wire as W, type ApiMethod as a, type ApiSuccessBody as b, type RouteMatch as c, type WhereClause as d, type WhereOperator as e, type SortOptions as f, type ContentQueryResult as g, type SingletonContent as h, type SettingsGroup as i, type CustomQuery as j, type ContentTypeSchema as k, type FieldOptions as l, matchRoute as m, type RealtimeEventType as n, type RealtimeEvent as o, type SubscriptionOptions as p, type CacheConfig as q, type RealtimeConfig as r, type RequestConfig as s, type ApiResponse as t, type RetryConfig as u, type CacheStrategy as v, type ValidationViolation as w, BaseValidationError as x, ValidationError as y, SchemaValidationError as z };
7537
+ 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 };