e621 3.4.1 → 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 (58) hide show
  1. package/README.md +23 -0
  2. package/dist/browser/e621.js +919 -190
  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 +169 -8
  9. package/dist/lib/generated/schemas.js +215 -13
  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 +880 -245
  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/SavedSearch.d.ts +37 -0
  17. package/dist/lib/models/SavedSearch.js +55 -0
  18. package/dist/lib/models/TagSubscription.d.ts +25 -0
  19. package/dist/lib/models/TagSubscription.js +36 -0
  20. package/dist/lib/models/Takedown.d.ts +13 -2
  21. package/dist/lib/models/Takedown.js +21 -2
  22. package/dist/lib/models/User.d.ts +1 -1
  23. package/dist/lib/models/UserNameChangeRequest.d.ts +1 -1
  24. package/dist/lib/models/index.d.ts +2 -0
  25. package/dist/lib/models/index.js +3 -1
  26. package/dist/lib/models/posts/Actions.d.ts +6 -6
  27. package/dist/lib/modules/Artists.d.ts +2 -0
  28. package/dist/lib/modules/Artists.js +3 -1
  29. package/dist/lib/modules/Base.js +4 -2
  30. package/dist/lib/modules/DText.d.ts +2 -3
  31. package/dist/lib/modules/DText.js +5 -6
  32. package/dist/lib/modules/PostVersions.d.ts +2 -1
  33. package/dist/lib/modules/PostVersions.js +3 -2
  34. package/dist/lib/modules/Posts.d.ts +6 -6
  35. package/dist/lib/modules/Posts.js +8 -14
  36. package/dist/lib/modules/SavedSearches.d.ts +94 -0
  37. package/dist/lib/modules/SavedSearches.js +162 -0
  38. package/dist/lib/modules/SearchTrendBlacklists.js +1 -1
  39. package/dist/lib/modules/StaffUsers.d.ts +1 -1
  40. package/dist/lib/modules/StaffUsers.js +4 -2
  41. package/dist/lib/modules/TagAliases.d.ts +1 -1
  42. package/dist/lib/modules/TagAliases.js +3 -2
  43. package/dist/lib/modules/TagImplications.d.ts +1 -1
  44. package/dist/lib/modules/TagImplications.js +3 -2
  45. package/dist/lib/modules/TagSubscriptions.d.ts +49 -0
  46. package/dist/lib/modules/TagSubscriptions.js +82 -0
  47. package/dist/lib/modules/Takedowns.d.ts +16 -2
  48. package/dist/lib/modules/Takedowns.js +25 -3
  49. package/dist/lib/modules/Uploads.d.ts +29 -2
  50. package/dist/lib/modules/Uploads.js +47 -11
  51. package/dist/lib/modules/UserNameChangeRequests.d.ts +2 -2
  52. package/dist/lib/modules/UserNameChangeRequests.js +5 -3
  53. package/dist/lib/modules/index.d.ts +6 -0
  54. package/dist/lib/modules/index.js +5 -1
  55. package/dist/lib/standalone.d.ts +1 -1
  56. package/dist/lib/version.d.ts +1 -1
  57. package/dist/lib/version.js +1 -1
  58. 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: {
@@ -2985,7 +3006,7 @@ export declare const PostStatsScoreSchema: {
2985
3006
  };
2986
3007
  export declare const PostVersionSchema: {
2987
3008
  readonly type: "object";
2988
- 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"];
2989
3010
  readonly properties: {
2990
3011
  readonly id: {
2991
3012
  readonly type: "integer";
@@ -3036,6 +3057,13 @@ export declare const PostVersionSchema: {
3036
3057
  readonly type: "string";
3037
3058
  };
3038
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
+ };
3039
3067
  readonly added_locked_tags: {
3040
3068
  readonly type: "array";
3041
3069
  readonly items: {
@@ -3338,6 +3366,51 @@ export declare const RisingSearchTrendSchema: {
3338
3366
  };
3339
3367
  };
3340
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
+ };
3341
3414
  export declare const SearchTrendSchema: {
3342
3415
  readonly type: "object";
3343
3416
  readonly required: readonly ["tag", "count", "day"];
@@ -4023,6 +4096,28 @@ export declare const TagPreviewSchema: {
4023
4096
  };
4024
4097
  };
4025
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
+ };
4026
4121
  export declare const TagTypeVersionSchema: {
4027
4122
  readonly type: "object";
4028
4123
  readonly required: readonly ["id", "created_at", "updated_at", "old_type", "new_type", "is_locked", "tag_id", "creator_id"];
@@ -4103,7 +4198,7 @@ export declare const TakedownSchema: {
4103
4198
  };
4104
4199
  export declare const ThumbnailPostSchema: {
4105
4200
  readonly type: "object";
4106
- 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"];
4107
4202
  readonly properties: {
4108
4203
  readonly id: {
4109
4204
  readonly type: "integer";
@@ -4128,6 +4223,10 @@ export declare const ThumbnailPostSchema: {
4128
4223
  readonly type: "integer";
4129
4224
  readonly format: "int64";
4130
4225
  };
4226
+ readonly duration: {
4227
+ readonly type: "number";
4228
+ readonly nullable: true;
4229
+ };
4131
4230
  readonly preview_url: {
4132
4231
  readonly type: "string";
4133
4232
  readonly format: "uri";
@@ -4258,7 +4357,7 @@ export declare const TrackedSearchTrendSchema: {
4258
4357
  };
4259
4358
  export declare const UploadSchema: {
4260
4359
  readonly type: "object";
4261
- 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"];
4262
4361
  readonly properties: {
4263
4362
  readonly id: {
4264
4363
  readonly type: "integer";
@@ -4277,12 +4376,13 @@ export declare const UploadSchema: {
4277
4376
  };
4278
4377
  readonly status: {
4279
4378
  readonly type: "string";
4280
- readonly description: "Note: The \"error\" status will be proceeded by an error, ex: \"error: RuntimeError - No file or source URL provided\"\n";
4281
- 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"];
4282
4381
  };
4283
4382
  readonly backtrace: {
4284
4383
  readonly type: "string";
4285
4384
  readonly nullable: true;
4385
+ readonly description: "Only visible to Staff+.";
4286
4386
  };
4287
4387
  readonly post_id: {
4288
4388
  readonly type: "integer";
@@ -4292,6 +4392,7 @@ export declare const UploadSchema: {
4292
4392
  readonly type: "string";
4293
4393
  readonly nullable: true;
4294
4394
  readonly deprecated: true;
4395
+ readonly description: "Only visible to Staff+.";
4295
4396
  };
4296
4397
  readonly created_at: {
4297
4398
  readonly type: "string";
@@ -4328,9 +4429,68 @@ export declare const UploadSchema: {
4328
4429
  readonly description: {
4329
4430
  readonly type: "string";
4330
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
+ };
4331
4487
  readonly uploader_name: {
4332
4488
  readonly type: "string";
4333
4489
  };
4490
+ readonly duplicate_post_id: {
4491
+ readonly type: "integer";
4492
+ readonly nullable: true;
4493
+ };
4334
4494
  };
4335
4495
  };
4336
4496
  export declare const UploadWhitelistSchema: {
@@ -4774,7 +4934,8 @@ export declare const AccessDeniedResponseSchema: {
4774
4934
  };
4775
4935
  readonly reason: {
4776
4936
  readonly type: "string";
4777
- 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";
4778
4939
  };
4779
4940
  };
4780
4941
  };