@sublay/js 7.7.1 → 7.9.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 (30) hide show
  1. package/dist/index.d.mts +527 -36
  2. package/dist/index.d.ts +7 -1
  3. package/dist/index.js +102 -23
  4. package/dist/index.mjs +102 -23
  5. package/dist/interfaces/ChatMessage.d.ts +8 -0
  6. package/dist/interfaces/Comment.d.ts +8 -0
  7. package/dist/interfaces/Entity.d.ts +8 -0
  8. package/dist/interfaces/Push.d.ts +55 -1
  9. package/dist/interfaces/ReputationGrant.d.ts +85 -0
  10. package/dist/interfaces/Workspace.d.ts +30 -0
  11. package/dist/modules/auth/changePassword.d.ts +23 -0
  12. package/dist/modules/auth/signOut.d.ts +95 -1
  13. package/dist/modules/chat/getMessage.d.ts +5 -0
  14. package/dist/modules/chat/listMessages.d.ts +5 -1
  15. package/dist/modules/reputation/createGrant.d.ts +45 -0
  16. package/dist/modules/reputation/index.d.ts +2 -0
  17. package/dist/modules/reputation/listGrants.d.ts +45 -0
  18. package/dist/modules/workspaces/createWorkspaceInvite.d.ts +50 -1
  19. package/dist/modules/workspaces/deleteWorkspace.d.ts +2 -2
  20. package/dist/modules/workspaces/fetchManyWorkspaces.d.ts +5 -1
  21. package/dist/modules/workspaces/fetchWorkspaceAuthority.d.ts +5 -0
  22. package/dist/modules/workspaces/fetchWorkspaceMemberStanding.d.ts +5 -1
  23. package/dist/modules/workspaces/fetchWorkspaceMembers.d.ts +5 -0
  24. package/dist/modules/workspaces/leaveWorkspace.d.ts +3 -2
  25. package/dist/modules/workspaces/removeWorkspaceMember.d.ts +1 -1
  26. package/dist/modules/workspaces/transferWorkspaceOwnership.d.ts +1 -1
  27. package/dist/modules/workspaces/updateWorkspace.d.ts +1 -1
  28. package/dist/modules/workspaces/updateWorkspaceInheritFlag.d.ts +1 -1
  29. package/dist/modules/workspaces/updateWorkspaceMember.d.ts +19 -1
  30. package/package.json +1 -1
package/dist/index.d.mts CHANGED
@@ -184,14 +184,182 @@ interface SignInResponse {
184
184
  }
185
185
  declare function signIn(client: SublayHttpClient, data: SignInProps): Promise<SignInResponse>;
186
186
 
187
+ /**
188
+ * Every push event type — the full app-notification type set plus the chat
189
+ * `message` event (push-only). Mirrors the server's `PUSH_EVENT_TYPES` exactly
190
+ * (server `src/constants/push/pushEvents.ts`); these are the only names a
191
+ * `disabledTypes` set may contain.
192
+ */
193
+ declare const PUSH_EVENT_TYPES: readonly ["entity-comment", "comment-reply", "entity-mention", "comment-mention", "entity-reaction", "comment-reaction", "entity-reaction-milestone-specific", "entity-reaction-milestone-total", "comment-reaction-milestone-specific", "comment-reaction-milestone-total", "new-follow", "connection-request", "connection-accepted", "space-membership-approved", "event-invite", "event-updated", "event-cancelled", "reputation-grant", "message"];
194
+ type PushEventType = (typeof PUSH_EVENT_TYPES)[number];
195
+ /**
196
+ * The four conversation-mute duration choices. Send the CHOICE, never a raw
197
+ * timestamp — the server resolves it and represents "forever" via the explicit
198
+ * `mutedForever` signal on the returned member. Mirrors the server's
199
+ * `MUTE_DURATIONS` (server `src/helpers/push/muteDuration.ts`).
200
+ */
201
+ declare const MUTE_DURATIONS: readonly ["8h", "24h", "1w", "forever"];
202
+ type MuteDuration = (typeof MUTE_DURATIONS)[number];
203
+ /** Response of read/update notification preferences. */
204
+ interface NotificationPreferences {
205
+ disabledTypes: PushEventType[];
206
+ }
207
+ /**
208
+ * A Web Push subscription in its SERIALIZED form — the JSON the server reads,
209
+ * not the live browser object.
210
+ *
211
+ * A `PushSubscription` straight from `PushManager.subscribe()` does NOT satisfy
212
+ * this type. It exposes its keys only through `getKey(name)`; there is no `keys`
213
+ * property to read, so it is not assignable here under strict TypeScript, and
214
+ * passing one through a cast sends a body the server rejects.
215
+ *
216
+ * To produce a value of this type:
217
+ *
218
+ * 1. **Serialize** the subscription with `subscription.toJSON()`.
219
+ * 2. **Confirm** `endpoint`, `keys.p256dh` and `keys.auth` are all present —
220
+ * `PushSubscriptionJSON` types every one of them as optional, while the
221
+ * server requires all three as non-empty strings and 400s otherwise.
222
+ *
223
+ * ```ts
224
+ * const json = subscription.toJSON();
225
+ * if (!json.endpoint || !json.keys?.p256dh || !json.keys?.auth) {
226
+ * throw new Error("Incomplete Web Push subscription");
227
+ * }
228
+ * const webPushSubscription: WebPushSubscription = {
229
+ * endpoint: json.endpoint,
230
+ * keys: { p256dh: json.keys.p256dh, auth: json.keys.auth },
231
+ * };
232
+ * ```
233
+ *
234
+ * Mirrors the server's `webPushSubscriptionSchema`
235
+ * (server `src/v7/validation/push-notifications/push-notifications.schema.ts`).
236
+ */
237
+ interface WebPushSubscription {
238
+ endpoint: string;
239
+ keys: {
240
+ p256dh: string;
241
+ auth: string;
242
+ };
243
+ }
244
+ /**
245
+ * Identifies one physical device. Mirrors the server's device-identifier body
246
+ * exactly (server `src/v7/validation/push-notifications/push-notifications.schema.ts`):
247
+ * a provider token for `ios`/`android`, a Web Push subscription for `web`. The
248
+ * union encodes the server's own cross-check — it rejects the same
249
+ * combinations the server's `superRefine` rejects.
250
+ *
251
+ * Passed to `auth.signOut` to unbind that device's push binding in the same
252
+ * transaction as the sign-out.
253
+ */
254
+ type PushDeviceIdentifier = {
255
+ platform: "ios" | "android";
256
+ token: string;
257
+ } | {
258
+ platform: "web";
259
+ subscription: WebPushSubscription;
260
+ };
261
+
187
262
  interface SignOutProps {
188
263
  /**
189
264
  * Defaults to the SDK's stored refresh token (SDK-managed mode). Pass it
190
265
  * explicitly in host-managed mode, where the SDK holds no refresh token.
191
266
  */
192
267
  refreshToken?: string;
268
+ /**
269
+ * Optional. When supplied — and the project has the `push` bundle — the
270
+ * server deletes this user's push binding for that device in the SAME
271
+ * transaction as the token-family destroy: signing out unbinds the device's
272
+ * push, or nothing happens at all.
273
+ *
274
+ * **Needs a refresh token to have any effect.** The unbind is scoped to the
275
+ * `sub` of the refresh token, which is what stops one account removing
276
+ * another account's binding on a shared device — so with no token there is no
277
+ * user to scope it to and the server answers `204` before it ever looks at
278
+ * `pushDevice`. When none can be resolved the field is DROPPED from the
279
+ * request rather than sent into that silent no-op, the sign-out proceeds
280
+ * normally, and the returned `pushUnbindSkipped` says so. Watch for it in
281
+ * **host-managed mode**: such a client is built with `getToken` and no
282
+ * `initialTokens`, and its `setTokens` is inert, so it starts with no refresh
283
+ * token and can never acquire one. Pass `refreshToken` explicitly alongside
284
+ * `pushDevice` there.
285
+ *
286
+ * If the unbind fails the request fails (HTTP 500, code
287
+ * `auth/device-deregistration-failed` or `auth/sign-out-failed`) and NOTHING
288
+ * is committed — the session survives so the caller can retry, and this call
289
+ * rethrows WITHOUT clearing the SDK's local tokens, so the credential that
290
+ * retry needs is still there.
291
+ *
292
+ * That is the ONLY failure that leaves you signed in. Every other one — a
293
+ * `429` from the rate limiter or a quota gate, a `423`, a `503`, a `400` on
294
+ * the body, a dropped connection — never touched a push binding, so it
295
+ * clears the local tokens and RESOLVES: a user must always be able to sign
296
+ * out. See `UNBIND_FAILURE_CODES`.
297
+ *
298
+ * Omit it and the request is byte-identical to before this field existed.
299
+ */
300
+ pushDevice?: PushDeviceIdentifier;
193
301
  }
194
- declare function signOut(client: SublayHttpClient, data?: SignOutProps): Promise<void>;
302
+ /**
303
+ * Why the unbind did not happen. Present only when `pushUnbindSkipped` is
304
+ * `true`, and it exists because THE TWO SKIPS ARE RECOVERED DIFFERENTLY — a
305
+ * caller that cannot tell them apart can only ever pick the wrong remedy for
306
+ * one of them:
307
+ *
308
+ * - `no-refresh-token` — this SDK never asked. Nothing was destroyed either:
309
+ * with no token the server has no session to end, so the account, its
310
+ * credential and its binding are all still there. **Retryable**: re-issue
311
+ * the sign-out with an explicit `refreshToken` and the unbind happens.
312
+ * - `push-unbind-status-unknown` — the server was asked and could not answer.
313
+ * The sign-out itself DID commit, so the credential that would have driven a
314
+ * retry is gone; re-issuing achieves nothing. The binding clears when that
315
+ * account next registers on this device, or when the server prunes the token
316
+ * as undeliverable.
317
+ */
318
+ type PushUnbindSkipReason = "no-refresh-token" | "push-unbind-status-unknown";
319
+ interface SignOutResult {
320
+ /**
321
+ * `true` whenever a `pushDevice` was supplied and the unbind did NOT happen,
322
+ * so this device's push binding for that account may still be live. Either
323
+ * the SDK declined to ask (no refresh token to scope the unbind to) or the
324
+ * server could not answer whether a binding exists; `pushUnbindSkipReason`
325
+ * says which, and the two are recovered differently.
326
+ *
327
+ * `false` means NO SKIP WAS REPORTED — by this SDK or by the server. It is
328
+ * not a promise that no skip happened, and the difference is not academic:
329
+ * the server declines the unbind for several reasons it answers with a plain
330
+ * `204`, and every one of them reads `false` here.
331
+ *
332
+ * - The refresh token is authentic but expired beyond the server's unbind
333
+ * window (90 days past `exp`), so there is no subject to scope the unbind
334
+ * to. Reachable from this SDK by passing an old `refreshToken` explicitly
335
+ * alongside `pushDevice`.
336
+ * - The refresh token is malformed or fails signature verification.
337
+ * - The project has no `push` bundle, so no binding can exist.
338
+ * - The unbind ran and matched zero rows — the binding was already gone, or
339
+ * was never registered under this device key.
340
+ *
341
+ * The server logs each of those under its own reason; only the case where it
342
+ * could not determine whether a binding exists is reported in the response,
343
+ * because that is the one where the binding may still be LIVE and nobody
344
+ * looked. The rest either prove there was nothing to remove or leave a device
345
+ * key the server cannot attribute to a user, and neither gives the caller
346
+ * anything to act on beyond what it already knows.
347
+ *
348
+ * A request that failed short of an unbind attempt reads `false` too — a
349
+ * gate's `429` or `423`, a `503`, a `400`, a dropped connection. Those clear
350
+ * the local tokens and resolve rather than reject (see `UNBIND_FAILURE_CODES`
351
+ * for why), and none of them is a REPORTED skip; they are logged with a
352
+ * warning instead.
353
+ *
354
+ * The sign-out itself is unaffected by the flag in both directions: a user
355
+ * must always be able to sign out, so a skipped unbind never fails the call
356
+ * and never leaves the local tokens in place.
357
+ */
358
+ pushUnbindSkipped: boolean;
359
+ /** Set only when `pushUnbindSkipped` is `true`. See `PushUnbindSkipReason`. */
360
+ pushUnbindSkipReason?: PushUnbindSkipReason;
361
+ }
362
+ declare function signOut(client: SublayHttpClient, data?: SignOutProps): Promise<SignOutResult>;
195
363
 
196
364
  interface RequestNewAccessTokenProps {
197
365
  /** Defaults to the SDK's stored refresh token (SDK-managed mode). */
@@ -234,11 +402,33 @@ interface ChangePasswordProps {
234
402
  /** The user's current password (verified before the change). */
235
403
  password: string;
236
404
  newPassword: string;
405
+ /**
406
+ * Optional. The physical device making this call.
407
+ *
408
+ * A password change also deletes every push binding the user holds, so an
409
+ * intruder's device stops receiving notification content. Naming this device
410
+ * keeps ITS binding — nothing re-binds a device from its live session, so
411
+ * without this the handset the user just changed their password on goes
412
+ * quiet until the app cold-starts or switches accounts.
413
+ *
414
+ * Same value passed to `push.register` / `auth.signOut`. Omit it and every
415
+ * binding for the user goes, this device included.
416
+ */
417
+ pushDevice?: PushDeviceIdentifier;
237
418
  }
238
419
  interface ChangePasswordResponse {
239
420
  success: boolean;
240
421
  message: string;
241
422
  }
423
+ /**
424
+ * Change the signed-in user's password.
425
+ *
426
+ * Ends every OTHER session for that user — every other device must sign in
427
+ * again with the new password — while the session making this call survives.
428
+ * The server identifies that session from the access token this request is
429
+ * already authenticated with, so nothing about the caller's session has to be
430
+ * sent.
431
+ */
242
432
  declare function changePassword(client: SublayHttpClient, data: ChangePasswordProps): Promise<ChangePasswordResponse>;
243
433
 
244
434
  interface SetPasswordProps {
@@ -831,6 +1021,91 @@ declare namespace Users {
831
1021
  export { Users_checkUsernameAvailability as checkUsernameAvailability, Users_createBlock as createBlock, Users_createFollow as createFollow, Users_deleteBlock as deleteBlock, deleteFollow$1 as deleteFollow, Users_fetchBlockStatus as fetchBlockStatus, Users_fetchBlockedUsers as fetchBlockedUsers, Users_fetchConnectionStatus as fetchConnectionStatus, Users_fetchConnectionsByUserId as fetchConnectionsByUserId, Users_fetchConnectionsCountByUserId as fetchConnectionsCountByUserId, Users_fetchFollowStatus as fetchFollowStatus, Users_fetchFollowersByUserId as fetchFollowersByUserId, Users_fetchFollowersCountByUserId as fetchFollowersCountByUserId, Users_fetchFollowingByUserId as fetchFollowingByUserId, Users_fetchFollowingCountByUserId as fetchFollowingCountByUserId, Users_fetchUserByForeignId as fetchUserByForeignId, Users_fetchUserById as fetchUserById, Users_fetchUserByUsername as fetchUserByUsername, Users_fetchUserSuggestions as fetchUserSuggestions, Users_removeConnectionByUserId as removeConnectionByUserId, Users_requestConnection as requestConnection, Users_updateUser as updateUser };
832
1022
  }
833
1023
 
1024
+ /** The three grantable target kinds. Polymorphic — `targetId` carries no FK. */
1025
+ type ReputationGrantTargetType = "entity" | "comment" | "chat-message";
1026
+ /**
1027
+ * Who created the grant. `"user"` is a debited transfer (reputation moved out
1028
+ * of `senderId`'s bucket); `"app"` is a mint issued by the project itself with
1029
+ * a null `senderId`. Persisted rather than inferred from `senderId`, which is
1030
+ * also null for a transfer whose sender was later deleted.
1031
+ */
1032
+ type ReputationGrantSourceType = "user" | "app";
1033
+ /**
1034
+ * The "which item was rewarded" pair, as a both-or-neither union.
1035
+ *
1036
+ * Modelled as a two-branch union rather than two independent optional fields so
1037
+ * a half-filled target — `{ targetType }` with no `targetId`, or the reverse —
1038
+ * does not compile. The server answers that shape with
1039
+ * `400 reputation-grant/invalid-body` on the write (a shared
1040
+ * `bothOrNeitherTarget` refinement) and
1041
+ * `400 reputation-grant/invalid-filter` on the list, so the union turns a
1042
+ * guaranteed round trip into a red squiggle.
1043
+ *
1044
+ * The empty branch is `?: undefined`, NOT `?: null` — deliberately, and for the
1045
+ * same reason `metadata` is not nullable: `grantBodyFields.targetType` is
1046
+ * `.optional()` with no `.nullable()`, so an explicit `targetType: null` is
1047
+ * rejected. Omit both keys to mean "no target".
1048
+ *
1049
+ * Building the pair conditionally needs one accommodation: an inline
1050
+ * conditional spread of just these two keys widens both to `T | undefined` and
1051
+ * then matches neither branch. Either branch the whole argument, or name this
1052
+ * type on a helper and spread that:
1053
+ *
1054
+ * ```ts
1055
+ * const target: ReputationGrantTargetFilter = item
1056
+ * ? { targetType: "entity", targetId: item.id }
1057
+ * : {};
1058
+ * await listGrants(client, { ...base, ...target });
1059
+ * ```
1060
+ */
1061
+ type ReputationGrantTargetFilter = {
1062
+ /** The kind of item rewarded. Requires `targetId` alongside it. */
1063
+ targetType: ReputationGrantTargetType;
1064
+ /** The rewarded item's id. Requires `targetType` alongside it. */
1065
+ targetId: string;
1066
+ } | {
1067
+ targetType?: undefined;
1068
+ targetId?: undefined;
1069
+ };
1070
+ /**
1071
+ * Per-item reputation-grant summary. Covers positive grants only — negative
1072
+ * grants (app deductions) are invisible on every public read surface.
1073
+ */
1074
+ interface GrantSummary {
1075
+ /** Sum of positive grant amounts on the item. */
1076
+ total: number;
1077
+ /** Number of positive grants on the item. */
1078
+ count: number;
1079
+ /** The calling user's own summed positive grants on the item. */
1080
+ viewerTotal: number;
1081
+ }
1082
+ /**
1083
+ * A single reputation movement. Rows are append-only — nothing updates or
1084
+ * soft-deletes them — so the table is the audit log behind every balance.
1085
+ */
1086
+ interface ReputationGrant {
1087
+ id: string;
1088
+ sourceType: ReputationGrantSourceType;
1089
+ /** Null for an app mint, and for a transfer whose sender was deleted. */
1090
+ senderId: string | null;
1091
+ /** Populated when the list is called with `include: "user"`. */
1092
+ sender?: User | null;
1093
+ recipientId: string;
1094
+ /** Populated when the list is called with `include: "user"`. */
1095
+ recipient?: User | null;
1096
+ /** Non-zero. Negative only when `sourceType` is `"app"`. */
1097
+ amount: number;
1098
+ /** The bucket both legs moved in; null = the project-general bucket. */
1099
+ spaceId: string | null;
1100
+ /** Both null or both non-null. */
1101
+ targetType: ReputationGrantTargetType | null;
1102
+ targetId: string | null;
1103
+ note: string | null;
1104
+ metadata: Record<string, any> | null;
1105
+ createdAt: string;
1106
+ updatedAt: string;
1107
+ }
1108
+
834
1109
  type Mention = UserMention | SpaceMention;
835
1110
  interface UserMention {
836
1111
  type: "user";
@@ -1036,6 +1311,13 @@ interface Entity {
1036
1311
  nsfwEffective: boolean;
1037
1312
  topComment: TopComment | null;
1038
1313
  isSaved?: boolean;
1314
+ /**
1315
+ * Reputation-grant summary. Opt-in — present exactly when the read requested
1316
+ * `include=grants`. Once requested the server always returns the object,
1317
+ * zero-filled rather than omitted, on projects with no grants and on projects
1318
+ * without the reputation bundle alike.
1319
+ */
1320
+ grants?: GrantSummary;
1039
1321
  isDraft: boolean | null;
1040
1322
  moderationStatus: "approved" | "removed" | null;
1041
1323
  moderatedAt: string | null;
@@ -1567,6 +1849,13 @@ interface Comment {
1567
1849
  reactionCounts: ReactionCounts;
1568
1850
  userReaction?: ReactionType | null;
1569
1851
  repliesCount: number;
1852
+ /**
1853
+ * Reputation-grant summary. Opt-in — present exactly when the read requested
1854
+ * `include=grants`. Once requested the server always returns the object,
1855
+ * zero-filled rather than omitted, on projects with no grants and on projects
1856
+ * without the reputation bundle alike.
1857
+ */
1858
+ grants?: GrantSummary;
1570
1859
  metadata: Record<string, any>;
1571
1860
  createdAt: string;
1572
1861
  updatedAt: string;
@@ -2051,6 +2340,13 @@ interface ChatMessage {
2051
2340
  threadReplyCount: number;
2052
2341
  reactionCounts: Record<string, number>;
2053
2342
  userReactions: string[];
2343
+ /**
2344
+ * Reputation-grant summary. Opt-in — present exactly when the read requested
2345
+ * `include=grants`. Once requested the server always returns the object,
2346
+ * zero-filled rather than omitted, on projects with no grants and on projects
2347
+ * without the reputation bundle alike.
2348
+ */
2349
+ grants?: GrantSummary;
2054
2350
  editedAt: string | null;
2055
2351
  userDeletedAt: string | null;
2056
2352
  moderationStatus: "approved" | "removed" | null;
@@ -2681,6 +2977,96 @@ declare namespace Reports {
2681
2977
  export { Reports_createReport as createReport, Reports_fetchModeratedReports as fetchModeratedReports };
2682
2978
  }
2683
2979
 
2980
+ interface CreateGrantBaseProps {
2981
+ /** The user receiving the reputation. Cannot be the logged-in user. */
2982
+ recipientId: string;
2983
+ /**
2984
+ * Positive integer. A user transfer can never mint (negatives) nor be a
2985
+ * no-op (zero) — minting is service-key-only and lives in `@sublay/node`.
2986
+ */
2987
+ amount: number;
2988
+ /** The bucket both legs move in. Omitted/null = the project-general bucket. */
2989
+ spaceId?: string | null;
2990
+ /**
2991
+ * Free-text reason. Trimmed and capped at 2000 characters server-side.
2992
+ * Genuinely nullable — an explicit `null` is accepted and means "no note".
2993
+ */
2994
+ note?: string | null;
2995
+ /**
2996
+ * Arbitrary JSON, capped at 1 MB server-side.
2997
+ *
2998
+ * NOT nullable — deliberately asymmetric with `note` directly above, not a
2999
+ * typo. The server's shared `metadataSchema` is `z.record(...).optional()`
3000
+ * with no `.nullable()`, so an explicit `metadata: null` is rejected with
3001
+ * `400 reputation-grant/invalid-body`. Omit the key to mean "no metadata".
3002
+ */
3003
+ metadata?: Record<string, any>;
3004
+ }
3005
+ /**
3006
+ * `targetType` and `targetId` are supplied together or not at all — the
3007
+ * both-or-neither pair is carried by {@link ReputationGrantTargetFilter}, which
3008
+ * makes the half-filled shape a compile error instead of a
3009
+ * `400 reputation-grant/invalid-body`.
3010
+ */
3011
+ type CreateGrantProps = CreateGrantBaseProps & ReputationGrantTargetFilter;
3012
+ /**
3013
+ * Transfers reputation from the logged-in user to another user — a **debited
3014
+ * transfer**: the amount leaves the sender's bucket and lands in the
3015
+ * recipient's bucket in the same space. Nothing is created.
3016
+ *
3017
+ * There is no actor field: the sender is always the user the token belongs to.
3018
+ * Naming somebody else as the sender requires a service key, which this SDK
3019
+ * never holds.
3020
+ */
3021
+ declare function createGrant(client: SublayHttpClient, data: CreateGrantProps): Promise<ReputationGrant>;
3022
+
3023
+ interface ListGrantsBaseProps extends SpaceReputationContextParams {
3024
+ page?: number;
3025
+ limit?: number;
3026
+ /** What this user received. */
3027
+ recipientId?: string;
3028
+ /** What this user sent. */
3029
+ senderId?: string;
3030
+ /** Associations to expand. Only `"user"` is supported (hydrates both parties). */
3031
+ include?: string;
3032
+ }
3033
+ /**
3034
+ * The third filter shape — "who rewarded this item" — is the
3035
+ * {@link ReputationGrantTargetFilter} pair, so a half-filled target is a
3036
+ * compile error rather than a `400 reputation-grant/invalid-filter`.
3037
+ *
3038
+ * Mutual exclusivity between the three shapes is NOT expressed in the type: a
3039
+ * three-way exclusive union would multiply out across every pagination and
3040
+ * space-reputation field and make the props unreadable, for a rule the server
3041
+ * reports clearly. Only the both-or-neither pairing is typed.
3042
+ */
3043
+ type ListGrantsProps = ListGrantsBaseProps & ReputationGrantTargetFilter;
3044
+ /**
3045
+ * The `summary` block rides alongside the page envelope, and only on the
3046
+ * target filter shape.
3047
+ */
3048
+ interface ListGrantsResponse extends PaginatedResponse<ReputationGrant> {
3049
+ summary?: GrantSummary;
3050
+ }
3051
+ /**
3052
+ * Lists reputation grants.
3053
+ *
3054
+ * Exactly one filter shape per request — `recipientId`, `senderId`, or
3055
+ * `targetType` + `targetId`. Supplying none or combining two is a `400`; the
3056
+ * shapes are not AND-ed, which is what keeps the `summary` block reconcilable
3057
+ * with the rows beneath it.
3058
+ *
3059
+ * Only positive grants are ever returned. Negative grants are app moderation
3060
+ * deductions and are unreadable from every public surface.
3061
+ */
3062
+ declare function listGrants(client: SublayHttpClient, data: ListGrantsProps): Promise<ListGrantsResponse>;
3063
+
3064
+ declare const Reputation_createGrant: typeof createGrant;
3065
+ declare const Reputation_listGrants: typeof listGrants;
3066
+ declare namespace Reputation {
3067
+ export { Reputation_createGrant as createGrant, Reputation_listGrants as listGrants };
3068
+ }
3069
+
2684
3070
  interface SearchContentProps extends SpaceReputationContextParams {
2685
3071
  query: string;
2686
3072
  sourceTypes?: ("entity" | "comment" | "message")[];
@@ -3133,7 +3519,11 @@ interface ListMessagesProps extends SpaceReputationContextParams {
3133
3519
  /** Page size (default 50, max 100). */
3134
3520
  limit?: number;
3135
3521
  sort?: "asc" | "desc";
3136
- /** Comma-separated associations to populate, e.g. "files". */
3522
+ /**
3523
+ * Comma-separated associations to populate: `"files"` (message
3524
+ * attachments) and `"grants"` (the reputation-grant summary). Combine
3525
+ * them as `"files,grants"` — the server splits and trims this itself.
3526
+ */
3137
3527
  include?: string;
3138
3528
  /** Optional filters, e.g. `{ hasReplies: true }`. */
3139
3529
  filters?: MessageFilters;
@@ -3173,6 +3563,11 @@ declare function sendMessage(client: SublayHttpClient, data: SendMessageProps):
3173
3563
  interface GetMessageProps extends SpaceReputationContextParams {
3174
3564
  conversationId: string;
3175
3565
  messageId: string;
3566
+ /**
3567
+ * Comma-separated associations to populate. Only `"grants"` is supported
3568
+ * here — it attaches the message's reputation-grant summary.
3569
+ */
3570
+ include?: string;
3176
3571
  }
3177
3572
  declare function getMessage(client: SublayHttpClient, data: GetMessageProps): Promise<ChatMessage>;
3178
3573
 
@@ -3244,27 +3639,6 @@ declare function markAsRead(client: SublayHttpClient, data: MarkAsReadProps): Pr
3244
3639
  message: string;
3245
3640
  }>;
3246
3641
 
3247
- /**
3248
- * Every push event type — the full app-notification type set plus the chat
3249
- * `message` event (push-only). Mirrors the server's `PUSH_EVENT_TYPES` exactly
3250
- * (server `src/constants/push/pushEvents.ts`); these are the only names a
3251
- * `disabledTypes` set may contain.
3252
- */
3253
- declare const PUSH_EVENT_TYPES: readonly ["entity-comment", "comment-reply", "entity-mention", "comment-mention", "entity-reaction", "comment-reaction", "entity-reaction-milestone-specific", "entity-reaction-milestone-total", "comment-reaction-milestone-specific", "comment-reaction-milestone-total", "new-follow", "connection-request", "connection-accepted", "space-membership-approved", "event-invite", "event-updated", "event-cancelled", "message"];
3254
- type PushEventType = (typeof PUSH_EVENT_TYPES)[number];
3255
- /**
3256
- * The four conversation-mute duration choices. Send the CHOICE, never a raw
3257
- * timestamp — the server resolves it and represents "forever" via the explicit
3258
- * `mutedForever` signal on the returned member. Mirrors the server's
3259
- * `MUTE_DURATIONS` (server `src/helpers/push/muteDuration.ts`).
3260
- */
3261
- declare const MUTE_DURATIONS: readonly ["8h", "24h", "1w", "forever"];
3262
- type MuteDuration = (typeof MUTE_DURATIONS)[number];
3263
- /** Response of read/update notification preferences. */
3264
- interface NotificationPreferences {
3265
- disabledTypes: PushEventType[];
3266
- }
3267
-
3268
3642
  interface MuteConversationProps {
3269
3643
  conversationId: string;
3270
3644
  /**
@@ -3403,6 +3777,29 @@ interface WorkspaceInvitation {
3403
3777
  interface WorkspaceRosterReason {
3404
3778
  type: "owner" | "member" | "ancestor-owner" | "reach-holder" | "descendant-member";
3405
3779
  rank?: number;
3780
+ /**
3781
+ * The SAME ladder position, expressed as an offset from the CALLER: `1` = one
3782
+ * rung below you, `0` = your peer, `-3` = three rungs above you. The caller's
3783
+ * own anchor is their member row on this workspace if they hold one, and apex
3784
+ * (one step above rank 0) if they do not — so a rank-0 member reads back as
3785
+ * `relativeRank: 1` for an owner.
3786
+ *
3787
+ * Authority-bearing and fenced WITH `rank`, never beside it: it is `rank`
3788
+ * minus a number the caller already knows, so leaking it leaks `rank` exactly.
3789
+ *
3790
+ * Present on same-node `member` reasons only. `descendant-member` entries
3791
+ * carry `rank` but NEVER `relativeRank` — rank is per-workspace, so an offset
3792
+ * measured against your standing on THIS node would be arithmetic across two
3793
+ * different ladders. Use their absolute `rank` there.
3794
+ *
3795
+ * Note the deliberate asymmetry with the fence described above: the FENCE is
3796
+ * per node (a descendant row may or may not carry `rank` depending on your
3797
+ * standing there), but PRESENCE of `relativeRank` is not — it is absent on
3798
+ * every `descendant-member` row, unconditionally, however much authority you
3799
+ * hold. A field that appears and disappears by who is asking is worse to
3800
+ * consume than one that is uniformly absent.
3801
+ */
3802
+ relativeRank?: number;
3406
3803
  capabilities?: WorkspaceCapability[];
3407
3804
  permissions?: string[];
3408
3805
  title?: string | null;
@@ -3442,6 +3839,13 @@ interface WorkspaceMemberStanding {
3442
3839
  capabilities?: WorkspaceCapability[];
3443
3840
  permissions?: string[];
3444
3841
  rank?: number | null;
3842
+ /**
3843
+ * `rank` expressed as an offset from the CALLER (negative = senior to you).
3844
+ * `null` exactly when `rank` is `null` — a target with no direct member row
3845
+ * here sits outside the ladder and has no position to measure. Fenced with
3846
+ * `rank`: absent (not null) for a caller who may not see it.
3847
+ */
3848
+ relativeRank?: number | null;
3445
3849
  title: string | null;
3446
3850
  metadata: Record<string, any>;
3447
3851
  }
@@ -3514,7 +3918,11 @@ interface FetchManyWorkspacesProps {
3514
3918
  }
3515
3919
  /**
3516
3920
  * List the bearer-token user's direct-membership + owned workspaces. The actor
3517
- * is derived from the token — no `userId` is sent.
3921
+ * is derived from the token — no actor field is sent.
3922
+ *
3923
+ * ⚠️ Only the fields declared above are accepted. The workspaces endpoints
3924
+ * refuse any undeclared top-level field with a 400 rather than ignoring it, so
3925
+ * do not spread an unrelated object into `data`.
3518
3926
  */
3519
3927
  declare function fetchManyWorkspaces(client: SublayHttpClient, data?: FetchManyWorkspacesProps): Promise<PaginatedResponse<Workspace>>;
3520
3928
 
@@ -3525,7 +3933,7 @@ interface UpdateWorkspaceProps {
3525
3933
  }
3526
3934
  /**
3527
3935
  * Edit a workspace's name / metadata. Requires the `edit-workspace` capability
3528
- * (or ownership). The actor is the bearer-token user — no `userId` is sent.
3936
+ * (or ownership). The actor is the bearer-token user — no actor field is sent.
3529
3937
  */
3530
3938
  declare function updateWorkspace(client: SublayHttpClient, data: UpdateWorkspaceProps): Promise<Workspace>;
3531
3939
 
@@ -3537,7 +3945,7 @@ interface UpdateWorkspaceInheritFlagProps {
3537
3945
  * Flip whether capabilities held on an ancestor "reach" into this workspace.
3538
3946
  * Owner-only in both directions (own owner or an ancestor owner), and blocked
3539
3947
  * (403 `workspace/inherit-enforced`) when the project enforces its default.
3540
- * The actor is the bearer-token user — no `userId` is sent.
3948
+ * The actor is the bearer-token user — no actor field is sent.
3541
3949
  */
3542
3950
  declare function updateWorkspaceInheritFlag(client: SublayHttpClient, data: UpdateWorkspaceInheritFlagProps): Promise<Workspace>;
3543
3951
 
@@ -3549,8 +3957,8 @@ interface DeleteWorkspaceResponse {
3549
3957
  }
3550
3958
  /**
3551
3959
  * Owner-only delete (own owner or an ancestor owner). Cascades the whole
3552
- * subtree transactionally. The actor is the bearer-token user — no `userId`
3553
- * body is sent.
3960
+ * subtree transactionally. The actor is the bearer-token user — no actor
3961
+ * field is sent.
3554
3962
  */
3555
3963
  declare function deleteWorkspace(client: SublayHttpClient, data: DeleteWorkspaceProps): Promise<DeleteWorkspaceResponse>;
3556
3964
 
@@ -3563,7 +3971,7 @@ interface TransferWorkspaceOwnershipProps {
3563
3971
  }
3564
3972
  /**
3565
3973
  * Hand the workspace to a new owner. Owner-only (own owner or an ancestor
3566
- * owner). The actor is the bearer-token user — no `userId` is sent;
3974
+ * owner). The actor is the bearer-token user — no actor field is sent;
3567
3975
  * `newOwnerId` addresses the TARGET, not the actor.
3568
3976
  */
3569
3977
  declare function transferWorkspaceOwnership(client: SublayHttpClient, data: TransferWorkspaceOwnershipProps): Promise<Workspace>;
@@ -3577,6 +3985,11 @@ interface FetchWorkspaceMembersProps {
3577
3985
  * Unified roster read — one entry per distinct user, each with a `reasons`
3578
3986
  * array. Always returned in full (never paginated). With `countOnly=true` the
3579
3987
  * shape is `WorkspaceRosterCountsResponse` instead. Actor from the token.
3988
+ *
3989
+ * Same-node `member` reasons carry both rank coordinates: absolute `rank` and
3990
+ * `relativeRank`, the offset from you (`1` = one rung below you, `-3` = three
3991
+ * above). Both are fenced together and both are absent for a caller who does
3992
+ * not operate people here. `descendant-member` reasons carry `rank` only.
3580
3993
  */
3581
3994
  declare function fetchWorkspaceMembers(client: SublayHttpClient, data: FetchWorkspaceMembersProps): Promise<WorkspaceRosterResponse | WorkspaceRosterCountsResponse>;
3582
3995
 
@@ -3586,7 +3999,11 @@ interface FetchWorkspaceMemberStandingProps {
3586
3999
  }
3587
4000
  /**
3588
4001
  * Read one user's resolved standing on a workspace (`reasons`, `capabilities`,
3589
- * `permissions`, `rank`, `title`, `metadata`).
4002
+ * `permissions`, `rank`, `relativeRank`, `title`, `metadata`).
4003
+ *
4004
+ * `relativeRank` is the target's `rank` as an offset from YOU (negative =
4005
+ * senior to you), and is fenced with `rank`: both are absent, not null, for a
4006
+ * caller who may not see the target's authority.
3590
4007
  */
3591
4008
  declare function fetchWorkspaceMemberStanding(client: SublayHttpClient, data: FetchWorkspaceMemberStandingProps): Promise<WorkspaceMemberStanding>;
3592
4009
 
@@ -3596,13 +4013,31 @@ interface UpdateWorkspaceMemberProps {
3596
4013
  capabilities?: WorkspaceCapability[];
3597
4014
  permissions?: string[];
3598
4015
  rank?: number;
4016
+ /**
4017
+ * `rank`'s relative twin: an offset from the ACTOR (`1` = one rung below me),
4018
+ * resolved to an absolute rank at write time and stored absolute. Must be
4019
+ * `>= 1`; mutually exclusive with `rank` (sending both is a 400). Both rank fields are also capped at `2147483647` (int4), and the RESOLVED sum is bounded too — an in-range anchor plus an in-range offset can still overflow, which is a 400 rather than a 500.
4020
+ *
4021
+ * The anchor is the actor's own rank if they hold a member row on this
4022
+ * workspace, apex otherwise. A SNAPSHOT — frozen at write time, it does not
4023
+ * follow the actor's own rank afterwards.
4024
+ *
4025
+ * Unlike invite, edit has NO default: omitting BOTH still means "rank
4026
+ * unchanged", so editing someone's capabilities never moves them on the
4027
+ * ladder.
4028
+ */
4029
+ relativeRank?: number;
3599
4030
  title?: string | null;
3600
4031
  metadata?: Record<string, any>;
3601
4032
  }
3602
4033
  /**
3603
4034
  * Edit a member's grant / profile. Powerful fields need `edit-member-access`
3604
4035
  * plus rank + no-escalation rules; cosmetic fields need only
3605
- * `edit-member-profile`. No `userId` is sent — the actor comes from the token.
4036
+ * `edit-member-profile`. No actor field is sent — the actor comes from the token.
4037
+ *
4038
+ * Rank moves in either coordinate — `rank` (absolute) or `relativeRank` (an
4039
+ * offset from the actor) — never both. Omitting both leaves rank UNCHANGED;
4040
+ * unlike invite, edit has no value default.
3606
4041
  */
3607
4042
  declare function updateWorkspaceMember(client: SublayHttpClient, data: UpdateWorkspaceMemberProps): Promise<WorkspaceMember>;
3608
4043
 
@@ -3613,7 +4048,7 @@ interface RemoveWorkspaceMemberProps {
3613
4048
  /**
3614
4049
  * Remove a member from this workspace. Requires the `remove-member` capability
3615
4050
  * and is rank-bounded. The workspace owner cannot be removed (409
3616
- * `workspace/sole-owner`) — transfer ownership first. No `userId` body is sent;
4051
+ * `workspace/sole-owner`) — transfer ownership first. No actor field is sent;
3617
4052
  * the actor comes from the token.
3618
4053
  */
3619
4054
  declare function removeWorkspaceMember(client: SublayHttpClient, data: RemoveWorkspaceMemberProps): Promise<void>;
@@ -3624,8 +4059,9 @@ interface LeaveWorkspaceProps {
3624
4059
  /**
3625
4060
  * The bearer-token user leaves this workspace — removes THEIR OWN direct
3626
4061
  * membership on THIS node only (owning a child is unaffected). An owner cannot
3627
- * leave (409 `workspace/sole-owner`); transfer or delete first. No `userId` is
3628
- * sent — the server derives the leaver from the token.
4062
+ * leave (409 `workspace/sole-owner`) — transfer ownership or remove the
4063
+ * workspace first. No actor field is sent; the server derives the leaver from
4064
+ * the token.
3629
4065
  */
3630
4066
  declare function leaveWorkspace(client: SublayHttpClient, data: LeaveWorkspaceProps): Promise<void>;
3631
4067
 
@@ -3651,12 +4087,61 @@ interface CreateWorkspaceInviteProps {
3651
4087
  username?: string;
3652
4088
  capabilities?: WorkspaceCapability[];
3653
4089
  permissions?: string[];
3654
- rank: number;
4090
+ /**
4091
+ * The invited rank, ABSOLUTE — a position on this workspace's ladder (smaller
4092
+ * = more senior). The escape hatch, and what tier-constant apps want, since
4093
+ * they compute the number anyway.
4094
+ *
4095
+ * Optional, and mutually exclusive with `relativeRank` — sending both is a
4096
+ * 400. Sending NEITHER defaults to `relativeRank: 1`, one rung below the
4097
+ * inviter, which is well defined for every actor and can never fail the rank
4098
+ * floor.
4099
+ *
4100
+ * ⚠️ That default is for a NEW invitation. Re-inviting a target who already
4101
+ * has a live pending invite updates it in place, and there omitting both rank
4102
+ * fields PRESERVES the stored rank instead of re-defaulting it. See the
4103
+ * function doc below.
4104
+ */
4105
+ rank?: number;
4106
+ /**
4107
+ * The invited rank, RELATIVE to the inviter: `1` = one rung below me, `2` =
4108
+ * two rungs below, and so on. The documented happy path — every governance
4109
+ * rule about rank is relative, so this is what callers usually mean.
4110
+ *
4111
+ * Must be `>= 1` on a write. `0` would mean "a peer", which the assign rule
4112
+ * forbids (you cannot clone your own authority), and a negative offset would
4113
+ * mint someone senior to you; both are a 400. Both rank fields are also capped at `2147483647` (int4), and the RESOLVED sum is bounded too — an in-range anchor plus an in-range offset can still overflow, which is a 400 rather than a 500.
4114
+ *
4115
+ * The anchor is the inviter's OWN rank if they hold a member row on this
4116
+ * workspace, and apex (one step above rank 0) if they do not — so an owner's
4117
+ * `relativeRank: 1` lands on rank 0, while a rank-3 member's lands on rank 4.
4118
+ *
4119
+ * ⚠️ A SNAPSHOT, not a live link: the offset is resolved to an absolute rank
4120
+ * once, at invite time, and frozen. It does not track the inviter's later
4121
+ * promotions or demotions.
4122
+ */
4123
+ relativeRank?: number;
3655
4124
  title?: string | null;
3656
4125
  }
3657
4126
  /**
3658
4127
  * Create an invitation (requires the `invite` capability on the workspace). The
3659
4128
  * inviter is the bearer-token user.
4129
+ *
4130
+ * The invited rank comes in either coordinate — `rank` (absolute) or
4131
+ * `relativeRank` (an offset from the inviter) — never both. Omitting both
4132
+ * defaults to `relativeRank: 1`, one rung below the inviter, which is the
4133
+ * documented happy path and can never fail the rank floor.
4134
+ *
4135
+ * ⚠️ This route doubles as an UPSERT, and the default above applies only to a
4136
+ * NEW invitation. Re-inviting a target who already holds a live pending invite
4137
+ * refreshes THAT invitation in place — same id, expiry reset — and on that
4138
+ * branch an omitted grant field is PRESERVED, not re-defaulted or blanked:
4139
+ * `rank`, `capabilities`, `permissions` and `title` all keep their stored
4140
+ * values. A "Resend invitation" button that posts only the address therefore
4141
+ * cannot silently re-rank the invitee to one below whoever clicked it. An
4142
+ * explicit value still overwrites, and an explicit `relativeRank` re-resolves
4143
+ * against the CURRENT caller. Full semantics:
4144
+ * https://docs.sublay.io/api-reference/workspaces/invitations/create-invite
3660
4145
  */
3661
4146
  declare function createWorkspaceInvite(client: SublayHttpClient, data: CreateWorkspaceInviteProps): Promise<WorkspaceInvitation>;
3662
4147
 
@@ -3748,6 +4233,11 @@ interface FetchWorkspaceAuthorityProps {
3748
4233
  * Authority-as-a-service read — the bearer-token user's resolved standing
3749
4234
  * (`{ reasons, capabilities, permissions, rank }`) on the workspace. A
3750
4235
  * permission check is a one-line `.includes()` on the result.
4236
+ *
4237
+ * ⚠️ No `relativeRank` on this read. It is an offset from the caller, and here
4238
+ * the caller IS the subject — so it could only ever be `0`. `rank` is the only
4239
+ * rank coordinate this endpoint exposes. `relativeRank` is meaningful on the
4240
+ * roster and member-standing reads, where the subject is somebody else.
3751
4241
  */
3752
4242
  declare function fetchWorkspaceAuthority(client: SublayHttpClient, data: FetchWorkspaceAuthorityProps): Promise<WorkspaceAuthority>;
3753
4243
 
@@ -3853,6 +4343,7 @@ declare class SublayClient {
3853
4343
  connections: BoundModule<typeof Connections>;
3854
4344
  appNotifications: BoundModule<typeof AppNotifications>;
3855
4345
  reports: BoundModule<typeof Reports>;
4346
+ reputation: BoundModule<typeof Reputation>;
3856
4347
  search: BoundModule<typeof Search>;
3857
4348
  storage: BoundModule<typeof Storage>;
3858
4349
  oauth: BoundModule<typeof OAuth>;
@@ -3873,4 +4364,4 @@ declare class SublayClient {
3873
4364
  clearTokens(): void;
3874
4365
  }
3875
4366
 
3876
- export { type AuthTokens, type BulkDeleteProps, type BulkDeleteResult, type ClientConfig, type DbFilter, type DbFilterOperator, type DeleteResult, MUTE_DURATIONS, type MuteConversationProps, type MuteConversationResponse, type MuteDuration, type NotificationPreferences, PUSH_EVENT_TYPES, type PaginatedResponse, type PaginationMetadata, type PushEventType, type RemoveWorkspaceMemberFromSubtreeResponse, type SkippedWorkspace, type SpaceReputationContextParams, type SpaceReputationUserParams, SublayClient, type TableAccessor, type TableQuery, type TableRow, type UpdateNotificationPreferencesProps, type UserSearchParams, type Workspace, type WorkspaceAuthority, type WorkspaceAuthorityReason, type WorkspaceAuthorityReasonDetail, type WorkspaceCapability, type WorkspaceInvitation, type WorkspaceInvitationStatus, type WorkspaceMember, type WorkspaceMemberStanding, type WorkspaceRosterCountsResponse, type WorkspaceRosterEntry, type WorkspaceRosterReason, type WorkspaceRosterResponse, type WorkspaceStandingUser };
4367
+ export { type AuthTokens, type BulkDeleteProps, type BulkDeleteResult, type ClientConfig, type CreateGrantProps, type DbFilter, type DbFilterOperator, type DeleteResult, type GrantSummary, type ListGrantsProps, type ListGrantsResponse, MUTE_DURATIONS, type MuteConversationProps, type MuteConversationResponse, type MuteDuration, type NotificationPreferences, PUSH_EVENT_TYPES, type PaginatedResponse, type PaginationMetadata, type PushDeviceIdentifier, type PushEventType, type PushUnbindSkipReason, type RemoveWorkspaceMemberFromSubtreeResponse, type ReputationGrant, type ReputationGrantSourceType, type ReputationGrantTargetFilter, type ReputationGrantTargetType, type SignOutResult, type SkippedWorkspace, type SpaceReputationContextParams, type SpaceReputationUserParams, SublayClient, type TableAccessor, type TableQuery, type TableRow, type UpdateNotificationPreferencesProps, type UserSearchParams, type WebPushSubscription, type Workspace, type WorkspaceAuthority, type WorkspaceAuthorityReason, type WorkspaceAuthorityReasonDetail, type WorkspaceCapability, type WorkspaceInvitation, type WorkspaceInvitationStatus, type WorkspaceMember, type WorkspaceMemberStanding, type WorkspaceRosterCountsResponse, type WorkspaceRosterEntry, type WorkspaceRosterReason, type WorkspaceRosterResponse, type WorkspaceStandingUser };