@relyio/sdk 0.6.0 → 0.8.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 +400 -0
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/{chunk-DY2XT7OF.cjs → chunk-72UK5U7T.cjs} +70 -60
  4. package/dist/{chunk-I3ESNANB.js → chunk-H6IBQSMM.js} +2 -2
  5. package/dist/{chunk-7ABNXVWL.js → chunk-QFHVF3YF.js} +1617 -404
  6. package/dist/{chunk-HT6NFRM2.cjs → chunk-TZL374LS.cjs} +2 -2
  7. package/dist/{chunk-GCMQUM6N.cjs → chunk-XIE7WJV3.cjs} +1621 -407
  8. package/dist/{chunk-XJVY2CLY.js → chunk-YEJUMW4X.js} +70 -60
  9. package/dist/client/index.cjs +4 -3
  10. package/dist/client/index.d.cts +5 -4
  11. package/dist/client/index.d.ts +5 -4
  12. package/dist/client/index.js +2 -1
  13. package/dist/{index-d1Kz1e19.d.cts → define-content-type-cEGjIwT5.d.cts} +1859 -733
  14. package/dist/{index-yPbhZc6q.d.ts → define-content-type-cEGjIwT5.d.ts} +1859 -733
  15. package/dist/{define-schema-1kr2HIzN.d.cts → define-schema-BPj2srgh.d.ts} +189 -85
  16. package/dist/{define-schema-ChvAzY8H.d.ts → define-schema-DgbJ5Kwn.d.cts} +189 -85
  17. package/dist/index-B_rIWO_l.d.cts +860 -0
  18. package/dist/index-Cv4tmcrw.d.ts +860 -0
  19. package/dist/{index-Df1VsfJR.d.cts → index-DBoPPlT1.d.cts} +684 -277
  20. package/dist/{index-XqoGUaAY.d.ts → index-yRJ2IqM_.d.ts} +684 -277
  21. package/dist/index.cjs +148 -124
  22. package/dist/index.d.cts +174 -64
  23. package/dist/index.d.ts +174 -64
  24. package/dist/index.js +43 -18
  25. package/dist/schema/index.cjs +35 -35
  26. package/dist/schema/index.d.cts +13 -11
  27. package/dist/schema/index.d.ts +13 -11
  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 +2 -1
  36. package/dist/define-content-type-CDB3kyeA.d.cts +0 -1173
  37. package/dist/define-content-type-CDB3kyeA.d.ts +0 -1173
@@ -1,6 +1,7 @@
1
- import { N as MergedRelyIOConfig, A as ApiPath, a as ApiMethod, O as PathParamsOf, v as ApiResponse, W as Wire, u as RequestConfig, B as BaseContent, f as WhereClause, h as SortOptions, i as ContentQueryResult, Q as QueryOptions, C as CreateInput, U as UpdateInput, S as SDKError, z as BaseValidationError, y as ValidationViolation, T as components, X as paths, R as RelyIOConfig } from './index-yPbhZc6q.js';
2
- import { a as SchemaDefinition, b as SchemaContentTypeNames, j as SchemaEntryOf, h as SchemaAssetTypeNames, c as SchemaSingletonNames, g as SchemaSettingsGroupNames, I as InferSettingsGroup, e as SchemaQueryNames, f as SchemaLocaleCodes } from './define-schema-ChvAzY8H.js';
3
- import { Q as InferContentType, a6 as InferAssetType, a0 as InferSingleton } from './define-content-type-CDB3kyeA.js';
1
+ import { K as MergedRelyIOConfig, A as ApiPath, c as ApiMethod, N as PathParamsOf, w as ApiResponse, W as Wire, v as RequestConfig, B as BaseContent, h as WhereClause, Q as QueryOptions, j as SortOptions, k as ContentQueryResult, C as CreateInput, U as UpdateInput, S as SDKError, H as BaseValidationError, G as ValidationViolation, R as RelyIOConfig, a as RelyIOConfigUpdate } from './index-Cv4tmcrw.js';
2
+ import { aK as components, aJ as paths, W as InferContentType, aa as InferAssetType, a3 as InferSingleton } from './define-content-type-cEGjIwT5.js';
3
+ import { a as SchemaDefinition, b as SchemaContentTypeNames, j as SchemaEntryOf, ay as FilterOperator, h as SchemaAssetTypeNames, c as SchemaSingletonNames, g as SchemaSettingsGroupNames, I as InferSettingsGroup, e as SchemaQueryNames, f as SchemaLocaleCodes } from './define-schema-BPj2srgh.js';
4
+ import { VisitorResyncReason } from './live-visitor.js';
4
5
  import { DevUnreadableReason } from './dev-handshake/index.js';
5
6
 
6
7
  /**
@@ -99,14 +100,21 @@ type SendOptions<P extends ApiPath, M extends ApiMethod<P>> = {
99
100
  * nothing inside the SDK uses them.
100
101
  */
101
102
  declare class HttpClient {
102
- private baseUrl;
103
- private defaultHeaders;
104
- private timeout;
105
- private retryPolicy;
106
- private debug;
107
- private logger?;
108
- private config;
103
+ /** What every request reads off the configuration, derived by {@link configure} and nowhere else. */
104
+ private connection;
109
105
  constructor(config: MergedRelyIOConfig);
106
+ /**
107
+ * Run on `config` from now on: every later request — whoever holds this client — is sent to its
108
+ * `baseUrl`, with its headers, key and dataset, its timeout and retries, through its `fetch`, and
109
+ * logged by its `debug` options.
110
+ *
111
+ * The client's own `updateConfig()` calls this rather than building a second client, so a
112
+ * `content()` or other sub-client taken before the update sends through the update too. Anything
113
+ * set on this client since it was last configured — `setDefaultHeaders()`, `setBaseUrl()` — is
114
+ * replaced by what `config` says.
115
+ */
116
+ configure(config: MergedRelyIOConfig): void;
117
+ private announce;
110
118
  /**
111
119
  * Call a route the committed document declares, and get back the body that
112
120
  * document says it serves.
@@ -129,13 +137,17 @@ declare class HttpClient {
129
137
  *
130
138
  * The loop always makes one attempt. The incumbent's `while (attempt <
131
139
  * maxAttempts)` made none at `retryAttempts: 0` — a value the config validator
132
- * accepts — and then dereferenced an unassigned `lastError`.
140
+ * then accepted, and now refuses — and then dereferenced an unassigned
141
+ * `lastError`. `retryAttempts` is the most attempts, the first included; an
142
+ * `HttpClient` constructed directly is not validated, so the first attempt
143
+ * stays unconditional.
133
144
  *
134
145
  * A request that would carry no `X-API-Key` makes none: it rejects with
135
146
  * `MissingApiKeyError` before `fetch` is called, is not retried, and names
136
147
  * `apiKey`. This is where a client built without a key learns it — the
137
148
  * constructor accepts one so that a module-scope client can be evaluated by a
138
- * build that holds no key (REL-1120).
149
+ * build that holds no key (REL-1120) — and so does one whose `setApiKey` was
150
+ * given none.
139
151
  */
140
152
  request<T = unknown>(config: RequestConfig): Promise<ApiResponse<T>>;
141
153
  /**
@@ -159,13 +171,28 @@ declare class HttpClient {
159
171
  */
160
172
  patch<T = unknown>(url: string, data?: unknown, params?: Record<string, unknown>): Promise<ApiResponse<T>>;
161
173
  /**
162
- * Set default headers for all requests
174
+ * Add headers to every later request, each replacing any header of the same name — the name
175
+ * matched without regard to case — until the client is next configured.
163
176
  */
164
177
  setDefaultHeaders(headers: Record<string, string>): void;
165
178
  /**
166
- * Set authentication token
179
+ * Replace the key every later request sends as `X-API-Key`, and the `apiKey` the configuration
180
+ * reports.
181
+ *
182
+ * The key is read the way construction reads it (`presentKey`): an absent, empty or blank key is
183
+ * no key, so the header is dropped and the next request is refused with `MissingApiKeyError`
184
+ * before anything is sent. A key header of any other spelling — one given in `headers` — goes
185
+ * too, from the headers sent and from the headers the configuration reports, so the old key is
186
+ * never sent beside the new one.
187
+ *
188
+ * The configuration is the one the owning `TypedRelyIOClient` holds (it hands its own to the
189
+ * constructor), so its `getConfig().apiKey` — what a surface reads to decide a key's kind — is the
190
+ * key sent from here on.
191
+ *
192
+ * This replaced `setAuthToken`, which added `Authorization: Bearer` beside an `X-API-Key` it
193
+ * never touched: the API reads `X-API-Key` first, so the old key was the one used (REL-1385).
167
194
  */
168
- setAuthToken(token: string): void;
195
+ setApiKey(apiKey: string): void;
169
196
  /**
170
197
  * Get current default headers
171
198
  */
@@ -190,7 +217,12 @@ declare class HttpClient {
190
217
  */
191
218
  private makeRequest;
192
219
  /**
193
- * Filter headers that browsers don't allow to be set manually
220
+ * The headers without those a browser controls itself, when this is a browser; unchanged when it
221
+ * is not.
222
+ *
223
+ * A name is matched without regard to case (RFC 9110 §5.1), because a browser refuses `Origin`
224
+ * whatever case a page spells it in. This matched only the all-lowercase and all-uppercase
225
+ * spellings, so `Origin` and `User-Agent` — how people write them — reached `fetch` (REL-1409).
194
226
  */
195
227
  private filterHeadersForBrowser;
196
228
  /**
@@ -205,6 +237,18 @@ declare class HttpClient {
205
237
  private log;
206
238
  }
207
239
 
240
+ /**
241
+ * The client's locale as a sub-client holds it: a function it asks on every call, or a locale fixed
242
+ * when it was built.
243
+ *
244
+ * `TypedRelyIOClient` hands every sub-client and builder a function over the configuration it holds,
245
+ * so one taken before `updateConfig({ locale })` sends the locale the client holds when the call is
246
+ * made, and none once `updateConfig({ locale: null })` has cleared it (REL-1453). A string is a locale
247
+ * fixed at construction — a sub-client's own `withLocale()`, or one built directly — and stays what it
248
+ * was.
249
+ */
250
+ type ClientLocale = string | (() => string | undefined);
251
+
208
252
  /**
209
253
  * Children population options
210
254
  */
@@ -244,10 +288,9 @@ type ExtendedQueryResult<T extends BaseContent = BaseContent> = ContentQueryResu
244
288
  * .execute()
245
289
  * ```
246
290
  */
247
- declare class ContentQueryBuilder<T extends BaseContent = BaseContent> {
291
+ declare class ContentQueryBuilder<T extends BaseContent = BaseContent, F extends BaseContent = T> {
248
292
  private readonly httpClient;
249
293
  private readonly contentType;
250
- private readonly defaultLocale?;
251
294
  private queryOptions;
252
295
  private localeValue?;
253
296
  private localesArray?;
@@ -257,7 +300,22 @@ declare class ContentQueryBuilder<T extends BaseContent = BaseContent> {
257
300
  private pageNumber?;
258
301
  private pageSizeValue?;
259
302
  private requestHeaders?;
260
- constructor(httpClient: HttpClient, contentType: string, defaultLocale?: string | undefined);
303
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
304
+ private readonly clientLocale;
305
+ private freshValue?;
306
+ /**
307
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when the
308
+ * query names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
309
+ */
310
+ constructor(httpClient: HttpClient, contentType: string, locale?: ClientLocale);
311
+ /**
312
+ * The feed position this read follows — a change's `fresh` (`FeedChange`), or a resync's. Sent as
313
+ * `?_fresh`, the one term the API declares for it: no cache — the Content API's edge or the
314
+ * browser's own — holds an answer for that position from before it, so the read is answered after
315
+ * the change, and every read naming the same position shares that answer. The answer is the
316
+ * read's own; omit it for a read no change prompted.
317
+ */
318
+ fresh(position: string): this;
261
319
  /**
262
320
  * Headers this query adds to the client's own, e.g. `X-RelyIO-Dataset` to list another dataset
263
321
  * the key can see. A name the client already sends is replaced for this query only; the client
@@ -265,13 +323,14 @@ declare class ContentQueryBuilder<T extends BaseContent = BaseContent> {
265
323
  */
266
324
  headers(headers: Record<string, string>): this;
267
325
  /**
268
- * Add where conditions to the query
326
+ * Add where conditions to the query: conditions on the fields the content type declares. A
327
+ * condition on `_metadata` is refused here, before anything is sent (`refuseMetadataConditions`).
269
328
  */
270
- where(conditions: WhereClause<T>): this;
329
+ where(conditions: WhereClause<F>): this;
271
330
  /**
272
331
  * Select specific fields to return
273
332
  */
274
- select(fields: (keyof T)[]): this;
333
+ select(fields: NonNullable<QueryOptions<T, F>['select']>): this;
275
334
  /**
276
335
  * Include related content in the response
277
336
  */
@@ -289,7 +348,7 @@ declare class ContentQueryBuilder<T extends BaseContent = BaseContent> {
289
348
  * ```
290
349
  */
291
350
  sort(field: string, direction: 'asc' | 'desc'): this;
292
- sort(sortOptions: SortOptions<T>): this;
351
+ sort(sortOptions: SortOptions<F>): this;
293
352
  /**
294
353
  * Sort by a specific field in ascending order
295
354
  */
@@ -418,11 +477,11 @@ declare class ContentQueryBuilder<T extends BaseContent = BaseContent> {
418
477
  /**
419
478
  * Clone the query builder
420
479
  */
421
- clone(): ContentQueryBuilder<T>;
480
+ clone(): ContentQueryBuilder<T, F>;
422
481
  /**
423
482
  * Get the current query options
424
483
  */
425
- getQueryOptions(): QueryOptions<T>;
484
+ getQueryOptions(): QueryOptions<T, F>;
426
485
  /**
427
486
  * Execute the query and return the whole body.
428
487
  *
@@ -459,14 +518,28 @@ declare class ContentByIdBuilder<T extends BaseContent = BaseContent> {
459
518
  private readonly httpClient;
460
519
  private readonly contentType;
461
520
  private readonly id;
462
- private readonly defaultLocale?;
463
521
  private includeRelations?;
464
522
  private localeValue?;
465
523
  private localesArray?;
466
524
  private fetchAllLocales;
467
525
  private childrenOptions?;
468
526
  private requestHeaders?;
469
- constructor(httpClient: HttpClient, contentType: string, id: string, defaultLocale?: string | undefined);
527
+ /** The client's locale, asked when the read is sent rather than copied when it was built. */
528
+ private readonly clientLocale;
529
+ private freshValue?;
530
+ /**
531
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when the
532
+ * read names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
533
+ */
534
+ constructor(httpClient: HttpClient, contentType: string, id: string, locale?: ClientLocale);
535
+ /**
536
+ * The feed position this read follows — a change's `fresh` (`FeedChange`), or a resync's. Sent as
537
+ * `?_fresh`, the one term the API declares for it: no cache — the Content API's edge or the
538
+ * browser's own — holds an answer for that position from before it, so the read is answered after
539
+ * the change, and every read naming the same position shares that answer. The answer is the
540
+ * read's own; omit it for a read no change prompted.
541
+ */
542
+ fresh(position: string): this;
470
543
  /**
471
544
  * Include related content in the response
472
545
  */
@@ -615,8 +688,13 @@ interface ContentFetchOptions<T extends BaseContent = BaseContent> {
615
688
  declare class ContentClient<T extends BaseContent = BaseContent> {
616
689
  private readonly httpClient;
617
690
  private readonly contentType;
618
- private readonly defaultLocale?;
619
- constructor(httpClient: HttpClient, contentType: string, defaultLocale?: string | undefined);
691
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
692
+ private readonly clientLocale;
693
+ /**
694
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
695
+ * every call, or a locale fixed for this client
696
+ */
697
+ constructor(httpClient: HttpClient, contentType: string, locale?: ClientLocale);
620
698
  /**
621
699
  * Create a new query builder for this content type
622
700
  */
@@ -683,7 +761,7 @@ declare class ContentClient<T extends BaseContent = BaseContent> {
683
761
  * @param options - Create options (slug, locale, parentId, sortOrder), and `headers` this one
684
762
  * request adds — e.g. `{ 'X-RelyIO-Dataset': 'staging' }` to write a dataset other than the
685
763
  * client's. They are sent, never put in the body; `idempotencyKey` still wins over an
686
- * `Idempotency-Key` among them.
764
+ * `Idempotency-Key` among them. `locale` defaults to the client's own (`withLocale()`).
687
765
  */
688
766
  create(data: CreateInput<T>, options?: {
689
767
  slug?: string;
@@ -698,7 +776,8 @@ declare class ContentClient<T extends BaseContent = BaseContent> {
698
776
  * @param data - Fields to update
699
777
  * @param options - Update options (slug, locale, parentId, sortOrder), and `headers` this one
700
778
  * request adds, as for {@link create}. `ifMatch` and `idempotencyKey` win over the same
701
- * header among them.
779
+ * header among them. `locale` defaults to the client's own, the locale whose entity tag
780
+ * {@link fetchOneWithTag} reads, so the tag it hands back is checked against the same locale.
702
781
  */
703
782
  update(id: string, data: UpdateInput<T>, options?: {
704
783
  slug?: string;
@@ -719,8 +798,9 @@ declare class ContentClient<T extends BaseContent = BaseContent> {
719
798
  * Get version history for one locale of an entry.
720
799
  *
721
800
  * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
722
- * schema default, no fallback is applied, and a locale with no history returns an empty array
723
- * rather than another locale's rows. Every row names the locale it belongs to.
801
+ * client's own (`withLocale()`), else the schema default; no fallback is applied, and a locale
802
+ * with no history returns an empty array rather than another locale's rows. Every row names the
803
+ * locale it belongs to.
724
804
  */
725
805
  versions(id: string, options?: {
726
806
  limit?: number;
@@ -732,8 +812,8 @@ declare class ContentClient<T extends BaseContent = BaseContent> {
732
812
  /**
733
813
  * Get a specific version of an entry.
734
814
  *
735
- * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
736
- * different content in each one.
815
+ * `locale` defaults to the client's own (`withLocale()`), else the schema default. Version
816
+ * numbers are per locale, so version 2 is different content in each one.
737
817
  */
738
818
  version(id: string, versionNumber: number, options?: {
739
819
  locale?: string;
@@ -770,11 +850,12 @@ declare class ContentClient<T extends BaseContent = BaseContent> {
770
850
  */
771
851
  ofType<U extends BaseContent = BaseContent>(contentType: string): ContentClient<U>;
772
852
  /**
773
- * Create a new ContentClient with a different default locale
853
+ * Create a new ContentClient with a different default locale, fixed: an update of the client's
854
+ * locale (`updateConfig({ locale })`) does not reach it
774
855
  */
775
856
  withLocale(locale: string): ContentClient<T>;
776
857
  /**
777
- * Get the current default locale
858
+ * Get the default locale as it is now: the client's, or the one `withLocale()` fixed
778
859
  */
779
860
  getDefaultLocale(): string | undefined;
780
861
  }
@@ -785,21 +866,40 @@ declare class ContentClient<T extends BaseContent = BaseContent> {
785
866
  * A **thin customer-side mirror** of the realtime-contracts `FileErrorCode`
786
867
  * (correction C6 — the SDK must not import the server/Studio contracts package).
787
868
  * Keep the members in sync with `@relyio/realtime-contracts`.
869
+ *
870
+ * Written once, as values, because a processing failure's code arrives as a string the service
871
+ * stored and has to be recognised at runtime; `FileErrorCode` is read off this list. The module is
872
+ * internal — `errors/index.ts` does not re-export it — so the list is not a second public name for
873
+ * the type.
788
874
  */
789
- type FileErrorCode = 'UPLOAD_TOO_LARGE' | 'UNSUPPORTED_MIME' | 'DIMENSION_OUT_OF_RANGE' | 'ASPECT_RATIO' | 'CORRUPT_FILE' | 'UNSUPPORTED_CODEC' | 'IMAGES_LIMIT_EXCEEDED' | 'STREAM_ENCODE_FAILED' | 'SCAN_INFECTED' | 'INTERNAL';
875
+ declare const FILE_ERROR_CODES: readonly ["UPLOAD_TOO_LARGE", "UNSUPPORTED_MIME", "DIMENSION_OUT_OF_RANGE", "ASPECT_RATIO", "CORRUPT_FILE", "UNSUPPORTED_CODEC", "IMAGES_LIMIT_EXCEEDED", "STREAM_ENCODE_FAILED", "SCAN_INFECTED", "INTERNAL"];
876
+
877
+ /**
878
+ * Upload/processing error taxonomy (plan 17, 00b Step 4): a customer-side mirror of the
879
+ * realtime-contracts `FileErrorCode`, read off the list in `./file-error-codes`.
880
+ */
881
+ type FileErrorCode = (typeof FILE_ERROR_CODES)[number];
882
+ /**
883
+ * The code a {@link FileUploadError} carries: a {@link FileErrorCode}, or `PROCESSING_FAILED` for a
884
+ * processing failure this SDK cannot name — the service stored no code, as an image or file
885
+ * processing failure is stored today, or one this version of the SDK predates. What the service
886
+ * stored is in the error's `context.processingError` either way.
887
+ */
888
+ type FileUploadErrorCode = FileErrorCode | 'PROCESSING_FAILED';
790
889
  /**
791
890
  * A failure during the upload protocol (presign / PUT / multipart / confirm) or
792
- * surfaced by the server's processing pipeline. Carries a typed {@link FileErrorCode}
891
+ * surfaced by the server's processing pipeline. Carries a typed {@link FileUploadErrorCode}
793
892
  * and a `retriable` hint so callers (and `upload()`'s bounded auto-retry) can
794
893
  * decide whether to retry on the same entry.
795
894
  */
796
895
  declare class FileUploadError extends SDKError {
797
- readonly code: FileErrorCode;
896
+ readonly code: FileUploadErrorCode;
798
897
  readonly retryable: boolean;
799
- constructor(code: FileErrorCode, message: string, options?: {
898
+ constructor(code: FileUploadErrorCode, message: string, options?: {
800
899
  retriable?: boolean;
801
900
  statusCode?: number;
802
901
  cause?: Error;
902
+ context?: Record<string, unknown>;
803
903
  });
804
904
  getUserMessage(): string;
805
905
  }
@@ -837,73 +937,20 @@ type AssetVisibility = 'public' | 'protected' | 'private';
837
937
  type FileStatus = 'pending_upload' | 'uploading' | 'processing' | 'ready' | 'failed';
838
938
  /** Storage backend: `r2` = image + file kinds, `stream` = video kind. */
839
939
  type FileBackend = 'r2' | 'stream';
840
- /** Extracted media metadata (Phase 1 basics + Phase 2 enrichment, plans 15–19). */
841
- interface AssetFileExtracted {
842
- width?: number;
843
- height?: number;
844
- format?: string;
845
- duration?: number;
846
- hasAlpha?: boolean;
847
- isAnimated?: boolean;
848
- orientation?: number;
849
- placeholder?: string;
850
- dominantColor?: string;
851
- palette?: string[];
852
- exif?: Record<string, unknown>;
853
- video?: {
854
- codec?: string;
855
- bitrate?: number;
856
- framerate?: number;
857
- audioTracks?: unknown[];
858
- };
859
- pageCount?: number;
860
- text?: string;
861
- safety?: {
862
- nsfwScore?: number;
863
- flagged?: boolean;
864
- categories?: string[];
865
- };
866
- [key: string]: unknown;
867
- }
868
- /** Customer-facing file binding block on an asset entry. */
869
- interface AssetFileBlock {
870
- status: FileStatus;
871
- backend: FileBackend;
872
- fileName: string;
873
- mimeType?: string | null;
874
- size?: number | null;
875
- /** Advisory client-computed SHA-256 (duplicate detection only). */
876
- hash?: string | null;
877
- visibility: AssetVisibility;
878
- extracted?: AssetFileExtracted;
879
- /** 0..1 normalized smart-crop anchor (written by plan 18). */
880
- focalPoint?: {
881
- x: number;
882
- y: number;
883
- };
884
- /** Phase-2 enrichment status — independent of `status` (plan 15). */
885
- enrichment?: {
886
- status: 'pending' | 'running' | 'complete' | 'partial' | 'failed';
887
- };
888
- /** File-kind malware scan status (plan 19). */
889
- scan?: {
890
- status: 'pending' | 'clean' | 'infected' | 'error' | 'skipped';
891
- };
892
- /** Processing progress (e.g. video encoding %) + terminal error. */
893
- processing?: {
894
- stage?: string;
895
- progress?: number;
896
- error?: {
897
- code?: string;
898
- message?: string;
899
- retriable?: boolean;
900
- };
901
- };
902
- /** Video playback readiness. */
903
- playback?: {
904
- ready?: boolean;
905
- };
906
- }
940
+ /**
941
+ * Customer-facing file binding block on an asset entry: the document's `AssetFile` — status,
942
+ * backend, file name, MIME type, size, advisory hash, visibility, extracted metadata, focal point,
943
+ * enrichment and scan status, processing stage/progress/error, and video playback readiness.
944
+ */
945
+ type AssetFileBlock = components['schemas']['AssetFile'];
946
+ /** Extracted media metadata (Phase 1 basics + Phase 2 enrichment, plans 15–19); open-ended. */
947
+ type AssetFileExtracted = NonNullable<AssetFileBlock['extracted']>;
948
+ /**
949
+ * Where one file binding's upload got to, as {@link AssetFileBuilder.status} reads it
950
+ * (`GET /v1/{assetType}/{id}/file`): the document's `FileStatus` — the binding's lifecycle and
951
+ * nothing of the entry's content. `processing.error` is present exactly while `status` is `failed`.
952
+ */
953
+ type FileStatusResult = components['schemas']['FileStatus'];
907
954
  /**
908
955
  * Computed gateway delivery URLs (the reserved `urls` key). Always served from
909
956
  * `cdn.relyio.net`. Image bindings expose `original` + `variants`; video bindings
@@ -1036,9 +1083,12 @@ type UpdateAssetOptions = {
1036
1083
  interface WaitUntilReadyOptions {
1037
1084
  /** Locale of the binding to watch. */
1038
1085
  locale?: string;
1039
- /** Total time to wait before giving up (ms). Default 60000. */
1086
+ /**
1087
+ * Total time to wait before giving up (ms), from 0 to 2147483647. Default 60000. `0` reads the
1088
+ * file once and rejects with a `TimeoutError` if it is not ready.
1089
+ */
1040
1090
  timeoutMs?: number;
1041
- /** Delay between polls (ms). Default 1500. */
1091
+ /** Delay between polls (ms), from 1 to 2147483647. Default 1500. */
1042
1092
  pollIntervalMs?: number;
1043
1093
  }
1044
1094
  /**
@@ -1049,8 +1099,13 @@ declare class AssetFileBuilder<T extends BaseContent = BaseContent> {
1049
1099
  private readonly httpClient;
1050
1100
  private readonly assetType;
1051
1101
  private readonly entryUid;
1052
- private readonly defaultLocale?;
1053
- constructor(httpClient: HttpClient, assetType: string, entryUid: string, defaultLocale?: string | undefined);
1102
+ /** The client's locale, asked on every call rather than copied when this builder was taken. */
1103
+ private readonly clientLocale;
1104
+ /**
1105
+ * @param locale - The client's locale, sent when a call names none: the function
1106
+ * `TypedRelyIOClient` hands over, or a locale fixed for this builder
1107
+ */
1108
+ constructor(httpClient: HttpClient, assetType: string, entryUid: string, locale?: ClientLocale);
1054
1109
  /**
1055
1110
  * The path parameters every `/file/*` route on this builder takes.
1056
1111
  *
@@ -1060,6 +1115,12 @@ declare class AssetFileBuilder<T extends BaseContent = BaseContent> {
1060
1115
  */
1061
1116
  private get target();
1062
1117
  private withLocale;
1118
+ /**
1119
+ * The `locale` body field of a multipart call: the session's, else the client's. The API finds
1120
+ * the binding by it, so a session a `withLocale()` client opened must name the same locale on
1121
+ * every later call or its `objectKey` is refused as another binding's.
1122
+ */
1123
+ private localeField;
1063
1124
  /**
1064
1125
  * Issue a single upload target — an R2 presigned PUT (image/file) or a
1065
1126
  * Cloudflare Stream direct-creator URL (video). Resumable multipart is plan 17.
@@ -1096,6 +1157,18 @@ declare class AssetFileBuilder<T extends BaseContent = BaseContent> {
1096
1157
  * Throws if the binding is not `ready`.
1097
1158
  */
1098
1159
  url(input?: ResolveUrlInput): Promise<ResolveUrlResult>;
1160
+ /**
1161
+ * Read where this file's upload got to — `status`, and the processing stage, progress and error
1162
+ * the pipeline recorded — whatever the asset entry is published in.
1163
+ *
1164
+ * An asset is a draft until its file is ready, and stays one when its file fails, so a key that
1165
+ * reads published content finds no entry for an upload in flight or one that failed. This read
1166
+ * answers for the binding itself. It takes the capability the upload calls take, so a read-only
1167
+ * key is refused with `ReadOnlyKeyError`, and it never returns the entry's fields.
1168
+ */
1169
+ status(options?: {
1170
+ locale?: string;
1171
+ }): Promise<FileStatusResult>;
1099
1172
  /**
1100
1173
  * Update the binding's delivery visibility (token-based; no byte relocation —
1101
1174
  * a downgrade purges the gateway cache). Returns the refreshed asset entry.
@@ -1123,8 +1196,23 @@ declare class AssetFileBuilder<T extends BaseContent = BaseContent> {
1123
1196
  locale?: string;
1124
1197
  }): Promise<void>;
1125
1198
  /**
1126
- * Poll the asset entry until its file binding reaches `ready` (resolves with
1127
- * the ready entry) or `failed` (throws). Times out after `timeoutMs`.
1199
+ * Poll the asset entry until its file binding reaches `ready`, and resolve with the ready entry.
1200
+ *
1201
+ * Each poll reads the entry through the key's lens. When that finds nothing — a key that reads
1202
+ * published content, and an asset that is a draft until its file is ready and stays one when it
1203
+ * fails — the poll reads the binding itself ({@link status}), so a failed upload rejects as one
1204
+ * rather than running out the limit (REL-1481).
1205
+ *
1206
+ * @throws {FileUploadError} When processing failed. `code` is the processing code the service
1207
+ * stored — `UNSUPPORTED_CODEC`, `CORRUPT_FILE` and so on — or `PROCESSING_FAILED` where it
1208
+ * stored none this SDK knows; `context.processingError` holds what it stored, and `retryable`
1209
+ * is its `retriable` hint.
1210
+ * @throws {TimeoutError} When `timeoutMs` passes first. The file may still become ready; the
1211
+ * error's `context.timeout` is the limit and `context.fileStatus` the status last seen. A file
1212
+ * that is `ready` in an asset the key's lens never shows — created with `publish: false`, or
1213
+ * awaiting a workflow — ends here too, and the message says so.
1214
+ * @throws {ReadOnlyKeyError} When the key's lens does not show the asset and the key may not read
1215
+ * its binding either: nothing it can read would ever report the file.
1128
1216
  */
1129
1217
  waitUntilReady(options?: WaitUntilReadyOptions): Promise<AssetEntryResponse<T>>;
1130
1218
  }
@@ -1139,7 +1227,6 @@ declare class AssetUploadBuilder<T extends BaseContent = BaseContent> {
1139
1227
  private readonly httpClient;
1140
1228
  private readonly assetType;
1141
1229
  private readonly file;
1142
- private readonly defaultLocale?;
1143
1230
  private _fileName?;
1144
1231
  private _visibility?;
1145
1232
  private _locale?;
@@ -1151,7 +1238,13 @@ declare class AssetUploadBuilder<T extends BaseContent = BaseContent> {
1151
1238
  private _onProgress?;
1152
1239
  private _validate?;
1153
1240
  private _maxPartRetries;
1154
- constructor(httpClient: HttpClient, assetType: string, file: Blob, defaultLocale?: string | undefined);
1241
+ /** The client's locale, read once when the upload starts. */
1242
+ private readonly clientLocale;
1243
+ /**
1244
+ * @param locale - The client's locale, the upload's when `.locale()` names none: the function
1245
+ * `TypedRelyIOClient` hands over, or a locale fixed for this upload
1246
+ */
1247
+ constructor(httpClient: HttpClient, assetType: string, file: Blob, locale?: ClientLocale);
1155
1248
  /** Subscribe to client → storage upload progress (single PUT + multipart). */
1156
1249
  onProgress(callback: (_progress: UploadProgress) => void): this;
1157
1250
  /**
@@ -1173,7 +1266,12 @@ declare class AssetUploadBuilder<T extends BaseContent = BaseContent> {
1173
1266
  content(content: Record<string, unknown>): this;
1174
1267
  /** Set an explicit slug for the new entry. */
1175
1268
  slug(slug: string): this;
1176
- /** Wait until the file binding becomes `ready` before resolving. */
1269
+ /**
1270
+ * Wait until the file binding becomes `ready` before resolving.
1271
+ *
1272
+ * @throws {Error} When `timeoutMs` or `pollIntervalMs` is one the wait cannot honour — refused
1273
+ * here, before anything is uploaded, rather than after the bytes are in.
1274
+ */
1177
1275
  waitForReady(options?: boolean | Omit<WaitUntilReadyOptions, 'locale'>): this;
1178
1276
  /** Execute the full upload flow and resolve with the asset entry. */
1179
1277
  execute(): Promise<AssetEntryResponse<T>>;
@@ -1197,10 +1295,18 @@ declare class AssetUploadBuilder<T extends BaseContent = BaseContent> {
1197
1295
  declare class AssetClient<T extends BaseContent = BaseContent> {
1198
1296
  private readonly httpClient;
1199
1297
  private readonly assetType;
1200
- private readonly defaultLocale?;
1201
- constructor(httpClient: HttpClient, assetType: string, defaultLocale?: string | undefined);
1202
- /** Create a query builder for this asset type. */
1203
- query(): ContentQueryBuilder<AssetEntryResponse<T>>;
1298
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
1299
+ private readonly clientLocale;
1300
+ /**
1301
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
1302
+ * every call, or a locale fixed for this client
1303
+ */
1304
+ constructor(httpClient: HttpClient, assetType: string, locale?: ClientLocale);
1305
+ /**
1306
+ * Create a query builder for this asset type. It resolves asset reads; its conditions name the
1307
+ * asset type's fields, which the `file` and `urls` blocks are not.
1308
+ */
1309
+ query(): ContentQueryBuilder<AssetEntryResponse<T>, T>;
1204
1310
  /** Find an asset entry by id (or slug) with fluent options. */
1205
1311
  findById(id: string): ContentByIdBuilder<AssetEntryResponse<T>>;
1206
1312
  /** Fetch a single asset entry by id (or slug), or `null` if not found. */
@@ -1209,14 +1315,18 @@ declare class AssetClient<T extends BaseContent = BaseContent> {
1209
1315
  locale?: string;
1210
1316
  }): Promise<AssetEntryResponse<T> | null>;
1211
1317
  /** Fetch the first asset entry matching the conditions, or `null`. */
1212
- fetchFirst(where?: WhereClause<AssetEntryResponse<T>>, locale?: string): Promise<AssetEntryResponse<T> | null>;
1318
+ fetchFirst(where?: WhereClause<T>, locale?: string): Promise<AssetEntryResponse<T> | null>;
1213
1319
  /**
1214
1320
  * Create a new asset entry as a draft. The binary is uploaded separately via
1215
1321
  * `file(uid)` (or use the high-level `upload()` helper), and the entry
1216
1322
  * auto-publishes when its file becomes ready (unless `publish: false`).
1323
+ * `locale` defaults to the client's own (`withLocale()`).
1217
1324
  */
1218
1325
  create(data: CreateInput<T>, options?: CreateAssetOptions & RetryableWriteOptions): Promise<AssetEntryResponse<T>>;
1219
- /** Update an asset entry's metadata fields (and/or slug). */
1326
+ /**
1327
+ * Update an asset entry's metadata fields (and/or slug). `locale` defaults to the client's own
1328
+ * (`withLocale()`).
1329
+ */
1220
1330
  update(id: string, data: UpdateInput<T>, options?: UpdateAssetOptions): Promise<AssetEntryResponse<T>>;
1221
1331
  /** Delete an asset entry (cascades file-byte cleanup + gateway purge). */
1222
1332
  delete(id: string, options?: ConditionalWriteOptions): Promise<void>;
@@ -1226,9 +1336,12 @@ declare class AssetClient<T extends BaseContent = BaseContent> {
1226
1336
  upload(file: Blob): AssetUploadBuilder<T>;
1227
1337
  /** Get the asset type id. */
1228
1338
  getAssetType(): string;
1229
- /** Get the current default locale. */
1339
+ /** Get the default locale as it is now: the client's, or the one `withLocale()` fixed. */
1230
1340
  getDefaultLocale(): string | undefined;
1231
- /** Create a new AssetClient for this type with a different default locale. */
1341
+ /**
1342
+ * Create a new AssetClient for this type with a different default locale, fixed: an update of the
1343
+ * client's locale (`updateConfig({ locale })`) does not reach it.
1344
+ */
1232
1345
  withLocale(locale: string): AssetClient<T>;
1233
1346
  }
1234
1347
  /**
@@ -1258,13 +1371,21 @@ interface SingletonFetchOptions {
1258
1371
  locale?: string;
1259
1372
  /** Reference fields to populate */
1260
1373
  include?: string[];
1374
+ /**
1375
+ * The feed position this read follows — a change's `fresh` (`FeedChange`), or a resync's. Sent as
1376
+ * `?_fresh`: no cache holds an answer for it from before that position, so the read is answered
1377
+ * after the change. The answer is the read's own; omit it for a read no change prompted.
1378
+ */
1379
+ fresh?: string;
1261
1380
  }
1262
1381
  /**
1263
1382
  * Singleton client for managing singleton content operations
1264
1383
  * Provides a fluent API for singleton operations following the same pattern as ContentClient
1265
1384
  *
1266
- * A read is in the locale it names — `fetch({ locale })`, then `.locale()` — and otherwise in
1267
- * `defaultLocale`, the client's own (`withLocale()`), as `content()`'s reads are.
1385
+ * Every call is in the locale it names — the argument (`fetch({ locale })`, `update(data, locale)`,
1386
+ * `versions({ locale })`), then `.locale()` — and otherwise in the client's own (`withLocale()`,
1387
+ * `updateConfig({ locale })`) as it is when the call is made, as `content()`'s are: reads, the write,
1388
+ * and version history alike.
1268
1389
  *
1269
1390
  * @example
1270
1391
  * ```typescript
@@ -1277,10 +1398,15 @@ interface SingletonFetchOptions {
1277
1398
  declare class SingletonClient<T = unknown> {
1278
1399
  private httpClient;
1279
1400
  private singletonKey;
1280
- private readonly defaultLocale?;
1281
1401
  private includeFields?;
1282
1402
  private localeValue?;
1283
- constructor(httpClient: HttpClient, singletonKey: string, defaultLocale?: string | undefined);
1403
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
1404
+ private readonly clientLocale;
1405
+ /**
1406
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
1407
+ * every call, or a locale fixed for this client
1408
+ */
1409
+ constructor(httpClient: HttpClient, singletonKey: string, locale?: ClientLocale);
1284
1410
  /**
1285
1411
  * Include reference fields in the response
1286
1412
  * @param fields - Reference field names to populate
@@ -1311,7 +1437,8 @@ declare class SingletonClient<T = unknown> {
1311
1437
  * Update singleton content. The API auto-publishes on PATCH — there is no
1312
1438
  * separate publish route; calling `update()` writes and publishes.
1313
1439
  * @param data - The content fields to update
1314
- * @param locale - Optional locale for localized content (overrides fluent locale)
1440
+ * @param locale - Optional locale for localized content (overrides the fluent locale, which
1441
+ * overrides the client's own)
1315
1442
  * @param options - `If-Match` / `Idempotency-Key`, both declared on this route
1316
1443
  */
1317
1444
  update(data: Partial<T>, locale?: string, options?: ConditionalWriteOptions): Promise<T>;
@@ -1323,8 +1450,9 @@ declare class SingletonClient<T = unknown> {
1323
1450
  * Get version history for one locale of the singleton.
1324
1451
  *
1325
1452
  * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
1326
- * schema default, no fallback is applied, and a locale with no history returns an empty array
1327
- * rather than another locale's rows. Every row names the locale it belongs to.
1453
+ * fluent `.locale()`, then the client's own (`withLocale()`), then the schema default; no
1454
+ * fallback is applied, and a locale with no history returns an empty array rather than another
1455
+ * locale's rows. Every row names the locale it belongs to.
1328
1456
  */
1329
1457
  versions(options?: {
1330
1458
  limit?: number;
@@ -1336,12 +1464,14 @@ declare class SingletonClient<T = unknown> {
1336
1464
  /**
1337
1465
  * Get a specific version of the singleton.
1338
1466
  *
1339
- * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
1340
- * different content in each one.
1467
+ * `locale` defaults to the fluent `.locale()`, then the client's own (`withLocale()`), then the
1468
+ * schema default. Version numbers are per locale, so version 2 is different content in each one.
1341
1469
  */
1342
1470
  version(versionNumber: number, options?: {
1343
1471
  locale?: string;
1344
1472
  }): Promise<T | null>;
1473
+ /** The locale a write or history read sends: the call's, the fluent one, else the client's. */
1474
+ private localeOf;
1345
1475
  /**
1346
1476
  * Get the singleton key
1347
1477
  */
@@ -1365,8 +1495,10 @@ interface SettingsFetchOptions {
1365
1495
  * Settings client for managing settings group operations
1366
1496
  * Provides a fluent API for settings operations following the same pattern as ContentClient
1367
1497
  *
1368
- * A read is in the locale it names — `fetch({ locale })`, then `.locale()` — and otherwise in
1369
- * `defaultLocale`, the client's own (`withLocale()`), as `content()`'s reads are.
1498
+ * Every call is in the locale it names — the argument (`fetch({ locale })`, `update(settings,
1499
+ * locale)`, `reset(locale)`, `versions({ locale })`), then `.locale()` — and otherwise in the
1500
+ * client's own (`withLocale()`, `updateConfig({ locale })`) as it is when the call is made, as
1501
+ * `content()`'s are: reads, writes and version history alike.
1370
1502
  *
1371
1503
  * @example
1372
1504
  * ```typescript
@@ -1379,10 +1511,15 @@ interface SettingsFetchOptions {
1379
1511
  declare class SettingsClient<T = unknown> {
1380
1512
  private readonly httpClient;
1381
1513
  private readonly groupId;
1382
- private readonly defaultLocale?;
1383
1514
  private includeFields?;
1384
1515
  private localeValue?;
1385
- constructor(httpClient: HttpClient, groupId: string, defaultLocale?: string | undefined);
1516
+ /** The client's locale, asked on every call rather than copied when this client was taken. */
1517
+ private readonly clientLocale;
1518
+ /**
1519
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, asked on
1520
+ * every call, or a locale fixed for this client
1521
+ */
1522
+ constructor(httpClient: HttpClient, groupId: string, locale?: ClientLocale);
1386
1523
  /**
1387
1524
  * Include reference fields in the response
1388
1525
  * @param fields - Reference field names to populate
@@ -1400,8 +1537,13 @@ declare class SettingsClient<T = unknown> {
1400
1537
  fetch(options?: SettingsFetchOptions): Promise<T | null>;
1401
1538
  /**
1402
1539
  * Update settings group
1540
+ *
1541
+ * The fields travel as `content` beside an optional `locale`, the body the route validates
1542
+ * (`UpdateSettingsDto`); any other top-level key is refused `REQUEST_INVALID`.
1543
+ *
1403
1544
  * @param settings - The settings fields to update
1404
- * @param locale - Optional locale for localized settings (overrides fluent locale)
1545
+ * @param locale - Optional locale for localized settings (overrides the fluent locale, which
1546
+ * overrides the client's own)
1405
1547
  */
1406
1548
  update(settings: Partial<T>, locale?: string, options?: ConditionalWriteOptions): Promise<T>;
1407
1549
  /**
@@ -1415,7 +1557,11 @@ declare class SettingsClient<T = unknown> {
1415
1557
  }>;
1416
1558
  /**
1417
1559
  * Reset settings to default values
1418
- * @param locale - Optional locale for localized settings
1560
+ *
1561
+ * The route reads its locale from `?locale=` and takes no body, so that is where it is sent.
1562
+ *
1563
+ * @param locale - Optional locale for localized settings (overrides the fluent locale, which
1564
+ * overrides the client's own)
1419
1565
  */
1420
1566
  reset(locale?: string, options?: ConditionalWriteOptions): Promise<T>;
1421
1567
  /**
@@ -1430,8 +1576,9 @@ declare class SettingsClient<T = unknown> {
1430
1576
  * Get version history for one locale of the settings group.
1431
1577
  *
1432
1578
  * Versions are numbered per locale, so this is one locale's timeline: `locale` defaults to the
1433
- * schema default, no fallback is applied, and a locale with no history returns an empty array
1434
- * rather than another locale's rows. Every row names the locale it belongs to.
1579
+ * fluent `.locale()`, then the client's own (`withLocale()`), then the schema default; no
1580
+ * fallback is applied, and a locale with no history returns an empty array rather than another
1581
+ * locale's rows. Every row names the locale it belongs to.
1435
1582
  */
1436
1583
  versions(options?: {
1437
1584
  limit?: number;
@@ -1443,12 +1590,14 @@ declare class SettingsClient<T = unknown> {
1443
1590
  /**
1444
1591
  * Get a specific version of the settings.
1445
1592
  *
1446
- * `locale` defaults to the schema default. Version numbers are per locale, so version 2 is
1447
- * different content in each one.
1593
+ * `locale` defaults to the fluent `.locale()`, then the client's own (`withLocale()`), then the
1594
+ * schema default. Version numbers are per locale, so version 2 is different content in each one.
1448
1595
  */
1449
1596
  version(versionNumber: number, options?: {
1450
1597
  locale?: string;
1451
1598
  }): Promise<T | null>;
1599
+ /** The locale a write or history read sends: the call's, the fluent one, else the client's. */
1600
+ private localeOf;
1452
1601
  /**
1453
1602
  * Get the settings group ID
1454
1603
  */
@@ -1499,17 +1648,27 @@ type RegisteredSchema = Register extends {
1499
1648
  */
1500
1649
  type SearchMode = 'keyword' | 'semantic' | 'hybrid';
1501
1650
  /**
1502
- * One search hit as the route emits it: the entry fields at the top level,
1503
- * plus optional score annotations. There is no per-item `data` wrapper.
1651
+ * What a search or similar hit reports beside its fields: the committed document's
1652
+ * `SearchHitMetadata`, read through `http/api-schema.ts`.
1653
+ *
1654
+ * Narrower than an entry read's `EntryMetadata`, because a hit is not built by the entry read: it
1655
+ * carries no `entryType`, `defaultLocale`, `availableLocales`, `refs`, `firstPublishedAt` or
1656
+ * version history. Until REL-1413 a hit was typed as an entry and so promised all five — the
1657
+ * locale helpers kept an optional chain after `availableLocales` for the hits that lacked it. Read
1658
+ * the entry (`content(type).findById(hit._metadata.id)`) for those.
1659
+ */
1660
+ type SearchHitMetadata = components['schemas']['SearchHitMetadata'];
1661
+ /** What a hit carries beside the entry's fields, as the document declares it. */
1662
+ type SearchHitSystemFields = Pick<components['schemas']['SearchHit'], '_metadata' | '_score' | '_scoreBreakdown' | '_highlights'>;
1663
+ /**
1664
+ * One search hit as the route emits it — the document's `SearchHit`: the fields `T` declares at the
1665
+ * top level (at `_metadata.locale`, or only the aliases a `fields` projection names), the hit's own
1666
+ * `_metadata`, and the score annotations the request asked for. There is no per-item `data` wrapper.
1667
+ *
1668
+ * `T`'s `_metadata` is replaced, not kept: `T` is an entry type, and a hit is not an entry read.
1669
+ * Distributes over a union of entry types, so a search across two types keeps each one's fields.
1504
1670
  */
1505
- type SearchResultItem<T = unknown> = T & {
1506
- _score?: number;
1507
- _scoreBreakdown?: {
1508
- keyword?: number;
1509
- semantic?: number;
1510
- };
1511
- _highlights?: Record<string, string[]>;
1512
- };
1671
+ type SearchResultItem<T = unknown> = T extends unknown ? Omit<T, '_metadata'> & SearchHitSystemFields : never;
1513
1672
  /**
1514
1673
  * Search response from API
1515
1674
  */
@@ -1529,20 +1688,12 @@ type SearchResultItem<T = unknown> = T & {
1529
1688
  */
1530
1689
  type SearchResponse<T = unknown> = Wire<'/v1/search', 'post', SearchResultItem<T>>;
1531
1690
  /**
1532
- * Autocomplete suggestion
1533
- */
1534
- interface AutocompleteSuggestion {
1535
- /** Suggested text */
1536
- text: string;
1537
- /** Highlighted version */
1538
- highlighted?: string;
1539
- /** Score */
1540
- score?: number;
1541
- /** Source entry ID */
1542
- entryId?: string;
1543
- /** Content type */
1544
- contentType?: string;
1545
- }
1691
+ * One autocomplete suggestion — the document's `AutocompleteSuggestion`: the value, its best score,
1692
+ * an entry holding it (`id`), and the value with its match wrapped in `<em>` when Atlas highlighted
1693
+ * it. The hand-written type this replaces named `highlighted`, `entryId` and `contentType`, none of
1694
+ * which the route sends, and made `score` optional where it is always sent.
1695
+ */
1696
+ type AutocompleteSuggestion = components['schemas']['AutocompleteSuggestion'];
1546
1697
  /**
1547
1698
  * Autocomplete response
1548
1699
  */
@@ -1555,11 +1706,10 @@ interface AutocompleteSuggestion {
1555
1706
  */
1556
1707
  type AutocompleteResponse = Wire<'/v1/search/autocomplete', 'post', AutocompleteSuggestion>;
1557
1708
  /**
1558
- * One similar-content hit as the route emits it — a flat entry, no `data` wrapper.
1709
+ * One similar-content hit as the route emits it: the same `SearchHit` a search serves, built by
1710
+ * the same transform, with `_score` on every hit.
1559
1711
  */
1560
- type SimilarResult<T = unknown> = T & {
1561
- _score?: number;
1562
- };
1712
+ type SimilarResult<T = unknown> = SearchResultItem<T>;
1563
1713
  /**
1564
1714
  * Similar response
1565
1715
  */
@@ -1610,19 +1760,28 @@ interface SearchSort {
1610
1760
  */
1611
1761
  declare class SearchBuilder<T extends BaseContent = BaseContent, S extends AnySchemaDefinition | undefined = undefined> {
1612
1762
  private readonly httpClient;
1613
- private readonly defaultLocale?;
1614
1763
  private query;
1615
1764
  private searchOptions;
1616
1765
  private requestHeaders?;
1766
+ private freshValue?;
1767
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
1768
+ private readonly clientLocale;
1617
1769
  /**
1618
- * @param defaultLocale - The client's locale (`withLocale()`), sent when `.locale()` names none
1770
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
1771
+ * `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
1619
1772
  */
1620
- constructor(httpClient: HttpClient, query: string, defaultLocale?: string | undefined);
1773
+ constructor(httpClient: HttpClient, query: string, locale?: ClientLocale);
1621
1774
  /**
1622
1775
  * Headers this search adds to the client's own, e.g. `X-RelyIO-Dataset` to search another
1623
1776
  * dataset the key can see. A name the client already sends is replaced for this search only.
1624
1777
  */
1625
1778
  headers(headers: Record<string, string>): this;
1779
+ /**
1780
+ * The feed position this search follows — a change's `fresh` (`FeedChange`), or a resync's. Sent
1781
+ * as `?_fresh` on the query string beside the body: the edge keys a search on both, so no answer
1782
+ * it holds from before that position can answer it. The answer is the search's own.
1783
+ */
1784
+ fresh(position: string): this;
1626
1785
  /**
1627
1786
  * Search within a single content type. Where a schema types the client, the name is one of its
1628
1787
  * content types and the results are that type's entries.
@@ -1636,7 +1795,8 @@ declare class SearchBuilder<T extends BaseContent = BaseContent, S extends AnySc
1636
1795
  */
1637
1796
  across<K extends SearchTypeName<S>>(contentTypes: K[] | '*'): SearchBuilder<SearchEntry<S, K, T>, S>;
1638
1797
  /**
1639
- * Add filter conditions
1798
+ * Add filter conditions, on the fields the content types declare. A condition on `_metadata` is
1799
+ * refused here, before anything is sent.
1640
1800
  * @param conditions - Filter conditions
1641
1801
  */
1642
1802
  where(conditions: SearchFilter): this;
@@ -1708,13 +1868,15 @@ declare class SearchBuilder<T extends BaseContent = BaseContent, S extends AnySc
1708
1868
  */
1709
1869
  declare class AutocompleteBuilder {
1710
1870
  private readonly httpClient;
1711
- private readonly defaultLocale?;
1712
1871
  private query;
1713
1872
  private autocompleteOptions;
1873
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
1874
+ private readonly clientLocale;
1714
1875
  /**
1715
- * @param defaultLocale - The client's locale (`withLocale()`), sent when `.locale()` names none
1876
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
1877
+ * `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
1716
1878
  */
1717
- constructor(httpClient: HttpClient, query: string, defaultLocale?: string | undefined);
1879
+ constructor(httpClient: HttpClient, query: string, locale?: ClientLocale);
1718
1880
  /**
1719
1881
  * Autocomplete within a content type
1720
1882
  * @param contentType - Content type to search
@@ -1730,7 +1892,8 @@ declare class AutocompleteBuilder {
1730
1892
  */
1731
1893
  fuzzy(): this;
1732
1894
  /**
1733
- * Add filter conditions
1895
+ * Add filter conditions, on the fields the content types declare. A condition on `_metadata` is
1896
+ * refused here, before anything is sent.
1734
1897
  * @param conditions - Filter conditions
1735
1898
  */
1736
1899
  where(conditions: SearchFilter): this;
@@ -1767,14 +1930,16 @@ declare class AutocompleteBuilder {
1767
1930
  */
1768
1931
  declare class SimilarBuilder<T extends BaseContent = BaseContent> {
1769
1932
  private readonly httpClient;
1770
- private readonly defaultLocale?;
1771
1933
  private sourceId;
1772
1934
  private similarOptions;
1773
1935
  private requestHeaders?;
1936
+ /** The client's locale, asked when the read is sent rather than copied when it was built. */
1937
+ private readonly clientLocale;
1774
1938
  /**
1775
- * @param defaultLocale - The client's locale (`withLocale()`), sent when `.locale()` names none
1939
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent when
1940
+ * `.locale()` names none: the function `TypedRelyIOClient` hands over, or a locale fixed for it
1776
1941
  */
1777
- constructor(httpClient: HttpClient, sourceId: string, defaultLocale?: string | undefined);
1942
+ constructor(httpClient: HttpClient, sourceId: string, locale?: ClientLocale);
1778
1943
  /**
1779
1944
  * Headers this read adds to the client's own, e.g. `X-RelyIO-Dataset` to read another dataset
1780
1945
  * the key can see. A name the client already sends is replaced for this read only.
@@ -1790,11 +1955,6 @@ declare class SimilarBuilder<T extends BaseContent = BaseContent> {
1790
1955
  * @param contentTypes - Array of content types or '*' for all
1791
1956
  */
1792
1957
  across(contentTypes: string[] | '*'): this;
1793
- /**
1794
- * Add filter conditions
1795
- * @param conditions - Filter conditions
1796
- */
1797
- where(conditions: SearchFilter): this;
1798
1958
  /**
1799
1959
  * Limit number of results
1800
1960
  * @param count - Maximum results
@@ -1845,12 +2005,14 @@ declare class SimilarBuilder<T extends BaseContent = BaseContent> {
1845
2005
  */
1846
2006
  declare class SearchClient {
1847
2007
  private readonly httpClient;
1848
- private readonly defaultLocale?;
2008
+ /** The client's locale, handed to every builder here to ask when it sends. */
2009
+ private readonly clientLocale;
1849
2010
  /**
1850
- * @param defaultLocale - The client's locale (`withLocale()`): every builder here sends it when
1851
- * the query names none, as `content()`'s reads do
2011
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`): every builder
2012
+ * here sends it when the query names none, as `content()`'s reads do — the function
2013
+ * `TypedRelyIOClient` hands over, or a locale fixed for this client
1852
2014
  */
1853
- constructor(httpClient: HttpClient, defaultLocale?: string | undefined);
2015
+ constructor(httpClient: HttpClient, locale?: ClientLocale);
1854
2016
  /**
1855
2017
  * Start a search query
1856
2018
  * @param query - Search query string
@@ -1866,12 +2028,6 @@ declare class SearchClient {
1866
2028
  * @param sourceId - Entry ID to find similar content for
1867
2029
  */
1868
2030
  similar<T extends BaseContent = BaseContent>(sourceId: string): SimilarBuilder<T>;
1869
- /**
1870
- * Quick search helper - searches all content types
1871
- * @param query - Search query
1872
- * @param limit - Max results (default 20)
1873
- */
1874
- global<T extends BaseContent = BaseContent>(query: string, limit?: number): Promise<SearchResponse<T>>;
1875
2031
  }
1876
2032
 
1877
2033
  /**
@@ -1900,7 +2056,10 @@ interface BatchOptions {
1900
2056
  *
1901
2057
  * Requires that all operations be the same kind of write — one transaction cannot span two
1902
2058
  * calls — so a batch mixing creates and deletes, or `update` and `replace`, is rejected with
1903
- * a 400 before anything is attempted.
2059
+ * a 400 before anything is attempted: `execute()` rejects with `InvalidPayloadError`. A
2060
+ * singleton write is a create when the dataset has never written that singleton and an update
2061
+ * after, and an atomic batch cannot create one — that operation reports `REQUEST_INVALID` and
2062
+ * every other `TRANSACTION_ROLLED_BACK` — so create it in a request of its own first.
1904
2063
  *
1905
2064
  * @default false
1906
2065
  */
@@ -1958,16 +2117,33 @@ type BatchResponse = components['schemas']['MultiPayload'];
1958
2117
  /**
1959
2118
  * Fluent builder for batch operations
1960
2119
  *
2120
+ * Every create, update, replace and singleton operation it builds is in the locale that operation
2121
+ * names, and otherwise in the client's own (`withLocale()`), sent as that operation's
2122
+ * `body.locale` — a batch is one request, but the API reads a locale per operation. A delete names
2123
+ * none (it removes the whole entry), and a `raw()` operation is sent exactly as written.
2124
+ *
2125
+ * An atomic batch — `.atomic()` or `execute({ atomic: true })` — is one transaction: every
2126
+ * operation lands or none does. The API accepts one only when every operation is the same kind of
2127
+ * write and none writes a singleton that does not exist yet (see {@link BatchOptions.atomic}).
2128
+ *
1961
2129
  * @example
1962
2130
  * ```typescript
2131
+ * // Each operation lands or fails on its own
1963
2132
  * const result = await relyio.batch()
1964
2133
  * .create('product', { content: { title: 'iPhone', price: 999 } })
1965
2134
  * .update('product', 'entry_abc', { content: { price: 899 } })
1966
2135
  * .delete('product', 'entry_xyz')
1967
2136
  * .upsertSingleton('homepage', { content: { hero: 'Welcome!' } })
1968
- * .execute({ atomic: true })
2137
+ * .execute()
2138
+ *
2139
+ * console.log(result.summary.succeeded)
1969
2140
  *
1970
- * console.log(result.summary.succeeded) // 4
2141
+ * // All or nothing: one kind of write
2142
+ * await relyio.batch()
2143
+ * .create('product', { content: { title: 'iPhone', price: 999 } })
2144
+ * .create('product', { content: { title: 'iPad', price: 799 } })
2145
+ * .atomic()
2146
+ * .execute()
1971
2147
  * ```
1972
2148
  */
1973
2149
  declare class BatchBuilder<TSchema = unknown> {
@@ -1975,7 +2151,19 @@ declare class BatchBuilder<TSchema = unknown> {
1975
2151
  private operations;
1976
2152
  private defaultOptions;
1977
2153
  private requestHeaders;
1978
- constructor(httpClient: HttpClient);
2154
+ /** The client's locale, asked as each operation is added rather than copied when this was built. */
2155
+ private readonly clientLocale;
2156
+ /**
2157
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), each
2158
+ * operation's when it names none: the function `TypedRelyIOClient` hands over, or a locale fixed
2159
+ * for this batch
2160
+ */
2161
+ constructor(httpClient: HttpClient, locale?: ClientLocale);
2162
+ /**
2163
+ * An operation's body with its locale: the one it names, else the client's as it is when the
2164
+ * operation is added.
2165
+ */
2166
+ private localized;
1979
2167
  /**
1980
2168
  * Add a create operation
1981
2169
  * @param contentType - Content type to create
@@ -2053,7 +2241,8 @@ declare class BatchBuilder<TSchema = unknown> {
2053
2241
  locale?: string;
2054
2242
  }, id?: string): this;
2055
2243
  /**
2056
- * Add a raw operation (for advanced use cases)
2244
+ * Add a raw operation (for advanced use cases). It is sent exactly as written: the client's
2245
+ * locale is not added to it.
2057
2246
  * @param operation - The operation to add
2058
2247
  */
2059
2248
  raw(operation: BatchOperation): this;
@@ -2170,9 +2359,15 @@ declare class BatchBuilder<TSchema = unknown> {
2170
2359
  */
2171
2360
  declare class BatchClient<TSchema = unknown> {
2172
2361
  private readonly httpClient;
2173
- constructor(httpClient: HttpClient);
2362
+ /** The client's locale, handed to every batch this builds to ask as operations are added. */
2363
+ private readonly clientLocale;
2364
+ /**
2365
+ * @param locale - The client's locale: the function `TypedRelyIOClient` hands over, or a locale
2366
+ * fixed for this client
2367
+ */
2368
+ constructor(httpClient: HttpClient, locale?: ClientLocale);
2174
2369
  /**
2175
- * Create a new batch builder
2370
+ * Create a new batch builder, whose operations default to this client's locale
2176
2371
  */
2177
2372
  create(): BatchBuilder<TSchema>;
2178
2373
  /**
@@ -2251,13 +2446,14 @@ interface AggregateBlock {
2251
2446
  }
2252
2447
  /**
2253
2448
  * One metric, as the Query DSL writes it: `<field>.<fn>`, where `fn` is `count`, `sum`, `avg`,
2254
- * `min` or `max` — `'id.count'`, `'pricing.basePrice.avg'`. The service validates every metric
2255
- * against that form (`INVALID_AGGREGATION_EXPRESSION`); `count` ignores the field it names.
2449
+ * `min`, `max`, `first` or `last` — `'id.count'`, `'pricing.basePrice.avg'`. The service
2450
+ * validates every metric against that form (`INVALID_AGGREGATION_EXPRESSION`); `count` ignores the
2451
+ * field it names. `first` and `last` were missing here while the service ran them (REL-1470).
2256
2452
  *
2257
2453
  * It used to be `{ fn, field? }`, a shape the service refuses on every request: the validator
2258
2454
  * tests the metric as a string, so an object arrives as `[object Object]`.
2259
2455
  */
2260
- type AggregateMetric = `${string}.${'count' | 'sum' | 'avg' | 'min' | 'max'}`;
2456
+ type AggregateMetric = `${string}.${'count' | 'sum' | 'avg' | 'min' | 'max' | 'first' | 'last'}`;
2261
2457
  /**
2262
2458
  * Search block for full-text/semantic search
2263
2459
  */
@@ -2276,36 +2472,11 @@ interface SearchBlock {
2276
2472
  limit?: number;
2277
2473
  }
2278
2474
  /**
2279
- * Similar block for vector similarity search
2475
+ * One post-fetch filter: a parameter expression, or the operators every query clause compares with
2476
+ * (`FilterOperator`, REL-1479). This kept a copy of eleven, without `exists` or `notExists`; and a
2477
+ * bare number or boolean, which it took, the service does not read as a filter.
2280
2478
  */
2281
- interface SimilarBlock {
2282
- /** Content type */
2283
- contentType: string;
2284
- /** Source entry ID */
2285
- source: string;
2286
- /** Minimum similarity threshold */
2287
- threshold?: number;
2288
- /** Additional filters */
2289
- where?: Record<string, unknown>;
2290
- /** Maximum results */
2291
- limit?: number;
2292
- }
2293
- /**
2294
- * Post-fetch filters with parameter support
2295
- */
2296
- type FilterValue = string | number | boolean | {
2297
- eq?: unknown;
2298
- ne?: unknown;
2299
- gt?: unknown;
2300
- gte?: unknown;
2301
- lt?: unknown;
2302
- lte?: unknown;
2303
- in?: unknown[];
2304
- nin?: unknown[];
2305
- contains?: unknown;
2306
- startsWith?: string;
2307
- endsWith?: string;
2308
- };
2479
+ type FilterValue = string | FilterOperator;
2309
2480
  /**
2310
2481
  * Full-text search configuration
2311
2482
  */
@@ -2327,8 +2498,6 @@ interface AdhocQueryDefinition {
2327
2498
  aggregate?: AggregateBlock;
2328
2499
  /** Search block - full-text/semantic search */
2329
2500
  search?: SearchBlock;
2330
- /** Similar block - vector similarity */
2331
- similar?: SimilarBlock;
2332
2501
  /** Field selection/transformation */
2333
2502
  select?: Record<string, string>;
2334
2503
  /** Post-fetch filters with parameter support */
@@ -2416,15 +2585,17 @@ interface AdhocQueryResult<T = unknown> {
2416
2585
  */
2417
2586
  declare class AdhocQueryBuilder<T = unknown> {
2418
2587
  private readonly httpClient;
2419
- private readonly defaultLocale?;
2420
2588
  private queryDef;
2421
2589
  private parameters;
2422
2590
  private options;
2591
+ /** The client's locale, asked when the query is sent rather than copied when it was built. */
2592
+ private readonly clientLocale;
2423
2593
  /**
2424
- * @param defaultLocale - The client's locale (`withLocale()`), sent as the `locale` parameter
2425
- * when `.param('locale', …)` binds none
2594
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent as the
2595
+ * `locale` parameter when `.param('locale', …)` binds none: the function `TypedRelyIOClient`
2596
+ * hands over, or a locale fixed for this builder
2426
2597
  */
2427
- constructor(httpClient: HttpClient, defaultLocale?: string | undefined);
2598
+ constructor(httpClient: HttpClient, locale?: ClientLocale);
2428
2599
  /**
2429
2600
  * Add a fetch block to retrieve content
2430
2601
  * @param config - Fetch configuration
@@ -2450,11 +2621,6 @@ declare class AdhocQueryBuilder<T = unknown> {
2450
2621
  * @param config - Search configuration
2451
2622
  */
2452
2623
  search(config: SearchBlock): this;
2453
- /**
2454
- * Add similar block
2455
- * @param config - Similar configuration
2456
- */
2457
- similar(config: SimilarBlock): this;
2458
2624
  /**
2459
2625
  * Add where conditions to fetch
2460
2626
  * @param conditions - Filter conditions
@@ -2583,12 +2749,14 @@ declare class AdhocQueryBuilder<T = unknown> {
2583
2749
  */
2584
2750
  declare class AdhocQueryClient {
2585
2751
  private readonly httpClient;
2586
- private readonly defaultLocale?;
2752
+ /** The client's locale, asked on every query rather than copied when this client was taken. */
2753
+ private readonly clientLocale;
2587
2754
  /**
2588
- * @param defaultLocale - The client's locale (`withLocale()`), sent as the `locale` parameter of
2589
- * every query that binds none
2755
+ * @param locale - The client's locale (`withLocale()`, `updateConfig({ locale })`), sent as the
2756
+ * `locale` parameter of every query that binds none: the function `TypedRelyIOClient` hands
2757
+ * over, or a locale fixed for this client
2590
2758
  */
2591
- constructor(httpClient: HttpClient, defaultLocale?: string | undefined);
2759
+ constructor(httpClient: HttpClient, locale?: ClientLocale);
2592
2760
  /**
2593
2761
  * Create a new query builder
2594
2762
  */
@@ -2697,8 +2865,34 @@ type ChangesPageBody = PollChanges['responses'][200]['content']['application/jso
2697
2865
  * item, and fails if it is ever `unknown` again.
2698
2866
  */
2699
2867
  type Change = ChangesPageBody['data'][number];
2700
- /** Why a cursor could no longer be replayed. `unknown` when the message named neither. */
2701
- type ChangesExpiredReason = 'retention' | 'dataset-replaced' | 'unknown';
2868
+ /**
2869
+ * A change as `relyio.changes()` and `relyio.liveChanges()` deliver it: the document's
2870
+ * {@link Change}, and `fresh`.
2871
+ *
2872
+ * `fresh` is the feed position a refetch for this change names, as the one query term the API
2873
+ * declares on every read its edge may keep (`?_fresh`, `sdk-surfaces-spec.md` decision 32): hand it
2874
+ * to the read — `.fresh(change.fresh)` on `findById()`, `query()` and `search()`, `{ fresh }` to a
2875
+ * singleton's `fetch()`. A position no request named before the change is a key no cache holds a
2876
+ * body under, so the read is answered after the change — at the edge and in the browser, whether
2877
+ * or not the change's purge has reached them — and every later read naming it shares that answer.
2878
+ *
2879
+ * It is at or after the change, never before: on `/v1/changes` the change's own cursor, the ledger
2880
+ * row it came from; at the live edge the cursor of the batch it arrived in. It is not always
2881
+ * `cursor`: at the edge an earlier change of a batch carries the position **before** the batch as
2882
+ * its `cursor`, so a failure part-way through replays the batch, and a refetch naming that position
2883
+ * would be answered from before the change.
2884
+ */
2885
+ type FeedChange = Change & {
2886
+ /** The feed position a refetch for this change names (`?_fresh`); at or after the change. */
2887
+ readonly fresh: string;
2888
+ };
2889
+ /**
2890
+ * Why a cursor could no longer be replayed, or why everything must be refetched. `/v1/changes`
2891
+ * names `retention` and `dataset-replaced`; the live edge's `feed.resync` may name any reason its
2892
+ * wire declares (`VisitorResyncReason` in `@relyio/api-contract`, read from there rather than
2893
+ * restated). `unknown` when the message named none.
2894
+ */
2895
+ type ChangesExpiredReason = VisitorResyncReason | 'unknown';
2702
2896
  /**
2703
2897
  * `RESOURCE_EXPIRED` from the changes feed: the cursor names a position the
2704
2898
  * ledger can no longer replay from (`INV-SS-CURSOR-REPLAYS`). The consumer
@@ -2707,12 +2901,28 @@ type ChangesExpiredReason = 'retention' | 'dataset-replaced' | 'unknown';
2707
2901
  * A `ResourceExpiredError`, so code that already catches that still does. The
2708
2902
  * refusal declares no details, so `reason` is read from the message the api
2709
2903
  * writes (`apps/services/api/src/changes/changes-request.ts` `refusalOf`).
2904
+ *
2905
+ * The live edge's `feed.resync` — a socket's frame or a poll's answer — is the
2906
+ * same instruction and arrives as the same error ({@link ChangesExpiredError.resync}),
2907
+ * so `onExpired` means one thing on both transports.
2710
2908
  */
2711
2909
  declare class ChangesExpiredError extends ResourceExpiredError {
2712
2910
  readonly reason: ChangesExpiredReason;
2713
- /** The base class's signature, so `withContext` can rebuild one. */
2714
- constructor(message: string, statusCode?: number, cause?: Error, context?: Record<string, unknown>);
2715
- static of(expired: ResourceExpiredError): ChangesExpiredError;
2911
+ /**
2912
+ * The position the feed resynced to, which a refetch of everything names as `?_fresh`, as a
2913
+ * change's {@link FeedChange.fresh} is named: the head a `/v1/changes` resync took, or the cursor
2914
+ * the edge's `feed.resync` sent. `undefined` when there was no resync to take one — the error was
2915
+ * thrown (`onExpired: 'throw'`) — and on an error a caller built itself.
2916
+ */
2917
+ readonly fresh: string | undefined;
2918
+ /** The base class's signature, so `withContext` can rebuild one; then the position resynced to. */
2919
+ constructor(message: string, statusCode?: number, cause?: Error, context?: Record<string, unknown>, fresh?: string);
2920
+ /** The base class rebuilds from its four arguments, which would drop the position resynced to. */
2921
+ withContext(context: Record<string, unknown>): this;
2922
+ /** `/v1/changes`' refusal, with the head the feed resynced to when it did. */
2923
+ static of(expired: ResourceExpiredError, fresh?: string): ChangesExpiredError;
2924
+ /** The live edge's `feed.resync`: refetch everything, then continue from the cursor it sent. */
2925
+ static resync(reason: VisitorResyncReason, cursor: string): ChangesExpiredError;
2716
2926
  }
2717
2927
  interface ChangesOptions {
2718
2928
  /**
@@ -2746,7 +2956,8 @@ interface ChangesOptions {
2746
2956
  * - a function — resync, and call it with the error once the new position is
2747
2957
  * taken and before any change after it is yielded. This is the observable
2748
2958
  * form: whatever the consumer derived from the feed may be stale, so the
2749
- * function is where it invalidates everything. The iterator waits for it.
2959
+ * function is where it invalidates everything — naming the error's `fresh`,
2960
+ * the new position, on every refetch. The iterator waits for it.
2750
2961
  */
2751
2962
  onExpired?: 'throw' | 'resync' | ((expired: ChangesExpiredError) => void | Promise<void>);
2752
2963
  }
@@ -2755,6 +2966,81 @@ interface ChangesHeadOptions {
2755
2966
  signal?: AbortSignal;
2756
2967
  }
2757
2968
 
2969
+ /**
2970
+ * `relyio.liveChanges()` — a dataset's published changes at RelyIO's live edge, for a publishable key
2971
+ * (`live-layer-spec.md` decision 20; LV5.2, REL-1158).
2972
+ *
2973
+ * The wire is `@relyio/api-contract`'s `live-visitor.ts`, read from there and never restated: the
2974
+ * path and query names, the frames and their reader, the keepalive, the poll's answer and its reader,
2975
+ * the poll interval, and what each close code and each refused poll means a client does next.
2976
+ *
2977
+ * **One open, two ways in.** A subscription opens a WebSocket to the edge. Where it cannot — the
2978
+ * runtime has no `WebSocket` (Node 18 and 20), constructing one throws, or the socket fails before it
2979
+ * opens (a network that blocks sockets) — it polls the edge instead, from the same cursor, about
2980
+ * every {@link VISITOR_POLL_INTERVAL_MS}, and tries a socket again about once a minute. Both carry
2981
+ * one cursor space, so a switch either way loses nothing.
2982
+ *
2983
+ * **It ends only when its signal aborts, and throws every other end** — a socket closed by a refusal
2984
+ * or a deploy, a refused poll, a keepalive nobody answered — as a `LiveEdgeError` saying what to do
2985
+ * next, so `followChanges()` reconnects, backs off or stops by the edge's own tables. That loop is
2986
+ * the one reconnect policy (`INV-SS-ONE-CORE`, REL-1215); this module keeps no back-off of its own.
2987
+ *
2988
+ * **Cursors.** The edge sends one cursor after a batch of changes. The last change of a batch carries
2989
+ * it; each earlier one carries the position before the batch, so a failure part-way through a batch
2990
+ * replays the whole batch rather than skipping its rest. Delivery is at-least-once: a replay and the
2991
+ * live frames after it may name one change twice, and a refetch makes a repeat cost a read, never a
2992
+ * wrong view (`INV-SS-CHANGE-IS-IDS`).
2993
+ *
2994
+ * **What a refetch names.** Every change of a batch carries the batch's own cursor as `fresh`
2995
+ * (`FeedChange`), the position its refetch names as `?_fresh` — not `cursor`, which for an earlier
2996
+ * change is the position before the batch: the previous batch's refetches were answered under that
2997
+ * one, before this batch, and a cache would hand the same answer back. A `feed.resync`'s error
2998
+ * carries the cursor it sent the same way.
2999
+ */
3000
+
3001
+ /**
3002
+ * How often an open socket sends the keepalive, which the edge's runtime answers without waking the
3003
+ * feed — the Studio's dataset room sends its own on the same interval. A socket that has heard
3004
+ * nothing by the next one, not even the answer, is presumed dead and reconnected: a client that only
3005
+ * receives never learns otherwise that a network change dropped its connection.
3006
+ */
3007
+ declare const LIVE_KEEPALIVE_INTERVAL_MS = 30000;
3008
+ interface LiveChangesOptions {
3009
+ /**
3010
+ * A change's cursor from an earlier subscription. Omitted, the edge answers the dataset's current
3011
+ * position first and replays nothing; fetch what you show **after** that position arrives — with
3012
+ * `followChanges()`, after `onState` reports `following` — so nothing lands in between unseen.
3013
+ */
3014
+ since?: string;
3015
+ /** Content types to keep. Omitted keeps every type; an empty list is refused. At most 50. */
3016
+ types?: readonly string[];
3017
+ /** Entry ids to keep. Omitted keeps every entry; an empty list is refused. At most 100. */
3018
+ ids?: readonly string[];
3019
+ /**
3020
+ * Ends the subscription. An abort — while connected, while polling, or between polls — makes the
3021
+ * `for await` **complete**, with the socket closed, no further request and nothing thrown.
3022
+ */
3023
+ signal?: AbortSignal;
3024
+ /**
3025
+ * What to do when the edge says to refetch everything (`feed.resync`: the cursor is too old, was
3026
+ * never this dataset's, or the dataset was replaced) — as `relyio.changes()` takes it: `'throw'`
3027
+ * (default) throws a `ChangesExpiredError`, `'resync'` carries on from the edge's position, and a
3028
+ * function is awaited with the error before any change after that position is yielded.
3029
+ */
3030
+ onExpired?: ChangesOptions['onExpired'];
3031
+ /**
3032
+ * Called when the edge has the subscription in hand — its `feed.opened` frame, or an answered
3033
+ * poll. `followChanges()` passes it to reset its back-off; see `ChangeSourceOptions.opened`.
3034
+ */
3035
+ opened?: () => void;
3036
+ /**
3037
+ * Called with a position reached without a change to carry it. `followChanges()` passes it so a
3038
+ * connection dropped before its first change reconnects from there; see
3039
+ * `ChangeSourceOptions.reached`.
3040
+ */
3041
+ reached?: (cursor: string) => void;
3042
+ }
3043
+
2758
3044
  /**
2759
3045
  * The key's project, as `GET /v1/project` describes it: organization, project, dataset and branch,
2760
3046
  * each by id and name, and `studioUrl` — the Studio root the preview toolbar deep-links from
@@ -2797,13 +3083,27 @@ interface TypedClientConfig<TSchema extends AnySchemaDefinition | undefined = un
2797
3083
  * ```
2798
3084
  */
2799
3085
  declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined = undefined> {
2800
- private httpClient;
3086
+ /**
3087
+ * The one HTTP client every sub-client sends through. `updateConfig()` and `setApiKey()` change it
3088
+ * in place rather than replacing it, so a sub-client taken before either sends through the change.
3089
+ */
3090
+ private readonly httpClient;
2801
3091
  private config;
3092
+ /**
3093
+ * The configuration as `createClient()`, `setApiKey()` and `updateConfig()` gave it, before the
3094
+ * `relyio dev` handshake: what the next update is laid over, and what `withLocale()` starts from.
3095
+ */
3096
+ private configured;
2802
3097
  private _sandbox;
2803
- private _search;
2804
- private _batch;
2805
- private _adhocQuery;
2806
3098
  private _schema;
3099
+ /**
3100
+ * The client's locale as it is when a call is made. Every sub-client and builder is handed this
3101
+ * rather than a copy of the locale, so one taken before `updateConfig({ locale })` sends the new
3102
+ * locale, or none after `locale: null` (REL-1453).
3103
+ */
3104
+ private readonly currentLocale;
3105
+ /** The live edge's poll client id: chosen once, when first needed, and kept for this client's life. */
3106
+ private _liveClientId;
2807
3107
  constructor(config: TypedClientConfig<TSchema>);
2808
3108
  /**
2809
3109
  * Get the schema definition
@@ -2825,7 +3125,7 @@ declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined
2825
3125
  */
2826
3126
  get sandbox(): SandboxState;
2827
3127
  /**
2828
- * Get the ad-hoc query client
3128
+ * Get the ad-hoc query client. Every query it sends is in the client's locale as it is then.
2829
3129
  */
2830
3130
  get query(): AdhocQueryClient;
2831
3131
  /**
@@ -2932,7 +3232,11 @@ declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined
2932
3232
  */
2933
3233
  similar<T extends BaseContent = BaseContent>(sourceId: string): SimilarBuilder<T>;
2934
3234
  /**
2935
- * Start a batch operation for bulk create/update/delete
3235
+ * Start a batch operation for bulk create/update/delete.
3236
+ *
3237
+ * By default each operation lands or fails on its own. `atomic: true` makes the batch one
3238
+ * transaction, which the API accepts only when every operation is the same kind of write and none
3239
+ * writes a singleton that does not exist yet.
2936
3240
  *
2937
3241
  * @example
2938
3242
  * ```typescript
@@ -2941,12 +3245,20 @@ declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined
2941
3245
  * .update('product', 'entry_abc', { content: { price: 899 } })
2942
3246
  * .delete('product', 'entry_xyz')
2943
3247
  * .upsertSingleton('homepage', { content: { hero: 'Welcome!' } })
2944
- * .execute({ atomic: true })
3248
+ * .execute()
2945
3249
  *
2946
3250
  * console.log(result.summary.succeeded)
3251
+ *
3252
+ * // All or nothing: one kind of write
3253
+ * await relyio.batch()
3254
+ * .update('product', 'entry_abc', { content: { price: 899 } })
3255
+ * .update('product', 'entry_def', { content: { price: 799 } })
3256
+ * .execute({ atomic: true })
2947
3257
  * ```
2948
3258
  */
2949
3259
  batch(): BatchBuilder<NonNullable<TSchema>>;
3260
+ /** The search client, whose builders send the client's locale as it is when each one is sent. */
3261
+ private searchClient;
2950
3262
  /**
2951
3263
  * Follow the dataset's changes feed: each write this key can see, as ids, in
2952
3264
  * order, long-polled from `GET /v1/changes`.
@@ -2954,13 +3266,15 @@ declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined
2954
3266
  * Lazy — nothing is requested until the first `next()`. It runs until
2955
3267
  * `signal` aborts, which ends the `for await` cleanly rather than throwing.
2956
3268
  * A change names what changed; refetch it through the ordinary read path
2957
- * (`INV-SS-CHANGE-IS-IDS`).
3269
+ * (`INV-SS-CHANGE-IS-IDS`), naming its `fresh` so no cache answers with the
3270
+ * body from before it (`FeedChange`).
2958
3271
  *
2959
3272
  * @example
2960
3273
  * ```typescript
2961
3274
  * const controller = new AbortController()
2962
3275
  * for await (const change of relyio.changes({ since: cursor, types: ['post'], signal: controller.signal })) {
2963
- * // { entryId, contentType, locale, kind, cursor }
3276
+ * // { entryId, contentType, locale, kind, cursor, fresh }
3277
+ * await relyio.content(change.contentType).findById(change.entryId).fresh(change.fresh).execute()
2964
3278
  * }
2965
3279
  * ```
2966
3280
  *
@@ -2968,11 +3282,42 @@ declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined
2968
3282
  * ```typescript
2969
3283
  * for await (const change of relyio.changes({
2970
3284
  * since: cursor,
2971
- * onExpired: async () => invalidateEverything(),
3285
+ * onExpired: async expired => refetchEverything(expired.fresh),
2972
3286
  * })) { … }
2973
3287
  * ```
2974
3288
  */
2975
- changes(options?: ChangesOptions): AsyncIterable<Change>;
3289
+ changes(options?: ChangesOptions): AsyncIterable<FeedChange>;
3290
+ /**
3291
+ * Follow the dataset's **published** changes at RelyIO's live edge, with a publishable key
3292
+ * (`rly_pub_…`): each change as ids, in order — the transport a browser follows changes with.
3293
+ *
3294
+ * A WebSocket to the edge, from `since` or the dataset's current position; where a socket cannot
3295
+ * open — the runtime has none, or the network refuses it — it polls the edge instead, about every
3296
+ * fifteen seconds, from the same cursor. The edge is `liveUrl`, or derived from the default
3297
+ * `baseUrl` (see `RelyIOConfig.liveUrl`).
3298
+ *
3299
+ * One subscription ends only when `signal` aborts, which ends the `for await` cleanly; every other
3300
+ * end — a socket a deploy dropped, a refusal, a refused poll — is thrown as a `LiveEdgeError`
3301
+ * that says whether to stop, retry or back off. Hand it to `followChanges()`, the one loop that
3302
+ * reconnects from the last cursor with jittered back-off and honours those answers:
3303
+ *
3304
+ * @example
3305
+ * ```typescript
3306
+ * const relyio = createClient({ apiKey: 'rly_pub_…' })
3307
+ * const controller = new AbortController()
3308
+ * await followChanges(from => relyio.liveChanges({ ...from, types: ['post'] }), {
3309
+ * signal: controller.signal,
3310
+ * // `fresh` names a position no cache holds a body for from before the change.
3311
+ * onChange: change =>
3312
+ * relyio.content(change.contentType).findById(change.entryId).fresh(change.fresh).execute(),
3313
+ * onResync: resync => refetchEverything(resync.cause === 'expired' ? resync.expired.fresh : undefined),
3314
+ * })
3315
+ * ```
3316
+ *
3317
+ * A client without a publishable key sends nothing: a secret or preview key is never put in the
3318
+ * edge's URL. On a server, follow `changes()` with it instead.
3319
+ */
3320
+ liveChanges(options?: LiveChangesOptions): AsyncIterable<FeedChange>;
2976
3321
  /**
2977
3322
  * The dataset's current position in the changes feed, as a cursor to start
2978
3323
  * `changes({ since })` or `followChanges(…, { since })` from. One
@@ -3065,15 +3410,73 @@ declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined
3065
3410
  */
3066
3411
  testConnection(): Promise<boolean>;
3067
3412
  /**
3068
- * Update the configuration and reinitialize all clients
3413
+ * Change some of the client's options and keep the rest.
3414
+ *
3415
+ * What you pass is laid over the configuration the client holds, field by field:
3416
+ *
3417
+ * - an option you name replaces the value the client holds;
3418
+ * - an option left out, or given as `undefined`, keeps the value the client holds;
3419
+ * - an option with no default given as `null` is cleared — `locale`, `dataset`, `apiKey`, `dev`,
3420
+ * `fetch`, `browser.onCorsError`, `realtime.wsUrl`, `debug.logger` — so the client runs as though
3421
+ * it had never been given one. An option with a default takes no `null`;
3422
+ * - a bag of options you name — `browser`, `cache`, `realtime`, `debug` — keeps every field of it
3423
+ * you do not name, so `updateConfig({ browser: { includeCredentials: true } })` keeps a
3424
+ * configured `onCorsError`;
3425
+ * - `headers` is laid over the headers the client sends, a name matched without regard to case: a
3426
+ * header you name is added or replaces every spelling of it, every other one is still sent, and a
3427
+ * header given as `null` is no longer sent;
3428
+ * - naming `apiKey` — a key, or `null` — replaces every key the client holds, one given in
3429
+ * `headers` included.
3430
+ *
3431
+ * The configuration it is laid over is what `createClient()`, `setApiKey()` and earlier updates
3432
+ * gave the client. The `relyio dev` handshake is read again, as `createClient()` reads it: while a
3433
+ * sandbox is active its key and dataset are sent over the configured ones, and once it has gone
3434
+ * the configured ones are.
3435
+ *
3436
+ * The client's one HTTP client is changed in place, so every request from now on is sent as the
3437
+ * update says — including one from a `content()`, `asset()`, `singleton()` or `settings()`
3438
+ * sub-client, a `query` client, or a builder such as `search()` or `batch()`, taken before the
3439
+ * call. The locale reaches them too: each reads the client's locale when it sends, so a new
3440
+ * `locale` is the default of its next request and `locale: null` leaves that request with none. A
3441
+ * locale the call names, and a sub-client's own `withLocale()`, still win over it. A client made
3442
+ * by `withLocale()` is a client of its own: an update of this one does not reach it.
3443
+ *
3444
+ * @example
3445
+ * ```typescript
3446
+ * const relyio = createClient({ apiKey, headers: { 'X-Tenant': 'acme' }, browser: { onCorsError } })
3447
+ *
3448
+ * relyio.updateConfig({ headers: { 'X-Trace': traceId } }) // X-Tenant is still sent
3449
+ * relyio.updateConfig({ browser: { includeCredentials: true } }) // onCorsError is kept
3450
+ * relyio.updateConfig({ headers: { 'X-Tenant': null } }) // X-Tenant is no longer sent
3451
+ * relyio.updateConfig({ locale: null }) // reads name no locale of the client's
3452
+ * ```
3069
3453
  */
3070
- updateConfig(newConfig: Partial<RelyIOConfig>): void;
3454
+ updateConfig(update: RelyIOConfigUpdate): void;
3071
3455
  /**
3072
3456
  * Get the current configuration
3073
3457
  */
3074
3458
  getConfig(): Readonly<MergedRelyIOConfig>;
3075
3459
  /**
3076
- * Set the API key
3460
+ * Replace the API key every later request sends as `X-API-Key`.
3461
+ *
3462
+ * It reaches every request this client makes from now on, including those of a `content()`,
3463
+ * `asset()` or other sub-client taken before the call, and `getConfig().apiKey` reports it. A key
3464
+ * given in `headers`, under any spelling, is replaced with it and does not come back on a later
3465
+ * `updateConfig()`. A client already derived with `withLocale()` is a client of its own and keeps
3466
+ * its key.
3467
+ *
3468
+ * An empty or blank key is no key, as it is when passed to `createClient`: the next request
3469
+ * rejects with `MissingApiKeyError` and nothing is sent.
3470
+ *
3471
+ * Under an active `relyio dev` sandbox the sandbox's scoped key stands, as it does over the key
3472
+ * passed to `createClient` — replacing the configured key does not retarget the client at the
3473
+ * sandbox's dataset with a key the sandbox did not issue.
3474
+ *
3475
+ * @example
3476
+ * ```typescript
3477
+ * const relyio = createClient({ apiKey: process.env.RELYIO_API_KEY! })
3478
+ * relyio.setApiKey(rotatedKey) // the next read sends `X-API-Key: <rotatedKey>`
3479
+ * ```
3077
3480
  */
3078
3481
  setApiKey(apiKey: string): void;
3079
3482
  /**
@@ -3083,9 +3486,12 @@ declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined
3083
3486
  /**
3084
3487
  * Create a locale-scoped client
3085
3488
  *
3086
- * Every read the returned client builds — `content()`, `asset()`, `singleton()`, `settings()`,
3087
- * `search()`, `similar()`, `autocomplete()`, `executeQuery()` and the ad-hoc queries — is in this
3088
- * locale unless the call names one of its own, which wins.
3489
+ * Every call the returned client builds is in this locale unless the call names one of its own,
3490
+ * which wins: every read — `content()`, `asset()`, `singleton()`, `settings()`, `search()`,
3491
+ * `similar()`, `autocomplete()`, `executeQuery()` and the ad-hoc queries — and every write and
3492
+ * version-history read — `create()` and `update()`, the singleton and settings writes, the asset
3493
+ * file writes, `versions()` and `version()`, and each operation `batch()` builds. `restore()`
3494
+ * always names its locale; a delete, and a `batch().raw()` operation, carry none of the client's.
3089
3495
  *
3090
3496
  * Type-safe when schema is provided: autocompletes valid locale codes!
3091
3497
  *
@@ -3093,10 +3499,11 @@ declare class TypedRelyIOClient<TSchema extends AnySchemaDefinition | undefined
3093
3499
  * ```typescript
3094
3500
  * const spanish = relyio.withLocale('es-ES') // ← Autocompletes with schema!
3095
3501
  *
3096
- * // Reads use Spanish
3502
+ * // Reads and writes use Spanish
3097
3503
  * const products = await spanish.content('product').query().execute()
3098
3504
  * const homepage = await spanish.singleton('homepage').fetch()
3099
3505
  * const results = await spanish.search('zapatos').execute()
3506
+ * await spanish.content('product').update(id, { title: 'Zapatos' })
3100
3507
  *
3101
3508
  * // Original client unchanged
3102
3509
  * const englishProducts = await relyio.content('product').query().execute()
@@ -3192,4 +3599,4 @@ declare function createClient<TSchema extends AnySchemaDefinition>(config: Typed
3192
3599
  */
3193
3600
  type ClientSchema<T extends TypedRelyIOClient<AnySchemaDefinition>> = T extends TypedRelyIOClient<infer TSchema> ? TSchema : never;
3194
3601
 
3195
- export { AdhocQueryBuilder as $, type ActiveSandbox as A, type SearchResponse as B, ChangesExpiredError as C, type AutocompleteSuggestion as D, type ExtendedQueryResult as E, type AutocompleteResponse as F, type SimilarResult as G, HttpClient as H, type SimilarResponse as I, type SearchFilter as J, type SearchFields as K, type SearchSort as L, type SearchTypeName as M, type SearchEntry as N, BatchClient as O, type Project as P, BatchBuilder as Q, type Register as R, type SandboxState as S, TypedRelyIOClient as T, type BatchMethod as U, type BatchOperation as V, type BatchOptions as W, type BatchOperationResult as X, type BatchSummary as Y, type BatchResponse as Z, AdhocQueryClient as _, type Change as a, type FetchBlock as a0, type AggregateBlock as a1, type AggregateMetric as a2, type SearchBlock as a3, type SimilarBlock as a4, type FilterValue as a5, type FullTextConfig as a6, type AdhocQueryDefinition as a7, type AdhocQueryOptions as a8, type QueryMetadata as a9, ResourceConflictError as aA, ResourceExpiredError as aB, isResourceNotFound as aC, type FileErrorCode as aD, FileUploadError as aE, FileValidationError as aF, type FileValidationConstraints as aG, validateFile as aH, type AdhocQueryResult as aa, AssetClient as ab, AssetFileBuilder as ac, AssetUploadBuilder as ad, isAssetEntry as ae, type AssetVisibility as af, type FileStatus as ag, type FileBackend as ah, type AssetFileBlock as ai, type AssetFileExtracted as aj, type AssetUrls as ak, type AssetEntryResponse as al, type PopulatedAssetReference as am, type PresignInput as an, type PresignResult as ao, type ConfirmInput as ap, type ConfirmResult as aq, type ResolveUrlInput as ar, type ResolveUrlResult as as, type CreateAssetOptions as at, type WaitUntilReadyOptions as au, type MultipartCreateResult as av, type MultipartPart as aw, type MultipartTarget as ax, type UploadProgress as ay, ResourceNotFoundError as az, type ChangesExpiredReason as b, createClient as c, type TypedClientConfig as d, type ClientSchema as e, type RegisteredSchema as f, type SendOptions as g, entityTagOf as h, type ConditionalWriteOptions as i, type RetryableWriteOptions as j, type ChangesHeadOptions as k, type ChangesOptions as l, ContentClient as m, SingletonClient as n, SettingsClient as o, ContentQueryBuilder as p, ContentByIdBuilder as q, type ChildrenOptions as r, type SingletonFetchOptions as s, type SettingsFetchOptions as t, SearchClient as u, SearchBuilder as v, AutocompleteBuilder as w, SimilarBuilder as x, type SearchMode as y, type SearchResultItem as z };
3602
+ export { type BatchOperationResult as $, type ActiveSandbox as A, type SearchResultItem as B, type Change as C, type SearchHitMetadata as D, type ExtendedQueryResult as E, type FeedChange as F, type SearchResponse as G, HttpClient as H, type AutocompleteSuggestion as I, type AutocompleteResponse as J, type SimilarResult as K, LIVE_KEEPALIVE_INTERVAL_MS as L, type SimilarResponse as M, type SearchFilter as N, type SearchFields as O, type Project as P, type SearchSort as Q, type Register as R, type SandboxState as S, TypedRelyIOClient as T, type SearchTypeName as U, type SearchEntry as V, BatchClient as W, BatchBuilder as X, type BatchMethod as Y, type BatchOperation as Z, type BatchOptions as _, ChangesExpiredError as a, type BatchSummary as a0, type BatchResponse as a1, AdhocQueryClient as a2, AdhocQueryBuilder as a3, type FetchBlock as a4, type AggregateBlock as a5, type AggregateMetric as a6, type SearchBlock as a7, type FilterValue as a8, type FullTextConfig as a9, type MultipartPart as aA, type MultipartTarget as aB, type UploadProgress as aC, ResourceNotFoundError as aD, ResourceConflictError as aE, ResourceExpiredError as aF, isResourceNotFound as aG, type FileErrorCode as aH, type FileUploadErrorCode as aI, FileUploadError as aJ, FileValidationError as aK, type FileValidationConstraints as aL, validateFile as aM, type AdhocQueryDefinition as aa, type AdhocQueryOptions as ab, type QueryMetadata as ac, type AdhocQueryResult as ad, AssetClient as ae, AssetFileBuilder as af, AssetUploadBuilder as ag, isAssetEntry as ah, type AssetVisibility as ai, type FileStatus as aj, type FileBackend as ak, type AssetFileBlock as al, type AssetFileExtracted as am, type FileStatusResult as an, type AssetUrls as ao, type AssetEntryResponse as ap, type PopulatedAssetReference as aq, type PresignInput as ar, type PresignResult as as, type ConfirmInput as at, type ConfirmResult as au, type ResolveUrlInput as av, type ResolveUrlResult as aw, type CreateAssetOptions as ax, type WaitUntilReadyOptions as ay, type MultipartCreateResult as az, type ChangesExpiredReason as b, createClient as c, type TypedClientConfig as d, type ClientSchema as e, type RegisteredSchema as f, type SendOptions as g, entityTagOf as h, type ConditionalWriteOptions as i, type RetryableWriteOptions as j, type ChangesHeadOptions as k, type ChangesOptions as l, type LiveChangesOptions as m, ContentClient as n, SingletonClient as o, SettingsClient as p, ContentQueryBuilder as q, ContentByIdBuilder as r, type ChildrenOptions as s, type SingletonFetchOptions as t, type SettingsFetchOptions as u, SearchClient as v, SearchBuilder as w, AutocompleteBuilder as x, SimilarBuilder as y, type SearchMode as z };