@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
@@ -60,6 +60,29 @@ export interface WorkspaceInvitation {
60
60
  export interface WorkspaceRosterReason {
61
61
  type: "owner" | "member" | "ancestor-owner" | "reach-holder" | "descendant-member";
62
62
  rank?: number;
63
+ /**
64
+ * The SAME ladder position, expressed as an offset from the CALLER: `1` = one
65
+ * rung below you, `0` = your peer, `-3` = three rungs above you. The caller's
66
+ * own anchor is their member row on this workspace if they hold one, and apex
67
+ * (one step above rank 0) if they do not — so a rank-0 member reads back as
68
+ * `relativeRank: 1` for an owner.
69
+ *
70
+ * Authority-bearing and fenced WITH `rank`, never beside it: it is `rank`
71
+ * minus a number the caller already knows, so leaking it leaks `rank` exactly.
72
+ *
73
+ * Present on same-node `member` reasons only. `descendant-member` entries
74
+ * carry `rank` but NEVER `relativeRank` — rank is per-workspace, so an offset
75
+ * measured against your standing on THIS node would be arithmetic across two
76
+ * different ladders. Use their absolute `rank` there.
77
+ *
78
+ * Note the deliberate asymmetry with the fence described above: the FENCE is
79
+ * per node (a descendant row may or may not carry `rank` depending on your
80
+ * standing there), but PRESENCE of `relativeRank` is not — it is absent on
81
+ * every `descendant-member` row, unconditionally, however much authority you
82
+ * hold. A field that appears and disappears by who is asking is worse to
83
+ * consume than one that is uniformly absent.
84
+ */
85
+ relativeRank?: number;
63
86
  capabilities?: WorkspaceCapability[];
64
87
  permissions?: string[];
65
88
  title?: string | null;
@@ -99,6 +122,13 @@ export interface WorkspaceMemberStanding {
99
122
  capabilities?: WorkspaceCapability[];
100
123
  permissions?: string[];
101
124
  rank?: number | null;
125
+ /**
126
+ * `rank` expressed as an offset from the CALLER (negative = senior to you).
127
+ * `null` exactly when `rank` is `null` — a target with no direct member row
128
+ * here sits outside the ladder and has no position to measure. Fenced with
129
+ * `rank`: absent (not null) for a caller who may not see it.
130
+ */
131
+ relativeRank?: number | null;
102
132
  title: string | null;
103
133
  metadata: Record<string, any>;
104
134
  }
@@ -1,11 +1,34 @@
1
1
  import { SublayHttpClient } from "../../core/client";
2
+ import { PushDeviceIdentifier } from "../../interfaces/Push";
2
3
  export interface ChangePasswordProps {
3
4
  /** The user's current password (verified before the change). */
4
5
  password: string;
5
6
  newPassword: string;
7
+ /**
8
+ * Optional. The physical device making this call.
9
+ *
10
+ * A password change also deletes every push binding the user holds, so an
11
+ * intruder's device stops receiving notification content. Naming this device
12
+ * keeps ITS binding — nothing re-binds a device from its live session, so
13
+ * without this the handset the user just changed their password on goes
14
+ * quiet until the app cold-starts or switches accounts.
15
+ *
16
+ * Same value passed to `push.register` / `auth.signOut`. Omit it and every
17
+ * binding for the user goes, this device included.
18
+ */
19
+ pushDevice?: PushDeviceIdentifier;
6
20
  }
7
21
  export interface ChangePasswordResponse {
8
22
  success: boolean;
9
23
  message: string;
10
24
  }
25
+ /**
26
+ * Change the signed-in user's password.
27
+ *
28
+ * Ends every OTHER session for that user — every other device must sign in
29
+ * again with the new password — while the session making this call survives.
30
+ * The server identifies that session from the access token this request is
31
+ * already authenticated with, so nothing about the caller's session has to be
32
+ * sent.
33
+ */
11
34
  export declare function changePassword(client: SublayHttpClient, data: ChangePasswordProps): Promise<ChangePasswordResponse>;
@@ -1,9 +1,103 @@
1
1
  import { SublayHttpClient } from "../../core/client";
2
+ import { PushDeviceIdentifier } from "../../interfaces/Push";
2
3
  export interface SignOutProps {
3
4
  /**
4
5
  * Defaults to the SDK's stored refresh token (SDK-managed mode). Pass it
5
6
  * explicitly in host-managed mode, where the SDK holds no refresh token.
6
7
  */
7
8
  refreshToken?: string;
9
+ /**
10
+ * Optional. When supplied — and the project has the `push` bundle — the
11
+ * server deletes this user's push binding for that device in the SAME
12
+ * transaction as the token-family destroy: signing out unbinds the device's
13
+ * push, or nothing happens at all.
14
+ *
15
+ * **Needs a refresh token to have any effect.** The unbind is scoped to the
16
+ * `sub` of the refresh token, which is what stops one account removing
17
+ * another account's binding on a shared device — so with no token there is no
18
+ * user to scope it to and the server answers `204` before it ever looks at
19
+ * `pushDevice`. When none can be resolved the field is DROPPED from the
20
+ * request rather than sent into that silent no-op, the sign-out proceeds
21
+ * normally, and the returned `pushUnbindSkipped` says so. Watch for it in
22
+ * **host-managed mode**: such a client is built with `getToken` and no
23
+ * `initialTokens`, and its `setTokens` is inert, so it starts with no refresh
24
+ * token and can never acquire one. Pass `refreshToken` explicitly alongside
25
+ * `pushDevice` there.
26
+ *
27
+ * If the unbind fails the request fails (HTTP 500, code
28
+ * `auth/device-deregistration-failed` or `auth/sign-out-failed`) and NOTHING
29
+ * is committed — the session survives so the caller can retry, and this call
30
+ * rethrows WITHOUT clearing the SDK's local tokens, so the credential that
31
+ * retry needs is still there.
32
+ *
33
+ * That is the ONLY failure that leaves you signed in. Every other one — a
34
+ * `429` from the rate limiter or a quota gate, a `423`, a `503`, a `400` on
35
+ * the body, a dropped connection — never touched a push binding, so it
36
+ * clears the local tokens and RESOLVES: a user must always be able to sign
37
+ * out. See `UNBIND_FAILURE_CODES`.
38
+ *
39
+ * Omit it and the request is byte-identical to before this field existed.
40
+ */
41
+ pushDevice?: PushDeviceIdentifier;
42
+ }
43
+ /**
44
+ * Why the unbind did not happen. Present only when `pushUnbindSkipped` is
45
+ * `true`, and it exists because THE TWO SKIPS ARE RECOVERED DIFFERENTLY — a
46
+ * caller that cannot tell them apart can only ever pick the wrong remedy for
47
+ * one of them:
48
+ *
49
+ * - `no-refresh-token` — this SDK never asked. Nothing was destroyed either:
50
+ * with no token the server has no session to end, so the account, its
51
+ * credential and its binding are all still there. **Retryable**: re-issue
52
+ * the sign-out with an explicit `refreshToken` and the unbind happens.
53
+ * - `push-unbind-status-unknown` — the server was asked and could not answer.
54
+ * The sign-out itself DID commit, so the credential that would have driven a
55
+ * retry is gone; re-issuing achieves nothing. The binding clears when that
56
+ * account next registers on this device, or when the server prunes the token
57
+ * as undeliverable.
58
+ */
59
+ export type PushUnbindSkipReason = "no-refresh-token" | "push-unbind-status-unknown";
60
+ export interface SignOutResult {
61
+ /**
62
+ * `true` whenever a `pushDevice` was supplied and the unbind did NOT happen,
63
+ * so this device's push binding for that account may still be live. Either
64
+ * the SDK declined to ask (no refresh token to scope the unbind to) or the
65
+ * server could not answer whether a binding exists; `pushUnbindSkipReason`
66
+ * says which, and the two are recovered differently.
67
+ *
68
+ * `false` means NO SKIP WAS REPORTED — by this SDK or by the server. It is
69
+ * not a promise that no skip happened, and the difference is not academic:
70
+ * the server declines the unbind for several reasons it answers with a plain
71
+ * `204`, and every one of them reads `false` here.
72
+ *
73
+ * - The refresh token is authentic but expired beyond the server's unbind
74
+ * window (90 days past `exp`), so there is no subject to scope the unbind
75
+ * to. Reachable from this SDK by passing an old `refreshToken` explicitly
76
+ * alongside `pushDevice`.
77
+ * - The refresh token is malformed or fails signature verification.
78
+ * - The project has no `push` bundle, so no binding can exist.
79
+ * - The unbind ran and matched zero rows — the binding was already gone, or
80
+ * was never registered under this device key.
81
+ *
82
+ * The server logs each of those under its own reason; only the case where it
83
+ * could not determine whether a binding exists is reported in the response,
84
+ * because that is the one where the binding may still be LIVE and nobody
85
+ * looked. The rest either prove there was nothing to remove or leave a device
86
+ * key the server cannot attribute to a user, and neither gives the caller
87
+ * anything to act on beyond what it already knows.
88
+ *
89
+ * A request that failed short of an unbind attempt reads `false` too — a
90
+ * gate's `429` or `423`, a `503`, a `400`, a dropped connection. Those clear
91
+ * the local tokens and resolve rather than reject (see `UNBIND_FAILURE_CODES`
92
+ * for why), and none of them is a REPORTED skip; they are logged with a
93
+ * warning instead.
94
+ *
95
+ * The sign-out itself is unaffected by the flag in both directions: a user
96
+ * must always be able to sign out, so a skipped unbind never fails the call
97
+ * and never leaves the local tokens in place.
98
+ */
99
+ pushUnbindSkipped: boolean;
100
+ /** Set only when `pushUnbindSkipped` is `true`. See `PushUnbindSkipReason`. */
101
+ pushUnbindSkipReason?: PushUnbindSkipReason;
8
102
  }
9
- export declare function signOut(client: SublayHttpClient, data?: SignOutProps): Promise<void>;
103
+ export declare function signOut(client: SublayHttpClient, data?: SignOutProps): Promise<SignOutResult>;
@@ -4,5 +4,10 @@ import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation";
4
4
  export interface GetMessageProps extends SpaceReputationContextParams {
5
5
  conversationId: string;
6
6
  messageId: string;
7
+ /**
8
+ * Comma-separated associations to populate. Only `"grants"` is supported
9
+ * here — it attaches the message's reputation-grant summary.
10
+ */
11
+ include?: string;
7
12
  }
8
13
  export declare function getMessage(client: SublayHttpClient, data: GetMessageProps): Promise<ChatMessage>;
@@ -20,7 +20,11 @@ export interface ListMessagesProps extends SpaceReputationContextParams {
20
20
  /** Page size (default 50, max 100). */
21
21
  limit?: number;
22
22
  sort?: "asc" | "desc";
23
- /** Comma-separated associations to populate, e.g. "files". */
23
+ /**
24
+ * Comma-separated associations to populate: `"files"` (message
25
+ * attachments) and `"grants"` (the reputation-grant summary). Combine
26
+ * them as `"files,grants"` — the server splits and trims this itself.
27
+ */
24
28
  include?: string;
25
29
  /** Optional filters, e.g. `{ hasReplies: true }`. */
26
30
  filters?: MessageFilters;
@@ -0,0 +1,45 @@
1
+ import { SublayHttpClient } from "../../core/client";
2
+ import { ReputationGrant, ReputationGrantTargetFilter } from "../../interfaces/ReputationGrant";
3
+ interface CreateGrantBaseProps {
4
+ /** The user receiving the reputation. Cannot be the logged-in user. */
5
+ recipientId: string;
6
+ /**
7
+ * Positive integer. A user transfer can never mint (negatives) nor be a
8
+ * no-op (zero) — minting is service-key-only and lives in `@sublay/node`.
9
+ */
10
+ amount: number;
11
+ /** The bucket both legs move in. Omitted/null = the project-general bucket. */
12
+ spaceId?: string | null;
13
+ /**
14
+ * Free-text reason. Trimmed and capped at 2000 characters server-side.
15
+ * Genuinely nullable — an explicit `null` is accepted and means "no note".
16
+ */
17
+ note?: string | null;
18
+ /**
19
+ * Arbitrary JSON, capped at 1 MB server-side.
20
+ *
21
+ * NOT nullable — deliberately asymmetric with `note` directly above, not a
22
+ * typo. The server's shared `metadataSchema` is `z.record(...).optional()`
23
+ * with no `.nullable()`, so an explicit `metadata: null` is rejected with
24
+ * `400 reputation-grant/invalid-body`. Omit the key to mean "no metadata".
25
+ */
26
+ metadata?: Record<string, any>;
27
+ }
28
+ /**
29
+ * `targetType` and `targetId` are supplied together or not at all — the
30
+ * both-or-neither pair is carried by {@link ReputationGrantTargetFilter}, which
31
+ * makes the half-filled shape a compile error instead of a
32
+ * `400 reputation-grant/invalid-body`.
33
+ */
34
+ export type CreateGrantProps = CreateGrantBaseProps & ReputationGrantTargetFilter;
35
+ /**
36
+ * Transfers reputation from the logged-in user to another user — a **debited
37
+ * transfer**: the amount leaves the sender's bucket and lands in the
38
+ * recipient's bucket in the same space. Nothing is created.
39
+ *
40
+ * There is no actor field: the sender is always the user the token belongs to.
41
+ * Naming somebody else as the sender requires a service key, which this SDK
42
+ * never holds.
43
+ */
44
+ export declare function createGrant(client: SublayHttpClient, data: CreateGrantProps): Promise<ReputationGrant>;
45
+ export {};
@@ -0,0 +1,2 @@
1
+ export { createGrant } from "./createGrant";
2
+ export { listGrants } from "./listGrants";
@@ -0,0 +1,45 @@
1
+ import { SublayHttpClient } from "../../core/client";
2
+ import { GrantSummary, ReputationGrant, ReputationGrantTargetFilter } from "../../interfaces/ReputationGrant";
3
+ import { PaginatedResponse } from "../../interfaces/IPaginatedResponse";
4
+ import { SpaceReputationContextParams } from "../../interfaces/SpaceReputation";
5
+ interface ListGrantsBaseProps extends SpaceReputationContextParams {
6
+ page?: number;
7
+ limit?: number;
8
+ /** What this user received. */
9
+ recipientId?: string;
10
+ /** What this user sent. */
11
+ senderId?: string;
12
+ /** Associations to expand. Only `"user"` is supported (hydrates both parties). */
13
+ include?: string;
14
+ }
15
+ /**
16
+ * The third filter shape — "who rewarded this item" — is the
17
+ * {@link ReputationGrantTargetFilter} pair, so a half-filled target is a
18
+ * compile error rather than a `400 reputation-grant/invalid-filter`.
19
+ *
20
+ * Mutual exclusivity between the three shapes is NOT expressed in the type: a
21
+ * three-way exclusive union would multiply out across every pagination and
22
+ * space-reputation field and make the props unreadable, for a rule the server
23
+ * reports clearly. Only the both-or-neither pairing is typed.
24
+ */
25
+ export type ListGrantsProps = ListGrantsBaseProps & ReputationGrantTargetFilter;
26
+ /**
27
+ * The `summary` block rides alongside the page envelope, and only on the
28
+ * target filter shape.
29
+ */
30
+ export interface ListGrantsResponse extends PaginatedResponse<ReputationGrant> {
31
+ summary?: GrantSummary;
32
+ }
33
+ /**
34
+ * Lists reputation grants.
35
+ *
36
+ * Exactly one filter shape per request — `recipientId`, `senderId`, or
37
+ * `targetType` + `targetId`. Supplying none or combining two is a `400`; the
38
+ * shapes are not AND-ed, which is what keeps the `summary` block reconcilable
39
+ * with the rows beneath it.
40
+ *
41
+ * Only positive grants are ever returned. Negative grants are app moderation
42
+ * deductions and are unreadable from every public surface.
43
+ */
44
+ export declare function listGrants(client: SublayHttpClient, data: ListGrantsProps): Promise<ListGrantsResponse>;
45
+ export {};
@@ -7,11 +7,60 @@ export interface CreateWorkspaceInviteProps {
7
7
  username?: string;
8
8
  capabilities?: WorkspaceCapability[];
9
9
  permissions?: string[];
10
- rank: number;
10
+ /**
11
+ * The invited rank, ABSOLUTE — a position on this workspace's ladder (smaller
12
+ * = more senior). The escape hatch, and what tier-constant apps want, since
13
+ * they compute the number anyway.
14
+ *
15
+ * Optional, and mutually exclusive with `relativeRank` — sending both is a
16
+ * 400. Sending NEITHER defaults to `relativeRank: 1`, one rung below the
17
+ * inviter, which is well defined for every actor and can never fail the rank
18
+ * floor.
19
+ *
20
+ * ⚠️ That default is for a NEW invitation. Re-inviting a target who already
21
+ * has a live pending invite updates it in place, and there omitting both rank
22
+ * fields PRESERVES the stored rank instead of re-defaulting it. See the
23
+ * function doc below.
24
+ */
25
+ rank?: number;
26
+ /**
27
+ * The invited rank, RELATIVE to the inviter: `1` = one rung below me, `2` =
28
+ * two rungs below, and so on. The documented happy path — every governance
29
+ * rule about rank is relative, so this is what callers usually mean.
30
+ *
31
+ * Must be `>= 1` on a write. `0` would mean "a peer", which the assign rule
32
+ * forbids (you cannot clone your own authority), and a negative offset would
33
+ * 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.
34
+ *
35
+ * The anchor is the inviter's OWN rank if they hold a member row on this
36
+ * workspace, and apex (one step above rank 0) if they do not — so an owner's
37
+ * `relativeRank: 1` lands on rank 0, while a rank-3 member's lands on rank 4.
38
+ *
39
+ * ⚠️ A SNAPSHOT, not a live link: the offset is resolved to an absolute rank
40
+ * once, at invite time, and frozen. It does not track the inviter's later
41
+ * promotions or demotions.
42
+ */
43
+ relativeRank?: number;
11
44
  title?: string | null;
12
45
  }
13
46
  /**
14
47
  * Create an invitation (requires the `invite` capability on the workspace). The
15
48
  * inviter is the bearer-token user.
49
+ *
50
+ * The invited rank comes in either coordinate — `rank` (absolute) or
51
+ * `relativeRank` (an offset from the inviter) — never both. Omitting both
52
+ * defaults to `relativeRank: 1`, one rung below the inviter, which is the
53
+ * documented happy path and can never fail the rank floor.
54
+ *
55
+ * ⚠️ This route doubles as an UPSERT, and the default above applies only to a
56
+ * NEW invitation. Re-inviting a target who already holds a live pending invite
57
+ * refreshes THAT invitation in place — same id, expiry reset — and on that
58
+ * branch an omitted grant field is PRESERVED, not re-defaulted or blanked:
59
+ * `rank`, `capabilities`, `permissions` and `title` all keep their stored
60
+ * values. A "Resend invitation" button that posts only the address therefore
61
+ * cannot silently re-rank the invitee to one below whoever clicked it. An
62
+ * explicit value still overwrites, and an explicit `relativeRank` re-resolves
63
+ * against the CURRENT caller. Full semantics:
64
+ * https://docs.sublay.io/api-reference/workspaces/invitations/create-invite
16
65
  */
17
66
  export declare function createWorkspaceInvite(client: SublayHttpClient, data: CreateWorkspaceInviteProps): Promise<WorkspaceInvitation>;
@@ -7,7 +7,7 @@ export interface DeleteWorkspaceResponse {
7
7
  }
8
8
  /**
9
9
  * Owner-only delete (own owner or an ancestor owner). Cascades the whole
10
- * subtree transactionally. The actor is the bearer-token user — no `userId`
11
- * body is sent.
10
+ * subtree transactionally. The actor is the bearer-token user — no actor
11
+ * field is sent.
12
12
  */
13
13
  export declare function deleteWorkspace(client: SublayHttpClient, data: DeleteWorkspaceProps): Promise<DeleteWorkspaceResponse>;
@@ -8,6 +8,10 @@ export interface FetchManyWorkspacesProps {
8
8
  }
9
9
  /**
10
10
  * List the bearer-token user's direct-membership + owned workspaces. The actor
11
- * is derived from the token — no `userId` is sent.
11
+ * is derived from the token — no actor field is sent.
12
+ *
13
+ * ⚠️ Only the fields declared above are accepted. The workspaces endpoints
14
+ * refuse any undeclared top-level field with a 400 rather than ignoring it, so
15
+ * do not spread an unrelated object into `data`.
12
16
  */
13
17
  export declare function fetchManyWorkspaces(client: SublayHttpClient, data?: FetchManyWorkspacesProps): Promise<PaginatedResponse<Workspace>>;
@@ -7,5 +7,10 @@ export interface FetchWorkspaceAuthorityProps {
7
7
  * Authority-as-a-service read — the bearer-token user's resolved standing
8
8
  * (`{ reasons, capabilities, permissions, rank }`) on the workspace. A
9
9
  * permission check is a one-line `.includes()` on the result.
10
+ *
11
+ * ⚠️ No `relativeRank` on this read. It is an offset from the caller, and here
12
+ * the caller IS the subject — so it could only ever be `0`. `rank` is the only
13
+ * rank coordinate this endpoint exposes. `relativeRank` is meaningful on the
14
+ * roster and member-standing reads, where the subject is somebody else.
10
15
  */
11
16
  export declare function fetchWorkspaceAuthority(client: SublayHttpClient, data: FetchWorkspaceAuthorityProps): Promise<WorkspaceAuthority>;
@@ -6,6 +6,10 @@ export interface FetchWorkspaceMemberStandingProps {
6
6
  }
7
7
  /**
8
8
  * Read one user's resolved standing on a workspace (`reasons`, `capabilities`,
9
- * `permissions`, `rank`, `title`, `metadata`).
9
+ * `permissions`, `rank`, `relativeRank`, `title`, `metadata`).
10
+ *
11
+ * `relativeRank` is the target's `rank` as an offset from YOU (negative =
12
+ * senior to you), and is fenced with `rank`: both are absent, not null, for a
13
+ * caller who may not see the target's authority.
10
14
  */
11
15
  export declare function fetchWorkspaceMemberStanding(client: SublayHttpClient, data: FetchWorkspaceMemberStandingProps): Promise<WorkspaceMemberStanding>;
@@ -9,5 +9,10 @@ export interface FetchWorkspaceMembersProps {
9
9
  * Unified roster read — one entry per distinct user, each with a `reasons`
10
10
  * array. Always returned in full (never paginated). With `countOnly=true` the
11
11
  * shape is `WorkspaceRosterCountsResponse` instead. Actor from the token.
12
+ *
13
+ * Same-node `member` reasons carry both rank coordinates: absolute `rank` and
14
+ * `relativeRank`, the offset from you (`1` = one rung below you, `-3` = three
15
+ * above). Both are fenced together and both are absent for a caller who does
16
+ * not operate people here. `descendant-member` reasons carry `rank` only.
12
17
  */
13
18
  export declare function fetchWorkspaceMembers(client: SublayHttpClient, data: FetchWorkspaceMembersProps): Promise<WorkspaceRosterResponse | WorkspaceRosterCountsResponse>;
@@ -5,7 +5,8 @@ export interface LeaveWorkspaceProps {
5
5
  /**
6
6
  * The bearer-token user leaves this workspace — removes THEIR OWN direct
7
7
  * membership on THIS node only (owning a child is unaffected). An owner cannot
8
- * leave (409 `workspace/sole-owner`); transfer or delete first. No `userId` is
9
- * sent — the server derives the leaver from the token.
8
+ * leave (409 `workspace/sole-owner`) — transfer ownership or remove the
9
+ * workspace first. No actor field is sent; the server derives the leaver from
10
+ * the token.
10
11
  */
11
12
  export declare function leaveWorkspace(client: SublayHttpClient, data: LeaveWorkspaceProps): Promise<void>;
@@ -6,7 +6,7 @@ export interface RemoveWorkspaceMemberProps {
6
6
  /**
7
7
  * Remove a member from this workspace. Requires the `remove-member` capability
8
8
  * and is rank-bounded. The workspace owner cannot be removed (409
9
- * `workspace/sole-owner`) — transfer ownership first. No `userId` body is sent;
9
+ * `workspace/sole-owner`) — transfer ownership first. No actor field is sent;
10
10
  * the actor comes from the token.
11
11
  */
12
12
  export declare function removeWorkspaceMember(client: SublayHttpClient, data: RemoveWorkspaceMemberProps): Promise<void>;
@@ -9,7 +9,7 @@ export interface TransferWorkspaceOwnershipProps {
9
9
  }
10
10
  /**
11
11
  * Hand the workspace to a new owner. Owner-only (own owner or an ancestor
12
- * owner). The actor is the bearer-token user — no `userId` is sent;
12
+ * owner). The actor is the bearer-token user — no actor field is sent;
13
13
  * `newOwnerId` addresses the TARGET, not the actor.
14
14
  */
15
15
  export declare function transferWorkspaceOwnership(client: SublayHttpClient, data: TransferWorkspaceOwnershipProps): Promise<Workspace>;
@@ -7,6 +7,6 @@ export interface UpdateWorkspaceProps {
7
7
  }
8
8
  /**
9
9
  * Edit a workspace's name / metadata. Requires the `edit-workspace` capability
10
- * (or ownership). The actor is the bearer-token user — no `userId` is sent.
10
+ * (or ownership). The actor is the bearer-token user — no actor field is sent.
11
11
  */
12
12
  export declare function updateWorkspace(client: SublayHttpClient, data: UpdateWorkspaceProps): Promise<Workspace>;
@@ -8,6 +8,6 @@ export interface UpdateWorkspaceInheritFlagProps {
8
8
  * Flip whether capabilities held on an ancestor "reach" into this workspace.
9
9
  * Owner-only in both directions (own owner or an ancestor owner), and blocked
10
10
  * (403 `workspace/inherit-enforced`) when the project enforces its default.
11
- * The actor is the bearer-token user — no `userId` is sent.
11
+ * The actor is the bearer-token user — no actor field is sent.
12
12
  */
13
13
  export declare function updateWorkspaceInheritFlag(client: SublayHttpClient, data: UpdateWorkspaceInheritFlagProps): Promise<Workspace>;
@@ -6,12 +6,30 @@ export interface UpdateWorkspaceMemberProps {
6
6
  capabilities?: WorkspaceCapability[];
7
7
  permissions?: string[];
8
8
  rank?: number;
9
+ /**
10
+ * `rank`'s relative twin: an offset from the ACTOR (`1` = one rung below me),
11
+ * resolved to an absolute rank at write time and stored absolute. Must be
12
+ * `>= 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.
13
+ *
14
+ * The anchor is the actor's own rank if they hold a member row on this
15
+ * workspace, apex otherwise. A SNAPSHOT — frozen at write time, it does not
16
+ * follow the actor's own rank afterwards.
17
+ *
18
+ * Unlike invite, edit has NO default: omitting BOTH still means "rank
19
+ * unchanged", so editing someone's capabilities never moves them on the
20
+ * ladder.
21
+ */
22
+ relativeRank?: number;
9
23
  title?: string | null;
10
24
  metadata?: Record<string, any>;
11
25
  }
12
26
  /**
13
27
  * Edit a member's grant / profile. Powerful fields need `edit-member-access`
14
28
  * plus rank + no-escalation rules; cosmetic fields need only
15
- * `edit-member-profile`. No `userId` is sent — the actor comes from the token.
29
+ * `edit-member-profile`. No actor field is sent — the actor comes from the token.
30
+ *
31
+ * Rank moves in either coordinate — `rank` (absolute) or `relativeRank` (an
32
+ * offset from the actor) — never both. Omitting both leaves rank UNCHANGED;
33
+ * unlike invite, edit has no value default.
16
34
  */
17
35
  export declare function updateWorkspaceMember(client: SublayHttpClient, data: UpdateWorkspaceMemberProps): Promise<WorkspaceMember>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sublay/js",
3
- "version": "7.7.1",
3
+ "version": "7.9.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "files": [