@dregs/sdk 0.1.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.
@@ -0,0 +1,576 @@
1
+ export { DEFAULT_TOLERANCE_SECONDS, EVENT_HEADER, SIGNATURE_HEADER, TIMESTAMP_HEADER, VerifyWebhookOptions, WebhookEvent, WebhookPayload, computeWebhookSignature, verifyWebhook, verifyWebhookSignature } from './webhooks.js';
2
+
3
+ /**
4
+ * The package version, used in the `User-Agent` header.
5
+ *
6
+ * Kept here rather than read from `package.json` at runtime, because the published package is
7
+ * both ESM and CommonJS and neither can reach its own manifest portably. A test asserts this
8
+ * stays in step with `package.json`, so the two cannot drift.
9
+ */
10
+ declare const VERSION = "0.1.0";
11
+
12
+ /**
13
+ * Typed views over the Dregs API's responses.
14
+ *
15
+ * Every model keeps the response it was built from in `raw`, so a field Dregs adds after this
16
+ * release is still reachable without waiting for an SDK upgrade. Parsing is deliberately lenient:
17
+ * a missing field becomes `null` rather than an error, because an SDK that refuses to parse a
18
+ * response it half-understands is worse than one that hands back what it got.
19
+ *
20
+ * @module
21
+ */
22
+ /**
23
+ * The four categories Dregs scores an identity in.
24
+ *
25
+ * A plain string union rather than an enum, so `scores.get('HUMANITY')` type-checks and a
26
+ * category from a future Dregs release still survives parsing (as a `null` category on a
27
+ * {@link Score} whose `raw` still names it).
28
+ */
29
+ type Category = 'HUMANITY' | 'AUTHENTICITY' | 'UNIQUENESS' | 'BEHAVIOR';
30
+ /** The four categories, in the order the dashboard shows them. */
31
+ declare const CATEGORIES: readonly Category[];
32
+ /** An unparsed JSON object, as received. */
33
+ type RawPayload = Readonly<Record<string, unknown>>;
34
+ /** The outcome of a {@link Dregs.track} call. */
35
+ interface TrackResult {
36
+ /** The status Dregs reported, normally `"success"`. */
37
+ readonly status: string | null;
38
+ /**
39
+ * The event's identifier, either the one you supplied or one the SDK generated. It is `null`
40
+ * when the event was not recorded.
41
+ */
42
+ readonly id: string | null;
43
+ /**
44
+ * The device fingerprint Dregs resolved, for events that carried a device signature.
45
+ * Server-side events do not, so this is normally `null`.
46
+ */
47
+ readonly fingerprint: string | null;
48
+ /**
49
+ * Whether Dregs recorded the event.
50
+ *
51
+ * This is `false` in the uncommon case where Dregs accepts the request without recording an
52
+ * event. A server-side integration holding a valid secret key should not normally see it, so it
53
+ * is worth a log line if you do. Ingestion failures that are yours to act on (a bad request, an
54
+ * unknown key, an exhausted quota, a rate limit) throw instead of landing here.
55
+ */
56
+ readonly accepted: boolean;
57
+ /** The response body as received. */
58
+ readonly raw: RawPayload;
59
+ }
60
+ /** A label Dregs applied to an identity, from an analyzer or a badge rule. */
61
+ interface Badge {
62
+ /** The badge's slug, such as `"behavior.account-takeover-signal"`. */
63
+ readonly slug: string | null;
64
+ /** The human-readable name, such as `"Account Takeover Suspected"`. */
65
+ readonly name: string | null;
66
+ /** Where the badge came from: an analyzer observation or a badge rule. */
67
+ readonly type: string | null;
68
+ /** A sentence describing why the badge was applied. */
69
+ readonly explanation: string | null;
70
+ /** The counts and details behind the badge. */
71
+ readonly metadata: RawPayload;
72
+ /** The response fragment this badge was built from. */
73
+ readonly raw: RawPayload;
74
+ }
75
+ /** One analyzer's finding, and the reasoning behind a slice of a score. */
76
+ interface Observation {
77
+ /** The category the observation contributes to, or `null` for one this release predates. */
78
+ readonly category: Category | null;
79
+ /** The analyzer's identifier, such as `"humanity.user-agent"`. */
80
+ readonly id: string | null;
81
+ /** A human-readable name for the analyzer. */
82
+ readonly label: string | null;
83
+ /** A sentence describing what the analyzer found. This is the text to show or log. */
84
+ readonly explanation: string | null;
85
+ /** 0.0 for entirely suspicious, 1.0 for entirely legitimate. */
86
+ readonly value: number | null;
87
+ /** How sure the analyzer is, from 0.0 to 1.0. */
88
+ readonly confidence: number | null;
89
+ /** How heavily this observation counts toward the category score. */
90
+ readonly weight: number | null;
91
+ /** The counts and details behind the finding. */
92
+ readonly metadata: RawPayload;
93
+ /** The response fragment this observation was built from. */
94
+ readonly raw: RawPayload;
95
+ }
96
+ /** One category's score. */
97
+ interface Score {
98
+ /** The category scored, or `null` for one this release predates. */
99
+ readonly category: Category | null;
100
+ /** An integer from 0 (worst) to 100 (best). */
101
+ readonly value: number | null;
102
+ /**
103
+ * The observations behind the score. Empty on the result of `identities.scores()`, which
104
+ * reports the scores alone; the observations come from `identities.analysis()`.
105
+ */
106
+ readonly observations: readonly Observation[];
107
+ /** The response fragment this score was built from. */
108
+ readonly raw: RawPayload;
109
+ }
110
+ /**
111
+ * An identity's category scores.
112
+ *
113
+ * An array of {@link Score}, so it indexes, iterates, spreads, and maps like any other, and it
114
+ * also offers the four categories by name:
115
+ *
116
+ * ```ts
117
+ * const scores = await client.identities.scores('user_12345');
118
+ *
119
+ * if (scores.authenticity !== null && scores.authenticity < 40) {
120
+ * await holdForReview('user_12345');
121
+ * }
122
+ * ```
123
+ *
124
+ * A category Dregs has not scored yet is absent from the array, and its named accessor reads
125
+ * `null`. A brand-new identity comes back empty.
126
+ */
127
+ declare class Scores extends Array<Score> {
128
+ /**
129
+ * `map`, `filter`, and `slice` return plain arrays rather than trying to rebuild a `Scores`
130
+ * through a constructor whose shape they know nothing about.
131
+ */
132
+ static get [Symbol.species](): ArrayConstructor;
133
+ constructor(items?: readonly Score[]);
134
+ /** Returns the score for `category`, or `null` when it has not been scored. */
135
+ get(category: Category): Score | null;
136
+ private value;
137
+ /** How likely it is that a person, rather than a script, is behind the account. */
138
+ get humanity(): number | null;
139
+ /** How genuine the details on the account look. */
140
+ get authenticity(): number | null;
141
+ /** How distinct the account is from others in the same tenant. */
142
+ get uniqueness(): number | null;
143
+ /** How ordinary the account's activity looks. */
144
+ get behavior(): number | null;
145
+ }
146
+ /**
147
+ * A user Dregs is tracking, and their current scores.
148
+ *
149
+ * `id` is your own identifier for the user, the one you pass to {@link Dregs.track} and to
150
+ * `dregs.identify()` in the browser tracker, not an internal Dregs id.
151
+ */
152
+ interface Identity {
153
+ /** Your own id for the user. */
154
+ readonly id: string | null;
155
+ /** The name Dregs resolved from the identity attributes you have sent. */
156
+ readonly displayName: string | null;
157
+ /** The email address Dregs resolved from the identity attributes you have sent. */
158
+ readonly displayEmail: string | null;
159
+ /** The username Dregs resolved from the identity attributes you have sent. */
160
+ readonly displayUsername: string | null;
161
+ /** The current humanity score, 0 to 100, or `null` when the category is unscored. */
162
+ readonly humanityScore: number | null;
163
+ /** The current authenticity score, 0 to 100, or `null` when the category is unscored. */
164
+ readonly authenticityScore: number | null;
165
+ /** The current uniqueness score, 0 to 100, or `null` when the category is unscored. */
166
+ readonly uniquenessScore: number | null;
167
+ /** The current behavior score, 0 to 100, or `null` when the category is unscored. */
168
+ readonly behaviorScore: number | null;
169
+ /** When Dregs first saw this identity. */
170
+ readonly createdAt: Date | null;
171
+ /** When the identity record last changed. */
172
+ readonly updatedAt: Date | null;
173
+ /** When the most recent event for this identity arrived. */
174
+ readonly lastTrackedAt: Date | null;
175
+ /** When the most recent analysis cycle finished. */
176
+ readonly lastScoredAt: Date | null;
177
+ /**
178
+ * Whether the identity is excluded from fraud analysis, which is how an operator marks their
179
+ * own admin or load-test accounts.
180
+ */
181
+ readonly disregarded: boolean;
182
+ /** The badges currently applied to the identity. */
183
+ readonly badges: readonly Badge[];
184
+ /** Every identity attribute you have sent, merged. */
185
+ readonly data: RawPayload;
186
+ /**
187
+ * The four category scores, as a {@link Scores} for parity with `identities.scores()`.
188
+ *
189
+ * Built from the score fields on this response, so it costs no extra request.
190
+ */
191
+ readonly scores: Scores;
192
+ /** The response body this identity was built from. */
193
+ readonly raw: RawPayload;
194
+ }
195
+ /** One analysis cycle: the scores an identity was given, and why. */
196
+ interface Analysis {
197
+ /** The cycle's identifier. */
198
+ readonly id: number | null;
199
+ /** The identity that was analyzed. */
200
+ readonly identityId: string | null;
201
+ /** The category scores, each carrying its observations. */
202
+ readonly scores: Scores;
203
+ /** Every observation from the cycle, flattened across all categories. */
204
+ readonly observations: readonly Observation[];
205
+ /** How many events the cycle considered. */
206
+ readonly eventCount: number | null;
207
+ /** How many devices the cycle considered. */
208
+ readonly deviceCount: number | null;
209
+ /** How long the cycle took, in milliseconds. */
210
+ readonly durationMillis: number | null;
211
+ /** When the cycle started. */
212
+ readonly startedAt: Date | null;
213
+ /** When the cycle finished. */
214
+ readonly finishedAt: Date | null;
215
+ /** The response body this analysis was built from. */
216
+ readonly raw: RawPayload;
217
+ }
218
+
219
+ /**
220
+ * The `client.identities` namespace.
221
+ *
222
+ * These are thin: they name the endpoint, then hand the response to a parser. The transport,
223
+ * retries, and error mapping all live on the client.
224
+ *
225
+ * @module
226
+ */
227
+
228
+ /** How a resource reaches the client's transport. @internal */
229
+ type RequestFn = (method: string, path: string, body?: unknown) => Promise<unknown>;
230
+ /**
231
+ * Read identities and their scores.
232
+ *
233
+ * Reached as `client.identities`; there is no reason to construct one yourself.
234
+ */
235
+ declare class Identities {
236
+ #private;
237
+ /** @internal */
238
+ constructor(request: RequestFn);
239
+ /**
240
+ * Returns the identity, with its current scores, badges, and attributes.
241
+ *
242
+ * @param identityId Your own id for the user, the one you pass to `track()`.
243
+ * @throws {NotFoundError} Dregs has never seen this identity.
244
+ */
245
+ get(identityId: string): Promise<Identity>;
246
+ /**
247
+ * Returns the current category scores.
248
+ *
249
+ * This is the cheap read and the one most integrations want. It reports the scores Dregs has
250
+ * already computed without triggering any work. For the observations behind them, use
251
+ * {@link Identities.analysis}.
252
+ *
253
+ * A category that has not been scored yet is absent, so a brand-new identity comes back empty.
254
+ *
255
+ * @throws {NotFoundError} Dregs has never seen this identity.
256
+ */
257
+ scores(identityId: string): Promise<Scores>;
258
+ /**
259
+ * Returns the most recent analysis cycle, with the observations behind each score.
260
+ *
261
+ * Use this when you need to show or log *why* an identity scored the way it did.
262
+ *
263
+ * @throws {NotFoundError} The identity is unknown, or it has not been analyzed yet.
264
+ */
265
+ analysis(identityId: string): Promise<Analysis>;
266
+ /**
267
+ * Queues a re-analysis of the identity.
268
+ *
269
+ * Scoring is asynchronous: this resolves as soon as the job is queued, not when it has run.
270
+ * Poll {@link Identities.scores} or watch for a webhook rather than expecting fresh scores on
271
+ * the next line.
272
+ *
273
+ * @throws {NotFoundError} Dregs has never seen this identity.
274
+ */
275
+ analyze(identityId: string): Promise<void>;
276
+ }
277
+
278
+ /**
279
+ * The Dregs client.
280
+ *
281
+ * There is one client and every method returns a promise; JavaScript has no meaningful
282
+ * sync/async split, so there is no async twin to pick between.
283
+ *
284
+ * @module
285
+ */
286
+
287
+ /** The API root used when neither an option nor `DREGS_BASE_URL` names one. */
288
+ declare const DEFAULT_BASE_URL = "https://dregs.com/api";
289
+ /** How long a request may take before it is abandoned, in milliseconds. */
290
+ declare const DEFAULT_TIMEOUT_MS = 10000;
291
+ /** How many times a failed request is retried before the error is thrown. */
292
+ declare const DEFAULT_MAX_RETRIES = 2;
293
+ /** The environment variable the secret key is read from. */
294
+ declare const SECRET_KEY_ENV = "DREGS_SECRET_KEY";
295
+ /** The environment variable the base URL is read from. */
296
+ declare const BASE_URL_ENV = "DREGS_BASE_URL";
297
+ /** The `source` sent on events when the caller does not name one. */
298
+ declare const DEFAULT_SOURCE = "node-sdk";
299
+ /** The `fetch` this client calls. Any implementation with the standard signature will do. */
300
+ type FetchLike = (input: string, init: RequestInit) => Promise<Response>;
301
+ /** Everything you can configure on a {@link Dregs} client. */
302
+ interface DregsOptions {
303
+ /**
304
+ * Your credential's secret key, the one starting `sk_`. Found under **Settings → Credentials**
305
+ * in the dashboard. Defaults to `$DREGS_SECRET_KEY`.
306
+ */
307
+ secretKey?: string;
308
+ /**
309
+ * The API root every request is built against. Defaults to `$DREGS_BASE_URL`, then
310
+ * `https://dregs.com/api`. A trailing slash is harmless.
311
+ */
312
+ baseUrl?: string;
313
+ /**
314
+ * Milliseconds before a request is abandoned and retried. Defaults to 10 000.
315
+ *
316
+ * This covers the whole request, not just the connect, so raise it if you are behind a slow
317
+ * egress proxy rather than lowering `maxRetries` to compensate.
318
+ */
319
+ timeout?: number;
320
+ /**
321
+ * How many times to retry a failed request. Defaults to 2; pass 0 to handle it yourself.
322
+ *
323
+ * Retries cover connection failures, timeouts, 408, 429, and 5xx, with exponential backoff and
324
+ * full jitter. `Retry-After` wins when the server sends one. A retried event keeps its id, so
325
+ * a retry can never double-count.
326
+ */
327
+ maxRetries?: number;
328
+ /**
329
+ * A `fetch` to call instead of the runtime's own, for callers who need a proxy agent, custom
330
+ * TLS, or their own instrumentation. Anything with the standard signature works, including a
331
+ * stub in a test.
332
+ */
333
+ fetch?: FetchLike;
334
+ }
335
+ /** The arguments to {@link Dregs.track} beyond the event type. */
336
+ interface TrackOptions {
337
+ /**
338
+ * Your own id for the user. This is the same id you pass to `dregs.identify()` in the browser
339
+ * tracker, and the one you look scores up by.
340
+ *
341
+ * It is required: a server-side event carries no device signature, so the identity is the only
342
+ * thing tying the event to a user.
343
+ */
344
+ identity: string;
345
+ /** Attributes of the event itself, such as the plan bought or the referrer that sent them. */
346
+ data?: Readonly<Record<string, unknown>>;
347
+ /**
348
+ * Attributes of the *user*, such as email, name, or username. Dregs merges these into the
349
+ * identity, and the analyzers lean on them heavily, so send them whenever you have them.
350
+ *
351
+ * Flat keys work best. Name them as your application already does and map them to Dregs's
352
+ * canonical fields under **Settings → Mappings**.
353
+ */
354
+ identityData?: Readonly<Record<string, unknown>>;
355
+ /**
356
+ * Your own id for the event, which makes ingestion idempotent: reposting the same id returns
357
+ * the original event instead of recording a second one.
358
+ *
359
+ * Pass the id your application already has — the row id of the record that triggered the
360
+ * event, say. When you omit it the SDK generates one, which is what makes its own retries
361
+ * safe. At most 64 characters, and it cannot start with `dregs-`.
362
+ */
363
+ eventId?: string;
364
+ /**
365
+ * When the event happened, if not now. A `Date`, or an ISO-8601 string. Sent as UTC.
366
+ */
367
+ timestamp?: Date | string;
368
+ /** A label for where the event came from. Defaults to `"node-sdk"`. */
369
+ source?: string;
370
+ }
371
+ /**
372
+ * A Dregs client.
373
+ *
374
+ * The secret key comes from the `DREGS_SECRET_KEY` environment variable unless you pass one.
375
+ * Find it under **Settings → Credentials** in the dashboard; it is the key starting `sk_`, not
376
+ * the `pk_` public key the browser tracker uses.
377
+ *
378
+ * ```ts
379
+ * import { Dregs } from '@dregs/sdk';
380
+ *
381
+ * const client = new Dregs();
382
+ *
383
+ * await client.track('user.signup', { identity: 'user_12345', data: { plan: 'pro' } });
384
+ *
385
+ * const scores = await client.identities.scores('user_12345');
386
+ * ```
387
+ *
388
+ * Build one at startup and keep it. There is nothing to close: the client holds no state beyond
389
+ * its configuration, and connection pooling belongs to the runtime's `fetch`.
390
+ */
391
+ declare class Dregs {
392
+ #private;
393
+ /** Read identities, their scores, and their analysis. */
394
+ readonly identities: Identities;
395
+ /**
396
+ * @param options Configuration. Every field has a default, so `new Dregs()` reads the
397
+ * environment and is usually enough.
398
+ * @throws {TypeError} No secret key was found, the key given is a `pk_` public key, or
399
+ * `maxRetries` is negative.
400
+ */
401
+ constructor(options?: DregsOptions);
402
+ /** The API root every request is built against, with any trailing slash removed. */
403
+ get baseUrl(): string;
404
+ /** How many times a failed request is retried before the error is thrown. */
405
+ get maxRetries(): number;
406
+ /** Milliseconds before a request is abandoned. */
407
+ get timeout(): number;
408
+ /**
409
+ * Records a backend event against an identity.
410
+ *
411
+ * ```ts
412
+ * await client.track('user.signup', {
413
+ * identity: 'user_12345',
414
+ * data: { plan: 'pro', referrer: 'partner-x' },
415
+ * identityData: { email: 'ada@example.com', name: 'Ada Lovelace' },
416
+ * });
417
+ * ```
418
+ *
419
+ * @param type Your name for the event, such as `"user.signup"`. Map it to one of Dregs's
420
+ * canonical types under **Settings → Mappings** so the analyzers know what it means.
421
+ * @param options The identity the event belongs to, and anything else worth sending.
422
+ * @returns The outcome. Check `.accepted` to confirm Dregs recorded the event.
423
+ * @throws {QuotaExceededError} The account is over its monthly event limit.
424
+ * @throws {RateLimitError} The credential is ingesting too fast.
425
+ * @throws {AuthenticationError} The secret key was not recognized.
426
+ * @throws {BadRequestError} The event was malformed.
427
+ * @throws {TypeError} The event type, identity, or event id was unusable. These are thrown
428
+ * before anything is sent.
429
+ */
430
+ track(type: string, options: TrackOptions): Promise<TrackResult>;
431
+ /**
432
+ * Builds the `POST /api/events` body.
433
+ *
434
+ * An event id is always sent. When the caller has an id of their own it is used verbatim, so
435
+ * reposting the same event is a no-op on the Dregs side; otherwise one is generated, which is
436
+ * what makes this client's own retries safe to perform.
437
+ */
438
+ private trackBody;
439
+ /**
440
+ * Sends one request, retrying what is worth retrying, and returns the parsed JSON body.
441
+ *
442
+ * The retry loop reuses the request body verbatim, which is what keeps a retried event
443
+ * idempotent: the generated id is built once, before the first attempt.
444
+ */
445
+ private request;
446
+ private requestInit;
447
+ private shouldRetry;
448
+ /**
449
+ * Milliseconds to wait before attempt `attempt + 1`.
450
+ *
451
+ * `Retry-After` wins when the server sent one. Otherwise this is exponential with full jitter,
452
+ * which keeps a fleet of workers that all hit the limit at once from retrying in lockstep.
453
+ *
454
+ * Protected rather than private so a test can stub the waiting out.
455
+ */
456
+ protected backoff(attempt: number, retryAfterSeconds: number | null): number;
457
+ }
458
+
459
+ /**
460
+ * Errors thrown by the Dregs SDK.
461
+ *
462
+ * Everything this library throws derives from {@link DregsError}, so a caller that only wants a
463
+ * coarse "the Dregs call failed" branch can catch that one class. Errors that came back from the
464
+ * API carry the HTTP status and the parsed body; errors that never reached the API (DNS failure,
465
+ * connection refused, timeout) derive from {@link DregsConnectionError} instead.
466
+ *
467
+ * @module
468
+ */
469
+ /**
470
+ * Base class for everything this library throws.
471
+ *
472
+ * `instanceof DregsError` is the one check that catches every failure mode, including webhook
473
+ * verification and transport failures that never produced an HTTP status.
474
+ */
475
+ declare class DregsError extends Error {
476
+ constructor(message: string, options?: ErrorOptions);
477
+ }
478
+ /** The request never reached Dregs: DNS, TCP, TLS, or a dropped connection. */
479
+ declare class DregsConnectionError extends DregsError {
480
+ }
481
+ /** The request was still outstanding when the configured timeout elapsed. */
482
+ declare class DregsTimeoutError extends DregsConnectionError {
483
+ }
484
+ /** An incoming webhook did not verify against the channel's signing secret. */
485
+ declare class WebhookVerificationError extends DregsError {
486
+ }
487
+ /** The fields carried by every error that reached the API and came back an error. */
488
+ interface DregsAPIErrorOptions {
489
+ /** The HTTP status code. */
490
+ statusCode: number;
491
+ /** The parsed JSON body, or `null` when the response was not JSON. */
492
+ body?: unknown;
493
+ /** Value of the `X-Request-Id` response header, when the response carried one. */
494
+ requestId?: string | null;
495
+ /** The underlying cause, when there is one worth keeping. */
496
+ cause?: unknown;
497
+ }
498
+ /**
499
+ * Dregs answered, and the answer was an error.
500
+ *
501
+ * `message` is the human-readable message the API sent, so `err.message` reads the way a JS
502
+ * caller expects. `toString()` prefixes it with the status and the request id, which is the form
503
+ * worth putting in a log line when you open a support ticket.
504
+ */
505
+ declare class DregsAPIError extends DregsError {
506
+ /** The HTTP status code. */
507
+ readonly statusCode: number;
508
+ /** The parsed JSON body, or `null` when the response was not JSON. */
509
+ readonly body: unknown;
510
+ /**
511
+ * Value of the `X-Request-Id` response header, when present.
512
+ *
513
+ * Quote it when you report a problem: it is what lets Dregs find your exact request.
514
+ */
515
+ readonly requestId: string | null;
516
+ constructor(message: string, options: DregsAPIErrorOptions);
517
+ toString(): string;
518
+ }
519
+ /**
520
+ * 400. The request was malformed or missing something Dregs requires.
521
+ *
522
+ * For event ingestion this most often means the event carried neither an identity nor a device,
523
+ * or the body failed validation.
524
+ */
525
+ declare class BadRequestError extends DregsAPIError {
526
+ }
527
+ /** 401. The secret key was missing, unrecognized, revoked, or expired. */
528
+ declare class AuthenticationError extends DregsAPIError {
529
+ }
530
+ /**
531
+ * 402. The account is over its monthly event limit and ingestion is refused.
532
+ *
533
+ * Events are not queued while an account is over its limit, so the caller decides whether to drop
534
+ * the event or hold it. The limit resets with the billing period; upgrading the plan clears it
535
+ * immediately.
536
+ */
537
+ declare class QuotaExceededError extends DregsAPIError {
538
+ }
539
+ /** 403. The credential authenticated but is not allowed to do this. */
540
+ declare class PermissionDeniedError extends DregsAPIError {
541
+ }
542
+ /** 404. No such identity, or no analysis has been run for it yet. */
543
+ declare class NotFoundError extends DregsAPIError {
544
+ }
545
+ /** The fields carried by a 429, on top of the usual API error fields. */
546
+ interface RateLimitErrorOptions extends Omit<DregsAPIErrorOptions, 'statusCode'> {
547
+ statusCode?: number;
548
+ /** Seconds to wait before retrying, from the `Retry-After` header. */
549
+ retryAfter?: number | null;
550
+ }
551
+ /**
552
+ * 429. The credential exceeded its request rate limit.
553
+ *
554
+ * The client retries these on its own; you only see one when the retries were exhausted or turned
555
+ * off. Wait {@link RateLimitError.retryAfter} seconds before trying again when it is set.
556
+ */
557
+ declare class RateLimitError extends DregsAPIError {
558
+ /**
559
+ * Seconds to wait before retrying, from the `Retry-After` header when the response carried a
560
+ * numeric one, and `null` otherwise.
561
+ */
562
+ readonly retryAfter: number | null;
563
+ constructor(message: string, options?: RateLimitErrorOptions);
564
+ }
565
+ /** 5xx. Something went wrong inside Dregs. These are retried automatically. */
566
+ declare class ServerError extends DregsAPIError {
567
+ }
568
+ /**
569
+ * Returns the error class that represents `statusCode`.
570
+ *
571
+ * 429 is deliberately absent from the table: it needs the `Retry-After` header, so the client
572
+ * builds a {@link RateLimitError} directly rather than going through here.
573
+ */
574
+ declare function errorForStatus(statusCode: number): new (message: string, options: DregsAPIErrorOptions) => DregsAPIError;
575
+
576
+ export { type Analysis, AuthenticationError, BASE_URL_ENV, BadRequestError, type Badge, CATEGORIES, type Category, DEFAULT_BASE_URL, DEFAULT_MAX_RETRIES, DEFAULT_SOURCE, DEFAULT_TIMEOUT_MS, Dregs, DregsAPIError, type DregsAPIErrorOptions, DregsConnectionError, DregsError, type DregsOptions, DregsTimeoutError, type FetchLike, Identities, type Identity, NotFoundError, type Observation, PermissionDeniedError, QuotaExceededError, RateLimitError, type RateLimitErrorOptions, type RawPayload, SECRET_KEY_ENV, type Score, Scores, ServerError, type TrackOptions, type TrackResult, VERSION, WebhookVerificationError, errorForStatus };