@mysten/sui 2.10.0 → 2.12.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.
- package/CHANGELOG.md +16 -0
- package/dist/bcs/bcs.d.mts +6 -6
- package/dist/bcs/index.d.mts +20 -20
- package/dist/client/types.d.mts +8 -0
- package/dist/client/types.d.mts.map +1 -1
- package/dist/graphql/core.d.mts.map +1 -1
- package/dist/graphql/core.mjs +2 -1
- package/dist/graphql/core.mjs.map +1 -1
- package/dist/grpc/core.d.mts.map +1 -1
- package/dist/grpc/core.mjs +3 -1
- package/dist/grpc/core.mjs.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/ledger_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/move_package_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/signature_verification_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/state_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/subscription_service.client.d.mts +4 -4
- package/dist/grpc/proto/sui/rpc/v2/transaction.d.mts.map +1 -1
- package/dist/grpc/proto/sui/rpc/v2/transaction_execution_service.client.d.mts +4 -4
- package/dist/jsonRpc/core.d.mts.map +1 -1
- package/dist/jsonRpc/core.mjs +30 -20
- package/dist/jsonRpc/core.mjs.map +1 -1
- package/dist/jsonRpc/http-transport.d.mts +1 -17
- package/dist/jsonRpc/http-transport.d.mts.map +1 -1
- package/dist/jsonRpc/http-transport.mjs +0 -23
- package/dist/jsonRpc/http-transport.mjs.map +1 -1
- package/dist/jsonRpc/index.d.mts +3 -3
- package/dist/jsonRpc/types/common.d.mts +1 -2
- package/dist/jsonRpc/types/common.d.mts.map +1 -1
- package/dist/jsonRpc/types/index.d.mts +1 -1
- package/dist/transactions/Transaction.d.mts +9 -9
- package/dist/transactions/Transaction.d.mts.map +1 -1
- package/dist/transactions/data/v1.d.mts +220 -220
- package/dist/transactions/data/v1.d.mts.map +1 -1
- package/dist/transactions/data/v2.d.mts +16 -16
- package/dist/transactions/data/v2.d.mts.map +1 -1
- package/dist/version.mjs +1 -1
- package/dist/version.mjs.map +1 -1
- package/dist/zklogin/bcs.d.mts +14 -14
- package/dist/zklogin/bcs.d.mts.map +1 -1
- package/docs/clients/core.md +15 -0
- package/docs/migrations/sui-2.0/json-rpc-migration.md +17 -1
- package/docs/utils/derived_objects.md +21 -0
- package/package.json +2 -4
- package/src/client/types.ts +8 -0
- package/src/graphql/core.ts +1 -0
- package/src/grpc/core.ts +5 -0
- package/src/jsonRpc/core.ts +50 -29
- package/src/jsonRpc/http-transport.ts +0 -52
- package/src/jsonRpc/index.ts +0 -1
- package/src/jsonRpc/types/common.ts +0 -1
- package/src/version.ts +1 -1
- package/dist/jsonRpc/rpc-websocket-client.d.mts +0 -26
- package/dist/jsonRpc/rpc-websocket-client.d.mts.map +0 -1
- package/dist/jsonRpc/rpc-websocket-client.mjs +0 -135
- package/dist/jsonRpc/rpc-websocket-client.mjs.map +0 -1
- package/src/jsonRpc/rpc-websocket-client.ts +0 -241
package/dist/zklogin/bcs.d.mts
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as _mysten_bcs1111 from "@mysten/bcs";
|
|
2
2
|
import { InferBcsInput } from "@mysten/bcs";
|
|
3
3
|
|
|
4
4
|
//#region src/zklogin/bcs.d.ts
|
|
5
|
-
declare const zkLoginSignature:
|
|
6
|
-
inputs:
|
|
7
|
-
proofPoints:
|
|
8
|
-
a:
|
|
5
|
+
declare const zkLoginSignature: _mysten_bcs1111.BcsStruct<{
|
|
6
|
+
inputs: _mysten_bcs1111.BcsStruct<{
|
|
7
|
+
proofPoints: _mysten_bcs1111.BcsStruct<{
|
|
8
|
+
a: _mysten_bcs1111.BcsType<string[], Iterable<string> & {
|
|
9
9
|
length: number;
|
|
10
10
|
}, string>;
|
|
11
|
-
b:
|
|
11
|
+
b: _mysten_bcs1111.BcsType<string[][], Iterable<Iterable<string> & {
|
|
12
12
|
length: number;
|
|
13
13
|
}> & {
|
|
14
14
|
length: number;
|
|
15
15
|
}, string>;
|
|
16
|
-
c:
|
|
16
|
+
c: _mysten_bcs1111.BcsType<string[], Iterable<string> & {
|
|
17
17
|
length: number;
|
|
18
18
|
}, string>;
|
|
19
19
|
}, string>;
|
|
20
|
-
issBase64Details:
|
|
21
|
-
value:
|
|
22
|
-
indexMod4:
|
|
20
|
+
issBase64Details: _mysten_bcs1111.BcsStruct<{
|
|
21
|
+
value: _mysten_bcs1111.BcsType<string, string, "string">;
|
|
22
|
+
indexMod4: _mysten_bcs1111.BcsType<number, number, "u8">;
|
|
23
23
|
}, string>;
|
|
24
|
-
headerBase64:
|
|
25
|
-
addressSeed:
|
|
24
|
+
headerBase64: _mysten_bcs1111.BcsType<string, string, "string">;
|
|
25
|
+
addressSeed: _mysten_bcs1111.BcsType<string, string, "string">;
|
|
26
26
|
}, string>;
|
|
27
|
-
maxEpoch:
|
|
28
|
-
userSignature:
|
|
27
|
+
maxEpoch: _mysten_bcs1111.BcsType<string, string | number | bigint, "u64">;
|
|
28
|
+
userSignature: _mysten_bcs1111.BcsType<Uint8Array<ArrayBufferLike>, Iterable<number>, "vector<u8>">;
|
|
29
29
|
}, string>;
|
|
30
30
|
type ZkLoginSignature = InferBcsInput<typeof zkLoginSignature>;
|
|
31
31
|
type ZkLoginSignatureInputs = ZkLoginSignature['inputs'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bcs.d.mts","names":[],"sources":["../../src/zklogin/bcs.ts"],"sourcesContent":[],"mappings":";;;;cAMa,
|
|
1
|
+
{"version":3,"file":"bcs.d.mts","names":[],"sources":["../../src/zklogin/bcs.ts"],"sourcesContent":[],"mappings":";;;;cAMa,kCAAgB;;;MAAhB,CAAA,yBAgBX,CAAA,MAAA,EAAA,UAAA,CAAA,MAAA,CAAA,GAAA;;;;;;;;;;;;;;;;;;;;eAhB2B,yBAAA,WAAA,gBAAA,CAAA,UAAA,CAAA,MAAA,CAAA,EAAA,YAAA,CAAA;CAAA,EAAA,MAAA,CAAA;AAkBjB,KAAA,gBAAA,GAAmB,aAAqB,CAAA,OAAA,gBAAR,CAAA;AAChC,KAAA,sBAAA,GAAyB,gBAAA,CAAA,QAAgB,CAAA"}
|
package/docs/clients/core.md
CHANGED
|
@@ -342,6 +342,21 @@ console.log(result.effects);
|
|
|
342
342
|
console.log(result.balanceChanges);
|
|
343
343
|
```
|
|
344
344
|
|
|
345
|
+
#### Disabling Checks
|
|
346
|
+
|
|
347
|
+
By default, `simulateTransaction` runs with full transaction validation. For example when inspecting
|
|
348
|
+
non-public or non-entry Move functions set `checksEnabled: false`:
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
const result = await client.core.simulateTransaction({
|
|
352
|
+
transaction: transactionBytes,
|
|
353
|
+
checksEnabled: false,
|
|
354
|
+
include: {
|
|
355
|
+
commandResults: true,
|
|
356
|
+
},
|
|
357
|
+
});
|
|
358
|
+
```
|
|
359
|
+
|
|
345
360
|
### signAndExecuteTransaction
|
|
346
361
|
|
|
347
362
|
Sign and execute a transaction in one step.
|
|
@@ -54,11 +54,27 @@ These JSON-RPC methods have direct replacements in the core API:
|
|
|
54
54
|
| `multiGetObjects` | `getObjects` |
|
|
55
55
|
| `getDynamicFields` | `listDynamicFields` |
|
|
56
56
|
| `getDynamicFieldObject` | `getDynamicField` |
|
|
57
|
-
| `devInspectTransactionBlock` | `simulateTransaction`
|
|
57
|
+
| `devInspectTransactionBlock` | `simulateTransaction` with `checksEnabled: false` |
|
|
58
58
|
| `dryRunTransactionBlock` | `simulateTransaction` |
|
|
59
59
|
| `getNormalizedMoveFunction` | `getMoveFunction` |
|
|
60
60
|
| `getMoveFunctionArgTypes` | `getMoveFunction` |
|
|
61
61
|
|
|
62
|
+
### Example: Migrating devInspectTransactionBlock
|
|
63
|
+
|
|
64
|
+
```diff
|
|
65
|
+
- const result = await jsonRpcClient.devInspectTransactionBlock({
|
|
66
|
+
- sender: '0xabc...',
|
|
67
|
+
- transactionBlock: tx,
|
|
68
|
+
- });
|
|
69
|
+
- const returnValues = result.results?.[0]?.returnValues;
|
|
70
|
+
+ const result = await client.core.simulateTransaction({
|
|
71
|
+
+ transaction: tx,
|
|
72
|
+
+ checksEnabled: false,
|
|
73
|
+
+ include: { commandResults: true },
|
|
74
|
+
+ });
|
|
75
|
+
+ const returnValues = result.commandResults?.[0]?.returnValues;
|
|
76
|
+
```
|
|
77
|
+
|
|
62
78
|
### Example: Migrating getOwnedObjects
|
|
63
79
|
|
|
64
80
|
```diff
|
|
@@ -57,3 +57,24 @@ const key = bcsType.serialize({ value: 1 }).toBytes();
|
|
|
57
57
|
// Derive the object ID for the key `DemoStruct { value: 1 }`.
|
|
58
58
|
deriveObjectID('0xc0ffee', `0xc0ffee::demo::DemoStruct`, key);
|
|
59
59
|
```
|
|
60
|
+
|
|
61
|
+
### Deriving with fieldless structs
|
|
62
|
+
|
|
63
|
+
In Move, structs with no user-defined fields automatically get a `dummy_field: bool` injected by the
|
|
64
|
+
compiler. This means their BCS encoding is not empty — it's a single `0x00` byte (the encoding of
|
|
65
|
+
`false`). You can treat this as a constant.
|
|
66
|
+
|
|
67
|
+
A real-world example is `0x2::coin_registry::CurrencyKey<T>`, which is a fieldless generic struct
|
|
68
|
+
used to derive `Currency` objects from the coin registry (`0xc`) based on their type:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
// On-chain: `public struct CurrencyKey<phantom T>() has copy, store, drop`
|
|
72
|
+
// The compiler injects `dummy_field: bool`, always `false`.
|
|
73
|
+
const key = new Uint8Array([0]);
|
|
74
|
+
|
|
75
|
+
const coinType = '0x2::sui::SUI';
|
|
76
|
+
const currencyId = deriveObjectID('0xc', `0x2::coin_registry::CurrencyKey<${coinType}>`, key);
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
This applies to any struct with no fields — phantom type parameters don't add any BCS-encoded data,
|
|
80
|
+
so the key is always `new Uint8Array([0])`.
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"author": "Mysten Labs <build@mystenlabs.com>",
|
|
4
4
|
"description": "Sui TypeScript API",
|
|
5
5
|
"homepage": "https://sdk.mystenlabs.com",
|
|
6
|
-
"version": "2.
|
|
6
|
+
"version": "2.12.0",
|
|
7
7
|
"license": "Apache-2.0",
|
|
8
8
|
"sideEffects": false,
|
|
9
9
|
"files": [
|
|
@@ -142,7 +142,6 @@
|
|
|
142
142
|
"@parcel/watcher": "^2.5.4",
|
|
143
143
|
"@types/node": "^25.0.8",
|
|
144
144
|
"@types/tmp": "^0.2.6",
|
|
145
|
-
"@types/ws": "^8.18.1",
|
|
146
145
|
"cross-env": "^10.1.0",
|
|
147
146
|
"graphql-config": "^5.1.5",
|
|
148
147
|
"msw": "^2.12.7",
|
|
@@ -152,8 +151,7 @@
|
|
|
152
151
|
"vite": "^7.3.1",
|
|
153
152
|
"vite-tsconfig-paths": "^6.0.4",
|
|
154
153
|
"vitest": "^4.0.17",
|
|
155
|
-
"wait-on": "^9.0.3"
|
|
156
|
-
"ws": "^8.19.0"
|
|
154
|
+
"wait-on": "^9.0.3"
|
|
157
155
|
},
|
|
158
156
|
"dependencies": {
|
|
159
157
|
"@graphql-typed-document-node/core": "^3.2.0",
|
package/src/client/types.ts
CHANGED
|
@@ -442,6 +442,14 @@ export namespace SuiClientTypes {
|
|
|
442
442
|
> extends CoreClientMethodOptions {
|
|
443
443
|
transaction: Uint8Array | TransactionInstance;
|
|
444
444
|
include?: Include & SimulateTransactionInclude;
|
|
445
|
+
/**
|
|
446
|
+
* When set to `false`, disables transaction validation checks during simulation.
|
|
447
|
+
* This allows inspecting non-public/non-entry Move functions and other transactions
|
|
448
|
+
* that would normally fail validation.
|
|
449
|
+
*
|
|
450
|
+
* Defaults to `true` (checks enabled).
|
|
451
|
+
*/
|
|
452
|
+
checksEnabled?: boolean;
|
|
445
453
|
}
|
|
446
454
|
|
|
447
455
|
export interface GetReferenceGasPriceOptions extends CoreClientMethodOptions {}
|
package/src/graphql/core.ts
CHANGED
|
@@ -406,6 +406,7 @@ export class GraphQLCoreClient extends CoreClient {
|
|
|
406
406
|
includeObjectTypes: options.include?.objectTypes ?? false,
|
|
407
407
|
includeCommandResults: options.include?.commandResults ?? false,
|
|
408
408
|
includeBcs: options.include?.bcs ?? false,
|
|
409
|
+
checksEnabled: options.checksEnabled ?? true,
|
|
409
410
|
},
|
|
410
411
|
},
|
|
411
412
|
(result) => result.simulateTransaction,
|
package/src/grpc/core.ts
CHANGED
|
@@ -44,6 +44,7 @@ import {
|
|
|
44
44
|
grpcTransactionToTransactionData,
|
|
45
45
|
} from '../client/transaction-resolver.js';
|
|
46
46
|
import { Value } from './proto/google/protobuf/struct.js';
|
|
47
|
+
import { SimulateTransactionRequest_TransactionChecks } from './proto/sui/rpc/v2/transaction_execution_service.js';
|
|
47
48
|
|
|
48
49
|
export interface GrpcCoreClientOptions extends CoreClientOptions {
|
|
49
50
|
client: SuiGrpcClient;
|
|
@@ -447,6 +448,10 @@ export class GrpcCoreClient extends CoreClient {
|
|
|
447
448
|
paths,
|
|
448
449
|
},
|
|
449
450
|
doGasSelection: false,
|
|
451
|
+
checks:
|
|
452
|
+
options.checksEnabled === false
|
|
453
|
+
? SimulateTransactionRequest_TransactionChecks.DISABLED
|
|
454
|
+
: SimulateTransactionRequest_TransactionChecks.ENABLED,
|
|
450
455
|
});
|
|
451
456
|
|
|
452
457
|
const transactionResult = parseTransaction(response.transaction!, options.include);
|
package/src/jsonRpc/core.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { fromBase64, type InferBcsInput } from '@mysten/bcs';
|
|
|
5
5
|
|
|
6
6
|
import { bcs, TypeTagSerializer } from '../bcs/index.js';
|
|
7
7
|
import type {
|
|
8
|
+
DevInspectResults,
|
|
9
|
+
DryRunTransactionBlockResponse,
|
|
8
10
|
ExecutionStatus as JsonRpcExecutionStatus,
|
|
9
11
|
ObjectOwner,
|
|
10
12
|
SuiMoveAbilitySet,
|
|
@@ -356,14 +358,44 @@ export class JSONRpcCoreClient extends CoreClient {
|
|
|
356
358
|
})
|
|
357
359
|
: (options.transaction as Uint8Array);
|
|
358
360
|
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
361
|
+
const sender = tx.getData().sender ?? normalizeSuiAddress('0x0');
|
|
362
|
+
const checksDisabled = options.checksEnabled === false;
|
|
363
|
+
|
|
364
|
+
let dryRunResult: DryRunTransactionBlockResponse | null = null;
|
|
365
|
+
try {
|
|
366
|
+
dryRunResult = await this.#jsonRpcClient.dryRunTransactionBlock({
|
|
367
|
+
transactionBlock: transactionBytes,
|
|
368
|
+
signal: options.signal,
|
|
369
|
+
});
|
|
370
|
+
} catch (e) {
|
|
371
|
+
if (!checksDisabled) {
|
|
372
|
+
throw e;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
let devInspectResult: DevInspectResults | null = null;
|
|
377
|
+
if (options.include?.commandResults || checksDisabled) {
|
|
378
|
+
try {
|
|
379
|
+
devInspectResult = await this.#jsonRpcClient.devInspectTransactionBlock({
|
|
380
|
+
sender,
|
|
381
|
+
transactionBlock: tx,
|
|
382
|
+
signal: options.signal,
|
|
383
|
+
});
|
|
384
|
+
} catch {}
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const dryRunFailed = !dryRunResult || dryRunResult.effects.status.status !== 'success';
|
|
388
|
+
const effectsSource =
|
|
389
|
+
checksDisabled && dryRunFailed && devInspectResult
|
|
390
|
+
? devInspectResult
|
|
391
|
+
: (dryRunResult ?? devInspectResult);
|
|
392
|
+
if (!effectsSource) {
|
|
393
|
+
throw new Error('simulateTransaction failed: no results from dryRun or devInspect');
|
|
394
|
+
}
|
|
363
395
|
|
|
364
396
|
const { effects, objectTypes } = parseTransactionEffectsJson({
|
|
365
|
-
effects:
|
|
366
|
-
objectChanges:
|
|
397
|
+
effects: effectsSource.effects,
|
|
398
|
+
objectChanges: dryRunResult?.objectChanges ?? [],
|
|
367
399
|
});
|
|
368
400
|
|
|
369
401
|
const transactionData: SuiClientTypes.Transaction<Include> = {
|
|
@@ -391,15 +423,15 @@ export class JSONRpcCoreClient extends CoreClient {
|
|
|
391
423
|
bcs: (options.include?.bcs
|
|
392
424
|
? transactionBytes
|
|
393
425
|
: undefined) as SuiClientTypes.Transaction<Include>['bcs'],
|
|
394
|
-
balanceChanges: (options.include?.balanceChanges
|
|
395
|
-
?
|
|
426
|
+
balanceChanges: (options.include?.balanceChanges && dryRunResult
|
|
427
|
+
? dryRunResult.balanceChanges.map((change) => ({
|
|
396
428
|
coinType: normalizeStructTag(change.coinType),
|
|
397
429
|
address: parseOwnerAddress(change.owner)!,
|
|
398
430
|
amount: change.amount,
|
|
399
431
|
}))
|
|
400
432
|
: undefined) as SuiClientTypes.Transaction<Include>['balanceChanges'],
|
|
401
433
|
events: (options.include?.events
|
|
402
|
-
? (
|
|
434
|
+
? (effectsSource.events?.map((event) => ({
|
|
403
435
|
packageId: event.packageId,
|
|
404
436
|
module: event.transactionModule,
|
|
405
437
|
sender: event.sender,
|
|
@@ -411,26 +443,15 @@ export class JSONRpcCoreClient extends CoreClient {
|
|
|
411
443
|
};
|
|
412
444
|
|
|
413
445
|
let commandResults: SuiClientTypes.CommandResult[] | undefined;
|
|
414
|
-
if (options.include?.commandResults) {
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
})
|
|
422
|
-
|
|
423
|
-
if (devInspectResult.results) {
|
|
424
|
-
commandResults = devInspectResult.results.map((result) => ({
|
|
425
|
-
returnValues: (result.returnValues ?? []).map(([bytes]) => ({
|
|
426
|
-
bcs: new Uint8Array(bytes),
|
|
427
|
-
})),
|
|
428
|
-
mutatedReferences: (result.mutableReferenceOutputs ?? []).map(([, bytes]) => ({
|
|
429
|
-
bcs: new Uint8Array(bytes),
|
|
430
|
-
})),
|
|
431
|
-
}));
|
|
432
|
-
}
|
|
433
|
-
} catch {}
|
|
446
|
+
if (options.include?.commandResults && devInspectResult?.results) {
|
|
447
|
+
commandResults = devInspectResult.results.map((result) => ({
|
|
448
|
+
returnValues: (result.returnValues ?? []).map(([bytes]) => ({
|
|
449
|
+
bcs: new Uint8Array(bytes),
|
|
450
|
+
})),
|
|
451
|
+
mutatedReferences: (result.mutableReferenceOutputs ?? []).map(([, bytes]) => ({
|
|
452
|
+
bcs: new Uint8Array(bytes),
|
|
453
|
+
})),
|
|
454
|
+
}));
|
|
434
455
|
}
|
|
435
456
|
|
|
436
457
|
return effects.status.success
|
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
|
|
4
4
|
import { PACKAGE_VERSION, TARGETED_RPC_VERSION } from '../version.js';
|
|
5
5
|
import { JsonRpcError, SuiHTTPStatusError } from './errors.js';
|
|
6
|
-
import type { WebsocketClientOptions } from './rpc-websocket-client.js';
|
|
7
|
-
import { WebsocketClient } from './rpc-websocket-client.js';
|
|
8
6
|
|
|
9
7
|
/**
|
|
10
8
|
* An object defining headers to be passed to the RPC server
|
|
@@ -13,15 +11,11 @@ export type HttpHeaders = { [header: string]: string };
|
|
|
13
11
|
|
|
14
12
|
export interface JsonRpcHTTPTransportOptions {
|
|
15
13
|
fetch?: typeof fetch;
|
|
16
|
-
WebSocketConstructor?: typeof WebSocket;
|
|
17
14
|
url: string;
|
|
18
15
|
rpc?: {
|
|
19
16
|
headers?: HttpHeaders;
|
|
20
17
|
url?: string;
|
|
21
18
|
};
|
|
22
|
-
websocket?: WebsocketClientOptions & {
|
|
23
|
-
url?: string;
|
|
24
|
-
};
|
|
25
19
|
}
|
|
26
20
|
|
|
27
21
|
export interface JsonRpcTransportRequestOptions {
|
|
@@ -30,25 +24,13 @@ export interface JsonRpcTransportRequestOptions {
|
|
|
30
24
|
signal?: AbortSignal;
|
|
31
25
|
}
|
|
32
26
|
|
|
33
|
-
export interface JsonRpcTransportSubscribeOptions<T> {
|
|
34
|
-
method: string;
|
|
35
|
-
unsubscribe: string;
|
|
36
|
-
params: unknown[];
|
|
37
|
-
onMessage: (event: T) => void;
|
|
38
|
-
signal?: AbortSignal;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
27
|
export interface JsonRpcTransport {
|
|
42
28
|
request<T = unknown>(input: JsonRpcTransportRequestOptions): Promise<T>;
|
|
43
|
-
subscribe<T = unknown>(
|
|
44
|
-
input: JsonRpcTransportSubscribeOptions<T>,
|
|
45
|
-
): Promise<() => Promise<boolean>>;
|
|
46
29
|
}
|
|
47
30
|
|
|
48
31
|
export class JsonRpcHTTPTransport implements JsonRpcTransport {
|
|
49
32
|
#requestId = 0;
|
|
50
33
|
#options: JsonRpcHTTPTransportOptions;
|
|
51
|
-
#websocketClient?: WebsocketClient;
|
|
52
34
|
|
|
53
35
|
constructor(options: JsonRpcHTTPTransportOptions) {
|
|
54
36
|
this.#options = options;
|
|
@@ -66,27 +48,6 @@ export class JsonRpcHTTPTransport implements JsonRpcTransport {
|
|
|
66
48
|
return fetchFn(input, init);
|
|
67
49
|
}
|
|
68
50
|
|
|
69
|
-
#getWebsocketClient(): WebsocketClient {
|
|
70
|
-
if (!this.#websocketClient) {
|
|
71
|
-
const WebSocketConstructor = this.#options.WebSocketConstructor ?? WebSocket;
|
|
72
|
-
if (!WebSocketConstructor) {
|
|
73
|
-
throw new Error(
|
|
74
|
-
'The current environment does not support WebSocket, you can provide a WebSocketConstructor in the options for SuiHTTPTransport.',
|
|
75
|
-
);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
this.#websocketClient = new WebsocketClient(
|
|
79
|
-
this.#options.websocket?.url ?? this.#options.url,
|
|
80
|
-
{
|
|
81
|
-
WebSocketConstructor,
|
|
82
|
-
...this.#options.websocket,
|
|
83
|
-
},
|
|
84
|
-
);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
return this.#websocketClient;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
51
|
async request<T>(input: JsonRpcTransportRequestOptions): Promise<T> {
|
|
91
52
|
this.#requestId += 1;
|
|
92
53
|
|
|
@@ -125,17 +86,4 @@ export class JsonRpcHTTPTransport implements JsonRpcTransport {
|
|
|
125
86
|
|
|
126
87
|
return data.result;
|
|
127
88
|
}
|
|
128
|
-
|
|
129
|
-
async subscribe<T>(input: JsonRpcTransportSubscribeOptions<T>): Promise<() => Promise<boolean>> {
|
|
130
|
-
const unsubscribe = await this.#getWebsocketClient().subscribe(input);
|
|
131
|
-
|
|
132
|
-
if (input.signal) {
|
|
133
|
-
input.signal.throwIfAborted();
|
|
134
|
-
input.signal.addEventListener('abort', () => {
|
|
135
|
-
unsubscribe();
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return async () => !!(await unsubscribe());
|
|
140
|
-
}
|
|
141
89
|
}
|
package/src/jsonRpc/index.ts
CHANGED
package/src/version.ts
CHANGED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
//#region src/jsonRpc/rpc-websocket-client.d.ts
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Configuration options for the websocket connection
|
|
5
|
-
*/
|
|
6
|
-
type WebsocketClientOptions = {
|
|
7
|
-
/**
|
|
8
|
-
* Custom WebSocket class to use. Defaults to the global WebSocket class, if available.
|
|
9
|
-
*/
|
|
10
|
-
WebSocketConstructor?: typeof WebSocket;
|
|
11
|
-
/**
|
|
12
|
-
* Milliseconds before timing out while calling an RPC method
|
|
13
|
-
*/
|
|
14
|
-
callTimeout?: number;
|
|
15
|
-
/**
|
|
16
|
-
* Milliseconds between attempts to connect
|
|
17
|
-
*/
|
|
18
|
-
reconnectTimeout?: number;
|
|
19
|
-
/**
|
|
20
|
-
* Maximum number of times to try connecting before giving up
|
|
21
|
-
*/
|
|
22
|
-
maxReconnects?: number;
|
|
23
|
-
};
|
|
24
|
-
//#endregion
|
|
25
|
-
export { WebsocketClientOptions };
|
|
26
|
-
//# sourceMappingURL=rpc-websocket-client.d.mts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-websocket-client.d.mts","names":[],"sources":["../../src/jsonRpc/rpc-websocket-client.ts"],"sourcesContent":[],"mappings":";;;;;KA8CY,sBAAA;;;;gCAImB"}
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { JsonRpcError } from "./errors.mjs";
|
|
2
|
-
|
|
3
|
-
//#region src/jsonRpc/rpc-websocket-client.ts
|
|
4
|
-
function getWebsocketUrl(httpUrl) {
|
|
5
|
-
const url = new URL(httpUrl);
|
|
6
|
-
url.protocol = url.protocol.replace("http", "ws");
|
|
7
|
-
return url.toString();
|
|
8
|
-
}
|
|
9
|
-
const DEFAULT_CLIENT_OPTIONS = {
|
|
10
|
-
WebSocketConstructor: typeof WebSocket !== "undefined" ? WebSocket : void 0,
|
|
11
|
-
callTimeout: 3e4,
|
|
12
|
-
reconnectTimeout: 3e3,
|
|
13
|
-
maxReconnects: 5
|
|
14
|
-
};
|
|
15
|
-
var WebsocketClient = class {
|
|
16
|
-
#requestId = 0;
|
|
17
|
-
#disconnects = 0;
|
|
18
|
-
#webSocket = null;
|
|
19
|
-
#connectionPromise = null;
|
|
20
|
-
#subscriptions = /* @__PURE__ */ new Set();
|
|
21
|
-
#pendingRequests = /* @__PURE__ */ new Map();
|
|
22
|
-
constructor(endpoint, options = {}) {
|
|
23
|
-
this.endpoint = endpoint;
|
|
24
|
-
this.options = {
|
|
25
|
-
...DEFAULT_CLIENT_OPTIONS,
|
|
26
|
-
...options
|
|
27
|
-
};
|
|
28
|
-
if (!this.options.WebSocketConstructor) throw new Error("Missing WebSocket constructor");
|
|
29
|
-
if (this.endpoint.startsWith("http")) this.endpoint = getWebsocketUrl(this.endpoint);
|
|
30
|
-
}
|
|
31
|
-
async makeRequest(method, params, signal) {
|
|
32
|
-
const webSocket = await this.#setupWebSocket();
|
|
33
|
-
return new Promise((resolve, reject) => {
|
|
34
|
-
this.#requestId += 1;
|
|
35
|
-
this.#pendingRequests.set(this.#requestId, {
|
|
36
|
-
resolve,
|
|
37
|
-
reject,
|
|
38
|
-
timeout: setTimeout(() => {
|
|
39
|
-
this.#pendingRequests.delete(this.#requestId);
|
|
40
|
-
reject(/* @__PURE__ */ new Error(`Request timeout: ${method}`));
|
|
41
|
-
}, this.options.callTimeout)
|
|
42
|
-
});
|
|
43
|
-
signal?.addEventListener("abort", () => {
|
|
44
|
-
this.#pendingRequests.delete(this.#requestId);
|
|
45
|
-
reject(signal.reason);
|
|
46
|
-
});
|
|
47
|
-
webSocket.send(JSON.stringify({
|
|
48
|
-
jsonrpc: "2.0",
|
|
49
|
-
id: this.#requestId,
|
|
50
|
-
method,
|
|
51
|
-
params
|
|
52
|
-
}));
|
|
53
|
-
}).then(({ error, result }) => {
|
|
54
|
-
if (error) throw new JsonRpcError(error.message, error.code);
|
|
55
|
-
return result;
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
#setupWebSocket() {
|
|
59
|
-
if (this.#connectionPromise) return this.#connectionPromise;
|
|
60
|
-
this.#connectionPromise = new Promise((resolve) => {
|
|
61
|
-
this.#webSocket?.close();
|
|
62
|
-
this.#webSocket = new this.options.WebSocketConstructor(this.endpoint);
|
|
63
|
-
this.#webSocket.addEventListener("open", () => {
|
|
64
|
-
this.#disconnects = 0;
|
|
65
|
-
resolve(this.#webSocket);
|
|
66
|
-
});
|
|
67
|
-
this.#webSocket.addEventListener("close", () => {
|
|
68
|
-
this.#disconnects++;
|
|
69
|
-
if (this.#disconnects <= this.options.maxReconnects) setTimeout(() => {
|
|
70
|
-
this.#reconnect();
|
|
71
|
-
}, this.options.reconnectTimeout);
|
|
72
|
-
});
|
|
73
|
-
this.#webSocket.addEventListener("message", ({ data }) => {
|
|
74
|
-
let json;
|
|
75
|
-
try {
|
|
76
|
-
json = JSON.parse(data);
|
|
77
|
-
} catch (error) {
|
|
78
|
-
console.error(new Error(`Failed to parse RPC message: ${data}`, { cause: error }));
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
if ("id" in json && json.id != null && this.#pendingRequests.has(json.id)) {
|
|
82
|
-
const { resolve: resolve$1, timeout } = this.#pendingRequests.get(json.id);
|
|
83
|
-
clearTimeout(timeout);
|
|
84
|
-
resolve$1(json);
|
|
85
|
-
} else if ("params" in json) {
|
|
86
|
-
const { params } = json;
|
|
87
|
-
this.#subscriptions.forEach((subscription) => {
|
|
88
|
-
if (subscription.subscriptionId === params.subscription) {
|
|
89
|
-
if (params.subscription === subscription.subscriptionId) subscription.onMessage(params.result);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
return this.#connectionPromise;
|
|
96
|
-
}
|
|
97
|
-
async #reconnect() {
|
|
98
|
-
this.#webSocket?.close();
|
|
99
|
-
this.#connectionPromise = null;
|
|
100
|
-
return Promise.allSettled([...this.#subscriptions].map((subscription) => subscription.subscribe(this)));
|
|
101
|
-
}
|
|
102
|
-
async subscribe(input) {
|
|
103
|
-
const subscription = new RpcSubscription(input);
|
|
104
|
-
this.#subscriptions.add(subscription);
|
|
105
|
-
await subscription.subscribe(this);
|
|
106
|
-
return () => subscription.unsubscribe(this);
|
|
107
|
-
}
|
|
108
|
-
};
|
|
109
|
-
var RpcSubscription = class {
|
|
110
|
-
constructor(input) {
|
|
111
|
-
this.subscriptionId = null;
|
|
112
|
-
this.subscribed = false;
|
|
113
|
-
this.input = input;
|
|
114
|
-
}
|
|
115
|
-
onMessage(message) {
|
|
116
|
-
if (this.subscribed) this.input.onMessage(message);
|
|
117
|
-
}
|
|
118
|
-
async unsubscribe(client) {
|
|
119
|
-
const { subscriptionId } = this;
|
|
120
|
-
this.subscribed = false;
|
|
121
|
-
if (subscriptionId == null) return false;
|
|
122
|
-
this.subscriptionId = null;
|
|
123
|
-
return client.makeRequest(this.input.unsubscribe, [subscriptionId]);
|
|
124
|
-
}
|
|
125
|
-
async subscribe(client) {
|
|
126
|
-
this.subscriptionId = null;
|
|
127
|
-
this.subscribed = true;
|
|
128
|
-
const newSubscriptionId = await client.makeRequest(this.input.method, this.input.params, this.input.signal);
|
|
129
|
-
if (this.subscribed) this.subscriptionId = newSubscriptionId;
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
|
-
|
|
133
|
-
//#endregion
|
|
134
|
-
export { WebsocketClient };
|
|
135
|
-
//# sourceMappingURL=rpc-websocket-client.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rpc-websocket-client.mjs","names":["#setupWebSocket","#requestId","#pendingRequests","#connectionPromise","#webSocket","#disconnects","#reconnect","#subscriptions"],"sources":["../../src/jsonRpc/rpc-websocket-client.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { JsonRpcError } from './errors.js';\n\nfunction getWebsocketUrl(httpUrl: string): string {\n\tconst url = new URL(httpUrl);\n\turl.protocol = url.protocol.replace('http', 'ws');\n\treturn url.toString();\n}\n\ntype JsonRpcMessage =\n\t| {\n\t\t\tid: number;\n\t\t\tresult: never;\n\t\t\terror: {\n\t\t\t\tcode: number;\n\t\t\t\tmessage: string;\n\t\t\t};\n\t }\n\t| {\n\t\t\tid: number;\n\t\t\tresult: unknown;\n\t\t\terror: never;\n\t }\n\t| {\n\t\t\tmethod: string;\n\t\t\tparams: NotificationMessageParams;\n\t };\n\ntype NotificationMessageParams = {\n\tsubscription?: number;\n\tresult: object;\n};\n\ntype SubscriptionRequest<T = any> = {\n\tmethod: string;\n\tunsubscribe: string;\n\tparams: any[];\n\tonMessage: (event: T) => void;\n\tsignal?: AbortSignal;\n};\n\n/**\n * Configuration options for the websocket connection\n */\nexport type WebsocketClientOptions = {\n\t/**\n\t * Custom WebSocket class to use. Defaults to the global WebSocket class, if available.\n\t */\n\tWebSocketConstructor?: typeof WebSocket;\n\t/**\n\t * Milliseconds before timing out while calling an RPC method\n\t */\n\tcallTimeout?: number;\n\t/**\n\t * Milliseconds between attempts to connect\n\t */\n\treconnectTimeout?: number;\n\t/**\n\t * Maximum number of times to try connecting before giving up\n\t */\n\tmaxReconnects?: number;\n};\n\nexport const DEFAULT_CLIENT_OPTIONS = {\n\t// We fudge the typing because we also check for undefined in the constructor:\n\tWebSocketConstructor: (typeof WebSocket !== 'undefined'\n\t\t? WebSocket\n\t\t: undefined) as typeof WebSocket,\n\tcallTimeout: 30000,\n\treconnectTimeout: 3000,\n\tmaxReconnects: 5,\n} satisfies WebsocketClientOptions;\n\nexport class WebsocketClient {\n\tendpoint: string;\n\toptions: Required<WebsocketClientOptions>;\n\t#requestId = 0;\n\t#disconnects = 0;\n\t#webSocket: WebSocket | null = null;\n\t#connectionPromise: Promise<WebSocket> | null = null;\n\t#subscriptions = new Set<RpcSubscription>();\n\t#pendingRequests = new Map<\n\t\tnumber,\n\t\t{\n\t\t\tresolve: (result: Extract<JsonRpcMessage, { id: number }>) => void;\n\t\t\treject: (reason: unknown) => void;\n\t\t\ttimeout: ReturnType<typeof setTimeout>;\n\t\t}\n\t>();\n\n\tconstructor(endpoint: string, options: WebsocketClientOptions = {}) {\n\t\tthis.endpoint = endpoint;\n\t\tthis.options = { ...DEFAULT_CLIENT_OPTIONS, ...options };\n\n\t\tif (!this.options.WebSocketConstructor) {\n\t\t\tthrow new Error('Missing WebSocket constructor');\n\t\t}\n\n\t\tif (this.endpoint.startsWith('http')) {\n\t\t\tthis.endpoint = getWebsocketUrl(this.endpoint);\n\t\t}\n\t}\n\n\tasync makeRequest<T>(method: string, params: any[], signal?: AbortSignal): Promise<T> {\n\t\tconst webSocket = await this.#setupWebSocket();\n\n\t\treturn new Promise<Extract<JsonRpcMessage, { id: number }>>((resolve, reject) => {\n\t\t\tthis.#requestId += 1;\n\t\t\tthis.#pendingRequests.set(this.#requestId, {\n\t\t\t\tresolve: resolve,\n\t\t\t\treject,\n\t\t\t\ttimeout: setTimeout(() => {\n\t\t\t\t\tthis.#pendingRequests.delete(this.#requestId);\n\t\t\t\t\treject(new Error(`Request timeout: ${method}`));\n\t\t\t\t}, this.options.callTimeout),\n\t\t\t});\n\n\t\t\tsignal?.addEventListener('abort', () => {\n\t\t\t\tthis.#pendingRequests.delete(this.#requestId);\n\t\t\t\treject(signal.reason);\n\t\t\t});\n\n\t\t\twebSocket.send(JSON.stringify({ jsonrpc: '2.0', id: this.#requestId, method, params }));\n\t\t}).then(({ error, result }) => {\n\t\t\tif (error) {\n\t\t\t\tthrow new JsonRpcError(error.message, error.code);\n\t\t\t}\n\n\t\t\treturn result as T;\n\t\t});\n\t}\n\n\t#setupWebSocket() {\n\t\tif (this.#connectionPromise) {\n\t\t\treturn this.#connectionPromise;\n\t\t}\n\n\t\tthis.#connectionPromise = new Promise<WebSocket>((resolve) => {\n\t\t\tthis.#webSocket?.close();\n\t\t\tthis.#webSocket = new this.options.WebSocketConstructor(this.endpoint);\n\n\t\t\tthis.#webSocket.addEventListener('open', () => {\n\t\t\t\tthis.#disconnects = 0;\n\t\t\t\tresolve(this.#webSocket!);\n\t\t\t});\n\n\t\t\tthis.#webSocket.addEventListener('close', () => {\n\t\t\t\tthis.#disconnects++;\n\t\t\t\tif (this.#disconnects <= this.options.maxReconnects) {\n\t\t\t\t\tsetTimeout(() => {\n\t\t\t\t\t\tthis.#reconnect();\n\t\t\t\t\t}, this.options.reconnectTimeout);\n\t\t\t\t}\n\t\t\t});\n\n\t\t\tthis.#webSocket.addEventListener('message', ({ data }: { data: string }) => {\n\t\t\t\tlet json: JsonRpcMessage;\n\t\t\t\ttry {\n\t\t\t\t\tjson = JSON.parse(data) as JsonRpcMessage;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tconsole.error(new Error(`Failed to parse RPC message: ${data}`, { cause: error }));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif ('id' in json && json.id != null && this.#pendingRequests.has(json.id)) {\n\t\t\t\t\tconst { resolve, timeout } = this.#pendingRequests.get(json.id)!;\n\n\t\t\t\t\tclearTimeout(timeout);\n\t\t\t\t\tresolve(json);\n\t\t\t\t} else if ('params' in json) {\n\t\t\t\t\tconst { params } = json;\n\t\t\t\t\tthis.#subscriptions.forEach((subscription) => {\n\t\t\t\t\t\tif (subscription.subscriptionId === params.subscription)\n\t\t\t\t\t\t\tif (params.subscription === subscription.subscriptionId) {\n\t\t\t\t\t\t\t\tsubscription.onMessage(params.result);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t});\n\t\t});\n\n\t\treturn this.#connectionPromise;\n\t}\n\n\tasync #reconnect() {\n\t\tthis.#webSocket?.close();\n\t\tthis.#connectionPromise = null;\n\n\t\treturn Promise.allSettled(\n\t\t\t[...this.#subscriptions].map((subscription) => subscription.subscribe(this)),\n\t\t);\n\t}\n\n\tasync subscribe<T>(input: SubscriptionRequest<T>) {\n\t\tconst subscription = new RpcSubscription(input);\n\t\tthis.#subscriptions.add(subscription);\n\t\tawait subscription.subscribe(this);\n\t\treturn () => subscription.unsubscribe(this);\n\t}\n}\n\nclass RpcSubscription {\n\tsubscriptionId: number | null = null;\n\tinput: SubscriptionRequest<any>;\n\tsubscribed = false;\n\n\tconstructor(input: SubscriptionRequest) {\n\t\tthis.input = input;\n\t}\n\n\tonMessage(message: unknown) {\n\t\tif (this.subscribed) {\n\t\t\tthis.input.onMessage(message);\n\t\t}\n\t}\n\n\tasync unsubscribe(client: WebsocketClient) {\n\t\tconst { subscriptionId } = this;\n\t\tthis.subscribed = false;\n\t\tif (subscriptionId == null) return false;\n\t\tthis.subscriptionId = null;\n\n\t\treturn client.makeRequest(this.input.unsubscribe, [subscriptionId]);\n\t}\n\n\tasync subscribe(client: WebsocketClient) {\n\t\tthis.subscriptionId = null;\n\t\tthis.subscribed = true;\n\t\tconst newSubscriptionId = await client.makeRequest<number>(\n\t\t\tthis.input.method,\n\t\t\tthis.input.params,\n\t\t\tthis.input.signal,\n\t\t);\n\n\t\tif (this.subscribed) {\n\t\t\tthis.subscriptionId = newSubscriptionId;\n\t\t}\n\t}\n}\n"],"mappings":"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"}
|