@elmohq/sdk 0.0.0-stage → 0.1.1

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 (129) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +326 -2
  3. package/dist/calls/index.d.mts +288 -0
  4. package/dist/calls/index.d.mts.map +1 -0
  5. package/dist/calls/index.mjs +390 -0
  6. package/dist/calls/index.mjs.map +1 -0
  7. package/dist/index.d.mts +2 -0
  8. package/dist/index.mjs +1031 -0
  9. package/dist/index.mjs.map +1 -0
  10. package/dist/request-options-B9S9d24M.d.mts +1549 -0
  11. package/dist/request-options-B9S9d24M.d.mts.map +1 -0
  12. package/dist/tools-7Hs5J2xb.d.mts +1945 -0
  13. package/dist/tools-7Hs5J2xb.d.mts.map +1 -0
  14. package/dist/tools-B1lVtYAr.mjs +2459 -0
  15. package/dist/tools-B1lVtYAr.mjs.map +1 -0
  16. package/dist/types/index.d.mts +2 -0
  17. package/dist/types/index.mjs +1 -0
  18. package/package.json +68 -4
  19. package/src/calls/brands-analytics-get.ts +33 -0
  20. package/src/calls/brands-citations-domains-list.ts +36 -0
  21. package/src/calls/brands-citations-urls-list.ts +32 -0
  22. package/src/calls/brands-create.ts +19 -0
  23. package/src/calls/brands-get.ts +19 -0
  24. package/src/calls/brands-list.ts +18 -0
  25. package/src/calls/brands-opportunities-get.ts +42 -0
  26. package/src/calls/brands-prompt-performance-list.ts +39 -0
  27. package/src/calls/brands-query-fanout-get.ts +30 -0
  28. package/src/calls/brands-tags-list.ts +28 -0
  29. package/src/calls/brands-update.ts +20 -0
  30. package/src/calls/competitors-create.ts +23 -0
  31. package/src/calls/competitors-delete.ts +19 -0
  32. package/src/calls/competitors-get.ts +19 -0
  33. package/src/calls/competitors-list.ts +23 -0
  34. package/src/calls/competitors-update.ts +24 -0
  35. package/src/calls/index.ts +33 -0
  36. package/src/calls/me-get.ts +18 -0
  37. package/src/calls/models-list.ts +20 -0
  38. package/src/calls/organizations-billing-get.ts +37 -0
  39. package/src/calls/organizations-get.ts +24 -0
  40. package/src/calls/organizations-list.ts +27 -0
  41. package/src/calls/prompts-create.ts +27 -0
  42. package/src/calls/prompts-delete.ts +28 -0
  43. package/src/calls/prompts-get.ts +23 -0
  44. package/src/calls/prompts-list.ts +28 -0
  45. package/src/calls/prompts-runs-get.ts +27 -0
  46. package/src/calls/prompts-runs-list.ts +30 -0
  47. package/src/calls/prompts-snapshot-get.ts +28 -0
  48. package/src/calls/prompts-update.ts +29 -0
  49. package/src/calls/reports-create.ts +31 -0
  50. package/src/calls/reports-get.ts +27 -0
  51. package/src/calls/reports-list.ts +28 -0
  52. package/src/calls/tools-analyze.ts +26 -0
  53. package/src/client.ts +649 -0
  54. package/src/index.ts +21 -0
  55. package/src/internal/binding/rest/binding.ts +127 -0
  56. package/src/internal/binding/rest/errors.ts +107 -0
  57. package/src/internal/binding/rest/path.ts +9 -0
  58. package/src/internal/binding/rest/url.ts +97 -0
  59. package/src/internal/codec/json.ts +66 -0
  60. package/src/internal/codec/registry.ts +55 -0
  61. package/src/internal/core/backoff.ts +170 -0
  62. package/src/internal/core/body.ts +54 -0
  63. package/src/internal/core/browser.ts +11 -0
  64. package/src/internal/core/call-promise.ts +145 -0
  65. package/src/internal/core/callable.ts +11 -0
  66. package/src/internal/core/client.ts +89 -0
  67. package/src/internal/core/config.ts +84 -0
  68. package/src/internal/core/credentials.ts +40 -0
  69. package/src/internal/core/dispatch.ts +225 -0
  70. package/src/internal/core/env.ts +68 -0
  71. package/src/internal/core/errors.ts +431 -0
  72. package/src/internal/core/features.ts +60 -0
  73. package/src/internal/core/lazy-promise.ts +39 -0
  74. package/src/internal/core/metadata.ts +79 -0
  75. package/src/internal/core/page.ts +402 -0
  76. package/src/internal/core/params.ts +98 -0
  77. package/src/internal/core/protocol.ts +17 -0
  78. package/src/internal/core/read-reply.ts +7 -0
  79. package/src/internal/core/text.ts +7 -0
  80. package/src/internal/core/types.ts +554 -0
  81. package/src/internal/feature/auth.ts +201 -0
  82. package/src/internal/feature/interceptors.ts +36 -0
  83. package/src/internal/feature/logger.ts +222 -0
  84. package/src/internal/feature/retry.ts +168 -0
  85. package/src/internal/feature/rules.ts +54 -0
  86. package/src/internal/feature/timeout.ts +146 -0
  87. package/src/internal/feature/validate.ts +82 -0
  88. package/src/internal/transport/fetch.ts +82 -0
  89. package/src/resources/analytics.ts +364 -0
  90. package/src/resources/brands.ts +288 -0
  91. package/src/resources/competitors.ts +213 -0
  92. package/src/resources/identity.ts +49 -0
  93. package/src/resources/models.ts +32 -0
  94. package/src/resources/opportunities.ts +81 -0
  95. package/src/resources/organizations.ts +182 -0
  96. package/src/resources/prompts.ts +293 -0
  97. package/src/resources/reports.ts +212 -0
  98. package/src/resources/runs.ts +124 -0
  99. package/src/resources/shared/auth.ts +13 -0
  100. package/src/resources/shared/request-options.ts +26 -0
  101. package/src/resources/shared/resource.ts +23 -0
  102. package/src/resources/shared/rule.ts +25 -0
  103. package/src/resources/snapshots.ts +54 -0
  104. package/src/resources/tags.ts +46 -0
  105. package/src/resources/tools.ts +69 -0
  106. package/src/types/analytics.ts +497 -0
  107. package/src/types/brands.ts +228 -0
  108. package/src/types/competitors.ts +196 -0
  109. package/src/types/identity.ts +55 -0
  110. package/src/types/index.ts +163 -0
  111. package/src/types/models.ts +40 -0
  112. package/src/types/opportunities.ts +84 -0
  113. package/src/types/organizations.ts +157 -0
  114. package/src/types/prompts.ts +231 -0
  115. package/src/types/reports.ts +266 -0
  116. package/src/types/runs.ts +131 -0
  117. package/src/types/shared/brand-id-path.ts +2 -0
  118. package/src/types/shared/conflict-error.ts +7 -0
  119. package/src/types/shared/error.ts +29 -0
  120. package/src/types/shared/limit.ts +8 -0
  121. package/src/types/shared/mention-entry.ts +21 -0
  122. package/src/types/shared/model-filter.ts +15 -0
  123. package/src/types/shared/not-found-error.ts +4 -0
  124. package/src/types/shared/page.ts +7 -0
  125. package/src/types/shared/pagination.ts +7 -0
  126. package/src/types/shared/validation-error.ts +4 -0
  127. package/src/types/snapshots.ts +88 -0
  128. package/src/types/tags.ts +47 -0
  129. package/src/types/tools.ts +78 -0
@@ -0,0 +1,554 @@
1
+ import type { BackoffOptions, RetryAfterHeader } from './backoff';
2
+ import { APIError, ElmoError } from './errors';
3
+
4
+ /** A request body in a form `fetch` sends as it is. */
5
+ export type BodyInput = NonNullable<RequestInit['body']>;
6
+
7
+ /** An encoded request body, or `null` for a request that sends none. */
8
+ export type BodyPayload = BodyInput | null;
9
+
10
+ /**
11
+ * One reply, as far as it has been read. Until its body is read, only `ok`,
12
+ * `response` and `status` are set.
13
+ */
14
+ export interface Result<TData = unknown, TError = unknown> {
15
+ /** The decoded body of a 2xx reply. */
16
+ data?: TData;
17
+ /** The decoded body of a reply that failed. */
18
+ error?: TError;
19
+ /** `true` for a 2xx status. */
20
+ ok?: boolean;
21
+ /** The reply itself, where one arrived. */
22
+ response?: Response;
23
+ status?: number;
24
+ }
25
+
26
+ export interface CallLog {
27
+ ended(error?: unknown): void;
28
+ failed(error: unknown): void;
29
+ replied(response: Response | undefined): void;
30
+ retrying(wait: number, retry: number, retries: number, after?: Result): void;
31
+ sending(): void;
32
+ }
33
+
34
+ /** One way the API takes a credential, as the API description declares it. */
35
+ export interface AuthScheme {
36
+ /**
37
+ * Where the credential is sent.
38
+ *
39
+ * @default 'header'
40
+ */
41
+ readonly in?: 'cookie' | 'header' | 'query';
42
+ /** Which credential this is. Its option, where it has one, has the same name. */
43
+ readonly key?: string;
44
+ /** The header, query parameter or cookie the credential is sent in. */
45
+ readonly name?: string;
46
+ /** How an `http` credential is written in the `Authorization` header. */
47
+ readonly scheme?: 'basic' | 'bearer';
48
+ /**
49
+ * `'apiKey'` sends the credential as it is, where `in` and `name` say.
50
+ * `'http'` sends it in the `Authorization` header, written as `scheme` says.
51
+ */
52
+ readonly type: 'apiKey' | 'http';
53
+ }
54
+
55
+ export type AuthRequirement = AuthScheme | ReadonlyArray<AuthScheme>;
56
+
57
+ /** A time limit in milliseconds, or `false` for none. */
58
+ export type CallTimeout = number | false;
59
+
60
+ export interface InputRule {
61
+ readonly above?: number;
62
+ readonly below?: number;
63
+ readonly max?: number;
64
+ readonly min?: number;
65
+ readonly name?: string;
66
+ readonly of?: 'characters' | 'entries' | 'items';
67
+ }
68
+
69
+ export type Interaction = 'unary';
70
+
71
+ export type PaginationStyle = 'cursor' | 'link' | 'offset' | 'page';
72
+
73
+ export interface PaginationDescriptor {
74
+ readonly cursor?: string;
75
+ readonly in?: 'body' | 'query';
76
+ readonly items?: string;
77
+ readonly limitParam?: string;
78
+ readonly link?: string;
79
+ readonly more?: string;
80
+ readonly pages?: string;
81
+ readonly param?: string;
82
+ readonly size?: string;
83
+ readonly start?: number;
84
+ readonly style: PaginationStyle;
85
+ readonly total?: string;
86
+ }
87
+
88
+ /** How a failed call is sent again. Anything left out keeps the client's rule. */
89
+ export interface RetryRules extends BackoffOptions {
90
+ /**
91
+ * How long a call may keep trying, in milliseconds, counted from the first
92
+ * attempt with the waits included. A retry that would start past it is not
93
+ * sent, and the last reply or error stands. An attempt that is running is
94
+ * not cut short: `timeout` limits each one.
95
+ *
96
+ * @default no limit
97
+ */
98
+ budget?: number;
99
+ /**
100
+ * How many times a failed call is sent again, after the first attempt.
101
+ *
102
+ * @default 2
103
+ */
104
+ maxRetries?: number;
105
+ /**
106
+ * The longest wait the API may ask for, in milliseconds. Past it, the call
107
+ * gives up and returns the reply as it is.
108
+ *
109
+ * @default 60_000
110
+ */
111
+ maxRetryAfter?: number;
112
+ /**
113
+ * Methods that may be sent again. A request that never reached the API,
114
+ * a call carrying its API's idempotency key, and 408, 425 and 429 are sent
115
+ * again whatever this says.
116
+ *
117
+ * @default idempotent methods
118
+ */
119
+ methods?: ReadonlyArray<string>;
120
+ /**
121
+ * Headers the API may name its own wait in, read before the backoff
122
+ * applies. `false` reads none.
123
+ *
124
+ * @default `retry-after-ms`, `retry-after`, `x-ratelimit-reset-after`,
125
+ * `x-ratelimit-reset` and `x-rate-limit-reset`, in that order
126
+ */
127
+ retryAfter?: ReadonlyArray<RetryAfterHeader> | boolean;
128
+ /**
129
+ * Send the request again when an attempt runs past its deadline.
130
+ *
131
+ * @default false
132
+ */
133
+ retryOnTimeout?: boolean;
134
+ /**
135
+ * Statuses worth another attempt. The API overrules them with
136
+ * `x-should-retry`: a reply answering `false` is never retried, and a
137
+ * failure answering `true` is, whatever its status and method.
138
+ */
139
+ statuses?: ReadonlyArray<number>;
140
+ }
141
+
142
+ export interface ParameterSerialization {
143
+ readonly allowReserved?: boolean;
144
+ readonly array?: { readonly explode?: boolean; readonly style?: string };
145
+ readonly mediaType?: string;
146
+ readonly object?: { readonly explode?: boolean; readonly style?: string };
147
+ }
148
+
149
+ export interface SerializationDescriptor {
150
+ readonly query?: Readonly<Record<string, ParameterSerialization>>;
151
+ }
152
+
153
+ export interface CallableDescriptor {
154
+ readonly accept?: string;
155
+ readonly address: string;
156
+ readonly auth?: ReadonlyArray<AuthRequirement>;
157
+ readonly authOptional?: boolean;
158
+ readonly baseURL?: string;
159
+ readonly deprecated?: boolean;
160
+ readonly idempotency?: string;
161
+ readonly interaction?: Interaction;
162
+ readonly mediaType?: string;
163
+ readonly method?: string;
164
+ readonly pagination?: PaginationDescriptor;
165
+ readonly retry?: RetryRules | false;
166
+ readonly returns?: 'json' | 'response';
167
+ readonly rules?: ReadonlyArray<InputRule>;
168
+ readonly serialization?: SerializationDescriptor;
169
+ readonly timeout?: CallTimeout;
170
+ readonly validators?: unknown;
171
+ }
172
+
173
+ export type MetadataValue = string | Array<string> | undefined;
174
+
175
+ export type Metadata = Record<string, MetadataValue>;
176
+
177
+ export interface Credential {
178
+ in: 'cookie' | 'header' | 'query';
179
+ name: string;
180
+ value: string;
181
+ }
182
+
183
+ export interface PlacedCredential {
184
+ readonly credential: Credential;
185
+ readonly scheme: AuthScheme;
186
+ }
187
+
188
+ export type BodyOptions = {
189
+ /** The request body, before it is encoded. */
190
+ body?: unknown;
191
+ };
192
+
193
+ export type SignalOptions = {
194
+ /** Cancels this call when it fires, retries included. */
195
+ signal?: AbortSignal;
196
+ };
197
+
198
+ export type ExchangeOptions = BodyOptions & SignalOptions;
199
+
200
+ /** A credential as a string, before it is written into the request. `undefined` sends none. */
201
+ export type AuthToken = string | undefined;
202
+
203
+ /**
204
+ * Returns the credential to send for `scheme`, given the value its option
205
+ * holds. `undefined` sends none for that scheme.
206
+ */
207
+ export type AuthResolver = (scheme: AuthScheme, value: AuthToken) => Promise<AuthToken> | AuthToken;
208
+
209
+ /** What the `auth` option takes: an {@link AuthResolver}, or `null` to send none. */
210
+ export type AuthValue = AuthResolver | null;
211
+
212
+ export type BodySerializerOptions = {
213
+ /**
214
+ * Encodes the request body, in place of the default for its content type.
215
+ * `null` sends the body as given.
216
+ */
217
+ bodySerializer?: ((body: unknown) => BodyPayload) | null;
218
+ };
219
+
220
+ export type BaseURLOptions<TBaseURL = string> = {
221
+ /** The base URL for this call, in place of the client's. */
222
+ baseURL?: TBaseURL;
223
+ };
224
+
225
+ export type CredentialOptions<TAuth = AuthValue> = {
226
+ /**
227
+ * Decides each credential a call sends, given the scheme and the value its
228
+ * option holds. What it returns is sent, so return the value to keep it.
229
+ * `null` sends no credential.
230
+ */
231
+ auth?: TAuth;
232
+ };
233
+
234
+ export type EnvironmentOptions<TEnvironment = string> = {
235
+ /** Which environment to send to. `baseURL` wins over this. */
236
+ environment?: TEnvironment;
237
+ };
238
+
239
+ export type ConnectionOptions<
240
+ TBaseURL = string,
241
+ TAuth = AuthValue,
242
+ TEnvironment = string,
243
+ > = BaseURLOptions<TBaseURL> &
244
+ CredentialOptions<TAuth> &
245
+ ([TEnvironment] extends [never] ? unknown : EnvironmentOptions<TEnvironment>);
246
+
247
+ /**
248
+ * How a failure reaches the caller.
249
+ *
250
+ * - `'throw'` resolves to the payload and throws the failure.
251
+ * - `'return'` resolves to the result envelope and throws no failure of the
252
+ * call. What one of your own functions throws is still thrown.
253
+ */
254
+ export type ErrorMode = 'return' | 'throw';
255
+
256
+ export type ErrorOptions = {
257
+ /**
258
+ * Whether a failure is thrown or handed back beside the data. Set on a
259
+ * client's defaults, not per call.
260
+ *
261
+ * @default 'throw'
262
+ */
263
+ errors?: ErrorMode;
264
+ };
265
+
266
+ /** Headers as a `Headers`, as pairs of name and value, or as an object. */
267
+ export type MetadataInput = Headers | Iterable<readonly [string, string]> | Record<string, unknown>;
268
+
269
+ /** What a call sends beside its body. Each member is merged per name. */
270
+ export type MetadataOptions = {
271
+ /** Headers to send. Merged per name, and `null` drops one. */
272
+ headers?: MetadataInput;
273
+ /** Path parameters. Merged per name. */
274
+ path?: Record<string, unknown>;
275
+ /** Query parameters to add. Merged per name, and `null` drops one. */
276
+ query?: Record<string, unknown>;
277
+ };
278
+
279
+ export type SharedOptions<
280
+ TAddress = string,
281
+ TAuth = AuthValue,
282
+ TEnvironment = string,
283
+ > = BodySerializerOptions &
284
+ ConnectionOptions<TAddress, TAuth, TEnvironment> &
285
+ ErrorOptions &
286
+ MetadataOptions;
287
+
288
+ export type CallOptions = ExchangeOptions & SharedOptions;
289
+
290
+ export interface ResolvedOptions extends CallOptions {
291
+ [key: string]: unknown;
292
+ envelope?: boolean;
293
+ path?: Record<string, unknown>;
294
+ query?: Record<string, unknown>;
295
+ raw?: boolean;
296
+ unread?: boolean;
297
+ }
298
+
299
+ /** A request about to be sent, which a `request` hook reads and may change. */
300
+ export interface PreparedRequest<TAddress = unknown> {
301
+ /** Where the request goes. Over HTTP, the whole URL, query string included. */
302
+ address: TAddress;
303
+ /** How many times this request was sent before. Unset on the first attempt. */
304
+ attempt?: number;
305
+ /** The request body, already encoded. */
306
+ body: BodyPayload | undefined;
307
+ /** The operation this request calls, as declared, `method` included. */
308
+ callable: CallableDescriptor;
309
+ /** How the call exchanges messages, such as one request for one reply. */
310
+ interaction: Interaction;
311
+ /** Where this call writes its log lines. Unset where the client does not log. */
312
+ log?: CallLog;
313
+ /** The headers to send, by lowercase name. */
314
+ meta: Metadata;
315
+ /** The options this call resolved to: the client's, with the call's own on top. */
316
+ options: ResolvedOptions;
317
+ /** Each credential put on the request, with the scheme it answers. */
318
+ placed?: ReadonlyArray<PlacedCredential>;
319
+ /**
320
+ * Set to `manual` where the client follows redirects itself. A transport
321
+ * that honors it hands back the redirect rather than following it.
322
+ */
323
+ redirect?: 'manual';
324
+ /** Calls the request off when it aborts. */
325
+ signal?: AbortSignal | undefined;
326
+ unauthenticated?: () => string;
327
+ }
328
+
329
+ /** The kinds of exchange a transport carries. `unary` is one request and one reply. */
330
+ export type TransportInteraction = 'unary';
331
+
332
+ interface UnaryTransport<TAddress> {
333
+ /**
334
+ * Sends one request and resolves to the reply, whatever its status, with the
335
+ * body unread. Rejects only when no reply arrived.
336
+ */
337
+ unary(request: PreparedRequest<TAddress>): Promise<Response>;
338
+ }
339
+
340
+ type TransportMethods<TAddress> = UnaryTransport<TAddress>;
341
+
342
+ /** What carries a request to the API and hands back what the API sends. */
343
+ export type Transport<TAddress, TInteraction extends TransportInteraction> = {
344
+ /** The transport's name, as an error message shows it. */
345
+ readonly name: string;
346
+ } & Pick<TransportMethods<TAddress>, TInteraction>;
347
+
348
+ /** A credential, or a function that returns one when a call needs it. */
349
+ export type CredentialValue = AuthToken | (() => Promise<AuthToken> | AuthToken);
350
+
351
+ export interface Codec {
352
+ readonly contentType: string | undefined;
353
+ decode?(raw: Response): Promise<unknown>;
354
+ encode(value: unknown): BodyPayload;
355
+ readonly mediaTypes: ReadonlyArray<string>;
356
+ readonly name: string;
357
+ }
358
+
359
+ export type AnyTransport<TAddress = unknown> = {
360
+ readonly name: string;
361
+ } & Partial<TransportMethods<TAddress>>;
362
+
363
+ export interface Binding<TAddress = unknown> {
364
+ readonly accept?: string;
365
+ applyAuth(credential: Credential, request: PreparedRequest<TAddress>): void;
366
+ readonly name: string;
367
+ readError?(result: Result, request: PreparedRequest<TAddress>): unknown;
368
+ readResult?(
369
+ raw: Response,
370
+ request: PreparedRequest<TAddress>,
371
+ codecs: ReadonlyArray<Codec>,
372
+ ): Promise<Result>;
373
+ resolveAddress(callable: CallableDescriptor, options: ResolvedOptions): TAddress;
374
+ }
375
+
376
+ export interface FeatureContext {
377
+ binding: Binding;
378
+ transport: AnyTransport;
379
+ }
380
+
381
+ export type Send = (request: PreparedRequest) => Promise<Result>;
382
+
383
+ export interface Feature {
384
+ readonly name: string;
385
+ onError?(error: unknown, request: PreparedRequest, ctx: FeatureContext): unknown;
386
+ onOpen?(request: PreparedRequest, next: Send, ctx: FeatureContext): Promise<Result>;
387
+ onOptions?(
388
+ options: ResolvedOptions,
389
+ callable: CallableDescriptor,
390
+ ctx: FeatureContext,
391
+ ): Promise<void> | void;
392
+ onPrepare?(request: PreparedRequest, ctx: FeatureContext): Promise<void> | void;
393
+ onRequest?(request: PreparedRequest, ctx: FeatureContext): Promise<void> | void;
394
+ onResult?(
395
+ result: Result,
396
+ request: PreparedRequest,
397
+ ctx: FeatureContext,
398
+ ): Promise<Result> | Result;
399
+ onSend?(request: PreparedRequest, next: Send, ctx: FeatureContext): Promise<Result>;
400
+ }
401
+
402
+ export type CredentialSpec = {
403
+ readonly option?: false;
404
+ readonly prefix?: string;
405
+ readonly variable?: string;
406
+ };
407
+
408
+ type Hundred = 3 | 4 | 5;
409
+
410
+ type Digit = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
411
+
412
+ type NumberOf<T> = T extends `${infer N extends number}` ? N : never;
413
+
414
+ type Tens = {
415
+ [H in Hundred]: {
416
+ [T in Digit]: NumberOf<`${H}${T}${Digit}`>;
417
+ };
418
+ };
419
+
420
+ type Block = {
421
+ [H in Hundred]: Tens[H][Digit];
422
+ };
423
+
424
+ type SplitDigits<TText> = TText extends `${infer H}${infer T}${string}`
425
+ ? [NumberOf<H>, NumberOf<T>]
426
+ : never;
427
+
428
+ type DigitsOf<TStatus> = TStatus extends number ? SplitDigits<`${TStatus}`> : never;
429
+
430
+ type LeftIn<H extends Hundred, TExact> = H extends DigitsOf<TExact>[0]
431
+ ? {
432
+ [T in Digit]: [H, T] extends DigitsOf<TExact> ? Exclude<Tens[H][T], TExact> : Tens[H][T];
433
+ }[Digit]
434
+ : Block[H];
435
+
436
+ type Left<THundreds, TExact> = THundreds extends Hundred ? LeftIn<THundreds, TExact> : never;
437
+
438
+ type RangeDigit<TKey> = TKey extends `${infer D extends number}${'X' | 'x'}${'X' | 'x'}`
439
+ ? D & Hundred
440
+ : never;
441
+
442
+ type Open<TErrors> = Exclude<Hundred, RangeDigit<keyof TErrors>>;
443
+
444
+ type StatusKey<TKey> = TKey extends number ? TKey : NumberOf<TKey>;
445
+
446
+ export type DefaultStatus<TErrors> = Left<Open<TErrors>, StatusKey<keyof TErrors>> & number;
447
+
448
+ export type RangeStatus<TErrors, TKey> = Left<RangeDigit<TKey>, StatusKey<keyof TErrors>> & number;
449
+
450
+ export type FailureStatusOf<TErrors, TKey> = TKey extends number
451
+ ? TKey
452
+ : TKey extends `${infer N extends number}`
453
+ ? N
454
+ : Lowercase<TKey & string> extends 'default'
455
+ ? DefaultStatus<TErrors>
456
+ : RangeStatus<TErrors, TKey>;
457
+
458
+ export type UndeclaredStatus<TErrors> = ('default' extends Lowercase<Extract<keyof TErrors, string>>
459
+ ? 0
460
+ : 0 | Left<Open<TErrors>, StatusKey<keyof TErrors>>) &
461
+ number;
462
+
463
+ export type ErrorOf<TErrors> =
464
+ | (TErrors extends object
465
+ ? {
466
+ [K in keyof TErrors]: {
467
+ data?: never;
468
+ error: APIError<TErrors[K]>;
469
+ ok: false;
470
+ status: FailureStatusOf<TErrors, K>;
471
+ };
472
+ }[keyof TErrors]
473
+ : never)
474
+ | {
475
+ data?: never;
476
+ error: APIError;
477
+ ok: false;
478
+ status: UndeclaredStatus<TErrors>;
479
+ };
480
+
481
+ type StatusOf<TKey> = TKey extends number ? TKey : number;
482
+
483
+ type OutputOf<TResponses> = TResponses extends object
484
+ ? {
485
+ [K in keyof TResponses]: {
486
+ data: TResponses[K];
487
+ error?: never;
488
+ ok: true;
489
+ status: StatusOf<K>;
490
+ };
491
+ }[keyof TResponses]
492
+ : Result;
493
+
494
+ export type UnansweredOf = {
495
+ data?: never;
496
+ error: ElmoError;
497
+ ok: false;
498
+ status?: undefined;
499
+ };
500
+
501
+ /**
502
+ * What awaiting a call gives back: the payload, or the whole result where the
503
+ * client returns a failure in place of throwing it.
504
+ */
505
+ export type CallResult<
506
+ TResponses = unknown,
507
+ TErrors = unknown,
508
+ TMode extends ErrorMode = 'throw',
509
+ > = TMode extends 'return'
510
+ ? ErrorOf<TErrors> | OutputOf<TResponses> | UnansweredOf
511
+ : TResponses extends object
512
+ ? TResponses[keyof TResponses]
513
+ : unknown;
514
+
515
+ export interface EncodedBody {
516
+ contentType: string | undefined;
517
+ payload: BodyPayload;
518
+ }
519
+
520
+ export type PageOptions = {
521
+ /**
522
+ * Where to start reading, from an earlier page's `nextPageParam`. Unset, the
523
+ * walk starts at the page the call's own arguments name.
524
+ */
525
+ pageParam?: unknown;
526
+ };
527
+
528
+ /** What `result()` gives back: the payload, or the failure as a value. */
529
+ export type ResultEnvelope<TResponses = unknown, TErrors = unknown> = CallResult<
530
+ TResponses,
531
+ TErrors,
532
+ 'return'
533
+ >;
534
+
535
+ /** What a paged call hands back when its failure is read rather than thrown. */
536
+ export type PageEnvelope<TAwaited = unknown, TErrors = unknown> =
537
+ | ErrorOf<TErrors>
538
+ | UnansweredOf
539
+ | {
540
+ data: TAwaited;
541
+ error?: never;
542
+ ok: true;
543
+ status: number;
544
+ };
545
+
546
+ /**
547
+ * What awaiting a paged call gives back: the page, or the whole result where
548
+ * the client returns a failure in place of throwing it.
549
+ */
550
+ export type PageResult<
551
+ TAwaited = unknown,
552
+ TErrors = unknown,
553
+ TMode extends ErrorMode = 'throw',
554
+ > = TMode extends 'return' ? PageEnvelope<TAwaited, TErrors> : TAwaited;