sidechat.js 2.6.5 → 2.7.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.
- package/dist/classes/SidechatAPIClient.d.ts +166 -11
- package/dist/classes/SidechatAPIClient.d.ts.map +1 -1
- package/dist/index.cjs +925 -365
- package/dist/index.mjs +925 -365
- package/dist/types/SidechatTypes.d.ts +260 -9
- package/dist/types/SidechatTypes.d.ts.map +1 -1
- package/docs/sidechat.js/2.6.6/SidechatAPIClient.html +3 -0
- package/docs/sidechat.js/2.6.6/SidechatAPIError.html +3 -0
- package/docs/sidechat.js/2.6.6/SidechatColorList.html +3 -0
- package/docs/sidechat.js/2.6.6/classes_SidechatAPIClient.js.html +1447 -0
- package/docs/sidechat.js/2.6.6/classes_SidechatAPIError.js.html +16 -0
- package/docs/sidechat.js/2.6.6/classes_SidechatColorList.js.html +79 -0
- package/docs/sidechat.js/2.6.6/data/search.json +1 -0
- package/docs/sidechat.js/2.6.6/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/sidechat.js/2.6.6/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/sidechat.js/2.6.6/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/sidechat.js/2.6.6/global.html +3 -0
- package/docs/sidechat.js/2.6.6/index.html +4 -0
- package/docs/sidechat.js/2.6.6/scripts/core.js +726 -0
- package/docs/sidechat.js/2.6.6/scripts/core.min.js +23 -0
- package/docs/sidechat.js/2.6.6/scripts/resize.js +90 -0
- package/docs/sidechat.js/2.6.6/scripts/search.js +265 -0
- package/docs/sidechat.js/2.6.6/scripts/search.min.js +6 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/Apache-License-2.0.txt +202 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/fuse.js +9 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/hljs-line-num-original.js +369 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/hljs-original.js +5171 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/hljs.js +1 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/popper.js +5 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/tippy.js +1 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/tocbot.js +672 -0
- package/docs/sidechat.js/2.6.6/scripts/third-party/tocbot.min.js +1 -0
- package/docs/sidechat.js/2.6.6/styles/clean-jsdoc-theme-base.css +1159 -0
- package/docs/sidechat.js/2.6.6/styles/clean-jsdoc-theme-dark.css +412 -0
- package/docs/sidechat.js/2.6.6/styles/clean-jsdoc-theme-light.css +482 -0
- package/docs/sidechat.js/2.6.6/styles/clean-jsdoc-theme-scrollbar.css +30 -0
- package/docs/sidechat.js/2.6.6/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
- package/docs/sidechat.js/2.6.6/styles/clean-jsdoc-theme.min.css +1 -0
- package/docs/sidechat.js/2.6.6/tutorial-Authentication.html +14 -0
- package/docs/sidechat.js/2.6.6/tutorial-Email Registration.html +6 -0
- package/docs/sidechat.js/2.6.6/types_SidechatTypes.js.html +204 -0
- package/docs/sidechat.js/2.7.0/SidechatAPIClient.html +3 -0
- package/docs/sidechat.js/2.7.0/SidechatAPIError.html +3 -0
- package/docs/sidechat.js/2.7.0/SidechatColorList.html +3 -0
- package/docs/sidechat.js/2.7.0/classes_SidechatAPIClient.js.html +1897 -0
- package/docs/sidechat.js/2.7.0/classes_SidechatAPIError.js.html +16 -0
- package/docs/sidechat.js/2.7.0/classes_SidechatColorList.js.html +79 -0
- package/docs/sidechat.js/2.7.0/data/search.json +1 -0
- package/docs/sidechat.js/2.7.0/fonts/Inconsolata-Regular.ttf +0 -0
- package/docs/sidechat.js/2.7.0/fonts/OpenSans-Regular.ttf +0 -0
- package/docs/sidechat.js/2.7.0/fonts/WorkSans-Bold.ttf +0 -0
- package/docs/sidechat.js/2.7.0/global.html +3 -0
- package/docs/sidechat.js/2.7.0/index.html +4 -0
- package/docs/sidechat.js/2.7.0/scripts/core.js +726 -0
- package/docs/sidechat.js/2.7.0/scripts/core.min.js +23 -0
- package/docs/sidechat.js/2.7.0/scripts/resize.js +90 -0
- package/docs/sidechat.js/2.7.0/scripts/search.js +265 -0
- package/docs/sidechat.js/2.7.0/scripts/search.min.js +6 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/Apache-License-2.0.txt +202 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/fuse.js +9 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/hljs-line-num-original.js +369 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/hljs-line-num.js +1 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/hljs-original.js +5171 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/hljs.js +1 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/popper.js +5 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/tippy.js +1 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/tocbot.js +672 -0
- package/docs/sidechat.js/2.7.0/scripts/third-party/tocbot.min.js +1 -0
- package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-base.css +1159 -0
- package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-dark.css +412 -0
- package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-light.css +482 -0
- package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-scrollbar.css +30 -0
- package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
- package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme.min.css +1 -0
- package/docs/sidechat.js/2.7.0/tutorial-Authentication.html +16 -0
- package/docs/sidechat.js/2.7.0/tutorial-Email Registration.html +6 -0
- package/docs/sidechat.js/2.7.0/tutorial-Feeds and Pagination.html +10 -0
- package/docs/sidechat.js/2.7.0/tutorial-Posting and Media.html +19 -0
- package/docs/sidechat.js/2.7.0/types_SidechatTypes.js.html +297 -0
- package/docs/tutorials/Authentication.md +63 -52
- package/docs/tutorials/Email Registration.md +19 -16
- package/docs/tutorials/Feeds and Pagination.md +45 -0
- package/docs/tutorials/Posting and Media.md +63 -0
- package/package.json +55 -55
- package/src/classes/SidechatAPIClient.js +549 -81
- package/src/types/SidechatTypes.js +294 -202
|
@@ -67,6 +67,16 @@ class SidechatAPIClient {
|
|
|
67
67
|
this.apiRoot = url;
|
|
68
68
|
};
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* Set an identifier for this device, which will be sent with every request in the `X-Device-ID` header. Should be stable across sessions on the same device.
|
|
72
|
+
* @method
|
|
73
|
+
* @param {String} deviceIdentifier - stable identifier for this device
|
|
74
|
+
* @since 2.7.0
|
|
75
|
+
*/
|
|
76
|
+
setDeviceIdentifier = (deviceIdentifier) => {
|
|
77
|
+
this.defaultHeaders["X-Device-ID"] = deviceIdentifier;
|
|
78
|
+
};
|
|
79
|
+
|
|
70
80
|
/**
|
|
71
81
|
* Run an arbitrary API request using the current client's authentication
|
|
72
82
|
* @method
|
|
@@ -82,7 +92,7 @@ class SidechatAPIClient {
|
|
|
82
92
|
method = "GET",
|
|
83
93
|
body = undefined,
|
|
84
94
|
headers = {},
|
|
85
|
-
stripHeaders = false
|
|
95
|
+
stripHeaders = false,
|
|
86
96
|
) => {
|
|
87
97
|
let requestHeaders = this.defaultHeaders;
|
|
88
98
|
if (stripHeaders) {
|
|
@@ -97,19 +107,32 @@ class SidechatAPIClient {
|
|
|
97
107
|
};
|
|
98
108
|
|
|
99
109
|
/**
|
|
100
|
-
* Initiate the login process with a phone number. Should be followed up with verifySMSCode().
|
|
110
|
+
* Initiate the login process with a phone number. Should be followed up with verifySMSCode(). If the response has an `error_code` of `"captcha_required"`, the server wants a captcha solved before it will send a code, and the request should be repeated with a captcha response. I haven't been able to recreate this yet, so I honestly don't know what captcha provider they want.
|
|
101
111
|
* @method
|
|
102
112
|
* @since 1.0.0
|
|
103
113
|
* @param {Number} phoneNumber - US phone number (WITHOUT +1) to send verification code to
|
|
114
|
+
* @param {Boolean} [useFallback] - send the code through the backup SMS route, which the official app offers when a code doesn't arrive
|
|
115
|
+
* @param {String} [captchaMethod] - type of captcha being answered
|
|
116
|
+
* @param {String} [captchaResponse] - solved captcha token
|
|
104
117
|
*/
|
|
105
|
-
loginViaSMS = async (
|
|
118
|
+
loginViaSMS = async (
|
|
119
|
+
phoneNumber,
|
|
120
|
+
useFallback = false,
|
|
121
|
+
captchaMethod = undefined,
|
|
122
|
+
captchaResponse = undefined,
|
|
123
|
+
) => {
|
|
106
124
|
try {
|
|
107
|
-
const
|
|
125
|
+
const endpoint = useFallback
|
|
126
|
+
? "/v1/login_register_sms_fallback"
|
|
127
|
+
: "/v1/login_register";
|
|
128
|
+
const res = await fetch(`${this.apiRoot}${endpoint}`, {
|
|
108
129
|
method: "POST",
|
|
109
130
|
headers: this.defaultHeaders,
|
|
110
131
|
body: JSON.stringify({
|
|
111
132
|
phone_number: `+1${phoneNumber}`,
|
|
112
133
|
version: 3,
|
|
134
|
+
captcha_method: captchaMethod,
|
|
135
|
+
captcha_response: captchaResponse,
|
|
113
136
|
}),
|
|
114
137
|
});
|
|
115
138
|
const json = await res.json();
|
|
@@ -154,8 +177,15 @@ class SidechatAPIClient {
|
|
|
154
177
|
* @since 1.0.0
|
|
155
178
|
* @param {Number} age - user's age in years
|
|
156
179
|
* @param {String} registrationID - the registration ID generated by verifySMSCode()
|
|
180
|
+
* @param {String} [timeZone] - time zone of the user (e.g. "America/Chicago"). Falls back to the system time zone.
|
|
181
|
+
* @param {String} [inviteLinkURL] - group invite link that the user signed up through
|
|
157
182
|
*/
|
|
158
|
-
setAge = async (
|
|
183
|
+
setAge = async (
|
|
184
|
+
age,
|
|
185
|
+
registrationID,
|
|
186
|
+
timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
187
|
+
inviteLinkURL = undefined,
|
|
188
|
+
) => {
|
|
159
189
|
if (age < 13) {
|
|
160
190
|
throw new SidechatAPIError("You're too young to use Offsides.");
|
|
161
191
|
}
|
|
@@ -166,6 +196,9 @@ class SidechatAPIClient {
|
|
|
166
196
|
body: JSON.stringify({
|
|
167
197
|
age: Number(age),
|
|
168
198
|
registration_id: registrationID,
|
|
199
|
+
time_zone: timeZone,
|
|
200
|
+
invite_link_url: inviteLinkURL,
|
|
201
|
+
device_id: this.defaultHeaders["X-Device-ID"],
|
|
169
202
|
}),
|
|
170
203
|
});
|
|
171
204
|
const json = await res.json();
|
|
@@ -248,8 +281,9 @@ class SidechatAPIClient {
|
|
|
248
281
|
* @method
|
|
249
282
|
* @since 1.0.0
|
|
250
283
|
* @param {String} deviceId - the device ID to set
|
|
284
|
+
* @param {"com.flowerave.sidechat"|"com.flowerave.yikyak"} [bundleID] - bundle ID of the app the push token belongs to
|
|
251
285
|
*/
|
|
252
|
-
setDeviceID = async (deviceID) => {
|
|
286
|
+
setDeviceID = async (deviceID, bundleID = "com.flowerave.sidechat") => {
|
|
253
287
|
if (!this.userToken) {
|
|
254
288
|
throw new SidechatAPIError("User is not authenticated.");
|
|
255
289
|
}
|
|
@@ -262,7 +296,7 @@ class SidechatAPIClient {
|
|
|
262
296
|
},
|
|
263
297
|
body: JSON.stringify({
|
|
264
298
|
build_type: "release",
|
|
265
|
-
bundle_id:
|
|
299
|
+
bundle_id: bundleID,
|
|
266
300
|
device_token: deviceID,
|
|
267
301
|
}),
|
|
268
302
|
});
|
|
@@ -305,7 +339,7 @@ class SidechatAPIClient {
|
|
|
305
339
|
...this.defaultHeaders,
|
|
306
340
|
Authorization: `Bearer ${this.userToken}`,
|
|
307
341
|
},
|
|
308
|
-
}
|
|
342
|
+
},
|
|
309
343
|
);
|
|
310
344
|
const json = await res.json();
|
|
311
345
|
return json;
|
|
@@ -322,23 +356,27 @@ class SidechatAPIClient {
|
|
|
322
356
|
* @param {String} groupID - group ID
|
|
323
357
|
* @param {"hot"|"recent"|"top"} category - category to filter posts
|
|
324
358
|
* @param {types.SidechatCursorString} [cursor] - cursor string
|
|
359
|
+
* @param {"day"|"week"|"month"|"year"|"all_time"} [period] - time period to pull top posts from (only if category is "top")
|
|
325
360
|
* @returns {Promise<types.SidechatPostsAndCursor>} List of posts and cursor
|
|
326
361
|
*/
|
|
327
|
-
getGroupPosts = async (groupID, category = "hot", cursor) => {
|
|
362
|
+
getGroupPosts = async (groupID, category = "hot", cursor, period) => {
|
|
328
363
|
if (!this.userToken) {
|
|
329
364
|
throw new SidechatAPIError("User is not authenticated.");
|
|
330
365
|
}
|
|
331
366
|
try {
|
|
332
367
|
const res = await fetch(
|
|
333
|
-
`${this.apiRoot}/v1/posts?${
|
|
334
|
-
|
|
368
|
+
`${this.apiRoot}/v1/posts?${
|
|
369
|
+
cursor ? "cursor=" + encodeURIComponent(cursor) + "&" : ""
|
|
370
|
+
}${
|
|
371
|
+
period ? "period=" + period + "&" : ""
|
|
372
|
+
}group_id=${groupID}&type=${category}&cacheBust=${Date.now()}`,
|
|
335
373
|
{
|
|
336
374
|
method: "GET",
|
|
337
375
|
headers: {
|
|
338
376
|
...this.defaultHeaders,
|
|
339
377
|
Authorization: `Bearer ${this.userToken}`,
|
|
340
378
|
},
|
|
341
|
-
}
|
|
379
|
+
},
|
|
342
380
|
);
|
|
343
381
|
const json = await res.json();
|
|
344
382
|
return json;
|
|
@@ -393,14 +431,14 @@ class SidechatAPIClient {
|
|
|
393
431
|
}
|
|
394
432
|
try {
|
|
395
433
|
const res = await fetch(
|
|
396
|
-
`${this.apiRoot}/v1/posts/get?include_deleted=${includeDeleted}&post_id=${postID}`,
|
|
434
|
+
`${this.apiRoot}/v1/posts/get?include_deleted=${includeDeleted}&post_id=${postID}&cacheBust=${Date.now()}`,
|
|
397
435
|
{
|
|
398
436
|
method: "GET",
|
|
399
437
|
headers: {
|
|
400
438
|
...this.defaultHeaders,
|
|
401
439
|
Authorization: `Bearer ${this.userToken}`,
|
|
402
440
|
},
|
|
403
|
-
}
|
|
441
|
+
},
|
|
404
442
|
);
|
|
405
443
|
const json = await res.json();
|
|
406
444
|
return json.post;
|
|
@@ -427,7 +465,7 @@ class SidechatAPIClient {
|
|
|
427
465
|
contentType = "my_comments";
|
|
428
466
|
}
|
|
429
467
|
try {
|
|
430
|
-
const res = await fetch(`${this.apiRoot}/v1/posts
|
|
468
|
+
const res = await fetch(`${this.apiRoot}/v1/posts?type=${contentType}`, {
|
|
431
469
|
method: "GET",
|
|
432
470
|
headers: {
|
|
433
471
|
...this.defaultHeaders,
|
|
@@ -455,14 +493,14 @@ class SidechatAPIClient {
|
|
|
455
493
|
}
|
|
456
494
|
try {
|
|
457
495
|
const res = await fetch(
|
|
458
|
-
`${this.apiRoot}/v1/posts/comments/?post_id=${postID}`,
|
|
496
|
+
`${this.apiRoot}/v1/posts/comments/?post_id=${postID}&cacheBust=${Date.now()}`,
|
|
459
497
|
{
|
|
460
498
|
method: "GET",
|
|
461
499
|
headers: {
|
|
462
500
|
...this.defaultHeaders,
|
|
463
501
|
Authorization: `Bearer ${this.userToken}`,
|
|
464
502
|
},
|
|
465
|
-
}
|
|
503
|
+
},
|
|
466
504
|
);
|
|
467
505
|
const json = await res.json();
|
|
468
506
|
// Function to preprocess the comments and organize them into a nested structure
|
|
@@ -558,13 +596,16 @@ class SidechatAPIClient {
|
|
|
558
596
|
throw new SidechatAPIError("User is not authenticated.");
|
|
559
597
|
}
|
|
560
598
|
try {
|
|
561
|
-
const res = await fetch(
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
599
|
+
const res = await fetch(
|
|
600
|
+
`${this.apiRoot}/v1/groups/explore/search?term=${encodeURIComponent(query)}`,
|
|
601
|
+
{
|
|
602
|
+
method: "GET",
|
|
603
|
+
headers: {
|
|
604
|
+
...this.defaultHeaders,
|
|
605
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
606
|
+
},
|
|
566
607
|
},
|
|
567
|
-
|
|
608
|
+
);
|
|
568
609
|
const json = await res.json();
|
|
569
610
|
return await json.results;
|
|
570
611
|
} catch (err) {
|
|
@@ -664,8 +705,9 @@ class SidechatAPIClient {
|
|
|
664
705
|
throw new SidechatAPIError("User is not authenticated.");
|
|
665
706
|
}
|
|
666
707
|
try {
|
|
708
|
+
// Joining moved to the v2 endpoint, which takes a list of IDs. Leave still sends group_id by itself, no list.
|
|
667
709
|
const res = await fetch(
|
|
668
|
-
`${this.apiRoot}
|
|
710
|
+
`${this.apiRoot}${isMember ? "/v2/groups/join" : "/v1/groups/leave"}`,
|
|
669
711
|
{
|
|
670
712
|
method: "POST",
|
|
671
713
|
headers: {
|
|
@@ -673,9 +715,10 @@ class SidechatAPIClient {
|
|
|
673
715
|
Authorization: `Bearer ${this.userToken}`,
|
|
674
716
|
},
|
|
675
717
|
body: JSON.stringify({
|
|
676
|
-
group_id: groupID,
|
|
718
|
+
group_id: isMember ? undefined : groupID,
|
|
719
|
+
group_ids: [groupID],
|
|
677
720
|
}),
|
|
678
|
-
}
|
|
721
|
+
},
|
|
679
722
|
);
|
|
680
723
|
const json = await res.json();
|
|
681
724
|
return await json;
|
|
@@ -707,7 +750,7 @@ class SidechatAPIClient {
|
|
|
707
750
|
topLevelReplyID,
|
|
708
751
|
assetList = [],
|
|
709
752
|
disableDMs = false,
|
|
710
|
-
anonymous = false
|
|
753
|
+
anonymous = false,
|
|
711
754
|
) => {
|
|
712
755
|
if (!this.userToken) {
|
|
713
756
|
throw new SidechatAPIError("User is not authenticated.");
|
|
@@ -732,15 +775,17 @@ class SidechatAPIClient {
|
|
|
732
775
|
}),
|
|
733
776
|
});
|
|
734
777
|
const json = await res.json();
|
|
778
|
+
if (!res.ok) throw new SidechatAPIError(json.message);
|
|
735
779
|
return await json.comment;
|
|
736
780
|
} catch (err) {
|
|
737
781
|
console.error(err);
|
|
782
|
+
if (err instanceof SidechatAPIError && err.message) throw err;
|
|
738
783
|
throw new SidechatAPIError(`Failed to post comment.`);
|
|
739
784
|
}
|
|
740
785
|
};
|
|
741
786
|
|
|
742
787
|
/**
|
|
743
|
-
* Creates a new post in the specified group
|
|
788
|
+
* Creates a new post in the specified group. Users can only make two posts a minute; if a post is rejected, the thrown error contains the reason from the server.
|
|
744
789
|
* @method
|
|
745
790
|
* @since 2.2.0
|
|
746
791
|
* @param {String} text - text content of comment
|
|
@@ -750,6 +795,7 @@ class SidechatAPIClient {
|
|
|
750
795
|
* @param {Boolean} [disableComments] - whether or not comments should be disabled on post
|
|
751
796
|
* @param {Boolean} [anonymous] - whether or not to hide user's name and icon on post
|
|
752
797
|
* @param {Array<String>} [pollOptions] - List of poll options. If provided, a poll will be created with these options.
|
|
798
|
+
* @param {Array<String>} [attachmentIDs] - IDs of link attachments created with createLinkAttachment()
|
|
753
799
|
* @returns {Promise<types.SidechatPostOrComment>} the created post
|
|
754
800
|
*/
|
|
755
801
|
createPost = async (
|
|
@@ -760,7 +806,8 @@ class SidechatAPIClient {
|
|
|
760
806
|
disableComments = false,
|
|
761
807
|
anonymous = false,
|
|
762
808
|
repostId = undefined,
|
|
763
|
-
pollOptions = undefined
|
|
809
|
+
pollOptions = undefined,
|
|
810
|
+
attachmentIDs = [],
|
|
764
811
|
) => {
|
|
765
812
|
if (!this.userToken) {
|
|
766
813
|
throw new SidechatAPIError("User is not authenticated.");
|
|
@@ -772,17 +819,17 @@ class SidechatAPIClient {
|
|
|
772
819
|
assets: assetList,
|
|
773
820
|
group_ids: [groupID],
|
|
774
821
|
text: text,
|
|
775
|
-
attachments:
|
|
822
|
+
attachments: attachmentIDs,
|
|
776
823
|
dms_disabled: disableDMs,
|
|
777
824
|
comments_disabled: disableComments,
|
|
778
825
|
using_identity: !anonymous,
|
|
779
|
-
quote_post_id: repostId
|
|
826
|
+
quote_post_id: repostId,
|
|
780
827
|
};
|
|
781
828
|
// If pollOptions is provided and is a non-empty array, add poll_request
|
|
782
829
|
if (Array.isArray(pollOptions) && pollOptions.length > 0) {
|
|
783
830
|
body.poll_request = {
|
|
784
831
|
allows_view_results: true,
|
|
785
|
-
choices: pollOptions
|
|
832
|
+
choices: pollOptions,
|
|
786
833
|
};
|
|
787
834
|
}
|
|
788
835
|
const res = await fetch(`${this.apiRoot}/v1/posts`, {
|
|
@@ -794,9 +841,11 @@ class SidechatAPIClient {
|
|
|
794
841
|
body: JSON.stringify(body),
|
|
795
842
|
});
|
|
796
843
|
const json = await res.json();
|
|
844
|
+
if (!res.ok) throw new SidechatAPIError(json.message);
|
|
797
845
|
return await json.posts[0];
|
|
798
846
|
} catch (err) {
|
|
799
847
|
console.error(err);
|
|
848
|
+
if (err instanceof SidechatAPIError && err.message) throw err;
|
|
800
849
|
throw new SidechatAPIError(`Failed to make post.`);
|
|
801
850
|
}
|
|
802
851
|
};
|
|
@@ -872,16 +921,19 @@ class SidechatAPIClient {
|
|
|
872
921
|
throw new SidechatAPIError("User is not authenticated.");
|
|
873
922
|
}
|
|
874
923
|
try {
|
|
875
|
-
const res = await fetch(
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
924
|
+
const res = await fetch(
|
|
925
|
+
`${this.apiRoot}/v1/polls/view_results?cacheBust=${Date.now()}`,
|
|
926
|
+
{
|
|
927
|
+
method: "POST",
|
|
928
|
+
headers: {
|
|
929
|
+
...this.defaultHeaders,
|
|
930
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
931
|
+
},
|
|
932
|
+
body: JSON.stringify({
|
|
933
|
+
poll_id: pollId,
|
|
934
|
+
}),
|
|
880
935
|
},
|
|
881
|
-
|
|
882
|
-
poll_id: pollId,
|
|
883
|
-
}),
|
|
884
|
-
});
|
|
936
|
+
);
|
|
885
937
|
const json = await res.json();
|
|
886
938
|
return await json;
|
|
887
939
|
} catch (err) {
|
|
@@ -891,22 +943,27 @@ class SidechatAPIClient {
|
|
|
891
943
|
};
|
|
892
944
|
|
|
893
945
|
/**
|
|
894
|
-
* Uploads an asset to AWS S3 for use in posts and comments.
|
|
946
|
+
* Uploads an asset to AWS S3 for use in posts and comments. Supports images and videos (videos must be under 50MB and are processed after upload)
|
|
895
947
|
* @method
|
|
896
948
|
* @param {String} uri - URI of the asset to upload
|
|
897
|
-
* @param {String} mimeType - mimetype of the asset (e.g. "image/png")
|
|
949
|
+
* @param {String} mimeType - mimetype of the asset (e.g. "image/png" or "video/mp4")
|
|
898
950
|
* @param {String} [name] - filename of the asset
|
|
951
|
+
* @param {"post"|"post_vod_source"|"chat"|"chat_icon"|"group_icon"|"profile_picture_icon"} [context] - where the asset will be used. Videos default to "post_vod_source", which is required for them to be processed into a playable stream.
|
|
899
952
|
* @returns {Promise<String>} URL of the uploaded asset
|
|
900
953
|
* @since 2.5.1
|
|
901
954
|
*/
|
|
902
|
-
uploadAsset = async (uri, mimeType, name = "") => {
|
|
955
|
+
uploadAsset = async (uri, mimeType, name = "", context = undefined) => {
|
|
903
956
|
if (!this.userToken) {
|
|
904
957
|
throw new SidechatAPIError("User is not authenticated.");
|
|
905
958
|
}
|
|
906
959
|
|
|
907
960
|
let imageType = mimeType.split("/")[1];
|
|
908
|
-
if (
|
|
909
|
-
|
|
961
|
+
if (imageType == "quicktime") imageType = "mov";
|
|
962
|
+
if (!["png", "jpeg", "gif", "webp", "mp4", "mov"].includes(imageType)) {
|
|
963
|
+
throw new SidechatAPIError("Unsupported file format.");
|
|
964
|
+
}
|
|
965
|
+
if (!context && ["mp4", "mov"].includes(imageType)) {
|
|
966
|
+
context = "post_vod_source";
|
|
910
967
|
}
|
|
911
968
|
|
|
912
969
|
const data = new FormData();
|
|
@@ -916,7 +973,11 @@ class SidechatAPIClient {
|
|
|
916
973
|
uri: uri,
|
|
917
974
|
});
|
|
918
975
|
|
|
919
|
-
const urlReq = await this.sendRequest(
|
|
976
|
+
const urlReq = await this.sendRequest(
|
|
977
|
+
`/v1/assets/upload_url?content_type=${imageType}${
|
|
978
|
+
context ? "&context=" + context : ""
|
|
979
|
+
}`,
|
|
980
|
+
);
|
|
920
981
|
const urlJson = await urlReq.json();
|
|
921
982
|
|
|
922
983
|
try {
|
|
@@ -931,7 +992,7 @@ class SidechatAPIClient {
|
|
|
931
992
|
return `${this.apiRoot}/v1/assets/library/${urlJson.asset_id}`;
|
|
932
993
|
} else {
|
|
933
994
|
throw new SidechatAPIError(
|
|
934
|
-
`Couldn't upload image - error ${uploadReq.status}
|
|
995
|
+
`Couldn't upload image - error ${uploadReq.status}`,
|
|
935
996
|
);
|
|
936
997
|
}
|
|
937
998
|
} catch (e) {
|
|
@@ -997,7 +1058,7 @@ class SidechatAPIClient {
|
|
|
997
1058
|
Authorization: `Bearer ${this.userToken}`,
|
|
998
1059
|
},
|
|
999
1060
|
body: JSON.stringify({
|
|
1000
|
-
bio: bio
|
|
1061
|
+
bio: bio,
|
|
1001
1062
|
}),
|
|
1002
1063
|
});
|
|
1003
1064
|
const json = await res.json();
|
|
@@ -1028,7 +1089,7 @@ class SidechatAPIClient {
|
|
|
1028
1089
|
...this.defaultHeaders,
|
|
1029
1090
|
Authorization: `Bearer ${this.userToken}`,
|
|
1030
1091
|
},
|
|
1031
|
-
}
|
|
1092
|
+
},
|
|
1032
1093
|
);
|
|
1033
1094
|
if (res?.status == 200 || res?.status == 204) {
|
|
1034
1095
|
return true;
|
|
@@ -1083,13 +1144,16 @@ class SidechatAPIClient {
|
|
|
1083
1144
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1084
1145
|
}
|
|
1085
1146
|
try {
|
|
1086
|
-
const res = await fetch(
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1147
|
+
const res = await fetch(
|
|
1148
|
+
`${this.apiRoot}/v1/groups/username?username=${username}&cacheBust=${Date.now()}`,
|
|
1149
|
+
{
|
|
1150
|
+
method: "GET",
|
|
1151
|
+
headers: {
|
|
1152
|
+
...this.defaultHeaders,
|
|
1153
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
1154
|
+
},
|
|
1155
|
+
},
|
|
1156
|
+
);
|
|
1093
1157
|
const json = await res.json();
|
|
1094
1158
|
return await json.group;
|
|
1095
1159
|
} catch (err) {
|
|
@@ -1110,13 +1174,16 @@ class SidechatAPIClient {
|
|
|
1110
1174
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1111
1175
|
}
|
|
1112
1176
|
try {
|
|
1113
|
-
const res = await fetch(
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1177
|
+
const res = await fetch(
|
|
1178
|
+
`${this.apiRoot}/v1/users/posts?username=${username}`,
|
|
1179
|
+
{
|
|
1180
|
+
method: "GET",
|
|
1181
|
+
headers: {
|
|
1182
|
+
...this.defaultHeaders,
|
|
1183
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
1184
|
+
},
|
|
1185
|
+
},
|
|
1186
|
+
);
|
|
1120
1187
|
const json = await res.json();
|
|
1121
1188
|
return await json.posts;
|
|
1122
1189
|
} catch (err) {
|
|
@@ -1164,13 +1231,16 @@ class SidechatAPIClient {
|
|
|
1164
1231
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1165
1232
|
}
|
|
1166
1233
|
try {
|
|
1167
|
-
const res = await fetch(
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1234
|
+
const res = await fetch(
|
|
1235
|
+
`${this.apiRoot}/v1/chats/explore?cacheBust=${Date.now()}`,
|
|
1236
|
+
{
|
|
1237
|
+
method: "GET",
|
|
1238
|
+
headers: {
|
|
1239
|
+
...this.defaultHeaders,
|
|
1240
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
1241
|
+
},
|
|
1172
1242
|
},
|
|
1173
|
-
|
|
1243
|
+
);
|
|
1174
1244
|
const json = await res.json();
|
|
1175
1245
|
return await json.chats;
|
|
1176
1246
|
} catch (err) {
|
|
@@ -1194,7 +1264,7 @@ class SidechatAPIClient {
|
|
|
1194
1264
|
displayName,
|
|
1195
1265
|
emoji,
|
|
1196
1266
|
primaryColor,
|
|
1197
|
-
secondaryColor
|
|
1267
|
+
secondaryColor,
|
|
1198
1268
|
) => {
|
|
1199
1269
|
if (!this.userToken) {
|
|
1200
1270
|
throw new SidechatAPIError("User is not authenticated.");
|
|
@@ -1227,21 +1297,27 @@ class SidechatAPIClient {
|
|
|
1227
1297
|
/**
|
|
1228
1298
|
* Gets a list of the user's direct messages
|
|
1229
1299
|
* @method
|
|
1300
|
+
* @param {types.SidechatCursorString} [cursor] - cursor string
|
|
1230
1301
|
* @returns {Promise<types.SidechatDirectThread[]>}
|
|
1231
1302
|
* @since 2.4.4
|
|
1232
1303
|
*/
|
|
1233
|
-
getDMs = async () => {
|
|
1304
|
+
getDMs = async (cursor) => {
|
|
1234
1305
|
if (!this.userToken) {
|
|
1235
1306
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1236
1307
|
}
|
|
1237
1308
|
try {
|
|
1238
|
-
const res = await fetch(
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1309
|
+
const res = await fetch(
|
|
1310
|
+
`${this.apiRoot}/v1/chats${
|
|
1311
|
+
cursor ? "?cursor=" + encodeURIComponent(cursor) : ""
|
|
1312
|
+
}`,
|
|
1313
|
+
{
|
|
1314
|
+
method: "GET",
|
|
1315
|
+
headers: {
|
|
1316
|
+
...this.defaultHeaders,
|
|
1317
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
1318
|
+
},
|
|
1243
1319
|
},
|
|
1244
|
-
|
|
1320
|
+
);
|
|
1245
1321
|
const json = await res.json();
|
|
1246
1322
|
const list = await json.chats;
|
|
1247
1323
|
let r = [];
|
|
@@ -1275,7 +1351,7 @@ class SidechatAPIClient {
|
|
|
1275
1351
|
...this.defaultHeaders,
|
|
1276
1352
|
Authorization: `Bearer ${this.userToken}`,
|
|
1277
1353
|
},
|
|
1278
|
-
}
|
|
1354
|
+
},
|
|
1279
1355
|
);
|
|
1280
1356
|
const json = await res.json();
|
|
1281
1357
|
return await json.chat;
|
|
@@ -1337,7 +1413,7 @@ class SidechatAPIClient {
|
|
|
1337
1413
|
clientID,
|
|
1338
1414
|
postID,
|
|
1339
1415
|
anonymous = false,
|
|
1340
|
-
postContext = "feed"
|
|
1416
|
+
postContext = "feed",
|
|
1341
1417
|
) => {
|
|
1342
1418
|
if (!this.userToken) {
|
|
1343
1419
|
throw new SidechatAPIError("User is not authenticated.");
|
|
@@ -1370,6 +1446,7 @@ class SidechatAPIClient {
|
|
|
1370
1446
|
* @method
|
|
1371
1447
|
* @param {String} postID - alphanumeric ID of post to hide
|
|
1372
1448
|
* @since 2.6.2
|
|
1449
|
+
* @deprecated since 2.7.0. Please use `blockUser` instead!
|
|
1373
1450
|
*/
|
|
1374
1451
|
hidePostsFromUser = async (postID) => {
|
|
1375
1452
|
if (!this.userToken) {
|
|
@@ -1385,7 +1462,7 @@ class SidechatAPIClient {
|
|
|
1385
1462
|
body: JSON.stringify({
|
|
1386
1463
|
post_id: postID,
|
|
1387
1464
|
post_context: "feed",
|
|
1388
|
-
report: false
|
|
1465
|
+
report: false,
|
|
1389
1466
|
}),
|
|
1390
1467
|
});
|
|
1391
1468
|
const json = await res.json();
|
|
@@ -1400,6 +1477,7 @@ class SidechatAPIClient {
|
|
|
1400
1477
|
* Unhides all posts from all users
|
|
1401
1478
|
* @method
|
|
1402
1479
|
* @since 2.6.2
|
|
1480
|
+
* @deprecated since 2.7.0. No longer used by the official app and may stop working.
|
|
1403
1481
|
*/
|
|
1404
1482
|
unhidePostsFromAllUsers = async () => {
|
|
1405
1483
|
if (!this.userToken) {
|
|
@@ -1421,6 +1499,396 @@ class SidechatAPIClient {
|
|
|
1421
1499
|
throw new SidechatAPIError(`Failed to unhide post.`);
|
|
1422
1500
|
}
|
|
1423
1501
|
};
|
|
1502
|
+
|
|
1503
|
+
/**
|
|
1504
|
+
* Fetches the home feed, which mixes posts from all of the user's groups
|
|
1505
|
+
* @method
|
|
1506
|
+
* @param {"for_you"|"hot"|"recent"} [type] - how the feed should be sorted
|
|
1507
|
+
* @param {String} [schoolGroupID] - alphanumeric ID of the user's school group
|
|
1508
|
+
* @param {types.SidechatCursorString} [cursor] - cursor string
|
|
1509
|
+
* @returns {Promise<types.SidechatFeed>} feed items and cursor
|
|
1510
|
+
* @since 2.7.0
|
|
1511
|
+
*/
|
|
1512
|
+
getHomeFeed = async (type = "for_you", schoolGroupID, cursor) => {
|
|
1513
|
+
if (!this.userToken) {
|
|
1514
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1515
|
+
}
|
|
1516
|
+
try {
|
|
1517
|
+
const params = new URLSearchParams({ type: type });
|
|
1518
|
+
if (schoolGroupID) params.set("school_group_id", schoolGroupID);
|
|
1519
|
+
if (cursor) params.set("cursor", cursor);
|
|
1520
|
+
const res = await this.sendRequest(`/v1/posts/home?${params}`);
|
|
1521
|
+
return await res.json();
|
|
1522
|
+
} catch (err) {
|
|
1523
|
+
console.error(err);
|
|
1524
|
+
throw new SidechatAPIError(`Failed to get home feed.`);
|
|
1525
|
+
}
|
|
1526
|
+
};
|
|
1527
|
+
|
|
1528
|
+
/**
|
|
1529
|
+
* Follows or unfollows a post. Followed posts send activity notifications when they get new comments.
|
|
1530
|
+
* @method
|
|
1531
|
+
* @param {String} postID - alphanumeric ID of post
|
|
1532
|
+
* @param {Boolean} following - whether or not the user should follow the post
|
|
1533
|
+
* @returns {Promise<{post: types.SidechatPostOrComment}>} the updated post
|
|
1534
|
+
* @since 2.7.0
|
|
1535
|
+
*/
|
|
1536
|
+
setPostFollowing = async (postID, following) => {
|
|
1537
|
+
if (!this.userToken) {
|
|
1538
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1539
|
+
}
|
|
1540
|
+
try {
|
|
1541
|
+
const res = await this.sendRequest(
|
|
1542
|
+
`/v1/posts/${following ? "follow" : "unfollow"}`,
|
|
1543
|
+
"POST",
|
|
1544
|
+
JSON.stringify({ post_id: postID }),
|
|
1545
|
+
);
|
|
1546
|
+
return await res.json();
|
|
1547
|
+
} catch (err) {
|
|
1548
|
+
console.error(err);
|
|
1549
|
+
throw new SidechatAPIError(`Failed to change post follow status.`);
|
|
1550
|
+
}
|
|
1551
|
+
};
|
|
1552
|
+
|
|
1553
|
+
/**
|
|
1554
|
+
* Reports a post or comment to the group's moderators
|
|
1555
|
+
* @method
|
|
1556
|
+
* @param {String} postID - alphanumeric ID of post or comment to report
|
|
1557
|
+
* @param {types.SidechatReportReason} reason - why the content is being reported
|
|
1558
|
+
* @param {String} [note] - explanation to send along with the report
|
|
1559
|
+
* @since 2.7.0
|
|
1560
|
+
*/
|
|
1561
|
+
flagPost = async (postID, reason, note = undefined) => {
|
|
1562
|
+
if (!this.userToken) {
|
|
1563
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1564
|
+
}
|
|
1565
|
+
try {
|
|
1566
|
+
const res = await this.sendRequest(
|
|
1567
|
+
"/v1/posts/flag",
|
|
1568
|
+
"POST",
|
|
1569
|
+
JSON.stringify({ post_id: postID, reason: reason, note: note }),
|
|
1570
|
+
);
|
|
1571
|
+
return await res.json();
|
|
1572
|
+
} catch (err) {
|
|
1573
|
+
console.error(err);
|
|
1574
|
+
throw new SidechatAPIError(`Failed to report post.`);
|
|
1575
|
+
}
|
|
1576
|
+
};
|
|
1577
|
+
|
|
1578
|
+
/**
|
|
1579
|
+
* Blocks the author of a post or comment, hiding all of their content from the user. Replaces `hidePostsFromUser`.
|
|
1580
|
+
* @method
|
|
1581
|
+
* @param {String} postID - alphanumeric ID of a post or comment by the user to block
|
|
1582
|
+
* @param {Boolean} [report] - whether or not to also report the content
|
|
1583
|
+
* @param {"feed"|"chat"} [postContext] - where the content was seen
|
|
1584
|
+
* @since 2.7.0
|
|
1585
|
+
*/
|
|
1586
|
+
blockUser = async (postID, report = false, postContext = "feed") => {
|
|
1587
|
+
if (!this.userToken) {
|
|
1588
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1589
|
+
}
|
|
1590
|
+
try {
|
|
1591
|
+
const res = await this.sendRequest(
|
|
1592
|
+
"/v1/posts/block_user",
|
|
1593
|
+
"POST",
|
|
1594
|
+
JSON.stringify({
|
|
1595
|
+
post_id: postID,
|
|
1596
|
+
post_context: postContext,
|
|
1597
|
+
report: report,
|
|
1598
|
+
}),
|
|
1599
|
+
);
|
|
1600
|
+
return await res.json();
|
|
1601
|
+
} catch (err) {
|
|
1602
|
+
console.error(err);
|
|
1603
|
+
throw new SidechatAPIError(`Failed to block user.`);
|
|
1604
|
+
}
|
|
1605
|
+
};
|
|
1606
|
+
|
|
1607
|
+
/**
|
|
1608
|
+
* Creates a link attachment that can be added to a post with createPost(). YouTube links are recognized and shown as embedded videos.
|
|
1609
|
+
* @method
|
|
1610
|
+
* @param {String} url - URL to attach
|
|
1611
|
+
* @returns {Promise<types.SidechatAttachment>} the created attachment
|
|
1612
|
+
* @since 2.7.0
|
|
1613
|
+
*/
|
|
1614
|
+
createLinkAttachment = async (url) => {
|
|
1615
|
+
if (!this.userToken) {
|
|
1616
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1617
|
+
}
|
|
1618
|
+
try {
|
|
1619
|
+
const res = await this.sendRequest(
|
|
1620
|
+
"/v1/attachments/upload_link",
|
|
1621
|
+
"POST",
|
|
1622
|
+
JSON.stringify({ link_url: url }),
|
|
1623
|
+
);
|
|
1624
|
+
return await res.json();
|
|
1625
|
+
} catch (err) {
|
|
1626
|
+
console.error(err);
|
|
1627
|
+
throw new SidechatAPIError(`Failed to create link attachment.`);
|
|
1628
|
+
}
|
|
1629
|
+
};
|
|
1630
|
+
|
|
1631
|
+
/**
|
|
1632
|
+
* Gets the user's activity feed (notifications for comments, votes, followers, etc.)
|
|
1633
|
+
* @method
|
|
1634
|
+
* @param {types.SidechatCursorString} [cursor] - cursor string
|
|
1635
|
+
* @returns {Promise<types.SidechatActivityList>} activity items and cursor
|
|
1636
|
+
* @since 2.7.0
|
|
1637
|
+
*/
|
|
1638
|
+
getActivity = async (cursor) => {
|
|
1639
|
+
if (!this.userToken) {
|
|
1640
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1641
|
+
}
|
|
1642
|
+
try {
|
|
1643
|
+
const res = await this.sendRequest(
|
|
1644
|
+
`/v1/activity${cursor ? "?cursor=" + encodeURIComponent(cursor) : ""}`,
|
|
1645
|
+
);
|
|
1646
|
+
return await res.json();
|
|
1647
|
+
} catch (err) {
|
|
1648
|
+
console.error(err);
|
|
1649
|
+
throw new SidechatAPIError(`Failed to get activity.`);
|
|
1650
|
+
}
|
|
1651
|
+
};
|
|
1652
|
+
|
|
1653
|
+
/**
|
|
1654
|
+
* Gets the groups the user is a member of
|
|
1655
|
+
* @method
|
|
1656
|
+
* @returns {Promise<types.SidechatGroup[]>}
|
|
1657
|
+
* @since 2.7.0
|
|
1658
|
+
*/
|
|
1659
|
+
getGroups = async () => {
|
|
1660
|
+
if (!this.userToken) {
|
|
1661
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1662
|
+
}
|
|
1663
|
+
try {
|
|
1664
|
+
const res = await this.sendRequest("/v1/groups");
|
|
1665
|
+
const json = await res.json();
|
|
1666
|
+
return json.groups;
|
|
1667
|
+
} catch (err) {
|
|
1668
|
+
console.error(err);
|
|
1669
|
+
throw new SidechatAPIError(`Failed to get groups.`);
|
|
1670
|
+
}
|
|
1671
|
+
};
|
|
1672
|
+
|
|
1673
|
+
/**
|
|
1674
|
+
* Gets groups suggested for the user to join
|
|
1675
|
+
* @method
|
|
1676
|
+
* @param {Number} [limit] - maximum number of groups to return
|
|
1677
|
+
* @returns {Promise<types.SidechatGroup[]>}
|
|
1678
|
+
* @since 2.7.0
|
|
1679
|
+
*/
|
|
1680
|
+
getSuggestedGroups = async (limit = 10) => {
|
|
1681
|
+
if (!this.userToken) {
|
|
1682
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1683
|
+
}
|
|
1684
|
+
try {
|
|
1685
|
+
const res = await this.sendRequest(
|
|
1686
|
+
`/v1/groups/suggestions?limit=${limit}`,
|
|
1687
|
+
);
|
|
1688
|
+
const json = await res.json();
|
|
1689
|
+
return json.groups;
|
|
1690
|
+
} catch (err) {
|
|
1691
|
+
console.error(err);
|
|
1692
|
+
throw new SidechatAPIError(`Failed to get suggested groups.`);
|
|
1693
|
+
}
|
|
1694
|
+
};
|
|
1695
|
+
|
|
1696
|
+
/**
|
|
1697
|
+
* Gets a shareable invite link for a group. School groups don't have invite links and will throw an error.
|
|
1698
|
+
* @method
|
|
1699
|
+
* @param {String} groupID - alphanumeric ID of group
|
|
1700
|
+
* @returns {Promise<String>} invite link URL
|
|
1701
|
+
* @since 2.7.0
|
|
1702
|
+
*/
|
|
1703
|
+
getGroupInviteLink = async (groupID) => {
|
|
1704
|
+
if (!this.userToken) {
|
|
1705
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1706
|
+
}
|
|
1707
|
+
try {
|
|
1708
|
+
const res = await this.sendRequest(
|
|
1709
|
+
`/v1/groups/invite_link?group_id=${groupID}`,
|
|
1710
|
+
);
|
|
1711
|
+
const json = await res.json();
|
|
1712
|
+
return json.link;
|
|
1713
|
+
} catch (err) {
|
|
1714
|
+
console.error(err);
|
|
1715
|
+
throw new SidechatAPIError(`Failed to get invite link.`);
|
|
1716
|
+
}
|
|
1717
|
+
};
|
|
1718
|
+
|
|
1719
|
+
/**
|
|
1720
|
+
* Gets the yakarma leaderboard for a group, along with the user's own karma
|
|
1721
|
+
* @method
|
|
1722
|
+
* @param {String} groupID - alphanumeric ID of group
|
|
1723
|
+
* @returns {Promise<types.SidechatLeaderboard>}
|
|
1724
|
+
* @since 2.7.0
|
|
1725
|
+
*/
|
|
1726
|
+
getLeaderboard = async (groupID) => {
|
|
1727
|
+
if (!this.userToken) {
|
|
1728
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1729
|
+
}
|
|
1730
|
+
try {
|
|
1731
|
+
const res = await this.sendRequest(`/v1/leaderboard?group_id=${groupID}`);
|
|
1732
|
+
return await res.json();
|
|
1733
|
+
} catch (err) {
|
|
1734
|
+
console.error(err);
|
|
1735
|
+
throw new SidechatAPIError(`Failed to get leaderboard.`);
|
|
1736
|
+
}
|
|
1737
|
+
};
|
|
1738
|
+
|
|
1739
|
+
/**
|
|
1740
|
+
* Gets the existing direct message thread for a post or comment. Returns undefined if the user hasn't started one.
|
|
1741
|
+
* @method
|
|
1742
|
+
* @param {String} postID - alphanumeric ID of post or comment
|
|
1743
|
+
* @returns {Promise<types.SidechatDirectThread>}
|
|
1744
|
+
* @since 2.7.0
|
|
1745
|
+
*/
|
|
1746
|
+
getDMForPost = async (postID) => {
|
|
1747
|
+
if (!this.userToken) {
|
|
1748
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1749
|
+
}
|
|
1750
|
+
try {
|
|
1751
|
+
const res = await this.sendRequest(`/v1/chats/by_post?post_id=${postID}`);
|
|
1752
|
+
const json = await res.json();
|
|
1753
|
+
return json.chat;
|
|
1754
|
+
} catch (err) {
|
|
1755
|
+
console.error(err);
|
|
1756
|
+
throw new SidechatAPIError(`Failed to get DM thread for post.`);
|
|
1757
|
+
}
|
|
1758
|
+
};
|
|
1759
|
+
|
|
1760
|
+
/**
|
|
1761
|
+
* Reports a direct message thread
|
|
1762
|
+
* @method
|
|
1763
|
+
* @param {String} chatID - alphanumeric ID of the thread to report
|
|
1764
|
+
* @param {types.SidechatReportReason} reason - why the thread is being reported
|
|
1765
|
+
* @since 2.7.0
|
|
1766
|
+
*/
|
|
1767
|
+
reportDM = async (chatID, reason) => {
|
|
1768
|
+
if (!this.userToken) {
|
|
1769
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1770
|
+
}
|
|
1771
|
+
try {
|
|
1772
|
+
const res = await this.sendRequest(
|
|
1773
|
+
"/v1/chats/report",
|
|
1774
|
+
"POST",
|
|
1775
|
+
JSON.stringify({ chat_id: chatID, reason: reason }),
|
|
1776
|
+
);
|
|
1777
|
+
return await res.json();
|
|
1778
|
+
} catch (err) {
|
|
1779
|
+
console.error(err);
|
|
1780
|
+
throw new SidechatAPIError(`Failed to report DM.`);
|
|
1781
|
+
}
|
|
1782
|
+
};
|
|
1783
|
+
|
|
1784
|
+
/**
|
|
1785
|
+
* Sets which push notifications the user receives
|
|
1786
|
+
* @method
|
|
1787
|
+
* @param {types.SidechatNotificationPreferences} preferences - notification types to enable or disable
|
|
1788
|
+
* @since 2.7.0
|
|
1789
|
+
*/
|
|
1790
|
+
setNotificationPreferences = async (preferences) => {
|
|
1791
|
+
if (!this.userToken) {
|
|
1792
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1793
|
+
}
|
|
1794
|
+
try {
|
|
1795
|
+
const res = await this.sendRequest(
|
|
1796
|
+
"/v1/users/set_notification_preferences",
|
|
1797
|
+
"POST",
|
|
1798
|
+
JSON.stringify({ notification_preferences: preferences }),
|
|
1799
|
+
);
|
|
1800
|
+
return await res.json();
|
|
1801
|
+
} catch (err) {
|
|
1802
|
+
console.error(err);
|
|
1803
|
+
throw new SidechatAPIError(`Failed to set notification preferences.`);
|
|
1804
|
+
}
|
|
1805
|
+
};
|
|
1806
|
+
|
|
1807
|
+
/**
|
|
1808
|
+
* Verifies the user's school email by signing in with Google or Microsoft instead of clicking an emailed link. Returns the same object as checkEmailVerification(). This was discovered from me decompiling the new Android app, I haven't tested this but based on the implementation it should work fine and might resolve the problem that a lot of people have with their accounts not being associated with their school automatically.
|
|
1809
|
+
* @method
|
|
1810
|
+
* @param {String} authToken - token from the Google or Microsoft sign-in
|
|
1811
|
+
* @param {"google"|"microsoft"} authType - provider the token came from
|
|
1812
|
+
* @param {Boolean} [isIncomingFreshman] - whether or not the user is an incoming freshman
|
|
1813
|
+
* @since 2.7.0
|
|
1814
|
+
* @tutorial Email Registration
|
|
1815
|
+
*/
|
|
1816
|
+
verifyEmailWithThirdParty = async (
|
|
1817
|
+
authToken,
|
|
1818
|
+
authType,
|
|
1819
|
+
isIncomingFreshman = false,
|
|
1820
|
+
) => {
|
|
1821
|
+
if (!this.userToken) {
|
|
1822
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1823
|
+
}
|
|
1824
|
+
try {
|
|
1825
|
+
const res = await this.sendRequest(
|
|
1826
|
+
"/v1/users/third_party_email_verified",
|
|
1827
|
+
"POST",
|
|
1828
|
+
JSON.stringify({
|
|
1829
|
+
auth: authToken,
|
|
1830
|
+
auth_type: authType,
|
|
1831
|
+
is_incoming_freshman: isIncomingFreshman,
|
|
1832
|
+
}),
|
|
1833
|
+
);
|
|
1834
|
+
const json = await res.json();
|
|
1835
|
+
if (json.verified_email_updates_response) {
|
|
1836
|
+
return json.verified_email_updates_response;
|
|
1837
|
+
} else {
|
|
1838
|
+
throw new SidechatAPIError(json?.message || "Email is not verified.");
|
|
1839
|
+
}
|
|
1840
|
+
} catch (err) {
|
|
1841
|
+
console.error(err);
|
|
1842
|
+
throw new SidechatAPIError("Failed to verify email.");
|
|
1843
|
+
}
|
|
1844
|
+
};
|
|
1845
|
+
|
|
1846
|
+
/**
|
|
1847
|
+
* Authorizes a realtime (Pusher) connection to subscribe to a private channel, such as `private-chat-<chatID>` for live direct messages. Pass the result to your Pusher client's channel authorizer. This hasn't been tested, and is mostly theoretical.
|
|
1848
|
+
* @method
|
|
1849
|
+
* @param {String} socketID - socket ID assigned by Pusher
|
|
1850
|
+
* @param {String} channelName - name of the private channel to subscribe to
|
|
1851
|
+
* @returns {Promise<{auth: String}>} signed channel authorization
|
|
1852
|
+
* @since 2.7.0
|
|
1853
|
+
*/
|
|
1854
|
+
authorizeRealtimeChannel = async (socketID, channelName) => {
|
|
1855
|
+
if (!this.userToken) {
|
|
1856
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1857
|
+
}
|
|
1858
|
+
try {
|
|
1859
|
+
const res = await this.sendRequest(
|
|
1860
|
+
"/pusher/auth",
|
|
1861
|
+
"POST",
|
|
1862
|
+
JSON.stringify({ socket_id: socketID, channel_name: channelName }),
|
|
1863
|
+
);
|
|
1864
|
+
return await res.json();
|
|
1865
|
+
} catch (err) {
|
|
1866
|
+
console.error(err);
|
|
1867
|
+
throw new SidechatAPIError(`Failed to authorize realtime channel.`);
|
|
1868
|
+
}
|
|
1869
|
+
};
|
|
1870
|
+
|
|
1871
|
+
/**
|
|
1872
|
+
* Permanently deletes the current user's account. This cannot be undone!
|
|
1873
|
+
* @method
|
|
1874
|
+
* @since 2.7.0
|
|
1875
|
+
*/
|
|
1876
|
+
deleteAccount = async () => {
|
|
1877
|
+
if (!this.userToken) {
|
|
1878
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1879
|
+
}
|
|
1880
|
+
try {
|
|
1881
|
+
const res = await this.sendRequest(
|
|
1882
|
+
"/v1/users/delete",
|
|
1883
|
+
"POST",
|
|
1884
|
+
JSON.stringify({}),
|
|
1885
|
+
);
|
|
1886
|
+
return await res.json();
|
|
1887
|
+
} catch (err) {
|
|
1888
|
+
console.error(err);
|
|
1889
|
+
throw new SidechatAPIError(`Failed to delete account.`);
|
|
1890
|
+
}
|
|
1891
|
+
};
|
|
1424
1892
|
}
|
|
1425
1893
|
|
|
1426
1894
|
export default SidechatAPIClient;
|