@arkiv-network/sdk 0.6.8-dev.5 → 0.7.0-dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/chains/index.d.ts +25 -25
  2. package/dist/consts-Bz0LZQZY.js +7 -0
  3. package/dist/consts-Bz0LZQZY.js.map +1 -0
  4. package/dist/{consts-AUoL-v42.cjs → consts-CxT1-RXU.cjs} +1 -1
  5. package/dist/entity-BhSXaB23.cjs +81 -0
  6. package/dist/{entity-B6g_EPm1.d.cts → entity-CN41IOrq.d.cts} +53 -34
  7. package/dist/entity-CN41IOrq.d.cts.map +1 -0
  8. package/dist/entity-DGfVyB-a.js +71 -0
  9. package/dist/entity-DGfVyB-a.js.map +1 -0
  10. package/dist/{entity-qoLMAuuk.d.ts → entity-NnEVlePN.d.ts} +53 -34
  11. package/dist/entity-NnEVlePN.d.ts.map +1 -0
  12. package/dist/{index-DdspxNAA.d.ts → index-ClkpS6s_.d.ts} +2 -2
  13. package/dist/{index-DdspxNAA.d.ts.map → index-ClkpS6s_.d.ts.map} +1 -1
  14. package/dist/{index-Ds9dwqb5.d.cts → index-w4qop0Pe.d.cts} +2 -2
  15. package/dist/{index-Ds9dwqb5.d.cts.map → index-w4qop0Pe.d.cts.map} +1 -1
  16. package/dist/index.cjs +281 -264
  17. package/dist/index.d.cts +13 -4
  18. package/dist/index.d.cts.map +1 -1
  19. package/dist/index.d.ts +14 -5
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +279 -266
  22. package/dist/index.js.map +1 -1
  23. package/dist/{payload-Claf2jUO.js → payload-BpNUPOnY.js} +3 -3
  24. package/dist/payload-BpNUPOnY.js.map +1 -0
  25. package/dist/{payload-B2kFJyah.d.ts → payload-C2KHOUoj.d.ts} +1 -1
  26. package/dist/{payload-B2kFJyah.d.ts.map → payload-C2KHOUoj.d.ts.map} +1 -1
  27. package/dist/{payload-DpA5PA-w.cjs → payload-D8YLKcJj.cjs} +1 -1
  28. package/dist/query/index.cjs +3 -2
  29. package/dist/query/index.d.cts +2 -2
  30. package/dist/query/index.d.ts +2 -2
  31. package/dist/query/index.js +3 -2
  32. package/dist/query/index.js.map +1 -1
  33. package/dist/{queryBuilder-D2uwP9jI.js → queryBuilder-BE_XhLLa.js} +98 -67
  34. package/dist/queryBuilder-BE_XhLLa.js.map +1 -0
  35. package/dist/{queryBuilder-UW2MCaX4.cjs → queryBuilder-J37buGCi.cjs} +137 -64
  36. package/dist/types/index.cjs +4 -1
  37. package/dist/types/index.d.cts +2 -2
  38. package/dist/types/index.d.ts +2 -2
  39. package/dist/types/index.js +4 -1
  40. package/dist/utils/index.cjs +2 -2
  41. package/dist/utils/index.d.ts +1 -1
  42. package/dist/utils/index.js +2 -2
  43. package/package.json +1 -1
  44. package/src/actions/public/subscribeEntityEvents.ts +25 -51
  45. package/src/actions/wallet/changeOwnership.ts +6 -6
  46. package/src/actions/wallet/createEntity.ts +7 -4
  47. package/src/actions/wallet/deleteEntity.ts +2 -3
  48. package/src/actions/wallet/extendEntity.ts +3 -4
  49. package/src/actions/wallet/mutateEntities.ts +11 -54
  50. package/src/actions/wallet/updateEntity.ts +3 -4
  51. package/src/clients/decorators/arkivWallet.ts +5 -1
  52. package/src/consts.ts +2 -1
  53. package/src/errors.ts +29 -1
  54. package/src/query/engine.test.ts +45 -0
  55. package/src/query/engine.ts +6 -1
  56. package/src/query/selectQueryBuilder.test.ts +5 -2
  57. package/src/types/attributes.ts +17 -5
  58. package/src/types/entity.ts +12 -2
  59. package/src/types/events.ts +14 -16
  60. package/src/types/index.ts +1 -0
  61. package/src/types/rpcSchema.ts +7 -2
  62. package/src/utils/arkivTransactions.test.ts +234 -36
  63. package/src/utils/arkivTransactions.ts +255 -101
  64. package/src/utils/entities.ts +17 -7
  65. package/src/utils/payload.ts +4 -2
  66. package/src/utils/validation.test.ts +52 -6
  67. package/src/utils/validation.ts +54 -6
  68. package/dist/consts-BV4PR-de.js +0 -7
  69. package/dist/consts-BV4PR-de.js.map +0 -1
  70. package/dist/entity-B6g_EPm1.d.cts.map +0 -1
  71. package/dist/entity-qoLMAuuk.d.ts.map +0 -1
  72. package/dist/payload-Claf2jUO.js.map +0 -1
  73. package/dist/queryBuilder-D2uwP9jI.js.map +0 -1
  74. /package/dist/{types-H-TSmRpm.js → types-Ci4BRClw.js} +0 -0
  75. /package/dist/{types-o3zWarRp.cjs → types-a8gm_IaQ.cjs} +0 -0
package/dist/index.js CHANGED
@@ -1,18 +1,19 @@
1
1
  import { t as chains_exports } from "./chains-CrtkVbBh.js";
2
- import { c as entityFromRpcResult, d as InvalidExpirationError, f as NoCursorOrLimitError, h as getLogger, l as EntityMutationError, m as NoMoreResultsError, n as QueryBuilder, p as NoEntityFoundError, r as SelectQueryBuilder, u as InvalidAttributeError } from "./queryBuilder-D2uwP9jI.js";
3
- import { n as BLOCK_TIME, t as ARKIV_ADDRESS } from "./consts-BV4PR-de.js";
4
- import "./types-H-TSmRpm.js";
5
- import { n as stringToPayload, t as jsonToPayload } from "./payload-Claf2jUO.js";
6
- import { TransactionExecutionError, bytesToHex, createClient, decodeEventLog, hexToBytes, hexToString, numberToHex, parseAbi, publicActions, toBytes, toHex, toRlp, walletActions } from "viem";
2
+ import { S as getLogger, _ as InvalidContentTypeError, b as NoEntityFoundError, c as isEntityKey, d as entityFromRpcResult, f as RpcAttributeValueType, g as InvalidAttributeKeyError, h as InvalidAttributeError, l as validateAttribute, m as EntityMutationError, n as QueryBuilder, p as DuplicateAttributeError, r as SelectQueryBuilder, u as validateExpiresIn, v as InvalidExpirationError, x as NoMoreResultsError, y as NoCursorOrLimitError } from "./queryBuilder-BE_XhLLa.js";
3
+ import { n as BLOCK_TIME, t as ARKIV_ADDRESS } from "./consts-Bz0LZQZY.js";
4
+ import { n as EntityOperationType } from "./entity-DGfVyB-a.js";
5
+ import "./types-Ci4BRClw.js";
6
+ import { n as stringToPayload, t as jsonToPayload } from "./payload-BpNUPOnY.js";
7
+ import { ContractFunctionExecutionError, ContractFunctionRevertedError, TransactionExecutionError, bytesToHex, createClient, decodeEventLog, encodePacked, hexToBytes, keccak256, numberToHex, parseAbi, publicActions, stringToBytes, toBytes, toHex, walletActions } from "viem";
7
8
 
8
9
  //#region src/actions/public/getBlockTiming.ts
9
- const logger$9 = getLogger("actions:public:get-block-timing");
10
+ const logger$8 = getLogger("actions:public:get-block-timing");
10
11
  async function getBlockTiming(client) {
11
12
  const blockTiming = await client.request({
12
13
  method: "arkiv_getBlockTiming",
13
14
  params: []
14
15
  });
15
- logger$9("Block timing %o", blockTiming);
16
+ logger$8("Block timing %o", blockTiming);
16
17
  return {
17
18
  currentBlock: BigInt(blockTiming.current_block),
18
19
  currentBlockTime: blockTiming.current_block_time,
@@ -98,78 +99,289 @@ async function query(client, query$1, queryOptions) {
98
99
  }
99
100
 
100
101
  //#endregion
101
- //#region src/actions/public/subscribeEntityEvents.ts
102
- const logger$8 = getLogger("actions:public:subscribe-entity-events");
103
- const arkivABI = parseAbi([
104
- "event ArkivEntityCreated(uint256 indexed entityKey, address indexed ownerAddress, uint256 expirationBlock, uint256 cost)",
105
- "event ArkivEntityUpdated(uint256 indexed entityKey, address indexed ownerAddress, uint256 oldExpirationBlock, uint256 newExpirationBlock, uint256 cost)",
106
- "event ArkivEntityExpired(uint256 indexed entityKey, address indexed ownerAddress)",
107
- "event ArkivEntityDeleted(uint256 indexed entityKey, address indexed ownerAddress)",
108
- "event ArkivEntityBTLExtended(uint256 indexed entityKey, address indexed ownerAddress, uint256 oldExpirationBlock, uint256 newExpirationBlock, uint256 cost)",
109
- "event ArkivEntityOwnerChanged(uint256 indexed entityKey, address indexed oldOwnerAddress, address indexed newOwnerAddress)"
102
+ //#region src/utils/arkivTransactions.ts
103
+ const logger$7 = getLogger("utils:arkiv-transactions");
104
+ const MIME_REGEX = /^[a-z][a-z0-9!#$&\-^_]*\/[a-z0-9][a-z0-9!#$&\-^_.+]*$/;
105
+ function validateContentType(contentType) {
106
+ if (!MIME_REGEX.test(contentType)) throw new InvalidContentTypeError(contentType);
107
+ }
108
+ const ENTITY_EXECUTE_ABI = parseAbi(["function execute((uint8 operationType, bytes32 entityKey, bytes payload, (bytes32[4] data) contentType, (bytes32 name, uint8 valueType, bytes32[4] value)[] attributes, uint32 expiresIn, address newOwner)[] ops) external"]);
109
+ const ENTITY_OPERATION_EVENT_ABI = parseAbi(["event EntityOperation(bytes32 indexed entityKey, uint8 indexed operationType, address indexed owner, uint32 expiresAt, bytes32 entityHash)"]);
110
+ const ENTITY_ERRORS_ABI = parseAbi([
111
+ "error EmptyBatch()",
112
+ "error AttributesNotSorted()",
113
+ "error InvalidValueType(bytes32 name, uint8 valueType)",
114
+ "error InvalidOpType(uint8 operationType)",
115
+ "error ExpiryInPast(uint32 expiresAt, uint32 currentBlock)",
116
+ "error TooManyAttributes(uint256 count, uint256 maxCount)",
117
+ "error EntityNotFound(bytes32 entityKey)",
118
+ "error NotOwner(bytes32 entityKey, address caller, address owner)",
119
+ "error EntityExpired(bytes32 entityKey, uint32 expiresAt)",
120
+ "error ExpiryNotExtended(bytes32 entityKey, uint32 newExpiresAt, uint32 currentExpiresAt)",
121
+ "error TransferToZeroAddress(bytes32 entityKey)",
122
+ "error TransferToSelf(bytes32 entityKey)",
123
+ "error EntityNotExpired(bytes32 entityKey, uint32 expiresAt)",
124
+ "error Ident32Empty()",
125
+ "error Ident32TooLong(uint256 length)",
126
+ "error Ident32InvalidByte(uint256 position, bytes1 value)",
127
+ "error MimeEmpty()",
128
+ "error MimeTooLong(uint256 length, uint256 maxLength)",
129
+ "error MimeInvalidByte(uint256 position, bytes1 value)",
130
+ "error MimeIncomplete()"
110
131
  ]);
132
+ const EXECUTE_ABI = [...ENTITY_EXECUTE_ABI, ...ENTITY_ERRORS_ABI];
133
+ const ENTITY_NONCE_ABI = parseAbi(["function nonces(address owner) view returns (uint32)"]);
134
+ const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000";
135
+ const ZERO_32 = `0x${"00".repeat(32)}`;
136
+ const EMPTY_BYTES128 = [
137
+ ZERO_32,
138
+ ZERO_32,
139
+ ZERO_32,
140
+ ZERO_32
141
+ ];
142
+ function encodeBytes128(data) {
143
+ const padded = new Uint8Array(128);
144
+ padded.set(data.slice(0, 128));
145
+ return [
146
+ toHex(padded.slice(0, 32)),
147
+ toHex(padded.slice(32, 64)),
148
+ toHex(padded.slice(64, 96)),
149
+ toHex(padded.slice(96, 128))
150
+ ];
151
+ }
152
+ function encodeMime128(contentType) {
153
+ return { data: contentType ? encodeBytes128(stringToBytes(contentType)) : EMPTY_BYTES128 };
154
+ }
155
+ function encodeAttribute(attr) {
156
+ validateAttribute(attr);
157
+ const name = toHex(attr.key, { size: 32 });
158
+ if (typeof attr.value === "string") {
159
+ if (isEntityKey(attr.value)) return {
160
+ name,
161
+ valueType: RpcAttributeValueType.EntityKey,
162
+ value: [
163
+ toHex(toBytes(attr.value), { size: 32 }),
164
+ ZERO_32,
165
+ ZERO_32,
166
+ ZERO_32
167
+ ]
168
+ };
169
+ return {
170
+ name,
171
+ valueType: RpcAttributeValueType.String,
172
+ value: encodeBytes128(stringToBytes(attr.value))
173
+ };
174
+ }
175
+ return {
176
+ name,
177
+ valueType: RpcAttributeValueType.Uint,
178
+ value: [
179
+ toHex(BigInt(attr.value), { size: 32 }),
180
+ ZERO_32,
181
+ ZERO_32,
182
+ ZERO_32
183
+ ]
184
+ };
185
+ }
186
+ function encodeAttributes(attrs) {
187
+ const encoded = attrs.map((attr) => ({
188
+ key: attr.key,
189
+ ...encodeAttribute(attr)
190
+ })).sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
191
+ for (let i = 1; i < encoded.length; i++) if (encoded[i].name === encoded[i - 1].name) throw new DuplicateAttributeError(encoded[i].key);
192
+ return encoded.map(({ key: _,...attr }) => attr);
193
+ }
194
+ function toBTL(expiresIn) {
195
+ validateExpiresIn(expiresIn);
196
+ return Math.ceil(expiresIn / BLOCK_TIME);
197
+ }
198
+ function deriveEntityKey(chainId, owner, nonce) {
199
+ return keccak256(encodePacked([
200
+ "uint256",
201
+ "address",
202
+ "address",
203
+ "uint32"
204
+ ], [
205
+ BigInt(chainId),
206
+ ARKIV_ADDRESS,
207
+ owner,
208
+ Number(nonce)
209
+ ]));
210
+ }
211
+ async function sendArkivTransaction(client, ops, txParams) {
212
+ if (!client.account) throw new Error("Account required");
213
+ if (!client.chain) throw new Error("Chain required");
214
+ const walletClient = client;
215
+ const { creates, updates, deletes, extensions, ownershipChanges } = ops;
216
+ const owner = client.account.address;
217
+ const ownerNonce = creates?.length ? BigInt(await walletClient.readContract({
218
+ address: ARKIV_ADDRESS,
219
+ abi: ENTITY_NONCE_ABI,
220
+ functionName: "nonces",
221
+ args: [owner]
222
+ })) : 0n;
223
+ const createdEntityKeys = (creates ?? []).map((_, i) => deriveEntityKey(client.chain.id, owner, ownerNonce + BigInt(i)));
224
+ for (const item of creates ?? []) validateContentType(item.contentType);
225
+ for (const item of updates ?? []) validateContentType(item.contentType);
226
+ const operations = [
227
+ ...(creates ?? []).map((item, i) => ({
228
+ operationType: EntityOperationType.Create,
229
+ entityKey: createdEntityKeys[i],
230
+ payload: toHex(item.payload),
231
+ contentType: encodeMime128(item.contentType),
232
+ attributes: encodeAttributes(item.attributes),
233
+ expiresIn: toBTL(item.expiresIn),
234
+ newOwner: ZERO_ADDRESS
235
+ })),
236
+ ...(updates ?? []).map((item) => ({
237
+ operationType: EntityOperationType.Update,
238
+ entityKey: item.entityKey,
239
+ payload: toHex(item.payload),
240
+ contentType: encodeMime128(item.contentType),
241
+ attributes: encodeAttributes(item.attributes),
242
+ expiresIn: 0,
243
+ newOwner: ZERO_ADDRESS
244
+ })),
245
+ ...(deletes ?? []).map((item) => ({
246
+ operationType: EntityOperationType.Delete,
247
+ entityKey: item.entityKey,
248
+ payload: "0x",
249
+ contentType: encodeMime128(""),
250
+ attributes: [],
251
+ expiresIn: 0,
252
+ newOwner: ZERO_ADDRESS
253
+ })),
254
+ ...(extensions ?? []).map((item) => ({
255
+ operationType: EntityOperationType.Extend,
256
+ entityKey: item.entityKey,
257
+ payload: "0x",
258
+ contentType: encodeMime128(""),
259
+ attributes: [],
260
+ expiresIn: toBTL(item.expiresIn),
261
+ newOwner: ZERO_ADDRESS
262
+ })),
263
+ ...(ownershipChanges ?? []).map((item) => ({
264
+ operationType: EntityOperationType.Transfer,
265
+ entityKey: item.entityKey,
266
+ payload: "0x",
267
+ contentType: encodeMime128(""),
268
+ attributes: [],
269
+ expiresIn: 0,
270
+ newOwner: item.newOwner
271
+ }))
272
+ ];
273
+ logger$7("Sending execute with %d operations %s", operations.length, JSON.stringify(operations));
274
+ try {
275
+ const txHash = await walletClient.writeContract({
276
+ address: ARKIV_ADDRESS,
277
+ abi: EXECUTE_ABI,
278
+ functionName: "execute",
279
+ args: [operations],
280
+ account: client.account,
281
+ chain: client.chain,
282
+ ...txParams
283
+ });
284
+ const receipt = await walletClient.waitForTransactionReceipt({ hash: txHash });
285
+ logger$7("Tx receipt %o", receipt);
286
+ if (receipt.status === "reverted") {
287
+ try {
288
+ await walletClient.simulateContract({
289
+ address: ARKIV_ADDRESS,
290
+ abi: EXECUTE_ABI,
291
+ functionName: "execute",
292
+ args: [operations],
293
+ account: client.account,
294
+ chain: client.chain
295
+ });
296
+ } catch (err) {
297
+ const error = err;
298
+ const reason = error.shortMessage ?? error.cause?.details ?? "No reason provided by backend.";
299
+ throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. Reason: ${reason}`);
300
+ }
301
+ throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. No reason provided by backend.`);
302
+ }
303
+ return {
304
+ receipt,
305
+ createdEntityKeys
306
+ };
307
+ } catch (error) {
308
+ let message = "Transaction failed";
309
+ if (error instanceof TransactionExecutionError) message += `: ${error.details}`;
310
+ else if (error instanceof ContractFunctionExecutionError) {
311
+ logger$7("Contract function execution error data:", error.shortMessage);
312
+ if (error.cause instanceof ContractFunctionRevertedError) message += `: ${error.cause.message}`;
313
+ else message += ": Execution error without revert data";
314
+ } else if (error instanceof EntityMutationError) throw error;
315
+ throw new EntityMutationError(message);
316
+ }
317
+ }
318
+
319
+ //#endregion
320
+ //#region src/actions/public/subscribeEntityEvents.ts
321
+ const logger$6 = getLogger("actions:public:subscribe-entity-events");
322
+ const arkivABI = ENTITY_OPERATION_EVENT_ABI;
111
323
  async function subscribeEntityEvents(client, { onError, onEntityCreated, onEntityUpdated, onEntityDeleted, onEntityExpired, onEntityExpiresInExtended, onEntityOwnerChanged }, pollingInterval, fromBlock) {
112
324
  return client.watchEvent({
113
325
  pollingInterval: pollingInterval ?? 1e3,
114
326
  fromBlock,
115
327
  events: arkivABI,
116
328
  onLogs: (logs) => {
117
- logger$8("logs from subscribeEntityEvents %o", logs);
329
+ logger$6("logs from subscribeEntityEvents %o", logs);
118
330
  for (const log of logs) {
119
331
  const event = decodeEventLog({
120
332
  abi: arkivABI,
121
333
  topics: log.topics,
122
334
  data: log.data
123
335
  });
124
- logger$8("event from subscribeEntityEvents %o", event);
125
- switch (event.eventName) {
126
- case "ArkivEntityCreated":
336
+ logger$6("event from subscribeEntityEvents %o", event);
337
+ if (event.eventName !== "EntityOperation") continue;
338
+ const entityKey = event.args.entityKey;
339
+ const owner = event.args.owner;
340
+ const expiresAt = event.args.expiresAt;
341
+ const entityHash = event.args.entityHash;
342
+ switch (Number(event.args.operationType)) {
343
+ case EntityOperationType.Create:
127
344
  onEntityCreated?.({
128
- entityKey: toHex(event.args.entityKey, { size: 32 }),
129
- owner: event.args.ownerAddress,
130
- expirationBlock: Number(event.args.expirationBlock),
131
- cost: event.args.cost
345
+ entityKey,
346
+ owner,
347
+ expiresAt,
348
+ entityHash
132
349
  });
133
350
  break;
134
- case "ArkivEntityUpdated":
351
+ case EntityOperationType.Update:
135
352
  onEntityUpdated?.({
136
- entityKey: toHex(event.args.entityKey, { size: 32 }),
137
- owner: event.args.ownerAddress,
138
- oldExpirationBlock: Number(event.args.oldExpirationBlock),
139
- newExpirationBlock: Number(event.args.newExpirationBlock),
140
- cost: event.args.cost
353
+ entityKey,
354
+ owner,
355
+ expiresAt,
356
+ entityHash
141
357
  });
142
358
  break;
143
- case "ArkivEntityDeleted":
144
- onEntityDeleted?.({
145
- entityKey: toHex(event.args.entityKey, { size: 32 }),
146
- owner: event.args.ownerAddress
147
- });
148
- break;
149
- case "ArkivEntityBTLExtended":
359
+ case EntityOperationType.Extend:
150
360
  onEntityExpiresInExtended?.({
151
- entityKey: toHex(event.args.entityKey, { size: 32 }),
152
- owner: event.args.ownerAddress,
153
- oldExpirationBlock: Number(event.args.oldExpirationBlock),
154
- newExpirationBlock: Number(event.args.newExpirationBlock),
155
- cost: event.args.cost
361
+ entityKey,
362
+ owner,
363
+ expiresAt,
364
+ entityHash
156
365
  });
157
366
  break;
158
- case "ArkivEntityExpired":
159
- onEntityExpired?.({
160
- entityKey: toHex(event.args.entityKey, { size: 32 }),
161
- owner: event.args.ownerAddress
367
+ case EntityOperationType.Transfer:
368
+ onEntityOwnerChanged?.({
369
+ entityKey,
370
+ owner,
371
+ entityHash
162
372
  });
163
373
  break;
164
- case "ArkivEntityOwnerChanged":
165
- onEntityOwnerChanged?.({
166
- entityKey: toHex(event.args.entityKey, { size: 32 }),
167
- oldOwner: event.args.oldOwnerAddress,
168
- newOwner: event.args.newOwnerAddress
374
+ case EntityOperationType.Delete:
375
+ onEntityDeleted?.({
376
+ entityKey,
377
+ owner
169
378
  });
170
379
  break;
171
380
  default:
172
- console.warn("unknown event from subscribeEntityEvents", event);
381
+ onEntityExpired?.({
382
+ entityKey,
383
+ owner
384
+ });
173
385
  break;
174
386
  }
175
387
  }
@@ -232,178 +444,12 @@ function createPublicClient(parameters) {
232
444
  }).extend(publicActions).extend(publicArkivActions);
233
445
  }
234
446
 
235
- //#endregion
236
- //#region src/utils/compression.ts
237
- const logger$7 = getLogger("utils:compression");
238
- const isNode = typeof process !== "undefined" && process.versions?.node != null;
239
- let zlib = null;
240
- let brotli = null;
241
- async function getZlib() {
242
- if (!isNode) return null;
243
- if (!zlib) try {
244
- zlib = await import("zlib");
245
- } catch (error) {
246
- console.error("Error importing zlib", error);
247
- return null;
248
- }
249
- return zlib;
250
- }
251
- async function getBrotli() {
252
- if (brotli) return brotli;
253
- try {
254
- const brotliModule = await import("brotli-wasm");
255
- brotli = brotliModule.default ? await brotliModule.default : brotliModule;
256
- } catch (error) {
257
- console.error("Error importing brotli-wasm", error);
258
- return null;
259
- }
260
- return brotli;
261
- }
262
- async function compress(data) {
263
- logger$7("Compressing data size %d", data.length);
264
- if (isNode) {
265
- const zlibModule = await getZlib();
266
- if (zlibModule) try {
267
- const buffer = Buffer.from(data);
268
- const compressed = zlibModule.brotliCompressSync(buffer);
269
- const result = new Uint8Array(compressed);
270
- logger$7("Brotli compressed with zlib size %d", result.length);
271
- return result;
272
- } catch (error) {
273
- console.warn("zlib compression failed, falling back to brotli-wasm", error);
274
- }
275
- }
276
- const brotliInstance = await getBrotli();
277
- if (!brotliInstance) {
278
- console.warn("Brotli instance not found, not compressing data");
279
- return data;
280
- }
281
- const brotliCompressed = brotliInstance.compress(data);
282
- logger$7("Brotli compressed with wasm size %d", brotliCompressed.length);
283
- return brotliCompressed;
284
- }
285
-
286
- //#endregion
287
- //#region src/utils/validation.ts
288
- /**
289
- * Expiration on Arkiv is measured in blocks (1 block =
290
- * 2 seconds), so the value must be a positive integer that is
291
- * a multiple of the block time.
292
- *
293
- * @param expiresIn - The expiration in seconds.
294
- * @throws {InvalidExpirationError} If the value is not a positive integer that
295
- * is a multiple of the block time.
296
- */
297
- function validateExpiresIn(expiresIn) {
298
- if (!Number.isInteger(expiresIn) || expiresIn <= 0 || expiresIn % BLOCK_TIME !== 0) throw new InvalidExpirationError(expiresIn);
299
- }
300
- /**
301
- * Validates a single attribute. Arkiv supports string and number attribute
302
- * values, but numeric values must be integers.
303
- *
304
- * @param attribute - The attribute to validate.
305
- * @throws {InvalidAttributeError} If the attribute has a non-integer numeric
306
- * value.
307
- */
308
- function validateAttribute(attribute) {
309
- if (typeof attribute.value === "number" && !Number.isInteger(attribute.value)) throw new InvalidAttributeError(attribute.key, attribute.value);
310
- }
311
-
312
- //#endregion
313
- //#region src/utils/arkivTransactions.ts
314
- const logger$6 = getLogger("utils:arkiv-transactions");
315
- function opsToTxData({ creates, updates, deletes, extensions, ownershipChanges }) {
316
- function formatAttributes(attribute) {
317
- return [toHex(attribute.key), toHex(typeof attribute.value === "number" && attribute.value === 0 ? "" : attribute.value)];
318
- }
319
- const payload = [
320
- (creates ?? []).map((item) => {
321
- validateExpiresIn(item.expiresIn);
322
- item.attributes.forEach(validateAttribute);
323
- return [
324
- toHex(item.expiresIn / BLOCK_TIME),
325
- toHex(item.contentType),
326
- toHex(item.payload),
327
- item.attributes.filter((attribute) => typeof attribute.value === "string").map(formatAttributes),
328
- item.attributes.filter((attribute) => typeof attribute.value === "number").map(formatAttributes)
329
- ];
330
- }),
331
- (updates ?? []).map((item) => {
332
- validateExpiresIn(item.expiresIn);
333
- item.attributes.forEach(validateAttribute);
334
- return [
335
- item.entityKey,
336
- toHex(item.contentType),
337
- toHex(item.expiresIn / BLOCK_TIME),
338
- toHex(item.payload),
339
- item.attributes.filter((attribute) => typeof attribute.value === "string").map(formatAttributes),
340
- item.attributes.filter((attribute) => typeof attribute.value === "number").map(formatAttributes)
341
- ];
342
- }),
343
- (deletes ?? []).map((item) => item.entityKey),
344
- (extensions ?? []).map((item) => {
345
- validateExpiresIn(item.expiresIn);
346
- return [item.entityKey, toHex(item.expiresIn / BLOCK_TIME)];
347
- }),
348
- (ownershipChanges ?? []).map((item) => [item.entityKey, item.newOwner])
349
- ];
350
- logger$6("txData to send as RLP %o length %d", payload, payload.length);
351
- return toRlp(payload);
352
- }
353
- async function sendArkivTransaction(client, data, txParams) {
354
- if (!client.account) throw new Error("Account required");
355
- const walletClient = client;
356
- logger$6("Sending transaction %o", {
357
- account: client.account,
358
- chain: client.chain,
359
- to: ARKIV_ADDRESS,
360
- value: 0n,
361
- data,
362
- ...txParams
363
- });
364
- try {
365
- const compressed = await compress(toBytes(data));
366
- const txHash = await walletClient.sendTransaction({
367
- account: client.account,
368
- chain: client.chain,
369
- to: ARKIV_ADDRESS,
370
- value: 0n,
371
- data: toHex(compressed),
372
- ...txParams
373
- });
374
- const receipt = await walletClient.waitForTransactionReceipt({ hash: txHash });
375
- logger$6("Tx receipt %o", receipt);
376
- if (receipt.status === "reverted") try {
377
- const callResult = await walletClient.call({
378
- account: client.account,
379
- to: ARKIV_ADDRESS,
380
- value: 0n,
381
- data: toHex(compressed),
382
- ...txParams
383
- });
384
- throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. Please make sure the data for entities doesn't contain invalid characters or invalid data types.
385
- Reason: ${callResult.data ? hexToString(callResult.data) : "No reason provided by backend."}`);
386
- } catch (err) {
387
- const reason = err.cause?.details ?? "No reason provided by backend.";
388
- logger$6("Error while calling to get more details about reverted transaction. Reason: %s", reason);
389
- throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. Reason: ${reason}`);
390
- }
391
- return receipt;
392
- } catch (error) {
393
- let message = "Transaction failed";
394
- if (error instanceof TransactionExecutionError) message += `: ${error.details}`;
395
- else if (error instanceof EntityMutationError) throw error;
396
- logger$6("%s Detailed error stack: %o", message, error);
397
- throw new EntityMutationError(message);
398
- }
399
- }
400
-
401
447
  //#endregion
402
448
  //#region src/actions/wallet/changeOwnership.ts
403
449
  const logger$5 = getLogger("actions:wallet:change-ownership");
404
450
  async function changeOwnership(client, data, txParams) {
405
451
  logger$5("changeOwnership %o", data);
406
- const receipt = await sendArkivTransaction(client, opsToTxData({ ownershipChanges: [data] }), txParams);
452
+ const { receipt } = await sendArkivTransaction(client, { ownershipChanges: [data] }, txParams);
407
453
  logger$5("Receipt from changeOwnership %o", receipt);
408
454
  return {
409
455
  txHash: receipt.transactionHash,
@@ -416,11 +462,11 @@ async function changeOwnership(client, data, txParams) {
416
462
  const logger$4 = getLogger("actions:wallet:create-entity");
417
463
  async function createEntity(client, data, txParams) {
418
464
  logger$4("createEntity %o", data);
419
- const receipt = await sendArkivTransaction(client, opsToTxData({ creates: [data] }), txParams);
465
+ const { receipt, createdEntityKeys } = await sendArkivTransaction(client, { creates: [data] }, txParams);
420
466
  logger$4("Receipt from createEntity %o", receipt);
421
467
  return {
422
468
  txHash: receipt.transactionHash,
423
- entityKey: receipt.logs[0].topics[1]
469
+ entityKey: createdEntityKeys[0]
424
470
  };
425
471
  }
426
472
 
@@ -429,7 +475,7 @@ async function createEntity(client, data, txParams) {
429
475
  const logger$3 = getLogger("actions:wallet:delete-entity");
430
476
  async function deleteEntity(client, data, txParams) {
431
477
  logger$3("deleteEntity %o", data);
432
- const receipt = await sendArkivTransaction(client, opsToTxData({ deletes: [data] }), txParams);
478
+ const { receipt } = await sendArkivTransaction(client, { deletes: [data] }, txParams);
433
479
  logger$3("Receipt from deleteEntity %o", receipt);
434
480
  return {
435
481
  txHash: receipt.transactionHash,
@@ -442,61 +488,28 @@ async function deleteEntity(client, data, txParams) {
442
488
  const logger$2 = getLogger("actions:wallet:extend-entity");
443
489
  async function extendEntity(client, data, txParams) {
444
490
  logger$2("extendEntity %o", data);
445
- const receipt = await sendArkivTransaction(client, opsToTxData({ extensions: [data] }), txParams);
491
+ const { receipt } = await sendArkivTransaction(client, { extensions: [data] }, txParams);
446
492
  logger$2("Receipt from extendEntity %o", receipt);
447
493
  return {
448
494
  txHash: receipt.transactionHash,
449
- entityKey: receipt.logs[0].topics[1]
495
+ entityKey: data.entityKey
450
496
  };
451
497
  }
452
498
 
453
499
  //#endregion
454
500
  //#region src/actions/wallet/mutateEntities.ts
455
501
  const logger$1 = getLogger("actions:wallet:mutate-entities");
456
- function parseReceipt(receipt, params) {
457
- const createdEntities = [];
458
- const updatedEntities = [];
459
- const deletedEntities = [];
460
- const extendedEntities = [];
461
- const ownershipChanges = [];
462
- const totalCreates = params.creates?.length ?? 0;
463
- const totalUpdates = params.updates?.length ?? 0;
464
- const totalDeletes = params.deletes?.length ?? 0;
465
- const totalExtensions = params.extensions?.length ?? 0;
466
- for (let index = 0; index < receipt.logs.length; index++) {
467
- const log = receipt.logs[index];
468
- if (index < totalCreates) createdEntities.push(log.topics[1]);
469
- else if (index < totalCreates + totalDeletes) deletedEntities.push(log.topics[1]);
470
- else if (index < totalCreates + totalUpdates + totalDeletes) updatedEntities.push(log.topics[1]);
471
- else if (index < totalCreates + totalUpdates + totalDeletes + totalExtensions) extendedEntities.push(log.topics[1]);
472
- else ownershipChanges.push(log.topics[1]);
473
- }
474
- return {
475
- createdEntities,
476
- updatedEntities,
477
- deletedEntities,
478
- extendedEntities,
479
- ownershipChanges
480
- };
481
- }
482
502
  async function mutateEntities(client, data, txParams) {
483
503
  if (!data.creates && !data.updates && !data.deletes && !data.extensions) throw new Error("No operations to perform");
484
- const receipt = await sendArkivTransaction(client, opsToTxData({
485
- creates: data.creates ?? [],
486
- updates: data.updates ?? [],
487
- deletes: data.deletes ?? [],
488
- extensions: data.extensions ?? [],
489
- ownershipChanges: data.ownershipChanges ?? []
490
- }), txParams);
504
+ const { receipt, createdEntityKeys } = await sendArkivTransaction(client, data, txParams);
491
505
  logger$1("Receipt from mutateEntities %o", receipt);
492
- const { createdEntities, updatedEntities, deletedEntities, extendedEntities, ownershipChanges } = parseReceipt(receipt, data);
493
506
  return {
494
507
  txHash: receipt.transactionHash,
495
- createdEntities,
496
- updatedEntities,
497
- deletedEntities,
498
- extendedEntities,
499
- ownershipChanges
508
+ createdEntities: createdEntityKeys,
509
+ updatedEntities: (data.updates ?? []).map((u) => u.entityKey),
510
+ deletedEntities: (data.deletes ?? []).map((d) => d.entityKey),
511
+ extendedEntities: (data.extensions ?? []).map((e) => e.entityKey),
512
+ ownershipChanges: (data.ownershipChanges ?? []).map((o) => o.entityKey)
500
513
  };
501
514
  }
502
515
 
@@ -505,11 +518,11 @@ async function mutateEntities(client, data, txParams) {
505
518
  const logger = getLogger("actions:wallet:update-entity");
506
519
  async function updateEntity(client, data, txParams) {
507
520
  logger("updateEntity %o", data);
508
- const receipt = await sendArkivTransaction(client, opsToTxData({ updates: [data] }), txParams);
521
+ const { receipt } = await sendArkivTransaction(client, { updates: [data] }, txParams);
509
522
  logger("Receipt from updateEntity %o", receipt);
510
523
  return {
511
524
  txHash: receipt.transactionHash,
512
- entityKey: receipt.logs[0].topics[1]
525
+ entityKey: data.entityKey
513
526
  };
514
527
  }
515
528
 
@@ -572,5 +585,5 @@ function chainFromName(name) {
572
585
  }
573
586
 
574
587
  //#endregion
575
- export { EntityMutationError, InvalidAttributeError, InvalidExpirationError, NoCursorOrLimitError, NoEntityFoundError, NoMoreResultsError, chainFromName, createPublicClient, createWalletClient, jsonToPayload, stringToPayload };
588
+ export { DuplicateAttributeError, EntityMutationError, EntityOperationType, InvalidAttributeError, InvalidAttributeKeyError, InvalidContentTypeError, InvalidExpirationError, NoCursorOrLimitError, NoEntityFoundError, NoMoreResultsError, chainFromName, createPublicClient, createWalletClient, jsonToPayload, stringToPayload };
576
589
  //# sourceMappingURL=index.js.map