sidechat.js 2.6.6 → 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.
Files changed (51) hide show
  1. package/dist/classes/SidechatAPIClient.d.ts +166 -11
  2. package/dist/classes/SidechatAPIClient.d.ts.map +1 -1
  3. package/dist/index.cjs +853 -311
  4. package/dist/index.mjs +853 -311
  5. package/dist/types/SidechatTypes.d.ts +260 -9
  6. package/dist/types/SidechatTypes.d.ts.map +1 -1
  7. package/docs/sidechat.js/2.7.0/SidechatAPIClient.html +3 -0
  8. package/docs/sidechat.js/2.7.0/SidechatAPIError.html +3 -0
  9. package/docs/sidechat.js/2.7.0/SidechatColorList.html +3 -0
  10. package/docs/sidechat.js/2.7.0/classes_SidechatAPIClient.js.html +1897 -0
  11. package/docs/sidechat.js/2.7.0/classes_SidechatAPIError.js.html +16 -0
  12. package/docs/sidechat.js/2.7.0/classes_SidechatColorList.js.html +79 -0
  13. package/docs/sidechat.js/2.7.0/data/search.json +1 -0
  14. package/docs/sidechat.js/2.7.0/fonts/Inconsolata-Regular.ttf +0 -0
  15. package/docs/sidechat.js/2.7.0/fonts/OpenSans-Regular.ttf +0 -0
  16. package/docs/sidechat.js/2.7.0/fonts/WorkSans-Bold.ttf +0 -0
  17. package/docs/sidechat.js/2.7.0/global.html +3 -0
  18. package/docs/sidechat.js/2.7.0/index.html +4 -0
  19. package/docs/sidechat.js/2.7.0/scripts/core.js +726 -0
  20. package/docs/sidechat.js/2.7.0/scripts/core.min.js +23 -0
  21. package/docs/sidechat.js/2.7.0/scripts/resize.js +90 -0
  22. package/docs/sidechat.js/2.7.0/scripts/search.js +265 -0
  23. package/docs/sidechat.js/2.7.0/scripts/search.min.js +6 -0
  24. package/docs/sidechat.js/2.7.0/scripts/third-party/Apache-License-2.0.txt +202 -0
  25. package/docs/sidechat.js/2.7.0/scripts/third-party/fuse.js +9 -0
  26. package/docs/sidechat.js/2.7.0/scripts/third-party/hljs-line-num-original.js +369 -0
  27. package/docs/sidechat.js/2.7.0/scripts/third-party/hljs-line-num.js +1 -0
  28. package/docs/sidechat.js/2.7.0/scripts/third-party/hljs-original.js +5171 -0
  29. package/docs/sidechat.js/2.7.0/scripts/third-party/hljs.js +1 -0
  30. package/docs/sidechat.js/2.7.0/scripts/third-party/popper.js +5 -0
  31. package/docs/sidechat.js/2.7.0/scripts/third-party/tippy.js +1 -0
  32. package/docs/sidechat.js/2.7.0/scripts/third-party/tocbot.js +672 -0
  33. package/docs/sidechat.js/2.7.0/scripts/third-party/tocbot.min.js +1 -0
  34. package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-base.css +1159 -0
  35. package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-dark.css +412 -0
  36. package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-light.css +482 -0
  37. package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-scrollbar.css +30 -0
  38. package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme-without-scrollbar.min.css +1 -0
  39. package/docs/sidechat.js/2.7.0/styles/clean-jsdoc-theme.min.css +1 -0
  40. package/docs/sidechat.js/2.7.0/tutorial-Authentication.html +16 -0
  41. package/docs/sidechat.js/2.7.0/tutorial-Email Registration.html +6 -0
  42. package/docs/sidechat.js/2.7.0/tutorial-Feeds and Pagination.html +10 -0
  43. package/docs/sidechat.js/2.7.0/tutorial-Posting and Media.html +19 -0
  44. package/docs/sidechat.js/2.7.0/types_SidechatTypes.js.html +297 -0
  45. package/docs/tutorials/Authentication.md +63 -52
  46. package/docs/tutorials/Email Registration.md +19 -16
  47. package/docs/tutorials/Feeds and Pagination.md +45 -0
  48. package/docs/tutorials/Posting and Media.md +63 -0
  49. package/package.json +55 -55
  50. package/src/classes/SidechatAPIClient.js +477 -27
  51. 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 {Array} attachments - undocumented
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] - undocumented
27
- * @prop {Number} [comment_count] - number of comments on post (only if type=post)
28
- * @prop {Boolean} [comments_disabled] - whether or not you can comment on post (only if type=post)
29
- * @prop {SidechatPoll} [poll] - poll attached to post (only if the post has a poll)
30
- * @prop {String} [parent_post_id] - alphanumeric ID of parent post (only if type=comment)
31
- * @prop {String} [reply_post_id] - alphanumeric ID of comment being replied to, falls back to parent_post_id (only if type=comment)
32
- * @prop {String} [context] - text content of comment being replied to, falls back to text (only if type=comment)
33
- */
34
-
35
- /**
36
- * 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.
37
- * @typedef {Object} SidechatGroup
38
- * @prop {String} id - alphanumeric ID of group
39
- * @prop {String} name - human-readable name of group
40
- * @prop {String} analytics_name - name to file group under
41
- * @prop {"non_member"|"member"} membership_type - whether or not current user is a member of group
42
- * @prop {String} color - group's theme color as hex code (e.g., #FFFFFF)
43
- * @prop {"open"|"closed"|"email_domain"} group_join_type - basis on which group accepts new members
44
- * @prop {"private"|"public_to_all"|"public_to_schools"} group_visibility - group's visibility setting
45
- * @prop {"show"|"hide"} asset_library_visibility - whether or not group's asset library is visible
46
- * @prop {Array} [roles] - undocumented
47
- * @prop {String} [description] - description of group
48
- * @prop {SidechatPrivateAssetURL} [icon_url] - image URL for group icon
49
- * @prop {Number} [member_count] - number of users in group
50
- * @prop {Boolean} [should_show_leaderboard] - undocumented
51
- */
52
-
53
- /**
54
- * An asset object, containing information about an image within a post or comment
55
- * @typedef {Object} SidechatSimpleAsset
56
- * @prop {String} id - alphanumeric ID of asset
57
- * @prop {"image"} type - undocumented
58
- * @prop {"jpeg"|"png"|"gif"} content_type - file type of asset
59
- * @prop {Number} width - width of asset
60
- * @prop {Number} height - height of asset
61
- * @prop {SidechatPrivateAssetURL} [url] - URL string of asset's location
62
- */
63
-
64
- /**
65
- * An asset object, containing information about an image from the asset library
66
- * @typedef {Object} SidechatLibraryAsset
67
- * @prop {String} id - alphanumeric ID of asset
68
- * @prop {String} created_at - date string of asset creation time
69
- * @prop {SidechatAssetMetadata} metadata - metadata associated with asset
70
- * @prop {SidechatPrivateAssetURL} url - URL string of asset's location
71
- */
72
-
73
- /**
74
- * An asset object, containing information about an image from the asset library
75
- * @typedef {Object} SidechatAssetMetadata
76
- * @prop {Number} width - width of asset
77
- * @prop {Number} height - height of asset
78
- * @prop {"image"} type - undocumented
79
- * @prop {"jpeg"|"png"|"gif"} content_type - file type of asset
80
- */
81
-
82
- /**
83
- * A user's anonymous identity information
84
- * @typedef {Object} SidechatIdentity
85
- * @prop {String} name - representation of user's name (varies across app)
86
- * @prop {Boolean} posted_with_username - undocumented
87
- */
88
-
89
- /**
90
- * A conversation icon associated with a user
91
- * @typedef {Object} SidechatIcon
92
- * @prop {String} emoji - unicode emoji character
93
- * @prop {String} color - primary hex color code
94
- * @prop {String} secondary_color - secondary hex color code
95
- */
96
-
97
- /**
98
- * The current user's information
99
- * @typedef {Object} SidechatCurrentUser
100
- * @prop {String} id - alphanumeric ID of current user
101
- * @prop {String} hashedVerifiedEmail - verified email of current user in an unreadable hashed form
102
- * @prop {Boolean} isGlobalModerator - whether or not user is a moderator
103
- * @prop {Boolean} isGlobalAdmin - whether or not user is an admin
104
- * @prop {SidechatMembership[]} memberships
105
- * @prop {Array} roles - undocumented
106
- * @prop {String} emailDomain - domain of verified email address on account
107
- * @prop {String} wildcardEmailDomain - domain of verified email address on account, preceeded by *. to support subdomains
108
- */
109
-
110
- /**
111
- * A user's public profile
112
- * @typedef {Object} SidechatProfile
113
- * @prop {String} id - alphanumeric ID of user
114
- * @prop {String} name - public-facing username
115
- * @prop {SidechatIcon} conversation_icon - icon associated with user
116
- * @prop {Boolean} description - the user bio
117
- * @prop {String} index_name - undocumented
118
- * @prop {String} analytics_name - undocumented
119
- * @prop {String} color - undocumented
120
- * @prop {String} share_color_start - undocumented
121
- * @prop {String} share_color_end - undocumented
122
- * @prop {"account"} group_join_type - undocumented
123
- * @prop {"public_to_all"} group_visibility - the profile visibility status
124
- */
125
-
126
- /**
127
- * Representation of a group membership
128
- * @typedef {Object} SidechatMembership
129
- * @prop {String} groupId - alphanumeric ID of group
130
- * @prop {String} type - role of current user in group
131
- */
132
-
133
- /**
134
- * An asset URL that can only be accessed by making a request with a user's bearer token attached in the Authorization header
135
- * @typedef {String} SidechatPrivateAssetURL
136
- */
137
-
138
- /**
139
- * A cursor for paginating through post lists
140
- * @typedef {String} SidechatCursorString
141
- */
142
-
143
- /**
144
- * A vote on a comment or post
145
- * @typedef {"upvote"|"downvote"|"none"} SidechatVoteString
146
- */
147
-
148
- /**
149
- * A user's bearer authentication token needed for most requests
150
- * @typedef {String} SidechatAuthToken
151
- */
152
-
153
- /**
154
- * A list of posts and the associated cursor
155
- * @typedef {Object} SidechatPostsAndCursor
156
- * @prop {SidechatPostOrComment[]} posts
157
- * @prop {SidechatCursorString} cursor
158
- */
159
-
160
-
161
- /**
162
- * A direct message thread
163
- * @typedef {Object} SidechatDirectThread
164
- * @prop {String} id - alphanumeric ID of thread
165
- * @prop {String} group_id - alphanumeric ID of group in which the thread exists
166
- * @prop {String} updated_at - date string of when the last message in the chat was sent
167
- * @prop {String} post_id - post or comment from which the thread was originally sent
168
- * @prop {String} post_context - the context of the DM thread (only "feed" is known at the moment)
169
- * @prop {"accepted"} accept_status - whether or not the other user has accepted this DM
170
- * @prop {"post"|"comment"} type - the type of the content from which the DM was originally sent
171
- * @prop {SidechatDirectMessage[]} messages - array of direct message objects
172
- */
173
-
174
- /**
175
- * A single direct message
176
- * @typedef {Object} SidechatDirectMessage
177
- * @prop {String} created_at - time at which the message was sent
178
- * @prop {String} client_id - alphanumeric ID of the device the message was sent on
179
- * @prop {String} obfuscatedUserId - obfuscated version of the sender's alphanumeric ID
180
- * @prop {String} text - body text of the message
181
- * @prop {String} id - alphanumeric ID of the message
182
- * @prop {String} chat_id - alphanumeric ID of the thread in which the message resides
183
- * @prop {Boolean} authored_by_user - whether or not the current user sent the message
184
- * @prop {"message"} type - undocumented
185
- */
186
-
187
- /**
188
- * Represents a poll with choices
189
- * @typedef {Object} SidechatPoll
190
- * @prop {String} id - alphanumeric ID of poll
191
- * @prop {String} post_id - alphanumeric ID of post to which poll is attached
192
- * @prop {SidechatPollChoice[]} choices - array of poll choices
193
- * @prop {Boolean} allows_view_results - whether or not poll results are publicly visible
194
- * @prop {Number} view_results_count - number of users who have viewed poll results
195
- * @prop {Boolean} participated - whether or not current user has voted in poll
196
- */
197
-
198
- /**
199
- * Represents a poll choice
200
- * @typedef {Object} SidechatPollChoice
201
- * @prop {Number} count - number of votes for choice
202
- * @prop {String} text - user-visible text of choice
203
- * @prop {Boolean} selected - whether or not current user has voted for choice
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
@@ -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 (phoneNumber) => {
427
+ loginViaSMS = async (
428
+ phoneNumber,
429
+ useFallback = false,
430
+ captchaMethod = undefined,
431
+ captchaResponse = undefined,
432
+ ) => {
323
433
  try {
324
- const res = await fetch(`${this.apiRoot}/v1/login_register`, {
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 (age, registrationID) => {
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: "com.flowerave.sidechat",
608
+ bundle_id: bundleID,
483
609
  device_token: deviceID,
484
610
  }),
485
611
  });
@@ -539,9 +665,10 @@ 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
  }
@@ -549,6 +676,8 @@ class SidechatAPIClient {
549
676
  const res = await fetch(
550
677
  `${this.apiRoot}/v1/posts?${
551
678
  cursor ? "cursor=" + encodeURIComponent(cursor) + "&" : ""
679
+ }${
680
+ period ? "period=" + period + "&" : ""
552
681
  }group_id=${groupID}&type=${category}&cacheBust=${Date.now()}`,
553
682
  {
554
683
  method: "GET",
@@ -645,7 +774,7 @@ class SidechatAPIClient {
645
774
  contentType = "my_comments";
646
775
  }
647
776
  try {
648
- const res = await fetch(`${this.apiRoot}/v1/posts&type=${contentType}`, {
777
+ const res = await fetch(`${this.apiRoot}/v1/posts?type=${contentType}`, {
649
778
  method: "GET",
650
779
  headers: {
651
780
  ...this.defaultHeaders,
@@ -885,8 +1014,9 @@ class SidechatAPIClient {
885
1014
  throw new SidechatAPIError("User is not authenticated.");
886
1015
  }
887
1016
  try {
1017
+ // Joining moved to the v2 endpoint, which takes a list of IDs. Leave still sends group_id by itself, no list.
888
1018
  const res = await fetch(
889
- `${this.apiRoot}/v1/groups/${isMember ? "join" : "leave"}`,
1019
+ `${this.apiRoot}${isMember ? "/v2/groups/join" : "/v1/groups/leave"}`,
890
1020
  {
891
1021
  method: "POST",
892
1022
  headers: {
@@ -894,7 +1024,8 @@ class SidechatAPIClient {
894
1024
  Authorization: `Bearer ${this.userToken}`,
895
1025
  },
896
1026
  body: JSON.stringify({
897
- group_id: groupID,
1027
+ group_id: isMember ? undefined : groupID,
1028
+ group_ids: [groupID],
898
1029
  }),
899
1030
  },
900
1031
  );
@@ -953,15 +1084,17 @@ class SidechatAPIClient {
953
1084
  }),
954
1085
  });
955
1086
  const json = await res.json();
1087
+ if (!res.ok) throw new SidechatAPIError(json.message);
956
1088
  return await json.comment;
957
1089
  } catch (err) {
958
1090
  console.error(err);
1091
+ if (err instanceof SidechatAPIError && err.message) throw err;
959
1092
  throw new SidechatAPIError(`Failed to post comment.`);
960
1093
  }
961
1094
  };
962
1095
 
963
1096
  /**
964
- * 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.
965
1098
  * @method
966
1099
  * @since 2.2.0
967
1100
  * @param {String} text - text content of comment
@@ -971,6 +1104,7 @@ class SidechatAPIClient {
971
1104
  * @param {Boolean} [disableComments] - whether or not comments should be disabled on post
972
1105
  * @param {Boolean} [anonymous] - whether or not to hide user's name and icon on post
973
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()
974
1108
  * @returns {Promise<types.SidechatPostOrComment>} the created post
975
1109
  */
976
1110
  createPost = async (
@@ -982,6 +1116,7 @@ class SidechatAPIClient {
982
1116
  anonymous = false,
983
1117
  repostId = undefined,
984
1118
  pollOptions = undefined,
1119
+ attachmentIDs = [],
985
1120
  ) => {
986
1121
  if (!this.userToken) {
987
1122
  throw new SidechatAPIError("User is not authenticated.");
@@ -993,7 +1128,7 @@ class SidechatAPIClient {
993
1128
  assets: assetList,
994
1129
  group_ids: [groupID],
995
1130
  text: text,
996
- attachments: [],
1131
+ attachments: attachmentIDs,
997
1132
  dms_disabled: disableDMs,
998
1133
  comments_disabled: disableComments,
999
1134
  using_identity: !anonymous,
@@ -1015,9 +1150,11 @@ class SidechatAPIClient {
1015
1150
  body: JSON.stringify(body),
1016
1151
  });
1017
1152
  const json = await res.json();
1153
+ if (!res.ok) throw new SidechatAPIError(json.message);
1018
1154
  return await json.posts[0];
1019
1155
  } catch (err) {
1020
1156
  console.error(err);
1157
+ if (err instanceof SidechatAPIError && err.message) throw err;
1021
1158
  throw new SidechatAPIError(`Failed to make post.`);
1022
1159
  }
1023
1160
  };
@@ -1094,7 +1231,7 @@ class SidechatAPIClient {
1094
1231
  }
1095
1232
  try {
1096
1233
  const res = await fetch(
1097
- `${this.apiRoot}/v1/polls/view_results&cacheBust=${Date.now()}`,
1234
+ `${this.apiRoot}/v1/polls/view_results?cacheBust=${Date.now()}`,
1098
1235
  {
1099
1236
  method: "POST",
1100
1237
  headers: {
@@ -1115,22 +1252,27 @@ class SidechatAPIClient {
1115
1252
  };
1116
1253
 
1117
1254
  /**
1118
- * Uploads an asset to AWS S3 for use in posts and comments. Currently photos only
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)
1119
1256
  * @method
1120
1257
  * @param {String} uri - URI of the asset to upload
1121
- * @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")
1122
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.
1123
1261
  * @returns {Promise<String>} URL of the uploaded asset
1124
1262
  * @since 2.5.1
1125
1263
  */
1126
- uploadAsset = async (uri, mimeType, name = "") => {
1264
+ uploadAsset = async (uri, mimeType, name = "", context = undefined) => {
1127
1265
  if (!this.userToken) {
1128
1266
  throw new SidechatAPIError("User is not authenticated.");
1129
1267
  }
1130
1268
 
1131
1269
  let imageType = mimeType.split("/")[1];
1132
- if (!["png", "jpeg", "gif"].includes(imageType)) {
1133
- throw new SidechatAPIError("Unsupported image format.");
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";
1134
1276
  }
1135
1277
 
1136
1278
  const data = new FormData();
@@ -1141,7 +1283,9 @@ class SidechatAPIClient {
1141
1283
  });
1142
1284
 
1143
1285
  const urlReq = await this.sendRequest(
1144
- `/v1/assets/upload_url?content_type=${imageType}`,
1286
+ `/v1/assets/upload_url?content_type=${imageType}${
1287
+ context ? "&context=" + context : ""
1288
+ }`,
1145
1289
  );
1146
1290
  const urlJson = await urlReq.json();
1147
1291
 
@@ -1397,7 +1541,7 @@ class SidechatAPIClient {
1397
1541
  }
1398
1542
  try {
1399
1543
  const res = await fetch(
1400
- `${this.apiRoot}/v1/chats/explore&cacheBust=${Date.now()}`,
1544
+ `${this.apiRoot}/v1/chats/explore?cacheBust=${Date.now()}`,
1401
1545
  {
1402
1546
  method: "GET",
1403
1547
  headers: {
@@ -1462,21 +1606,27 @@ class SidechatAPIClient {
1462
1606
  /**
1463
1607
  * Gets a list of the user's direct messages
1464
1608
  * @method
1609
+ * @param {types.SidechatCursorString} [cursor] - cursor string
1465
1610
  * @returns {Promise<types.SidechatDirectThread[]>}
1466
1611
  * @since 2.4.4
1467
1612
  */
1468
- getDMs = async () => {
1613
+ getDMs = async (cursor) => {
1469
1614
  if (!this.userToken) {
1470
1615
  throw new SidechatAPIError("User is not authenticated.");
1471
1616
  }
1472
1617
  try {
1473
- const res = await fetch(`${this.apiRoot}/v1/chats`, {
1474
- method: "GET",
1475
- headers: {
1476
- ...this.defaultHeaders,
1477
- Authorization: `Bearer ${this.userToken}`,
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
+ },
1478
1628
  },
1479
- });
1629
+ );
1480
1630
  const json = await res.json();
1481
1631
  const list = await json.chats;
1482
1632
  let r = [];
@@ -1605,6 +1755,7 @@ class SidechatAPIClient {
1605
1755
  * @method
1606
1756
  * @param {String} postID - alphanumeric ID of post to hide
1607
1757
  * @since 2.6.2
1758
+ * @deprecated since 2.7.0. Please use `blockUser` instead!
1608
1759
  */
1609
1760
  hidePostsFromUser = async (postID) => {
1610
1761
  if (!this.userToken) {
@@ -1635,6 +1786,7 @@ class SidechatAPIClient {
1635
1786
  * Unhides all posts from all users
1636
1787
  * @method
1637
1788
  * @since 2.6.2
1789
+ * @deprecated since 2.7.0. No longer used by the official app and may stop working.
1638
1790
  */
1639
1791
  unhidePostsFromAllUsers = async () => {
1640
1792
  if (!this.userToken) {
@@ -1656,81 +1808,471 @@ class SidechatAPIClient {
1656
1808
  throw new SidechatAPIError(`Failed to unhide post.`);
1657
1809
  }
1658
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
+ };
1659
2201
  }
1660
2202
 
1661
- /**
1662
- * @typedef SidechatColor
1663
- * @prop {String} primary - hex code of primary color
1664
- * @prop {String} secondary - hex code of secondary color
1665
- */
1666
-
1667
- /**
1668
- * List of colors compatible with user conversation icons
1669
- * @prop {SidechatColor[]} colors - list of color themes for user icons
1670
- */
1671
- class SidechatColorList {
1672
- colors = [
1673
- {
1674
- primary: "#74DEEE",
1675
- secondary: "#239EAB",
1676
- },
1677
- {
1678
- primary: "#15FF46",
1679
- secondary: "#3FC0FF",
1680
- },
1681
- {
1682
- primary: "#D9FB8A",
1683
- secondary: "#B1FD00",
1684
- },
1685
- {
1686
- primary: "#FC40FF",
1687
- secondary: "#0DD5B2",
1688
- },
1689
- {
1690
- primary: "#3E973C",
1691
- secondary: "#0F430E",
1692
- },
1693
- {
1694
- primary: "#FFD305",
1695
- secondary: "#F4B320",
1696
- },
1697
- {
1698
- primary: "#8483FF",
1699
- secondary: "#5857FF",
1700
- },
1701
- {
1702
- primary: "#FA81FF",
1703
- secondary: "#722DFF",
1704
- },
1705
- {
1706
- primary: "#00CBFE",
1707
- secondary: "#0D13D5",
1708
- },
1709
- {
1710
- primary: "#FF7B51",
1711
- secondary: "#B2431F",
1712
- },
1713
- {
1714
- primary: "#FF47CC",
1715
- secondary: "#69004C",
1716
- },
1717
- {
1718
- primary: "#00EE6E",
1719
- secondary: "#0C75E6",
1720
- },
1721
- {
1722
- primary: "#FF1885",
1723
- secondary: "#FA81FF",
1724
- },
1725
- {
1726
- primary: "#D8DC44",
1727
- secondary: "#228B3F",
1728
- },
1729
- {
1730
- primary: "#0968E5",
1731
- secondary: "#091970",
1732
- },
1733
- ];
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
+ ];
1734
2276
  }
1735
2277
 
1736
2278
  exports.SidechatAPIClient = SidechatAPIClient;