@mysten/sui-groups 0.0.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/README.md +108 -0
- package/dist/bcs.d.mts +82 -0
- package/dist/bcs.d.mts.map +1 -0
- package/dist/bcs.mjs +55 -0
- package/dist/bcs.mjs.map +1 -0
- package/dist/call.d.mts +99 -0
- package/dist/call.d.mts.map +1 -0
- package/dist/call.mjs +171 -0
- package/dist/call.mjs.map +1 -0
- package/dist/client.d.mts +143 -0
- package/dist/client.d.mts.map +1 -0
- package/dist/client.mjs +173 -0
- package/dist/client.mjs.map +1 -0
- package/dist/constants.d.mts +65 -0
- package/dist/constants.d.mts.map +1 -0
- package/dist/constants.mjs +77 -0
- package/dist/constants.mjs.map +1 -0
- package/dist/contracts/sui_groups/deps/std/type_name.mjs +17 -0
- package/dist/contracts/sui_groups/deps/std/type_name.mjs.map +1 -0
- package/dist/contracts/sui_groups/permissioned_group.d.mts +84 -0
- package/dist/contracts/sui_groups/permissioned_group.d.mts.map +1 -0
- package/dist/contracts/sui_groups/permissioned_group.mjs +368 -0
- package/dist/contracts/sui_groups/permissioned_group.mjs.map +1 -0
- package/dist/contracts/sui_groups/permissions_table.mjs +26 -0
- package/dist/contracts/sui_groups/permissions_table.mjs.map +1 -0
- package/dist/contracts/utils/index.d.mts +35 -0
- package/dist/contracts/utils/index.d.mts.map +1 -0
- package/dist/contracts/utils/index.mjs +119 -0
- package/dist/contracts/utils/index.mjs.map +1 -0
- package/dist/error.d.mts +5 -0
- package/dist/error.d.mts.map +1 -0
- package/dist/error.mjs +6 -0
- package/dist/error.mjs.map +1 -0
- package/dist/index.d.mts +9 -0
- package/dist/index.mjs +9 -0
- package/dist/transactions.d.mts +110 -0
- package/dist/transactions.d.mts.map +1 -0
- package/dist/transactions.mjs +91 -0
- package/dist/transactions.mjs.map +1 -0
- package/dist/types.d.mts +221 -0
- package/dist/types.d.mts.map +1 -0
- package/dist/view.d.mts +85 -0
- package/dist/view.d.mts.map +1 -0
- package/dist/view.mjs +221 -0
- package/dist/view.mjs.map +1 -0
- package/package.json +57 -0
package/dist/view.mjs
ADDED
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { PERMISSIONS_TABLE_DERIVATION_KEY, pausedMarkerType } from "./constants.mjs";
|
|
2
|
+
import { deriveDynamicFieldID, deriveObjectID } from "@mysten/sui/utils";
|
|
3
|
+
import { bcs } from "@mysten/sui/bcs";
|
|
4
|
+
|
|
5
|
+
//#region src/view.ts
|
|
6
|
+
/**
|
|
7
|
+
* Checks whether an error is a transport/network-level error that should
|
|
8
|
+
* be propagated (not swallowed as "object not found").
|
|
9
|
+
*
|
|
10
|
+
* Each Sui client transport produces structurally distinct transport errors:
|
|
11
|
+
*
|
|
12
|
+
* - JSON-RPC `SuiHTTPStatusError`: has `status: number` and `statusText: string`
|
|
13
|
+
* - JSON-RPC `JsonRpcError`: has `code: number` and `type: string`
|
|
14
|
+
* - gRPC `RpcError` (@protobuf-ts): has `meta: object`
|
|
15
|
+
* - GraphQL `SuiGraphQLRequestError`: has `name: 'SuiGraphQLRequestError'`
|
|
16
|
+
* - GraphQL `GraphQLResponseError`: has `locations` array
|
|
17
|
+
* - `fetch` failures: `TypeError`
|
|
18
|
+
*
|
|
19
|
+
* Object-level errors (not found, deleted, etc.) lack these markers:
|
|
20
|
+
* - JSON-RPC / GraphQL: `ObjectError` with string `code`
|
|
21
|
+
* - gRPC: plain `Error(message)` with no transport metadata
|
|
22
|
+
*/
|
|
23
|
+
function isTransportError(error) {
|
|
24
|
+
if (!(error instanceof Error)) return false;
|
|
25
|
+
const e = error;
|
|
26
|
+
if (typeof e.status === "number" && typeof e.statusText === "string") return true;
|
|
27
|
+
if (typeof e.code === "number" && typeof e.type === "string") return true;
|
|
28
|
+
if (typeof e.meta === "object" && e.meta !== null) return true;
|
|
29
|
+
if (error.constructor.name === "SuiGraphQLRequestError") return true;
|
|
30
|
+
if ("locations" in e) return true;
|
|
31
|
+
if (error instanceof TypeError) return true;
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* BCS type for dynamic field entries keyed by address with VecSet<TypeName> values.
|
|
36
|
+
*/
|
|
37
|
+
const DynamicFieldEntry = bcs.struct("Field", {
|
|
38
|
+
id: bcs.Address,
|
|
39
|
+
name: bcs.Address,
|
|
40
|
+
value: bcs.vector(bcs.struct("TypeName", { name: bcs.string() }))
|
|
41
|
+
});
|
|
42
|
+
/**
|
|
43
|
+
* View methods for querying permissioned group state.
|
|
44
|
+
*
|
|
45
|
+
* These methods query on-chain state by fetching objects directly,
|
|
46
|
+
* without requiring a signature or spending gas.
|
|
47
|
+
*
|
|
48
|
+
* Note: Fields like `creator` and `permissions_admin_count` are available
|
|
49
|
+
* directly on the PermissionedGroup object when fetched via getObject.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```ts
|
|
53
|
+
* const hasPerm = await client.groups.view.hasPermission({
|
|
54
|
+
* groupId: '0x456...',
|
|
55
|
+
* member: '0x789...',
|
|
56
|
+
* permissionType: '0xabc::my_app::Editor',
|
|
57
|
+
* });
|
|
58
|
+
*
|
|
59
|
+
* const isMember = await client.groups.view.isMember({
|
|
60
|
+
* groupId: '0x456...',
|
|
61
|
+
* member: '0x789...',
|
|
62
|
+
* });
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
var SuiGroupsView = class {
|
|
66
|
+
#client;
|
|
67
|
+
#packageConfig;
|
|
68
|
+
constructor(options) {
|
|
69
|
+
this.#client = options.client;
|
|
70
|
+
this.#packageConfig = options.packageConfig;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Derives the PermissionsTable object ID from a PermissionedGroup ID.
|
|
74
|
+
*
|
|
75
|
+
* The PermissionsTable is a derived object from its parent PermissionedGroup,
|
|
76
|
+
* using the fixed derivation key "permissions_table" (as a Move `String`).
|
|
77
|
+
* This makes the table ID fully deterministic — no RPC call needed.
|
|
78
|
+
*/
|
|
79
|
+
#derivePermissionsTableId(groupId) {
|
|
80
|
+
return deriveObjectID(groupId, "0x0000000000000000000000000000000000000000000000000000000000000001::string::String", bcs.string().serialize(PERMISSIONS_TABLE_DERIVATION_KEY).toBytes());
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Fetches a member's permissions from the group's permissions table.
|
|
84
|
+
* Returns null if the member is not in the group.
|
|
85
|
+
*/
|
|
86
|
+
async #getMemberPermissions(groupId, member) {
|
|
87
|
+
const dynamicFieldId = deriveDynamicFieldID(this.#derivePermissionsTableId(groupId), "address", bcs.Address.serialize(member).toBytes());
|
|
88
|
+
try {
|
|
89
|
+
const { object } = await this.#client.core.getObject({
|
|
90
|
+
objectId: dynamicFieldId,
|
|
91
|
+
include: { content: true }
|
|
92
|
+
});
|
|
93
|
+
return DynamicFieldEntry.parse(object.content).value.map((typeName) => typeName.name);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (isTransportError(error)) throw error;
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Checks if the given address has the specified permission.
|
|
101
|
+
*
|
|
102
|
+
* @param options.groupId - Object ID of the PermissionedGroup
|
|
103
|
+
* @param options.member - Address to check
|
|
104
|
+
* @param options.permissionType - The permission type to check (e.g., '0xabc::my_app::Editor')
|
|
105
|
+
* @returns `true` if the address has the permission, `false` otherwise
|
|
106
|
+
*/
|
|
107
|
+
async hasPermission(options) {
|
|
108
|
+
const permissions = await this.#getMemberPermissions(options.groupId, options.member);
|
|
109
|
+
if (permissions === null) return false;
|
|
110
|
+
const normalizedPermissionType = options.permissionType.replace(/^0x/, "");
|
|
111
|
+
return permissions.includes(normalizedPermissionType);
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Checks if the given address is a member of the group.
|
|
115
|
+
* A member is any address that has at least one permission.
|
|
116
|
+
*
|
|
117
|
+
* @param options.groupId - Object ID of the PermissionedGroup
|
|
118
|
+
* @param options.member - Address to check
|
|
119
|
+
* @returns `true` if the address is a member, `false` otherwise
|
|
120
|
+
*/
|
|
121
|
+
async isMember(options) {
|
|
122
|
+
return await this.#getMemberPermissions(options.groupId, options.member) !== null;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Fetches PermissionsTable entries by their dynamic field IDs
|
|
126
|
+
* and parses each into a MemberWithPermissions.
|
|
127
|
+
*/
|
|
128
|
+
async #fetchPermissionsTableEntries(fieldIds) {
|
|
129
|
+
if (fieldIds.length === 0) return [];
|
|
130
|
+
const { objects } = await this.#client.core.getObjects({
|
|
131
|
+
objectIds: fieldIds,
|
|
132
|
+
include: { content: true }
|
|
133
|
+
});
|
|
134
|
+
const members = [];
|
|
135
|
+
for (const obj of objects) {
|
|
136
|
+
if (obj instanceof Error) continue;
|
|
137
|
+
const parsed = DynamicFieldEntry.parse(obj.content);
|
|
138
|
+
members.push({
|
|
139
|
+
address: parsed.name,
|
|
140
|
+
permissions: parsed.value.map((typeName) => typeName.name)
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
return members;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Returns members of the group with their permissions.
|
|
147
|
+
*
|
|
148
|
+
* Supports two modes:
|
|
149
|
+
* - **Paginated** (default): returns a single page of members with cursor-based pagination.
|
|
150
|
+
* - **Exhaustive** (`{ exhaustive: true }`): fetches all members across all pages.
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* // Paginated
|
|
155
|
+
* const page = await client.groups.view.getMembers({ groupId: '0x...' });
|
|
156
|
+
* console.log(page.members, page.hasNextPage, page.cursor);
|
|
157
|
+
*
|
|
158
|
+
* // Exhaustive
|
|
159
|
+
* const all = await client.groups.view.getMembers({ groupId: '0x...', exhaustive: true });
|
|
160
|
+
* console.log(all.members); // all.hasNextPage is always false
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
async getMembers(options) {
|
|
164
|
+
const tableId = this.#derivePermissionsTableId(options.groupId);
|
|
165
|
+
if ("exhaustive" in options) {
|
|
166
|
+
const allMembers = [];
|
|
167
|
+
let cursor = null;
|
|
168
|
+
let hasNextPage = true;
|
|
169
|
+
while (hasNextPage) {
|
|
170
|
+
const page = await this.#client.core.listDynamicFields({
|
|
171
|
+
parentId: tableId,
|
|
172
|
+
cursor
|
|
173
|
+
});
|
|
174
|
+
const members = await this.#fetchPermissionsTableEntries(page.dynamicFields.map((f) => f.fieldId));
|
|
175
|
+
allMembers.push(...members);
|
|
176
|
+
cursor = page.cursor;
|
|
177
|
+
hasNextPage = page.hasNextPage;
|
|
178
|
+
}
|
|
179
|
+
return {
|
|
180
|
+
members: allMembers,
|
|
181
|
+
hasNextPage: false,
|
|
182
|
+
cursor: null
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
const page = await this.#client.core.listDynamicFields({
|
|
186
|
+
parentId: tableId,
|
|
187
|
+
cursor: options.cursor ?? null,
|
|
188
|
+
limit: options.limit
|
|
189
|
+
});
|
|
190
|
+
return {
|
|
191
|
+
members: await this.#fetchPermissionsTableEntries(page.dynamicFields.map((f) => f.fieldId)),
|
|
192
|
+
hasNextPage: page.hasNextPage,
|
|
193
|
+
cursor: page.cursor
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Checks if the group is currently paused.
|
|
198
|
+
*
|
|
199
|
+
* A group is paused when it has a `PausedMarker` dynamic field on its UID.
|
|
200
|
+
* Paused groups reject all mutation calls.
|
|
201
|
+
*
|
|
202
|
+
* @param options.groupId - Object ID of the PermissionedGroup
|
|
203
|
+
* @returns `true` if the group is paused, `false` otherwise
|
|
204
|
+
*/
|
|
205
|
+
async isPaused(options) {
|
|
206
|
+
const keyBytes = bcs.bool().serialize(false).toBytes();
|
|
207
|
+
const markerType = pausedMarkerType(this.#packageConfig.originalPackageId);
|
|
208
|
+
const pausedFieldId = deriveDynamicFieldID(options.groupId, markerType, keyBytes);
|
|
209
|
+
try {
|
|
210
|
+
await this.#client.core.getObject({ objectId: pausedFieldId });
|
|
211
|
+
return true;
|
|
212
|
+
} catch (error) {
|
|
213
|
+
if (isTransportError(error)) throw error;
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
|
|
219
|
+
//#endregion
|
|
220
|
+
export { SuiGroupsView };
|
|
221
|
+
//# sourceMappingURL=view.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"view.mjs","names":["#client","#packageConfig","#getMemberPermissions","#derivePermissionsTableId","#fetchPermissionsTableEntries"],"sources":["../src/view.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { bcs } from '@mysten/sui/bcs';\nimport { deriveDynamicFieldID, deriveObjectID } from '@mysten/sui/utils';\n\nimport { PERMISSIONS_TABLE_DERIVATION_KEY, pausedMarkerType } from './constants.js';\nimport type {\n\tGetMembersResponse,\n\tGetMembersViewOptions,\n\tHasPermissionViewOptions,\n\tIsMemberViewOptions,\n\tIsPausedViewOptions,\n\tMemberWithPermissions,\n\tSuiGroupsCompatibleClient,\n\tSuiGroupsPackageConfig,\n} from './types.js';\n\n/**\n * Checks whether an error is a transport/network-level error that should\n * be propagated (not swallowed as \"object not found\").\n *\n * Each Sui client transport produces structurally distinct transport errors:\n *\n * - JSON-RPC `SuiHTTPStatusError`: has `status: number` and `statusText: string`\n * - JSON-RPC `JsonRpcError`: has `code: number` and `type: string`\n * - gRPC `RpcError` (@protobuf-ts): has `meta: object`\n * - GraphQL `SuiGraphQLRequestError`: has `name: 'SuiGraphQLRequestError'`\n * - GraphQL `GraphQLResponseError`: has `locations` array\n * - `fetch` failures: `TypeError`\n *\n * Object-level errors (not found, deleted, etc.) lack these markers:\n * - JSON-RPC / GraphQL: `ObjectError` with string `code`\n * - gRPC: plain `Error(message)` with no transport metadata\n */\nexport function isTransportError(error: unknown): boolean {\n\tif (!(error instanceof Error)) return false;\n\n\tconst e = error as unknown as Record<string, unknown>;\n\n\t// JSON-RPC: SuiHTTPStatusError\n\tif (typeof e.status === 'number' && typeof e.statusText === 'string') return true;\n\n\t// JSON-RPC: JsonRpcError (numeric code + type string)\n\tif (typeof e.code === 'number' && typeof e.type === 'string') return true;\n\n\t// gRPC: RpcError from @protobuf-ts (carries request metadata)\n\tif (typeof e.meta === 'object' && e.meta !== null) return true;\n\n\t// GraphQL: SuiGraphQLRequestError\n\tif (error.constructor.name === 'SuiGraphQLRequestError') return true;\n\n\t// GraphQL: GraphQLResponseError\n\tif ('locations' in e) return true;\n\n\t// fetch() failures (network unreachable, DNS resolution, etc.)\n\tif (error instanceof TypeError) return true;\n\n\treturn false;\n}\n\n/**\n * BCS type for dynamic field entries keyed by address with VecSet<TypeName> values.\n */\nconst DynamicFieldEntry = bcs.struct('Field', {\n\tid: bcs.Address,\n\tname: bcs.Address,\n\tvalue: bcs.vector(\n\t\tbcs.struct('TypeName', {\n\t\t\tname: bcs.string(),\n\t\t}),\n\t),\n});\n\nexport interface SuiGroupsViewOptions {\n\tpackageConfig: SuiGroupsPackageConfig;\n\twitnessType: string;\n\tclient: SuiGroupsCompatibleClient;\n}\n\n/**\n * View methods for querying permissioned group state.\n *\n * These methods query on-chain state by fetching objects directly,\n * without requiring a signature or spending gas.\n *\n * Note: Fields like `creator` and `permissions_admin_count` are available\n * directly on the PermissionedGroup object when fetched via getObject.\n *\n * @example\n * ```ts\n * const hasPerm = await client.groups.view.hasPermission({\n * groupId: '0x456...',\n * member: '0x789...',\n * permissionType: '0xabc::my_app::Editor',\n * });\n *\n * const isMember = await client.groups.view.isMember({\n * groupId: '0x456...',\n * member: '0x789...',\n * });\n * ```\n */\nexport class SuiGroupsView {\n\t#client: SuiGroupsCompatibleClient;\n\t#packageConfig: SuiGroupsPackageConfig;\n\n\tconstructor(options: SuiGroupsViewOptions) {\n\t\tthis.#client = options.client;\n\t\tthis.#packageConfig = options.packageConfig;\n\t}\n\n\t/**\n\t * Derives the PermissionsTable object ID from a PermissionedGroup ID.\n\t *\n\t * The PermissionsTable is a derived object from its parent PermissionedGroup,\n\t * using the fixed derivation key \"permissions_table\" (as a Move `String`).\n\t * This makes the table ID fully deterministic — no RPC call needed.\n\t */\n\t#derivePermissionsTableId(groupId: string): string {\n\t\tconst string_type =\n\t\t\t'0x0000000000000000000000000000000000000000000000000000000000000001::string::String';\n\t\tconst keyBytes = bcs.string().serialize(PERMISSIONS_TABLE_DERIVATION_KEY).toBytes();\n\t\treturn deriveObjectID(groupId, string_type, keyBytes);\n\t}\n\n\t/**\n\t * Fetches a member's permissions from the group's permissions table.\n\t * Returns null if the member is not in the group.\n\t */\n\tasync #getMemberPermissions(groupId: string, member: string): Promise<string[] | null> {\n\t\tconst tableId = this.#derivePermissionsTableId(groupId);\n\n\t\t// Derive the dynamic field ID for this member's entry in the table.\n\t\t// Table entries use `address` as the key type.\n\t\tconst memberBcs = bcs.Address.serialize(member).toBytes();\n\t\tconst dynamicFieldId = deriveDynamicFieldID(tableId, 'address', memberBcs);\n\n\t\ttry {\n\t\t\tconst { object } = await this.#client.core.getObject({\n\t\t\t\tobjectId: dynamicFieldId,\n\t\t\t\tinclude: { content: true },\n\t\t\t});\n\t\t\tconst parsed = DynamicFieldEntry.parse(object.content);\n\t\t\treturn parsed.value.map((typeName) => typeName.name);\n\t\t} catch (error) {\n\t\t\tif (isTransportError(error)) throw error;\n\t\t\t// Object doesn't exist means member is not in the group\n\t\t\treturn null;\n\t\t}\n\t}\n\n\t/**\n\t * Checks if the given address has the specified permission.\n\t *\n\t * @param options.groupId - Object ID of the PermissionedGroup\n\t * @param options.member - Address to check\n\t * @param options.permissionType - The permission type to check (e.g., '0xabc::my_app::Editor')\n\t * @returns `true` if the address has the permission, `false` otherwise\n\t */\n\tasync hasPermission(options: HasPermissionViewOptions): Promise<boolean> {\n\t\tconst permissions = await this.#getMemberPermissions(options.groupId, options.member);\n\t\tif (permissions === null) {\n\t\t\treturn false;\n\t\t}\n\t\t// Normalize the permission type to match Move's type_name format (no 0x prefix)\n\t\tconst normalizedPermissionType = options.permissionType.replace(/^0x/, '');\n\t\treturn permissions.includes(normalizedPermissionType);\n\t}\n\n\t/**\n\t * Checks if the given address is a member of the group.\n\t * A member is any address that has at least one permission.\n\t *\n\t * @param options.groupId - Object ID of the PermissionedGroup\n\t * @param options.member - Address to check\n\t * @returns `true` if the address is a member, `false` otherwise\n\t */\n\tasync isMember(options: IsMemberViewOptions): Promise<boolean> {\n\t\tconst permissions = await this.#getMemberPermissions(options.groupId, options.member);\n\t\treturn permissions !== null;\n\t}\n\n\t/**\n\t * Fetches PermissionsTable entries by their dynamic field IDs\n\t * and parses each into a MemberWithPermissions.\n\t */\n\tasync #fetchPermissionsTableEntries(fieldIds: string[]): Promise<MemberWithPermissions[]> {\n\t\tif (fieldIds.length === 0) return [];\n\n\t\tconst { objects } = await this.#client.core.getObjects({\n\t\t\tobjectIds: fieldIds,\n\t\t\tinclude: { content: true },\n\t\t});\n\n\t\tconst members: MemberWithPermissions[] = [];\n\t\tfor (const obj of objects) {\n\t\t\tif (obj instanceof Error) continue;\n\t\t\tconst parsed = DynamicFieldEntry.parse(obj.content);\n\t\t\tmembers.push({\n\t\t\t\taddress: parsed.name,\n\t\t\t\tpermissions: parsed.value.map((typeName) => typeName.name),\n\t\t\t});\n\t\t}\n\t\treturn members;\n\t}\n\n\t/**\n\t * Returns members of the group with their permissions.\n\t *\n\t * Supports two modes:\n\t * - **Paginated** (default): returns a single page of members with cursor-based pagination.\n\t * - **Exhaustive** (`{ exhaustive: true }`): fetches all members across all pages.\n\t *\n\t * @example\n\t * ```ts\n\t * // Paginated\n\t * const page = await client.groups.view.getMembers({ groupId: '0x...' });\n\t * console.log(page.members, page.hasNextPage, page.cursor);\n\t *\n\t * // Exhaustive\n\t * const all = await client.groups.view.getMembers({ groupId: '0x...', exhaustive: true });\n\t * console.log(all.members); // all.hasNextPage is always false\n\t * ```\n\t */\n\tasync getMembers(options: GetMembersViewOptions): Promise<GetMembersResponse> {\n\t\tconst tableId = this.#derivePermissionsTableId(options.groupId);\n\n\t\tif ('exhaustive' in options) {\n\t\t\tconst allMembers: MemberWithPermissions[] = [];\n\t\t\tlet cursor: string | null = null;\n\t\t\tlet hasNextPage = true;\n\n\t\t\twhile (hasNextPage) {\n\t\t\t\tconst page = await this.#client.core.listDynamicFields({\n\t\t\t\t\tparentId: tableId,\n\t\t\t\t\tcursor,\n\t\t\t\t});\n\t\t\t\tconst members = await this.#fetchPermissionsTableEntries(\n\t\t\t\t\tpage.dynamicFields.map((f) => f.fieldId),\n\t\t\t\t);\n\t\t\t\tallMembers.push(...members);\n\t\t\t\tcursor = page.cursor;\n\t\t\t\thasNextPage = page.hasNextPage;\n\t\t\t}\n\n\t\t\treturn { members: allMembers, hasNextPage: false, cursor: null };\n\t\t}\n\n\t\t// Paginated mode\n\t\tconst page = await this.#client.core.listDynamicFields({\n\t\t\tparentId: tableId,\n\t\t\tcursor: options.cursor ?? null,\n\t\t\tlimit: options.limit,\n\t\t});\n\n\t\tconst members = await this.#fetchPermissionsTableEntries(\n\t\t\tpage.dynamicFields.map((f) => f.fieldId),\n\t\t);\n\n\t\treturn { members, hasNextPage: page.hasNextPage, cursor: page.cursor };\n\t}\n\n\t/**\n\t * Checks if the group is currently paused.\n\t *\n\t * A group is paused when it has a `PausedMarker` dynamic field on its UID.\n\t * Paused groups reject all mutation calls.\n\t *\n\t * @param options.groupId - Object ID of the PermissionedGroup\n\t * @returns `true` if the group is paused, `false` otherwise\n\t */\n\tasync isPaused(options: IsPausedViewOptions): Promise<boolean> {\n\t\t// PausedMarker is a unit struct with a single bool field (MoveTuple pattern).\n\t\t// The key stored on-chain is `false` (the phantom bool value).\n\t\tconst keyBytes = bcs.bool().serialize(false).toBytes();\n\t\tconst markerType = pausedMarkerType(this.#packageConfig.originalPackageId);\n\t\tconst pausedFieldId = deriveDynamicFieldID(options.groupId, markerType, keyBytes);\n\t\ttry {\n\t\t\tawait this.#client.core.getObject({ objectId: pausedFieldId });\n\t\t\treturn true;\n\t\t} catch (error) {\n\t\t\tif (isTransportError(error)) throw error;\n\t\t\treturn false;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mysten/sui-groups",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "Permissioned Groups",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"author": "Mysten Labs <build@mystenlabs.com>",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.mjs",
|
|
10
|
+
"types": "./dist/index.d.mts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.mts",
|
|
14
|
+
"import": "./dist/index.mjs"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"sideEffects": false,
|
|
18
|
+
"files": [
|
|
19
|
+
"dist"
|
|
20
|
+
],
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/MystenLabs/sui-groups.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/MystenLabs/sui-groups/issues/new"
|
|
27
|
+
},
|
|
28
|
+
"scripts": {
|
|
29
|
+
"clean": "rm -rf tsconfig.tsbuildinfo ./dist",
|
|
30
|
+
"build": "rm -rf dist && tsc --noEmit && tsdown",
|
|
31
|
+
"codegen:summaries": "(cd ../../../move/packages/sui_groups && sui move summary)",
|
|
32
|
+
"codegen": "pnpm codegen:summaries && sui-ts-codegen generate && pnpm lint:fix",
|
|
33
|
+
"prettier:check": "prettier -c --ignore-unknown .",
|
|
34
|
+
"prettier:fix": "prettier -w --ignore-unknown .",
|
|
35
|
+
"oxlint:check": "oxlint .",
|
|
36
|
+
"oxlint:fix": "oxlint --fix .",
|
|
37
|
+
"vitest": "vitest",
|
|
38
|
+
"test": "pnpm test:typecheck && pnpm test:unit",
|
|
39
|
+
"test:typecheck": "tsc -p ./test",
|
|
40
|
+
"test:unit": "vitest run unit",
|
|
41
|
+
"test:integration": "vitest run --config vitest.integration.config.mts",
|
|
42
|
+
"lint": "pnpm run oxlint:check && pnpm run prettier:check",
|
|
43
|
+
"lint:fix": "pnpm run oxlint:fix && pnpm run prettier:fix"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@mysten/bcs": "^2.0.3",
|
|
47
|
+
"@mysten/codegen": "^0.8.3",
|
|
48
|
+
"@mysten/sui": "^2.13.0",
|
|
49
|
+
"testcontainers": "^11.13.0",
|
|
50
|
+
"typescript": "^5.9.3",
|
|
51
|
+
"vitest": "^4.0.18"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@mysten/bcs": "^2.0.3",
|
|
55
|
+
"@mysten/sui": "^2.13.0"
|
|
56
|
+
}
|
|
57
|
+
}
|