e621 3.4.1 → 3.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +56 -0
  2. package/dist/browser/e621.js +1191 -252
  3. package/dist/browser/e621.js.map +4 -4
  4. package/dist/lib/OAuthClient.d.ts +152 -0
  5. package/dist/lib/OAuthClient.js +223 -0
  6. package/dist/lib/client.d.ts +75 -1
  7. package/dist/lib/client.js +61 -29
  8. package/dist/lib/errors.d.ts +26 -0
  9. package/dist/lib/errors.js +50 -2
  10. package/dist/lib/generated/schemas.d.ts +169 -8
  11. package/dist/lib/generated/schemas.js +215 -13
  12. package/dist/lib/generated/sdk.d.ts +77 -7
  13. package/dist/lib/generated/sdk.js +134 -9
  14. package/dist/lib/generated/types.d.ts +880 -245
  15. package/dist/lib/index.d.ts +3 -1
  16. package/dist/lib/index.js +2 -1
  17. package/dist/lib/models/Artist.d.ts +1 -0
  18. package/dist/lib/models/Artist.js +2 -1
  19. package/dist/lib/models/SavedSearch.d.ts +37 -0
  20. package/dist/lib/models/SavedSearch.js +55 -0
  21. package/dist/lib/models/TagSubscription.d.ts +25 -0
  22. package/dist/lib/models/TagSubscription.js +36 -0
  23. package/dist/lib/models/Takedown.d.ts +13 -2
  24. package/dist/lib/models/Takedown.js +21 -2
  25. package/dist/lib/models/User.d.ts +1 -1
  26. package/dist/lib/models/UserNameChangeRequest.d.ts +1 -1
  27. package/dist/lib/models/index.d.ts +2 -0
  28. package/dist/lib/models/index.js +3 -1
  29. package/dist/lib/models/posts/Actions.d.ts +6 -6
  30. package/dist/lib/modules/Artists.d.ts +2 -0
  31. package/dist/lib/modules/Artists.js +3 -1
  32. package/dist/lib/modules/Base.js +4 -2
  33. package/dist/lib/modules/DText.d.ts +2 -3
  34. package/dist/lib/modules/DText.js +5 -6
  35. package/dist/lib/modules/PostVersions.d.ts +2 -1
  36. package/dist/lib/modules/PostVersions.js +3 -2
  37. package/dist/lib/modules/Posts.d.ts +6 -6
  38. package/dist/lib/modules/Posts.js +8 -14
  39. package/dist/lib/modules/SavedSearches.d.ts +94 -0
  40. package/dist/lib/modules/SavedSearches.js +162 -0
  41. package/dist/lib/modules/SearchTrendBlacklists.js +1 -1
  42. package/dist/lib/modules/StaffUsers.d.ts +1 -1
  43. package/dist/lib/modules/StaffUsers.js +4 -2
  44. package/dist/lib/modules/TagAliases.d.ts +1 -1
  45. package/dist/lib/modules/TagAliases.js +3 -2
  46. package/dist/lib/modules/TagImplications.d.ts +1 -1
  47. package/dist/lib/modules/TagImplications.js +3 -2
  48. package/dist/lib/modules/TagSubscriptions.d.ts +49 -0
  49. package/dist/lib/modules/TagSubscriptions.js +82 -0
  50. package/dist/lib/modules/Takedowns.d.ts +16 -2
  51. package/dist/lib/modules/Takedowns.js +25 -3
  52. package/dist/lib/modules/Uploads.d.ts +29 -2
  53. package/dist/lib/modules/Uploads.js +47 -11
  54. package/dist/lib/modules/UserNameChangeRequests.d.ts +2 -2
  55. package/dist/lib/modules/UserNameChangeRequests.js +5 -3
  56. package/dist/lib/modules/index.d.ts +6 -0
  57. package/dist/lib/modules/index.js +5 -1
  58. package/dist/lib/standalone.d.ts +1 -1
  59. package/dist/lib/version.d.ts +1 -1
  60. package/dist/lib/version.js +1 -1
  61. package/package.json +5 -1
@@ -8,6 +8,85 @@ var __export = (target, all) => {
8
8
  function Debug(_namespace, _formatter, ..._args) {
9
9
  }
10
10
 
11
+ // dist/lib/errors.js
12
+ function parseRetryAfter(response) {
13
+ const header = response?.headers.get("Retry-After");
14
+ if (!header)
15
+ return null;
16
+ const seconds = Number(header);
17
+ if (!Number.isNaN(seconds))
18
+ return Math.max(0, seconds);
19
+ const timestamp = Date.parse(header);
20
+ return Number.isNaN(timestamp) ? null : Math.max(0, Math.round((timestamp - Date.now()) / 1e3));
21
+ }
22
+ var UnexpectedResponseError = class extends Error {
23
+ error;
24
+ name = "UnexpectedResponseError";
25
+ request;
26
+ response;
27
+ constructor(request, response, error) {
28
+ let message = response ? `Unexpected ${response.status} ${response.statusText} on ${request?.method ?? "?"} ${request?.url ?? response.url}` : request ? `Network error on ${request.method} ${request.url}` : "Network error while building the request";
29
+ if (error) {
30
+ if (typeof error === "string")
31
+ message += `
32
+ ${error}`;
33
+ else if (error instanceof Error)
34
+ message += `
35
+ ${error.message}`;
36
+ else if (typeof error === "object" && error !== null) {
37
+ if ("message" in error && typeof error.message === "string")
38
+ message += `
39
+ ${error.message}`;
40
+ else if ("error" in error && typeof error.error === "string") {
41
+ message += `
42
+ ${error.error}`;
43
+ if ("error_description" in error && typeof error.error_description === "string")
44
+ message += `: ${error.error_description}`;
45
+ } else if ("errors" in error && typeof error.errors === "object" && error.errors !== null) {
46
+ for (const [key, value] of Object.entries(error.errors)) {
47
+ if (typeof value === "string")
48
+ message += `
49
+ ${key}: ${value}`;
50
+ else if (Array.isArray(value))
51
+ message += `
52
+ ${key}: ${value.join(", ")}`;
53
+ }
54
+ }
55
+ }
56
+ }
57
+ super(message);
58
+ Object.defineProperties(this, {
59
+ request: { value: request, enumerable: false },
60
+ response: { value: response, enumerable: false },
61
+ error: { value: error, enumerable: false }
62
+ });
63
+ }
64
+ };
65
+ var RatelimitError = class extends UnexpectedResponseError {
66
+ name = "RatelimitError";
67
+ /** Seconds to wait before retrying, parsed from the response's `Retry-After` header - `null` if it was missing or unparsable. */
68
+ retryAfter;
69
+ constructor(request, response, error) {
70
+ super(request, response, error);
71
+ this.retryAfter = parseRetryAfter(response);
72
+ this.message = this.message.replace("Unexpected", "Ratelimited") + (this.retryAfter === null ? "" : `
73
+ Retry after ${this.retryAfter}s`);
74
+ }
75
+ };
76
+ var OAuthCallbackError = class extends Error {
77
+ /** The OAuth error code, e.g. `access_denied`. */
78
+ error;
79
+ errorDescription;
80
+ name = "OAuthCallbackError";
81
+ state;
82
+ constructor(error, errorDescription, state) {
83
+ super(errorDescription ? `${error}: ${errorDescription}` : error);
84
+ this.error = error;
85
+ this.errorDescription = errorDescription;
86
+ this.state = state;
87
+ }
88
+ };
89
+
11
90
  // dist/lib/generated/core/serverSentEvents.js
12
91
  function createSseClient({ onRequest, onSseError, onSseEvent, responseTransformer, responseValidator, sseDefaultRetryDelay, sseMaxRetryAttempts, sseMaxRetryDelay, sseSleepFn, url, ...options }) {
13
92
  let lastEventId;
@@ -787,21 +866,38 @@ var createClient = (config = {}) => {
787
866
  };
788
867
 
789
868
  // dist/lib/version.js
790
- var VERSION = "3.4.1";
869
+ var VERSION = "3.5.1";
791
870
 
792
871
  // dist/lib/client.js
793
872
  function createE621Client(options) {
794
873
  const resolved = {
795
874
  authKey: options?.authKey ?? null,
875
+ authToken: options?.authToken ?? null,
796
876
  authUser: options?.authUser ?? null,
797
877
  baseURL: options?.baseURL ?? "https://e621.net",
878
+ ratelimit: {
879
+ maxRetries: options?.ratelimit?.maxRetries ?? 3,
880
+ maxRetryDelay: options?.ratelimit?.maxRetryDelay ?? 60,
881
+ onRatelimit: options?.ratelimit?.onRatelimit,
882
+ retry: options?.ratelimit?.retry ?? true,
883
+ retryDelay: options?.ratelimit?.retryDelay ?? 1
884
+ },
798
885
  requestTimeout: options?.requestTimeout ?? 30,
799
886
  statusCheckURL: options?.statusCheckURL ?? "https://status.e621.church/json",
800
887
  userAgent: options?.userAgent ?? `E621/${VERSION} (https://github.com/DonovanDMC/E621${options?.authUser ? `; "${options.authUser}"` : ""})`,
801
888
  userAgentInQuery: options?.userAgentInQuery ?? "window" in globalThis
802
889
  };
803
- let config;
804
- const commonConfig = {
890
+ const getAuthorization = async () => {
891
+ if (resolved.authToken) {
892
+ const token = typeof resolved.authToken === "function" ? await resolved.authToken() : resolved.authToken;
893
+ if (token)
894
+ return `Bearer ${token}`;
895
+ }
896
+ if (resolved.authKey && resolved.authUser)
897
+ return `Basic ${btoa(`${resolved.authUser}:${resolved.authKey}`)}`;
898
+ return null;
899
+ };
900
+ const config = createConfig({
805
901
  baseUrl: resolved.baseURL,
806
902
  headers: resolved.userAgentInQuery ? void 0 : {
807
903
  "User-Agent": resolved.userAgent
@@ -811,19 +907,21 @@ function createE621Client(options) {
811
907
  if (input instanceof Request) {
812
908
  url = input.url;
813
909
  method = input.method.toLowerCase();
814
- if (!input.headers.has("Auithorization") && resolved.authKey && resolved.authUser) {
815
- input.headers.set("Authorization", `Basic ${btoa(`${resolved.authUser}:${resolved.authKey}`)}`);
910
+ if (!input.headers.has("Authorization")) {
911
+ const authorization = await getAuthorization();
912
+ if (authorization)
913
+ input.headers.set("Authorization", authorization);
816
914
  }
817
915
  } else if (init) {
818
916
  url = input.toString();
819
917
  method = init.method?.toLowerCase() ?? "get";
820
- if (resolved.authKey && resolved.authUser) {
821
- const headers = new Headers(init.headers);
822
- if (!headers.has("Authorization")) {
823
- headers.set("Authorization", `Basic ${btoa(`${resolved.authUser}:${resolved.authKey}`)}`);
824
- }
825
- init.headers = headers;
918
+ const headers = new Headers(init.headers);
919
+ if (!headers.has("Authorization")) {
920
+ const authorization = await getAuthorization();
921
+ if (authorization)
922
+ headers.set("Authorization", authorization);
826
923
  }
924
+ init.headers = headers;
827
925
  }
828
926
  if (resolved.userAgentInQuery && input instanceof Request) {
829
927
  const requestURL = new URL(input.url);
@@ -832,24 +930,34 @@ function createE621Client(options) {
832
930
  url = requestURL.toString();
833
931
  }
834
932
  Debug(`request:${method}`, `-> ${url}`);
835
- const res = await fetch(input, init);
836
- Debug(`response:${method}`, `<- ${url} ${res.status} ${res.statusText}`);
933
+ let attempt = 0, res;
934
+ for (; ; ) {
935
+ res = await fetch(input instanceof Request ? input.clone() : input, init);
936
+ Debug(`response:${method}`, `<- ${url} ${res.status} ${res.statusText}`);
937
+ if (res.status !== 429)
938
+ break;
939
+ const retryAfter = parseRetryAfter(res);
940
+ const willRetry = resolved.ratelimit.retry && attempt < resolved.ratelimit.maxRetries;
941
+ resolved.ratelimit.onRatelimit?.({
942
+ attempt: attempt + 1,
943
+ maxRetries: resolved.ratelimit.maxRetries,
944
+ request: input instanceof Request ? input : new Request(url, init),
945
+ response: res,
946
+ retryAfter,
947
+ willRetry
948
+ });
949
+ if (!willRetry)
950
+ break;
951
+ const delay = Math.min(retryAfter ?? resolved.ratelimit.retryDelay * 2 ** attempt, resolved.ratelimit.maxRetryDelay);
952
+ Debug(`response:${method}`, `<- ${url} ratelimited, retrying in ${delay}s (attempt ${attempt + 1}/${resolved.ratelimit.maxRetries})`);
953
+ await res.body?.cancel().catch(() => {
954
+ });
955
+ await new Promise((resolve) => setTimeout(resolve, delay * 1e3));
956
+ attempt++;
957
+ }
837
958
  return res;
838
959
  }
839
- };
840
- if (resolved.authKey && resolved.authUser) {
841
- config = createConfig({
842
- ...commonConfig,
843
- auth: (auth) => {
844
- if (auth.scheme === "basic") {
845
- return `${resolved.authUser}:${resolved.authKey}`;
846
- }
847
- return;
848
- }
849
- });
850
- } else {
851
- config = createConfig(commonConfig);
852
- }
960
+ });
853
961
  return { client: createClient(config), options: resolved };
854
962
  }
855
963
 
@@ -1058,6 +1166,13 @@ __export(sdk_exports, {
1058
1166
  posts_updateIqdb: () => posts_updateIqdb,
1059
1167
  railsHealth_show: () => railsHealth_show,
1060
1168
  relatedTags_bulk: () => relatedTags_bulk,
1169
+ savedSearches_badge: () => savedSearches_badge,
1170
+ savedSearches_create: () => savedSearches_create,
1171
+ savedSearches_destroy: () => savedSearches_destroy,
1172
+ savedSearches_index: () => savedSearches_index,
1173
+ savedSearches_markAllSeen: () => savedSearches_markAllSeen,
1174
+ savedSearches_show: () => savedSearches_show,
1175
+ savedSearches_update: () => savedSearches_update,
1061
1176
  searchTrendBlacklists_create: () => searchTrendBlacklists_create,
1062
1177
  searchTrendBlacklists_destroy: () => searchTrendBlacklists_destroy,
1063
1178
  searchTrendBlacklists_index: () => searchTrendBlacklists_index,
@@ -1150,6 +1265,9 @@ __export(sdk_exports, {
1150
1265
  tagImplications_show: () => tagImplications_show,
1151
1266
  tagImplications_undo: () => tagImplications_undo,
1152
1267
  tagImplications_update: () => tagImplications_update,
1268
+ tagSubscriptions_create: () => tagSubscriptions_create,
1269
+ tagSubscriptions_destroy: () => tagSubscriptions_destroy,
1270
+ tagSubscriptions_index: () => tagSubscriptions_index,
1153
1271
  tagTypeVersions_index: () => tagTypeVersions_index,
1154
1272
  tags_destroy: () => tags_destroy,
1155
1273
  tags_index: () => tags_index,
@@ -1158,6 +1276,7 @@ __export(sdk_exports, {
1158
1276
  tags_update: () => tags_update,
1159
1277
  takedowns_addByIds: () => takedowns_addByIds,
1160
1278
  takedowns_addByTags: () => takedowns_addByTags,
1279
+ takedowns_clearPosts: () => takedowns_clearPosts,
1161
1280
  takedowns_countMatchingPosts: () => takedowns_countMatchingPosts,
1162
1281
  takedowns_create: () => takedowns_create,
1163
1282
  takedowns_destroy: () => takedowns_destroy,
@@ -1793,11 +1912,7 @@ var dmails_markAllAsRead = (options) => (options?.client ?? client).put({
1793
1912
  });
1794
1913
  var dtextPreviews_create = (options) => (options?.client ?? client).post({
1795
1914
  ...urlSearchParamsBodySerializer,
1796
- security: [{ scheme: "basic", type: "http" }, {
1797
- in: "query",
1798
- name: "authenticity_token",
1799
- type: "apiKey"
1800
- }],
1915
+ security: [{ scheme: "basic", type: "http" }],
1801
1916
  url: "/dtext_preview.json",
1802
1917
  ...options,
1803
1918
  headers: {
@@ -2411,6 +2526,51 @@ var postVotes_delete = (options) => (options.client ?? client).post({
2411
2526
  url: "/post_votes/delete.json",
2412
2527
  ...options
2413
2528
  });
2529
+ var savedSearches_index = (options) => (options?.client ?? client).get({
2530
+ security: [{ scheme: "basic", type: "http" }],
2531
+ url: "/saved_searches.json",
2532
+ ...options
2533
+ });
2534
+ var savedSearches_create = (options) => (options?.client ?? client).post({
2535
+ ...urlSearchParamsBodySerializer,
2536
+ security: [{ scheme: "basic", type: "http" }],
2537
+ url: "/saved_searches.json",
2538
+ ...options,
2539
+ headers: {
2540
+ "Content-Type": "application/x-www-form-urlencoded",
2541
+ ...options?.headers
2542
+ }
2543
+ });
2544
+ var savedSearches_destroy = (options) => (options.client ?? client).delete({
2545
+ security: [{ scheme: "basic", type: "http" }],
2546
+ url: "/saved_searches/{id}.json",
2547
+ ...options
2548
+ });
2549
+ var savedSearches_show = (options) => (options.client ?? client).get({
2550
+ security: [{ scheme: "basic", type: "http" }],
2551
+ url: "/saved_searches/{id}.json",
2552
+ ...options
2553
+ });
2554
+ var savedSearches_update = (options) => (options.client ?? client).patch({
2555
+ ...urlSearchParamsBodySerializer,
2556
+ security: [{ scheme: "basic", type: "http" }],
2557
+ url: "/saved_searches/{id}.json",
2558
+ ...options,
2559
+ headers: {
2560
+ "Content-Type": "application/x-www-form-urlencoded",
2561
+ ...options.headers
2562
+ }
2563
+ });
2564
+ var savedSearches_markAllSeen = (options) => (options?.client ?? client).post({
2565
+ security: [{ scheme: "basic", type: "http" }],
2566
+ url: "/saved_searches/mark_all_seen.json",
2567
+ ...options
2568
+ });
2569
+ var savedSearches_badge = (options) => (options?.client ?? client).get({
2570
+ security: [{ scheme: "basic", type: "http" }],
2571
+ url: "/saved_searches/badge.json",
2572
+ ...options
2573
+ });
2414
2574
  var tags_index = (options) => (options?.client ?? client).get({ url: "/tags.json", ...options });
2415
2575
  var tags_destroy = (options) => (options.client ?? client).delete({
2416
2576
  security: [{ scheme: "basic", type: "http" }],
@@ -2524,6 +2684,26 @@ var tagImplicationRequests_create = (options) => (options?.client ?? client).pos
2524
2684
  ...options?.headers
2525
2685
  }
2526
2686
  });
2687
+ var tagSubscriptions_index = (options) => (options?.client ?? client).get({
2688
+ security: [{ scheme: "basic", type: "http" }],
2689
+ url: "/tag_subscriptions.json",
2690
+ ...options
2691
+ });
2692
+ var tagSubscriptions_create = (options) => (options?.client ?? client).post({
2693
+ ...urlSearchParamsBodySerializer,
2694
+ security: [{ scheme: "basic", type: "http" }],
2695
+ url: "/tag_subscriptions.json",
2696
+ ...options,
2697
+ headers: {
2698
+ "Content-Type": "application/x-www-form-urlencoded",
2699
+ ...options?.headers
2700
+ }
2701
+ });
2702
+ var tagSubscriptions_destroy = (options) => (options.client ?? client).delete({
2703
+ security: [{ scheme: "basic", type: "http" }],
2704
+ url: "/tag_subscriptions/{id}.json",
2705
+ ...options
2706
+ });
2527
2707
  var relatedTags_bulk = (options) => (options?.client ?? client).post({
2528
2708
  ...urlSearchParamsBodySerializer,
2529
2709
  security: [{ scheme: "basic", type: "http" }],
@@ -2733,6 +2913,11 @@ var takedowns_removeByIds = (options) => (options.client ?? client).post({
2733
2913
  ...options.headers
2734
2914
  }
2735
2915
  });
2916
+ var takedowns_clearPosts = (options) => (options.client ?? client).post({
2917
+ security: [{ scheme: "basic", type: "http" }],
2918
+ url: "/takedowns/{id}/clear_posts.json",
2919
+ ...options
2920
+ });
2736
2921
  var tickets_index = (options) => (options?.client ?? client).get({ url: "/tickets.json", ...options });
2737
2922
  var tickets_show = (options) => (options.client ?? client).get({
2738
2923
  security: [{ scheme: "basic", type: "http" }],
@@ -3487,49 +3672,6 @@ Appeal = __decorate([
3487
3672
  ], Appeal);
3488
3673
  var Appeal_default = Appeal;
3489
3674
 
3490
- // dist/lib/errors.js
3491
- var UnexpectedResponseError = class extends Error {
3492
- error;
3493
- name = "UnexpectedResponseError";
3494
- request;
3495
- response;
3496
- constructor(request, response, error) {
3497
- let message = response ? `Unexpected ${response.status} ${response.statusText} on ${request?.method ?? "?"} ${request?.url ?? response.url}` : request ? `Network error on ${request.method} ${request.url}` : "Network error while building the request";
3498
- if (error) {
3499
- if (typeof error === "string")
3500
- message += `
3501
- ${error}`;
3502
- else if (error instanceof Error)
3503
- message += `
3504
- ${error.message}`;
3505
- else if (typeof error === "object" && error !== null) {
3506
- if ("message" in error && typeof error.message === "string")
3507
- message += `
3508
- ${error.message}`;
3509
- else if ("error" in error && typeof error.error === "string")
3510
- message += `
3511
- ${error.error}`;
3512
- else if ("errors" in error && typeof error.errors === "object" && error.errors !== null) {
3513
- for (const [key, value] of Object.entries(error.errors)) {
3514
- if (typeof value === "string")
3515
- message += `
3516
- ${key}: ${value}`;
3517
- else if (Array.isArray(value))
3518
- message += `
3519
- ${key}: ${value.join(", ")}`;
3520
- }
3521
- }
3522
- }
3523
- }
3524
- super(message);
3525
- Object.defineProperties(this, {
3526
- request: { value: request, enumerable: false },
3527
- response: { value: response, enumerable: false },
3528
- error: { value: error, enumerable: false }
3529
- });
3530
- }
3531
- };
3532
-
3533
3675
  // dist/lib/modules/Base.js
3534
3676
  var Base2 = class {
3535
3677
  client;
@@ -3566,6 +3708,8 @@ var Base2 = class {
3566
3708
  }
3567
3709
  } else if (res.response?.status === 404 && !throwOnNotFound)
3568
3710
  return null;
3711
+ else if (res.response?.status === 429)
3712
+ throw new RatelimitError(res.request, res.response, res.error);
3569
3713
  else
3570
3714
  throw new UnexpectedResponseError(res.request, res.response, res.error);
3571
3715
  }
@@ -3728,6 +3872,7 @@ var Artist = class Artist2 extends Base {
3728
3872
  `other_names` & `urls` are silently truncated to 25 entries.
3729
3873
  `notes` is silently truncated to the wiki page limit (250,000).
3730
3874
  Individual `other_names` are silently truncated to 100 characters.
3875
+ Individual `urls` cannot be longer than 512 characters.
3731
3876
  If an artist is on the avoid posting list, you must have the bd staff user flag to edit name, other_names, or group_name.
3732
3877
 
3733
3878
  *
@@ -3772,6 +3917,7 @@ var Artists = class extends Base2 {
3772
3917
  * `other_names` & `urls` are silently truncated to 25 entries.
3773
3918
  `notes` is silently truncated to the wiki page limit (250,000).
3774
3919
  Individual `other_names` are silently truncated to 100 characters.
3920
+ Individual `urls` cannot be longer than 512 characters.
3775
3921
 
3776
3922
  *
3777
3923
  * @requiresApiKeyAuth
@@ -3851,6 +3997,7 @@ var Artists = class extends Base2 {
3851
3997
  `other_names` & `urls` are silently truncated to 25 entries.
3852
3998
  `notes` is silently truncated to the wiki page limit (250,000).
3853
3999
  Individual `other_names` are silently truncated to 100 characters.
4000
+ Individual `urls` cannot be longer than 512 characters.
3854
4001
  If an artist is on the avoid posting list, you must have the bd staff user flag to edit name, other_names, or group_name.
3855
4002
 
3856
4003
  *
@@ -8118,7 +8265,7 @@ var Posts = class extends Base2 {
8118
8265
  client: this.client,
8119
8266
  path: { id },
8120
8267
  body: options
8121
- }).then((res) => this._handleResponse(res, 200, true));
8268
+ }).then((res) => this._handleResponse(res, 201, true));
8122
8269
  }
8123
8270
  /**
8124
8271
  *
@@ -8135,10 +8282,7 @@ var Posts = class extends Base2 {
8135
8282
  client: this.client,
8136
8283
  path: { id },
8137
8284
  body: { reason }
8138
- }).then((res) => {
8139
- const data = this._handleResponse(res, 201, true);
8140
- return new Post_default(this.e621, data.post);
8141
- });
8285
+ }).then((res) => this._handleResponse(res, 201, true));
8142
8286
  }
8143
8287
  /**
8144
8288
  *
@@ -8213,8 +8357,9 @@ var Posts = class extends Base2 {
8213
8357
  return staffPostPosts_moveFavorites({
8214
8358
  client: this.client,
8215
8359
  path: { id },
8216
- body: options
8217
- }).then((res) => this._handleResponse(res, 200, true));
8360
+ body: options,
8361
+ redirect: "manual"
8362
+ }).then((res) => this._handleResponse(res, 302, true));
8218
8363
  }
8219
8364
  /**
8220
8365
  *
@@ -8331,9 +8476,9 @@ var Posts = class extends Base2 {
8331
8476
  return staffPostPosts_reowner({
8332
8477
  client: this.client,
8333
8478
  path: { id },
8334
- body: prefixKeys(options, "reowner"),
8335
- redirect: "manual"
8336
- }).then((res) => this._handleResponse(res, 302, true));
8479
+ body: prefixKeys(options, "reowner")
8480
+ // 204 means the post already belonged to the new owner
8481
+ }).then((res) => res.response?.status === 204 ? null : this._handleResponse(res, 201, true));
8337
8482
  }
8338
8483
  /**
8339
8484
  *
@@ -8405,10 +8550,7 @@ var Posts = class extends Base2 {
8405
8550
  return staffPostPosts_undelete({
8406
8551
  client: this.client,
8407
8552
  path: { id }
8408
- }).then((res) => {
8409
- const data = this._handleResponse(res, 201, true);
8410
- return new Post_default(this.e621, data.post);
8411
- });
8553
+ }).then((res) => this._handleResponse(res, 201, true));
8412
8554
  }
8413
8555
  /**
8414
8556
  *
@@ -8916,9 +9058,8 @@ __decorate([
8916
9058
  __metadata("design:returntype", Promise)
8917
9059
  ], PostSets.prototype, "updatePosts", null);
8918
9060
 
8919
- // dist/lib/modules/PostVersions.js
8920
- var PostVersions = class extends Base2 {
8921
- static moduleKey = "postVersions";
9061
+ // dist/lib/models/PostVersion.js
9062
+ var PostVersion = class PostVersion2 extends Base {
8922
9063
  /**
8923
9064
  *
8924
9065
  * You must be Admin+.
@@ -8929,23 +9070,19 @@ var PostVersions = class extends Base2 {
8929
9070
  *
8930
9071
  * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#hide Documentation} for more details.
8931
9072
  */
8932
- async hide(id) {
8933
- return postVersions_hide({
8934
- client: this.client,
8935
- path: { id }
8936
- }).then((res) => this._handleResponse(res, 302, true));
9073
+ async hide() {
9074
+ return this.e621.postVersions.hide(this.id);
8937
9075
  }
8938
9076
  /**
8939
9077
  *
8940
- * @operationId {@link https://e621.wiki/#operations-Post_Versions-post_versions\#index post_versions#index}
9078
+ * @requiresApiKeyAuth
8941
9079
  *
8942
- * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#index Documentation} for more details.
9080
+ * @operationId {@link https://e621.wiki/#operations-Posts-posts\#revert posts#revert}
9081
+ *
9082
+ * @see {@link https://e621.wiki/#operations-Posts-posts\#revert Documentation} for more details.
8943
9083
  */
8944
- async search(options) {
8945
- return postVersions_index({
8946
- client: this.client,
8947
- query: prefixKeys(options, "search", ["limit", "page"])
8948
- }).then((res) => this._handleResponse(res, 204, true));
9084
+ async revertTo() {
9085
+ return this.e621.posts.revert(this.post_id, this.id);
8949
9086
  }
8950
9087
  /**
8951
9088
  *
@@ -8955,11 +9092,8 @@ var PostVersions = class extends Base2 {
8955
9092
  *
8956
9093
  * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#undo Documentation} for more details.
8957
9094
  */
8958
- async undo(id) {
8959
- return postVersions_undo({
8960
- client: this.client,
8961
- path: { id }
8962
- }).then((res) => this._handleResponse(res, 204, true));
9095
+ async undo() {
9096
+ return this.e621.postVersions.undo(this.id);
8963
9097
  }
8964
9098
  /**
8965
9099
  *
@@ -8971,54 +9105,142 @@ var PostVersions = class extends Base2 {
8971
9105
  *
8972
9106
  * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#unhide Documentation} for more details.
8973
9107
  */
8974
- async unhide(id) {
8975
- return postVersions_unhide({
8976
- client: this.client,
8977
- path: { id }
8978
- }).then((res) => this._handleResponse(res, 302, true));
9108
+ async unhide() {
9109
+ return this.e621.postVersions.unhide(this.id);
8979
9110
  }
8980
9111
  };
8981
9112
  __decorate([
8982
9113
  OperationID("post_versions#hide"),
8983
9114
  __metadata("design:type", Function),
8984
- __metadata("design:paramtypes", [Number]),
9115
+ __metadata("design:paramtypes", []),
8985
9116
  __metadata("design:returntype", Promise)
8986
- ], PostVersions.prototype, "hide", null);
9117
+ ], PostVersion.prototype, "hide", null);
8987
9118
  __decorate([
8988
- OperationID("post_versions#index"),
9119
+ OperationID("posts#revert"),
8989
9120
  __metadata("design:type", Function),
8990
- __metadata("design:paramtypes", [Object]),
9121
+ __metadata("design:paramtypes", []),
8991
9122
  __metadata("design:returntype", Promise)
8992
- ], PostVersions.prototype, "search", null);
9123
+ ], PostVersion.prototype, "revertTo", null);
8993
9124
  __decorate([
8994
9125
  OperationID("post_versions#undo"),
8995
9126
  __metadata("design:type", Function),
8996
- __metadata("design:paramtypes", [Number]),
9127
+ __metadata("design:paramtypes", []),
8997
9128
  __metadata("design:returntype", Promise)
8998
- ], PostVersions.prototype, "undo", null);
9129
+ ], PostVersion.prototype, "undo", null);
8999
9130
  __decorate([
9000
9131
  OperationID("post_versions#unhide"),
9001
9132
  __metadata("design:type", Function),
9002
- __metadata("design:paramtypes", [Number]),
9133
+ __metadata("design:paramtypes", []),
9003
9134
  __metadata("design:returntype", Promise)
9004
- ], PostVersions.prototype, "unhide", null);
9135
+ ], PostVersion.prototype, "unhide", null);
9136
+ PostVersion = __decorate([
9137
+ Schema("PostVersion")
9138
+ ], PostVersion);
9139
+ var PostVersion_default = PostVersion;
9005
9140
 
9006
- // dist/lib/models/SearchTrendBlacklist.js
9007
- var SearchTrendBlacklist = class SearchTrendBlacklist2 extends Base {
9141
+ // dist/lib/modules/PostVersions.js
9142
+ var PostVersions = class extends Base2 {
9143
+ static moduleKey = "postVersions";
9008
9144
  /**
9009
9145
  *
9010
9146
  * You must be Admin+.
9011
9147
  *
9012
9148
  * @requiresApiKeyAuth
9013
9149
  *
9014
- * @operationId {@link https://e621.wiki/#operations-Search_Trend_Blacklists-search_trend_blacklists\#destroy search_trend_blacklists#destroy}
9150
+ * @operationId {@link https://e621.wiki/#operations-Post_Versions-post_versions\#hide post_versions#hide}
9015
9151
  *
9016
- * @see {@link https://e621.wiki/#operations-Search_Trend_Blacklists-search_trend_blacklists\#destroy Documentation} for more details.
9152
+ * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#hide Documentation} for more details.
9017
9153
  */
9018
- async delete() {
9019
- return this.e621.searchTrendBlacklists.delete(this.id);
9020
- }
9021
- /**
9154
+ async hide(id) {
9155
+ return postVersions_hide({
9156
+ client: this.client,
9157
+ path: { id }
9158
+ }).then((res) => this._handleResponse(res, 302, true));
9159
+ }
9160
+ /**
9161
+ *
9162
+ * @operationId {@link https://e621.wiki/#operations-Post_Versions-post_versions\#index post_versions#index}
9163
+ *
9164
+ * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#index Documentation} for more details.
9165
+ */
9166
+ async search(options) {
9167
+ return postVersions_index({
9168
+ client: this.client,
9169
+ query: prefixKeys(options, "search", ["limit", "page"])
9170
+ }).then((res) => this._handleResponse(res, 200, true, PostVersion_default));
9171
+ }
9172
+ /**
9173
+ *
9174
+ * @requiresApiKeyAuth
9175
+ *
9176
+ * @operationId {@link https://e621.wiki/#operations-Post_Versions-post_versions\#undo post_versions#undo}
9177
+ *
9178
+ * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#undo Documentation} for more details.
9179
+ */
9180
+ async undo(id) {
9181
+ return postVersions_undo({
9182
+ client: this.client,
9183
+ path: { id }
9184
+ }).then((res) => this._handleResponse(res, 204, true));
9185
+ }
9186
+ /**
9187
+ *
9188
+ * You must be Admin+.
9189
+ *
9190
+ * @requiresApiKeyAuth
9191
+ *
9192
+ * @operationId {@link https://e621.wiki/#operations-Post_Versions-post_versions\#unhide post_versions#unhide}
9193
+ *
9194
+ * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#unhide Documentation} for more details.
9195
+ */
9196
+ async unhide(id) {
9197
+ return postVersions_unhide({
9198
+ client: this.client,
9199
+ path: { id }
9200
+ }).then((res) => this._handleResponse(res, 302, true));
9201
+ }
9202
+ };
9203
+ __decorate([
9204
+ OperationID("post_versions#hide"),
9205
+ __metadata("design:type", Function),
9206
+ __metadata("design:paramtypes", [Number]),
9207
+ __metadata("design:returntype", Promise)
9208
+ ], PostVersions.prototype, "hide", null);
9209
+ __decorate([
9210
+ OperationID("post_versions#index"),
9211
+ __metadata("design:type", Function),
9212
+ __metadata("design:paramtypes", [Object]),
9213
+ __metadata("design:returntype", Promise)
9214
+ ], PostVersions.prototype, "search", null);
9215
+ __decorate([
9216
+ OperationID("post_versions#undo"),
9217
+ __metadata("design:type", Function),
9218
+ __metadata("design:paramtypes", [Number]),
9219
+ __metadata("design:returntype", Promise)
9220
+ ], PostVersions.prototype, "undo", null);
9221
+ __decorate([
9222
+ OperationID("post_versions#unhide"),
9223
+ __metadata("design:type", Function),
9224
+ __metadata("design:paramtypes", [Number]),
9225
+ __metadata("design:returntype", Promise)
9226
+ ], PostVersions.prototype, "unhide", null);
9227
+
9228
+ // dist/lib/models/SearchTrendBlacklist.js
9229
+ var SearchTrendBlacklist = class SearchTrendBlacklist2 extends Base {
9230
+ /**
9231
+ *
9232
+ * You must be Admin+.
9233
+ *
9234
+ * @requiresApiKeyAuth
9235
+ *
9236
+ * @operationId {@link https://e621.wiki/#operations-Search_Trend_Blacklists-search_trend_blacklists\#destroy search_trend_blacklists#destroy}
9237
+ *
9238
+ * @see {@link https://e621.wiki/#operations-Search_Trend_Blacklists-search_trend_blacklists\#destroy Documentation} for more details.
9239
+ */
9240
+ async delete() {
9241
+ return this.e621.searchTrendBlacklists.delete(this.id);
9242
+ }
9243
+ /**
9022
9244
  *
9023
9245
  * You must be Admin+.
9024
9246
  *
@@ -9066,7 +9288,7 @@ var SearchTrendBlacklists = class extends Base2 {
9066
9288
  return searchTrendBlacklists_create({
9067
9289
  client: this.client,
9068
9290
  body: prefixKeys(options, "search_trend_blacklist")
9069
- }).then((res) => this._handleResponse(res, 200, true, SearchTrendBlacklist_default));
9291
+ }).then((res) => this._handleResponse(res, 201, true, SearchTrendBlacklist_default));
9070
9292
  }
9071
9293
  /**
9072
9294
  *
@@ -9701,7 +9923,20 @@ var Takedown = class Takedown2 extends Base {
9701
9923
  }
9702
9924
  /**
9703
9925
  *
9704
- * You must have the bd staff user flag.
9926
+ * You must have the bd staff user flag. Removes all posts from the takedown.
9927
+ *
9928
+ * @requiresApiKeyAuth
9929
+ *
9930
+ * @operationId {@link https://e621.wiki/#operations-Takedowns-takedowns\#clear_posts takedowns#clear_posts}
9931
+ *
9932
+ * @see {@link https://e621.wiki/#operations-Takedowns-takedowns\#clear_posts Documentation} for more details.
9933
+ */
9934
+ async clearPosts() {
9935
+ return this.e621.takedowns.clearPosts(this.id);
9936
+ }
9937
+ /**
9938
+ *
9939
+ * You must have the bd staff user flag. Deleted posts are not counted.
9705
9940
  *
9706
9941
  * @requiresApiKeyAuth
9707
9942
  *
@@ -9764,6 +9999,12 @@ __decorate([
9764
9999
  __metadata("design:paramtypes", [Array]),
9765
10000
  __metadata("design:returntype", Promise)
9766
10001
  ], Takedown.prototype, "addByTags", null);
10002
+ __decorate([
10003
+ OperationID("takedowns#clear_posts"),
10004
+ __metadata("design:type", Function),
10005
+ __metadata("design:paramtypes", []),
10006
+ __metadata("design:returntype", Promise)
10007
+ ], Takedown.prototype, "clearPosts", null);
9767
10008
  __decorate([
9768
10009
  OperationID("takedowns#count_matching_posts"),
9769
10010
  __metadata("design:type", Function),
@@ -9832,7 +10073,23 @@ var Takedowns = class extends Base2 {
9832
10073
  }
9833
10074
  /**
9834
10075
  *
9835
- * You must have the bd staff user flag.
10076
+ * You must have the bd staff user flag. Removes all posts from the takedown.
10077
+ *
10078
+ * @requiresApiKeyAuth
10079
+ *
10080
+ * @operationId {@link https://e621.wiki/#operations-Takedowns-takedowns\#clear_posts takedowns#clear_posts}
10081
+ *
10082
+ * @see {@link https://e621.wiki/#operations-Takedowns-takedowns\#clear_posts Documentation} for more details.
10083
+ */
10084
+ async clearPosts(id) {
10085
+ return takedowns_clearPosts({
10086
+ client: this.client,
10087
+ path: { id }
10088
+ }).then((res) => this._handleResponse(res, 200, true));
10089
+ }
10090
+ /**
10091
+ *
10092
+ * You must have the bd staff user flag. Deleted posts are not counted.
9836
10093
  *
9837
10094
  * @requiresApiKeyAuth
9838
10095
  *
@@ -9948,6 +10205,12 @@ __decorate([
9948
10205
  __metadata("design:paramtypes", [Number, Array]),
9949
10206
  __metadata("design:returntype", Promise)
9950
10207
  ], Takedowns.prototype, "addByTags", null);
10208
+ __decorate([
10209
+ OperationID("takedowns#clear_posts"),
10210
+ __metadata("design:type", Function),
10211
+ __metadata("design:paramtypes", [Number]),
10212
+ __metadata("design:returntype", Promise)
10213
+ ], Takedowns.prototype, "clearPosts", null);
9951
10214
  __decorate([
9952
10215
  OperationID("takedowns#count_matching_posts"),
9953
10216
  __metadata("design:type", Function),
@@ -10210,6 +10473,8 @@ var Upload_default = Upload;
10210
10473
  var Uploads = class extends Base2 {
10211
10474
  static moduleKey = "uploads";
10212
10475
  /**
10476
+ *
10477
+ * Uploads are processed asynchronously, if the upload isn't finished right away this waits for it (see {@link Uploads.wait}).
10213
10478
  *
10214
10479
  * @requiresApiKeyAuth
10215
10480
  *
@@ -10217,22 +10482,22 @@ var Uploads = class extends Base2 {
10217
10482
  *
10218
10483
  * @see {@link https://e621.wiki/#operations-Uploads-uploads\#create Documentation} for more details.
10219
10484
  */
10220
- async create(options) {
10485
+ async create(options, waitOptions) {
10221
10486
  return uploads_create({
10222
10487
  client: this.client,
10223
10488
  body: prefixKeys(options, "upload")
10224
- }).then((res) => {
10489
+ }).then(async (res) => {
10225
10490
  const data = this._handleResponse(res, 200, true);
10226
- return this.e621.posts.get(data.post_id).then((post) => {
10227
- if (post === null)
10228
- throw new Error(`Post not found after upload: ${data.post_id}`);
10229
- return post;
10230
- });
10491
+ const postID = data.post_id ?? (await this.wait(data.upload_id, waitOptions)).post_id;
10492
+ const post = await this.e621.posts.get(postID);
10493
+ if (post === null)
10494
+ throw new Error(`Post not found after upload: ${postID}`);
10495
+ return post;
10231
10496
  });
10232
10497
  }
10233
10498
  /**
10234
10499
  *
10235
- * You must be Staff+.
10500
+ * You must be the uploader, or Staff+. Can be polled while an upload is processing.
10236
10501
  *
10237
10502
  * @operationId {@link https://e621.wiki/#operations-Uploads-uploads\#show uploads#show}
10238
10503
  *
@@ -10256,11 +10521,40 @@ var Uploads = class extends Base2 {
10256
10521
  query: prefixKeys(options, "search", ["limit", "page"])
10257
10522
  }).then((res) => this._handleResponse(res, 200, true, Upload_default));
10258
10523
  }
10524
+ /**
10525
+ * Waits for an upload to finish processing. Throws if it fails, turns out to be a duplicate, or doesn't finish within the timeout.
10526
+ */
10527
+ /**
10528
+ *
10529
+ * You must be the uploader, or Staff+. Can be polled while an upload is processing.
10530
+ *
10531
+ * @operationId {@link https://e621.wiki/#operations-Uploads-uploads\#show uploads#show}
10532
+ *
10533
+ * @see {@link https://e621.wiki/#operations-Uploads-uploads\#show Documentation} for more details.
10534
+ */
10535
+ async wait(id, options) {
10536
+ const interval = (options?.interval ?? 2) * 1e3;
10537
+ const deadline = Date.now() + (options?.timeout ?? 300) * 1e3;
10538
+ for (; ; ) {
10539
+ const upload = await this.get(id);
10540
+ if (upload === null)
10541
+ throw new Error(`Upload not found: ${id}`);
10542
+ if (upload.status === "completed" && upload.post_id !== null)
10543
+ return upload;
10544
+ if (upload.status === "failed")
10545
+ throw new Error(`Upload ${id} failed: ${upload.error_message ?? "unknown error"}`);
10546
+ if (upload.status.startsWith("duplicate"))
10547
+ throw new Error(`Upload ${id} is a duplicate of post #${upload.duplicate_post_id}`);
10548
+ if (Date.now() + interval > deadline)
10549
+ throw new Error(`Upload ${id} did not finish processing in time (status: ${upload.status})`);
10550
+ await new Promise((resolve) => setTimeout(resolve, interval));
10551
+ }
10552
+ }
10259
10553
  };
10260
10554
  __decorate([
10261
10555
  OperationID("uploads#create"),
10262
10556
  __metadata("design:type", Function),
10263
- __metadata("design:paramtypes", [Object]),
10557
+ __metadata("design:paramtypes", [Object, Object]),
10264
10558
  __metadata("design:returntype", Promise)
10265
10559
  ], Uploads.prototype, "create", null);
10266
10560
  __decorate([
@@ -10275,6 +10569,12 @@ __decorate([
10275
10569
  __metadata("design:paramtypes", [Object]),
10276
10570
  __metadata("design:returntype", Promise)
10277
10571
  ], Uploads.prototype, "search", null);
10572
+ __decorate([
10573
+ OperationID("uploads#show"),
10574
+ __metadata("design:type", Function),
10575
+ __metadata("design:paramtypes", [Number, Object]),
10576
+ __metadata("design:returntype", Promise)
10577
+ ], Uploads.prototype, "wait", null);
10278
10578
 
10279
10579
  // dist/lib/models/UploadWhitelist.js
10280
10580
  var UploadWhitelist = class UploadWhitelist2 extends Base {
@@ -11317,8 +11617,9 @@ var UserNameChangeRequests = class extends Base2 {
11317
11617
  async create(options) {
11318
11618
  return userNameChangeRequests_create({
11319
11619
  client: this.client,
11320
- body: prefixKeys(options, "user_name_change_request")
11321
- }).then((res) => this._handleResponse(res, 200, true));
11620
+ body: prefixKeys(options, "user_name_change_request"),
11621
+ redirect: "manual"
11622
+ }).then((res) => this._handleResponse(res, 302, true));
11322
11623
  }
11323
11624
  /**
11324
11625
  *
@@ -11333,8 +11634,9 @@ var UserNameChangeRequests = class extends Base2 {
11333
11634
  async delete(id) {
11334
11635
  return userNameChangeRequests_destroy({
11335
11636
  client: this.client,
11336
- path: { id }
11337
- }).then((res) => this._handleResponse(res, 200, true));
11637
+ path: { id },
11638
+ redirect: "manual"
11639
+ }).then((res) => this._handleResponse(res, 302, true));
11338
11640
  }
11339
11641
  /**
11340
11642
  *
@@ -11834,26 +12136,25 @@ var DText = class extends Base2 {
11834
12136
  static moduleKey = "dtext";
11835
12137
  /**
11836
12138
  *
11837
- * Note while this route does not require auth, without auth it requires a CSRF token. For that reason it has been marked as requiring auth.
12139
+ * Limited to 20 requests per minute.
11838
12140
  *
11839
12141
  * @requiresApiKeyAuth
11840
- * @requiresCsrfToken
11841
12142
  *
11842
12143
  * @operationId {@link https://e621.wiki/#operations-DText-dtext_previews\#create dtext_previews#create}
11843
12144
  *
11844
12145
  * @see {@link https://e621.wiki/#operations-DText-dtext_previews\#create Documentation} for more details.
11845
12146
  */
11846
- async preview(body) {
12147
+ async preview(body, allow_color) {
11847
12148
  return dtextPreviews_create({
11848
12149
  client: this.client,
11849
- body: { body }
12150
+ body: { body, allow_color }
11850
12151
  }).then((res) => this._handleResponse(res, 200, true));
11851
12152
  }
11852
12153
  };
11853
12154
  __decorate([
11854
12155
  OperationID("dtext_previews#create"),
11855
12156
  __metadata("design:type", Function),
11856
- __metadata("design:paramtypes", [String]),
12157
+ __metadata("design:paramtypes", [String, Boolean]),
11857
12158
  __metadata("design:returntype", Promise)
11858
12159
  ], DText.prototype, "preview", null);
11859
12160
 
@@ -12643,8 +12944,9 @@ var TagAliases = class extends Base2 {
12643
12944
  async create(options) {
12644
12945
  return tagAliasRequests_create({
12645
12946
  client: this.client,
12646
- body: prefixKeys(options, "tag_alias_request")
12647
- }).then((res) => this._handleResponse(res, 200, true));
12947
+ body: prefixKeys(options, "tag_alias_request"),
12948
+ redirect: "manual"
12949
+ }).then((res) => this._handleResponse(res, 302, true));
12648
12950
  }
12649
12951
  /**
12650
12952
  *
@@ -12917,8 +13219,9 @@ var TagImplications = class extends Base2 {
12917
13219
  async create(options) {
12918
13220
  return tagImplicationRequests_create({
12919
13221
  client: this.client,
12920
- body: prefixKeys(options, "tag_implication_request")
12921
- }).then((res) => this._handleResponse(res, 200, true));
13222
+ body: prefixKeys(options, "tag_implication_request"),
13223
+ redirect: "manual"
13224
+ }).then((res) => this._handleResponse(res, 302, true));
12922
13225
  }
12923
13226
  /**
12924
13227
  *
@@ -13879,8 +14182,10 @@ var StaffUsers = class extends Base2 {
13879
14182
  return staffUsers_update({
13880
14183
  client: this.client,
13881
14184
  path: { id },
13882
- body: prefixKeys(options, "user")
13883
- }).then((res) => this._handleResponse(res, 204, true));
14185
+ body: prefixKeys(options, "user"),
14186
+ // the spec says 200, but that's only after following the redirect
14187
+ redirect: "manual"
14188
+ }).then((res) => this._handleResponse(res, 302, true));
13884
14189
  }
13885
14190
  /**
13886
14191
  *
@@ -14512,6 +14817,209 @@ __decorate([
14512
14817
  __metadata("design:returntype", Promise)
14513
14818
  ], SearchTrendHourlies.prototype, "search", null);
14514
14819
 
14820
+ // dist/lib/models/SavedSearch.js
14821
+ var SavedSearch = class SavedSearch2 extends Base {
14822
+ /**
14823
+ *
14824
+ * You must be the owner of the saved search.
14825
+ *
14826
+ * @requiresApiKeyAuth
14827
+ *
14828
+ * @operationId {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#destroy saved_searches#destroy}
14829
+ *
14830
+ * @see {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#destroy Documentation} for more details.
14831
+ */
14832
+ async delete() {
14833
+ return this.e621.savedSearches.delete(this.id);
14834
+ }
14835
+ /**
14836
+ *
14837
+ * You must be the owner of the saved search. The subscription search cannot be updated.
14838
+ *
14839
+ * @requiresApiKeyAuth
14840
+ *
14841
+ * @operationId {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#update saved_searches#update}
14842
+ *
14843
+ * @see {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#update Documentation} for more details.
14844
+ */
14845
+ async update(options) {
14846
+ return this.e621.savedSearches.update(this.id, options);
14847
+ }
14848
+ };
14849
+ __decorate([
14850
+ OperationID("saved_searches#destroy"),
14851
+ __metadata("design:type", Function),
14852
+ __metadata("design:paramtypes", []),
14853
+ __metadata("design:returntype", Promise)
14854
+ ], SavedSearch.prototype, "delete", null);
14855
+ __decorate([
14856
+ OperationID("saved_searches#update"),
14857
+ __metadata("design:type", Function),
14858
+ __metadata("design:paramtypes", [Object]),
14859
+ __metadata("design:returntype", Promise)
14860
+ ], SavedSearch.prototype, "update", null);
14861
+ SavedSearch = __decorate([
14862
+ Schema("SavedSearch")
14863
+ ], SavedSearch);
14864
+ var SavedSearch_default = SavedSearch;
14865
+
14866
+ // dist/lib/modules/SavedSearches.js
14867
+ var SavedSearches = class extends Base2 {
14868
+ static moduleKey = "savedSearches";
14869
+ /**
14870
+ *
14871
+ * Total new post count across the current user's tracked saved searches. Read from cache only.
14872
+ *
14873
+ * @requiresApiKeyAuth
14874
+ *
14875
+ * @operationId {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#badge saved_searches#badge}
14876
+ *
14877
+ * @see {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#badge Documentation} for more details.
14878
+ */
14879
+ async badge() {
14880
+ return savedSearches_badge({
14881
+ client: this.client
14882
+ }).then((res) => this._handleResponse(res, 200, true));
14883
+ }
14884
+ /**
14885
+ *
14886
+ * Users can have up to 250 saved searches, and track up to 50 of them.
14887
+ Saved search queries cannot contain wildcard tags or `search:` metatags.
14888
+
14889
+ *
14890
+ * @requiresApiKeyAuth
14891
+ *
14892
+ * @operationId {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#create saved_searches#create}
14893
+ *
14894
+ * @see {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#create Documentation} for more details.
14895
+ */
14896
+ async create(options) {
14897
+ return savedSearches_create({
14898
+ client: this.client,
14899
+ body: prefixKeys(options, "saved_search")
14900
+ }).then((res) => this._handleResponse(res, 200, true, SavedSearch_default));
14901
+ }
14902
+ /**
14903
+ *
14904
+ * You must be the owner of the saved search.
14905
+ *
14906
+ * @requiresApiKeyAuth
14907
+ *
14908
+ * @operationId {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#destroy saved_searches#destroy}
14909
+ *
14910
+ * @see {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#destroy Documentation} for more details.
14911
+ */
14912
+ async delete(id) {
14913
+ return savedSearches_destroy({
14914
+ client: this.client,
14915
+ path: { id }
14916
+ }).then((res) => this._handleResponse(res, 204, true));
14917
+ }
14918
+ /**
14919
+ *
14920
+ * You must be the owner of the saved search. `new_count` is read from cache and may be stale.
14921
+ *
14922
+ * @requiresApiKeyAuth
14923
+ *
14924
+ * @operationId {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#show saved_searches#show}
14925
+ *
14926
+ * @see {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#show Documentation} for more details.
14927
+ */
14928
+ async get(id) {
14929
+ return savedSearches_show({
14930
+ client: this.client,
14931
+ path: { id }
14932
+ }).then((res) => this._handleResponse(res, 200, false, SavedSearch_default));
14933
+ }
14934
+ /**
14935
+ *
14936
+ * Lists the current user's saved searches. New post counts are refreshed when this is called.
14937
+ *
14938
+ * @requiresApiKeyAuth
14939
+ *
14940
+ * @operationId {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#index saved_searches#index}
14941
+ *
14942
+ * @see {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#index Documentation} for more details.
14943
+ */
14944
+ async list() {
14945
+ return savedSearches_index({
14946
+ client: this.client
14947
+ }).then((res) => this._handleResponse(res, 200, true, SavedSearch_default));
14948
+ }
14949
+ /**
14950
+ *
14951
+ * @requiresApiKeyAuth
14952
+ *
14953
+ * @operationId {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#mark_all_seen saved_searches#mark_all_seen}
14954
+ *
14955
+ * @see {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#mark_all_seen Documentation} for more details.
14956
+ */
14957
+ async markAllSeen() {
14958
+ return savedSearches_markAllSeen({
14959
+ client: this.client
14960
+ }).then((res) => this._handleResponse(res, 204, true));
14961
+ }
14962
+ /**
14963
+ *
14964
+ * You must be the owner of the saved search. The subscription search cannot be updated.
14965
+ *
14966
+ * @requiresApiKeyAuth
14967
+ *
14968
+ * @operationId {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#update saved_searches#update}
14969
+ *
14970
+ * @see {@link https://e621.wiki/#operations-Saved_Searches-saved_searches\#update Documentation} for more details.
14971
+ */
14972
+ async update(id, options) {
14973
+ return savedSearches_update({
14974
+ client: this.client,
14975
+ path: { id },
14976
+ body: prefixKeys(options, "saved_search")
14977
+ }).then((res) => this._handleResponse(res, 200, true, SavedSearch_default));
14978
+ }
14979
+ };
14980
+ __decorate([
14981
+ OperationID("saved_searches#badge"),
14982
+ __metadata("design:type", Function),
14983
+ __metadata("design:paramtypes", []),
14984
+ __metadata("design:returntype", Promise)
14985
+ ], SavedSearches.prototype, "badge", null);
14986
+ __decorate([
14987
+ OperationID("saved_searches#create"),
14988
+ __metadata("design:type", Function),
14989
+ __metadata("design:paramtypes", [Object]),
14990
+ __metadata("design:returntype", Promise)
14991
+ ], SavedSearches.prototype, "create", null);
14992
+ __decorate([
14993
+ OperationID("saved_searches#destroy"),
14994
+ __metadata("design:type", Function),
14995
+ __metadata("design:paramtypes", [Number]),
14996
+ __metadata("design:returntype", Promise)
14997
+ ], SavedSearches.prototype, "delete", null);
14998
+ __decorate([
14999
+ OperationID("saved_searches#show"),
15000
+ __metadata("design:type", Function),
15001
+ __metadata("design:paramtypes", [Number]),
15002
+ __metadata("design:returntype", Promise)
15003
+ ], SavedSearches.prototype, "get", null);
15004
+ __decorate([
15005
+ OperationID("saved_searches#index"),
15006
+ __metadata("design:type", Function),
15007
+ __metadata("design:paramtypes", []),
15008
+ __metadata("design:returntype", Promise)
15009
+ ], SavedSearches.prototype, "list", null);
15010
+ __decorate([
15011
+ OperationID("saved_searches#mark_all_seen"),
15012
+ __metadata("design:type", Function),
15013
+ __metadata("design:paramtypes", []),
15014
+ __metadata("design:returntype", Promise)
15015
+ ], SavedSearches.prototype, "markAllSeen", null);
15016
+ __decorate([
15017
+ OperationID("saved_searches#update"),
15018
+ __metadata("design:type", Function),
15019
+ __metadata("design:paramtypes", [Number, Object]),
15020
+ __metadata("design:returntype", Promise)
15021
+ ], SavedSearches.prototype, "update", null);
15022
+
14515
15023
  // dist/lib/modules/Sessions.js
14516
15024
  var Sessions = class extends Base2 {
14517
15025
  static moduleKey = "sessions";
@@ -14575,7 +15083,111 @@ __decorate([
14575
15083
  __metadata("design:type", Function),
14576
15084
  __metadata("design:paramtypes", [Object]),
14577
15085
  __metadata("design:returntype", Promise)
14578
- ], Sessions.prototype, "verifyTotp", null);
15086
+ ], Sessions.prototype, "verifyTotp", null);
15087
+
15088
+ // dist/lib/models/TagSubscription.js
15089
+ var TagSubscription = class TagSubscription2 extends Base {
15090
+ /**
15091
+ *
15092
+ * You must be the owner of the tag subscription.
15093
+ *
15094
+ * @requiresApiKeyAuth
15095
+ *
15096
+ * @operationId {@link https://e621.wiki/#operations-Tag_Subscriptions-tag_subscriptions\#destroy tag_subscriptions#destroy}
15097
+ *
15098
+ * @see {@link https://e621.wiki/#operations-Tag_Subscriptions-tag_subscriptions\#destroy Documentation} for more details.
15099
+ */
15100
+ async delete() {
15101
+ return this.e621.tagSubscriptions.delete(this.id);
15102
+ }
15103
+ };
15104
+ __decorate([
15105
+ OperationID("tag_subscriptions#destroy"),
15106
+ __metadata("design:type", Function),
15107
+ __metadata("design:paramtypes", []),
15108
+ __metadata("design:returntype", Promise)
15109
+ ], TagSubscription.prototype, "delete", null);
15110
+ TagSubscription = __decorate([
15111
+ Schema("TagSubscription")
15112
+ ], TagSubscription);
15113
+ var TagSubscription_default = TagSubscription;
15114
+
15115
+ // dist/lib/modules/TagSubscriptions.js
15116
+ var TagSubscriptions = class extends Base2 {
15117
+ static moduleKey = "tagSubscriptions";
15118
+ /**
15119
+ *
15120
+ * Subscribes to one or more tags, following aliases. Users can subscribe to up to 500 tags.
15121
+ Subscribed tags can be searched with the `search:subscriptions` metatag.
15122
+
15123
+ *
15124
+ * Subscribe to one or more tags. Tags that couldn't be subscribed to are listed in `skipped`.
15125
+ *
15126
+ * @requiresApiKeyAuth
15127
+ *
15128
+ * @operationId {@link https://e621.wiki/#operations-Tag_Subscriptions-tag_subscriptions\#create tag_subscriptions#create}
15129
+ *
15130
+ * @see {@link https://e621.wiki/#operations-Tag_Subscriptions-tag_subscriptions\#create Documentation} for more details.
15131
+ */
15132
+ async create(tags) {
15133
+ return tagSubscriptions_create({
15134
+ client: this.client,
15135
+ body: { tag_names: Array.isArray(tags) ? tags.join(" ") : tags }
15136
+ }).then((res) => {
15137
+ const data = this._handleResponse(res, 200, true);
15138
+ return { ...data, added: data.added.map((sub) => new TagSubscription_default(this.e621, sub)) };
15139
+ });
15140
+ }
15141
+ /**
15142
+ *
15143
+ * You must be the owner of the tag subscription.
15144
+ *
15145
+ * @requiresApiKeyAuth
15146
+ *
15147
+ * @operationId {@link https://e621.wiki/#operations-Tag_Subscriptions-tag_subscriptions\#destroy tag_subscriptions#destroy}
15148
+ *
15149
+ * @see {@link https://e621.wiki/#operations-Tag_Subscriptions-tag_subscriptions\#destroy Documentation} for more details.
15150
+ */
15151
+ async delete(id) {
15152
+ return tagSubscriptions_destroy({
15153
+ client: this.client,
15154
+ path: { id }
15155
+ }).then((res) => this._handleResponse(res, 204, true));
15156
+ }
15157
+ /**
15158
+ *
15159
+ * Lists the current user's tag subscriptions, ordered by tag name.
15160
+ *
15161
+ * @requiresApiKeyAuth
15162
+ *
15163
+ * @operationId {@link https://e621.wiki/#operations-Tag_Subscriptions-tag_subscriptions\#index tag_subscriptions#index}
15164
+ *
15165
+ * @see {@link https://e621.wiki/#operations-Tag_Subscriptions-tag_subscriptions\#index Documentation} for more details.
15166
+ */
15167
+ async list() {
15168
+ return tagSubscriptions_index({
15169
+ client: this.client
15170
+ }).then((res) => this._handleResponse(res, 200, true, TagSubscription_default));
15171
+ }
15172
+ };
15173
+ __decorate([
15174
+ OperationID("tag_subscriptions#create"),
15175
+ __metadata("design:type", Function),
15176
+ __metadata("design:paramtypes", [Object]),
15177
+ __metadata("design:returntype", Promise)
15178
+ ], TagSubscriptions.prototype, "create", null);
15179
+ __decorate([
15180
+ OperationID("tag_subscriptions#destroy"),
15181
+ __metadata("design:type", Function),
15182
+ __metadata("design:paramtypes", [Number]),
15183
+ __metadata("design:returntype", Promise)
15184
+ ], TagSubscriptions.prototype, "delete", null);
15185
+ __decorate([
15186
+ OperationID("tag_subscriptions#index"),
15187
+ __metadata("design:type", Function),
15188
+ __metadata("design:paramtypes", []),
15189
+ __metadata("design:returntype", Promise)
15190
+ ], TagSubscriptions.prototype, "list", null);
14579
15191
 
14580
15192
  // dist/lib/modules/StaffIpAddrs.js
14581
15193
  var StaffIpAddrs = class extends Base2 {
@@ -14884,6 +15496,7 @@ function apply(e621, client2, defaultPostFormat = {}) {
14884
15496
  posts: new Posts(e621, client2, defaultPostFormat),
14885
15497
  railsHealth: new RailsHealth(baseE621, client2),
14886
15498
  relatedTags: new RelatedTags(baseE621, client2),
15499
+ savedSearches: new SavedSearches(baseE621, client2),
14887
15500
  searchTrendBlacklists: new SearchTrendBlacklists(baseE621, client2),
14888
15501
  searchTrendHourlies: new SearchTrendHourlies(baseE621, client2),
14889
15502
  searchTrends: new SearchTrends(baseE621, client2),
@@ -14909,6 +15522,7 @@ function apply(e621, client2, defaultPostFormat = {}) {
14909
15522
  tagImplications: new TagImplications(baseE621, client2),
14910
15523
  tagTypeVersions: new TagTypeVersions(baseE621, client2),
14911
15524
  tags: new Tags(baseE621, client2),
15525
+ tagSubscriptions: new TagSubscriptions(baseE621, client2),
14912
15526
  takedowns: new Takedowns(baseE621, client2),
14913
15527
  tickets: new Tickets(baseE621, client2),
14914
15528
  uploadKarmaEvents: new UploadKarmaEvents(baseE621, client2),
@@ -14932,86 +15546,6 @@ APIKey = __decorate([
14932
15546
  ], APIKey);
14933
15547
  var APIKey_default = APIKey;
14934
15548
 
14935
- // dist/lib/models/PostVersion.js
14936
- var PostVersion = class PostVersion2 extends Base {
14937
- /**
14938
- *
14939
- * You must be Admin+.
14940
- *
14941
- * @requiresApiKeyAuth
14942
- *
14943
- * @operationId {@link https://e621.wiki/#operations-Post_Versions-post_versions\#hide post_versions#hide}
14944
- *
14945
- * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#hide Documentation} for more details.
14946
- */
14947
- async hide() {
14948
- return this.e621.postVersions.hide(this.id);
14949
- }
14950
- /**
14951
- *
14952
- * @requiresApiKeyAuth
14953
- *
14954
- * @operationId {@link https://e621.wiki/#operations-Posts-posts\#revert posts#revert}
14955
- *
14956
- * @see {@link https://e621.wiki/#operations-Posts-posts\#revert Documentation} for more details.
14957
- */
14958
- async revertTo() {
14959
- return this.e621.posts.revert(this.post_id, this.id);
14960
- }
14961
- /**
14962
- *
14963
- * @requiresApiKeyAuth
14964
- *
14965
- * @operationId {@link https://e621.wiki/#operations-Post_Versions-post_versions\#undo post_versions#undo}
14966
- *
14967
- * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#undo Documentation} for more details.
14968
- */
14969
- async undo() {
14970
- return this.e621.postVersions.undo(this.id);
14971
- }
14972
- /**
14973
- *
14974
- * You must be Admin+.
14975
- *
14976
- * @requiresApiKeyAuth
14977
- *
14978
- * @operationId {@link https://e621.wiki/#operations-Post_Versions-post_versions\#unhide post_versions#unhide}
14979
- *
14980
- * @see {@link https://e621.wiki/#operations-Post_Versions-post_versions\#unhide Documentation} for more details.
14981
- */
14982
- async unhide() {
14983
- return this.e621.postVersions.unhide(this.id);
14984
- }
14985
- };
14986
- __decorate([
14987
- OperationID("post_versions#hide"),
14988
- __metadata("design:type", Function),
14989
- __metadata("design:paramtypes", []),
14990
- __metadata("design:returntype", Promise)
14991
- ], PostVersion.prototype, "hide", null);
14992
- __decorate([
14993
- OperationID("posts#revert"),
14994
- __metadata("design:type", Function),
14995
- __metadata("design:paramtypes", []),
14996
- __metadata("design:returntype", Promise)
14997
- ], PostVersion.prototype, "revertTo", null);
14998
- __decorate([
14999
- OperationID("post_versions#undo"),
15000
- __metadata("design:type", Function),
15001
- __metadata("design:paramtypes", []),
15002
- __metadata("design:returntype", Promise)
15003
- ], PostVersion.prototype, "undo", null);
15004
- __decorate([
15005
- OperationID("post_versions#unhide"),
15006
- __metadata("design:type", Function),
15007
- __metadata("design:paramtypes", []),
15008
- __metadata("design:returntype", Promise)
15009
- ], PostVersion.prototype, "unhide", null);
15010
- PostVersion = __decorate([
15011
- Schema("PostVersion")
15012
- ], PostVersion);
15013
- var PostVersion_default = PostVersion;
15014
-
15015
15549
  // dist/lib/generated.js
15016
15550
  var generated_exports = {};
15017
15551
  __export(generated_exports, {
@@ -15126,6 +15660,7 @@ __export(schemas_exports, {
15126
15660
  RawPostSchema: () => RawPostSchema,
15127
15661
  RecommendedPostsSchema: () => RecommendedPostsSchema,
15128
15662
  RisingSearchTrendSchema: () => RisingSearchTrendSchema,
15663
+ SavedSearchSchema: () => SavedSearchSchema,
15129
15664
  SearchTrendBlacklistSchema: () => SearchTrendBlacklistSchema,
15130
15665
  SearchTrendHourlySchema: () => SearchTrendHourlySchema,
15131
15666
  SearchTrendSchema: () => SearchTrendSchema,
@@ -15147,6 +15682,7 @@ __export(schemas_exports, {
15147
15682
  TagPreviewSchema: () => TagPreviewSchema,
15148
15683
  TagRequestStatusSchema: () => TagRequestStatusSchema,
15149
15684
  TagSchema: () => TagSchema,
15685
+ TagSubscriptionSchema: () => TagSubscriptionSchema,
15150
15686
  TagTypeVersionSchema: () => TagTypeVersionSchema,
15151
15687
  TagWithCountSchema: () => TagWithCountSchema,
15152
15688
  TakedownSchema: () => TakedownSchema,
@@ -16894,7 +17430,10 @@ var ForumPostSchema = {
16894
17430
  "created_at",
16895
17431
  "updated_at",
16896
17432
  "warning_type",
16897
- "warning_user_id"
17433
+ "warning_user_id",
17434
+ "vote_score",
17435
+ "creator_name",
17436
+ "updater_name"
16898
17437
  ],
16899
17438
  properties: {
16900
17439
  id: {
@@ -16929,6 +17468,17 @@ var ForumPostSchema = {
16929
17468
  warning_user_id: {
16930
17469
  type: "integer",
16931
17470
  nullable: true
17471
+ },
17472
+ vote_score: {
17473
+ type: "string",
17474
+ nullable: true,
17475
+ description: "Net votes divided by total votes, from -1 to 1. Null if the post has never been voted on."
17476
+ },
17477
+ creator_name: {
17478
+ type: "string"
17479
+ },
17480
+ updater_name: {
17481
+ type: "string"
16932
17482
  }
16933
17483
  }
16934
17484
  };
@@ -16982,7 +17532,10 @@ var ForumTopicSchema = {
16982
17532
  "is_hidden",
16983
17533
  "created_at",
16984
17534
  "updated_at",
16985
- "category_id"
17535
+ "category_id",
17536
+ "last_bumped_at",
17537
+ "creator_name",
17538
+ "updater_name"
16986
17539
  ],
16987
17540
  properties: {
16988
17541
  id: {
@@ -17019,6 +17572,16 @@ var ForumTopicSchema = {
17019
17572
  },
17020
17573
  category_id: {
17021
17574
  type: "integer"
17575
+ },
17576
+ last_bumped_at: {
17577
+ type: "string",
17578
+ format: "date-time"
17579
+ },
17580
+ creator_name: {
17581
+ type: "string"
17582
+ },
17583
+ updater_name: {
17584
+ type: "string"
17022
17585
  }
17023
17586
  }
17024
17587
  };
@@ -19285,6 +19848,7 @@ var PostVersionSchema = {
19285
19848
  "locked_tags",
19286
19849
  "added_tags",
19287
19850
  "removed_tags",
19851
+ "original_tags",
19288
19852
  "added_locked_tags",
19289
19853
  "removed_locked_tags",
19290
19854
  "rating_changed",
@@ -19348,6 +19912,13 @@ var PostVersionSchema = {
19348
19912
  type: "string"
19349
19913
  }
19350
19914
  },
19915
+ original_tags: {
19916
+ type: "array",
19917
+ 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:`.",
19918
+ items: {
19919
+ type: "string"
19920
+ }
19921
+ },
19351
19922
  added_locked_tags: {
19352
19923
  type: "array",
19353
19924
  items: {
@@ -19725,6 +20296,61 @@ var RisingSearchTrendSchema = {
19725
20296
  }
19726
20297
  }
19727
20298
  };
20299
+ var SavedSearchSchema = {
20300
+ type: "object",
20301
+ required: [
20302
+ "id",
20303
+ "query",
20304
+ "name",
20305
+ "is_tracked",
20306
+ "is_subscription",
20307
+ "last_seen_post_id",
20308
+ "created_at",
20309
+ "updated_at",
20310
+ "new_count"
20311
+ ],
20312
+ properties: {
20313
+ id: {
20314
+ type: "integer"
20315
+ },
20316
+ query: {
20317
+ type: "string",
20318
+ description: "Empty for the subscription search, its tags are managed through tag subscriptions."
20319
+ },
20320
+ name: {
20321
+ type: "string",
20322
+ nullable: true
20323
+ },
20324
+ is_tracked: {
20325
+ type: "boolean"
20326
+ },
20327
+ is_subscription: {
20328
+ type: "boolean",
20329
+ description: "True for the search that holds the user's tag subscriptions."
20330
+ },
20331
+ last_seen_post_id: {
20332
+ type: "integer",
20333
+ nullable: true
20334
+ },
20335
+ created_at: {
20336
+ type: "string",
20337
+ format: "date-time"
20338
+ },
20339
+ updated_at: {
20340
+ type: "string",
20341
+ format: "date-time"
20342
+ },
20343
+ tag_count: {
20344
+ type: "integer",
20345
+ description: "Only present on the subscription search."
20346
+ },
20347
+ new_count: {
20348
+ type: "integer",
20349
+ nullable: true,
20350
+ 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."
20351
+ }
20352
+ }
20353
+ };
19728
20354
  var SearchTrendSchema = {
19729
20355
  type: "object",
19730
20356
  required: [
@@ -20592,6 +21218,34 @@ var TagPreviewSchema = {
20592
21218
  }
20593
21219
  }
20594
21220
  };
21221
+ var TagSubscriptionSchema = {
21222
+ type: "object",
21223
+ required: [
21224
+ "id",
21225
+ "tag_id",
21226
+ "created_at",
21227
+ "tag_name",
21228
+ "category"
21229
+ ],
21230
+ properties: {
21231
+ id: {
21232
+ type: "integer"
21233
+ },
21234
+ tag_id: {
21235
+ type: "integer"
21236
+ },
21237
+ created_at: {
21238
+ type: "string",
21239
+ format: "date-time"
21240
+ },
21241
+ tag_name: {
21242
+ type: "string"
21243
+ },
21244
+ category: {
21245
+ $ref: "#/components/schemas/TagCategory"
21246
+ }
21247
+ }
21248
+ };
20595
21249
  var TagTypeVersionSchema = {
20596
21250
  type: "object",
20597
21251
  required: [
@@ -20706,6 +21360,7 @@ var ThumbnailPostSchema = {
20706
21360
  "width",
20707
21361
  "height",
20708
21362
  "size",
21363
+ "duration",
20709
21364
  "preview_url",
20710
21365
  "preview_webp",
20711
21366
  "sample_url",
@@ -20748,6 +21403,10 @@ var ThumbnailPostSchema = {
20748
21403
  type: "integer",
20749
21404
  format: "int64"
20750
21405
  },
21406
+ duration: {
21407
+ type: "number",
21408
+ nullable: true
21409
+ },
20751
21410
  preview_url: {
20752
21411
  type: "string",
20753
21412
  format: "uri",
@@ -20901,9 +21560,7 @@ var UploadSchema = {
20901
21560
  "uploader_id",
20902
21561
  "tag_string",
20903
21562
  "status",
20904
- "backtrace",
20905
21563
  "post_id",
20906
- "md5_confirmation",
20907
21564
  "created_at",
20908
21565
  "updated_at",
20909
21566
  "parent_id",
@@ -20913,7 +21570,21 @@ var UploadSchema = {
20913
21570
  "image_width",
20914
21571
  "image_height",
20915
21572
  "description",
20916
- "uploader_name"
21573
+ "processing_step",
21574
+ "error_message",
21575
+ "warning_messages",
21576
+ "is_animated",
21577
+ "duration",
21578
+ "has_sound",
21579
+ "locked_tags",
21580
+ "locked_rating",
21581
+ "as_pending",
21582
+ "submitted_tag_string",
21583
+ "processing_started_at",
21584
+ "processed_at",
21585
+ "requeued_at",
21586
+ "uploader_name",
21587
+ "duplicate_post_id"
20917
21588
  ],
20918
21589
  properties: {
20919
21590
  id: {
@@ -20933,18 +21604,21 @@ var UploadSchema = {
20933
21604
  },
20934
21605
  status: {
20935
21606
  type: "string",
20936
- description: 'Note: The "error" status will be proceeded by an error, ex: "error: RuntimeError - No file or source URL provided"\n',
21607
+ description: `Note: The "duplicate" status will be followed by the duplicate post's id, ex: "duplicate: 123"
21608
+ `,
20937
21609
  enum: [
20938
21610
  "completed",
20939
21611
  "duplicate",
20940
- "error",
21612
+ "failed",
20941
21613
  "processing",
21614
+ "queued",
20942
21615
  "pending"
20943
21616
  ]
20944
21617
  },
20945
21618
  backtrace: {
20946
21619
  type: "string",
20947
- nullable: true
21620
+ nullable: true,
21621
+ description: "Only visible to Staff+."
20948
21622
  },
20949
21623
  post_id: {
20950
21624
  type: "integer",
@@ -20953,7 +21627,8 @@ var UploadSchema = {
20953
21627
  md5_confirmation: {
20954
21628
  type: "string",
20955
21629
  nullable: true,
20956
- deprecated: true
21630
+ deprecated: true,
21631
+ description: "Only visible to Staff+."
20957
21632
  },
20958
21633
  created_at: {
20959
21634
  type: "string",
@@ -20990,8 +21665,73 @@ var UploadSchema = {
20990
21665
  description: {
20991
21666
  type: "string"
20992
21667
  },
21668
+ processing_step: {
21669
+ type: "string",
21670
+ nullable: true,
21671
+ description: "The step currently being processed.",
21672
+ enum: [
21673
+ "integrity",
21674
+ "thumbnail",
21675
+ "sound",
21676
+ "post",
21677
+ null
21678
+ ]
21679
+ },
21680
+ error_message: {
21681
+ type: "string",
21682
+ nullable: true
21683
+ },
21684
+ warning_messages: {
21685
+ type: "array",
21686
+ items: {
21687
+ type: "string"
21688
+ }
21689
+ },
21690
+ is_animated: {
21691
+ type: "boolean"
21692
+ },
21693
+ duration: {
21694
+ type: "string",
21695
+ nullable: true
21696
+ },
21697
+ has_sound: {
21698
+ type: "boolean"
21699
+ },
21700
+ locked_tags: {
21701
+ type: "string",
21702
+ nullable: true
21703
+ },
21704
+ locked_rating: {
21705
+ type: "boolean"
21706
+ },
21707
+ as_pending: {
21708
+ type: "boolean"
21709
+ },
21710
+ submitted_tag_string: {
21711
+ type: "string",
21712
+ nullable: true
21713
+ },
21714
+ processing_started_at: {
21715
+ type: "string",
21716
+ format: "date-time",
21717
+ nullable: true
21718
+ },
21719
+ processed_at: {
21720
+ type: "string",
21721
+ format: "date-time",
21722
+ nullable: true
21723
+ },
21724
+ requeued_at: {
21725
+ type: "string",
21726
+ format: "date-time",
21727
+ nullable: true
21728
+ },
20993
21729
  uploader_name: {
20994
21730
  type: "string"
21731
+ },
21732
+ duplicate_post_id: {
21733
+ type: "integer",
21734
+ nullable: true
20995
21735
  }
20996
21736
  }
20997
21737
  };
@@ -21560,9 +22300,8 @@ var AccessDeniedResponseSchema = {
21560
22300
  },
21561
22301
  reason: {
21562
22302
  type: "string",
21563
- enum: [
21564
- "Access Denied"
21565
- ]
22303
+ description: "Usually `Access Denied`, but may include more detail, ex: `Access Denied: Must be logged in`.",
22304
+ example: "Access Denied"
21566
22305
  }
21567
22306
  }
21568
22307
  };
@@ -21715,6 +22454,200 @@ var OAuthErrorSchema = {
21715
22454
  }
21716
22455
  };
21717
22456
 
22457
+ // dist/lib/OAuthClient.js
22458
+ function base64URL(bytes) {
22459
+ let str = "";
22460
+ for (const byte of bytes)
22461
+ str += String.fromCharCode(byte);
22462
+ return btoa(str).replaceAll("+", "-").replaceAll("/", "_").replace(/=+$/, "");
22463
+ }
22464
+ function randomString(byteLength = 32) {
22465
+ return base64URL(crypto.getRandomValues(new Uint8Array(byteLength)));
22466
+ }
22467
+ var OAuthClient = class _OAuthClient {
22468
+ _clientSecret;
22469
+ _discovery;
22470
+ _onToken;
22471
+ _refreshing;
22472
+ _token;
22473
+ _tokenInfo;
22474
+ _tokens;
22475
+ _userinfo;
22476
+ baseURL;
22477
+ clientId;
22478
+ redirectURI;
22479
+ refreshLeeway;
22480
+ scopes;
22481
+ constructor(options) {
22482
+ const { clientId, clientSecret, onToken, redirectURI, refreshLeeway, scopes, token, ...clientOptions } = options;
22483
+ this.clientId = clientId;
22484
+ this.redirectURI = redirectURI ?? null;
22485
+ this.refreshLeeway = refreshLeeway ?? 60;
22486
+ this.scopes = scopes ?? [];
22487
+ const { client: client2, options: resolved } = createE621Client(clientOptions);
22488
+ const { client: authedClient } = createE621Client({ ...clientOptions, authToken: () => this.getAccessToken() });
22489
+ this.baseURL = resolved.baseURL;
22490
+ Object.defineProperties(this, {
22491
+ _clientSecret: { value: clientSecret ?? null, enumerable: false },
22492
+ _discovery: { value: new DoorkeeperOpenidConnectDiscovery(void 0, client2), enumerable: false },
22493
+ _onToken: { value: onToken, enumerable: false },
22494
+ _refreshing: { value: null, writable: true, enumerable: false },
22495
+ _token: { value: token ?? null, writable: true, enumerable: false },
22496
+ _tokenInfo: { value: new DoorkeeperTokenInfo(void 0, authedClient), enumerable: false },
22497
+ _tokens: { value: new DoorkeeperTokens(void 0, client2), enumerable: false },
22498
+ _userinfo: { value: new DoorkeeperOpenidConnectUserinfo(void 0, authedClient), enumerable: false }
22499
+ });
22500
+ this.getAccessToken = this.getAccessToken.bind(this);
22501
+ }
22502
+ /** Creates a PKCE `code_challenge` (S256) from a code verifier. */
22503
+ static async createCodeChallenge(codeVerifier) {
22504
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(codeVerifier));
22505
+ return base64URL(new Uint8Array(digest));
22506
+ }
22507
+ /** Creates a random PKCE code verifier. */
22508
+ static createCodeVerifier() {
22509
+ return randomString(32);
22510
+ }
22511
+ /** Creates a random state value. */
22512
+ static createState() {
22513
+ return randomString(16);
22514
+ }
22515
+ /** When the current access token expires, as a unix timestamp in milliseconds - `null` if there's no token. */
22516
+ get expiresAt() {
22517
+ if (this._token === null)
22518
+ return null;
22519
+ return (this._token.created_at + this._token.expires_in) * 1e3;
22520
+ }
22521
+ /** Whether the current access token is expired (or within {@link OAuthClientOptions.refreshLeeway} of expiring). */
22522
+ get isExpired() {
22523
+ const expiresAt = this.expiresAt;
22524
+ return expiresAt === null || Date.now() >= expiresAt - this.refreshLeeway * 1e3;
22525
+ }
22526
+ /** The current token, if any. */
22527
+ get token() {
22528
+ return this._token;
22529
+ }
22530
+ _clientAuth() {
22531
+ return this._clientSecret === null ? { client_id: this.clientId } : { client_id: this.clientId, client_secret: this._clientSecret };
22532
+ }
22533
+ _requireToken() {
22534
+ if (this._token === null)
22535
+ throw new Error("No OAuth token is available, the user must authorize first.");
22536
+ return this._token;
22537
+ }
22538
+ /** Builds the url to send the user to, to authorize your application. */
22539
+ async createAuthorizationURL(options = {}) {
22540
+ const codeVerifier = options.codeVerifier ?? _OAuthClient.createCodeVerifier();
22541
+ const state = options.state ?? _OAuthClient.createState();
22542
+ const redirectURI = options.redirectURI ?? this.redirectURI;
22543
+ const scopes = options.scopes ?? this.scopes;
22544
+ const url = new URL("/oauth/authorize", this.baseURL);
22545
+ url.searchParams.set("response_type", "code");
22546
+ url.searchParams.set("client_id", this.clientId);
22547
+ if (redirectURI)
22548
+ url.searchParams.set("redirect_uri", redirectURI);
22549
+ if (scopes.length !== 0)
22550
+ url.searchParams.set("scope", scopes.join(" "));
22551
+ url.searchParams.set("state", state);
22552
+ url.searchParams.set("code_challenge", await _OAuthClient.createCodeChallenge(codeVerifier));
22553
+ url.searchParams.set("code_challenge_method", "S256");
22554
+ if (options.nonce)
22555
+ url.searchParams.set("nonce", options.nonce);
22556
+ if (options.prompt)
22557
+ url.searchParams.set("prompt", options.prompt);
22558
+ return { codeVerifier, redirectURI, state, url: url.toString() };
22559
+ }
22560
+ /** Gets e621's OpenID Connect discovery document. */
22561
+ async discovery() {
22562
+ return this._discovery.provider();
22563
+ }
22564
+ /** Exchanges an authorization code for a token, and stores it. */
22565
+ async exchangeCode(code, codeVerifier, redirectURI = this.redirectURI) {
22566
+ const token = await this._tokens.create({
22567
+ grant_type: "authorization_code",
22568
+ code,
22569
+ code_verifier: codeVerifier,
22570
+ redirect_uri: redirectURI ?? void 0,
22571
+ ...this._clientAuth()
22572
+ });
22573
+ await this.setToken(token);
22574
+ return token;
22575
+ }
22576
+ /**
22577
+ * Gets a valid access token, refreshing it first if it's expired. Already bound, so it can be passed
22578
+ * directly as {@link Options.authToken}.
22579
+ */
22580
+ async getAccessToken() {
22581
+ if (this._token === null)
22582
+ throw new Error("No OAuth token is available, the user must authorize first.");
22583
+ if (this.isExpired)
22584
+ return (await this.refresh()).access_token;
22585
+ return this._token.access_token;
22586
+ }
22587
+ /**
22588
+ * Validates the url the user was redirected back to (state, and any error e621 sent), then exchanges
22589
+ * its code for a token.
22590
+ * @param callbackURL - The full callback url, or just its query string.
22591
+ */
22592
+ async handleCallback(callbackURL, options) {
22593
+ const params = callbackURL instanceof URLSearchParams ? callbackURL : typeof callbackURL === "string" && !/^[a-z][\d+.a-z-]*:/i.test(callbackURL) ? new URLSearchParams(callbackURL) : new URL(callbackURL).searchParams;
22594
+ const state = params.get("state");
22595
+ const error = params.get("error");
22596
+ if (error)
22597
+ throw new OAuthCallbackError(error, params.get("error_description"), state);
22598
+ if (state !== options.state)
22599
+ throw new OAuthCallbackError("invalid_state", "The callback's state does not match the expected state.", state);
22600
+ const code = params.get("code");
22601
+ if (!code)
22602
+ throw new OAuthCallbackError("invalid_request", "The callback is missing the authorization code.", state);
22603
+ return this.exchangeCode(code, options.codeVerifier, options.redirectURI ?? this.redirectURI);
22604
+ }
22605
+ /** Introspects a token - by default the current access token. */
22606
+ async introspect(token = this._requireToken().access_token) {
22607
+ return this._tokens.introspect({ token, ...this._clientAuth() });
22608
+ }
22609
+ /**
22610
+ * Refreshes the access token, and stores the new token. Concurrent calls share the same request.
22611
+ * @param scopes - Narrow the new token to these scopes.
22612
+ */
22613
+ async refresh(scopes) {
22614
+ if (this._refreshing)
22615
+ return this._refreshing;
22616
+ const refreshToken = this._requireToken().refresh_token;
22617
+ this._refreshing = this._tokens.create({
22618
+ grant_type: "refresh_token",
22619
+ refresh_token: refreshToken,
22620
+ scope: scopes?.join(" "),
22621
+ ...this._clientAuth()
22622
+ }).then(async (token) => {
22623
+ await this.setToken(token);
22624
+ return token;
22625
+ }).finally(() => {
22626
+ this._refreshing = null;
22627
+ });
22628
+ return this._refreshing;
22629
+ }
22630
+ /** Revokes the current token (which also invalidates its refresh token), and clears it. */
22631
+ async revoke() {
22632
+ const token = this._requireToken();
22633
+ await this._tokens.revoke({ token: token.access_token, token_type_hint: "access_token", ...this._clientAuth() });
22634
+ await this.setToken(null);
22635
+ }
22636
+ /** Replaces the stored token, calling {@link OAuthClientOptions.onToken}. */
22637
+ async setToken(token) {
22638
+ this._token = token;
22639
+ await this._onToken?.(token);
22640
+ }
22641
+ /** Gets metadata about the current access token. */
22642
+ async tokenInfo() {
22643
+ return this._tokenInfo.get();
22644
+ }
22645
+ /** Gets the OpenID Connect claims of the authorized user, gated by the token's scopes. */
22646
+ async userInfo() {
22647
+ return this._userinfo.get();
22648
+ }
22649
+ };
22650
+
21718
22651
  // dist/lib/index.js
21719
22652
  var E621 = class {
21720
22653
  client;
@@ -21763,6 +22696,8 @@ export {
21763
22696
  NewsUpdate_default as NewsUpdate,
21764
22697
  Note_default as Note,
21765
22698
  NoteVersion_default as NoteVersion,
22699
+ OAuthCallbackError,
22700
+ OAuthClient,
21766
22701
  Pool_default as Pool,
21767
22702
  PoolVersion_default as PoolVersion,
21768
22703
  Post_default as Post,
@@ -21774,7 +22709,9 @@ export {
21774
22709
  PostSet_default as PostSet,
21775
22710
  PostVersion_default as PostVersion,
21776
22711
  PostVote_default as PostVote,
22712
+ RatelimitError,
21777
22713
  RisingSearchTrend_default as RisingSearchTrend,
22714
+ SavedSearch_default as SavedSearch,
21778
22715
  SearchTrend_default as SearchTrend,
21779
22716
  SearchTrendBlacklist_default as SearchTrendBlacklist,
21780
22717
  SearchTrendHourly_default as SearchTrendHourly,
@@ -21787,6 +22724,7 @@ export {
21787
22724
  TagCorrection_default as TagCorrection,
21788
22725
  TagImplication_default as TagImplication,
21789
22726
  TagPreview_default as TagPreview,
22727
+ TagSubscription_default as TagSubscription,
21790
22728
  TagTypeVersion_default as TagTypeVersion,
21791
22729
  Takedown_default as Takedown,
21792
22730
  ThumbnailPost_default as ThumbnailPost,
@@ -21801,6 +22739,7 @@ export {
21801
22739
  UserNameChangeRequest_default as UserNameChangeRequest,
21802
22740
  WikiPage_default as WikiPage,
21803
22741
  WikiPageVersion_default as WikiPageVersion,
21804
- index_default as default
22742
+ index_default as default,
22743
+ parseRetryAfter
21805
22744
  };
21806
22745
  //# sourceMappingURL=e621.js.map