@fizzyflow/endless-vector 0.0.3 → 0.0.5
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/EndlessVector.js +136 -24
- package/README.md +9 -11
- package/ids.js +4 -4
- package/index.d.ts +347 -0
- package/package.json +3 -2
- package/test/base.test.js +80 -14
package/EndlessVector.js
CHANGED
|
@@ -8,6 +8,7 @@ import ids from './ids.js';
|
|
|
8
8
|
* @typedef {import('@mysten/sui/client').SuiClient} SuiClient
|
|
9
9
|
* @typedef {import('@mysten/sui/client').GetObjectParams} GetObjectParams
|
|
10
10
|
* @typedef {import('@mysten/sui/client').GetDynamicFieldsParams} GetDynamicFieldsParams
|
|
11
|
+
* @typedef {import('@mysten/sui/transactions').TransactionResult} TransactionResult
|
|
11
12
|
*/
|
|
12
13
|
|
|
13
14
|
/**
|
|
@@ -94,7 +95,7 @@ export default class EndlessVector {
|
|
|
94
95
|
* @param {SuiClient} params.suiClient - Sui client instance for blockchain interactions
|
|
95
96
|
* @param {string} params.packageId - ID of the Move package containing the EndlessVector module
|
|
96
97
|
* @param {CustomSignAndExecuteTransactionFunction} params.signAndExecuteTransaction - Function to sign and execute transactions
|
|
97
|
-
* @param {?
|
|
98
|
+
* @param {?Uint8Array|Uint8Array[]} [params.array] - Optional Uint8Array to initialize the vector with as the first item to get with .at(0)
|
|
98
99
|
* @param {?Object} [params.gasCoin] - Optional gas coin object reference {objectId: string, digest: string, version: string} to use for transaction payment
|
|
99
100
|
* @param {?Object} [params.options] - Optional transaction parameters
|
|
100
101
|
* @param {?Number} [params.options.timeout] - Transaction confirmation timeout in ms, default 30000
|
|
@@ -103,7 +104,7 @@ export default class EndlessVector {
|
|
|
103
104
|
* @throws {Error} If the transaction fails or no EndlessVector object is created
|
|
104
105
|
*/
|
|
105
106
|
static async create(params) {
|
|
106
|
-
const { suiClient, packageId, signAndExecuteTransaction,
|
|
107
|
+
const { suiClient, packageId, signAndExecuteTransaction, array, gasCoin, options = {} } = params;
|
|
107
108
|
|
|
108
109
|
let normalizedPackageId = packageId;
|
|
109
110
|
if (normalizedPackageId == 'mainnet' || (!normalizedPackageId && suiClient?.network == 'mainnet')) {
|
|
@@ -129,11 +130,31 @@ export default class EndlessVector {
|
|
|
129
130
|
tx.setGasPayment([gasCoin]);
|
|
130
131
|
}
|
|
131
132
|
|
|
132
|
-
if (
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
133
|
+
if (array && array.length) {
|
|
134
|
+
if ((array instanceof Uint8Array)) {
|
|
135
|
+
// single chunk
|
|
136
|
+
const vectorInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
137
|
+
packageId: normalizedPackageId,
|
|
138
|
+
}, array, tx);
|
|
139
|
+
tx.moveCall({
|
|
140
|
+
target: `${normalizedPackageId}::endless_vector::transfer_to_sender`,
|
|
141
|
+
arguments: [vectorInput],
|
|
142
|
+
});
|
|
143
|
+
} else if (array[0] && (array[0] instanceof Uint8Array)) {
|
|
144
|
+
// multiple chunks
|
|
145
|
+
const vectorInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
146
|
+
packageId: normalizedPackageId,
|
|
147
|
+
}, null, tx);
|
|
148
|
+
for (let i = 0; i < array.length; i++) {
|
|
149
|
+
EndlessVector.composePushTransaction(normalizedPackageId, vectorInput, array[i], tx);
|
|
150
|
+
}
|
|
151
|
+
tx.moveCall({
|
|
152
|
+
target: `${normalizedPackageId}::endless_vector::transfer_to_sender`,
|
|
153
|
+
arguments: [vectorInput],
|
|
154
|
+
});
|
|
155
|
+
} else {
|
|
156
|
+
throw new Error('.array must be Uint8Array or array of Uint8Array');
|
|
157
|
+
}
|
|
137
158
|
} else {
|
|
138
159
|
tx.moveCall({
|
|
139
160
|
target: `${normalizedPackageId}::endless_vector::empty_entry`,
|
|
@@ -180,33 +201,92 @@ export default class EndlessVector {
|
|
|
180
201
|
});
|
|
181
202
|
}
|
|
182
203
|
|
|
183
|
-
get isWritable() {
|
|
184
|
-
return !!(this._packageId && this._signAndExecuteTransaction);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
204
|
/**
|
|
188
|
-
|
|
189
|
-
|
|
205
|
+
* Creates an empty EndlessVector and returns the vector input reference.
|
|
206
|
+
* Appends vector creation to existing transaction or makes new one.
|
|
207
|
+
*
|
|
208
|
+
* Returns the vector input reference for use in subsequent move calls as argument or to be transferred.
|
|
209
|
+
*
|
|
210
|
+
* @param {Object} params - Configuration parameters
|
|
211
|
+
* @param {string} params.packageId - The package ID ('mainnet', 'testnet', or explicit package ID)
|
|
212
|
+
* @param {Uint8Array|null} [arr=null] - Optional Uint8Array to push back to the new vector as the first item
|
|
213
|
+
* @param {Transaction|null} [txToAppendTo=null] - Optional existing transaction to append the move calls to
|
|
214
|
+
* @returns {Promise<TransactionResult>} Vector input reference for use in subsequent move calls
|
|
215
|
+
* @throws {Error} Throws if packageId is not provided or invalid
|
|
216
|
+
*
|
|
217
|
+
* @example
|
|
218
|
+
* // Create an empty vector
|
|
219
|
+
* const vectorInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
220
|
+
* packageId: 'mainnet'
|
|
221
|
+
* });
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* // Create and populate a vector within an existing transaction
|
|
225
|
+
* const data = new Uint8Array([1, 2, 3, 4]);
|
|
226
|
+
* const tx = new Transaction();
|
|
227
|
+
* const vectorInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
228
|
+
* packageId: contract.id
|
|
229
|
+
* }, data, tx);
|
|
230
|
+
*/
|
|
231
|
+
static async getCreateTransactionAndReturnVectorInput(params, arr = null, txToAppendTo = null) {
|
|
232
|
+
const { packageId } = params;
|
|
233
|
+
let normalizedPackageId = packageId;
|
|
234
|
+
if (normalizedPackageId == 'mainnet') {
|
|
235
|
+
normalizedPackageId = ids['mainnet'].packageId;
|
|
236
|
+
} else if (normalizedPackageId == 'testnet') {
|
|
237
|
+
normalizedPackageId = ids['testnet'].packageId;
|
|
238
|
+
}
|
|
190
239
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
*/
|
|
194
|
-
getPushTransaction(arr, txToAppendTo = null) {
|
|
195
|
-
if (!this._packageId) {
|
|
196
|
-
throw new Error('packageId is required to compose push transaction');
|
|
240
|
+
if (!normalizedPackageId) {
|
|
241
|
+
throw new Error('packageId is required');
|
|
197
242
|
}
|
|
243
|
+
// Create transaction to call empty_entry
|
|
198
244
|
|
|
199
245
|
let tx = txToAppendTo;
|
|
200
246
|
if (!tx) {
|
|
201
247
|
tx = new Transaction();
|
|
202
248
|
}
|
|
203
249
|
|
|
250
|
+
const vectorInput = tx.moveCall({
|
|
251
|
+
target: `${normalizedPackageId}::endless_vector::empty`,
|
|
252
|
+
arguments: [],
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
if (arr && arr) {
|
|
256
|
+
EndlessVector.composePushTransaction(normalizedPackageId, vectorInput, arr, tx);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return vectorInput;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
get isWritable() {
|
|
263
|
+
return !!(this._packageId && this._signAndExecuteTransaction);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Attach move calls to transaction, to push item into endlessvector, handling large arrays by chunking them.
|
|
268
|
+
* This static method can be used to compose transactions for any existing EndlessVector instance:
|
|
269
|
+
* tx.object(vector.id)
|
|
270
|
+
* or newly created one, accepting TransactionResult as vectorInput, see: getCreateTransactionAndReturnVectorInput
|
|
271
|
+
*
|
|
272
|
+
* For arrays smaller than 12KB, it uses a single push_back call.
|
|
273
|
+
* For arrays between 12KB and 120KB, it splits the data into 10 chunks and uses compose_and_push_back.
|
|
274
|
+
*
|
|
275
|
+
* @static
|
|
276
|
+
* @param {string} packageId - The package ID of the Move module containing the endless_vector functions
|
|
277
|
+
* @param {TransactionObjectArgument} vectorInput - The transaction object argument representing the EndlessVector
|
|
278
|
+
* @param {Uint8Array} arr - The byte array to push to the vector
|
|
279
|
+
* @param {Transaction} tx - The transaction object to append the move calls to
|
|
280
|
+
* @returns {Transaction} The transaction object with the push operations added
|
|
281
|
+
* @throws {Error} If the array is larger than 120KB (10 * 12KB)
|
|
282
|
+
*/
|
|
283
|
+
static composePushTransaction(packageId, vectorInput, arr, tx) {
|
|
204
284
|
const maxArgLength = 12 * 1024;
|
|
205
285
|
if (arr.length < maxArgLength) {
|
|
206
286
|
tx.moveCall({
|
|
207
|
-
target: `${
|
|
287
|
+
target: `${packageId}::endless_vector::push_back`,
|
|
208
288
|
arguments: [
|
|
209
|
-
|
|
289
|
+
vectorInput,
|
|
210
290
|
tx.pure(bcs.vector(bcs.u8()).serialize(arr)),
|
|
211
291
|
],
|
|
212
292
|
});
|
|
@@ -223,17 +303,49 @@ export default class EndlessVector {
|
|
|
223
303
|
chunks.push(new Uint8Array()); // empty chunk
|
|
224
304
|
}
|
|
225
305
|
}
|
|
226
|
-
const args = [
|
|
306
|
+
const args = [vectorInput];
|
|
227
307
|
for (let i = 0; i < N; i++) {
|
|
228
308
|
args.push(tx.pure(bcs.vector(bcs.u8()).serialize(chunks[i])));
|
|
229
309
|
}
|
|
230
310
|
tx.moveCall({
|
|
231
|
-
target: `${
|
|
311
|
+
target: `${packageId}::endless_vector::compose_and_push_back`,
|
|
232
312
|
arguments: args,
|
|
233
313
|
});
|
|
234
314
|
} else {
|
|
235
315
|
throw new Error('Array too large, max '+(10*maxArgLength)+' bytes supported per single tx');
|
|
236
316
|
}
|
|
317
|
+
|
|
318
|
+
return tx;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Creates a transaction to push new byte arrays to the EndlessVector.
|
|
324
|
+
* Note: this method only creates the transaction, it does not sign or execute it.
|
|
325
|
+
|
|
326
|
+
* @param {Uint8Array|Uint8Array[]} arr - Uint8Array to push
|
|
327
|
+
* @returns {Transaction} The transaction object to be signed and executed
|
|
328
|
+
*/
|
|
329
|
+
getPushTransaction(arr, txToAppendTo = null) {
|
|
330
|
+
if (!this._packageId) {
|
|
331
|
+
throw new Error('packageId is required to compose push transaction');
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
let tx = txToAppendTo;
|
|
335
|
+
if (!tx) {
|
|
336
|
+
tx = new Transaction();
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
if (arr instanceof Uint8Array) {
|
|
340
|
+
EndlessVector.composePushTransaction(this._packageId, tx.object(this.id), arr, tx);
|
|
341
|
+
} else if (Array.isArray(arr) && arr[0] && (arr[0] instanceof Uint8Array)) {
|
|
342
|
+
for (let i = 0; i < arr.length; i++) {
|
|
343
|
+
EndlessVector.composePushTransaction(this._packageId, tx.object(this.id), arr[i], tx);
|
|
344
|
+
}
|
|
345
|
+
} else {
|
|
346
|
+
throw new Error('.array must be Uint8Array or array of Uint8Array');
|
|
347
|
+
}
|
|
348
|
+
|
|
237
349
|
return tx;
|
|
238
350
|
}
|
|
239
351
|
|
|
@@ -243,7 +355,7 @@ export default class EndlessVector {
|
|
|
243
355
|
* Requires the instance to be writable (packageId and signAndExecuteTransaction must be provided).
|
|
244
356
|
* @throws {Error} If the instance is not writable or if the transaction fails
|
|
245
357
|
*
|
|
246
|
-
* @param {Uint8Array} arr - Byte array to push
|
|
358
|
+
* @param {Uint8Array|Uint8Array[]} arr - Byte array or array of byte arrays to push
|
|
247
359
|
* @param {?Object} params - Configuration parameters
|
|
248
360
|
* @param {?Number} [params.timeout] - wait for transaction confirmation timeout in ms, default 30000
|
|
249
361
|
* @param {?Number} [params.pollIntervalMs] - wait for transaction confirmation poll interval in ms, default 1000
|
package/README.md
CHANGED
|
@@ -32,10 +32,8 @@ const vector = await EndlessVector.create({
|
|
|
32
32
|
const vectorWithData = await EndlessVector.create({
|
|
33
33
|
suiClient: client,
|
|
34
34
|
packageId: 'testnet', // or 'mainnet' or '0xYOUR_PACKAGE_ID'
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
new Uint8Array([4, 5, 6])
|
|
38
|
-
],
|
|
35
|
+
array: new Uint8Array([1, 2, 3]), // [0] to append to EndlessVector
|
|
36
|
+
//array: [new Uint8Array([1, 2, 3]), new Uint8Array([5, 6, 7])], // or [0] and [1] to append to EndlessVector
|
|
39
37
|
signAndExecuteTransaction: async (tx) => {
|
|
40
38
|
const result = await wallet.signAndExecuteTransaction({ transaction: tx });
|
|
41
39
|
return result.digest;
|
|
@@ -57,7 +55,7 @@ console.log('Total items:', vector.length);
|
|
|
57
55
|
console.log('Total size:', vector.binaryLength, 'bytes');
|
|
58
56
|
|
|
59
57
|
// Read items
|
|
60
|
-
const firstItem = await vector.at(0);
|
|
58
|
+
const firstItem = await vector.at(0); // Uint8Array
|
|
61
59
|
```
|
|
62
60
|
|
|
63
61
|
## API Reference
|
|
@@ -72,7 +70,7 @@ Creates a new EndlessVector on the blockchain.
|
|
|
72
70
|
- `suiClient` (SuiClient) - Sui client instance for blockchain interactions
|
|
73
71
|
- `packageId` (string) - 'testnet', 'mainnet', or ID of the Move package containing the EndlessVector module
|
|
74
72
|
- `signAndExecuteTransaction` (function) - Function to sign and execute transactions
|
|
75
|
-
- `
|
|
73
|
+
- `array` (Uint8Array or Uint8Array[], optional) - Optional first vector<u8>(s) to push back to the new vector
|
|
76
74
|
- `gasCoin` (Object, optional) - Gas coin object reference `{objectId: string, digest: string, version: string}` for transaction payment
|
|
77
75
|
- `options` (Object, optional) - Additional options:
|
|
78
76
|
- `timeout` (number) - Transaction confirmation timeout in ms (default: 30000)
|
|
@@ -85,7 +83,7 @@ Creates a new EndlessVector on the blockchain.
|
|
|
85
83
|
const vector = await EndlessVector.create({
|
|
86
84
|
suiClient: client,
|
|
87
85
|
packageId: 'testnet', // or 'mainnet' or '0xPACKAGE_ID'
|
|
88
|
-
|
|
86
|
+
array: new Uint8Array([1, 2, 3]),
|
|
89
87
|
gasCoin: {
|
|
90
88
|
objectId: '0xGAS_COIN_ID',
|
|
91
89
|
digest: 'DIGEST',
|
|
@@ -145,7 +143,7 @@ await vector.reInitialize();
|
|
|
145
143
|
|
|
146
144
|
#### push(arr, params)
|
|
147
145
|
|
|
148
|
-
Pushes a
|
|
146
|
+
Pushes a Uint8Array or few Uint8Array(Uint8Array[]) to the vector. Requires writable mode. Maximum size per push: ~120KB.
|
|
149
147
|
|
|
150
148
|
```javascript
|
|
151
149
|
const data = new Uint8Array([1, 2, 3, 4, 5]);
|
|
@@ -153,7 +151,7 @@ await vector.push(data);
|
|
|
153
151
|
```
|
|
154
152
|
|
|
155
153
|
**Parameters:**
|
|
156
|
-
- `arr` (Uint8Array) - Data to push
|
|
154
|
+
- `arr` (Uint8Array or Uint8Array[]) - Data to push
|
|
157
155
|
- `params` (Object, optional) - Additional parameters
|
|
158
156
|
|
|
159
157
|
#### getPushTransaction(arr, tx)
|
|
@@ -173,7 +171,7 @@ await signAndExecuteTransaction(tx);
|
|
|
173
171
|
```
|
|
174
172
|
|
|
175
173
|
**Parameters:**
|
|
176
|
-
- `arr` (Uint8Array) - Data to push
|
|
174
|
+
- `arr` (Uint8Array or Uint8Array[]) - Data to push
|
|
177
175
|
- `tx` (Transaction, optional) - Existing transaction to append to
|
|
178
176
|
|
|
179
177
|
**Returns:** Transaction
|
|
@@ -276,7 +274,7 @@ const vectors = await Promise.all(
|
|
|
276
274
|
EndlessVector.create({
|
|
277
275
|
suiClient: client,
|
|
278
276
|
packageId: 'testnet', // or 'mainnet' or '0xPACKAGE_ID'
|
|
279
|
-
|
|
277
|
+
array: items,
|
|
280
278
|
gasCoin: gasCoinRefs[i],
|
|
281
279
|
signAndExecuteTransaction: async (tx) => {
|
|
282
280
|
const result = await wallet.signAndExecuteTransaction({ transaction: tx });
|
package/ids.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
|
|
2
2
|
export default {
|
|
3
3
|
'testnet': {
|
|
4
|
-
packageId: '
|
|
5
|
-
originalPackageId: '
|
|
4
|
+
packageId: '0x30bf8e91f40774ed08234f767360b4154562232903928b5f2f8fe5b2d51655bc', // should be the same as in Move.lock
|
|
5
|
+
originalPackageId: '0x30bf8e91f40774ed08234f767360b4154562232903928b5f2f8fe5b2d51655bc',
|
|
6
6
|
},
|
|
7
7
|
'mainnet': {
|
|
8
|
-
packageId: '
|
|
9
|
-
originalPackageId: '
|
|
8
|
+
packageId: '0x94cf19d164f014cfe73dda1121f27b54b69f0dbfa89d8b6ed48ae8a9144f5d65', // should be the same as in Move.lock
|
|
9
|
+
originalPackageId: '0x94cf19d164f014cfe73dda1121f27b54b69f0dbfa89d8b6ed48ae8a9144f5d65',
|
|
10
10
|
},
|
|
11
11
|
};
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import type { SuiClient, GetObjectParams, GetDynamicFieldsParams } from '@mysten/sui/client';
|
|
2
|
+
import type { Transaction, TransactionResult, TransactionObjectArgument } from '@mysten/sui/transactions';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Custom function to sign and execute transactions
|
|
6
|
+
*/
|
|
7
|
+
export type CustomSignAndExecuteTransactionFunction = (tx: Transaction) => Promise<string>;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Configuration parameters for creating an EndlessVector instance
|
|
11
|
+
*/
|
|
12
|
+
export interface EndlessVectorConstructorParams {
|
|
13
|
+
/** Sui client instance for blockchain interactions */
|
|
14
|
+
suiClient?: SuiClient;
|
|
15
|
+
/** ID or address of the EndlessVector on the Sui blockchain */
|
|
16
|
+
id?: string;
|
|
17
|
+
/** Adds write capability if provided, ID of the Move package containing the EndlessVector module or 'mainnet', 'testnet' to use known IDs */
|
|
18
|
+
packageId?: string | null;
|
|
19
|
+
/** Adds write capability if provided, function should accept Sui transaction, sign and submit it to the blockchain and return its digest */
|
|
20
|
+
signAndExecuteTransaction?: CustomSignAndExecuteTransactionFunction | null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Configuration parameters for creating a new EndlessVector via static create method
|
|
25
|
+
*/
|
|
26
|
+
export interface EndlessVectorCreateParams {
|
|
27
|
+
/** Sui client instance for blockchain interactions */
|
|
28
|
+
suiClient: SuiClient;
|
|
29
|
+
/** ID of the Move package containing the EndlessVector module */
|
|
30
|
+
packageId: string;
|
|
31
|
+
/** Function to sign and execute transactions */
|
|
32
|
+
signAndExecuteTransaction: CustomSignAndExecuteTransactionFunction;
|
|
33
|
+
/** Optional Uint8Array or array of Uint8Arrays to initialize the vector with */
|
|
34
|
+
array?: Uint8Array | Uint8Array[] | null;
|
|
35
|
+
/** Optional gas coin object reference {objectId: string, digest: string, version: string} to use for transaction payment */
|
|
36
|
+
gasCoin?: { objectId: string; digest: string; version: string } | null;
|
|
37
|
+
/** Optional transaction parameters */
|
|
38
|
+
options?: {
|
|
39
|
+
/** Transaction confirmation timeout in ms, default 30000 */
|
|
40
|
+
timeout?: number;
|
|
41
|
+
/** Poll interval in ms, default 1000 */
|
|
42
|
+
pollIntervalMs?: number;
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Configuration parameters for getCreateTransactionAndReturnVectorInput
|
|
48
|
+
*/
|
|
49
|
+
export interface GetCreateTransactionParams {
|
|
50
|
+
/** The package ID ('mainnet', 'testnet', or explicit package ID) */
|
|
51
|
+
packageId: string;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Configuration parameters for push and concat operations
|
|
56
|
+
*/
|
|
57
|
+
export interface TransactionOptions {
|
|
58
|
+
/** wait for transaction confirmation timeout in ms, default 30000 */
|
|
59
|
+
timeout?: number;
|
|
60
|
+
/** wait for transaction confirmation poll interval in ms, default 1000 */
|
|
61
|
+
pollIntervalMs?: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Configuration parameters for creating an EndlessVectorHistory instance
|
|
66
|
+
*/
|
|
67
|
+
export interface EndlessVectorHistoryConstructorParams {
|
|
68
|
+
/** Sui client instance for blockchain interactions */
|
|
69
|
+
suiClient?: SuiClient;
|
|
70
|
+
/** Unique identifier for this history item */
|
|
71
|
+
id?: string;
|
|
72
|
+
/** Index position of this history item in the sequence */
|
|
73
|
+
index?: number;
|
|
74
|
+
/** Raw field data from the blockchain object */
|
|
75
|
+
fields?: any | null;
|
|
76
|
+
/** Reference to the parent EndlessVector instance */
|
|
77
|
+
endlessVector?: EndlessVector;
|
|
78
|
+
/** Reference to the parent EndlessVectorArchive instance */
|
|
79
|
+
endlessVectorArchive?: EndlessVectorArchive | null;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Configuration parameters for creating an EndlessVectorArchive instance
|
|
84
|
+
*/
|
|
85
|
+
export interface EndlessVectorArchiveConstructorParams {
|
|
86
|
+
/** Sui client instance for blockchain interactions */
|
|
87
|
+
suiClient?: SuiClient;
|
|
88
|
+
/** ID or address of the EndlessVectorArchive on the Sui blockchain */
|
|
89
|
+
id?: string;
|
|
90
|
+
/** Index position of this archive item in the sequence */
|
|
91
|
+
index?: number;
|
|
92
|
+
/** Reference to the parent EndlessVector instance */
|
|
93
|
+
endlessVector?: EndlessVector;
|
|
94
|
+
/** Raw field data from the blockchain object */
|
|
95
|
+
fields?: any;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Represents a history item in an EndlessVector, managing a segment of the vector's data.
|
|
100
|
+
* Each history item stores a portion of the vector's elements and maintains metadata
|
|
101
|
+
* about its position and relationships with adjacent history items.
|
|
102
|
+
*/
|
|
103
|
+
export declare class EndlessVectorHistory {
|
|
104
|
+
suiClient: SuiClient;
|
|
105
|
+
id: string;
|
|
106
|
+
index: number;
|
|
107
|
+
|
|
108
|
+
constructor(params?: EndlessVectorHistoryConstructorParams);
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Sets the fields data for this history item. Called by loader of EndlessVector.
|
|
112
|
+
*/
|
|
113
|
+
setFields(fields: any): void;
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Checks if this history item has been initialized and is ready for use.
|
|
117
|
+
*/
|
|
118
|
+
isReady(): boolean;
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Initializes this history item by loading its data from the blockchain.
|
|
122
|
+
* Uses promise-based synchronization to prevent multiple concurrent initializations.
|
|
123
|
+
*/
|
|
124
|
+
initialize(): Promise<boolean>;
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Gets the last index position that this history item covers.
|
|
128
|
+
*/
|
|
129
|
+
get endsAt(): number | undefined;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Indicates whether the first item in this history contains suffix bytes that should be
|
|
133
|
+
* added to the last item from the previous history segment.
|
|
134
|
+
*/
|
|
135
|
+
get firstItemIsFromPreviousHistory(): boolean;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Gets the first index position that this history item covers.
|
|
139
|
+
*/
|
|
140
|
+
get startsAt(): number;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Gets the number of bytes from the next history item that should be appended
|
|
144
|
+
* to the last item in this history segment.
|
|
145
|
+
*/
|
|
146
|
+
get followedByNextBytes(): number;
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Retrieves the byte array at the specified index within this history segment.
|
|
150
|
+
*/
|
|
151
|
+
at(i: number): Promise<Uint8Array>;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Gets the suffix bytes stored in this history item that should be appended
|
|
155
|
+
* to the last item of the previous history segment.
|
|
156
|
+
*/
|
|
157
|
+
getSuffixStoredBytes(): Uint8Array;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Represents an archive item in an EndlessVector
|
|
162
|
+
*/
|
|
163
|
+
export declare class EndlessVectorArchive {
|
|
164
|
+
suiClient: SuiClient;
|
|
165
|
+
id: string;
|
|
166
|
+
index: number;
|
|
167
|
+
historyTableId: string | null;
|
|
168
|
+
historyItemsCount: number;
|
|
169
|
+
|
|
170
|
+
constructor(params?: EndlessVectorArchiveConstructorParams);
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Sets the fields data for this archive item. Called by loader of EndlessVector.
|
|
174
|
+
*/
|
|
175
|
+
setFields(fields: any): void;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Checks if this archive item has been initialized and is ready for use.
|
|
179
|
+
*/
|
|
180
|
+
isReady(): boolean;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Gets the total number of items stored in this archive.
|
|
184
|
+
*/
|
|
185
|
+
get length(): number;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Gets the first index position that this archive covers.
|
|
189
|
+
*/
|
|
190
|
+
get startsAt(): number;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Gets the last index position that this archive covers.
|
|
194
|
+
*/
|
|
195
|
+
get endsAt(): number | undefined;
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Initializes this archive item by loading its data from the blockchain.
|
|
199
|
+
*/
|
|
200
|
+
initialize(): Promise<boolean>;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Gets a history item within this archive by its index.
|
|
204
|
+
*/
|
|
205
|
+
getHistory(historyIndex: number | string): Promise<EndlessVectorHistory>;
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Retrieves the byte array at the specified index within this archive.
|
|
209
|
+
*/
|
|
210
|
+
at(i: number): Promise<Uint8Array>;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Gets suffix bytes from a history item at the specified index within this archive.
|
|
214
|
+
*/
|
|
215
|
+
getSuffixFromHistoryItemOfIndex(i: number): Promise<Uint8Array>;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Represents an endless vector data structure that can grow beyond Sui object size limits
|
|
220
|
+
* by storing overflow data in history items. Provides seamless access to all elements regardless
|
|
221
|
+
* of whether they're stored in the current object or historical segments.
|
|
222
|
+
*/
|
|
223
|
+
export declare class EndlessVector {
|
|
224
|
+
suiClient: SuiClient;
|
|
225
|
+
id: string;
|
|
226
|
+
binaryLength: number;
|
|
227
|
+
length: number;
|
|
228
|
+
historyItemsCount: number;
|
|
229
|
+
historyTableId: string | null;
|
|
230
|
+
firstItemIsFromPreviousHistory: boolean;
|
|
231
|
+
archiveTableId: string | null;
|
|
232
|
+
archiveItemsCount: number;
|
|
233
|
+
archivedAtLength: number;
|
|
234
|
+
archivedFromLength: number;
|
|
235
|
+
burnedArchiveCount: number;
|
|
236
|
+
|
|
237
|
+
constructor(params?: EndlessVectorConstructorParams);
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Static factory method to create a new empty EndlessVector on the blockchain.
|
|
241
|
+
*/
|
|
242
|
+
static create(params: EndlessVectorCreateParams): Promise<EndlessVector>;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Creates an empty EndlessVector and returns the vector input reference.
|
|
246
|
+
*/
|
|
247
|
+
static getCreateTransactionAndReturnVectorInput(
|
|
248
|
+
params: GetCreateTransactionParams,
|
|
249
|
+
arr?: Uint8Array | null,
|
|
250
|
+
txToAppendTo?: Transaction | null
|
|
251
|
+
): Promise<TransactionResult>;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Attach move calls to transaction, to push item into endlessvector, handling large arrays by chunking them.
|
|
255
|
+
*/
|
|
256
|
+
static composePushTransaction(
|
|
257
|
+
packageId: string,
|
|
258
|
+
vectorInput: TransactionObjectArgument,
|
|
259
|
+
arr: Uint8Array,
|
|
260
|
+
tx: Transaction
|
|
261
|
+
): Transaction;
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Check if the EndlessVector instance is writable
|
|
265
|
+
*/
|
|
266
|
+
get isWritable(): boolean;
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Gets the first index that is stored in the current EndlessVector object (not in history items).
|
|
270
|
+
*/
|
|
271
|
+
get firstNotHistoryIndex(): number;
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Forces re-initialization of the EndlessVector to reload data from the blockchain.
|
|
275
|
+
*/
|
|
276
|
+
reInitialize(): void;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Initializes the EndlessVector by loading data from the Sui blockchain.
|
|
280
|
+
*/
|
|
281
|
+
initialize(): Promise<void>;
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Gets a history item by its index, loading it from the blockchain if needed.
|
|
285
|
+
*/
|
|
286
|
+
getHistory(historyIndex: number | string): Promise<EndlessVectorHistory>;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Gets an archive item by its index, loading it from the blockchain if needed.
|
|
290
|
+
*/
|
|
291
|
+
getArchive(archiveIndex: number | string): Promise<EndlessVectorArchive>;
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Loads multiple history items in a single batch request for efficiency.
|
|
295
|
+
*/
|
|
296
|
+
loadHistoryItemsBunch(historyItems: EndlessVectorHistory[]): Promise<void>;
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Loads a single history item, batching requests for efficiency.
|
|
300
|
+
*/
|
|
301
|
+
loadHistoryItem(historyItem: EndlessVectorHistory): Promise<EndlessVectorHistory>;
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Loads multiple archive items in a single batch request for efficiency.
|
|
305
|
+
*/
|
|
306
|
+
loadArchiveItemsBunch(archiveItems: EndlessVectorArchive[]): Promise<void>;
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Loads a single archive item, batching requests for efficiency.
|
|
310
|
+
*/
|
|
311
|
+
loadArchiveItem(archiveItem: EndlessVectorArchive): Promise<EndlessVectorArchive>;
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Retrieves the byte array at the specified index from either current items or history.
|
|
315
|
+
*/
|
|
316
|
+
at(i: number): Promise<Uint8Array>;
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* Gets suffix bytes from a history item at the specified index.
|
|
320
|
+
*/
|
|
321
|
+
getSuffixFromHistoryItemOfIndex(i: number): Promise<Uint8Array | undefined>;
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Creates a transaction to push new byte arrays to the EndlessVector.
|
|
325
|
+
*/
|
|
326
|
+
getPushTransaction(arr: Uint8Array | Uint8Array[], txToAppendTo?: Transaction | null): Transaction;
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Pushes new byte array to the EndlessVector, creating and executing the necessary transaction.
|
|
330
|
+
*/
|
|
331
|
+
push(arr: Uint8Array | Uint8Array[], params?: TransactionOptions): Promise<boolean>;
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Creates a transaction to concatenate EndlessVector(s) into this one.
|
|
335
|
+
*/
|
|
336
|
+
getConcatTransaction(
|
|
337
|
+
other: string | EndlessVector | Array<string | EndlessVector>,
|
|
338
|
+
txToAppendTo?: Transaction | null
|
|
339
|
+
): Transaction;
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Concatenates EndlessVector(s) into this one, creating and executing the necessary transaction.
|
|
343
|
+
*/
|
|
344
|
+
concat(other: string | EndlessVector | Array<string | EndlessVector>, params?: TransactionOptions): Promise<boolean>;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export { EndlessVector as default };
|
package/package.json
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fizzyflow/endless-vector",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
7
|
+
"types": "./index.d.ts",
|
|
7
8
|
"keywords": [
|
|
8
9
|
"sui",
|
|
9
10
|
"vector",
|
|
@@ -24,7 +25,7 @@
|
|
|
24
25
|
"author": "suidouble (https://github.com/suidouble)",
|
|
25
26
|
"license": "Apache-2.0",
|
|
26
27
|
"scripts": {
|
|
27
|
-
"test": "tap -j1 -
|
|
28
|
+
"test": "tap -j1 -t320 ./test/*.test.js"
|
|
28
29
|
},
|
|
29
30
|
"peerDependencies": {
|
|
30
31
|
"@mysten/sui": "^1.44.0"
|
package/test/base.test.js
CHANGED
|
@@ -71,8 +71,78 @@ test('attach a local package', async t => {
|
|
|
71
71
|
});
|
|
72
72
|
|
|
73
73
|
|
|
74
|
+
test('test raw create transaction', async t => {
|
|
75
|
+
const arr = randomBytesOfLength(120 * 1024); // 100KB
|
|
76
|
+
|
|
77
|
+
const tx = new suiMaster.Transaction();
|
|
78
|
+
const vectorTxInput = await EndlessVector.getCreateTransactionAndReturnVectorInput({
|
|
79
|
+
packageId: contract.id,
|
|
80
|
+
}, arr, tx);
|
|
81
|
+
tx.transferObjects([vectorTxInput], tx.pure.address(suiMaster.address));
|
|
82
|
+
|
|
83
|
+
t.ok(tx);
|
|
84
|
+
let digest = null;
|
|
85
|
+
try {
|
|
86
|
+
digest = await signAndExecuteTransaction(tx);
|
|
87
|
+
t.ok(digest);
|
|
88
|
+
} catch (e) {
|
|
89
|
+
console.error('Error preparing transaction:', e);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const transactionBlockResponse = await suiMaster.client.waitForTransaction({
|
|
93
|
+
digest: digest,
|
|
94
|
+
options: { showObjectChanges: true, },
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Find the created EndlessVector object
|
|
98
|
+
const objectChanges = transactionBlockResponse.objectChanges || [];
|
|
99
|
+
const createdVector = objectChanges.find(
|
|
100
|
+
change => change.type === 'created' &&
|
|
101
|
+
change.objectType &&
|
|
102
|
+
change.objectType.includes('endless_vector::EndlessVector')
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const createdVectorId = createdVector ? createdVector.objectId : null;
|
|
106
|
+
t.ok(createdVectorId, 'Created EndlessVector object should have an ID');
|
|
107
|
+
|
|
108
|
+
const loadBack = new EndlessVector({
|
|
109
|
+
suiClient: suiMaster.client,
|
|
110
|
+
id: createdVectorId,
|
|
111
|
+
});
|
|
112
|
+
await loadBack.initialize();
|
|
113
|
+
|
|
114
|
+
t.ok(loadBack.length === 1, `Loaded vector should have length 1, got ${loadBack.length}`);
|
|
115
|
+
const getBack = await loadBack.at(0);
|
|
116
|
+
t.ok(equalUint8Arrays(getBack, arr), 'Data retrieved from loaded vector should match original data');
|
|
117
|
+
});
|
|
74
118
|
|
|
75
119
|
|
|
120
|
+
test('make a test EndlessVector with few chunks in a single tx', async t => {
|
|
121
|
+
const data = [
|
|
122
|
+
randomBytesOfLength(1 * 1024),
|
|
123
|
+
randomBytesOfLength(2 * 1024),
|
|
124
|
+
randomBytesOfLength(3 * 1024),
|
|
125
|
+
];
|
|
126
|
+
|
|
127
|
+
const testEndlessVector = await EndlessVector.create({
|
|
128
|
+
array: data,
|
|
129
|
+
suiClient: suiMaster.client, // instance of Sui SDK SuiClient
|
|
130
|
+
packageId: contract.id, // provide packageId and signAndExecuteTransaction to make EndlessVector writable
|
|
131
|
+
signAndExecuteTransaction: signAndExecuteTransaction,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
const getBack0 = await testEndlessVector.at(0);
|
|
135
|
+
const getBack1 = await testEndlessVector.at(1);
|
|
136
|
+
const getBack2 = await testEndlessVector.at(2);
|
|
137
|
+
|
|
138
|
+
t.ok(equalUint8Arrays(getBack0, data[0]));
|
|
139
|
+
t.ok(equalUint8Arrays(getBack1, data[1]));
|
|
140
|
+
t.ok(equalUint8Arrays(getBack2, data[2]));
|
|
141
|
+
|
|
142
|
+
t.ok(testEndlessVector.length === 3);
|
|
143
|
+
t.ok(testEndlessVector.binaryLength === 6 * 1024);
|
|
144
|
+
});
|
|
145
|
+
|
|
76
146
|
test('make a test EndlessVector and push single Uint8Array to it', async t => {
|
|
77
147
|
endlessVector = await EndlessVector.create({
|
|
78
148
|
suiClient: suiMaster.client, // instance of Sui SDK SuiClient
|
|
@@ -358,7 +428,7 @@ test('test parallel creation, push, and append of 6 vectors', async t => {
|
|
|
358
428
|
// Prepare test data for each vector
|
|
359
429
|
const testData = [];
|
|
360
430
|
for (let i = 0; i < vectorCount; i++) {
|
|
361
|
-
testData.push(
|
|
431
|
+
testData.push(randomBytesOfLength(1024));
|
|
362
432
|
}
|
|
363
433
|
|
|
364
434
|
// Create N EndlessVectors in parallel using static create method
|
|
@@ -368,7 +438,7 @@ test('test parallel creation, push, and append of 6 vectors', async t => {
|
|
|
368
438
|
EndlessVector.create({
|
|
369
439
|
suiClient: suiMaster.client,
|
|
370
440
|
packageId: contract.id,
|
|
371
|
-
|
|
441
|
+
array: testData[i] ? testData[i] : null,
|
|
372
442
|
gasCoin: gasCoinInputs[i],
|
|
373
443
|
signAndExecuteTransaction: async (tx) => {
|
|
374
444
|
console.log(`Creating vector ${i}...`);
|
|
@@ -407,24 +477,20 @@ test('test parallel creation, push, and append of 6 vectors', async t => {
|
|
|
407
477
|
// Verify the data after concatenation
|
|
408
478
|
await mainVector.initialize();
|
|
409
479
|
|
|
410
|
-
|
|
411
|
-
const expectedLength = vectorCount * 2;
|
|
480
|
+
const expectedLength = vectorCount;
|
|
412
481
|
t.ok(mainVector.length === expectedLength, `mainVector should have ${expectedLength} items, got ${mainVector.length}`);
|
|
413
482
|
|
|
414
483
|
console.log(`Verifying ${expectedLength} items in concatenated vector...`);
|
|
415
484
|
|
|
416
485
|
// Verify each item matches the original testData
|
|
417
486
|
for (let vectorIdx = 0; vectorIdx < vectorCount; vectorIdx++) {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
`Item ${globalIdx} (vector ${vectorIdx}, item ${itemIdx}) should match`
|
|
426
|
-
);
|
|
427
|
-
}
|
|
487
|
+
const expected = testData[vectorIdx];
|
|
488
|
+
const retrieved = await mainVector.at(vectorIdx);
|
|
489
|
+
|
|
490
|
+
t.ok(
|
|
491
|
+
equalUint8Arrays(retrieved, expected),
|
|
492
|
+
`Item ${vectorIdx} (vector ${vectorIdx}, item ${vectorIdx}) should match`
|
|
493
|
+
);
|
|
428
494
|
}
|
|
429
495
|
});
|
|
430
496
|
|