e621 3.4.0 → 3.5.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 (62) hide show
  1. package/README.md +23 -0
  2. package/dist/browser/e621.js +1006 -223
  3. package/dist/browser/e621.js.map +4 -4
  4. package/dist/lib/client.d.ts +61 -0
  5. package/dist/lib/client.js +37 -4
  6. package/dist/lib/errors.d.ts +13 -0
  7. package/dist/lib/errors.js +27 -1
  8. package/dist/lib/generated/schemas.d.ts +218 -9
  9. package/dist/lib/generated/schemas.js +272 -16
  10. package/dist/lib/generated/sdk.d.ts +77 -7
  11. package/dist/lib/generated/sdk.js +134 -9
  12. package/dist/lib/generated/types.d.ts +907 -255
  13. package/dist/lib/index.d.ts +1 -1
  14. package/dist/lib/models/Artist.d.ts +1 -0
  15. package/dist/lib/models/Artist.js +2 -1
  16. package/dist/lib/models/PostFlag.d.ts +2 -1
  17. package/dist/lib/models/PostFlag.js +1 -1
  18. package/dist/lib/models/SavedSearch.d.ts +37 -0
  19. package/dist/lib/models/SavedSearch.js +55 -0
  20. package/dist/lib/models/TagSubscription.d.ts +25 -0
  21. package/dist/lib/models/TagSubscription.js +36 -0
  22. package/dist/lib/models/Takedown.d.ts +13 -2
  23. package/dist/lib/models/Takedown.js +21 -2
  24. package/dist/lib/models/User.d.ts +1 -1
  25. package/dist/lib/models/UserNameChangeRequest.d.ts +1 -1
  26. package/dist/lib/models/index.d.ts +2 -0
  27. package/dist/lib/models/index.js +3 -1
  28. package/dist/lib/models/posts/Actions.d.ts +6 -6
  29. package/dist/lib/modules/Artists.d.ts +2 -0
  30. package/dist/lib/modules/Artists.js +3 -1
  31. package/dist/lib/modules/Base.js +4 -2
  32. package/dist/lib/modules/DText.d.ts +2 -3
  33. package/dist/lib/modules/DText.js +5 -6
  34. package/dist/lib/modules/PostFlags.d.ts +6 -3
  35. package/dist/lib/modules/PostFlags.js +2 -2
  36. package/dist/lib/modules/PostVersions.d.ts +2 -1
  37. package/dist/lib/modules/PostVersions.js +3 -2
  38. package/dist/lib/modules/Posts.d.ts +6 -6
  39. package/dist/lib/modules/Posts.js +8 -14
  40. package/dist/lib/modules/SavedSearches.d.ts +94 -0
  41. package/dist/lib/modules/SavedSearches.js +162 -0
  42. package/dist/lib/modules/SearchTrendBlacklists.js +1 -1
  43. package/dist/lib/modules/StaffUsers.d.ts +1 -1
  44. package/dist/lib/modules/StaffUsers.js +4 -2
  45. package/dist/lib/modules/TagAliases.d.ts +1 -1
  46. package/dist/lib/modules/TagAliases.js +3 -2
  47. package/dist/lib/modules/TagImplications.d.ts +1 -1
  48. package/dist/lib/modules/TagImplications.js +3 -2
  49. package/dist/lib/modules/TagSubscriptions.d.ts +49 -0
  50. package/dist/lib/modules/TagSubscriptions.js +82 -0
  51. package/dist/lib/modules/Takedowns.d.ts +16 -2
  52. package/dist/lib/modules/Takedowns.js +25 -3
  53. package/dist/lib/modules/Uploads.d.ts +29 -2
  54. package/dist/lib/modules/Uploads.js +47 -11
  55. package/dist/lib/modules/UserNameChangeRequests.d.ts +2 -2
  56. package/dist/lib/modules/UserNameChangeRequests.js +5 -3
  57. package/dist/lib/modules/index.d.ts +6 -0
  58. package/dist/lib/modules/index.js +5 -1
  59. package/dist/lib/standalone.d.ts +1 -1
  60. package/dist/lib/version.d.ts +1 -1
  61. package/dist/lib/version.js +1 -1
  62. package/package.json +1 -1
@@ -1,6 +1,53 @@
1
1
  import type { Client } from "./generated/client/types.js";
2
2
  import type { NoV2Options, PostFormatOptions } from "./modules/posts/Format.js";
3
3
  /** @category Main */
4
+ export interface RatelimitInfo {
5
+ /** The 1-indexed attempt that just got rate limited. */
6
+ attempt: number;
7
+ /** The configured {@link RatelimitOptions.maxRetries}, for context. */
8
+ maxRetries: number;
9
+ request: Request;
10
+ response: Response;
11
+ /** Seconds parsed from the response's `Retry-After` header - `null` if missing/unparsable. */
12
+ retryAfter: number | null;
13
+ /** Whether this request will be retried, or is about to fail with a {@link RatelimitError}. */
14
+ willRetry: boolean;
15
+ }
16
+ /** @category Main */
17
+ export interface RatelimitOptions {
18
+ /**
19
+ * The maximum number of times to retry a rate limited (HTTP 429) request before giving up and
20
+ * throwing a {@link RatelimitError}.
21
+ * @default 3
22
+ */
23
+ maxRetries?: number;
24
+ /**
25
+ * The maximum delay, in seconds, to wait before retrying, regardless of what the `Retry-After` header
26
+ * says or how many attempts have been made.
27
+ * @default 60
28
+ */
29
+ maxRetryDelay?: number;
30
+ /**
31
+ * Called every time a request gets rate limited, before the retry delay (or before throwing, if
32
+ * retries are exhausted or disabled). Useful for logging/metrics.
33
+ * @default none
34
+ */
35
+ onRatelimit?: (info: RatelimitInfo) => void;
36
+ /**
37
+ * Whether to automatically retry requests that get rate limited (HTTP 429), waiting for the duration
38
+ * in the response's `Retry-After` header (or `retryDelay`, backed off exponentially per attempt, if
39
+ * the header is missing or unusable) before retrying.
40
+ * @default true
41
+ */
42
+ retry?: boolean;
43
+ /**
44
+ * The delay, in seconds, to wait before retrying a rate limited request when the response has no (or
45
+ * an unusable) `Retry-After` header. Doubled per attempt (capped at `maxRetryDelay`).
46
+ * @default 1
47
+ */
48
+ retryDelay?: number;
49
+ }
50
+ /** @category Main */
4
51
  export interface Options<PF extends PostFormatOptions = NoV2Options> {
5
52
  /**
6
53
  * The api key you want to authenticate with (Account -> Manage API Access)
@@ -25,6 +72,11 @@ export interface Options<PF extends PostFormatOptions = NoV2Options> {
25
72
  * @default legacy (v2: false)
26
73
  */
27
74
  defaultPostFormat?: PF;
75
+ /**
76
+ * Controls how rate limited (HTTP 429) requests are retried.
77
+ * @default \{ retry: true, maxRetries: 3, retryDelay: 1, maxRetryDelay: 60 \}
78
+ */
79
+ ratelimit?: RatelimitOptions;
28
80
  /**
29
81
  * The number of seconds before a request times out
30
82
  * @default 30
@@ -49,10 +101,19 @@ export interface Options<PF extends PostFormatOptions = NoV2Options> {
49
101
  userAgentInQuery?: boolean;
50
102
  }
51
103
  /** @category Main */
104
+ export interface ResolvedRatelimitOptions {
105
+ maxRetries: number;
106
+ maxRetryDelay: number;
107
+ onRatelimit?: (info: RatelimitInfo) => void;
108
+ retry: boolean;
109
+ retryDelay: number;
110
+ }
111
+ /** @category Main */
52
112
  export interface InstanceOptions {
53
113
  authKey: string | null;
54
114
  authUser: string | null;
55
115
  baseURL: string;
116
+ ratelimit: ResolvedRatelimitOptions;
56
117
  requestTimeout: number;
57
118
  statusCheckURL: string;
58
119
  userAgent: string;
@@ -1,4 +1,5 @@
1
1
  import Debug from "./Debug.js";
2
+ import { parseRetryAfter } from "./errors.js";
2
3
  import { createClient } from "./generated/client/client.js";
3
4
  import { createConfig } from "./generated/client/utils.js";
4
5
  import { VERSION } from "./version.js";
@@ -16,6 +17,13 @@ export function createE621Client(options) {
16
17
  authKey: options?.authKey ?? null,
17
18
  authUser: options?.authUser ?? null,
18
19
  baseURL: options?.baseURL ?? "https://e621.net",
20
+ ratelimit: {
21
+ maxRetries: options?.ratelimit?.maxRetries ?? 3,
22
+ maxRetryDelay: options?.ratelimit?.maxRetryDelay ?? 60,
23
+ onRatelimit: options?.ratelimit?.onRatelimit,
24
+ retry: options?.ratelimit?.retry ?? true,
25
+ retryDelay: options?.ratelimit?.retryDelay ?? 1,
26
+ },
19
27
  requestTimeout: options?.requestTimeout ?? 30,
20
28
  statusCheckURL: options?.statusCheckURL ?? "https://status.e621.church/json",
21
29
  userAgent: options?.userAgent ?? `E621/${VERSION} (https://github.com/DonovanDMC/E621${options?.authUser ? `; "${options.authUser}"` : ""})`,
@@ -33,7 +41,7 @@ export function createE621Client(options) {
33
41
  if (input instanceof Request) {
34
42
  url = input.url;
35
43
  method = input.method.toLowerCase();
36
- if (!input.headers.has("Auithorization") && resolved.authKey && resolved.authUser) {
44
+ if (!input.headers.has("Authorization") && resolved.authKey && resolved.authUser) {
37
45
  input.headers.set("Authorization", `Basic ${btoa(`${resolved.authUser}:${resolved.authKey}`)}`);
38
46
  }
39
47
  }
@@ -55,8 +63,33 @@ export function createE621Client(options) {
55
63
  url = requestURL.toString();
56
64
  }
57
65
  Debug(`request:${method}`, `-> ${url}`);
58
- const res = await fetch(input, init);
59
- Debug(`response:${method}`, `<- ${url} ${res.status} ${res.statusText}`);
66
+ let attempt = 0, res;
67
+ for (;;) {
68
+ // clone so a retry can re-send the body - `input` itself is never fetched directly, so it's
69
+ // never disturbed and can be cloned again on the next attempt
70
+ res = await fetch(input instanceof Request ? input.clone() : input, init);
71
+ Debug(`response:${method}`, `<- ${url} ${res.status} ${res.statusText}`);
72
+ if (res.status !== 429)
73
+ break;
74
+ const retryAfter = parseRetryAfter(res);
75
+ const willRetry = resolved.ratelimit.retry && attempt < resolved.ratelimit.maxRetries;
76
+ resolved.ratelimit.onRatelimit?.({
77
+ attempt: attempt + 1,
78
+ maxRetries: resolved.ratelimit.maxRetries,
79
+ request: input instanceof Request ? input : new Request(url, init),
80
+ response: res,
81
+ retryAfter,
82
+ willRetry,
83
+ });
84
+ if (!willRetry)
85
+ break;
86
+ const delay = Math.min(retryAfter ?? resolved.ratelimit.retryDelay * 2 ** attempt, resolved.ratelimit.maxRetryDelay);
87
+ Debug(`response:${method}`, `<- ${url} ratelimited, retrying in ${delay}s (attempt ${attempt + 1}/${resolved.ratelimit.maxRetries})`);
88
+ // free the connection, the body of a response we're discarding is never read
89
+ await res.body?.cancel().catch(() => { });
90
+ await new Promise(resolve => setTimeout(resolve, delay * 1000));
91
+ attempt++;
92
+ }
60
93
  return res;
61
94
  },
62
95
  };
@@ -76,4 +109,4 @@ export function createE621Client(options) {
76
109
  }
77
110
  return { client: createClient(config), options: resolved };
78
111
  }
79
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbGliL2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssTUFBTSxZQUFZLENBQUM7QUFDL0IsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzVELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUMzRCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBdUV2Qzs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sVUFBVSxnQkFBZ0IsQ0FBbUQsT0FBcUI7SUFDcEcsTUFBTSxRQUFRLEdBQW9CO1FBQzlCLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxJQUFJLElBQUk7UUFDakMsUUFBUSxFQUFFLE9BQU8sRUFBRSxRQUFRLElBQUksSUFBSTtRQUNuQyxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sSUFBSSxrQkFBa0I7UUFDL0MsY0FBYyxFQUFFLE9BQU8sRUFBRSxjQUFjLElBQUksRUFBRTtRQUM3QyxjQUFjLEVBQUUsT0FBTyxFQUFFLGNBQWMsSUFBSSxpQ0FBaUM7UUFDNUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxTQUFTLElBQUksUUFBUSxPQUFPLHVDQUF1QyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxNQUFNLE9BQU8sQ0FBQyxRQUFRLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHO1FBQzVJLGdCQUFnQixFQUFFLE9BQU8sRUFBRSxnQkFBZ0IsSUFBSSxRQUFRLElBQUksVUFBVTtLQUN4RSxDQUFDO0lBQ0YsSUFBSSxNQUFjLENBQUM7SUFDbkIsTUFBTSxZQUFZLEdBQWdEO1FBQzlELE9BQU8sRUFBRSxRQUFRLENBQUMsT0FBTztRQUN6QixPQUFPLEVBQUUsUUFBUSxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO1lBQzdDLFlBQVksRUFB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
112
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbGliL2NsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssTUFBTSxZQUFZLENBQUM7QUFDL0IsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM5QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDNUQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQzNELE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxjQUFjLENBQUM7QUF1SXZDOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxVQUFVLGdCQUFnQixDQUFtRCxPQUFxQjtJQUNwRyxNQUFNLFFBQVEsR0FBb0I7UUFDOUIsT0FBTyxFQUFFLE9BQU8sRUFBRSxPQUFPLElBQUksSUFBSTtRQUNqQyxRQUFRLEVBQUUsT0FBTyxFQUFFLFFBQVEsSUFBSSxJQUFJO1FBQ25DLE9BQU8sRUFBRSxPQUFPLEVBQUUsT0FBTyxJQUFJLGtCQUFrQjtRQUMvQyxTQUFTLEVBQUU7WUFDUCxVQUFVLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxVQUFVLElBQUksQ0FBQztZQUMvQyxhQUFhLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxhQUFhLElBQUksRUFBRTtZQUN0RCxXQUFXLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFBRSxXQUFXO1lBQzVDLEtBQUssRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLEtBQUssSUFBSSxJQUFJO1lBQ3hDLFVBQVUsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsSUFBSSxDQUFDO1NBQ2xEO1FBQ0QsY0FBYyxFQUFFLE9BQU8sRUFBRSxjQUFjLElBQUksRUFBRTtRQUM3QyxjQUFjLEVBQUUsT0FBTyxFQUFFLGNBQWMsSUFBSSxpQ0FBaUM7UUFDNUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxTQUFTLElBQUksUUFBUSxPQUFPLHVD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
@@ -1,3 +1,5 @@
1
+ /** Parses a response's `Retry-After` header (seconds or an HTTP-date) into seconds - `null` if missing/unparsable. @category Errors */
2
+ export declare function parseRetryAfter(response?: Response): number | null;
1
3
  /** @category Errors */
2
4
  export declare class UnexpectedResponseError extends Error {
3
5
  error: unknown;
@@ -6,3 +8,14 @@ export declare class UnexpectedResponseError extends Error {
6
8
  response?: Response;
7
9
  constructor(request: Request | undefined, response: Response | undefined, error: unknown);
8
10
  }
11
+ /**
12
+ * Thrown when e621 responds with `429 Too Many Requests` and the request either wasn't set to retry (see
13
+ * {@link RatelimitOptions.retry}) or ran out of retries.
14
+ * @category Errors
15
+ */
16
+ export declare class RatelimitError extends UnexpectedResponseError {
17
+ name: string;
18
+ /** Seconds to wait before retrying, parsed from the response's `Retry-After` header - `null` if it was missing or unparsable. */
19
+ retryAfter: number | null;
20
+ constructor(request: Request | undefined, response: Response | undefined, error: unknown);
21
+ }
@@ -1,3 +1,14 @@
1
+ /** Parses a response's `Retry-After` header (seconds or an HTTP-date) into seconds - `null` if missing/unparsable. @category Errors */
2
+ export function parseRetryAfter(response) {
3
+ const header = response?.headers.get("Retry-After");
4
+ if (!header)
5
+ return null;
6
+ const seconds = Number(header);
7
+ if (!Number.isNaN(seconds))
8
+ return Math.max(0, seconds);
9
+ const timestamp = Date.parse(header);
10
+ return Number.isNaN(timestamp) ? null : Math.max(0, Math.round((timestamp - Date.now()) / 1000));
11
+ }
1
12
  /** @category Errors */
2
13
  export class UnexpectedResponseError extends Error {
3
14
  error;
@@ -39,4 +50,19 @@ export class UnexpectedResponseError extends Error {
39
50
  });
40
51
  }
41
52
  }
42
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbGliL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx1QkFBdUI7QUFDdkIsTUFBTSxPQUFPLHVCQUF3QixTQUFRLEtBQUs7SUFDOUMsS0FBSyxDQUFXO0lBQ1AsSUFBSSxHQUFHLHlCQUF5QixDQUFDO0lBQzFDLE9BQU8sQ0FBVztJQUNsQixRQUFRLENBQVk7SUFDcEIsWUFBWSxPQUE0QixFQUFFLFFBQThCLEVBQUUsS0FBYztRQUNwRixJQUFJLE9BQU8sR0FBRyxRQUFRO1lBQ2xCLENBQUMsQ0FBQyxjQUFjLFFBQVEsQ0FBQyxNQUFNLElBQUksUUFBUSxDQUFDLFVBQVUsT0FBTyxPQUFPLEVBQUUsTUFBTSxJQUFJLEdBQUcsSUFBSSxPQUFPLEVBQUUsR0FBRyxJQUFJLFFBQVEsQ0FBQyxHQUFHLEVBQUU7WUFDckgsQ0FBQyxDQUFDLE9BQU87Z0JBQ0wsQ0FBQyxDQUFDLG9CQUFvQixPQUFPLENBQUMsTUFBTSxJQUFJLE9BQU8sQ0FBQyxHQUFHLEVBQUU7Z0JBQ3JELENBQUMsQ0FBQywwQ0FBMEMsQ0FBQztRQUNyRCxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ1IsSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRO2dCQUFFLE9BQU8sSUFBSSxLQUFLLEtBQUssRUFBRSxDQUFDO2lCQUNsRCxJQUFJLEtBQUssWUFBWSxLQUFLO2dCQUFFLE9BQU8sSUFBSSxLQUFLLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNqRSx1RUFBdUU7aUJBQ2xFLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLEtBQUssS0FBSyxJQUFJLEVBQUUsQ0FBQztnQkFDbkQsSUFBSSxTQUFTLElBQUksS0FBSyxJQUFJLE9BQU8sS0FBSyxDQUFDLE9BQU8sS0FBSyxRQUFRO29CQUFFLE9BQU8sSUFBSSxLQUFLLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztxQkFDeEYsSUFBSSxPQUFPLElBQUksS0FBSyxJQUFJLE9BQU8sS0FBSyxDQUFDLEtBQUssS0FBSyxRQUFRO29CQUFFLE9BQU8sSUFBSSxLQUFLLEtBQUssQ0FBQyxLQUFLLEVBQUUsQ0FBQztxQkFDdkYsSUFBSSxRQUFRLElBQUksS0FBSyxJQUFJLE9BQU8sS0FBSyxDQUFDLE1BQU0sS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxJQUFJLEVBQUUsQ0FBQztvQkFDdEYsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUM7d0JBQ3RELElBQUksT0FBTyxLQUFLLEtBQUssUUFBUTs0QkFBRSxPQUFPLElBQUksS0FBSyxHQUFHLEtBQUssS0FBSyxFQUFFLENBQUM7NkJBQzFELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7NEJBQUUsT0FBTyxJQUFJLEtBQUssR0FBRyxLQUFLLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztvQkFDOUUsQ0FBQztnQkFDTCxDQUFDO1lBQ0wsQ0FBQztRQUNMLENBQUM7UUFDRCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDZixNQUFNLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFO1lBQzFCLE9BQU8sRUFBRSxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsVUFBVSxFQUFFLEtBQUssRUFBRTtZQUM5QyxRQUFRLEVBQUUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLFVBQVUsRUFBRSxLQUFLLEVBQUU7WUFDaEQsS0FBSyxFQUFFLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFO1NBQzdDLENBQUMsQ0FBQztJQUNQLENBQUM7Q0FDSiJ9
53
+ /**
54
+ * Thrown when e621 responds with `429 Too Many Requests` and the request either wasn't set to retry (see
55
+ * {@link RatelimitOptions.retry}) or ran out of retries.
56
+ * @category Errors
57
+ */
58
+ export class RatelimitError extends UnexpectedResponseError {
59
+ name = "RatelimitError";
60
+ /** Seconds to wait before retrying, parsed from the response's `Retry-After` header - `null` if it was missing or unparsable. */
61
+ retryAfter;
62
+ constructor(request, response, error) {
63
+ super(request, response, error);
64
+ this.retryAfter = parseRetryAfter(response);
65
+ this.message = this.message.replace("Unexpected", "Ratelimited") + (this.retryAfter === null ? "" : `\nRetry after ${this.retryAfter}s`);
66
+ }
67
+ }
68
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbGliL2Vycm9ycy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSx1SUFBdUk7QUFDdkksTUFBTSxVQUFVLGVBQWUsQ0FBQyxRQUFtQjtJQUMvQyxNQUFNLE1BQU0sR0FBRyxRQUFRLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxhQUFhLENBQUMsQ0FBQztJQUNwRCxJQUFJLENBQUMsTUFBTTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQ3pCLE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUMvQixJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUM7UUFBRSxPQUFPLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3hELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDckMsT0FBTyxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQztBQUNyRyxDQUFDO0FBRUQsdUJBQXVCO0FBQ3ZCLE1BQU0sT0FBTyx1QkFBd0IsU0FBUSxLQUFLO0lBQzlDLEtBQUssQ0FBVztJQUNQLElBQUksR0FBRyx5QkFBeUIsQ0FBQztJQUMxQyxPQUFPLENBQVc7SUFDbEIsUUFBUSxDQUFZO0lBQ3BCLFlBQVksT0FBNEIsRUFBRSxRQUE4QixFQUFFLEtBQWM7UUFDcEYsSUFBSSxPQUFPLEdBQUcsUUFBUTtZQUNsQixDQUFDLENBQUMsY0FBYyxRQUFRLENBQUMsTUFBTSxJQUFJLFFBQVEsQ0FBQyxVQUFV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
@@ -1093,7 +1093,7 @@ export declare const ExtendedPostSchema: {
1093
1093
  };
1094
1094
  export declare const ForumPostSchema: {
1095
1095
  readonly type: "object";
1096
- readonly required: readonly ["id", "topic_id", "creator_id", "updater_id", "body", "is_hidden", "created_at", "updated_at", "warning_type", "warning_user_id"];
1096
+ readonly required: readonly ["id", "topic_id", "creator_id", "updater_id", "body", "is_hidden", "created_at", "updated_at", "warning_type", "warning_user_id", "vote_score", "creator_name", "updater_name"];
1097
1097
  readonly properties: {
1098
1098
  readonly id: {
1099
1099
  readonly type: "integer";
@@ -1128,6 +1128,17 @@ export declare const ForumPostSchema: {
1128
1128
  readonly type: "integer";
1129
1129
  readonly nullable: true;
1130
1130
  };
1131
+ readonly vote_score: {
1132
+ readonly type: "string";
1133
+ readonly nullable: true;
1134
+ readonly description: "Net votes divided by total votes, from -1 to 1. Null if the post has never been voted on.";
1135
+ };
1136
+ readonly creator_name: {
1137
+ readonly type: "string";
1138
+ };
1139
+ readonly updater_name: {
1140
+ readonly type: "string";
1141
+ };
1131
1142
  };
1132
1143
  };
1133
1144
  export declare const ForumPostVoteSchema: {
@@ -1161,7 +1172,7 @@ export declare const ForumPostVoteSchema: {
1161
1172
  };
1162
1173
  export declare const ForumTopicSchema: {
1163
1174
  readonly type: "object";
1164
- readonly required: readonly ["id", "creator_id", "updater_id", "title", "response_count", "is_sticky", "is_locked", "is_hidden", "created_at", "updated_at", "category_id"];
1175
+ readonly required: readonly ["id", "creator_id", "updater_id", "title", "response_count", "is_sticky", "is_locked", "is_hidden", "created_at", "updated_at", "category_id", "last_bumped_at", "creator_name", "updater_name"];
1165
1176
  readonly properties: {
1166
1177
  readonly id: {
1167
1178
  readonly type: "integer";
@@ -1198,6 +1209,16 @@ export declare const ForumTopicSchema: {
1198
1209
  readonly category_id: {
1199
1210
  readonly type: "integer";
1200
1211
  };
1212
+ readonly last_bumped_at: {
1213
+ readonly type: "string";
1214
+ readonly format: "date-time";
1215
+ };
1216
+ readonly creator_name: {
1217
+ readonly type: "string";
1218
+ };
1219
+ readonly updater_name: {
1220
+ readonly type: "string";
1221
+ };
1201
1222
  };
1202
1223
  };
1203
1224
  export declare const FullCurrentUserSchema: {
@@ -1601,6 +1622,10 @@ export declare const LegacyPostSchema: {
1601
1622
  readonly type: "string";
1602
1623
  readonly nullable: true;
1603
1624
  };
1625
+ readonly alt: {
1626
+ readonly type: "string";
1627
+ readonly nullable: true;
1628
+ };
1604
1629
  };
1605
1630
  };
1606
1631
  readonly sample: {
@@ -1622,6 +1647,10 @@ export declare const LegacyPostSchema: {
1622
1647
  readonly type: "string";
1623
1648
  readonly nullable: true;
1624
1649
  };
1650
+ readonly alt: {
1651
+ readonly type: "string";
1652
+ readonly nullable: true;
1653
+ };
1625
1654
  readonly alternates: {
1626
1655
  readonly type: "object";
1627
1656
  readonly properties: {
@@ -2562,6 +2591,40 @@ export declare const PostFilesSchema: {
2562
2591
  readonly sample: {
2563
2592
  readonly $ref: "#/components/schemas/PostFilesSample";
2564
2593
  };
2594
+ readonly video: {
2595
+ readonly type: "object";
2596
+ readonly required: readonly ["has", "original", "variants", "samples"];
2597
+ readonly properties: {
2598
+ readonly has: {
2599
+ readonly type: "boolean";
2600
+ };
2601
+ readonly original: {
2602
+ readonly $ref: "#/components/schemas/PostSampleAlternate";
2603
+ };
2604
+ readonly variants: {
2605
+ readonly type: "object";
2606
+ readonly properties: {
2607
+ readonly webm: {
2608
+ readonly $ref: "#/components/schemas/PostSampleAlternate";
2609
+ };
2610
+ readonly mp4: {
2611
+ readonly $ref: "#/components/schemas/PostSampleAlternate";
2612
+ };
2613
+ };
2614
+ };
2615
+ readonly samples: {
2616
+ readonly type: "object";
2617
+ readonly properties: {
2618
+ readonly '480p': {
2619
+ readonly $ref: "#/components/schemas/PostSampleAlternate";
2620
+ };
2621
+ readonly '720p': {
2622
+ readonly $ref: "#/components/schemas/PostSampleAlternate";
2623
+ };
2624
+ };
2625
+ };
2626
+ };
2627
+ };
2565
2628
  };
2566
2629
  };
2567
2630
  export declare const PostFilesMetaSchema: {
@@ -2838,6 +2901,7 @@ export declare const PostSampleAlternateSchema: {
2838
2901
  };
2839
2902
  readonly codec: {
2840
2903
  readonly type: "string";
2904
+ readonly nullable: true;
2841
2905
  };
2842
2906
  readonly size: {
2843
2907
  readonly type: "integer";
@@ -2852,6 +2916,7 @@ export declare const PostSampleAlternateSchema: {
2852
2916
  readonly url: {
2853
2917
  readonly type: "string";
2854
2918
  readonly format: "uri";
2919
+ readonly nullable: true;
2855
2920
  };
2856
2921
  };
2857
2922
  };
@@ -2901,7 +2966,7 @@ export declare const PostSetSchema: {
2901
2966
  };
2902
2967
  export declare const PostStatsSchema: {
2903
2968
  readonly type: "object";
2904
- readonly required: readonly ["score", "fav_count", "is_favorited", "vote", "comment_count"];
2969
+ readonly required: readonly ["score", "fav_count", "is_favorited", "vote", "comment_count", "hotness"];
2905
2970
  readonly properties: {
2906
2971
  readonly score: {
2907
2972
  readonly $ref: "#/components/schemas/PostStatsScore";
@@ -2918,6 +2983,10 @@ export declare const PostStatsSchema: {
2918
2983
  readonly comment_count: {
2919
2984
  readonly type: "integer";
2920
2985
  };
2986
+ readonly hotness: {
2987
+ readonly type: "number";
2988
+ readonly format: "float";
2989
+ };
2921
2990
  };
2922
2991
  };
2923
2992
  export declare const PostStatsScoreSchema: {
@@ -2937,7 +3006,7 @@ export declare const PostStatsScoreSchema: {
2937
3006
  };
2938
3007
  export declare const PostVersionSchema: {
2939
3008
  readonly type: "object";
2940
- readonly required: readonly ["id", "post_id", "tags", "updater_id", "updated_at", "rating", "parent_id", "source", "description", "reason", "locked_tags", "added_tags", "removed_tags", "added_locked_tags", "removed_locked_tags", "rating_changed", "parent_changed", "source_changed", "description_changed", "version", "obsolete_added_tags", "obsolete_removed_tags", "unchanged_tags", "updater_name", "is_hidden"];
3009
+ readonly required: readonly ["id", "post_id", "tags", "updater_id", "updated_at", "rating", "parent_id", "source", "description", "reason", "locked_tags", "added_tags", "removed_tags", "original_tags", "added_locked_tags", "removed_locked_tags", "rating_changed", "parent_changed", "source_changed", "description_changed", "version", "obsolete_added_tags", "obsolete_removed_tags", "unchanged_tags", "updater_name", "is_hidden"];
2941
3010
  readonly properties: {
2942
3011
  readonly id: {
2943
3012
  readonly type: "integer";
@@ -2988,6 +3057,13 @@ export declare const PostVersionSchema: {
2988
3057
  readonly type: "string";
2989
3058
  };
2990
3059
  };
3060
+ readonly original_tags: {
3061
+ readonly type: "array";
3062
+ readonly description: "The tag changes as the user submitted them, before aliases, implications, and automatic tags. Removed tags are prefixed with `-`. May include metatags such as `rating:`, `pool:`, `parent:`, and `source:`.";
3063
+ readonly items: {
3064
+ readonly type: "string";
3065
+ };
3066
+ };
2991
3067
  readonly added_locked_tags: {
2992
3068
  readonly type: "array";
2993
3069
  readonly items: {
@@ -3290,6 +3366,51 @@ export declare const RisingSearchTrendSchema: {
3290
3366
  };
3291
3367
  };
3292
3368
  };
3369
+ export declare const SavedSearchSchema: {
3370
+ readonly type: "object";
3371
+ readonly required: readonly ["id", "query", "name", "is_tracked", "is_subscription", "last_seen_post_id", "created_at", "updated_at", "new_count"];
3372
+ readonly properties: {
3373
+ readonly id: {
3374
+ readonly type: "integer";
3375
+ };
3376
+ readonly query: {
3377
+ readonly type: "string";
3378
+ readonly description: "Empty for the subscription search, its tags are managed through tag subscriptions.";
3379
+ };
3380
+ readonly name: {
3381
+ readonly type: "string";
3382
+ readonly nullable: true;
3383
+ };
3384
+ readonly is_tracked: {
3385
+ readonly type: "boolean";
3386
+ };
3387
+ readonly is_subscription: {
3388
+ readonly type: "boolean";
3389
+ readonly description: "True for the search that holds the user's tag subscriptions.";
3390
+ };
3391
+ readonly last_seen_post_id: {
3392
+ readonly type: "integer";
3393
+ readonly nullable: true;
3394
+ };
3395
+ readonly created_at: {
3396
+ readonly type: "string";
3397
+ readonly format: "date-time";
3398
+ };
3399
+ readonly updated_at: {
3400
+ readonly type: "string";
3401
+ readonly format: "date-time";
3402
+ };
3403
+ readonly tag_count: {
3404
+ readonly type: "integer";
3405
+ readonly description: "Only present on the subscription search.";
3406
+ };
3407
+ readonly new_count: {
3408
+ readonly type: "integer";
3409
+ readonly nullable: true;
3410
+ readonly description: "New posts since the search was last seen, capped at 100. Null for untracked searches, when no counts are cached, or when the search could not be evaluated.";
3411
+ };
3412
+ };
3413
+ };
3293
3414
  export declare const SearchTrendSchema: {
3294
3415
  readonly type: "object";
3295
3416
  readonly required: readonly ["tag", "count", "day"];
@@ -3975,6 +4096,28 @@ export declare const TagPreviewSchema: {
3975
4096
  };
3976
4097
  };
3977
4098
  };
4099
+ export declare const TagSubscriptionSchema: {
4100
+ readonly type: "object";
4101
+ readonly required: readonly ["id", "tag_id", "created_at", "tag_name", "category"];
4102
+ readonly properties: {
4103
+ readonly id: {
4104
+ readonly type: "integer";
4105
+ };
4106
+ readonly tag_id: {
4107
+ readonly type: "integer";
4108
+ };
4109
+ readonly created_at: {
4110
+ readonly type: "string";
4111
+ readonly format: "date-time";
4112
+ };
4113
+ readonly tag_name: {
4114
+ readonly type: "string";
4115
+ };
4116
+ readonly category: {
4117
+ readonly $ref: "#/components/schemas/TagCategory";
4118
+ };
4119
+ };
4120
+ };
3978
4121
  export declare const TagTypeVersionSchema: {
3979
4122
  readonly type: "object";
3980
4123
  readonly required: readonly ["id", "created_at", "updated_at", "old_type", "new_type", "is_locked", "tag_id", "creator_id"];
@@ -4055,7 +4198,7 @@ export declare const TakedownSchema: {
4055
4198
  };
4056
4199
  export declare const ThumbnailPostSchema: {
4057
4200
  readonly type: "object";
4058
- readonly required: readonly ["id", "created_at", "md5", "file_ext", "width", "height", "size", "preview_url", "preview_webp", "sample_url", "file_url", "preview_width", "preview_height", "uploader_id", "uploader", "score", "fav_count", "is_favorited", "vote", "comment_count", "flags", "pools", "rating", "tags"];
4201
+ readonly required: readonly ["id", "created_at", "md5", "file_ext", "width", "height", "size", "duration", "preview_url", "preview_webp", "sample_url", "file_url", "preview_width", "preview_height", "uploader_id", "uploader", "score", "fav_count", "is_favorited", "vote", "comment_count", "flags", "pools", "rating", "tags"];
4059
4202
  readonly properties: {
4060
4203
  readonly id: {
4061
4204
  readonly type: "integer";
@@ -4080,6 +4223,10 @@ export declare const ThumbnailPostSchema: {
4080
4223
  readonly type: "integer";
4081
4224
  readonly format: "int64";
4082
4225
  };
4226
+ readonly duration: {
4227
+ readonly type: "number";
4228
+ readonly nullable: true;
4229
+ };
4083
4230
  readonly preview_url: {
4084
4231
  readonly type: "string";
4085
4232
  readonly format: "uri";
@@ -4210,7 +4357,7 @@ export declare const TrackedSearchTrendSchema: {
4210
4357
  };
4211
4358
  export declare const UploadSchema: {
4212
4359
  readonly type: "object";
4213
- readonly required: readonly ["id", "source", "rating", "uploader_id", "tag_string", "status", "backtrace", "post_id", "md5_confirmation", "created_at", "updated_at", "parent_id", "md5", "file_ext", "file_size", "image_width", "image_height", "description", "uploader_name"];
4360
+ readonly required: readonly ["id", "source", "rating", "uploader_id", "tag_string", "status", "post_id", "created_at", "updated_at", "parent_id", "md5", "file_ext", "file_size", "image_width", "image_height", "description", "processing_step", "error_message", "warning_messages", "is_animated", "duration", "has_sound", "locked_tags", "locked_rating", "as_pending", "submitted_tag_string", "processing_started_at", "processed_at", "requeued_at", "uploader_name", "duplicate_post_id"];
4214
4361
  readonly properties: {
4215
4362
  readonly id: {
4216
4363
  readonly type: "integer";
@@ -4229,12 +4376,13 @@ export declare const UploadSchema: {
4229
4376
  };
4230
4377
  readonly status: {
4231
4378
  readonly type: "string";
4232
- readonly description: "Note: The \"error\" status will be proceeded by an error, ex: \"error: RuntimeError - No file or source URL provided\"\n";
4233
- readonly enum: readonly ["completed", "duplicate", "error", "processing", "pending"];
4379
+ readonly description: "Note: The \"duplicate\" status will be followed by the duplicate post's id, ex: \"duplicate: 123\"\n";
4380
+ readonly enum: readonly ["completed", "duplicate", "failed", "processing", "queued", "pending"];
4234
4381
  };
4235
4382
  readonly backtrace: {
4236
4383
  readonly type: "string";
4237
4384
  readonly nullable: true;
4385
+ readonly description: "Only visible to Staff+.";
4238
4386
  };
4239
4387
  readonly post_id: {
4240
4388
  readonly type: "integer";
@@ -4244,6 +4392,7 @@ export declare const UploadSchema: {
4244
4392
  readonly type: "string";
4245
4393
  readonly nullable: true;
4246
4394
  readonly deprecated: true;
4395
+ readonly description: "Only visible to Staff+.";
4247
4396
  };
4248
4397
  readonly created_at: {
4249
4398
  readonly type: "string";
@@ -4280,9 +4429,68 @@ export declare const UploadSchema: {
4280
4429
  readonly description: {
4281
4430
  readonly type: "string";
4282
4431
  };
4432
+ readonly processing_step: {
4433
+ readonly type: "string";
4434
+ readonly nullable: true;
4435
+ readonly description: "The step currently being processed.";
4436
+ readonly enum: readonly ["integrity", "thumbnail", "sound", "post", null];
4437
+ };
4438
+ readonly error_message: {
4439
+ readonly type: "string";
4440
+ readonly nullable: true;
4441
+ };
4442
+ readonly warning_messages: {
4443
+ readonly type: "array";
4444
+ readonly items: {
4445
+ readonly type: "string";
4446
+ };
4447
+ };
4448
+ readonly is_animated: {
4449
+ readonly type: "boolean";
4450
+ };
4451
+ readonly duration: {
4452
+ readonly type: "string";
4453
+ readonly nullable: true;
4454
+ };
4455
+ readonly has_sound: {
4456
+ readonly type: "boolean";
4457
+ };
4458
+ readonly locked_tags: {
4459
+ readonly type: "string";
4460
+ readonly nullable: true;
4461
+ };
4462
+ readonly locked_rating: {
4463
+ readonly type: "boolean";
4464
+ };
4465
+ readonly as_pending: {
4466
+ readonly type: "boolean";
4467
+ };
4468
+ readonly submitted_tag_string: {
4469
+ readonly type: "string";
4470
+ readonly nullable: true;
4471
+ };
4472
+ readonly processing_started_at: {
4473
+ readonly type: "string";
4474
+ readonly format: "date-time";
4475
+ readonly nullable: true;
4476
+ };
4477
+ readonly processed_at: {
4478
+ readonly type: "string";
4479
+ readonly format: "date-time";
4480
+ readonly nullable: true;
4481
+ };
4482
+ readonly requeued_at: {
4483
+ readonly type: "string";
4484
+ readonly format: "date-time";
4485
+ readonly nullable: true;
4486
+ };
4283
4487
  readonly uploader_name: {
4284
4488
  readonly type: "string";
4285
4489
  };
4490
+ readonly duplicate_post_id: {
4491
+ readonly type: "integer";
4492
+ readonly nullable: true;
4493
+ };
4286
4494
  };
4287
4495
  };
4288
4496
  export declare const UploadWhitelistSchema: {
@@ -4726,7 +4934,8 @@ export declare const AccessDeniedResponseSchema: {
4726
4934
  };
4727
4935
  readonly reason: {
4728
4936
  readonly type: "string";
4729
- readonly enum: readonly ["Access Denied"];
4937
+ readonly description: "Usually `Access Denied`, but may include more detail, ex: `Access Denied: Must be logged in`.";
4938
+ readonly example: "Access Denied";
4730
4939
  };
4731
4940
  };
4732
4941
  };