@relyio/sdk 0.19.0 → 0.20.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 (54) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/automations/index.cjs +1 -1
  3. package/dist/automations/index.d.cts +2 -1588
  4. package/dist/automations/index.d.ts +2 -1588
  5. package/dist/automations/index.js +1 -1
  6. package/dist/{chunk-ZO6QDYJG.cjs → chunk-5WGMIQBH.cjs} +2 -2
  7. package/dist/{chunk-W2A4OTCI.js → chunk-EQUZNVAR.js} +2 -2
  8. package/dist/{chunk-P23G5NXD.cjs → chunk-K66MBRI4.cjs} +68 -51
  9. package/dist/{chunk-356SF5Y2.js → chunk-L42C4G2S.js} +25 -8
  10. package/dist/{chunk-T7LGREB3.js → chunk-OUR7OUUZ.js} +3 -3
  11. package/dist/{chunk-NN45CSPZ.cjs → chunk-UO2QRYKV.cjs} +3 -3
  12. package/dist/client/index.cjs +5 -5
  13. package/dist/client/index.d.cts +4 -4
  14. package/dist/client/index.d.ts +4 -4
  15. package/dist/client/index.js +3 -3
  16. package/dist/{define-content-type-BZ6X8GvL.d.cts → define-content-type-C2HnCYYX.d.cts} +1 -1
  17. package/dist/{define-content-type-C12jh8cY.d.ts → define-content-type-CVLUusfx.d.ts} +1 -1
  18. package/dist/dev-handshake/index.cjs +8 -8
  19. package/dist/dev-handshake/index.d.cts +1 -1
  20. package/dist/dev-handshake/index.d.ts +1 -1
  21. package/dist/dev-handshake/index.js +1 -1
  22. package/dist/extensions/index.cjs +3 -3
  23. package/dist/extensions/index.d.cts +2 -4
  24. package/dist/extensions/index.d.ts +2 -4
  25. package/dist/extensions/index.js +1 -1
  26. package/dist/functions/index.cjs +1 -1
  27. package/dist/functions/index.d.cts +2 -4
  28. package/dist/functions/index.d.ts +2 -4
  29. package/dist/functions/index.js +1 -1
  30. package/dist/{index-D5jyIeQ5.d.cts → index-BLVNMYUU.d.cts} +54 -9
  31. package/dist/{index-C-MymZTe.d.ts → index-BY1xU93u.d.ts} +1 -1
  32. package/dist/{index-DN0l8RHw.d.cts → index-Cmup6HJY.d.cts} +1 -1
  33. package/dist/index-D1fiaQlK.d.ts +2284 -0
  34. package/dist/index-DImzg3ew.d.cts +2284 -0
  35. package/dist/{index-BxNnlc5D.d.ts → index-IjSyBr8f.d.ts} +54 -9
  36. package/dist/index.cjs +76 -76
  37. package/dist/index.d.cts +7 -8
  38. package/dist/index.d.ts +7 -8
  39. package/dist/index.js +4 -4
  40. package/dist/preview/index.cjs +3 -3
  41. package/dist/preview/index.js +1 -1
  42. package/dist/rich-text/index.d.cts +2 -2
  43. package/dist/rich-text/index.d.ts +2 -2
  44. package/dist/schema/index.cjs +1 -1
  45. package/dist/schema/index.d.cts +947 -4
  46. package/dist/schema/index.d.ts +947 -4
  47. package/dist/schema/index.js +1 -1
  48. package/dist/types/index.d.cts +1 -1
  49. package/dist/types/index.d.ts +1 -1
  50. package/package.json +4 -4
  51. package/dist/define-schema-BPlZl4a2.d.cts +0 -947
  52. package/dist/define-schema-CK7TtYot.d.ts +0 -947
  53. package/dist/register-BiMQKVp-.d.ts +0 -693
  54. package/dist/register-DeMsaurp.d.cts +0 -693
@@ -1,693 +0,0 @@
1
- import { c$ as paths, d0 as RetryConfig, d1 as MergedRelyIOConfig, d2 as ApiResponse, cR as components, cx as FileUpload } from './define-content-type-BZ6X8GvL.cjs';
2
- import { a as SchemaDefinition } from './define-schema-BPlZl4a2.cjs';
3
-
4
- /**
5
- * Where the SDK's transport gets its truth.
6
- *
7
- * Every route this client calls is named by its **path template as the
8
- * committed document spells it**, and the body type it expects is read out of
9
- * that document rather than written down here. `api-schema.ts` beside this file
10
- * is generated by `pnpm api:types` from `apps/services/api/openapi-spec.json`,
11
- * which is itself generated from that service's `RouteContract`s
12
- * (`INV-API-DOCUMENT-IS-DERIVED`). So the chain is: one declaration in
13
- * `routes.ts` → the serializer that produces the body → the document → these
14
- * types → the method that reads it.
15
- *
16
- * That chain is the answer to the question this phase exists to close. Before
17
- * it, six SDK methods read a key the server does not send; each had no caller
18
- * and no test, so nothing could see them. Now:
19
- *
20
- * - A route that changes **kind** — `collection` to `object`, say — changes
21
- * whether the document's 200 body carries `page` and whether `data` is an
22
- * array. `Wire<…>` follows, `readPayload` follows, and the method's declared
23
- * return type stops matching. `tsc` names the method.
24
- * - A route that changes **path** or is deleted stops being a `keyof paths`, so
25
- * the call site fails on the literal.
26
- * - A route that changes **dialect** changes `page` from `CursorPage` to
27
- * `OffsetPage`, and anything reading `nextCursor` fails.
28
- *
29
- * `/v1` lives in these templates because it lives in the document
30
- * (`INV-API-VERSION-IS-DECIDED-ONCE`). Before this phase the SDK's base URL was
31
- * `https://api.relyio.com` and its paths were `/{contentType}`, so every
32
- * versioned request went to a path the router does not serve.
33
- *
34
- * Spec: `devtools/docs/guide/engineering/api-contract-spec.md`,
35
- * `INV-API-CLIENT-IS-DERIVED`.
36
- */
37
-
38
- /** Every path the committed document declares. */
39
- type ApiPath = keyof paths;
40
- type Verb = 'get' | 'post' | 'put' | 'patch' | 'delete';
41
- /** The verbs the document declares on this path — not the seven HTTP has. */
42
- type ApiMethod<P extends ApiPath> = {
43
- [M in Verb]: M extends keyof paths[P] ? paths[P][M] extends {
44
- responses: unknown;
45
- } ? M : never : never;
46
- }[Verb];
47
- type Operation<P extends ApiPath, M extends ApiMethod<P>> = M extends keyof paths[P] ? paths[P][M] : never;
48
- type JsonBody<R> = R extends {
49
- content: {
50
- 'application/json': infer B;
51
- };
52
- } ? B : never;
53
- /**
54
- * The success body the document declares, preferring 200 where a route serves
55
- * both. A route with neither — `kind: 'empty'`, which serves 204 — resolves to
56
- * `never`, and `readPayload` cannot be called on it.
57
- */
58
- type ApiSuccessBody<P extends ApiPath, M extends ApiMethod<P>> = Operation<P, M> extends {
59
- responses: infer R;
60
- } ? 200 extends keyof R ? JsonBody<R[200]> : 201 extends keyof R ? JsonBody<R[201]> : never : never;
61
- /**
62
- * The document's success body with the payload typed as the caller's `T`.
63
- *
64
- * The array arm is tested **first** on purpose: `{ data: unknown[] }` also
65
- * satisfies `{ data: unknown }`, so the object arm would swallow every
66
- * collection and hand a list route's caller a single entity — which is the
67
- * exact defect class (`ContentClient.children` reading `.data.items` from an
68
- * object route) that this phase makes unrepresentable.
69
- */
70
- type Wire<P extends ApiPath, M extends ApiMethod<P>, T> = ApiSuccessBody<P, M> extends {
71
- data: unknown[];
72
- } ? Omit<ApiSuccessBody<P, M>, 'data'> & {
73
- data: T[];
74
- } : ApiSuccessBody<P, M> extends {
75
- data: unknown;
76
- } ? Omit<ApiSuccessBody<P, M>, 'data'> & {
77
- data: T;
78
- } : ApiSuccessBody<P, M>;
79
- /**
80
- * The path parameters the document declares for this operation, or `never`
81
- * where it declares none.
82
- *
83
- * `never` rather than `{}`: a route with no segments must **forbid** a `path`
84
- * argument, not merely tolerate an empty one, and `keyof Record<string, never>`
85
- * is `string`, so an empty-object encoding cannot be told apart from a real
86
- * one at the type level.
87
- */
88
- type PathParamsOf<P extends ApiPath, M extends ApiMethod<P>> = Operation<P, M> extends {
89
- parameters: {
90
- path?: infer X;
91
- };
92
- } ? [X] extends [undefined] ? never : NonNullable<X> : never;
93
- /**
94
- * The query parameters the document declares for this operation, or `never` where it declares
95
- * none (REL-687).
96
- *
97
- * The service declares them beside each route — a query DTO's whitelisted properties, the names a
98
- * handler reads, `?_fresh` on a read the edge keeps — and `apps/services/api`'s
99
- * `contract/query-parameters.spec.ts` holds the document to what each handler reads. So a name the
100
- * API stops reading stops compiling here, and a name it refuses — `offset` on the entry list, which
101
- * the SDK once sent on every `.offset()` and the API answered with a 400 — never compiled at all.
102
- *
103
- * `never` for the same reason {@link PathParamsOf} uses it: a route with no query must forbid one.
104
- */
105
- type QueryOf<P extends ApiPath, M extends ApiMethod<P>> = Operation<P, M> extends {
106
- parameters: {
107
- query?: infer Q;
108
- };
109
- } ? [Q] extends [undefined] ? never : NonNullable<Q> : never;
110
- /** What {@link matchRoute} recovers from a URL the client emitted. */
111
- interface RouteMatch {
112
- /** The document's path template — the value a tag translator switches on. */
113
- path: ApiPath;
114
- /** The template's `{name}` segments, decoded: the inverse of {@link fillPath}. */
115
- params: Record<string, string>;
116
- /** The query string; a key that appears more than once comes back as an array. */
117
- query: Record<string, string | string[]>;
118
- }
119
- interface MatchRouteOptions {
120
- /**
121
- * The client's `baseUrl`, when it carries a path prefix of its own
122
- * (`https://example.com/relyio`). Its path is removed before the template is
123
- * matched. Unneeded for the default `https://api.relyio.com`.
124
- */
125
- baseUrl?: string;
126
- }
127
- /**
128
- * Recover the route a URL names: the inverse of {@link fillPath}, over the same
129
- * committed document (`INV-API-CLIENT-IS-DERIVED`).
130
- *
131
- * `matchRoute(url).path` is an `ApiPath`, so anything that keys behaviour on a
132
- * request — a cache-tag translator, say — switches on the document's templates
133
- * and never on a route table of its own.
134
- *
135
- * Returns `null` for a URL no declared template matches — a presigned storage
136
- * URL, or a path outside `baseUrl` — rather than a guess.
137
- */
138
- declare function matchRoute(url: string | URL, options?: MatchRouteOptions): RouteMatch | null;
139
-
140
- /**
141
- * The part of a request a retry decision is allowed to look at.
142
- *
143
- * `method` is typed as a plain `string` rather than as `RequestConfig['method']`
144
- * on purpose. The five verbs that union names are the five the typed transport
145
- * can express today; the question "may this be sent twice?" is a fact about
146
- * HTTP, and an unrecognised verb has to reach the conservative arm rather than
147
- * be unrepresentable.
148
- */
149
- interface RetryableRequest {
150
- method: string;
151
- headers?: Record<string, string>;
152
- }
153
- /**
154
- * Whether a failed request may be sent again, and after how long.
155
- *
156
- * The two halves are separate because they fail separately. The incumbent loop
157
- * had neither: it asked `error.retryable` and nothing else, so a `POST` that met
158
- * a 500 was sent again twice — and `SERVICE_INDETERMINATE`, whose whole meaning
159
- * is "the service could not decide", is marked retryable, which means the write
160
- * may already have landed. Meanwhile the `Retry-After` the service sent was
161
- * collected by the transport and read by nobody, so a 429 whose window is
162
- * measured in minutes was retried after an exponential guess capped at ten
163
- * seconds.
164
- *
165
- * `error` is `Error`, not `SDKError`, because that is what the loop actually
166
- * holds: a `TypeError: fetch failed` is only mapped to an `SDKError` **after**
167
- * the loop gives up, so a policy typed to `SDKError` could not see the transport
168
- * failures it most needs to retry.
169
- */
170
- interface RetryPolicy {
171
- /**
172
- * Never replays a request that could apply twice: a write is retried only
173
- * when it carries `Idempotency-Key`, or the verb is idempotent.
174
- *
175
- * @param attempt - How many attempts have been made, 1 for the first.
176
- */
177
- shouldRetry(attempt: number, error: Error, request: RetryableRequest): boolean;
178
- /** Honours `Retry-After` / `RateLimitError.resetAt` over exponential backoff. */
179
- delayFor(attempt: number, error: Error): number;
180
- }
181
- /**
182
- * Whether sending this request a second time can apply it a second time.
183
- *
184
- * Two ways to be safe, and they are genuinely different questions: the verb may
185
- * be idempotent by definition, or the request may carry an `Idempotency-Key`
186
- * that makes the service answer a replay from the original outcome rather than
187
- * applying it again.
188
- */
189
- declare function isReplaySafe(request: RetryableRequest): boolean;
190
- /**
191
- * The policy the SDK ships with.
192
- *
193
- * Construction takes the same `RetryConfig` the SDK has always exported; what
194
- * it no longer takes is a `retryCondition`, because a caller-supplied predicate
195
- * over `(error, attempt)` structurally **cannot** see the request and so cannot
196
- * express the rule this class exists for.
197
- */
198
- declare class DefaultRetryPolicy implements RetryPolicy {
199
- private readonly config;
200
- constructor(config: RetryConfig);
201
- shouldRetry(attempt: number, error: Error, request: RetryableRequest): boolean;
202
- delayFor(attempt: number, error: Error): number;
203
- }
204
- /**
205
- * The retry policy a client sends with, at `maxAttempts` attempts (the first included): the SDK's
206
- * own, from `retryAttempts`, and the CLI's (REL-721).
207
- *
208
- * The backoff numbers are stated here once. The CLI ran a second policy beside this one —
209
- * `axios-retry` with its own delays and its own reading of a refusal, which retried by numeric
210
- * status — so a refusal one client gave up on, the other sent again. Now both ask this function, and
211
- * a change to when a request is replayed reaches both.
212
- */
213
- declare function retryPolicyFor(maxAttempts: number): RetryPolicy;
214
-
215
- /**
216
- * What a call site supplies beside the route it named.
217
- *
218
- * `path` is required exactly when the document's template has segments, and
219
- * forbidden when it does not — so a call that forgot to scope a request, or one
220
- * that scoped a request the route does not scope, is a compile error rather
221
- * than a URL with a literal `{id}` in it.
222
- */
223
- type SendOptions<P extends ApiPath, M extends ApiMethod<P>> = {
224
- /**
225
- * Query string values: exactly the names the document declares for this route, at the types it
226
- * declares them (`QueryOf`, REL-687). An undeclared name is a compile error, not a 400.
227
- */
228
- query?: QueryOf<P, M>;
229
- body?: unknown;
230
- /** Request headers this call adds, e.g. `If-Match` / `Idempotency-Key` (API4). */
231
- headers?: Record<string, string>;
232
- signal?: AbortSignal;
233
- timeout?: number;
234
- } & ([PathParamsOf<P, M>] extends [never] ? {
235
- path?: never;
236
- } : {
237
- path: PathParamsOf<P, M>;
238
- });
239
- /**
240
- * Core HTTP client for the RelyIO SDK.
241
- *
242
- * `send` is **the** typed entry: it names a route by the path template the
243
- * committed document declares, and returns that operation's body type with the
244
- * payload typed as `T`. `readPayload` from `@relyio/api-contract/client` is
245
- * then the one unwrap — there is no second spelling and no runtime test of
246
- * which envelope arrived (`INV-API-CLIENT-IS-DERIVED`).
247
- *
248
- * What the class makes public is what something outside it calls: `send` and `fetchPayload` are
249
- * the requests; `configure`, `withHeaders` and `setApiKey` are the owning client's (`updateConfig()`,
250
- * `with()`, `setApiKey()`). There are no verb helpers, no header or base-URL accessors and no
251
- * untyped `request` (REL-717): a route is named by its document path, or it is not called.
252
- */
253
- declare class HttpClient {
254
- /** What every request reads off the configuration, derived by {@link configure} and nowhere else. */
255
- protected connection: Connection;
256
- /**
257
- * Set on a view {@link withHeaders} made: the client every request is sent through, and the
258
- * headers laid beneath each request's own. A view keeps no connection of its own that matters —
259
- * everything it is asked to change, it changes on that client.
260
- */
261
- protected view?: {
262
- readonly client: ControlledHttpClient;
263
- readonly headers: Readonly<Record<string, string>>;
264
- /** The End user's token function this view asks in place of its client's, when it names one. */
265
- readonly getToken?: EndUserTokenSource;
266
- };
267
- constructor(config: MergedRelyIOConfig);
268
- protected announce(): void;
269
- /**
270
- * Send bytes to an address that is not a RelyIO route — an asset upload's presigned `PUT` and its
271
- * multipart parts — through the client's configured `fetch`, so a wrapper that records, proxies or
272
- * forbids network access sees every request this client makes (REL-2671). Nothing else is added: no
273
- * key, no retry, no timeout, because the address belongs to the storage service, not to RelyIO.
274
- *
275
- * Static so the instances a customer holds stay `send` and `fetchPayload` (REL-3107). The `fetch`
276
- * is read per call, from the client a view sends through, like the requests are.
277
- */
278
- static transfer(client: HttpClient, url: string, init: RequestInit): Promise<Response>;
279
- /**
280
- * Call a route the committed document declares, and get back the body that
281
- * document says it serves.
282
- */
283
- send<P extends ApiPath, M extends ApiMethod<P>, T = unknown>(path: P, method: M, options: SendOptions<P, M>): Promise<ApiResponse<Wire<P, M, T>>>;
284
- /**
285
- * Call a route and return its payload — `send` plus the one unwrap, which is
286
- * what all but a handful of call sites want.
287
- */
288
- fetchPayload<P extends ApiPath, M extends ApiMethod<P>, T = unknown>(path: P, method: M, options: SendOptions<P, M>): Promise<Wire<P, M, T> extends {
289
- data: unknown;
290
- } ? Wire<P, M, T>['data'] : never>;
291
- /**
292
- * Make an HTTP request, retrying only where a retry is safe.
293
- *
294
- * The headers are merged **once**, before the first attempt, and every attempt
295
- * sends that same object. That is what makes a minted `Idempotency-Key` stable
296
- * across the retries of one logical write: the service sees one key and
297
- * answers the replay from the original outcome instead of applying it twice.
298
- *
299
- * The loop always makes one attempt. The incumbent's `while (attempt <
300
- * maxAttempts)` made none at `retryAttempts: 0` — a value the config validator
301
- * then accepted, and now refuses — and then dereferenced an unassigned
302
- * `lastError`. `retryAttempts` is the most attempts, the first included; an
303
- * `HttpClient` constructed directly is not validated, so the first attempt
304
- * stays unconditional.
305
- *
306
- * A request that would carry no `X-API-Key` makes none: it rejects with
307
- * `MissingApiKeyError` before `fetch` is called, is not retried, and names
308
- * `apiKey`. This is where a client built without a key learns it — the
309
- * constructor accepts one so that a module-scope client can be evaluated by a
310
- * build that holds no key (REL-1120) — and so does one whose `setApiKey` was
311
- * given none.
312
- *
313
- * The End user's token is asked for once, after the key is known to be there and before the first
314
- * attempt — of `getToken`, the nearest view's function, or the configuration's — so every retry
315
- * of one call sends the token its first attempt sent. See `RelyIOConfig.getToken`.
316
- */
317
- private request;
318
- /**
319
- * One attempt.
320
- *
321
- * The caller's `signal` and the timeout both end it, through one controller.
322
- * The incumbent handed `fetch` the caller's signal **instead of** its own, so a
323
- * request that passed a signal had no timeout at all — and a caller abort then
324
- * surfaced as `Request timed out`. `timedOut` is what tells the two apart: a
325
- * timeout is a `TimeoutError`, a caller abort is the platform's `AbortError`,
326
- * rethrown as it came.
327
- */
328
- private makeRequest;
329
- /**
330
- * The headers without those a browser controls itself, when this is a browser; unchanged when it
331
- * is not.
332
- *
333
- * A name is matched without regard to case (RFC 9110 §5.1), because a browser refuses `Origin`
334
- * whatever case a page spells it in. This matched only the all-lowercase and all-uppercase
335
- * spellings, so `Origin` and `User-Agent` — how people write them — reached `fetch` (REL-1409).
336
- */
337
- private filterHeadersForBrowser;
338
- /**
339
- * Prepare request body based on content type and environment
340
- */
341
- private prepareRequestBody;
342
- private parseResponse;
343
- private resolveUrl;
344
- private mergeRequestConfig;
345
- private buildQueryString;
346
- private headersToObject;
347
- private log;
348
- }
349
- /**
350
- * The client the SDK's own factory holds: {@link HttpClient} plus the three things only the owning
351
- * client does to it — `configure` (`updateConfig()`), `withHeaders` (`with()`) and `setApiKey`
352
- * (`setApiKey()`). It is not exported from the package, so a customer holding the client from
353
- * `getHttpClient()` sees `send` and `fetchPayload` and nothing else (REL-3107).
354
- */
355
- declare class ControlledHttpClient extends HttpClient {
356
- /**
357
- * A view of this client that sends every request through it with `headers` added — beneath the
358
- * request's own, over this client's — and changes nothing else: its key, base URL, timeout,
359
- * retries and `fetch` are this client's as they are when each request is sent, so a later
360
- * `configure()` or `setApiKey()` on this client reaches the view, and one on the view reaches
361
- * this client. `client.with({ dataset })` is one (REL-2417).
362
- *
363
- * `options.getToken` is the End user's token function the view asks in place of this client's,
364
- * and of any view it is made from: `client.with({ getToken })` (REL-3882).
365
- */
366
- withHeaders(headers: Readonly<Record<string, string>>, options?: {
367
- readonly getToken?: EndUserTokenSource;
368
- }): ControlledHttpClient;
369
- /**
370
- * Run on `config` from now on: every later request — whoever holds this client — is sent to its
371
- * `baseUrl`, with its headers, key and dataset, its timeout and retries, through its `fetch`, and
372
- * logged by its `debug` options.
373
- *
374
- * The client's own `updateConfig()` calls this rather than building a second client, so a
375
- * `content()` or other sub-client taken before the update sends through the update too. Anything
376
- * set on this client since it was last configured — `setApiKey()` — is replaced by what `config`
377
- * says.
378
- */
379
- configure(config: MergedRelyIOConfig): void;
380
- /**
381
- * Replace the key every later request sends as `X-API-Key`, and the `apiKey` the configuration
382
- * reports.
383
- *
384
- * The key is read the way construction reads it (`presentCredential`): an absent, empty or blank key is
385
- * no key, so the header is dropped and the next request is refused with `MissingApiKeyError`
386
- * before anything is sent. A key header of any other spelling — one given in `headers` — goes
387
- * too, from the headers sent and from the headers the configuration reports, so the old key is
388
- * never sent beside the new one.
389
- *
390
- * The configuration is the one the owning `TypedRelyIOClient` holds (it hands its own to the
391
- * constructor), so its `getConfig().apiKey` — what a surface reads to decide a key's kind — is the
392
- * key sent from here on.
393
- *
394
- * This replaced `setAuthToken`, which added `Authorization: Bearer` beside an `X-API-Key` it
395
- * never touched: the API reads `X-API-Key` first, so the old key was the one used (REL-1385).
396
- */
397
- setApiKey(apiKey: string): void;
398
- }
399
- /** What `getToken` is: asked per call, answering the signed-in End user's token or `null`. */
400
- type EndUserTokenSource = NonNullable<MergedRelyIOConfig['getToken']>;
401
- /** Everything a request reads off the configuration, replaced whole whenever it changes. */
402
- interface Connection {
403
- /**
404
- * The configuration itself, for what is read per request — `fetch`, the `browser` options,
405
- * `debug` — and the object `setApiKey` writes the key into, which the owning client reports.
406
- */
407
- readonly config: MergedRelyIOConfig;
408
- readonly baseUrl: string;
409
- readonly defaultHeaders: Readonly<Record<string, string>>;
410
- readonly timeout: number;
411
- readonly retryPolicy: RetryPolicy;
412
- }
413
-
414
- /**
415
- * One Record type's Records over the Content API (spec 1, REL-3771): `relyio.records('order')`.
416
- *
417
- * A Record is an app's data — an order, a stock level, a cart — written by your server with a
418
- * secret key and live the moment it lands: no draft, no publication, no locale, no version. A
419
- * publishable key lists and gets the Records a Record type's read Policy grants it — anonymously, or
420
- * as the End user whose token it carries (spec 4, REL-3883) — and creates, updates and deletes them
421
- * only as that End user, as the type's write Policy allows (REL-3884): RelyIO sets the owner from
422
- * the token. With no token it writes nothing (`PUBLISHABLE_KEY_REFUSED`).
423
- *
424
- * Every body is read from the committed document (`INV-API-CLIENT-IS-DERIVED`): the paths are the
425
- * document's, and `RecordMetadata` is its schema by name.
426
- */
427
-
428
- /** What the API reports about a Record beside its fields. */
429
- type RecordMetadata = components['schemas']['RecordMetadata'];
430
- /** A Record as a read answers it: its fields at the top level, and `_metadata`. */
431
- type BaseRecord = Record<string, unknown> & {
432
- _metadata: RecordMetadata;
433
- };
434
- /** What a Record read and write take beside their own options. */
435
- interface RecordCallOptions {
436
- /** The dataset, by id or name, over the client's. */
437
- dataset?: string;
438
- signal?: AbortSignal;
439
- }
440
- /**
441
- * What a Record read may expand (REL-3772): include paths, in the grammar `content().get` takes —
442
- * `lines.product`, `convertedTo.lines.product(title)`. A reference to an entry expands into the
443
- * entry as this key reads it — published with a secret key, its draft with a preview key — and one
444
- * to a Record into the Record. A reference to an entry the key cannot see, or that is gone, reads
445
- * as `null` — unless it is a pinned reference (`pin: 'version'`), which reads the entry as it was
446
- * at the version the Record pinned, whatever it has done since, its `_metadata.pin` naming that
447
- * version and the one the key reads now (REL-3776).
448
- */
449
- interface RecordReadOptions extends RecordCallOptions {
450
- include?: readonly string[];
451
- /**
452
- * The locale each included entry is composed in, with its schema's fallback; the schema's
453
- * default when absent. A Record has no locale of its own (REL-3776).
454
- */
455
- locale?: string;
456
- }
457
- /** What an update takes: the revision the change was made on. */
458
- interface RecordUpdateOptions extends RecordCallOptions {
459
- /**
460
- * `_metadata.revision` of the read the change was made on. A Record written since is refused
461
- * with `ResourceConflictError`, its `blockage` (`revision-stale`) naming the fields that changed,
462
- * and nothing is written.
463
- */
464
- revision: number;
465
- }
466
- /** A list's options: one page of the Records `where` keeps, in one order. */
467
- interface RecordListOptions<TFields> extends RecordReadOptions {
468
- /** Field conditions, in the grammar `content().list({ where })` takes. */
469
- where?: {
470
- [K in keyof TFields]?: unknown;
471
- } & Record<string, unknown>;
472
- /** One key: `createdAt`, `updatedAt`, `id` or a field holding one value. Default `createdAt:desc`. */
473
- sort?: `${'createdAt' | 'updatedAt' | 'id' | (keyof TFields & string)}:${'asc' | 'desc'}`;
474
- limit?: number;
475
- cursor?: string;
476
- /** Answer `meta.count`: how many Records `where` keeps across every page. */
477
- count?: boolean;
478
- /** Count the values of each of these fields among the Records `where` keeps, under `meta.facets`. */
479
- facets?: ReadonlyArray<keyof TFields & string>;
480
- }
481
- /** What an upload of a Record's File takes beside its bytes (REL-3824). */
482
- interface RecordFileUploadOptions extends RecordCallOptions {
483
- /** The File's name, as a read will answer it. */
484
- name: string;
485
- /** Its media type: one the field's `accept` admits. */
486
- type: string;
487
- }
488
- /** The bytes of a File: what `fetch` sends as a body, of a length known before it is sent. */
489
- type RecordFileBytes = Blob | ArrayBuffer | Uint8Array;
490
- /** One facet's buckets: each value and how many Records hold it, most frequent first. */
491
- interface RecordFacetBucket {
492
- readonly value: unknown;
493
- readonly count: number;
494
- }
495
- /** One page of a Record list, as the API answers it. */
496
- interface RecordList<T> {
497
- data: T[];
498
- page: {
499
- nextCursor: string | null;
500
- hasMore: boolean;
501
- };
502
- meta: {
503
- count?: number;
504
- facets?: Record<string, RecordFacetBucket[]>;
505
- };
506
- }
507
- /**
508
- * One Record type's Records.
509
- *
510
- * @example
511
- * ```typescript
512
- * const orders = relyio.records('order')
513
- * const order = await orders.create({ shopperEmail: 'ada@example.com', status: 'paid', total: 19 })
514
- * const { data: paid, meta } = await orders.list({
515
- * where: { status: 'paid' },
516
- * sort: 'createdAt:asc',
517
- * count: true,
518
- * })
519
- * ```
520
- */
521
- declare class RecordsClient<TRecord extends BaseRecord = BaseRecord, TInput = Record<string, unknown>,
522
- /** What an update takes: the create's values without the type's Counters (REL-3765). */
523
- TUpdate = TInput> {
524
- private readonly httpClient;
525
- readonly recordType: string;
526
- constructor(httpClient: HttpClient, recordType: string);
527
- /**
528
- * Store a Record, live the moment it lands. Values that break the Record type's fields are
529
- * refused with `ValidationError` naming each field, and nothing is stored. Values a unique set of
530
- * the type claims, held by another Record, are refused with `ResourceConflictError` — its
531
- * `blockage` is `{ kind: 'value-taken', facts: { fields, recordId } }` (REL-3782) — with no
532
- * `recordId` for an End user's write, whose read Policy may hide the holder (REL-3863).
533
- */
534
- create(fields: TInput, options?: RecordCallOptions): Promise<TRecord>;
535
- /** One page of the Records `where` keeps, newest first unless `sort` names one key. */
536
- list(options?: RecordListOptions<Omit<TRecord, '_metadata'>>): Promise<RecordList<TRecord>>;
537
- /**
538
- * Upload a File for one of this Record type's file fields (REL-3824), and answer what a create or
539
- * update sets the field to. The bytes go straight to object storage at the address the upload
540
- * names, never through RelyIO; a File outside the field's `accept` or over its `maxSize` is
541
- * refused with `ValidationError` naming the field before any byte is sent. An upload no write
542
- * names within a day is deleted with its bytes. Server-side only, as every Record call is.
543
- *
544
- * @example
545
- * ```typescript
546
- * const invoice = await relyio.records('order').upload('invoice', pdfBytes, {
547
- * name: 'invoice-1001.pdf',
548
- * type: 'application/pdf',
549
- * })
550
- * await relyio.records('order').update(id, { invoice }, { revision })
551
- * ```
552
- */
553
- upload(field: string, bytes: RecordFileBytes, options: RecordFileUploadOptions): Promise<FileUpload>;
554
- /**
555
- * One Record by its id, or `null` when none is stored. A Record type nobody deployed throws
556
- * `ResourceNotFoundError` naming it, so it never reads as a missing Record.
557
- */
558
- get(id: string, options?: RecordReadOptions): Promise<TRecord | null>;
559
- /**
560
- * Change the fields named, against the revision the change was made on, and answer the Record at
561
- * its next revision. A field given `null` is removed; one not named keeps its value. A Record
562
- * written since `revision` is refused with `ResourceConflictError` — its `blockage` is
563
- * `{ kind: 'revision-stale', facts: { changedFields } }` — and nothing is written. Values that
564
- * break the Record type are refused with `ValidationError` naming each field, and values another
565
- * Record holds under a unique set with `ResourceConflictError`, its blockage `value-taken`.
566
- *
567
- * @example
568
- * ```typescript
569
- * const order = await relyio.records('order').get(id)
570
- * await relyio.records('order').update(id, { status: 'shipped' }, {
571
- * revision: order._metadata.revision,
572
- * })
573
- * ```
574
- */
575
- update(id: string, fields: {
576
- [K in keyof TUpdate]?: TUpdate[K] | null;
577
- }, options: RecordUpdateOptions): Promise<TRecord>;
578
- /**
579
- * Remove a Record. Another Record holding it through a reference declared to block its delete —
580
- * the default — is refused with `ResourceConflictError`, its `blockage`
581
- * (`{ kind: 'referenced', facts: { referrers } }`) naming each; one declared `nullify` is cleared.
582
- */
583
- delete(id: string, options?: RecordCallOptions): Promise<void>;
584
- }
585
-
586
- /**
587
- * The atomic Record batch (spec 1, REL-3774): `relyio.records.batch([...])` — an ordered list of
588
- * Record operations across Record types, run in one transaction, all or none.
589
- *
590
- * Each operation is `create`, `update`, `delete`, `increment` or `decrement`, and names its Record by
591
- * `id`, by `where` (the one Record of its type whose top-level fields have those values), or both —
592
- * `where` then a precondition. A refused operation rolls the whole batch back, and the refusal names
593
- * it: {@link refusedOperationOf} reads its index off the error. A counter moved past its bound is a
594
- * `ResourceConflictError` whose `blockage` is `counter-out-of-bounds`, naming the field, the bound and
595
- * the value it holds.
596
- *
597
- * Every batch is sent with an `Idempotency-Key` — yours, or one minted for the call — so a batch
598
- * retried after a lost answer is answered as done, never written twice.
599
- */
600
-
601
- /** A condition's value: what one top-level field holds, compared for equality. */
602
- type RecordConditionValue = string | number | boolean | null;
603
- /**
604
- * Which stored Record an operation lands on: by `id`, by `where`, or both. Every `where` is read
605
- * before the batch's first operation runs, so it names a Record stored before the batch — never one
606
- * an earlier operation of the same batch creates.
607
- */
608
- type RecordBatchTarget = {
609
- id: string;
610
- where?: Record<string, RecordConditionValue>;
611
- } | {
612
- id?: undefined;
613
- where: Record<string, RecordConditionValue>;
614
- };
615
- /** One operation of a batch. `type` is a Record type the schema declares. */
616
- type RecordBatchOperation<TType extends string = string> = {
617
- op: 'create';
618
- type: TType;
619
- fields: Record<string, unknown>;
620
- } | ({
621
- op: 'update';
622
- type: TType;
623
- /** The fields to change; one given `null` is removed. A counter is never set. */
624
- fields: Record<string, unknown>;
625
- /** The revision the change was made on; absent, the update writes over the one stored. */
626
- revision?: number;
627
- } & RecordBatchTarget) | ({
628
- op: 'delete';
629
- type: TType;
630
- } & RecordBatchTarget) | ({
631
- op: 'increment' | 'decrement';
632
- type: TType;
633
- /** The counter. */
634
- field: string;
635
- /** A whole number above zero. */
636
- by: number;
637
- } & RecordBatchTarget);
638
- /** What a batch takes beside its operations. */
639
- interface RecordBatchOptions extends RecordCallOptions {
640
- /**
641
- * The key naming this batch. Sent again — by you, or by a retry — the batch is answered as the
642
- * first was and written once; with other operations it is refused. Minted for you when absent.
643
- */
644
- idempotencyKey?: string;
645
- }
646
- /** What a committed batch answers: each operation, in order, and whether this is a replay. */
647
- type RecordBatchResult = components['schemas']['RecordBatchResult'];
648
- /** What one operation of a committed batch did. */
649
- type RecordBatchOperationResult = components['schemas']['RecordBatchOperationResult'];
650
- /**
651
- * The index, from 0, of the batch operation a refusal names: a `ResourceConflictError`'s
652
- * `blockage.facts.operation`, or the first violation under `operations[<index>]` of a
653
- * `ValidationError`. `undefined` for an error that names none — one about the whole batch, such as
654
- * an allowance, or no batch refusal at all.
655
- */
656
- declare function refusedOperationOf(error: unknown): number | undefined;
657
-
658
- /**
659
- * Any schema the client can be typed by. `any` is deliberate: the client accepts whatever content
660
- * types, singletons, queries and settings groups a customer declares.
661
- *
662
- * This is the constraint `TypedRelyIOClient`'s `TSchema` carries, so `RegisteredSchema` is inferred
663
- * against the same one — `createClient` returns `TypedRelyIOClient<RegisteredSchema>`, and a schema
664
- * inferred against any wider alias would not be provably inside the client's bound.
665
- */
666
- type AnySchemaDefinition = SchemaDefinition<any, any, any, any, any>;
667
- /**
668
- * The seam `relyio generate-types` fills (`INV-SS-TYPES-INFERRED`).
669
- *
670
- * Empty here on purpose. The generated `schema.ts` augments it —
671
- *
672
- * ```ts
673
- * declare module '@relyio/sdk' {
674
- * interface Register {
675
- * schema: typeof schema
676
- * }
677
- * }
678
- * ```
679
- *
680
- * — and from then on `createClient({ apiKey })`, with no generic and no `schema:`, is typed by that
681
- * schema. The pattern is TanStack Router's. It is type-level only: nothing at runtime reads it.
682
- */
683
- interface Register {
684
- }
685
- /**
686
- * The schema the project registered through `Register`, or `undefined` when nothing did — which is
687
- * the untyped client, exactly as before the generator ran.
688
- */
689
- type RegisteredSchema = Register extends {
690
- schema: infer S extends AnySchemaDefinition;
691
- } ? S : undefined;
692
-
693
- export { type AnySchemaDefinition as A, type BaseRecord as B, type RecordBatchOptions as C, DefaultRetryPolicy as D, HttpClient as H, type MatchRouteOptions as M, type QueryOf as Q, type RegisteredSchema as R, type SendOptions as S, type Wire as W, type RecordBatchTarget as a, type RecordBatchResult as b, type Register as c, type RecordConditionValue as d, type ApiPath as e, type ApiMethod as f, type ApiSuccessBody as g, type RouteMatch as h, isReplaySafe as i, type RetryPolicy as j, type RetryableRequest as k, RecordsClient as l, matchRoute as m, type RecordCallOptions as n, type RecordFacetBucket as o, type RecordFileBytes as p, type RecordFileUploadOptions as q, retryPolicyFor as r, type RecordList as s, type RecordListOptions as t, type RecordMetadata as u, type RecordReadOptions as v, type RecordUpdateOptions as w, refusedOperationOf as x, type RecordBatchOperation as y, type RecordBatchOperationResult as z };