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
package/dist/index.cjs
CHANGED
|
@@ -2,219 +2,311 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
/**
|
|
6
|
-
* A user-created post or comment, depending on the "type" prop
|
|
7
|
-
* @typedef {Object} SidechatPostOrComment
|
|
8
|
-
* @prop {"post"|"comment"} type - whether this object represents a post or a comment on a post
|
|
9
|
-
* @prop {String} id - alphanumeric ID of post or comment
|
|
10
|
-
* @prop {Boolean} authored_by_user - whether or not the post or comment was created by the current user
|
|
11
|
-
* @prop {String} alias - post creator's name in-app
|
|
12
|
-
* @prop {String} group_id - alphanumeric ID of group
|
|
13
|
-
* @prop {SidechatGroup} group - group in which post or comment was created
|
|
14
|
-
* @prop {String} text - text content of post or comment
|
|
15
|
-
* @prop {String} created_at - date string of post or comment creation time
|
|
16
|
-
* @prop {Number} vote_total - sum of upvotes and downvotes
|
|
17
|
-
* @prop {SidechatVoteString} vote_status - current user's vote on post or comment
|
|
18
|
-
* @prop {SidechatSimpleAsset[]} assets - array of simple assets attached to post or comment
|
|
19
|
-
* @prop {
|
|
20
|
-
* @prop {Boolean} dms_disabled - whether or not you can send a DM to creator of post
|
|
21
|
-
* @prop {String[]} tags - undocumented
|
|
22
|
-
* @prop {SidechatIdentity} identity - creator's identity information
|
|
23
|
-
* @prop {Boolean} pinned - undocumented
|
|
24
|
-
* @prop {Boolean} is_saved - whether or not the current user has saved the post
|
|
25
|
-
* @prop {"following"|"not_following"} follow_status - whether or not the current user should recieve activity notifications for the post
|
|
26
|
-
* @prop {"group"} [destination] -
|
|
27
|
-
* @prop {
|
|
28
|
-
* @prop {Boolean} [
|
|
29
|
-
* @prop {
|
|
30
|
-
* @prop {
|
|
31
|
-
* @prop {
|
|
32
|
-
* @prop {String} [
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
*
|
|
39
|
-
* @
|
|
40
|
-
* @prop {String}
|
|
41
|
-
* @prop {
|
|
42
|
-
* @prop {String}
|
|
43
|
-
* @prop {"
|
|
44
|
-
* @prop {
|
|
45
|
-
* @prop {"
|
|
46
|
-
* @prop {
|
|
47
|
-
* @prop {
|
|
48
|
-
* @prop {
|
|
49
|
-
* @prop {
|
|
50
|
-
* @prop {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
*
|
|
57
|
-
* @
|
|
58
|
-
* @prop {
|
|
59
|
-
* @prop {
|
|
60
|
-
* @prop {
|
|
61
|
-
* @prop {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
*
|
|
70
|
-
* @
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
*
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
*
|
|
79
|
-
* @
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
*
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
*
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
*
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
*
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
*
|
|
103
|
-
* @
|
|
104
|
-
* @prop {
|
|
105
|
-
* @prop {
|
|
106
|
-
* @prop {
|
|
107
|
-
* @prop {
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
*
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
*
|
|
116
|
-
* @
|
|
117
|
-
* @prop {String}
|
|
118
|
-
* @prop {String}
|
|
119
|
-
* @prop {
|
|
120
|
-
* @prop {
|
|
121
|
-
* @prop {String}
|
|
122
|
-
* @prop {
|
|
123
|
-
* @prop {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
*
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
*
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
*
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
*
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
*
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
*
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
*
|
|
166
|
-
* @
|
|
167
|
-
* @prop {String}
|
|
168
|
-
* @prop {String}
|
|
169
|
-
* @prop {
|
|
170
|
-
* @prop {
|
|
171
|
-
* @prop {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
*
|
|
179
|
-
* @
|
|
180
|
-
* @prop {String}
|
|
181
|
-
* @prop {String}
|
|
182
|
-
* @prop {String}
|
|
183
|
-
* @prop {
|
|
184
|
-
* @prop {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
*
|
|
192
|
-
* @
|
|
193
|
-
* @prop {
|
|
194
|
-
* @prop {
|
|
195
|
-
* @prop {
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
*
|
|
203
|
-
* @
|
|
204
|
-
|
|
205
|
-
|
|
5
|
+
/**
|
|
6
|
+
* A user-created post or comment, depending on the "type" prop
|
|
7
|
+
* @typedef {Object} SidechatPostOrComment
|
|
8
|
+
* @prop {"post"|"comment"} type - whether this object represents a post or a comment on a post
|
|
9
|
+
* @prop {String} id - alphanumeric ID of post or comment
|
|
10
|
+
* @prop {Boolean} authored_by_user - whether or not the post or comment was created by the current user
|
|
11
|
+
* @prop {String} alias - post creator's name in-app
|
|
12
|
+
* @prop {String} group_id - alphanumeric ID of group
|
|
13
|
+
* @prop {SidechatGroup} group - group in which post or comment was created
|
|
14
|
+
* @prop {String} text - text content of post or comment
|
|
15
|
+
* @prop {String} created_at - date string of post or comment creation time
|
|
16
|
+
* @prop {Number} vote_total - sum of upvotes and downvotes
|
|
17
|
+
* @prop {SidechatVoteString} vote_status - current user's vote on post or comment
|
|
18
|
+
* @prop {SidechatSimpleAsset[]} assets - array of simple assets attached to post or comment
|
|
19
|
+
* @prop {SidechatAttachment[]} attachments - link attachments on the post
|
|
20
|
+
* @prop {Boolean} dms_disabled - whether or not you can send a DM to creator of post
|
|
21
|
+
* @prop {String[]} tags - undocumented
|
|
22
|
+
* @prop {SidechatIdentity} identity - creator's identity information
|
|
23
|
+
* @prop {Boolean} pinned - undocumented
|
|
24
|
+
* @prop {Boolean} is_saved - whether or not the current user has saved the post
|
|
25
|
+
* @prop {"following"|"following_commented"|"not_following"} follow_status - whether or not the current user should recieve activity notifications for the post
|
|
26
|
+
* @prop {"group"|"account"} [destination] - whether the post was made in a group or on the author's profile
|
|
27
|
+
* @prop {Boolean} [is_deleted] - whether or not the post or comment has been deleted
|
|
28
|
+
* @prop {{post: SidechatPostOrComment, is_unavailable: Boolean}} [quote_post] - the post being quoted, if this is a repost
|
|
29
|
+
* @prop {Number} [comment_count] - number of comments on post (only if type=post)
|
|
30
|
+
* @prop {Boolean} [comments_disabled] - whether or not you can comment on post (only if type=post)
|
|
31
|
+
* @prop {SidechatPoll} [poll] - poll attached to post (only if the post has a poll)
|
|
32
|
+
* @prop {String} [parent_post_id] - alphanumeric ID of parent post (only if type=comment)
|
|
33
|
+
* @prop {String} [reply_post_id] - alphanumeric ID of comment being replied to, falls back to parent_post_id (only if type=comment)
|
|
34
|
+
* @prop {String} [context] - text content of comment being replied to, falls back to text (only if type=comment)
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A group object, containing metadata about a group as well as its join conditions and states. Some properties vary based on the endpoint the object came from.
|
|
39
|
+
* @typedef {Object} SidechatGroup
|
|
40
|
+
* @prop {String} id - alphanumeric ID of group
|
|
41
|
+
* @prop {String} name - human-readable name of group
|
|
42
|
+
* @prop {String} analytics_name - name to file group under
|
|
43
|
+
* @prop {"non_member"|"member"} membership_type - whether or not current user is a member of group
|
|
44
|
+
* @prop {String} color - group's theme color as hex code (e.g., #FFFFFF)
|
|
45
|
+
* @prop {"open"|"closed"|"email_domain"} group_join_type - basis on which group accepts new members
|
|
46
|
+
* @prop {"private"|"public_to_all"|"public_to_schools"} group_visibility - group's visibility setting
|
|
47
|
+
* @prop {"show"|"hide"} asset_library_visibility - whether or not group's asset library is visible
|
|
48
|
+
* @prop {Array} [roles] - undocumented
|
|
49
|
+
* @prop {String} [description] - description of group
|
|
50
|
+
* @prop {SidechatPrivateAssetURL} [icon_url] - image URL for group icon
|
|
51
|
+
* @prop {Number} [member_count] - number of users in group
|
|
52
|
+
* @prop {Boolean} [should_show_leaderboard] - undocumented
|
|
53
|
+
*/
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* An asset object, containing information about an image within a post or comment
|
|
57
|
+
* @typedef {Object} SidechatSimpleAsset
|
|
58
|
+
* @prop {String} id - alphanumeric ID of asset
|
|
59
|
+
* @prop {"image"|"video"} type - whether the asset is an image or a video
|
|
60
|
+
* @prop {"jpeg"|"png"|"gif"|"webp"|"mp4"|"mov"} content_type - file type of asset
|
|
61
|
+
* @prop {Number} width - width of asset
|
|
62
|
+
* @prop {Number} height - height of asset
|
|
63
|
+
* @prop {SidechatPrivateAssetURL} [url] - URL string of asset's location (an HLS .m3u8 stream for processed videos)
|
|
64
|
+
* @prop {SidechatSimpleAsset} [thumbnail_asset] - preview image (only if type=video)
|
|
65
|
+
* @prop {"not_started"|"ingest"|"complete"|"error"} [vod_status] - processing status (only if type=video)
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* An asset object, containing information about an image from the asset library
|
|
70
|
+
* @typedef {Object} SidechatLibraryAsset
|
|
71
|
+
* @prop {String} id - alphanumeric ID of asset
|
|
72
|
+
* @prop {String} created_at - date string of asset creation time
|
|
73
|
+
* @prop {SidechatAssetMetadata} metadata - metadata associated with asset
|
|
74
|
+
* @prop {SidechatPrivateAssetURL} url - URL string of asset's location
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* An asset object, containing information about an image from the asset library
|
|
79
|
+
* @typedef {Object} SidechatAssetMetadata
|
|
80
|
+
* @prop {Number} width - width of asset
|
|
81
|
+
* @prop {Number} height - height of asset
|
|
82
|
+
* @prop {"image"} type - undocumented
|
|
83
|
+
* @prop {"jpeg"|"png"|"gif"} content_type - file type of asset
|
|
84
|
+
*/
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* A user's anonymous identity information
|
|
88
|
+
* @typedef {Object} SidechatIdentity
|
|
89
|
+
* @prop {String} name - representation of user's name (varies across app)
|
|
90
|
+
* @prop {Boolean} posted_with_username - undocumented
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* A conversation icon associated with a user
|
|
95
|
+
* @typedef {Object} SidechatIcon
|
|
96
|
+
* @prop {String} emoji - unicode emoji character
|
|
97
|
+
* @prop {String} color - primary hex color code
|
|
98
|
+
* @prop {String} secondary_color - secondary hex color code
|
|
99
|
+
*/
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* The current user's information
|
|
103
|
+
* @typedef {Object} SidechatCurrentUser
|
|
104
|
+
* @prop {String} id - alphanumeric ID of current user
|
|
105
|
+
* @prop {String} hashedVerifiedEmail - verified email of current user in an unreadable hashed form
|
|
106
|
+
* @prop {Boolean} isGlobalModerator - whether or not user is a moderator
|
|
107
|
+
* @prop {Boolean} isGlobalAdmin - whether or not user is an admin
|
|
108
|
+
* @prop {SidechatMembership[]} memberships
|
|
109
|
+
* @prop {Array} roles - undocumented
|
|
110
|
+
* @prop {String} emailDomain - domain of verified email address on account
|
|
111
|
+
* @prop {String} wildcardEmailDomain - domain of verified email address on account, preceeded by *. to support subdomains
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* A user's public profile
|
|
116
|
+
* @typedef {Object} SidechatProfile
|
|
117
|
+
* @prop {String} id - alphanumeric ID of user
|
|
118
|
+
* @prop {String} name - public-facing username
|
|
119
|
+
* @prop {SidechatIcon} conversation_icon - icon associated with user
|
|
120
|
+
* @prop {Boolean} description - the user bio
|
|
121
|
+
* @prop {String} index_name - undocumented
|
|
122
|
+
* @prop {String} analytics_name - undocumented
|
|
123
|
+
* @prop {String} color - undocumented
|
|
124
|
+
* @prop {String} share_color_start - undocumented
|
|
125
|
+
* @prop {String} share_color_end - undocumented
|
|
126
|
+
* @prop {"account"} group_join_type - undocumented
|
|
127
|
+
* @prop {"public_to_all"} group_visibility - the profile visibility status
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Representation of a group membership
|
|
132
|
+
* @typedef {Object} SidechatMembership
|
|
133
|
+
* @prop {String} groupId - alphanumeric ID of group
|
|
134
|
+
* @prop {String} type - role of current user in group
|
|
135
|
+
*/
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* An asset URL that can only be accessed by making a request with a user's bearer token attached in the Authorization header
|
|
139
|
+
* @typedef {String} SidechatPrivateAssetURL
|
|
140
|
+
*/
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* A cursor for paginating through post lists
|
|
144
|
+
* @typedef {String} SidechatCursorString
|
|
145
|
+
*/
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* A vote on a comment or post
|
|
149
|
+
* @typedef {"upvote"|"downvote"|"none"} SidechatVoteString
|
|
150
|
+
*/
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* A user's bearer authentication token needed for most requests
|
|
154
|
+
* @typedef {String} SidechatAuthToken
|
|
155
|
+
*/
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* A list of posts and the associated cursor
|
|
159
|
+
* @typedef {Object} SidechatPostsAndCursor
|
|
160
|
+
* @prop {SidechatPostOrComment[]} posts
|
|
161
|
+
* @prop {SidechatCursorString} cursor
|
|
162
|
+
*/
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* A direct message thread
|
|
166
|
+
* @typedef {Object} SidechatDirectThread
|
|
167
|
+
* @prop {String} id - alphanumeric ID of thread
|
|
168
|
+
* @prop {String} group_id - alphanumeric ID of group in which the thread exists
|
|
169
|
+
* @prop {String} updated_at - date string of when the last message in the chat was sent
|
|
170
|
+
* @prop {String} post_id - post or comment from which the thread was originally sent
|
|
171
|
+
* @prop {String} post_context - the context of the DM thread (only "feed" is known at the moment)
|
|
172
|
+
* @prop {"accepted"} accept_status - whether or not the other user has accepted this DM
|
|
173
|
+
* @prop {"post"|"comment"} type - the type of the content from which the DM was originally sent
|
|
174
|
+
* @prop {SidechatDirectMessage[]} messages - array of direct message objects
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* A single direct message
|
|
179
|
+
* @typedef {Object} SidechatDirectMessage
|
|
180
|
+
* @prop {String} created_at - time at which the message was sent
|
|
181
|
+
* @prop {String} client_id - alphanumeric ID of the device the message was sent on
|
|
182
|
+
* @prop {String} obfuscatedUserId - obfuscated version of the sender's alphanumeric ID
|
|
183
|
+
* @prop {String} text - body text of the message
|
|
184
|
+
* @prop {String} id - alphanumeric ID of the message
|
|
185
|
+
* @prop {String} chat_id - alphanumeric ID of the thread in which the message resides
|
|
186
|
+
* @prop {Boolean} authored_by_user - whether or not the current user sent the message
|
|
187
|
+
* @prop {"message"} type - undocumented
|
|
188
|
+
*/
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Represents a poll with choices
|
|
192
|
+
* @typedef {Object} SidechatPoll
|
|
193
|
+
* @prop {String} id - alphanumeric ID of poll
|
|
194
|
+
* @prop {String} post_id - alphanumeric ID of post to which poll is attached
|
|
195
|
+
* @prop {SidechatPollChoice[]} choices - array of poll choices
|
|
196
|
+
* @prop {Boolean} allows_view_results - whether or not poll results are publicly visible
|
|
197
|
+
* @prop {Number} view_results_count - number of users who have viewed poll results
|
|
198
|
+
* @prop {Boolean} participated - whether or not current user has voted in poll
|
|
199
|
+
*/
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Represents a poll choice
|
|
203
|
+
* @typedef {Object} SidechatPollChoice
|
|
204
|
+
* @prop {Number} count - number of votes for choice
|
|
205
|
+
* @prop {String} text - user-visible text of choice
|
|
206
|
+
* @prop {Boolean} selected - whether or not current user has voted for choice
|
|
207
|
+
*/
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* A link attachment on a post
|
|
211
|
+
* @typedef {Object} SidechatAttachment
|
|
212
|
+
* @prop {String} id - alphanumeric ID of attachment
|
|
213
|
+
* @prop {"link"|"youtube"} type - whether the link is a regular link or a YouTube video
|
|
214
|
+
* @prop {String} link_url - URL the attachment points to
|
|
215
|
+
* @prop {String} [display_url] - shortened URL for display
|
|
216
|
+
* @prop {String} [title] - title of the linked page
|
|
217
|
+
* @prop {{id: String, url: String, width: Number, height: Number, content_type: "png"|"gif"}} [asset] - preview image of the linked page
|
|
218
|
+
*/
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* A page of the home feed
|
|
222
|
+
* @typedef {Object} SidechatFeed
|
|
223
|
+
* @prop {SidechatFeedItem[]} feed_items - items in the feed
|
|
224
|
+
* @prop {SidechatCursorString} cursor
|
|
225
|
+
*/
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* A single item in the home feed
|
|
229
|
+
* @typedef {Object} SidechatFeedItem
|
|
230
|
+
* @prop {String} item_type - type of item (posts have a type of "post")
|
|
231
|
+
* @prop {SidechatPostOrComment} [post] - the post, if this item is a post
|
|
232
|
+
*/
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* A page of the user's activity
|
|
236
|
+
* @typedef {Object} SidechatActivityList
|
|
237
|
+
* @prop {SidechatActivityItem[]} items - activity items
|
|
238
|
+
* @prop {SidechatCursorString} cursor
|
|
239
|
+
*/
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* A single activity item (in-app notification)
|
|
243
|
+
* @typedef {Object} SidechatActivityItem
|
|
244
|
+
* @prop {String} id - alphanumeric ID of activity item
|
|
245
|
+
* @prop {String} type - kind of activity (e.g. "comment", "comment_reply", "votes", "new_follower", "quote", "trending_post")
|
|
246
|
+
* @prop {String} text - user-facing description of the activity
|
|
247
|
+
* @prop {String} timestamp - date string of when the activity happened
|
|
248
|
+
* @prop {Boolean} is_seen - whether or not the user has seen the activity
|
|
249
|
+
* @prop {String} [post_id] - alphanumeric ID of related post
|
|
250
|
+
* @prop {String} [comment_id] - alphanumeric ID of related comment
|
|
251
|
+
* @prop {String} [group_id] - alphanumeric ID of related group
|
|
252
|
+
* @prop {Number} [yakarma] - yakarma gained
|
|
253
|
+
* @prop {String} [username] - username of the other user involved, if any
|
|
254
|
+
*/
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* A group leaderboard and the current user's place in it
|
|
258
|
+
* @typedef {Object} SidechatLeaderboard
|
|
259
|
+
* @prop {Array<{value: Number}>} leaderboard - all-time leaderboard entries
|
|
260
|
+
* @prop {Array<{value: Number}>} season_leaderboard - leaderboard entries for the current season
|
|
261
|
+
* @prop {{year: Number, season: String, remaining_days: Number}} season - the current season
|
|
262
|
+
* @prop {SidechatKarma} karma - current user's all-time karma in the group
|
|
263
|
+
* @prop {SidechatKarma} season_karma - current user's karma this season
|
|
264
|
+
*/
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* A user's karma within a group
|
|
268
|
+
* @typedef {Object} SidechatKarma
|
|
269
|
+
* @prop {String} group_id - alphanumeric ID of group
|
|
270
|
+
* @prop {Number} post - karma from posts
|
|
271
|
+
* @prop {Number} comment - karma from comments
|
|
272
|
+
* @prop {Number} yakarma - total karma
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Which push notifications a user receives
|
|
277
|
+
* @typedef {Object} SidechatNotificationPreferences
|
|
278
|
+
* @prop {Boolean} [chats] - direct messages
|
|
279
|
+
* @prop {Boolean} [followed_posts_activity] - new comments on followed posts
|
|
280
|
+
* @prop {Boolean} [new_followers] - new followers
|
|
281
|
+
* @prop {Boolean} [post_activity] - comments and votes on the user's own posts
|
|
282
|
+
* @prop {Boolean} [trending] - trending posts
|
|
283
|
+
* @prop {Boolean} [community_activity] - undocumented
|
|
284
|
+
* @prop {Boolean} [leaderboards] - leaderboard updates
|
|
285
|
+
* @prop {Boolean} [rewards] - undocumented
|
|
286
|
+
* @prop {Boolean} [feature_updates] - announcements about new features
|
|
287
|
+
* @prop {Boolean} [yak_ball_updates] - undocumented
|
|
288
|
+
* @prop {Boolean} [game_reminders] - undocumented
|
|
289
|
+
* @prop {Boolean} [daily_game_reminders] - undocumented
|
|
290
|
+
* @prop {Boolean} [game_invitations] - undocumented
|
|
291
|
+
* @prop {Boolean} [game_match_updates] - undocumented
|
|
292
|
+
*/
|
|
293
|
+
/**
|
|
294
|
+
* A reason for reporting a post, comment, or direct message thread
|
|
295
|
+
* @typedef {"username"|"spam"|"offTopic"|"pii"|"selfHarmDangerousActs"|"illegalActivities"|"offensiveHateSpeech"|"harassmentBullying"|"minorSafety"|"sexualContent"|"violentGraphicContent"|"misinformation"|"other"} SidechatReportReason
|
|
296
|
+
*/
|
|
297
|
+
|
|
206
298
|
var SidechatTypes = {};
|
|
207
299
|
|
|
208
|
-
/**
|
|
209
|
-
* Throwable error caused by the Sidechat API
|
|
210
|
-
* @class
|
|
211
|
-
* @extends Error
|
|
212
|
-
*/
|
|
213
|
-
class SidechatAPIError extends Error {
|
|
214
|
-
constructor(message) {
|
|
215
|
-
super(message);
|
|
216
|
-
this.name = "SidechatAPIError";
|
|
217
|
-
}
|
|
300
|
+
/**
|
|
301
|
+
* Throwable error caused by the Sidechat API
|
|
302
|
+
* @class
|
|
303
|
+
* @extends Error
|
|
304
|
+
*/
|
|
305
|
+
class SidechatAPIError extends Error {
|
|
306
|
+
constructor(message) {
|
|
307
|
+
super(message);
|
|
308
|
+
this.name = "SidechatAPIError";
|
|
309
|
+
}
|
|
218
310
|
}
|
|
219
311
|
|
|
220
312
|
/** @import * as types from "../types/SidechatTypes.js" */
|
|
@@ -284,6 +376,16 @@ class SidechatAPIClient {
|
|
|
284
376
|
this.apiRoot = url;
|
|
285
377
|
};
|
|
286
378
|
|
|
379
|
+
/**
|
|
380
|
+
* 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.
|
|
381
|
+
* @method
|
|
382
|
+
* @param {String} deviceIdentifier - stable identifier for this device
|
|
383
|
+
* @since 2.7.0
|
|
384
|
+
*/
|
|
385
|
+
setDeviceIdentifier = (deviceIdentifier) => {
|
|
386
|
+
this.defaultHeaders["X-Device-ID"] = deviceIdentifier;
|
|
387
|
+
};
|
|
388
|
+
|
|
287
389
|
/**
|
|
288
390
|
* Run an arbitrary API request using the current client's authentication
|
|
289
391
|
* @method
|
|
@@ -299,7 +401,7 @@ class SidechatAPIClient {
|
|
|
299
401
|
method = "GET",
|
|
300
402
|
body = undefined,
|
|
301
403
|
headers = {},
|
|
302
|
-
stripHeaders = false
|
|
404
|
+
stripHeaders = false,
|
|
303
405
|
) => {
|
|
304
406
|
let requestHeaders = this.defaultHeaders;
|
|
305
407
|
if (stripHeaders) {
|
|
@@ -314,19 +416,32 @@ class SidechatAPIClient {
|
|
|
314
416
|
};
|
|
315
417
|
|
|
316
418
|
/**
|
|
317
|
-
* Initiate the login process with a phone number. Should be followed up with verifySMSCode().
|
|
419
|
+
* 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.
|
|
318
420
|
* @method
|
|
319
421
|
* @since 1.0.0
|
|
320
422
|
* @param {Number} phoneNumber - US phone number (WITHOUT +1) to send verification code to
|
|
423
|
+
* @param {Boolean} [useFallback] - send the code through the backup SMS route, which the official app offers when a code doesn't arrive
|
|
424
|
+
* @param {String} [captchaMethod] - type of captcha being answered
|
|
425
|
+
* @param {String} [captchaResponse] - solved captcha token
|
|
321
426
|
*/
|
|
322
|
-
loginViaSMS = async (
|
|
427
|
+
loginViaSMS = async (
|
|
428
|
+
phoneNumber,
|
|
429
|
+
useFallback = false,
|
|
430
|
+
captchaMethod = undefined,
|
|
431
|
+
captchaResponse = undefined,
|
|
432
|
+
) => {
|
|
323
433
|
try {
|
|
324
|
-
const
|
|
434
|
+
const endpoint = useFallback
|
|
435
|
+
? "/v1/login_register_sms_fallback"
|
|
436
|
+
: "/v1/login_register";
|
|
437
|
+
const res = await fetch(`${this.apiRoot}${endpoint}`, {
|
|
325
438
|
method: "POST",
|
|
326
439
|
headers: this.defaultHeaders,
|
|
327
440
|
body: JSON.stringify({
|
|
328
441
|
phone_number: `+1${phoneNumber}`,
|
|
329
442
|
version: 3,
|
|
443
|
+
captcha_method: captchaMethod,
|
|
444
|
+
captcha_response: captchaResponse,
|
|
330
445
|
}),
|
|
331
446
|
});
|
|
332
447
|
const json = await res.json();
|
|
@@ -371,8 +486,15 @@ class SidechatAPIClient {
|
|
|
371
486
|
* @since 1.0.0
|
|
372
487
|
* @param {Number} age - user's age in years
|
|
373
488
|
* @param {String} registrationID - the registration ID generated by verifySMSCode()
|
|
489
|
+
* @param {String} [timeZone] - time zone of the user (e.g. "America/Chicago"). Falls back to the system time zone.
|
|
490
|
+
* @param {String} [inviteLinkURL] - group invite link that the user signed up through
|
|
374
491
|
*/
|
|
375
|
-
setAge = async (
|
|
492
|
+
setAge = async (
|
|
493
|
+
age,
|
|
494
|
+
registrationID,
|
|
495
|
+
timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone,
|
|
496
|
+
inviteLinkURL = undefined,
|
|
497
|
+
) => {
|
|
376
498
|
if (age < 13) {
|
|
377
499
|
throw new SidechatAPIError("You're too young to use Offsides.");
|
|
378
500
|
}
|
|
@@ -383,6 +505,9 @@ class SidechatAPIClient {
|
|
|
383
505
|
body: JSON.stringify({
|
|
384
506
|
age: Number(age),
|
|
385
507
|
registration_id: registrationID,
|
|
508
|
+
time_zone: timeZone,
|
|
509
|
+
invite_link_url: inviteLinkURL,
|
|
510
|
+
device_id: this.defaultHeaders["X-Device-ID"],
|
|
386
511
|
}),
|
|
387
512
|
});
|
|
388
513
|
const json = await res.json();
|
|
@@ -465,8 +590,9 @@ class SidechatAPIClient {
|
|
|
465
590
|
* @method
|
|
466
591
|
* @since 1.0.0
|
|
467
592
|
* @param {String} deviceId - the device ID to set
|
|
593
|
+
* @param {"com.flowerave.sidechat"|"com.flowerave.yikyak"} [bundleID] - bundle ID of the app the push token belongs to
|
|
468
594
|
*/
|
|
469
|
-
setDeviceID = async (deviceID) => {
|
|
595
|
+
setDeviceID = async (deviceID, bundleID = "com.flowerave.sidechat") => {
|
|
470
596
|
if (!this.userToken) {
|
|
471
597
|
throw new SidechatAPIError("User is not authenticated.");
|
|
472
598
|
}
|
|
@@ -479,7 +605,7 @@ class SidechatAPIClient {
|
|
|
479
605
|
},
|
|
480
606
|
body: JSON.stringify({
|
|
481
607
|
build_type: "release",
|
|
482
|
-
bundle_id:
|
|
608
|
+
bundle_id: bundleID,
|
|
483
609
|
device_token: deviceID,
|
|
484
610
|
}),
|
|
485
611
|
});
|
|
@@ -522,7 +648,7 @@ class SidechatAPIClient {
|
|
|
522
648
|
...this.defaultHeaders,
|
|
523
649
|
Authorization: `Bearer ${this.userToken}`,
|
|
524
650
|
},
|
|
525
|
-
}
|
|
651
|
+
},
|
|
526
652
|
);
|
|
527
653
|
const json = await res.json();
|
|
528
654
|
return json;
|
|
@@ -539,23 +665,27 @@ class SidechatAPIClient {
|
|
|
539
665
|
* @param {String} groupID - group ID
|
|
540
666
|
* @param {"hot"|"recent"|"top"} category - category to filter posts
|
|
541
667
|
* @param {types.SidechatCursorString} [cursor] - cursor string
|
|
668
|
+
* @param {"day"|"week"|"month"|"year"|"all_time"} [period] - time period to pull top posts from (only if category is "top")
|
|
542
669
|
* @returns {Promise<types.SidechatPostsAndCursor>} List of posts and cursor
|
|
543
670
|
*/
|
|
544
|
-
getGroupPosts = async (groupID, category = "hot", cursor) => {
|
|
671
|
+
getGroupPosts = async (groupID, category = "hot", cursor, period) => {
|
|
545
672
|
if (!this.userToken) {
|
|
546
673
|
throw new SidechatAPIError("User is not authenticated.");
|
|
547
674
|
}
|
|
548
675
|
try {
|
|
549
676
|
const res = await fetch(
|
|
550
|
-
`${this.apiRoot}/v1/posts?${
|
|
551
|
-
|
|
677
|
+
`${this.apiRoot}/v1/posts?${
|
|
678
|
+
cursor ? "cursor=" + encodeURIComponent(cursor) + "&" : ""
|
|
679
|
+
}${
|
|
680
|
+
period ? "period=" + period + "&" : ""
|
|
681
|
+
}group_id=${groupID}&type=${category}&cacheBust=${Date.now()}`,
|
|
552
682
|
{
|
|
553
683
|
method: "GET",
|
|
554
684
|
headers: {
|
|
555
685
|
...this.defaultHeaders,
|
|
556
686
|
Authorization: `Bearer ${this.userToken}`,
|
|
557
687
|
},
|
|
558
|
-
}
|
|
688
|
+
},
|
|
559
689
|
);
|
|
560
690
|
const json = await res.json();
|
|
561
691
|
return json;
|
|
@@ -610,14 +740,14 @@ class SidechatAPIClient {
|
|
|
610
740
|
}
|
|
611
741
|
try {
|
|
612
742
|
const res = await fetch(
|
|
613
|
-
`${this.apiRoot}/v1/posts/get?include_deleted=${includeDeleted}&post_id=${postID}`,
|
|
743
|
+
`${this.apiRoot}/v1/posts/get?include_deleted=${includeDeleted}&post_id=${postID}&cacheBust=${Date.now()}`,
|
|
614
744
|
{
|
|
615
745
|
method: "GET",
|
|
616
746
|
headers: {
|
|
617
747
|
...this.defaultHeaders,
|
|
618
748
|
Authorization: `Bearer ${this.userToken}`,
|
|
619
749
|
},
|
|
620
|
-
}
|
|
750
|
+
},
|
|
621
751
|
);
|
|
622
752
|
const json = await res.json();
|
|
623
753
|
return json.post;
|
|
@@ -644,7 +774,7 @@ class SidechatAPIClient {
|
|
|
644
774
|
contentType = "my_comments";
|
|
645
775
|
}
|
|
646
776
|
try {
|
|
647
|
-
const res = await fetch(`${this.apiRoot}/v1/posts
|
|
777
|
+
const res = await fetch(`${this.apiRoot}/v1/posts?type=${contentType}`, {
|
|
648
778
|
method: "GET",
|
|
649
779
|
headers: {
|
|
650
780
|
...this.defaultHeaders,
|
|
@@ -672,14 +802,14 @@ class SidechatAPIClient {
|
|
|
672
802
|
}
|
|
673
803
|
try {
|
|
674
804
|
const res = await fetch(
|
|
675
|
-
`${this.apiRoot}/v1/posts/comments/?post_id=${postID}`,
|
|
805
|
+
`${this.apiRoot}/v1/posts/comments/?post_id=${postID}&cacheBust=${Date.now()}`,
|
|
676
806
|
{
|
|
677
807
|
method: "GET",
|
|
678
808
|
headers: {
|
|
679
809
|
...this.defaultHeaders,
|
|
680
810
|
Authorization: `Bearer ${this.userToken}`,
|
|
681
811
|
},
|
|
682
|
-
}
|
|
812
|
+
},
|
|
683
813
|
);
|
|
684
814
|
const json = await res.json();
|
|
685
815
|
// Function to preprocess the comments and organize them into a nested structure
|
|
@@ -775,13 +905,16 @@ class SidechatAPIClient {
|
|
|
775
905
|
throw new SidechatAPIError("User is not authenticated.");
|
|
776
906
|
}
|
|
777
907
|
try {
|
|
778
|
-
const res = await fetch(
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
908
|
+
const res = await fetch(
|
|
909
|
+
`${this.apiRoot}/v1/groups/explore/search?term=${encodeURIComponent(query)}`,
|
|
910
|
+
{
|
|
911
|
+
method: "GET",
|
|
912
|
+
headers: {
|
|
913
|
+
...this.defaultHeaders,
|
|
914
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
915
|
+
},
|
|
783
916
|
},
|
|
784
|
-
|
|
917
|
+
);
|
|
785
918
|
const json = await res.json();
|
|
786
919
|
return await json.results;
|
|
787
920
|
} catch (err) {
|
|
@@ -881,8 +1014,9 @@ class SidechatAPIClient {
|
|
|
881
1014
|
throw new SidechatAPIError("User is not authenticated.");
|
|
882
1015
|
}
|
|
883
1016
|
try {
|
|
1017
|
+
// Joining moved to the v2 endpoint, which takes a list of IDs. Leave still sends group_id by itself, no list.
|
|
884
1018
|
const res = await fetch(
|
|
885
|
-
`${this.apiRoot}
|
|
1019
|
+
`${this.apiRoot}${isMember ? "/v2/groups/join" : "/v1/groups/leave"}`,
|
|
886
1020
|
{
|
|
887
1021
|
method: "POST",
|
|
888
1022
|
headers: {
|
|
@@ -890,9 +1024,10 @@ class SidechatAPIClient {
|
|
|
890
1024
|
Authorization: `Bearer ${this.userToken}`,
|
|
891
1025
|
},
|
|
892
1026
|
body: JSON.stringify({
|
|
893
|
-
group_id: groupID,
|
|
1027
|
+
group_id: isMember ? undefined : groupID,
|
|
1028
|
+
group_ids: [groupID],
|
|
894
1029
|
}),
|
|
895
|
-
}
|
|
1030
|
+
},
|
|
896
1031
|
);
|
|
897
1032
|
const json = await res.json();
|
|
898
1033
|
return await json;
|
|
@@ -924,7 +1059,7 @@ class SidechatAPIClient {
|
|
|
924
1059
|
topLevelReplyID,
|
|
925
1060
|
assetList = [],
|
|
926
1061
|
disableDMs = false,
|
|
927
|
-
anonymous = false
|
|
1062
|
+
anonymous = false,
|
|
928
1063
|
) => {
|
|
929
1064
|
if (!this.userToken) {
|
|
930
1065
|
throw new SidechatAPIError("User is not authenticated.");
|
|
@@ -949,15 +1084,17 @@ class SidechatAPIClient {
|
|
|
949
1084
|
}),
|
|
950
1085
|
});
|
|
951
1086
|
const json = await res.json();
|
|
1087
|
+
if (!res.ok) throw new SidechatAPIError(json.message);
|
|
952
1088
|
return await json.comment;
|
|
953
1089
|
} catch (err) {
|
|
954
1090
|
console.error(err);
|
|
1091
|
+
if (err instanceof SidechatAPIError && err.message) throw err;
|
|
955
1092
|
throw new SidechatAPIError(`Failed to post comment.`);
|
|
956
1093
|
}
|
|
957
1094
|
};
|
|
958
1095
|
|
|
959
1096
|
/**
|
|
960
|
-
* Creates a new post in the specified group
|
|
1097
|
+
* 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.
|
|
961
1098
|
* @method
|
|
962
1099
|
* @since 2.2.0
|
|
963
1100
|
* @param {String} text - text content of comment
|
|
@@ -967,6 +1104,7 @@ class SidechatAPIClient {
|
|
|
967
1104
|
* @param {Boolean} [disableComments] - whether or not comments should be disabled on post
|
|
968
1105
|
* @param {Boolean} [anonymous] - whether or not to hide user's name and icon on post
|
|
969
1106
|
* @param {Array<String>} [pollOptions] - List of poll options. If provided, a poll will be created with these options.
|
|
1107
|
+
* @param {Array<String>} [attachmentIDs] - IDs of link attachments created with createLinkAttachment()
|
|
970
1108
|
* @returns {Promise<types.SidechatPostOrComment>} the created post
|
|
971
1109
|
*/
|
|
972
1110
|
createPost = async (
|
|
@@ -977,7 +1115,8 @@ class SidechatAPIClient {
|
|
|
977
1115
|
disableComments = false,
|
|
978
1116
|
anonymous = false,
|
|
979
1117
|
repostId = undefined,
|
|
980
|
-
pollOptions = undefined
|
|
1118
|
+
pollOptions = undefined,
|
|
1119
|
+
attachmentIDs = [],
|
|
981
1120
|
) => {
|
|
982
1121
|
if (!this.userToken) {
|
|
983
1122
|
throw new SidechatAPIError("User is not authenticated.");
|
|
@@ -989,17 +1128,17 @@ class SidechatAPIClient {
|
|
|
989
1128
|
assets: assetList,
|
|
990
1129
|
group_ids: [groupID],
|
|
991
1130
|
text: text,
|
|
992
|
-
attachments:
|
|
1131
|
+
attachments: attachmentIDs,
|
|
993
1132
|
dms_disabled: disableDMs,
|
|
994
1133
|
comments_disabled: disableComments,
|
|
995
1134
|
using_identity: !anonymous,
|
|
996
|
-
quote_post_id: repostId
|
|
1135
|
+
quote_post_id: repostId,
|
|
997
1136
|
};
|
|
998
1137
|
// If pollOptions is provided and is a non-empty array, add poll_request
|
|
999
1138
|
if (Array.isArray(pollOptions) && pollOptions.length > 0) {
|
|
1000
1139
|
body.poll_request = {
|
|
1001
1140
|
allows_view_results: true,
|
|
1002
|
-
choices: pollOptions
|
|
1141
|
+
choices: pollOptions,
|
|
1003
1142
|
};
|
|
1004
1143
|
}
|
|
1005
1144
|
const res = await fetch(`${this.apiRoot}/v1/posts`, {
|
|
@@ -1011,9 +1150,11 @@ class SidechatAPIClient {
|
|
|
1011
1150
|
body: JSON.stringify(body),
|
|
1012
1151
|
});
|
|
1013
1152
|
const json = await res.json();
|
|
1153
|
+
if (!res.ok) throw new SidechatAPIError(json.message);
|
|
1014
1154
|
return await json.posts[0];
|
|
1015
1155
|
} catch (err) {
|
|
1016
1156
|
console.error(err);
|
|
1157
|
+
if (err instanceof SidechatAPIError && err.message) throw err;
|
|
1017
1158
|
throw new SidechatAPIError(`Failed to make post.`);
|
|
1018
1159
|
}
|
|
1019
1160
|
};
|
|
@@ -1089,16 +1230,19 @@ class SidechatAPIClient {
|
|
|
1089
1230
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1090
1231
|
}
|
|
1091
1232
|
try {
|
|
1092
|
-
const res = await fetch(
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1233
|
+
const res = await fetch(
|
|
1234
|
+
`${this.apiRoot}/v1/polls/view_results?cacheBust=${Date.now()}`,
|
|
1235
|
+
{
|
|
1236
|
+
method: "POST",
|
|
1237
|
+
headers: {
|
|
1238
|
+
...this.defaultHeaders,
|
|
1239
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
1240
|
+
},
|
|
1241
|
+
body: JSON.stringify({
|
|
1242
|
+
poll_id: pollId,
|
|
1243
|
+
}),
|
|
1097
1244
|
},
|
|
1098
|
-
|
|
1099
|
-
poll_id: pollId,
|
|
1100
|
-
}),
|
|
1101
|
-
});
|
|
1245
|
+
);
|
|
1102
1246
|
const json = await res.json();
|
|
1103
1247
|
return await json;
|
|
1104
1248
|
} catch (err) {
|
|
@@ -1108,22 +1252,27 @@ class SidechatAPIClient {
|
|
|
1108
1252
|
};
|
|
1109
1253
|
|
|
1110
1254
|
/**
|
|
1111
|
-
* Uploads an asset to AWS S3 for use in posts and comments.
|
|
1255
|
+
* 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)
|
|
1112
1256
|
* @method
|
|
1113
1257
|
* @param {String} uri - URI of the asset to upload
|
|
1114
|
-
* @param {String} mimeType - mimetype of the asset (e.g. "image/png")
|
|
1258
|
+
* @param {String} mimeType - mimetype of the asset (e.g. "image/png" or "video/mp4")
|
|
1115
1259
|
* @param {String} [name] - filename of the asset
|
|
1260
|
+
* @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.
|
|
1116
1261
|
* @returns {Promise<String>} URL of the uploaded asset
|
|
1117
1262
|
* @since 2.5.1
|
|
1118
1263
|
*/
|
|
1119
|
-
uploadAsset = async (uri, mimeType, name = "") => {
|
|
1264
|
+
uploadAsset = async (uri, mimeType, name = "", context = undefined) => {
|
|
1120
1265
|
if (!this.userToken) {
|
|
1121
1266
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1122
1267
|
}
|
|
1123
1268
|
|
|
1124
1269
|
let imageType = mimeType.split("/")[1];
|
|
1125
|
-
if (
|
|
1126
|
-
|
|
1270
|
+
if (imageType == "quicktime") imageType = "mov";
|
|
1271
|
+
if (!["png", "jpeg", "gif", "webp", "mp4", "mov"].includes(imageType)) {
|
|
1272
|
+
throw new SidechatAPIError("Unsupported file format.");
|
|
1273
|
+
}
|
|
1274
|
+
if (!context && ["mp4", "mov"].includes(imageType)) {
|
|
1275
|
+
context = "post_vod_source";
|
|
1127
1276
|
}
|
|
1128
1277
|
|
|
1129
1278
|
const data = new FormData();
|
|
@@ -1133,7 +1282,11 @@ class SidechatAPIClient {
|
|
|
1133
1282
|
uri: uri,
|
|
1134
1283
|
});
|
|
1135
1284
|
|
|
1136
|
-
const urlReq = await this.sendRequest(
|
|
1285
|
+
const urlReq = await this.sendRequest(
|
|
1286
|
+
`/v1/assets/upload_url?content_type=${imageType}${
|
|
1287
|
+
context ? "&context=" + context : ""
|
|
1288
|
+
}`,
|
|
1289
|
+
);
|
|
1137
1290
|
const urlJson = await urlReq.json();
|
|
1138
1291
|
|
|
1139
1292
|
try {
|
|
@@ -1148,7 +1301,7 @@ class SidechatAPIClient {
|
|
|
1148
1301
|
return `${this.apiRoot}/v1/assets/library/${urlJson.asset_id}`;
|
|
1149
1302
|
} else {
|
|
1150
1303
|
throw new SidechatAPIError(
|
|
1151
|
-
`Couldn't upload image - error ${uploadReq.status}
|
|
1304
|
+
`Couldn't upload image - error ${uploadReq.status}`,
|
|
1152
1305
|
);
|
|
1153
1306
|
}
|
|
1154
1307
|
} catch (e) {
|
|
@@ -1214,7 +1367,7 @@ class SidechatAPIClient {
|
|
|
1214
1367
|
Authorization: `Bearer ${this.userToken}`,
|
|
1215
1368
|
},
|
|
1216
1369
|
body: JSON.stringify({
|
|
1217
|
-
bio: bio
|
|
1370
|
+
bio: bio,
|
|
1218
1371
|
}),
|
|
1219
1372
|
});
|
|
1220
1373
|
const json = await res.json();
|
|
@@ -1245,7 +1398,7 @@ class SidechatAPIClient {
|
|
|
1245
1398
|
...this.defaultHeaders,
|
|
1246
1399
|
Authorization: `Bearer ${this.userToken}`,
|
|
1247
1400
|
},
|
|
1248
|
-
}
|
|
1401
|
+
},
|
|
1249
1402
|
);
|
|
1250
1403
|
if (res?.status == 200 || res?.status == 204) {
|
|
1251
1404
|
return true;
|
|
@@ -1300,13 +1453,16 @@ class SidechatAPIClient {
|
|
|
1300
1453
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1301
1454
|
}
|
|
1302
1455
|
try {
|
|
1303
|
-
const res = await fetch(
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1456
|
+
const res = await fetch(
|
|
1457
|
+
`${this.apiRoot}/v1/groups/username?username=${username}&cacheBust=${Date.now()}`,
|
|
1458
|
+
{
|
|
1459
|
+
method: "GET",
|
|
1460
|
+
headers: {
|
|
1461
|
+
...this.defaultHeaders,
|
|
1462
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
1463
|
+
},
|
|
1464
|
+
},
|
|
1465
|
+
);
|
|
1310
1466
|
const json = await res.json();
|
|
1311
1467
|
return await json.group;
|
|
1312
1468
|
} catch (err) {
|
|
@@ -1327,13 +1483,16 @@ class SidechatAPIClient {
|
|
|
1327
1483
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1328
1484
|
}
|
|
1329
1485
|
try {
|
|
1330
|
-
const res = await fetch(
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1486
|
+
const res = await fetch(
|
|
1487
|
+
`${this.apiRoot}/v1/users/posts?username=${username}`,
|
|
1488
|
+
{
|
|
1489
|
+
method: "GET",
|
|
1490
|
+
headers: {
|
|
1491
|
+
...this.defaultHeaders,
|
|
1492
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
1493
|
+
},
|
|
1494
|
+
},
|
|
1495
|
+
);
|
|
1337
1496
|
const json = await res.json();
|
|
1338
1497
|
return await json.posts;
|
|
1339
1498
|
} catch (err) {
|
|
@@ -1381,13 +1540,16 @@ class SidechatAPIClient {
|
|
|
1381
1540
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1382
1541
|
}
|
|
1383
1542
|
try {
|
|
1384
|
-
const res = await fetch(
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1543
|
+
const res = await fetch(
|
|
1544
|
+
`${this.apiRoot}/v1/chats/explore?cacheBust=${Date.now()}`,
|
|
1545
|
+
{
|
|
1546
|
+
method: "GET",
|
|
1547
|
+
headers: {
|
|
1548
|
+
...this.defaultHeaders,
|
|
1549
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
1550
|
+
},
|
|
1389
1551
|
},
|
|
1390
|
-
|
|
1552
|
+
);
|
|
1391
1553
|
const json = await res.json();
|
|
1392
1554
|
return await json.chats;
|
|
1393
1555
|
} catch (err) {
|
|
@@ -1411,7 +1573,7 @@ class SidechatAPIClient {
|
|
|
1411
1573
|
displayName,
|
|
1412
1574
|
emoji,
|
|
1413
1575
|
primaryColor,
|
|
1414
|
-
secondaryColor
|
|
1576
|
+
secondaryColor,
|
|
1415
1577
|
) => {
|
|
1416
1578
|
if (!this.userToken) {
|
|
1417
1579
|
throw new SidechatAPIError("User is not authenticated.");
|
|
@@ -1444,21 +1606,27 @@ class SidechatAPIClient {
|
|
|
1444
1606
|
/**
|
|
1445
1607
|
* Gets a list of the user's direct messages
|
|
1446
1608
|
* @method
|
|
1609
|
+
* @param {types.SidechatCursorString} [cursor] - cursor string
|
|
1447
1610
|
* @returns {Promise<types.SidechatDirectThread[]>}
|
|
1448
1611
|
* @since 2.4.4
|
|
1449
1612
|
*/
|
|
1450
|
-
getDMs = async () => {
|
|
1613
|
+
getDMs = async (cursor) => {
|
|
1451
1614
|
if (!this.userToken) {
|
|
1452
1615
|
throw new SidechatAPIError("User is not authenticated.");
|
|
1453
1616
|
}
|
|
1454
1617
|
try {
|
|
1455
|
-
const res = await fetch(
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1618
|
+
const res = await fetch(
|
|
1619
|
+
`${this.apiRoot}/v1/chats${
|
|
1620
|
+
cursor ? "?cursor=" + encodeURIComponent(cursor) : ""
|
|
1621
|
+
}`,
|
|
1622
|
+
{
|
|
1623
|
+
method: "GET",
|
|
1624
|
+
headers: {
|
|
1625
|
+
...this.defaultHeaders,
|
|
1626
|
+
Authorization: `Bearer ${this.userToken}`,
|
|
1627
|
+
},
|
|
1460
1628
|
},
|
|
1461
|
-
|
|
1629
|
+
);
|
|
1462
1630
|
const json = await res.json();
|
|
1463
1631
|
const list = await json.chats;
|
|
1464
1632
|
let r = [];
|
|
@@ -1492,7 +1660,7 @@ class SidechatAPIClient {
|
|
|
1492
1660
|
...this.defaultHeaders,
|
|
1493
1661
|
Authorization: `Bearer ${this.userToken}`,
|
|
1494
1662
|
},
|
|
1495
|
-
}
|
|
1663
|
+
},
|
|
1496
1664
|
);
|
|
1497
1665
|
const json = await res.json();
|
|
1498
1666
|
return await json.chat;
|
|
@@ -1554,7 +1722,7 @@ class SidechatAPIClient {
|
|
|
1554
1722
|
clientID,
|
|
1555
1723
|
postID,
|
|
1556
1724
|
anonymous = false,
|
|
1557
|
-
postContext = "feed"
|
|
1725
|
+
postContext = "feed",
|
|
1558
1726
|
) => {
|
|
1559
1727
|
if (!this.userToken) {
|
|
1560
1728
|
throw new SidechatAPIError("User is not authenticated.");
|
|
@@ -1587,6 +1755,7 @@ class SidechatAPIClient {
|
|
|
1587
1755
|
* @method
|
|
1588
1756
|
* @param {String} postID - alphanumeric ID of post to hide
|
|
1589
1757
|
* @since 2.6.2
|
|
1758
|
+
* @deprecated since 2.7.0. Please use `blockUser` instead!
|
|
1590
1759
|
*/
|
|
1591
1760
|
hidePostsFromUser = async (postID) => {
|
|
1592
1761
|
if (!this.userToken) {
|
|
@@ -1602,7 +1771,7 @@ class SidechatAPIClient {
|
|
|
1602
1771
|
body: JSON.stringify({
|
|
1603
1772
|
post_id: postID,
|
|
1604
1773
|
post_context: "feed",
|
|
1605
|
-
report: false
|
|
1774
|
+
report: false,
|
|
1606
1775
|
}),
|
|
1607
1776
|
});
|
|
1608
1777
|
const json = await res.json();
|
|
@@ -1617,6 +1786,7 @@ class SidechatAPIClient {
|
|
|
1617
1786
|
* Unhides all posts from all users
|
|
1618
1787
|
* @method
|
|
1619
1788
|
* @since 2.6.2
|
|
1789
|
+
* @deprecated since 2.7.0. No longer used by the official app and may stop working.
|
|
1620
1790
|
*/
|
|
1621
1791
|
unhidePostsFromAllUsers = async () => {
|
|
1622
1792
|
if (!this.userToken) {
|
|
@@ -1638,81 +1808,471 @@ class SidechatAPIClient {
|
|
|
1638
1808
|
throw new SidechatAPIError(`Failed to unhide post.`);
|
|
1639
1809
|
}
|
|
1640
1810
|
};
|
|
1811
|
+
|
|
1812
|
+
/**
|
|
1813
|
+
* Fetches the home feed, which mixes posts from all of the user's groups
|
|
1814
|
+
* @method
|
|
1815
|
+
* @param {"for_you"|"hot"|"recent"} [type] - how the feed should be sorted
|
|
1816
|
+
* @param {String} [schoolGroupID] - alphanumeric ID of the user's school group
|
|
1817
|
+
* @param {types.SidechatCursorString} [cursor] - cursor string
|
|
1818
|
+
* @returns {Promise<types.SidechatFeed>} feed items and cursor
|
|
1819
|
+
* @since 2.7.0
|
|
1820
|
+
*/
|
|
1821
|
+
getHomeFeed = async (type = "for_you", schoolGroupID, cursor) => {
|
|
1822
|
+
if (!this.userToken) {
|
|
1823
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1824
|
+
}
|
|
1825
|
+
try {
|
|
1826
|
+
const params = new URLSearchParams({ type: type });
|
|
1827
|
+
if (schoolGroupID) params.set("school_group_id", schoolGroupID);
|
|
1828
|
+
if (cursor) params.set("cursor", cursor);
|
|
1829
|
+
const res = await this.sendRequest(`/v1/posts/home?${params}`);
|
|
1830
|
+
return await res.json();
|
|
1831
|
+
} catch (err) {
|
|
1832
|
+
console.error(err);
|
|
1833
|
+
throw new SidechatAPIError(`Failed to get home feed.`);
|
|
1834
|
+
}
|
|
1835
|
+
};
|
|
1836
|
+
|
|
1837
|
+
/**
|
|
1838
|
+
* Follows or unfollows a post. Followed posts send activity notifications when they get new comments.
|
|
1839
|
+
* @method
|
|
1840
|
+
* @param {String} postID - alphanumeric ID of post
|
|
1841
|
+
* @param {Boolean} following - whether or not the user should follow the post
|
|
1842
|
+
* @returns {Promise<{post: types.SidechatPostOrComment}>} the updated post
|
|
1843
|
+
* @since 2.7.0
|
|
1844
|
+
*/
|
|
1845
|
+
setPostFollowing = async (postID, following) => {
|
|
1846
|
+
if (!this.userToken) {
|
|
1847
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1848
|
+
}
|
|
1849
|
+
try {
|
|
1850
|
+
const res = await this.sendRequest(
|
|
1851
|
+
`/v1/posts/${following ? "follow" : "unfollow"}`,
|
|
1852
|
+
"POST",
|
|
1853
|
+
JSON.stringify({ post_id: postID }),
|
|
1854
|
+
);
|
|
1855
|
+
return await res.json();
|
|
1856
|
+
} catch (err) {
|
|
1857
|
+
console.error(err);
|
|
1858
|
+
throw new SidechatAPIError(`Failed to change post follow status.`);
|
|
1859
|
+
}
|
|
1860
|
+
};
|
|
1861
|
+
|
|
1862
|
+
/**
|
|
1863
|
+
* Reports a post or comment to the group's moderators
|
|
1864
|
+
* @method
|
|
1865
|
+
* @param {String} postID - alphanumeric ID of post or comment to report
|
|
1866
|
+
* @param {types.SidechatReportReason} reason - why the content is being reported
|
|
1867
|
+
* @param {String} [note] - explanation to send along with the report
|
|
1868
|
+
* @since 2.7.0
|
|
1869
|
+
*/
|
|
1870
|
+
flagPost = async (postID, reason, note = undefined) => {
|
|
1871
|
+
if (!this.userToken) {
|
|
1872
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1873
|
+
}
|
|
1874
|
+
try {
|
|
1875
|
+
const res = await this.sendRequest(
|
|
1876
|
+
"/v1/posts/flag",
|
|
1877
|
+
"POST",
|
|
1878
|
+
JSON.stringify({ post_id: postID, reason: reason, note: note }),
|
|
1879
|
+
);
|
|
1880
|
+
return await res.json();
|
|
1881
|
+
} catch (err) {
|
|
1882
|
+
console.error(err);
|
|
1883
|
+
throw new SidechatAPIError(`Failed to report post.`);
|
|
1884
|
+
}
|
|
1885
|
+
};
|
|
1886
|
+
|
|
1887
|
+
/**
|
|
1888
|
+
* Blocks the author of a post or comment, hiding all of their content from the user. Replaces `hidePostsFromUser`.
|
|
1889
|
+
* @method
|
|
1890
|
+
* @param {String} postID - alphanumeric ID of a post or comment by the user to block
|
|
1891
|
+
* @param {Boolean} [report] - whether or not to also report the content
|
|
1892
|
+
* @param {"feed"|"chat"} [postContext] - where the content was seen
|
|
1893
|
+
* @since 2.7.0
|
|
1894
|
+
*/
|
|
1895
|
+
blockUser = async (postID, report = false, postContext = "feed") => {
|
|
1896
|
+
if (!this.userToken) {
|
|
1897
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1898
|
+
}
|
|
1899
|
+
try {
|
|
1900
|
+
const res = await this.sendRequest(
|
|
1901
|
+
"/v1/posts/block_user",
|
|
1902
|
+
"POST",
|
|
1903
|
+
JSON.stringify({
|
|
1904
|
+
post_id: postID,
|
|
1905
|
+
post_context: postContext,
|
|
1906
|
+
report: report,
|
|
1907
|
+
}),
|
|
1908
|
+
);
|
|
1909
|
+
return await res.json();
|
|
1910
|
+
} catch (err) {
|
|
1911
|
+
console.error(err);
|
|
1912
|
+
throw new SidechatAPIError(`Failed to block user.`);
|
|
1913
|
+
}
|
|
1914
|
+
};
|
|
1915
|
+
|
|
1916
|
+
/**
|
|
1917
|
+
* Creates a link attachment that can be added to a post with createPost(). YouTube links are recognized and shown as embedded videos.
|
|
1918
|
+
* @method
|
|
1919
|
+
* @param {String} url - URL to attach
|
|
1920
|
+
* @returns {Promise<types.SidechatAttachment>} the created attachment
|
|
1921
|
+
* @since 2.7.0
|
|
1922
|
+
*/
|
|
1923
|
+
createLinkAttachment = async (url) => {
|
|
1924
|
+
if (!this.userToken) {
|
|
1925
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1926
|
+
}
|
|
1927
|
+
try {
|
|
1928
|
+
const res = await this.sendRequest(
|
|
1929
|
+
"/v1/attachments/upload_link",
|
|
1930
|
+
"POST",
|
|
1931
|
+
JSON.stringify({ link_url: url }),
|
|
1932
|
+
);
|
|
1933
|
+
return await res.json();
|
|
1934
|
+
} catch (err) {
|
|
1935
|
+
console.error(err);
|
|
1936
|
+
throw new SidechatAPIError(`Failed to create link attachment.`);
|
|
1937
|
+
}
|
|
1938
|
+
};
|
|
1939
|
+
|
|
1940
|
+
/**
|
|
1941
|
+
* Gets the user's activity feed (notifications for comments, votes, followers, etc.)
|
|
1942
|
+
* @method
|
|
1943
|
+
* @param {types.SidechatCursorString} [cursor] - cursor string
|
|
1944
|
+
* @returns {Promise<types.SidechatActivityList>} activity items and cursor
|
|
1945
|
+
* @since 2.7.0
|
|
1946
|
+
*/
|
|
1947
|
+
getActivity = async (cursor) => {
|
|
1948
|
+
if (!this.userToken) {
|
|
1949
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1950
|
+
}
|
|
1951
|
+
try {
|
|
1952
|
+
const res = await this.sendRequest(
|
|
1953
|
+
`/v1/activity${cursor ? "?cursor=" + encodeURIComponent(cursor) : ""}`,
|
|
1954
|
+
);
|
|
1955
|
+
return await res.json();
|
|
1956
|
+
} catch (err) {
|
|
1957
|
+
console.error(err);
|
|
1958
|
+
throw new SidechatAPIError(`Failed to get activity.`);
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
|
|
1962
|
+
/**
|
|
1963
|
+
* Gets the groups the user is a member of
|
|
1964
|
+
* @method
|
|
1965
|
+
* @returns {Promise<types.SidechatGroup[]>}
|
|
1966
|
+
* @since 2.7.0
|
|
1967
|
+
*/
|
|
1968
|
+
getGroups = async () => {
|
|
1969
|
+
if (!this.userToken) {
|
|
1970
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1971
|
+
}
|
|
1972
|
+
try {
|
|
1973
|
+
const res = await this.sendRequest("/v1/groups");
|
|
1974
|
+
const json = await res.json();
|
|
1975
|
+
return json.groups;
|
|
1976
|
+
} catch (err) {
|
|
1977
|
+
console.error(err);
|
|
1978
|
+
throw new SidechatAPIError(`Failed to get groups.`);
|
|
1979
|
+
}
|
|
1980
|
+
};
|
|
1981
|
+
|
|
1982
|
+
/**
|
|
1983
|
+
* Gets groups suggested for the user to join
|
|
1984
|
+
* @method
|
|
1985
|
+
* @param {Number} [limit] - maximum number of groups to return
|
|
1986
|
+
* @returns {Promise<types.SidechatGroup[]>}
|
|
1987
|
+
* @since 2.7.0
|
|
1988
|
+
*/
|
|
1989
|
+
getSuggestedGroups = async (limit = 10) => {
|
|
1990
|
+
if (!this.userToken) {
|
|
1991
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
1992
|
+
}
|
|
1993
|
+
try {
|
|
1994
|
+
const res = await this.sendRequest(
|
|
1995
|
+
`/v1/groups/suggestions?limit=${limit}`,
|
|
1996
|
+
);
|
|
1997
|
+
const json = await res.json();
|
|
1998
|
+
return json.groups;
|
|
1999
|
+
} catch (err) {
|
|
2000
|
+
console.error(err);
|
|
2001
|
+
throw new SidechatAPIError(`Failed to get suggested groups.`);
|
|
2002
|
+
}
|
|
2003
|
+
};
|
|
2004
|
+
|
|
2005
|
+
/**
|
|
2006
|
+
* Gets a shareable invite link for a group. School groups don't have invite links and will throw an error.
|
|
2007
|
+
* @method
|
|
2008
|
+
* @param {String} groupID - alphanumeric ID of group
|
|
2009
|
+
* @returns {Promise<String>} invite link URL
|
|
2010
|
+
* @since 2.7.0
|
|
2011
|
+
*/
|
|
2012
|
+
getGroupInviteLink = async (groupID) => {
|
|
2013
|
+
if (!this.userToken) {
|
|
2014
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
2015
|
+
}
|
|
2016
|
+
try {
|
|
2017
|
+
const res = await this.sendRequest(
|
|
2018
|
+
`/v1/groups/invite_link?group_id=${groupID}`,
|
|
2019
|
+
);
|
|
2020
|
+
const json = await res.json();
|
|
2021
|
+
return json.link;
|
|
2022
|
+
} catch (err) {
|
|
2023
|
+
console.error(err);
|
|
2024
|
+
throw new SidechatAPIError(`Failed to get invite link.`);
|
|
2025
|
+
}
|
|
2026
|
+
};
|
|
2027
|
+
|
|
2028
|
+
/**
|
|
2029
|
+
* Gets the yakarma leaderboard for a group, along with the user's own karma
|
|
2030
|
+
* @method
|
|
2031
|
+
* @param {String} groupID - alphanumeric ID of group
|
|
2032
|
+
* @returns {Promise<types.SidechatLeaderboard>}
|
|
2033
|
+
* @since 2.7.0
|
|
2034
|
+
*/
|
|
2035
|
+
getLeaderboard = async (groupID) => {
|
|
2036
|
+
if (!this.userToken) {
|
|
2037
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
2038
|
+
}
|
|
2039
|
+
try {
|
|
2040
|
+
const res = await this.sendRequest(`/v1/leaderboard?group_id=${groupID}`);
|
|
2041
|
+
return await res.json();
|
|
2042
|
+
} catch (err) {
|
|
2043
|
+
console.error(err);
|
|
2044
|
+
throw new SidechatAPIError(`Failed to get leaderboard.`);
|
|
2045
|
+
}
|
|
2046
|
+
};
|
|
2047
|
+
|
|
2048
|
+
/**
|
|
2049
|
+
* Gets the existing direct message thread for a post or comment. Returns undefined if the user hasn't started one.
|
|
2050
|
+
* @method
|
|
2051
|
+
* @param {String} postID - alphanumeric ID of post or comment
|
|
2052
|
+
* @returns {Promise<types.SidechatDirectThread>}
|
|
2053
|
+
* @since 2.7.0
|
|
2054
|
+
*/
|
|
2055
|
+
getDMForPost = async (postID) => {
|
|
2056
|
+
if (!this.userToken) {
|
|
2057
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
2058
|
+
}
|
|
2059
|
+
try {
|
|
2060
|
+
const res = await this.sendRequest(`/v1/chats/by_post?post_id=${postID}`);
|
|
2061
|
+
const json = await res.json();
|
|
2062
|
+
return json.chat;
|
|
2063
|
+
} catch (err) {
|
|
2064
|
+
console.error(err);
|
|
2065
|
+
throw new SidechatAPIError(`Failed to get DM thread for post.`);
|
|
2066
|
+
}
|
|
2067
|
+
};
|
|
2068
|
+
|
|
2069
|
+
/**
|
|
2070
|
+
* Reports a direct message thread
|
|
2071
|
+
* @method
|
|
2072
|
+
* @param {String} chatID - alphanumeric ID of the thread to report
|
|
2073
|
+
* @param {types.SidechatReportReason} reason - why the thread is being reported
|
|
2074
|
+
* @since 2.7.0
|
|
2075
|
+
*/
|
|
2076
|
+
reportDM = async (chatID, reason) => {
|
|
2077
|
+
if (!this.userToken) {
|
|
2078
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
2079
|
+
}
|
|
2080
|
+
try {
|
|
2081
|
+
const res = await this.sendRequest(
|
|
2082
|
+
"/v1/chats/report",
|
|
2083
|
+
"POST",
|
|
2084
|
+
JSON.stringify({ chat_id: chatID, reason: reason }),
|
|
2085
|
+
);
|
|
2086
|
+
return await res.json();
|
|
2087
|
+
} catch (err) {
|
|
2088
|
+
console.error(err);
|
|
2089
|
+
throw new SidechatAPIError(`Failed to report DM.`);
|
|
2090
|
+
}
|
|
2091
|
+
};
|
|
2092
|
+
|
|
2093
|
+
/**
|
|
2094
|
+
* Sets which push notifications the user receives
|
|
2095
|
+
* @method
|
|
2096
|
+
* @param {types.SidechatNotificationPreferences} preferences - notification types to enable or disable
|
|
2097
|
+
* @since 2.7.0
|
|
2098
|
+
*/
|
|
2099
|
+
setNotificationPreferences = async (preferences) => {
|
|
2100
|
+
if (!this.userToken) {
|
|
2101
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
2102
|
+
}
|
|
2103
|
+
try {
|
|
2104
|
+
const res = await this.sendRequest(
|
|
2105
|
+
"/v1/users/set_notification_preferences",
|
|
2106
|
+
"POST",
|
|
2107
|
+
JSON.stringify({ notification_preferences: preferences }),
|
|
2108
|
+
);
|
|
2109
|
+
return await res.json();
|
|
2110
|
+
} catch (err) {
|
|
2111
|
+
console.error(err);
|
|
2112
|
+
throw new SidechatAPIError(`Failed to set notification preferences.`);
|
|
2113
|
+
}
|
|
2114
|
+
};
|
|
2115
|
+
|
|
2116
|
+
/**
|
|
2117
|
+
* 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.
|
|
2118
|
+
* @method
|
|
2119
|
+
* @param {String} authToken - token from the Google or Microsoft sign-in
|
|
2120
|
+
* @param {"google"|"microsoft"} authType - provider the token came from
|
|
2121
|
+
* @param {Boolean} [isIncomingFreshman] - whether or not the user is an incoming freshman
|
|
2122
|
+
* @since 2.7.0
|
|
2123
|
+
* @tutorial Email Registration
|
|
2124
|
+
*/
|
|
2125
|
+
verifyEmailWithThirdParty = async (
|
|
2126
|
+
authToken,
|
|
2127
|
+
authType,
|
|
2128
|
+
isIncomingFreshman = false,
|
|
2129
|
+
) => {
|
|
2130
|
+
if (!this.userToken) {
|
|
2131
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
2132
|
+
}
|
|
2133
|
+
try {
|
|
2134
|
+
const res = await this.sendRequest(
|
|
2135
|
+
"/v1/users/third_party_email_verified",
|
|
2136
|
+
"POST",
|
|
2137
|
+
JSON.stringify({
|
|
2138
|
+
auth: authToken,
|
|
2139
|
+
auth_type: authType,
|
|
2140
|
+
is_incoming_freshman: isIncomingFreshman,
|
|
2141
|
+
}),
|
|
2142
|
+
);
|
|
2143
|
+
const json = await res.json();
|
|
2144
|
+
if (json.verified_email_updates_response) {
|
|
2145
|
+
return json.verified_email_updates_response;
|
|
2146
|
+
} else {
|
|
2147
|
+
throw new SidechatAPIError(json?.message || "Email is not verified.");
|
|
2148
|
+
}
|
|
2149
|
+
} catch (err) {
|
|
2150
|
+
console.error(err);
|
|
2151
|
+
throw new SidechatAPIError("Failed to verify email.");
|
|
2152
|
+
}
|
|
2153
|
+
};
|
|
2154
|
+
|
|
2155
|
+
/**
|
|
2156
|
+
* 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.
|
|
2157
|
+
* @method
|
|
2158
|
+
* @param {String} socketID - socket ID assigned by Pusher
|
|
2159
|
+
* @param {String} channelName - name of the private channel to subscribe to
|
|
2160
|
+
* @returns {Promise<{auth: String}>} signed channel authorization
|
|
2161
|
+
* @since 2.7.0
|
|
2162
|
+
*/
|
|
2163
|
+
authorizeRealtimeChannel = async (socketID, channelName) => {
|
|
2164
|
+
if (!this.userToken) {
|
|
2165
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
2166
|
+
}
|
|
2167
|
+
try {
|
|
2168
|
+
const res = await this.sendRequest(
|
|
2169
|
+
"/pusher/auth",
|
|
2170
|
+
"POST",
|
|
2171
|
+
JSON.stringify({ socket_id: socketID, channel_name: channelName }),
|
|
2172
|
+
);
|
|
2173
|
+
return await res.json();
|
|
2174
|
+
} catch (err) {
|
|
2175
|
+
console.error(err);
|
|
2176
|
+
throw new SidechatAPIError(`Failed to authorize realtime channel.`);
|
|
2177
|
+
}
|
|
2178
|
+
};
|
|
2179
|
+
|
|
2180
|
+
/**
|
|
2181
|
+
* Permanently deletes the current user's account. This cannot be undone!
|
|
2182
|
+
* @method
|
|
2183
|
+
* @since 2.7.0
|
|
2184
|
+
*/
|
|
2185
|
+
deleteAccount = async () => {
|
|
2186
|
+
if (!this.userToken) {
|
|
2187
|
+
throw new SidechatAPIError("User is not authenticated.");
|
|
2188
|
+
}
|
|
2189
|
+
try {
|
|
2190
|
+
const res = await this.sendRequest(
|
|
2191
|
+
"/v1/users/delete",
|
|
2192
|
+
"POST",
|
|
2193
|
+
JSON.stringify({}),
|
|
2194
|
+
);
|
|
2195
|
+
return await res.json();
|
|
2196
|
+
} catch (err) {
|
|
2197
|
+
console.error(err);
|
|
2198
|
+
throw new SidechatAPIError(`Failed to delete account.`);
|
|
2199
|
+
}
|
|
2200
|
+
};
|
|
1641
2201
|
}
|
|
1642
2202
|
|
|
1643
|
-
/**
|
|
1644
|
-
* @typedef SidechatColor
|
|
1645
|
-
* @prop {String} primary - hex code of primary color
|
|
1646
|
-
* @prop {String} secondary - hex code of secondary color
|
|
1647
|
-
*/
|
|
1648
|
-
|
|
1649
|
-
/**
|
|
1650
|
-
* List of colors compatible with user conversation icons
|
|
1651
|
-
* @prop {SidechatColor[]} colors - list of color themes for user icons
|
|
1652
|
-
*/
|
|
1653
|
-
class SidechatColorList {
|
|
1654
|
-
colors = [
|
|
1655
|
-
{
|
|
1656
|
-
primary: "#74DEEE",
|
|
1657
|
-
secondary: "#239EAB",
|
|
1658
|
-
},
|
|
1659
|
-
{
|
|
1660
|
-
primary: "#15FF46",
|
|
1661
|
-
secondary: "#3FC0FF",
|
|
1662
|
-
},
|
|
1663
|
-
{
|
|
1664
|
-
primary: "#D9FB8A",
|
|
1665
|
-
secondary: "#B1FD00",
|
|
1666
|
-
},
|
|
1667
|
-
{
|
|
1668
|
-
primary: "#FC40FF",
|
|
1669
|
-
secondary: "#0DD5B2",
|
|
1670
|
-
},
|
|
1671
|
-
{
|
|
1672
|
-
primary: "#3E973C",
|
|
1673
|
-
secondary: "#0F430E",
|
|
1674
|
-
},
|
|
1675
|
-
{
|
|
1676
|
-
primary: "#FFD305",
|
|
1677
|
-
secondary: "#F4B320",
|
|
1678
|
-
},
|
|
1679
|
-
{
|
|
1680
|
-
primary: "#8483FF",
|
|
1681
|
-
secondary: "#5857FF",
|
|
1682
|
-
},
|
|
1683
|
-
{
|
|
1684
|
-
primary: "#FA81FF",
|
|
1685
|
-
secondary: "#722DFF",
|
|
1686
|
-
},
|
|
1687
|
-
{
|
|
1688
|
-
primary: "#00CBFE",
|
|
1689
|
-
secondary: "#0D13D5",
|
|
1690
|
-
},
|
|
1691
|
-
{
|
|
1692
|
-
primary: "#FF7B51",
|
|
1693
|
-
secondary: "#B2431F",
|
|
1694
|
-
},
|
|
1695
|
-
{
|
|
1696
|
-
primary: "#FF47CC",
|
|
1697
|
-
secondary: "#69004C",
|
|
1698
|
-
},
|
|
1699
|
-
{
|
|
1700
|
-
primary: "#00EE6E",
|
|
1701
|
-
secondary: "#0C75E6",
|
|
1702
|
-
},
|
|
1703
|
-
{
|
|
1704
|
-
primary: "#FF1885",
|
|
1705
|
-
secondary: "#FA81FF",
|
|
1706
|
-
},
|
|
1707
|
-
{
|
|
1708
|
-
primary: "#D8DC44",
|
|
1709
|
-
secondary: "#228B3F",
|
|
1710
|
-
},
|
|
1711
|
-
{
|
|
1712
|
-
primary: "#0968E5",
|
|
1713
|
-
secondary: "#091970",
|
|
1714
|
-
},
|
|
1715
|
-
];
|
|
2203
|
+
/**
|
|
2204
|
+
* @typedef SidechatColor
|
|
2205
|
+
* @prop {String} primary - hex code of primary color
|
|
2206
|
+
* @prop {String} secondary - hex code of secondary color
|
|
2207
|
+
*/
|
|
2208
|
+
|
|
2209
|
+
/**
|
|
2210
|
+
* List of colors compatible with user conversation icons
|
|
2211
|
+
* @prop {SidechatColor[]} colors - list of color themes for user icons
|
|
2212
|
+
*/
|
|
2213
|
+
class SidechatColorList {
|
|
2214
|
+
colors = [
|
|
2215
|
+
{
|
|
2216
|
+
primary: "#74DEEE",
|
|
2217
|
+
secondary: "#239EAB",
|
|
2218
|
+
},
|
|
2219
|
+
{
|
|
2220
|
+
primary: "#15FF46",
|
|
2221
|
+
secondary: "#3FC0FF",
|
|
2222
|
+
},
|
|
2223
|
+
{
|
|
2224
|
+
primary: "#D9FB8A",
|
|
2225
|
+
secondary: "#B1FD00",
|
|
2226
|
+
},
|
|
2227
|
+
{
|
|
2228
|
+
primary: "#FC40FF",
|
|
2229
|
+
secondary: "#0DD5B2",
|
|
2230
|
+
},
|
|
2231
|
+
{
|
|
2232
|
+
primary: "#3E973C",
|
|
2233
|
+
secondary: "#0F430E",
|
|
2234
|
+
},
|
|
2235
|
+
{
|
|
2236
|
+
primary: "#FFD305",
|
|
2237
|
+
secondary: "#F4B320",
|
|
2238
|
+
},
|
|
2239
|
+
{
|
|
2240
|
+
primary: "#8483FF",
|
|
2241
|
+
secondary: "#5857FF",
|
|
2242
|
+
},
|
|
2243
|
+
{
|
|
2244
|
+
primary: "#FA81FF",
|
|
2245
|
+
secondary: "#722DFF",
|
|
2246
|
+
},
|
|
2247
|
+
{
|
|
2248
|
+
primary: "#00CBFE",
|
|
2249
|
+
secondary: "#0D13D5",
|
|
2250
|
+
},
|
|
2251
|
+
{
|
|
2252
|
+
primary: "#FF7B51",
|
|
2253
|
+
secondary: "#B2431F",
|
|
2254
|
+
},
|
|
2255
|
+
{
|
|
2256
|
+
primary: "#FF47CC",
|
|
2257
|
+
secondary: "#69004C",
|
|
2258
|
+
},
|
|
2259
|
+
{
|
|
2260
|
+
primary: "#00EE6E",
|
|
2261
|
+
secondary: "#0C75E6",
|
|
2262
|
+
},
|
|
2263
|
+
{
|
|
2264
|
+
primary: "#FF1885",
|
|
2265
|
+
secondary: "#FA81FF",
|
|
2266
|
+
},
|
|
2267
|
+
{
|
|
2268
|
+
primary: "#D8DC44",
|
|
2269
|
+
secondary: "#228B3F",
|
|
2270
|
+
},
|
|
2271
|
+
{
|
|
2272
|
+
primary: "#0968E5",
|
|
2273
|
+
secondary: "#091970",
|
|
2274
|
+
},
|
|
2275
|
+
];
|
|
1716
2276
|
}
|
|
1717
2277
|
|
|
1718
2278
|
exports.SidechatAPIClient = SidechatAPIClient;
|