@crowdedkingdomstudios/crowdyjs 5.2.0 → 5.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/MIGRATION.md +22 -0
- package/dist/client.d.ts +98 -5
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +74 -5
- package/dist/crowdy-client.d.ts +31 -0
- package/dist/crowdy-client.d.ts.map +1 -1
- package/dist/crowdy-client.js +8 -0
- package/dist/domains/actors.d.ts +87 -4
- package/dist/domains/actors.d.ts.map +1 -1
- package/dist/domains/actors.js +87 -4
- package/dist/domains/apps.d.ts +95 -41
- package/dist/domains/apps.d.ts.map +1 -1
- package/dist/domains/apps.js +80 -33
- package/dist/domains/auth.d.ts +139 -19
- package/dist/domains/auth.d.ts.map +1 -1
- package/dist/domains/auth.js +137 -17
- package/dist/domains/channels.d.ts +264 -5
- package/dist/domains/channels.d.ts.map +1 -1
- package/dist/domains/channels.js +264 -5
- package/dist/domains/chunks.d.ts +116 -3
- package/dist/domains/chunks.d.ts.map +1 -1
- package/dist/domains/chunks.js +116 -3
- package/dist/domains/gameModel.d.ts +412 -6
- package/dist/domains/gameModel.d.ts.map +1 -1
- package/dist/domains/gameModel.js +412 -6
- package/dist/domains/platform.d.ts +36 -20
- package/dist/domains/platform.d.ts.map +1 -1
- package/dist/domains/platform.js +29 -18
- package/dist/domains/serverStatus.d.ts +74 -6
- package/dist/domains/serverStatus.d.ts.map +1 -1
- package/dist/domains/serverStatus.js +74 -6
- package/dist/domains/state.d.ts +50 -2
- package/dist/domains/state.d.ts.map +1 -1
- package/dist/domains/state.js +50 -2
- package/dist/domains/teams.d.ts +263 -5
- package/dist/domains/teams.d.ts.map +1 -1
- package/dist/domains/teams.js +263 -5
- package/dist/domains/teleport.d.ts +30 -2
- package/dist/domains/teleport.d.ts.map +1 -1
- package/dist/domains/teleport.js +30 -2
- package/dist/domains/udp.d.ts +341 -5
- package/dist/domains/udp.d.ts.map +1 -1
- package/dist/domains/udp.js +341 -5
- package/dist/domains/users.d.ts +42 -11
- package/dist/domains/users.d.ts.map +1 -1
- package/dist/domains/users.js +41 -10
- package/dist/domains/voxels.d.ts +107 -2
- package/dist/domains/voxels.d.ts.map +1 -1
- package/dist/domains/voxels.js +107 -2
- package/dist/errors.d.ts +116 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +100 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/realtime.d.ts +226 -0
- package/dist/realtime.d.ts.map +1 -1
- package/dist/realtime.js +90 -0
- package/dist/session.d.ts +46 -0
- package/dist/session.d.ts.map +1 -1
- package/dist/session.js +35 -0
- package/dist/types.d.ts +429 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +53 -0
- package/dist/utils.d.ts +86 -0
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +86 -0
- package/dist/world.d.ts +192 -0
- package/dist/world.d.ts.map +1 -1
- package/dist/world.js +170 -0
- package/package.json +1 -1
package/dist/domains/auth.js
CHANGED
|
@@ -1,23 +1,53 @@
|
|
|
1
|
+
import { ChangePasswordDocument, ConfirmEmailDocument, LoginDocument, LogoutAllDevicesDocument, LogoutDocument, RegisterDocument, RequestPasswordResetDocument, ResendConfirmationEmailDocument, ResetPasswordDocument, } from '../generated/graphql.js';
|
|
1
2
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
3
|
+
* Authentication and account-lifecycle flows — exposed as `client.auth`.
|
|
4
|
+
*
|
|
5
|
+
* Targets the **management-api**: every call routes to `managementUrl` (falling
|
|
6
|
+
* back to the game-api endpoint only in legacy single-endpoint mode). The
|
|
7
|
+
* management API owns the `game_tokens` table that backs every login / register
|
|
8
|
+
* / password / email-confirmation flow; the `token` it returns is a
|
|
9
|
+
* `game_tokens` row that game-api validates against the same shared Postgres.
|
|
10
|
+
*
|
|
11
|
+
* {@link login} and {@link register} mint that session token **and** store it on
|
|
12
|
+
* the shared session state automatically, so every later call on *either*
|
|
13
|
+
* endpoint (auth, users, apps, actors, chunks, udp, ...) is authenticated
|
|
14
|
+
* without you threading the token through by hand. Use {@link setToken} to
|
|
15
|
+
* rehydrate a saved token and {@link getToken} to read the current one. `BigInt`
|
|
16
|
+
* ids on the returned user (e.g. `userId`, `orgId`) are decimal strings.
|
|
5
17
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
18
|
+
* **Public — no session required:** {@link login}, {@link register},
|
|
19
|
+
* {@link confirmEmail}, {@link requestPasswordReset}, {@link resetPassword}, and
|
|
20
|
+
* {@link resendConfirmationEmail}. **Require a valid session:** {@link logout},
|
|
21
|
+
* {@link logoutAllDevices}, and {@link changePassword}, which otherwise throw
|
|
22
|
+
* {@link CrowdyGraphQLError} with `UNAUTHENTICATED` when the bearer token is
|
|
23
|
+
* missing, expired, or revoked.
|
|
10
24
|
*/
|
|
11
|
-
import { ChangePasswordDocument, ConfirmEmailDocument, LoginDocument, LogoutAllDevicesDocument, LogoutDocument, RegisterDocument, RequestPasswordResetDocument, ResendConfirmationEmailDocument, ResetPasswordDocument, } from '../generated/graphql.js';
|
|
12
25
|
export class AuthAPI {
|
|
13
26
|
constructor(graphql, session) {
|
|
14
27
|
this.graphql = graphql;
|
|
15
28
|
this.session = session;
|
|
16
29
|
}
|
|
17
30
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
31
|
+
* Authenticate with email + password and start a new session. **Public** — no
|
|
32
|
+
* existing session required.
|
|
33
|
+
*
|
|
34
|
+
* On success the returned `token` is minted **and** stored on the shared
|
|
35
|
+
* session state, so subsequent calls on any sub-client (management-api or
|
|
36
|
+
* game-api) carry it automatically — no need to call {@link setToken}.
|
|
37
|
+
*
|
|
38
|
+
* @param input - Credentials ({@link LoginUserInput}): `email` and `password`
|
|
39
|
+
* (min 8 characters).
|
|
40
|
+
* @returns An {@link AuthResponse}: the opaque session `token` (sent as
|
|
41
|
+
* `Authorization: Bearer <token>`), `gameTokenId` (the session row id, a
|
|
42
|
+
* string), and the authenticated `user`.
|
|
43
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` on invalid credentials, or
|
|
44
|
+
* `BAD_USER_INPUT` on malformed input.
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const { user } = await client.auth.login({ email, password });
|
|
48
|
+
* // the session token is now stored; later calls are authenticated for you
|
|
49
|
+
* await client.users.me();
|
|
50
|
+
* ```
|
|
21
51
|
*/
|
|
22
52
|
async login(input) {
|
|
23
53
|
const data = await this.graphql.request(LoginDocument, { input });
|
|
@@ -26,7 +56,21 @@ export class AuthAPI {
|
|
|
26
56
|
}
|
|
27
57
|
return data.login;
|
|
28
58
|
}
|
|
29
|
-
/**
|
|
59
|
+
/**
|
|
60
|
+
* Create a new (initially unconfirmed) account, send a confirmation email, and
|
|
61
|
+
* return a session for immediate login. **Public** — no existing session
|
|
62
|
+
* required. Same token-persistence behaviour as {@link login}: the new `token`
|
|
63
|
+
* is stored on the shared session state automatically.
|
|
64
|
+
*
|
|
65
|
+
* @param input - New-account details ({@link RegisterUserInput}): `email`
|
|
66
|
+
* (where the confirmation email is sent), `password` (min 8 characters), and
|
|
67
|
+
* an optional initial `gamertag` (min 3 characters; can also be set later via
|
|
68
|
+
* `client.users.updateGamertag`).
|
|
69
|
+
* @returns An {@link AuthResponse} (session `token`, `gameTokenId`, and the new
|
|
70
|
+
* `user`).
|
|
71
|
+
* @throws {CrowdyGraphQLError} `BAD_USER_INPUT` if the email already exists or
|
|
72
|
+
* the input is invalid.
|
|
73
|
+
*/
|
|
30
74
|
async register(input) {
|
|
31
75
|
const data = await this.graphql.request(RegisterDocument, { input });
|
|
32
76
|
if (data.register?.token) {
|
|
@@ -35,41 +79,106 @@ export class AuthAPI {
|
|
|
35
79
|
return data.register;
|
|
36
80
|
}
|
|
37
81
|
/**
|
|
38
|
-
* Single-device logout
|
|
39
|
-
*
|
|
82
|
+
* Single-device logout: revoke the `game_tokens` row that authenticated this
|
|
83
|
+
* request; other devices/tokens are unaffected. After a successful server-side
|
|
84
|
+
* revoke the in-memory token is cleared from the shared session state so the
|
|
85
|
+
* other sub-clients stop using it. Requires a valid session.
|
|
86
|
+
*
|
|
87
|
+
* @returns `true` if a token was revoked, or `false` if the request carried no
|
|
88
|
+
* game token.
|
|
89
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` if the session is invalid.
|
|
40
90
|
*/
|
|
41
91
|
async logout() {
|
|
42
92
|
const data = await this.graphql.request(LogoutDocument);
|
|
43
93
|
this.session.setToken(null);
|
|
44
94
|
return data.logout;
|
|
45
95
|
}
|
|
46
|
-
/**
|
|
96
|
+
/**
|
|
97
|
+
* Revoke **every** active session for the authenticated user (deletes all
|
|
98
|
+
* their `game_tokens` rows and records revocations). Requires a valid session;
|
|
99
|
+
* use {@link logout} to end only the current one.
|
|
100
|
+
*
|
|
101
|
+
* Note: unlike {@link logout}, this does not clear the SDK's in-memory token —
|
|
102
|
+
* call {@link setToken}`(null)` afterwards if you also want to drop it locally.
|
|
103
|
+
*
|
|
104
|
+
* @returns `true` on success.
|
|
105
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` if the session is invalid.
|
|
106
|
+
*/
|
|
47
107
|
async logoutAllDevices() {
|
|
48
108
|
const data = await this.graphql.request(LogoutAllDevicesDocument);
|
|
49
109
|
return data.logoutAllDevices;
|
|
50
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* Confirm a user's email address using the token from the confirmation email.
|
|
113
|
+
* **Public** — the token itself authorizes the call.
|
|
114
|
+
*
|
|
115
|
+
* @param token - The confirmation token from the emailed link.
|
|
116
|
+
* @returns `true` on success, or `false` if the token is invalid or expired.
|
|
117
|
+
* @throws {CrowdyGraphQLError} on transport/validation failures (invalid or
|
|
118
|
+
* expired tokens resolve to `false` rather than throwing).
|
|
119
|
+
*/
|
|
51
120
|
async confirmEmail(token) {
|
|
52
121
|
const data = await this.graphql.request(ConfirmEmailDocument, { token });
|
|
53
122
|
return data.confirmEmail;
|
|
54
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Start the password-reset flow by emailing a reset link to the address.
|
|
126
|
+
* **Public**. Always returns `true` regardless of whether the email exists or
|
|
127
|
+
* is confirmed, to prevent account enumeration.
|
|
128
|
+
*
|
|
129
|
+
* @param email - Email address to send the password-reset link to.
|
|
130
|
+
* @returns `true` (always, even when no such account exists).
|
|
131
|
+
* @throws {CrowdyGraphQLError} on transport/validation failures.
|
|
132
|
+
*/
|
|
55
133
|
async requestPasswordReset(email) {
|
|
56
134
|
const data = await this.graphql.request(RequestPasswordResetDocument, {
|
|
57
135
|
email,
|
|
58
136
|
});
|
|
59
137
|
return data.requestPasswordReset;
|
|
60
138
|
}
|
|
139
|
+
/**
|
|
140
|
+
* Complete a password reset using the reset token and a new password.
|
|
141
|
+
* **Public** — the reset token authorizes the call. Existing sessions are
|
|
142
|
+
* **not** revoked.
|
|
143
|
+
*
|
|
144
|
+
* @param input - {@link ResetPasswordInput}: the `token` from the emailed reset
|
|
145
|
+
* link and the `newPassword` to set (min 8 characters).
|
|
146
|
+
* @returns `true` on success.
|
|
147
|
+
* @throws {CrowdyGraphQLError} `BAD_USER_INPUT` if the token is invalid or
|
|
148
|
+
* expired.
|
|
149
|
+
*/
|
|
61
150
|
async resetPassword(input) {
|
|
62
151
|
const data = await this.graphql.request(ResetPasswordDocument, {
|
|
63
152
|
input,
|
|
64
153
|
});
|
|
65
154
|
return data.resetPassword;
|
|
66
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Re-send the email-confirmation link. **Public**. Always returns `true`
|
|
158
|
+
* regardless of whether the account exists or is already confirmed (prevents
|
|
159
|
+
* enumeration); the email is only actually sent for existing unconfirmed
|
|
160
|
+
* accounts.
|
|
161
|
+
*
|
|
162
|
+
* @param email - Email address of the account to re-send confirmation to.
|
|
163
|
+
* @returns `true` (always).
|
|
164
|
+
* @throws {CrowdyGraphQLError} on transport/validation failures.
|
|
165
|
+
*/
|
|
67
166
|
async resendConfirmationEmail(email) {
|
|
68
167
|
const data = await this.graphql.request(ResendConfirmationEmailDocument, {
|
|
69
168
|
email,
|
|
70
169
|
});
|
|
71
170
|
return data.resendConfirmationEmail;
|
|
72
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Change the authenticated user's password after verifying the current one.
|
|
174
|
+
* Requires a valid session. Existing sessions are **not** revoked.
|
|
175
|
+
*
|
|
176
|
+
* @param currentPassword - The user's current password, for verification.
|
|
177
|
+
* @param newPassword - The new password to set (min 8 characters).
|
|
178
|
+
* @returns `true` on success.
|
|
179
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` without a valid session, or
|
|
180
|
+
* `BAD_USER_INPUT` if the current password is wrong.
|
|
181
|
+
*/
|
|
73
182
|
async changePassword(currentPassword, newPassword) {
|
|
74
183
|
const data = await this.graphql.request(ChangePasswordDocument, {
|
|
75
184
|
currentPassword,
|
|
@@ -77,11 +186,22 @@ export class AuthAPI {
|
|
|
77
186
|
});
|
|
78
187
|
return data.changePassword;
|
|
79
188
|
}
|
|
80
|
-
/**
|
|
189
|
+
/**
|
|
190
|
+
* Imperatively replace the in-memory bearer token on the shared session state
|
|
191
|
+
* (e.g. to rehydrate a token persisted to disk). Affects every sub-client.
|
|
192
|
+
* Local only — performs no network call. Pass `null` to clear it.
|
|
193
|
+
*
|
|
194
|
+
* @param token - The bearer token to use, or `null` to clear the session.
|
|
195
|
+
*/
|
|
81
196
|
setToken(token) {
|
|
82
197
|
this.session.setToken(token);
|
|
83
198
|
}
|
|
84
|
-
/**
|
|
199
|
+
/**
|
|
200
|
+
* Read the current in-memory bearer token from the shared session state. Local
|
|
201
|
+
* only — performs no network call.
|
|
202
|
+
*
|
|
203
|
+
* @returns The current bearer token, or `null` if none is set.
|
|
204
|
+
*/
|
|
85
205
|
getToken() {
|
|
86
206
|
return this.session.getToken();
|
|
87
207
|
}
|
|
@@ -1,34 +1,293 @@
|
|
|
1
1
|
import type { GraphQLClient } from '../client.js';
|
|
2
2
|
import { type MyChannelsQuery, type MyChannelsQueryVariables, type ChannelsQuery, type ChannelsQueryVariables, type ChannelQuery, type ChannelQueryVariables, type ChannelMembersQuery, type ChannelMembersQueryVariables, type ChannelRolesQuery, type ChannelRolesQueryVariables, type ChannelPolicyQuery, type ChannelPolicyQueryVariables, type SetChannelPolicyMutation, type SetChannelPolicyMutationVariables, type CreateChannelMutation, type CreateChannelMutationVariables, type UpdateChannelMutation, type UpdateChannelMutationVariables, type DeleteChannelMutationVariables, type JoinChannelMutation, type JoinChannelMutationVariables, type RequestToJoinChannelMutation, type RequestToJoinChannelMutationVariables, type LeaveChannelMutationVariables, type AddChannelMemberMutation, type AddChannelMemberMutationVariables, type RemoveChannelMemberMutationVariables, type SetChannelMemberRolesMutation, type SetChannelMemberRolesMutationVariables, type CreateChannelRoleMutation, type CreateChannelRoleMutationVariables, type UpdateChannelRoleMutation, type UpdateChannelRoleMutationVariables, type DeleteChannelRoleMutationVariables } from '../generated/graphql.js';
|
|
3
3
|
/**
|
|
4
|
-
* Channels: app-scoped
|
|
5
|
-
*
|
|
6
|
-
* CRUD/membership runs over the game-api GraphQL endpoint; publishing and
|
|
7
|
-
* receiving channel messages happens over the realtime UDP path (`client.udp`).
|
|
4
|
+
* Channels: app-scoped, location-independent pub/sub messaging groups on the
|
|
5
|
+
* **game-api**. Exposed as `client.channels`.
|
|
8
6
|
*
|
|
9
|
-
*
|
|
7
|
+
* A channel is a named subscriber set with role-gated messaging, built on the
|
|
8
|
+
* same generic groups subsystem as Teams (`group_type='channel'`). The methods
|
|
9
|
+
* here manage a channel's lifecycle and configuration — creating channels,
|
|
10
|
+
* listing/fetching them, managing membership (join/leave/add/remove), roles,
|
|
11
|
+
* and the per-app channel policy — all over the game-api GraphQL endpoint.
|
|
12
|
+
*
|
|
13
|
+
* Realtime message delivery is a **separate** path: publish to a channel with
|
|
14
|
+
* `client.udp.sendChannelMessage(...)` over UDP. That call requires the
|
|
15
|
+
* channel's `send_messages` permission and fans the payload out to every
|
|
16
|
+
* active member (as a `ChannelMessageNotification` on `client.udp`
|
|
17
|
+
* notifications) rather than chunk-routing it. The methods on this class never
|
|
18
|
+
* carry message payloads — they only manage who belongs to a channel and what
|
|
19
|
+
* each member may do.
|
|
20
|
+
*
|
|
21
|
+
* `BigInt` ids (`appId`, `groupId`, `userId`, `groupRoleId`) are sent and
|
|
22
|
+
* received as decimal strings.
|
|
23
|
+
*
|
|
24
|
+
* Every method requires an authenticated session (a Bearer token set via
|
|
25
|
+
* `client.auth.login()` or `client.setToken()`) and the caller must be
|
|
26
|
+
* entitled to the target app; membership/role/policy mutations additionally
|
|
27
|
+
* require a specific channel permission (e.g. `manage_group`, `manage_members`,
|
|
28
|
+
* `manage_roles`) or app-admin (`manage_apps`). Failures throw
|
|
29
|
+
* {@link CrowdyGraphQLError} carrying a stable `extensions.code` such as
|
|
30
|
+
* `UNAUTHENTICATED`, `SCOPE_MISSING`, or `FORBIDDEN`.
|
|
10
31
|
*/
|
|
11
32
|
export declare class ChannelsAPI {
|
|
12
33
|
private gql;
|
|
13
34
|
constructor(gql: GraphQLClient);
|
|
35
|
+
/**
|
|
36
|
+
* List the caller's own channels in an app, each with the caller's roles and
|
|
37
|
+
* effective channel permissions (e.g. whether they hold `send_messages`). Use
|
|
38
|
+
* this to discover which channels the current user can read and post in.
|
|
39
|
+
*
|
|
40
|
+
* @param appId - The app (tenant) to list the caller's channels within, as a
|
|
41
|
+
* decimal `BigInt` string.
|
|
42
|
+
* @returns One {@link GroupMembership} per channel the caller belongs to
|
|
43
|
+
* (the channel {@link Group}, the caller's {@link GroupRole}s, their
|
|
44
|
+
* effective permission keys, and the join time).
|
|
45
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` if there is no valid token,
|
|
46
|
+
* or `SCOPE_MISSING` / `FORBIDDEN` if the caller isn't entitled to the app.
|
|
47
|
+
*/
|
|
14
48
|
mine(appId: MyChannelsQueryVariables['appId']): Promise<MyChannelsQuery['myChannels']>;
|
|
49
|
+
/**
|
|
50
|
+
* List all active channels in an app — not just the caller's. Use
|
|
51
|
+
* {@link mine} instead when you only want the channels the caller belongs to.
|
|
52
|
+
*
|
|
53
|
+
* @param appId - The app (tenant) whose channels to list, as a decimal
|
|
54
|
+
* `BigInt` string.
|
|
55
|
+
* @returns Every active channel in the app as {@link Group} records.
|
|
56
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED`, or `SCOPE_MISSING` /
|
|
57
|
+
* `FORBIDDEN` if the caller isn't entitled to the app.
|
|
58
|
+
*/
|
|
15
59
|
list(appId: ChannelsQueryVariables['appId']): Promise<ChannelsQuery['channels']>;
|
|
60
|
+
/**
|
|
61
|
+
* Fetch a single channel by its group id.
|
|
62
|
+
*
|
|
63
|
+
* @param groupId - The channel's group id, as a decimal `BigInt` string.
|
|
64
|
+
* @returns The channel as a {@link Group}.
|
|
65
|
+
* @throws {CrowdyGraphQLError} if the id does not resolve to a channel (e.g.
|
|
66
|
+
* it is a team, or does not exist), or `UNAUTHENTICATED` / `FORBIDDEN` if
|
|
67
|
+
* the caller isn't entitled to the app.
|
|
68
|
+
*/
|
|
16
69
|
get(groupId: ChannelQueryVariables['groupId']): Promise<ChannelQuery['channel']>;
|
|
70
|
+
/**
|
|
71
|
+
* List a channel's members — its subscriber set, including pending join
|
|
72
|
+
* requests — each with their membership status and roles.
|
|
73
|
+
*
|
|
74
|
+
* @param groupId - The channel whose members to list, as a decimal `BigInt`
|
|
75
|
+
* string.
|
|
76
|
+
* @returns The channel's members as {@link GroupMember} records.
|
|
77
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN` if the caller
|
|
78
|
+
* isn't entitled to the channel's app.
|
|
79
|
+
*/
|
|
17
80
|
members(groupId: ChannelMembersQueryVariables['groupId']): Promise<ChannelMembersQuery['channelMembers']>;
|
|
81
|
+
/**
|
|
82
|
+
* List a channel's roles, including the system `leader` role and any default
|
|
83
|
+
* `member` role (which typically grants `send_messages`).
|
|
84
|
+
*
|
|
85
|
+
* @param groupId - The channel whose roles to list, as a decimal `BigInt`
|
|
86
|
+
* string.
|
|
87
|
+
* @returns The channel's roles as {@link GroupRole} records, each with its
|
|
88
|
+
* granted permission keys.
|
|
89
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN` if the caller
|
|
90
|
+
* isn't entitled to the channel's app.
|
|
91
|
+
*/
|
|
18
92
|
roles(groupId: ChannelRolesQueryVariables['groupId']): Promise<ChannelRolesQuery['channelRoles']>;
|
|
93
|
+
/**
|
|
94
|
+
* Read an app's current channel policy: who may create channels and the
|
|
95
|
+
* default membership policy applied to new channels. Falls back to app
|
|
96
|
+
* defaults when unset.
|
|
97
|
+
*
|
|
98
|
+
* @param appId - The app (tenant) whose channel policy to read, as a decimal
|
|
99
|
+
* `BigInt` string.
|
|
100
|
+
* @returns The effective {@link AppGroupPolicy} for channels in the app
|
|
101
|
+
* (creation policy, default membership policy, and any member/group caps).
|
|
102
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED` / `FORBIDDEN` if the caller
|
|
103
|
+
* isn't entitled to the app.
|
|
104
|
+
*/
|
|
19
105
|
policy(appId: ChannelPolicyQueryVariables['appId']): Promise<ChannelPolicyQuery['channelPolicy']>;
|
|
106
|
+
/**
|
|
107
|
+
* Create a channel in an app. Whether the caller may create one is governed
|
|
108
|
+
* by the per-app channel creation policy (`admin` | `member` | `anyone`).
|
|
109
|
+
* The caller becomes the owner with a system `leader` role. When
|
|
110
|
+
* `input.membersCanSend` is true (the default) a default `member` role
|
|
111
|
+
* granting `send_messages` is created and auto-assigned to joiners (an open
|
|
112
|
+
* chat channel); when false, only roles you explicitly grant may post (an
|
|
113
|
+
* announce / read-only channel).
|
|
114
|
+
*
|
|
115
|
+
* @param input - {@link CreateChannelInput}: the owning `appId`, the channel
|
|
116
|
+
* `name` (max 128 chars, unique per app + type), and optional
|
|
117
|
+
* `description`, `membershipPolicy` (`open` | `request` | `invite` |
|
|
118
|
+
* `admin`; defaults to the app policy), and `membersCanSend` flag.
|
|
119
|
+
* @returns The newly created channel as a {@link Group}.
|
|
120
|
+
* @throws {CrowdyGraphQLError} `BAD_USER_INPUT` (e.g. name too long or a
|
|
121
|
+
* duplicate name), `FORBIDDEN` if the channel policy disallows creation, or
|
|
122
|
+
* `UNAUTHENTICATED`.
|
|
123
|
+
*/
|
|
20
124
|
create(input: CreateChannelMutationVariables['input']): Promise<CreateChannelMutation['createChannel']>;
|
|
125
|
+
/**
|
|
126
|
+
* Update a channel's name, description, and/or membership policy. Only the
|
|
127
|
+
* fields present on `input` change; omitted fields are left as-is. Requires
|
|
128
|
+
* the `manage_group` channel permission (app admins bypass).
|
|
129
|
+
*
|
|
130
|
+
* @param input - {@link UpdateChannelInput}: the `groupId` plus the fields to
|
|
131
|
+
* change — `name` (max 128 chars), `description`, and/or `membershipPolicy`
|
|
132
|
+
* (`open` | `request` | `invite` | `admin`).
|
|
133
|
+
* @returns The updated channel as a {@link Group}.
|
|
134
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` / `SCOPE_MISSING` if the caller
|
|
135
|
+
* lacks `manage_group`, `BAD_USER_INPUT` on a validation failure, or
|
|
136
|
+
* `UNAUTHENTICATED`.
|
|
137
|
+
*/
|
|
21
138
|
update(input: UpdateChannelMutationVariables['input']): Promise<UpdateChannelMutation['updateChannel']>;
|
|
139
|
+
/**
|
|
140
|
+
* Delete a channel. Requires the `manage_group` channel permission (app
|
|
141
|
+
* admins bypass). **Destructive**: cascades to the channel's members and
|
|
142
|
+
* roles and notifies Buddy servers to tear down message routing for the
|
|
143
|
+
* channel.
|
|
144
|
+
*
|
|
145
|
+
* @param groupId - The channel to delete, as a decimal `BigInt` string.
|
|
146
|
+
* @returns `true` on success.
|
|
147
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` / `SCOPE_MISSING` if the caller
|
|
148
|
+
* lacks `manage_group`, or `UNAUTHENTICATED`.
|
|
149
|
+
*/
|
|
22
150
|
remove(groupId: DeleteChannelMutationVariables['groupId']): Promise<boolean>;
|
|
151
|
+
/**
|
|
152
|
+
* Set who may create channels in an app and the default membership policy
|
|
153
|
+
* for new channels. Requires app-admin (`manage_apps`). Affects future
|
|
154
|
+
* channel creation only — existing channels are unchanged.
|
|
155
|
+
*
|
|
156
|
+
* @param input - {@link SetChannelPolicyInput}: the `appId`, the
|
|
157
|
+
* `creationPolicy` (`admin` | `member` | `anyone`), the
|
|
158
|
+
* `defaultMembershipPolicy` (`open` | `request` | `invite` | `admin`), and
|
|
159
|
+
* optional `maxMembers` / `maxGroupsPerUser` caps (`null` = unlimited).
|
|
160
|
+
* @returns The updated {@link AppGroupPolicy}.
|
|
161
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` / `SCOPE_MISSING` if the caller
|
|
162
|
+
* isn't app-admin, `BAD_USER_INPUT` on an invalid policy value, or
|
|
163
|
+
* `UNAUTHENTICATED`.
|
|
164
|
+
*/
|
|
23
165
|
setPolicy(input: SetChannelPolicyMutationVariables['input']): Promise<SetChannelPolicyMutation['setChannelPolicy']>;
|
|
166
|
+
/**
|
|
167
|
+
* Join a channel as the caller (subscribe to it). Honors the channel's
|
|
168
|
+
* membership policy: `open` → active immediately; `request` → pending until
|
|
169
|
+
* a manager approves; `invite` / `admin` → rejected. On becoming active,
|
|
170
|
+
* Buddy is notified with the caller's effective send permission so message
|
|
171
|
+
* routing starts.
|
|
172
|
+
*
|
|
173
|
+
* @param groupId - The channel to join, as a decimal `BigInt` string.
|
|
174
|
+
* @returns The caller's {@link GroupMember} record; its `status` reflects
|
|
175
|
+
* `active` vs. `pending`.
|
|
176
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` if the membership policy rejects
|
|
177
|
+
* the join, or `UNAUTHENTICATED`.
|
|
178
|
+
*/
|
|
24
179
|
join(groupId: JoinChannelMutationVariables['groupId']): Promise<JoinChannelMutation['joinChannel']>;
|
|
180
|
+
/**
|
|
181
|
+
* Request to join a request-only channel, creating a pending membership a
|
|
182
|
+
* manager can later approve via {@link addMember}. Behaves identically to
|
|
183
|
+
* {@link join}; it exists as a clearer name for request-policy UIs.
|
|
184
|
+
*
|
|
185
|
+
* @param groupId - The request-only channel to request to join, as a decimal
|
|
186
|
+
* `BigInt` string.
|
|
187
|
+
* @returns The caller's pending {@link GroupMember} record.
|
|
188
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` if the membership policy rejects
|
|
189
|
+
* the request, or `UNAUTHENTICATED`.
|
|
190
|
+
*/
|
|
25
191
|
requestToJoin(groupId: RequestToJoinChannelMutationVariables['groupId']): Promise<RequestToJoinChannelMutation['requestToJoinChannel']>;
|
|
192
|
+
/**
|
|
193
|
+
* Leave a channel (unsubscribe the caller). Notifies Buddy to stop routing
|
|
194
|
+
* messages to the caller.
|
|
195
|
+
*
|
|
196
|
+
* @param groupId - The channel to leave, as a decimal `BigInt` string.
|
|
197
|
+
* @returns `true` if a membership was removed (`false` if the caller wasn't
|
|
198
|
+
* a member).
|
|
199
|
+
* @throws {CrowdyGraphQLError} `UNAUTHENTICATED`.
|
|
200
|
+
*/
|
|
26
201
|
leave(groupId: LeaveChannelMutationVariables['groupId']): Promise<boolean>;
|
|
202
|
+
/**
|
|
203
|
+
* Add a user to a channel, or approve their pending join request (upserts
|
|
204
|
+
* the membership to `active`). Requires the `manage_members` channel
|
|
205
|
+
* permission (app admins bypass). Auto-assigns the channel's default role if
|
|
206
|
+
* configured and notifies Buddy with the member's effective send permission.
|
|
207
|
+
*
|
|
208
|
+
* @param groupId - The channel to add the user to, as a decimal `BigInt`
|
|
209
|
+
* string.
|
|
210
|
+
* @param userId - The user to add or approve, as a decimal `BigInt` string.
|
|
211
|
+
* @returns The added/approved {@link GroupMember} record.
|
|
212
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` / `SCOPE_MISSING` if the caller
|
|
213
|
+
* lacks `manage_members`, or `UNAUTHENTICATED`.
|
|
214
|
+
*/
|
|
27
215
|
addMember(groupId: AddChannelMemberMutationVariables['groupId'], userId: AddChannelMemberMutationVariables['userId']): Promise<AddChannelMemberMutation['addChannelMember']>;
|
|
216
|
+
/**
|
|
217
|
+
* Remove a member from a channel. Requires the `manage_members` channel
|
|
218
|
+
* permission, except that any member may remove themselves (pass their own
|
|
219
|
+
* `userId`). Notifies Buddy to stop routing messages to the removed member.
|
|
220
|
+
*
|
|
221
|
+
* @param groupId - The channel to remove the user from, as a decimal
|
|
222
|
+
* `BigInt` string.
|
|
223
|
+
* @param userId - The user to remove; may be the caller's own id to
|
|
224
|
+
* self-remove. Decimal `BigInt` string.
|
|
225
|
+
* @returns `true` if a membership was removed.
|
|
226
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` / `SCOPE_MISSING` when removing
|
|
227
|
+
* another member without `manage_members`, or `UNAUTHENTICATED`.
|
|
228
|
+
*/
|
|
28
229
|
removeMember(groupId: RemoveChannelMemberMutationVariables['groupId'], userId: RemoveChannelMemberMutationVariables['userId']): Promise<boolean>;
|
|
230
|
+
/**
|
|
231
|
+
* Replace a member's channel roles with the given set. This is **not
|
|
232
|
+
* additive** — roles not listed are removed. Requires the `manage_roles`
|
|
233
|
+
* channel permission (app admins bypass). Re-pushes the member's effective
|
|
234
|
+
* send permission to Buddy so their ability to post updates immediately.
|
|
235
|
+
*
|
|
236
|
+
* @param input - {@link SetMemberRolesInput}: the `groupId`, the target
|
|
237
|
+
* `userId`, and `roleIds` — the complete set of channel role ids the member
|
|
238
|
+
* should have (ids that are unknown or belong to another group are
|
|
239
|
+
* ignored).
|
|
240
|
+
* @returns The updated {@link GroupMember} record with its new roles.
|
|
241
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` / `SCOPE_MISSING` if the caller
|
|
242
|
+
* lacks `manage_roles`, or `UNAUTHENTICATED`.
|
|
243
|
+
*/
|
|
29
244
|
setMemberRoles(input: SetChannelMemberRolesMutationVariables['input']): Promise<SetChannelMemberRolesMutation['setChannelMemberRoles']>;
|
|
245
|
+
/**
|
|
246
|
+
* Create a custom (non-system) channel role granting the given channel
|
|
247
|
+
* permission keys (e.g. `send_messages` for posting rights). Requires the
|
|
248
|
+
* `manage_roles` channel permission (app admins bypass).
|
|
249
|
+
*
|
|
250
|
+
* @param input - {@link CreateGroupRoleInput}: the `groupId`, the `roleName`
|
|
251
|
+
* (max 128 chars, unique within the channel), the `permissions` keys to
|
|
252
|
+
* grant (e.g. `send_messages`, `manage_members`; each max 64 chars,
|
|
253
|
+
* defaults to none), and an optional `rank` (higher = more senior;
|
|
254
|
+
* defaults to 0).
|
|
255
|
+
* @returns The created {@link GroupRole}.
|
|
256
|
+
* @throws {CrowdyGraphQLError} `BAD_USER_INPUT` on an invalid/duplicate name
|
|
257
|
+
* or unknown permission key, `FORBIDDEN` / `SCOPE_MISSING` if the caller
|
|
258
|
+
* lacks `manage_roles`, or `UNAUTHENTICATED`.
|
|
259
|
+
*/
|
|
30
260
|
createRole(input: CreateChannelRoleMutationVariables['input']): Promise<CreateChannelRoleMutation['createChannelRole']>;
|
|
261
|
+
/**
|
|
262
|
+
* Update a channel role's name, rank, and/or permission keys (system roles
|
|
263
|
+
* cannot be renamed or re-ranked). When `input.permissions` is supplied it
|
|
264
|
+
* **replaces** the role's existing keys. Requires the `manage_roles` channel
|
|
265
|
+
* permission (app admins bypass).
|
|
266
|
+
*
|
|
267
|
+
* Note: changing `send_messages` here does not re-push to Buddy until each
|
|
268
|
+
* affected member's roles are re-applied via {@link setMemberRoles}.
|
|
269
|
+
*
|
|
270
|
+
* @param input - {@link UpdateGroupRoleInput}: the `groupRoleId` plus the
|
|
271
|
+
* fields to change (`roleName`, `permissions`, `rank`); omitted fields are
|
|
272
|
+
* left unchanged.
|
|
273
|
+
* @returns The updated {@link GroupRole}.
|
|
274
|
+
* @throws {CrowdyGraphQLError} `BAD_USER_INPUT` on a validation failure,
|
|
275
|
+
* `FORBIDDEN` / `SCOPE_MISSING` if the caller lacks `manage_roles`, or
|
|
276
|
+
* `UNAUTHENTICATED`.
|
|
277
|
+
*/
|
|
31
278
|
updateRole(input: UpdateChannelRoleMutationVariables['input']): Promise<UpdateChannelRoleMutation['updateChannelRole']>;
|
|
279
|
+
/**
|
|
280
|
+
* Delete a non-system channel role. Requires the `manage_roles` channel
|
|
281
|
+
* permission (app admins bypass). The system `leader` role cannot be
|
|
282
|
+
* deleted. **Destructive**: removes the role from any members that held it.
|
|
283
|
+
*
|
|
284
|
+
* @param groupRoleId - The channel role to delete (must be a non-system
|
|
285
|
+
* role), as a decimal `BigInt` string.
|
|
286
|
+
* @returns `true` if a role was deleted.
|
|
287
|
+
* @throws {CrowdyGraphQLError} `FORBIDDEN` / `SCOPE_MISSING` if the caller
|
|
288
|
+
* lacks `manage_roles`, `BAD_USER_INPUT` if targeting a system role, or
|
|
289
|
+
* `UNAUTHENTICATED`.
|
|
290
|
+
*/
|
|
32
291
|
deleteRole(groupRoleId: DeleteChannelRoleMutationVariables['groupRoleId']): Promise<boolean>;
|
|
33
292
|
}
|
|
34
293
|
//# sourceMappingURL=channels.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/domains/channels.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,EAEL,KAAK,eAAe,EACpB,KAAK,wBAAwB,EAE7B,KAAK,aAAa,EAClB,KAAK,sBAAsB,EAE3B,KAAK,YAAY,EACjB,KAAK,qBAAqB,EAE1B,KAAK,mBAAmB,EACxB,KAAK,4BAA4B,EAEjC,KAAK,iBAAiB,EACtB,KAAK,0BAA0B,EAE/B,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAEhC,KAAK,wBAAwB,EAC7B,KAAK,iCAAiC,EAEtC,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EAEnC,KAAK,qBAAqB,EAC1B,KAAK,8BAA8B,EAEnC,KAAK,8BAA8B,EAEnC,KAAK,mBAAmB,EACxB,KAAK,4BAA4B,EAEjC,KAAK,4BAA4B,EACjC,KAAK,qCAAqC,EAE1C,KAAK,6BAA6B,EAElC,KAAK,wBAAwB,EAC7B,KAAK,iCAAiC,EAEtC,KAAK,oCAAoC,EAEzC,KAAK,6BAA6B,EAClC,KAAK,sCAAsC,EAE3C,KAAK,yBAAyB,EAC9B,KAAK,kCAAkC,EAEvC,KAAK,yBAAyB,EAC9B,KAAK,kCAAkC,EAEvC,KAAK,kCAAkC,EACxC,MAAM,yBAAyB,CAAC;AAEjC
|
|
1
|
+
{"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../src/domains/channels.ts"],"names":[],"mappings":"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"}
|