@misofm/partyos 0.1.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 (58) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +50 -0
  3. package/dist/client.d.ts +84 -0
  4. package/dist/client.d.ts.map +1 -0
  5. package/dist/client.js +109 -0
  6. package/dist/client.js.map +1 -0
  7. package/dist/contracts/partyos/deps/sui/vec_set.d.ts +21 -0
  8. package/dist/contracts/partyos/deps/sui/vec_set.d.ts.map +1 -0
  9. package/dist/contracts/partyos/deps/sui/vec_set.js +20 -0
  10. package/dist/contracts/partyos/deps/sui/vec_set.js.map +1 -0
  11. package/dist/contracts/partyos/party.d.ts +481 -0
  12. package/dist/contracts/partyos/party.d.ts.map +1 -0
  13. package/dist/contracts/partyos/party.js +527 -0
  14. package/dist/contracts/partyos/party.js.map +1 -0
  15. package/dist/contracts/utils/index.d.ts +104 -0
  16. package/dist/contracts/utils/index.d.ts.map +1 -0
  17. package/dist/contracts/utils/index.js +272 -0
  18. package/dist/contracts/utils/index.js.map +1 -0
  19. package/dist/contracts.d.ts +12 -0
  20. package/dist/contracts.d.ts.map +1 -0
  21. package/dist/contracts.js +21 -0
  22. package/dist/contracts.js.map +1 -0
  23. package/dist/deployments.d.ts +33 -0
  24. package/dist/deployments.d.ts.map +1 -0
  25. package/dist/deployments.js +63 -0
  26. package/dist/deployments.js.map +1 -0
  27. package/dist/index.d.ts +7 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +14 -0
  30. package/dist/index.js.map +1 -0
  31. package/dist/internal.d.ts +5 -0
  32. package/dist/internal.d.ts.map +1 -0
  33. package/dist/internal.js +24 -0
  34. package/dist/internal.js.map +1 -0
  35. package/dist/queries.d.ts +37 -0
  36. package/dist/queries.d.ts.map +1 -0
  37. package/dist/queries.js +123 -0
  38. package/dist/queries.js.map +1 -0
  39. package/dist/transactions.d.ts +74 -0
  40. package/dist/transactions.d.ts.map +1 -0
  41. package/dist/transactions.js +85 -0
  42. package/dist/transactions.js.map +1 -0
  43. package/dist/types.d.ts +12 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +4 -0
  46. package/dist/types.js.map +1 -0
  47. package/package.json +97 -0
  48. package/src/client.ts +165 -0
  49. package/src/contracts/partyos/deps/sui/vec_set.ts +22 -0
  50. package/src/contracts/partyos/party.ts +798 -0
  51. package/src/contracts/utils/index.ts +428 -0
  52. package/src/contracts.ts +31 -0
  53. package/src/deployments.ts +90 -0
  54. package/src/index.ts +15 -0
  55. package/src/internal.ts +30 -0
  56. package/src/queries.ts +167 -0
  57. package/src/transactions.ts +167 -0
  58. package/src/types.ts +18 -0
@@ -0,0 +1,428 @@
1
+
2
+ import {
3
+ bcs,
4
+ type BcsType,
5
+ type TypeTag,
6
+ TypeTagSerializer,
7
+ BcsStruct,
8
+ BcsEnum,
9
+ BcsTuple,
10
+ } from '@mysten/sui/bcs';
11
+ import { normalizeStructTag, normalizeSuiAddress } from '@mysten/sui/utils';
12
+ import {
13
+ type TransactionArgument,
14
+ type TransactionObjectArgument,
15
+ isArgument,
16
+ } from '@mysten/sui/transactions';
17
+ import { type ClientWithCoreApi, type SuiClientTypes } from '@mysten/sui/client';
18
+
19
+ const MOVE_STDLIB_ADDRESS = normalizeSuiAddress('0x1');
20
+ const SUI_FRAMEWORK_ADDRESS = normalizeSuiAddress('0x2');
21
+
22
+ export type RawTransactionArgument<T> = T | TransactionArgument;
23
+
24
+ export type GetOptions<Include extends Omit<SuiClientTypes.ObjectInclude, 'content'> = {}> =
25
+ SuiClientTypes.GetObjectOptions<Include> & { client: ClientWithCoreApi };
26
+
27
+ export type GetManyOptions<Include extends Omit<SuiClientTypes.ObjectInclude, 'content'> = {}> =
28
+ SuiClientTypes.GetObjectsOptions<Include> & { client: ClientWithCoreApi };
29
+
30
+ export function getPureBcsSchema(typeTag: string | TypeTag): BcsType<any> | null {
31
+ const parsedTag = typeof typeTag === 'string' ? TypeTagSerializer.parseFromStr(typeTag) : typeTag;
32
+
33
+ if ('u8' in parsedTag) {
34
+ return bcs.U8;
35
+ } else if ('u16' in parsedTag) {
36
+ return bcs.U16;
37
+ } else if ('u32' in parsedTag) {
38
+ return bcs.U32;
39
+ } else if ('u64' in parsedTag) {
40
+ return bcs.U64;
41
+ } else if ('u128' in parsedTag) {
42
+ return bcs.U128;
43
+ } else if ('u256' in parsedTag) {
44
+ return bcs.U256;
45
+ } else if ('address' in parsedTag) {
46
+ return bcs.Address;
47
+ } else if ('bool' in parsedTag) {
48
+ return bcs.Bool;
49
+ } else if ('vector' in parsedTag) {
50
+ const type = getPureBcsSchema(parsedTag.vector);
51
+ return type ? bcs.vector(type) : null;
52
+ } else if ('struct' in parsedTag) {
53
+ const structTag = parsedTag.struct;
54
+ const pkg = normalizeSuiAddress(structTag.address);
55
+
56
+ if (pkg === MOVE_STDLIB_ADDRESS) {
57
+ if (
58
+ (structTag.module === 'ascii' || structTag.module === 'string') &&
59
+ structTag.name === 'String'
60
+ ) {
61
+ return bcs.String;
62
+ }
63
+
64
+ if (structTag.module === 'option' && structTag.name === 'Option') {
65
+ const inner = structTag.typeParams[0];
66
+ const type = inner ? getPureBcsSchema(inner) : null;
67
+ return type ? bcs.option(type) : null;
68
+ }
69
+ }
70
+
71
+ if (
72
+ pkg === SUI_FRAMEWORK_ADDRESS &&
73
+ structTag.module === 'object' &&
74
+ (structTag.name === 'ID' || structTag.name === 'UID')
75
+ ) {
76
+ return bcs.Address;
77
+ }
78
+ }
79
+
80
+ return null;
81
+ }
82
+
83
+ export function normalizeMoveArguments(
84
+ args: unknown[] | object,
85
+ argTypes: readonly (string | null)[],
86
+ parameterNames?: string[],
87
+ ) {
88
+ const argLen = Array.isArray(args) ? args.length : Object.keys(args).length;
89
+ if (parameterNames && argLen !== parameterNames.length) {
90
+ throw new Error(
91
+ `Invalid number of arguments, expected ${parameterNames.length}, got ${argLen}`,
92
+ );
93
+ }
94
+
95
+ const normalizedArgs: TransactionArgument[] = [];
96
+
97
+ let index = 0;
98
+ for (const argType of argTypes) {
99
+ if (argType === '0x2::clock::Clock') {
100
+ normalizedArgs.push((tx) => tx.object.clock());
101
+ continue;
102
+ }
103
+
104
+ if (argType === '0x2::random::Random') {
105
+ normalizedArgs.push((tx) => tx.object.random());
106
+ continue;
107
+ }
108
+
109
+ if (argType === '0x2::deny_list::DenyList') {
110
+ normalizedArgs.push((tx) => tx.object.denyList());
111
+ continue;
112
+ }
113
+
114
+ if (argType === '0x2::accumulator::AccumulatorRoot') {
115
+ // Chain-wide shared singleton at a fixed address (SUI_ACCUMULATOR_ROOT_OBJECT_ID).
116
+ normalizedArgs.push((tx) => tx.object('0xacc'));
117
+ continue;
118
+ }
119
+
120
+ if (argType === '0x3::sui_system::SuiSystemState') {
121
+ normalizedArgs.push((tx) => tx.object.system());
122
+ continue;
123
+ }
124
+
125
+ let arg;
126
+ if (Array.isArray(args)) {
127
+ if (index >= args.length) {
128
+ throw new Error(
129
+ `Invalid number of arguments, expected at least ${index + 1}, got ${args.length}`,
130
+ );
131
+ }
132
+ arg = args[index];
133
+ } else {
134
+ if (!parameterNames) {
135
+ throw new Error(`Expected arguments to be passed as an array`);
136
+ }
137
+ const name = parameterNames[index];
138
+ arg =
139
+ name !== undefined && Object.prototype.hasOwnProperty.call(args, name)
140
+ ? args[name as keyof typeof args]
141
+ : undefined;
142
+
143
+ if (arg === undefined) {
144
+ throw new Error(`Parameter ${name} is required`);
145
+ }
146
+ }
147
+
148
+ index += 1;
149
+
150
+ if (typeof arg === 'function' || isArgument(arg)) {
151
+ normalizedArgs.push(arg as TransactionArgument);
152
+ continue;
153
+ }
154
+
155
+ const bcsType = argType === null ? null : getPureBcsSchema(argType);
156
+
157
+ if (bcsType) {
158
+ const bytes = bcsType.serialize(arg as never);
159
+ normalizedArgs.push((tx) => tx.pure(bytes));
160
+ continue;
161
+ }
162
+
163
+ if (typeof arg === 'string') {
164
+ normalizedArgs.push((tx) => tx.object(arg));
165
+ continue;
166
+ }
167
+
168
+ throw new Error(`Invalid argument ${stringify(arg)} for type ${argType}`);
169
+ }
170
+
171
+ return normalizedArgs;
172
+ }
173
+
174
+ /* -------------------------- Config-mapped arguments -------------------------- */
175
+
176
+ /** Context passed to config resolver functions. */
177
+ export interface ConfigResolverContext {
178
+ /**
179
+ * The matched parameter's own instantiated type arguments (not the whole function's type
180
+ * argument tuple). Concrete instantiations are canonical type tags; generic positions pass
181
+ * the caller's `typeArguments` strings through as provided.
182
+ */
183
+ typeArguments: string[];
184
+ /** The package address the generated call will be sent to. */
185
+ packageAddress: string;
186
+ /** The Move module of the generated call. */
187
+ moduleName: string;
188
+ /** The Move function of the generated call. */
189
+ functionName: string;
190
+ /** The Move name of the matched parameter, when the summary includes parameter names. */
191
+ parameterName?: string;
192
+ /** The matched parameter's position in the generated function's arguments. */
193
+ parameterIndex: number;
194
+ }
195
+
196
+ /**
197
+ * A non-callback transaction argument in a generated config object, used for keys whose matched
198
+ * parameter can't be supplied as an object id string.
199
+ */
200
+ export type ConfigObjectValue = Exclude<TransactionObjectArgument, (...args: never[]) => unknown>;
201
+
202
+ /**
203
+ * A plain value in a generated config object: an object id or a non-callback transaction
204
+ * argument. Keys that can resolve multiple bindings are typed as resolver functions instead.
205
+ */
206
+ export type ConfigValue = string | ConfigObjectValue;
207
+
208
+ /* -------------------------- Move type tags -------------------------- */
209
+
210
+ /** A type argument: a type tag string, or a BCS type whose name is a Move type. */
211
+ export type TypeArgument = string | BcsType<any>;
212
+
213
+ export interface TypeTagOptions {
214
+ package?: string;
215
+ typeArguments?: readonly TypeArgument[];
216
+ }
217
+
218
+ /**
219
+ * `typeArguments` is required when the type's name contains unfilled
220
+ * `phantom X` parameters (at any depth). Everything else — argument arity,
221
+ * position contents, and tag validity — is validated at runtime.
222
+ */
223
+ type TypeTagParams<Name extends string> = Name extends `${string}phantom ${string}`
224
+ ? [options: TypeTagOptions & { typeArguments: readonly TypeArgument[] }]
225
+ : [options?: TypeTagOptions];
226
+
227
+ type ResolveTypeTagOptions<Name extends string> = { client: ClientWithCoreApi } & (
228
+ Name extends `${string}phantom ${string}`
229
+ ? TypeTagOptions & { typeArguments: readonly TypeArgument[] }
230
+ : TypeTagOptions
231
+ );
232
+
233
+ const HAS_PHANTOM_REGEX = /phantom [A-Za-z_$][A-Za-z0-9_$]*/;
234
+
235
+ function splitTopLevelTypeArgs(inner: string): string[] {
236
+ const parts: string[] = [];
237
+ let depth = 0;
238
+ let current = '';
239
+ for (const char of inner) {
240
+ if (char === ',' && depth === 0) {
241
+ parts.push(current.trim());
242
+ current = '';
243
+ continue;
244
+ }
245
+ if (char === '<') depth++;
246
+ if (char === '>') depth--;
247
+ current += char;
248
+ }
249
+ if (current) parts.push(current.trim());
250
+ return parts;
251
+ }
252
+
253
+ function buildTypeTag(name: string, options: TypeTagOptions | undefined): string {
254
+ const lt = name.indexOf('<');
255
+ const base = lt === -1 ? name : name.slice(0, lt);
256
+
257
+ if (base.split('::').length !== 3) {
258
+ throw new Error(`${name} is not a top-level Move type`);
259
+ }
260
+
261
+ let result = name;
262
+
263
+ if (options?.typeArguments) {
264
+ const baked = lt === -1 ? [] : splitTopLevelTypeArgs(name.slice(lt + 1, -1));
265
+ const supplied = options.typeArguments.map((arg) => {
266
+ if (typeof arg === 'string') {
267
+ return arg;
268
+ }
269
+ if (arg && typeof arg.serialize === 'function' && typeof arg.name === 'string') {
270
+ return arg.name;
271
+ }
272
+ throw new Error(`Invalid type argument ${stringify(arg)}`);
273
+ });
274
+
275
+ if (supplied.length !== baked.length) {
276
+ throw new Error(
277
+ `Expected ${baked.length} type arguments for ${base}, got ${supplied.length}`,
278
+ );
279
+ }
280
+
281
+ result = supplied.length === 0 ? base : `${base}<${supplied.join(', ')}>`;
282
+ }
283
+
284
+ if (HAS_PHANTOM_REGEX.test(result)) {
285
+ throw new Error(
286
+ options?.typeArguments
287
+ ? `A type argument contains an unfilled phantom parameter in ${result}`
288
+ : `Missing type arguments for ${result}`,
289
+ );
290
+ }
291
+
292
+ if (options?.package) {
293
+ const [, ...rest] = result.split('::');
294
+ result = [options.package, ...rest].join('::');
295
+ }
296
+
297
+ // fully validate address-only tags (MVR names can't be parsed as type tags)
298
+ if (!HAS_PHANTOM_REGEX.test(result) && !/[@/]/.test(result)) {
299
+ TypeTagSerializer.parseFromStr(result);
300
+ }
301
+
302
+ return result;
303
+ }
304
+
305
+ async function resolveBuiltTypeTag(
306
+ name: string,
307
+ options: { client: ClientWithCoreApi } & TypeTagOptions,
308
+ ): Promise<string> {
309
+ const { client, ...rest } = options;
310
+ const { type } = await client.core.mvr.resolveType({
311
+ type: buildTypeTag(name, rest),
312
+ });
313
+ return normalizeStructTag(type);
314
+ }
315
+
316
+ export class MoveStruct<
317
+ T extends Record<string, BcsType<any>>,
318
+ const Name extends string = string,
319
+ > extends BcsStruct<T, Name> {
320
+ /**
321
+ * Build the type tag for this struct.
322
+ *
323
+ * `typeArguments` is the full positional list, in Move declaration order, and
324
+ * is required when the struct has unfilled phantom parameters. The result may
325
+ * contain MVR names: those are valid in transaction `typeArguments`, but for
326
+ * queries or comparisons against on-chain data use `resolveTypeTag` instead.
327
+ */
328
+ typeTag(...args: TypeTagParams<Name>): string {
329
+ return buildTypeTag(this.name, args[0] as TypeTagOptions | undefined);
330
+ }
331
+
332
+ /**
333
+ * Build the type tag for this struct, then resolve any MVR names through the
334
+ * client (using its configured overrides and the MVR API) and return the
335
+ * normalized, address-only form suitable for queries and comparisons against
336
+ * on-chain data.
337
+ */
338
+ async resolveTypeTag(options: ResolveTypeTagOptions<Name>): Promise<string> {
339
+ return resolveBuiltTypeTag(this.name, options as { client: ClientWithCoreApi } & TypeTagOptions);
340
+ }
341
+
342
+ async get<Include extends Omit<SuiClientTypes.ObjectInclude, 'content' | 'json'> = {}>({
343
+ objectId,
344
+ ...options
345
+ }: GetOptions<Include>): Promise<
346
+ SuiClientTypes.Object<Include & { content: true, json: true }> & { json: BcsStruct<T>['$inferType'] }
347
+ > {
348
+ const [res] = await this.getMany<Include>({
349
+ ...options,
350
+ objectIds: [objectId],
351
+ });
352
+
353
+ if (!res) {
354
+ throw new Error(`No object found for id ${objectId}`);
355
+ }
356
+
357
+ return res;
358
+ }
359
+
360
+ async getMany<Include extends Omit<SuiClientTypes.ObjectInclude, 'content' | 'json'> = {}>({
361
+ client,
362
+ ...options
363
+ }: GetManyOptions<Include>): Promise<
364
+ Array<SuiClientTypes.Object<Include & { content: true, json: true }> & { json: BcsStruct<T>['$inferType'] }>
365
+ > {
366
+ const response = (await client.core.getObjects({
367
+ ...options,
368
+ include: {
369
+ ...options.include,
370
+ content: true,
371
+ },
372
+ })) as SuiClientTypes.GetObjectsResponse<Include & { content: true }>;
373
+
374
+ return response.objects.map((obj) => {
375
+ if (obj instanceof Error) {
376
+ throw obj;
377
+ }
378
+
379
+ return {
380
+ ...obj,
381
+ json: this.parse(obj.content),
382
+ };
383
+ });
384
+ }
385
+ }
386
+
387
+ export class MoveEnum<
388
+ T extends Record<string, BcsType<any> | null>,
389
+ const Name extends string,
390
+ > extends BcsEnum<T, Name> {
391
+ /** Build the type tag for this enum. See `MoveStruct.typeTag` for semantics. */
392
+ typeTag(...args: TypeTagParams<Name>): string {
393
+ return buildTypeTag(this.name, args[0] as TypeTagOptions | undefined);
394
+ }
395
+
396
+ /** Build and resolve the type tag for this enum. See `MoveStruct.resolveTypeTag`. */
397
+ async resolveTypeTag(options: ResolveTypeTagOptions<Name>): Promise<string> {
398
+ return resolveBuiltTypeTag(this.name, options as { client: ClientWithCoreApi } & TypeTagOptions);
399
+ }
400
+ }
401
+
402
+ export class MoveTuple<
403
+ const T extends readonly BcsType<any>[],
404
+ const Name extends string,
405
+ > extends BcsTuple<T, Name> {
406
+ /** Build the type tag for this struct. See `MoveStruct.typeTag` for semantics. */
407
+ typeTag(...args: TypeTagParams<Name>): string {
408
+ return buildTypeTag(this.name, args[0] as TypeTagOptions | undefined);
409
+ }
410
+
411
+ /** Build and resolve the type tag for this struct. See `MoveStruct.resolveTypeTag`. */
412
+ async resolveTypeTag(options: ResolveTypeTagOptions<Name>): Promise<string> {
413
+ return resolveBuiltTypeTag(this.name, options as { client: ClientWithCoreApi } & TypeTagOptions);
414
+ }
415
+ }
416
+
417
+ function stringify(val: unknown) {
418
+ if (typeof val === 'object') {
419
+ return JSON.stringify(val, (_key, value) =>
420
+ typeof value === 'bigint' ? value.toString() : value,
421
+ );
422
+ }
423
+ if (typeof val === 'bigint') {
424
+ return val.toString();
425
+ }
426
+
427
+ return val;
428
+ }
@@ -0,0 +1,31 @@
1
+ // Copyright (c) Miso Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // Barrel for the codegen-generated, ABI-bound bindings (BCS structs + type-safe
5
+ // Move calls). Re-exported from the package root as the `contracts` namespace.
6
+ //
7
+ // The generated default `@local-pkg/partyos` identity is a source label only:
8
+ // callers must inject the exact published address through `PartyDeployment`
9
+ // before building a transaction.
10
+
11
+ import * as rawParty from "./contracts/partyos/party.ts";
12
+
13
+ type PublicModule<M extends object, K extends readonly (keyof M)[]> = Omit<M, K[number]>;
14
+ function withoutUnsafeCalls<M extends object, K extends readonly (keyof M)[]>(
15
+ module: M,
16
+ keys: K,
17
+ ): PublicModule<M, K> {
18
+ return Object.fromEntries(
19
+ Object.entries(module).filter(([key]) => !keys.includes(key as keyof M)),
20
+ ) as PublicModule<M, K>;
21
+ }
22
+
23
+ /**
24
+ * Public Move functions that return references. A PTB can borrow internally,
25
+ * but a Move-call command result cannot carry a reference to a later command,
26
+ * so they are kept out of the curated barrel and the client's `call` namespace.
27
+ */
28
+ export const PARTY_REF_RETURNING_CALLS = ["groupMembers", "uid", "uidMut"] as const;
29
+
30
+ /** Party core (BCS codecs remain available; PTB-inaccessible references do not). */
31
+ export const party = withoutUnsafeCalls(rawParty, PARTY_REF_RETURNING_CALLS);
@@ -0,0 +1,90 @@
1
+ // Copyright (c) Miso Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ import { normalizeSuiAddress } from "@mysten/sui/utils";
5
+
6
+ /** Sui networks for which this SDK may bundle a verified deployment. */
7
+ export type PartyosNetwork = "mainnet" | "testnet";
8
+
9
+ /**
10
+ * The single independently published package required by this SDK surface:
11
+ * the `partyos` object-model package (module `party`).
12
+ *
13
+ * This name is a stable deployment-manifest key, not a Move module name. Its
14
+ * value is never inferred from a source label or a previous publish.
15
+ */
16
+ const CANONICAL_PARTYOS_PACKAGE_NAMES = ["partyos"] as const;
17
+
18
+ export type PartyosPackageName = (typeof CANONICAL_PARTYOS_PACKAGE_NAMES)[number];
19
+
20
+ /**
21
+ * Exact package address from one compatible publish. Fill this only from the
22
+ * verified immutable publish record.
23
+ */
24
+ export type PartyDeployment = Readonly<Record<PartyosPackageName, string>>;
25
+
26
+ /** Verified immutable deployments bundled with this SDK release. */
27
+ export const PARTYOS_DEPLOYMENTS = Object.freeze({
28
+ testnet: Object.freeze({
29
+ partyos: "0xc9fc5d918da992b7c6499880fc509635def384d8529948b28f58494daedf8ec8",
30
+ } as const),
31
+ } as const) satisfies Partial<Record<PartyosNetwork, PartyDeployment>>;
32
+
33
+ /** Resolve a verified manifest, failing closed for unbundled networks. */
34
+ export function getPartyDeployment(network: string): PartyDeployment {
35
+ const deployment = (PARTYOS_DEPLOYMENTS as Partial<Record<string, PartyDeployment>>)[network];
36
+ if (!deployment) {
37
+ throw new Error(
38
+ `@misofm/partyos: no verified PartyOS deployment is bundled for network "${network}". ` +
39
+ "Inject the exact post-publish manifest or pass an explicit deployment; historic package IDs are rejected.",
40
+ );
41
+ }
42
+ return normalizePartyDeployment(deployment);
43
+ }
44
+
45
+ /**
46
+ * Validates an explicit manifest before any Move target is constructed. This is
47
+ * useful at configuration boundaries such as environment-file loading.
48
+ */
49
+ export function assertPartyDeployment(deployment: unknown): asserts deployment is PartyDeployment {
50
+ if (!deployment || typeof deployment !== "object" || Array.isArray(deployment)) {
51
+ throw new Error(
52
+ `@misofm/partyos: deployment must be an object with exactly these package IDs: ${CANONICAL_PARTYOS_PACKAGE_NAMES.join(", ")}.`,
53
+ );
54
+ }
55
+ const entries = deployment as Record<string, unknown>;
56
+ const keys = Object.keys(entries);
57
+ const unexpected = keys.filter(
58
+ (key) => !CANONICAL_PARTYOS_PACKAGE_NAMES.includes(key as PartyosPackageName),
59
+ );
60
+ if (unexpected.length > 0 || keys.length !== CANONICAL_PARTYOS_PACKAGE_NAMES.length) {
61
+ throw new Error(
62
+ `@misofm/partyos: deployment must contain exactly these package IDs: ${CANONICAL_PARTYOS_PACKAGE_NAMES.join(", ")}.`,
63
+ );
64
+ }
65
+ for (const name of CANONICAL_PARTYOS_PACKAGE_NAMES) {
66
+ const packageId = entries[name];
67
+ if (typeof packageId !== "string") {
68
+ throw new Error(`@misofm/partyos: deployment is missing package ID for "${name}".`);
69
+ }
70
+ let normalized: string;
71
+ try {
72
+ normalized = normalizeSuiAddress(packageId);
73
+ } catch {
74
+ throw new Error(`@misofm/partyos: deployment package ID for "${name}" is not a valid Sui address.`);
75
+ }
76
+ if (packageId !== normalized) {
77
+ throw new Error(
78
+ `@misofm/partyos: deployment package ID for "${name}" must be normalized (${normalized}).`,
79
+ );
80
+ }
81
+ }
82
+ }
83
+
84
+ /** Validate and snapshot an untrusted manifest so later caller mutation is inert. */
85
+ export function normalizePartyDeployment(deployment: unknown): PartyDeployment {
86
+ assertPartyDeployment(deployment);
87
+ return Object.freeze(
88
+ Object.fromEntries(CANONICAL_PARTYOS_PACKAGE_NAMES.map((name) => [name, deployment[name]])),
89
+ ) as PartyDeployment;
90
+ }
package/src/index.ts ADDED
@@ -0,0 +1,15 @@
1
+ // Copyright (c) Miso Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // `@misofm/partyos` — the PartyOS object model: Party identity, its admin cap,
5
+ // and consent-based group membership. Everything Miso offers on top of a Party
6
+ // (profiles, media, roles, tags, genres, CTAs, platform links, the party
7
+ // wallet) is an extension and ships from `@misofm/platform`.
8
+ export * from "./types.ts";
9
+ export * from "./transactions.ts";
10
+ export * from "./queries.ts";
11
+ export * from "./client.ts";
12
+ export * from "./deployments.ts";
13
+
14
+ // Generated, ABI-bound bindings (BCS structs + type-safe Move calls).
15
+ export * as contracts from "./contracts.ts";
@@ -0,0 +1,30 @@
1
+ // Copyright (c) Miso Labs, Inc.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+
4
+ // The single boundary between generated BCS-parse output (snake_case, Move-shaped)
5
+ // and the public camelCase types.
6
+
7
+ import { fromBase64 } from "@mysten/sui/utils";
8
+ import type { Party } from "./types.ts";
9
+
10
+ // deno-lint-ignore no-explicit-any -- generated parse output is loosely typed
11
+ export function mapParty(id: string, d: any): Party {
12
+ const kind = d.kind;
13
+ const createdAtMs = Number(d.created_at_ms);
14
+ // PartyKind is `Individual | Group(VecSet<ID>)`. The enum parses to
15
+ // `{ $kind, Individual? , Group? }`; Group's payload is a VecSet `{ contents }`.
16
+ const groupPayload = kind?.Group ?? (kind?.$kind === "Group" ? kind.value : undefined);
17
+ if (groupPayload !== undefined) {
18
+ const contents = groupPayload?.contents ?? groupPayload ?? [];
19
+ const members = (Array.isArray(contents) ? contents : []).map((m: unknown) =>
20
+ typeof m === "string" ? m : (m as { id?: string })?.id ?? String(m),
21
+ );
22
+ return { id, kind: "group", name: d.name, members, createdAtMs };
23
+ }
24
+ return { id, kind: "individual", name: d.name, createdAtMs };
25
+ }
26
+
27
+ /** Normalizes a dynamic-field key's BCS bytes (Uint8Array or base64 string). */
28
+ export function keyBytes(bcs: unknown): Uint8Array {
29
+ return typeof bcs === "string" ? fromBase64(bcs) : (bcs as Uint8Array);
30
+ }