@arkiv-network/sdk 0.7.0-dev.1 → 0.8.0-advanced.2

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 (237) hide show
  1. package/README.md +71 -16
  2. package/dist/actions/advanced/index.cjs +13 -0
  3. package/dist/actions/advanced/index.d.cts +8 -0
  4. package/dist/actions/advanced/index.d.ts +9 -0
  5. package/dist/actions/advanced/index.js +9 -0
  6. package/dist/advanced-8ZPTmmaN.js +598 -0
  7. package/dist/advanced-8ZPTmmaN.js.map +1 -0
  8. package/dist/advanced-fPImL6lW.cjs +656 -0
  9. package/dist/arkivTransactions-D74gERHG.d.cts +571 -0
  10. package/dist/arkivTransactions-D74gERHG.d.cts.map +1 -0
  11. package/dist/arkivTransactions-NtGD6uk5.d.ts +571 -0
  12. package/dist/arkivTransactions-NtGD6uk5.d.ts.map +1 -0
  13. package/dist/attr/index.cjs +35 -0
  14. package/dist/attr/index.d.cts +2 -0
  15. package/dist/attr/index.d.ts +3 -0
  16. package/dist/attr/index.js +4 -0
  17. package/dist/attributes-BhY5DwJp.js +809 -0
  18. package/dist/attributes-BhY5DwJp.js.map +1 -0
  19. package/dist/attributes-Df9IsCVs.cjs +1029 -0
  20. package/dist/chains/index.cjs +2 -3
  21. package/dist/chains/index.d.cts +22 -60
  22. package/dist/chains/index.d.cts.map +1 -1
  23. package/dist/chains/index.d.ts +22 -60
  24. package/dist/chains/index.d.ts.map +1 -1
  25. package/dist/chains/index.js +2 -2
  26. package/dist/chains-BJrZs6sG.js +57 -0
  27. package/dist/chains-BJrZs6sG.js.map +1 -0
  28. package/dist/chains-BYRTTipa.cjs +73 -0
  29. package/dist/codec-Car3KkFF.d.ts +102 -0
  30. package/dist/codec-Car3KkFF.d.ts.map +1 -0
  31. package/dist/entity/index.cjs +20 -0
  32. package/dist/entity/index.d.cts +4 -0
  33. package/dist/entity/index.d.ts +5 -0
  34. package/dist/entity/index.js +7 -0
  35. package/dist/entity-B00Li04j.cjs +71 -0
  36. package/dist/entity-B7G8q_Eo.cjs +0 -0
  37. package/dist/entity-BYQR1uoe.js +67 -0
  38. package/dist/entity-BYQR1uoe.js.map +1 -0
  39. package/dist/entity-CD_qFF2M.js +0 -0
  40. package/dist/errors-BVbjKVMN.cjs +56 -0
  41. package/dist/errors-LTe7bOYS.js +33 -0
  42. package/dist/errors-LTe7bOYS.js.map +1 -0
  43. package/dist/expiry-BELY2Kpw.cjs +135 -0
  44. package/dist/expiry-BjpxZZQU.js +95 -0
  45. package/dist/expiry-BjpxZZQU.js.map +1 -0
  46. package/dist/expiry-DRV29F1r.d.cts +79 -0
  47. package/dist/expiry-DRV29F1r.d.cts.map +1 -0
  48. package/dist/expiry-nDbCgZX4.d.ts +79 -0
  49. package/dist/expiry-nDbCgZX4.d.ts.map +1 -0
  50. package/dist/flags-5dTNRnow.d.ts +41 -0
  51. package/dist/flags-5dTNRnow.d.ts.map +1 -0
  52. package/dist/flags-CRjPpoh3.d.cts +41 -0
  53. package/dist/flags-CRjPpoh3.d.cts.map +1 -0
  54. package/dist/flags-DFBs2J94.js +33 -0
  55. package/dist/flags-DFBs2J94.js.map +1 -0
  56. package/dist/flags-kr276q6i.cjs +43 -0
  57. package/dist/index-B5j76711.d.ts +184 -0
  58. package/dist/index-B5j76711.d.ts.map +1 -0
  59. package/dist/index-BF7Mq9Is.d.cts +280 -0
  60. package/dist/index-BF7Mq9Is.d.cts.map +1 -0
  61. package/dist/index-CA4V7Pdh.d.cts +167 -0
  62. package/dist/index-CA4V7Pdh.d.cts.map +1 -0
  63. package/dist/index-CV5zCdpa.d.cts +417 -0
  64. package/dist/index-CV5zCdpa.d.cts.map +1 -0
  65. package/dist/index-DHDud2hC.d.ts +280 -0
  66. package/dist/index-DHDud2hC.d.ts.map +1 -0
  67. package/dist/index-DvYvrkdk.d.ts +320 -0
  68. package/dist/index-DvYvrkdk.d.ts.map +1 -0
  69. package/dist/index-EeUO0nnJ.d.cts +184 -0
  70. package/dist/index-EeUO0nnJ.d.cts.map +1 -0
  71. package/dist/index-fX_XyqLp.d.ts +167 -0
  72. package/dist/index-fX_XyqLp.d.ts.map +1 -0
  73. package/dist/index.cjs +411 -405
  74. package/dist/index.d.cts +360 -209
  75. package/dist/index.d.cts.map +1 -1
  76. package/dist/index.d.ts +361 -209
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +342 -387
  79. package/dist/index.js.map +1 -1
  80. package/dist/key-D1Bh7MF0.js +70 -0
  81. package/dist/key-D1Bh7MF0.js.map +1 -0
  82. package/dist/key-WKhXnXuU.cjs +98 -0
  83. package/dist/logger-CVpvU8ik.js +153 -0
  84. package/dist/logger-CVpvU8ik.js.map +1 -0
  85. package/dist/logger-Cr15lPAQ.cjs +188 -0
  86. package/dist/payload-BNoud2KZ.d.cts +94 -0
  87. package/dist/payload-BNoud2KZ.d.cts.map +1 -0
  88. package/dist/payload-Bz6651ax.js +67 -0
  89. package/dist/payload-Bz6651ax.js.map +1 -0
  90. package/dist/payload-CcUj85ys.d.ts +94 -0
  91. package/dist/payload-CcUj85ys.d.ts.map +1 -0
  92. package/dist/payload-KC14SDlN.cjs +83 -0
  93. package/dist/query/index.cjs +26 -150
  94. package/dist/query/index.d.cts +5 -3
  95. package/dist/query/index.d.ts +6 -3
  96. package/dist/query/index.js +8 -138
  97. package/dist/queryBuilder-DM6AWCBa.js +820 -0
  98. package/dist/queryBuilder-DM6AWCBa.js.map +1 -0
  99. package/dist/queryBuilder-DbUMEZln.cjs +944 -0
  100. package/dist/selection-C4UhsMOO.d.ts +434 -0
  101. package/dist/selection-C4UhsMOO.d.ts.map +1 -0
  102. package/dist/selection-DPg0uyJf.d.cts +433 -0
  103. package/dist/selection-DPg0uyJf.d.cts.map +1 -0
  104. package/dist/types/index.cjs +3 -3
  105. package/dist/types/index.d.cts +7 -2
  106. package/dist/types/index.d.ts +8 -2
  107. package/dist/types/index.js +3 -3
  108. package/dist/types-Bu_ZwMbZ.js +0 -0
  109. package/dist/types-NRqymi6S.cjs +0 -0
  110. package/dist/utils/index.cjs +4 -17
  111. package/dist/utils/index.d.cts +3 -17
  112. package/dist/utils/index.d.ts +3 -17
  113. package/dist/utils/index.js +4 -18
  114. package/package.json +26 -5
  115. package/src/actions/advanced/advanced.test.ts +258 -0
  116. package/src/actions/advanced/buildMutation.ts +104 -0
  117. package/src/actions/advanced/getMutationResult.ts +112 -0
  118. package/src/actions/advanced/index.ts +21 -0
  119. package/src/actions/advanced/pingTransaction.ts +43 -0
  120. package/src/actions/advanced/sendMutation.ts +59 -0
  121. package/src/actions/public/getEntity.ts +27 -43
  122. package/src/actions/public/getEntityNonce.ts +30 -0
  123. package/src/actions/public/predictEntityKeys.test.ts +143 -0
  124. package/src/actions/public/predictEntityKeys.ts +138 -0
  125. package/src/actions/public/query.ts +35 -67
  126. package/src/actions/public/watchEntityEvents.test.ts +414 -0
  127. package/src/actions/public/watchEntityEvents.ts +225 -0
  128. package/src/actions/wallet/changeOwnership.ts +2 -2
  129. package/src/actions/wallet/createEntity.ts +99 -24
  130. package/src/actions/wallet/extendEntity.ts +37 -13
  131. package/src/actions/wallet/mutateEntities.test.ts +76 -0
  132. package/src/actions/wallet/mutateEntities.ts +16 -33
  133. package/src/actions/wallet/patchEntity.ts +90 -0
  134. package/src/attr/attributes.test.ts +120 -0
  135. package/src/attr/attributes.ts +190 -0
  136. package/src/attr/codec.test.ts +162 -0
  137. package/src/attr/codec.ts +220 -0
  138. package/src/attr/decimal.ts +86 -0
  139. package/src/attr/errors.ts +145 -0
  140. package/src/attr/index.ts +50 -0
  141. package/src/attr/names.ts +106 -0
  142. package/src/attr/types.ts +150 -0
  143. package/src/attr/values.test.ts +271 -0
  144. package/src/attr/values.ts +502 -0
  145. package/src/chains/cheesecake.ts +22 -0
  146. package/src/chains/index.ts +1 -2
  147. package/src/clients/createPublicClient.test.ts +3 -5
  148. package/src/clients/createPublicClient.ts +5 -4
  149. package/src/clients/createWalletClient.test.ts +2 -2
  150. package/src/clients/createWalletClient.ts +13 -7
  151. package/src/clients/decorators/arkivAdvanced.ts +144 -0
  152. package/src/clients/decorators/arkivPublic.ts +172 -139
  153. package/src/clients/decorators/arkivWallet.ts +101 -94
  154. package/src/entity/create.test.ts +184 -0
  155. package/src/entity/errors.ts +38 -0
  156. package/src/entity/events.ts +16 -0
  157. package/src/entity/expiry.test.ts +195 -0
  158. package/src/entity/expiry.ts +181 -0
  159. package/src/entity/flags.ts +65 -0
  160. package/src/entity/index.ts +15 -0
  161. package/src/entity/key.ts +68 -0
  162. package/src/entity/operations.ts +134 -0
  163. package/src/entity/params.ts +15 -0
  164. package/src/errors.ts +26 -49
  165. package/src/index.ts +19 -0
  166. package/src/query/engine.ts +68 -137
  167. package/src/query/errors.ts +151 -0
  168. package/src/query/expression.test.ts +286 -0
  169. package/src/query/expression.ts +493 -0
  170. package/src/query/index.ts +40 -4
  171. package/src/query/injection.test.ts +151 -0
  172. package/src/query/queryBuilder.test.ts +342 -637
  173. package/src/query/queryBuilder.ts +133 -359
  174. package/src/query/queryResult.ts +54 -51
  175. package/src/query/selection.test.ts +48 -98
  176. package/src/query/selection.ts +77 -65
  177. package/src/types/entity.test.ts +44 -155
  178. package/src/types/entity.ts +60 -52
  179. package/src/types/events.ts +59 -16
  180. package/src/types/index.ts +20 -17
  181. package/src/types/rpcSchema.ts +69 -37
  182. package/src/utils/arkivTransactions.test.ts +600 -155
  183. package/src/utils/arkivTransactions.ts +350 -219
  184. package/src/utils/chains.test.ts +21 -24
  185. package/src/utils/compression.ts +1 -1
  186. package/src/utils/entities.test.ts +62 -0
  187. package/src/utils/entities.ts +109 -37
  188. package/src/utils/expirationTime.ts +114 -10
  189. package/src/utils/logger.ts +2 -2
  190. package/src/utils/revert.test.ts +99 -0
  191. package/src/utils/revert.ts +145 -0
  192. package/dist/chains-BifaY04V.cjs +0 -108
  193. package/dist/chains-CrtkVbBh.js +0 -86
  194. package/dist/chains-CrtkVbBh.js.map +0 -1
  195. package/dist/consts-Bz0LZQZY.js +0 -7
  196. package/dist/consts-Bz0LZQZY.js.map +0 -1
  197. package/dist/consts-CxT1-RXU.cjs +0 -18
  198. package/dist/entity-BhSXaB23.cjs +0 -81
  199. package/dist/entity-CN41IOrq.d.cts +0 -401
  200. package/dist/entity-CN41IOrq.d.cts.map +0 -1
  201. package/dist/entity-DGfVyB-a.js +0 -71
  202. package/dist/entity-DGfVyB-a.js.map +0 -1
  203. package/dist/entity-NnEVlePN.d.ts +0 -401
  204. package/dist/entity-NnEVlePN.d.ts.map +0 -1
  205. package/dist/index-ClkpS6s_.d.ts +0 -481
  206. package/dist/index-ClkpS6s_.d.ts.map +0 -1
  207. package/dist/index-w4qop0Pe.d.cts +0 -481
  208. package/dist/index-w4qop0Pe.d.cts.map +0 -1
  209. package/dist/payload-BpNUPOnY.js +0 -13
  210. package/dist/payload-BpNUPOnY.js.map +0 -1
  211. package/dist/payload-C2KHOUoj.d.ts +0 -6
  212. package/dist/payload-C2KHOUoj.d.ts.map +0 -1
  213. package/dist/payload-CJN8fTvX.d.cts +0 -6
  214. package/dist/payload-CJN8fTvX.d.cts.map +0 -1
  215. package/dist/payload-D8YLKcJj.cjs +0 -23
  216. package/dist/query/index.js.map +0 -1
  217. package/dist/queryBuilder-BE_XhLLa.js +0 -735
  218. package/dist/queryBuilder-BE_XhLLa.js.map +0 -1
  219. package/dist/queryBuilder-J37buGCi.cjs +0 -865
  220. package/dist/utils/index.d.cts.map +0 -1
  221. package/dist/utils/index.d.ts.map +0 -1
  222. package/dist/utils/index.js.map +0 -1
  223. package/src/actions/public/buildQuery.ts +0 -10
  224. package/src/actions/public/subscribeEntityEvents.ts +0 -93
  225. package/src/actions/wallet/updateEntity.ts +0 -59
  226. package/src/chains/braga.ts +0 -26
  227. package/src/chains/kaolin.ts +0 -29
  228. package/src/query/engine.test.ts +0 -571
  229. package/src/query/predicate.test.ts +0 -461
  230. package/src/query/predicate.ts +0 -144
  231. package/src/query/queryResult.test.ts +0 -270
  232. package/src/query/selectQueryBuilder.test.ts +0 -213
  233. package/src/types/attributes.ts +0 -28
  234. package/src/utils/validation.test.ts +0 -106
  235. package/src/utils/validation.ts +0 -80
  236. /package/dist/{types-Ci4BRClw.js → attr-DlmErkvR.cjs} +0 -0
  237. /package/dist/{types-a8gm_IaQ.cjs → attr-GcQKatub.js} +0 -0
@@ -0,0 +1,598 @@
1
+ import { a as OperationType, n as resolveExpiry, o as ARKIV_ADDRESS } from "./expiry-BjpxZZQU.js";
2
+ import { i as encodeMutations, r as encodeAttributes } from "./attributes-BhY5DwJp.js";
3
+ import { a as ENTITY_EVENTS_ABI, i as validateSalt, r as randomSalt } from "./key-D1Bh7MF0.js";
4
+ import { n as encodeCreationFlags } from "./flags-DFBs2J94.js";
5
+ import { i as InvalidContentTypeError, n as EmptyPatchError, r as EntityMutationError, t as getLogger } from "./logger-CVpvU8ik.js";
6
+ import { BaseError, ContractFunctionExecutionError, ContractFunctionRevertedError, TransactionExecutionError, TransactionReceiptNotFoundError, decodeEventLog, encodeAbiParameters, encodeFunctionData, hexToString, parseAbi, parseAbiParameters } from "viem";
7
+
8
+ //#region src/entity/operations.ts
9
+ /**
10
+ * The one external entry point. A transaction is an ordered, **atomic** batch of entity operations:
11
+ * all of them apply or none do, operation *n+1* observes operation *n*'s effects, and each applied
12
+ * operation emits one event.
13
+ */
14
+ const EXECUTE_ABI = parseAbi(["function execute((uint8 operation, bytes operationData)[] ops) external returns (bytes32[] keys)"]);
15
+ /**
16
+ * The engine's one read-only view: an owner's entity-minting nonce, which is the input
17
+ * {@link predictEntityKey} needs and the only part of the derivation the caller cannot know.
18
+ *
19
+ * It is a `view` on the same address `execute` is called on, so it answers over `eth_call` without
20
+ * a transaction.
21
+ */
22
+ const ENTITY_NONCE_ABI = parseAbi(["function entityNonce(address owner) external view returns (uint64)"]);
23
+ /**
24
+ * The shared attribute shape, used by `create` (attributes) and `patch` (mutations). Written out
25
+ * once and reused by every payload that carries attributes.
26
+ */
27
+ const ATTRIBUTE_TUPLE = "(bytes32 name, uint8 typeId, bytes value)[]";
28
+ /**
29
+ * The payload struct for each operation tag. `operationData` is `abi.encode` of the struct the tag
30
+ * selects — a tagged union, so a new operation is additive rather than a change to `execute`.
31
+ */
32
+ const PAYLOAD_PARAMS = {
33
+ [OperationType.Create]: parseAbiParameters(`(uint128 salt, uint64 expiresAt, uint64 minLifetime, uint8 creationFlags, ${ATTRIBUTE_TUPLE} attributes)`),
34
+ [OperationType.Patch]: parseAbiParameters(`(bytes32 entityKey, ${ATTRIBUTE_TUPLE} mutations)`),
35
+ [OperationType.ExtendExpiry]: parseAbiParameters("(bytes32 entityKey, uint64 expiresAt, uint64 minLifetime)"),
36
+ [OperationType.TransferOwnership]: parseAbiParameters("(bytes32 entityKey, address newOwner)"),
37
+ [OperationType.Delete]: parseAbiParameters("(bytes32 entityKey)")
38
+ };
39
+ /** Creates an entity. The key is derived by the engine; predict it with `predictEntityKey`. */
40
+ function createOperation({ salt, expiry, creationFlags, attributes }) {
41
+ return {
42
+ operation: OperationType.Create,
43
+ operationData: encodeAbiParameters(PAYLOAD_PARAMS[OperationType.Create], [{
44
+ salt,
45
+ expiresAt: expiry.expiresAt,
46
+ minLifetime: expiry.minLifetime,
47
+ creationFlags,
48
+ attributes
49
+ }])
50
+ };
51
+ }
52
+ /** Applies a set of mutations to an existing entity. Tombstones unset attributes. */
53
+ function patchOperation({ entityKey, mutations }) {
54
+ return {
55
+ operation: OperationType.Patch,
56
+ operationData: encodeAbiParameters(PAYLOAD_PARAMS[OperationType.Patch], [{
57
+ entityKey,
58
+ mutations
59
+ }])
60
+ };
61
+ }
62
+ /** Pushes an entity's expiry further out. Extending is allowed; shortening reverts. */
63
+ function extendExpiryOperation({ entityKey, expiry }) {
64
+ return {
65
+ operation: OperationType.ExtendExpiry,
66
+ operationData: encodeAbiParameters(PAYLOAD_PARAMS[OperationType.ExtendExpiry], [{
67
+ entityKey,
68
+ expiresAt: expiry.expiresAt,
69
+ minLifetime: expiry.minLifetime
70
+ }])
71
+ };
72
+ }
73
+ /** Hands an entity to a new owner. */
74
+ function transferOwnershipOperation({ entityKey, newOwner }) {
75
+ return {
76
+ operation: OperationType.TransferOwnership,
77
+ operationData: encodeAbiParameters(PAYLOAD_PARAMS[OperationType.TransferOwnership], [{
78
+ entityKey,
79
+ newOwner
80
+ }])
81
+ };
82
+ }
83
+ /** Deletes an entity before its expiry. */
84
+ function deleteOperation({ entityKey }) {
85
+ return {
86
+ operation: OperationType.Delete,
87
+ operationData: encodeAbiParameters(PAYLOAD_PARAMS[OperationType.Delete], [{ entityKey }])
88
+ };
89
+ }
90
+
91
+ //#endregion
92
+ //#region src/utils/revert.ts
93
+ /**
94
+ * Turns a decoded engine revert into a sentence that says what to change.
95
+ *
96
+ * viem decodes the error and then renders it positionally — `Ident32InvalidByte(uint256 position,
97
+ * bytes1 value)` arrives as `(5, 0x41)`, which is the right data and no help at all. The engine's
98
+ * errors carry enough to name the actual problem, so this spends the args rather than printing
99
+ * them.
100
+ *
101
+ * @param error - Anything thrown by a write action.
102
+ * @returns The explanation, or `undefined` if this was not a decodable engine revert — in which
103
+ * case the caller should fall back to whatever the transport said.
104
+ */
105
+ function describeEntityRevert(error) {
106
+ if (!(error instanceof BaseError)) return void 0;
107
+ const reverted = error.walk((e) => e instanceof ContractFunctionRevertedError);
108
+ if (!(reverted instanceof ContractFunctionRevertedError)) return void 0;
109
+ const name = reverted.data?.errorName;
110
+ if (name === void 0) return void 0;
111
+ return explain(name, reverted.data?.args ?? []) ?? `the engine rejected the batch with ${name}`;
112
+ }
113
+ /** The attribute-name charset, quoted the way an error message should read. */
114
+ const CHARSET = "\"A\"-\"Z\", \"a\"-\"z\", \"0\"-\"9\", \".\", \"-\" and \"_\", with a letter first";
115
+ function explain(name, args) {
116
+ switch (name) {
117
+ case "Ident32InvalidByte": {
118
+ const position = Number(args[0] ?? 0);
119
+ return `an attribute name holds ${printable(String(args[1] ?? "0x00"))} at byte ${position}, which is outside the name charset (${CHARSET})`;
120
+ }
121
+ case "Ident32Empty": return "an attribute name is empty";
122
+ case "SystemAttributeNotWritable": return `"${identName(args[0])}" is owned by the engine and cannot be written. Only $payload and \$contentType are yours to set`;
123
+ case "TombstoneInCreate": return `a create cannot unset "${identName(args[0])}" — nothing exists yet, so leave the name out instead`;
124
+ case "TombstoneValueNotEmpty": return `the tombstone for "${identName(args[0])}" carries a value; unsetting takes no value`;
125
+ case "InvalidValueType": return `"${identName(args[0])}" names type id ${String(args[1])}, which is not a known type`;
126
+ case "AttributesNotSorted": return "attributes must be strictly ascending by name, which also makes each name unique";
127
+ case "TooManyAttributes": return `${String(args[0])} attributes exceeds the limit of ${String(args[1])}`;
128
+ case "EmptyMutations": return `the patch of ${short(args[0])} has no mutations, so it would do nothing`;
129
+ case "EntityNotFound": return `no entity ${short(args[0])} — it may have been deleted, or have expired`;
130
+ case "EntityExpired": return `entity ${short(args[0])} expired at block ${String(args[1])}`;
131
+ case "NotOwner": return `entity ${short(args[0])} is owned by ${String(args[2])}, not ${String(args[1])}`;
132
+ case "ReadOnlyEntity": return `entity ${short(args[0])} was created readonly, so its contents can never change. Its expiry can still be extended, and it can be transferred or deleted`;
133
+ case "ReservedCreationFlags": return `creation flags 0b${Number(args[0] ?? 0).toString(2).padStart(8, "0")} set a reserved bit; only readonly and permissionlessExtension are defined`;
134
+ case "ExpiryDeadOnArrival": return `the expiry resolves to block ${String(args[0])}, which is not after the current block ${String(args[1])}`;
135
+ case "ExpiryNotExtended": return `entity ${short(args[0])} already expires at block ${String(args[2])}, so extending it to ${String(args[1])} would shorten its life`;
136
+ case "TransferToZeroAddress": return `entity ${short(args[0])} cannot be transferred to the zero address`;
137
+ case "TransferToSelf": return `entity ${short(args[0])} is already owned by that account`;
138
+ case "EmptyBatch": return "the batch has no operations";
139
+ case "InvalidOpType": return `operation tag ${String(args[0])} is not one the engine knows`;
140
+ case "NonCanonicalOperationData": return `the payload for operation tag ${String(args[0])} is not its canonical encoding, so the engine refused it rather than accept a second spelling of the same operation`;
141
+ default: return;
142
+ }
143
+ }
144
+ /** A `bytes32` Ident32 cell as the name it holds — left-aligned, null-padded. */
145
+ function identName(raw) {
146
+ if (typeof raw !== "string") return String(raw);
147
+ try {
148
+ return hexToString(raw).split("\0")[0] ?? "";
149
+ } catch {
150
+ return raw;
151
+ }
152
+ }
153
+ /** An entity key, abbreviated */
154
+ function short(raw) {
155
+ const text = String(raw);
156
+ return text.length > 18 ? `${text.slice(0, 10)}…${text.slice(-6)}` : text;
157
+ }
158
+ /** A `bytes1` as something readable: the character it is, plus the byte it was. */
159
+ function printable(byte) {
160
+ const code = Number.parseInt(byte.replace(/^0x/, ""), 16);
161
+ if (!Number.isFinite(code)) return `byte ${byte}`;
162
+ return code >= 33 && code <= 126 ? `"${String.fromCharCode(code)}" (${byte})` : `byte ${byte}`;
163
+ }
164
+
165
+ //#endregion
166
+ //#region src/utils/arkivTransactions.ts
167
+ const logger$4 = getLogger("utils:arkiv-transactions");
168
+ const MIME_REGEX = /^[a-z][a-z0-9!#$&\-^_]*\/[a-z0-9][a-z0-9!#$&\-^_.+]*$/;
169
+ function validateContentType(contentType) {
170
+ if (!MIME_REGEX.test(contentType)) throw new InvalidContentTypeError(contentType);
171
+ }
172
+ const ENTITY_ERRORS_ABI = parseAbi([
173
+ "error EmptyBatch()",
174
+ "error InvalidOpType(uint8 operation)",
175
+ "error NonCanonicalOperationData(uint8 operation)",
176
+ "error AttributesNotSorted()",
177
+ "error TooManyAttributes(uint256 count, uint256 maxCount)",
178
+ "error EmptyMutations(bytes32 entityKey)",
179
+ "error TombstoneInCreate(bytes32 name)",
180
+ "error TombstoneValueNotEmpty(bytes32 name)",
181
+ "error SystemAttributeNotWritable(bytes32 name)",
182
+ "error InvalidValueType(bytes32 name, uint8 typeId)",
183
+ "error Ident32Empty()",
184
+ "error Ident32InvalidByte(uint256 position, bytes1 value)",
185
+ "error EntityNotFound(bytes32 entityKey)",
186
+ "error EntityExpired(bytes32 entityKey, uint64 expiresAt)",
187
+ "error NotOwner(bytes32 entityKey, address caller, address owner)",
188
+ "error ReadOnlyEntity(bytes32 entityKey)",
189
+ "error ReservedCreationFlags(uint8 creationFlags)",
190
+ "error ExpiryDeadOnArrival(uint64 target, uint64 currentBlock)",
191
+ "error ExpiryNotExtended(bytes32 entityKey, uint64 newExpiresAt, uint64 currentExpiresAt)",
192
+ "error TransferToZeroAddress(bytes32 entityKey)",
193
+ "error TransferToSelf(bytes32 entityKey)"
194
+ ]);
195
+ const EXECUTE_ABI$1 = [...EXECUTE_ABI, ...ENTITY_ERRORS_ABI];
196
+ async function sendArkivTransaction(client, ops, txParams) {
197
+ if (!client.account) throw new Error("Account required");
198
+ if (!client.chain) throw new Error("Chain required");
199
+ const walletClient = client;
200
+ const { creates, extensions } = ops;
201
+ const operations = buildEntityOperations(ops, { currentBlock: creates?.length || extensions?.length ? await walletClient.getBlockNumber() : 0n });
202
+ logger$4("Sending execute with %d operations %o", operations.length, operations);
203
+ const txHash = await submitMutation(client, operations, txParams);
204
+ try {
205
+ const receipt = await walletClient.waitForTransactionReceipt({ hash: txHash });
206
+ logger$4("Tx receipt %o", receipt);
207
+ if (receipt.status === "reverted") {
208
+ try {
209
+ await walletClient.simulateContract({
210
+ address: ARKIV_ADDRESS,
211
+ abi: EXECUTE_ABI$1,
212
+ functionName: "execute",
213
+ args: [operations],
214
+ account: client.account,
215
+ chain: client.chain
216
+ });
217
+ } catch (err) {
218
+ const error = err;
219
+ const reason = describeEntityRevert(err) ?? error.shortMessage ?? error.cause?.details ?? "No reason provided by backend.";
220
+ throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. Reason: ${reason}`);
221
+ }
222
+ throw new EntityMutationError(`Transaction ${receipt.transactionHash} reverted. No reason provided by backend.`);
223
+ }
224
+ return {
225
+ receipt,
226
+ ...readAppliedOperations(receipt, {
227
+ creates: creates?.length ?? 0,
228
+ extensions: extensions?.length ?? 0
229
+ })
230
+ };
231
+ } catch (error) {
232
+ throw asEntityMutationError(error);
233
+ }
234
+ }
235
+ /**
236
+ * Wraps whatever a write step threw into an {@link EntityMutationError} — engine terms when the
237
+ * revert data decodes, the node's own message otherwise. An {@link EntityMutationError} passes
238
+ * through unchanged, so wrapped steps compose without double-wrapping.
239
+ */
240
+ function asEntityMutationError(error) {
241
+ if (error instanceof EntityMutationError) return error;
242
+ const described = describeEntityRevert(error);
243
+ if (described !== void 0) return new EntityMutationError(`Transaction failed: ${described}`, { cause: error });
244
+ let message = "Transaction failed";
245
+ if (error instanceof TransactionExecutionError) message += `: ${error.details}`;
246
+ else if (error instanceof ContractFunctionExecutionError) {
247
+ logger$4("Contract function execution error data:", error.shortMessage);
248
+ if (error.cause instanceof ContractFunctionRevertedError) message += `: ${error.cause.message}`;
249
+ else message += ": Execution error without revert data";
250
+ } else if (error instanceof Error) message += `: ${error.message}`;
251
+ return new EntityMutationError(message, { cause: error });
252
+ }
253
+ /**
254
+ * The keys and expiries the engine recorded, read back from the events the batch emitted.
255
+ */
256
+ function readAppliedOperations(receipt, expected) {
257
+ const events = collectMutationEvents(receipt.logs);
258
+ const createdEntityKeys = events.created.map((e) => e.entityKey);
259
+ const createdExpiries = events.created.map((e) => e.expiresAt);
260
+ const extendedExpiries = events.extended.map((e) => e.expiresAt);
261
+ assertCount(receipt, "create", createdEntityKeys.length, expected.creates);
262
+ assertCount(receipt, "extension", extendedExpiries.length, expected.extensions);
263
+ return {
264
+ createdEntityKeys,
265
+ createdExpiries,
266
+ extendedExpiries
267
+ };
268
+ }
269
+ /** One log as an entity event, or `undefined` for anything this SDK has no name for. */
270
+ function decodeEntityLog(log) {
271
+ try {
272
+ return decodeEventLog({
273
+ abi: ENTITY_EVENTS_ABI,
274
+ topics: log.topics,
275
+ data: log.data
276
+ });
277
+ } catch {
278
+ return;
279
+ }
280
+ }
281
+ function assertCount(receipt, what, got, want) {
282
+ if (got === want) return;
283
+ throw new EntityMutationError(`Transaction ${receipt.transactionHash} succeeded — do not retry it — but emitted ${got} ${what} event(s) for ${want} ${what} operation(s). The batch was applied; the SDK cannot say which entity each operation produced, so read them back to find them.`);
284
+ }
285
+ /**
286
+ * Whether encoding the batch actually requires the chain head.
287
+ *
288
+ * Only a relative lifetime (`minLifetime > 0`) or a wall-clock deadline (a `Date`) is measured
289
+ * from the current block. A purely absolute `atBlock(n)` expiry encodes the same bytes whatever
290
+ * the head is, so a batch of those — or one with no expiries at all — needs no `eth_blockNumber`.
291
+ */
292
+ function mutationNeedsBlockNumber(ops) {
293
+ return [...ops.creates ?? [], ...ops.extensions ?? []].some((item) => {
294
+ const expires = item.expires;
295
+ if (expires === void 0 || typeof expires.minLifetime !== "bigint") return false;
296
+ return expires.minLifetime !== 0n || expires.expiresAt instanceof Date;
297
+ });
298
+ }
299
+ /**
300
+ * Encodes a batch into the `execute` operations, in the order the engine applies them: creates,
301
+ * patches, deletes, extensions, ownership transfers.
302
+ *
303
+ * Pure — every check here is local (content types, salts, expiry bounds, non-empty patches and a
304
+ * non-empty batch), so the only chain input is `context.currentBlock`. Callers that carry no
305
+ * relative expiry (see {@link mutationNeedsBlockNumber}) can pass `0n`, which disables the
306
+ * dead-on-arrival pre-check and leaves that to the engine.
307
+ */
308
+ function buildEntityOperations(ops, context) {
309
+ const { creates, patches, deletes, extensions, ownershipChanges } = ops;
310
+ const createOps = (creates ?? []).map((item) => {
311
+ validateContentType(item.contentType);
312
+ return createOperation({
313
+ salt: item.salt === void 0 ? randomSalt() : validateSalt(item.salt),
314
+ expiry: resolveExpiry(item.expires, context),
315
+ creationFlags: encodeCreationFlags(item.flags),
316
+ attributes: encodeAttributes(item.attributes, {
317
+ payload: item.payload,
318
+ contentType: item.contentType
319
+ })
320
+ });
321
+ });
322
+ const patchOps = (patches ?? []).map((item) => {
323
+ if (item.contentType !== void 0) validateContentType(item.contentType);
324
+ const mutations = encodeMutations(item);
325
+ if (mutations.length === 0) throw new EmptyPatchError(item.entityKey);
326
+ return patchOperation({
327
+ entityKey: item.entityKey,
328
+ mutations
329
+ });
330
+ });
331
+ const extendOps = (extensions ?? []).map((item) => {
332
+ const expiry = resolveExpiry(item.expires, context);
333
+ return extendExpiryOperation({
334
+ entityKey: item.entityKey,
335
+ expiry
336
+ });
337
+ });
338
+ const operations = [
339
+ ...createOps,
340
+ ...patchOps,
341
+ ...(deletes ?? []).map((item) => deleteOperation({ entityKey: item.entityKey })),
342
+ ...extendOps,
343
+ ...(ownershipChanges ?? []).map((item) => transferOwnershipOperation({
344
+ entityKey: item.entityKey,
345
+ newOwner: item.newOwner
346
+ }))
347
+ ];
348
+ if (operations.length === 0) throw new Error("No operations to perform");
349
+ return operations;
350
+ }
351
+ /**
352
+ * Signs and sends an encoded batch, wrapping any node rejection in {@link EntityMutationError}.
353
+ *
354
+ * The submission half both write paths share: one `writeContract` — an `eth_sendRawTransaction`,
355
+ * plus only the lookups viem needs for whatever `txParams` leaves out — with no waiting and no
356
+ * polling. A rejection is reported in engine terms when the node returned decodable revert data,
357
+ * and with the node's own message otherwise; either way the caller sees an
358
+ * {@link EntityMutationError}.
359
+ *
360
+ * Internal seam shared with `actions/advanced/sendMutation`; not part of the package's public
361
+ * surface.
362
+ */
363
+ async function submitMutation(client, operations, txParams) {
364
+ if (!client.account) throw new Error("Account required");
365
+ if (!client.chain) throw new Error("Chain required");
366
+ const walletClient = client;
367
+ try {
368
+ return await walletClient.writeContract({
369
+ address: ARKIV_ADDRESS,
370
+ abi: EXECUTE_ABI$1,
371
+ functionName: "execute",
372
+ args: [operations],
373
+ account: client.account,
374
+ chain: client.chain,
375
+ ...txParams
376
+ });
377
+ } catch (error) {
378
+ throw asEntityMutationError(error);
379
+ }
380
+ }
381
+ /**
382
+ * Reads the entity events out of a receipt's logs, exactly as they were emitted.
383
+ *
384
+ * Lenient by design: it reports what the events say and nothing else — no counting against what
385
+ * was asked for (the caller may not have the request at hand) and no error for a receipt with no
386
+ * entity events at all. Logs from other contracts and events this SDK has no name for are skipped.
387
+ */
388
+ function collectMutationEvents(logs) {
389
+ const events = {
390
+ created: [],
391
+ patched: [],
392
+ deleted: [],
393
+ extended: [],
394
+ ownershipTransferred: []
395
+ };
396
+ for (const log of logs ?? []) {
397
+ if (log.address.toLowerCase() !== ARKIV_ADDRESS.toLowerCase()) continue;
398
+ const decoded = decodeEntityLog(log);
399
+ if (decoded === void 0) continue;
400
+ switch (decoded.eventName) {
401
+ case "EntityCreated":
402
+ events.created.push({
403
+ entityKey: decoded.args.entityKey,
404
+ owner: decoded.args.owner,
405
+ expiresAt: decoded.args.expiresAt
406
+ });
407
+ break;
408
+ case "EntityPatched":
409
+ events.patched.push({
410
+ entityKey: decoded.args.entityKey,
411
+ owner: decoded.args.owner
412
+ });
413
+ break;
414
+ case "EntityDeleted":
415
+ events.deleted.push({
416
+ entityKey: decoded.args.entityKey,
417
+ owner: decoded.args.owner
418
+ });
419
+ break;
420
+ case "ExpiryExtended":
421
+ events.extended.push({
422
+ entityKey: decoded.args.entityKey,
423
+ owner: decoded.args.owner,
424
+ expiresAt: decoded.args.expiresAt
425
+ });
426
+ break;
427
+ case "OwnershipTransferred":
428
+ events.ownershipTransferred.push({
429
+ entityKey: decoded.args.entityKey,
430
+ previousOwner: decoded.args.previousOwner,
431
+ newOwner: decoded.args.newOwner
432
+ });
433
+ break;
434
+ }
435
+ }
436
+ return events;
437
+ }
438
+
439
+ //#endregion
440
+ //#region src/actions/advanced/buildMutation.ts
441
+ const logger$3 = getLogger("actions:advanced:build-mutation");
442
+ /**
443
+ * Encodes a mutation batch without sending anything.
444
+ *
445
+ * This is the first step of the advanced path: it performs only local validation and encoding, so
446
+ * it costs **zero RPC calls** when `options.currentBlock` is provided (or no expiry is relative),
447
+ * and at most one `eth_blockNumber` otherwise. Send the result however you like: pass `operations`
448
+ * to `writeContract`, or sign `{ to, data }` offline and push it with `eth_sendRawTransaction`.
449
+ *
450
+ * One check rides on knowing the head: an absolute `atBlock(n)` already in the past is rejected
451
+ * locally only when the head is supplied or was fetched anyway. With neither, a dead-on-arrival
452
+ * expiry encodes cleanly and the engine reverts it on-chain — see
453
+ * {@link BuildMutationOptions.currentBlock}.
454
+ *
455
+ * @throws {InvalidExpiryError} If an expiry exceeds a protocol bound.
456
+ * @throws {InvalidValueError} If an attribute value does not fit the type it names.
457
+ * @throws {EmptyPatchError} If a patch has nothing to apply.
458
+ */
459
+ async function buildMutation(client, data, options = {}) {
460
+ const currentBlock = options.currentBlock ?? (mutationNeedsBlockNumber(data) ? await client.getBlockNumber() : 0n);
461
+ const operations = buildEntityOperations(data, { currentBlock });
462
+ logger$3("Built %d operations at block %d", operations.length, currentBlock);
463
+ return {
464
+ operations,
465
+ to: ARKIV_ADDRESS,
466
+ data: encodeFunctionData({
467
+ abi: EXECUTE_ABI,
468
+ functionName: "execute",
469
+ args: [operations]
470
+ }),
471
+ expected: {
472
+ creates: data.creates?.length ?? 0,
473
+ patches: data.patches?.length ?? 0,
474
+ deletes: data.deletes?.length ?? 0,
475
+ extensions: data.extensions?.length ?? 0,
476
+ ownershipChanges: data.ownershipChanges?.length ?? 0
477
+ }
478
+ };
479
+ }
480
+
481
+ //#endregion
482
+ //#region src/actions/advanced/getMutationResult.ts
483
+ const logger$2 = getLogger("actions:advanced:get-mutation-result");
484
+ /**
485
+ * Decodes a receipt you already hold into a {@link MutationResult}. **Zero RPC calls.**
486
+ *
487
+ * The pure tail of the advanced path: if a receipt reached you some other way — your own
488
+ * `waitForTransactionReceipt`, a webhook, a block watcher — this turns it into entity keys and
489
+ * expiries without touching the network. Lenient by design: it reports what the events say,
490
+ * without counting them against a request it never saw.
491
+ */
492
+ function decodeMutationResult(receipt) {
493
+ const events = collectMutationEvents(receipt.logs);
494
+ return {
495
+ status: receipt.status,
496
+ txHash: receipt.transactionHash,
497
+ blockNumber: receipt.blockNumber,
498
+ createdEntities: events.created.map((e) => e.entityKey),
499
+ createdExpiries: events.created.map((e) => e.expiresAt),
500
+ patchedEntities: events.patched.map((e) => e.entityKey),
501
+ deletedEntities: events.deleted.map((e) => e.entityKey),
502
+ extendedEntities: events.extended.map((e) => e.entityKey),
503
+ extendedExpiries: events.extended.map((e) => e.expiresAt),
504
+ ownershipChanges: events.ownershipTransferred.map((e) => e.entityKey),
505
+ receipt
506
+ };
507
+ }
508
+ /**
509
+ * Fetches a transaction's receipt — once — and decodes what the mutation did.
510
+ *
511
+ * Exactly one `eth_getTransactionReceipt`, like `pingTransaction`, but the answer carries the
512
+ * decoded entity events as well: created keys, recorded expiries, and the keys of everything
513
+ * patched, deleted, extended or handed over. A transaction that is not mined yet comes back as
514
+ * `{ status: "pending" }` — check `status` before reading the rest.
515
+ *
516
+ * No revert diagnosis is run: a `reverted` result reports the fact and the raw receipt, and
517
+ * spending a `simulateContract` on the why is your call, not the SDK's.
518
+ */
519
+ async function getMutationResult(client, txHash) {
520
+ const receipt = await fetchReceipt(client, txHash);
521
+ if (receipt === void 0) {
522
+ logger$2("Tx %s still pending", txHash);
523
+ return { status: "pending" };
524
+ }
525
+ return decodeMutationResult(receipt);
526
+ }
527
+ /**
528
+ * One `eth_getTransactionReceipt`, with "not there yet" as a value instead of an exception.
529
+ *
530
+ * Internal seam shared with `pingTransaction`; not part of the package's public surface.
531
+ */
532
+ async function fetchReceipt(client, txHash) {
533
+ const reader = client;
534
+ try {
535
+ return await reader.getTransactionReceipt({ hash: txHash });
536
+ } catch (error) {
537
+ if (error instanceof TransactionReceiptNotFoundError) return void 0;
538
+ throw error;
539
+ }
540
+ }
541
+
542
+ //#endregion
543
+ //#region src/actions/advanced/pingTransaction.ts
544
+ const logger$1 = getLogger("actions:advanced:ping-transaction");
545
+ /**
546
+ * Asks the chain — once — whether a transaction has landed.
547
+ *
548
+ * Exactly one `eth_getTransactionReceipt`, never a poll: a transaction that is not mined yet comes
549
+ * back as `{ status: "pending" }` rather than being waited on. This is the "ping" of the advanced
550
+ * path — you own the schedule, the SDK owns nothing.
551
+ *
552
+ * When it reports `success` and you need the created keys or recorded expiries, spend the next
553
+ * call on `getMutationResult` — or none at all, if you predicted the keys up front with
554
+ * `predictEntityKeys`.
555
+ */
556
+ async function pingTransaction(client, txHash) {
557
+ const receipt = await fetchReceipt(client, txHash);
558
+ if (receipt === void 0) {
559
+ logger$1("Tx %s still pending", txHash);
560
+ return { status: "pending" };
561
+ }
562
+ return {
563
+ status: receipt.status,
564
+ blockNumber: receipt.blockNumber
565
+ };
566
+ }
567
+
568
+ //#endregion
569
+ //#region src/actions/advanced/sendMutation.ts
570
+ const logger = getLogger("actions:advanced:send-mutation");
571
+ /**
572
+ * Signs and sends a mutation batch, returning as soon as the transaction is submitted.
573
+ *
574
+ * The fire-and-forget half of the advanced path. Unlike `mutateEntities`, this does **not** wait
575
+ * for a receipt, does not poll, and runs no revert diagnosis — it spends only what submitting
576
+ * costs. With `options.currentBlock` and full `txParams` (nonce, gas, fees) that is exactly one
577
+ * RPC call; each omitted piece adds only the lookup viem needs to fill it.
578
+ *
579
+ * Follow up separately, on your own schedule:
580
+ * - `pingTransaction(txHash)` — one `eth_getTransactionReceipt`, tells you pending/success/reverted.
581
+ * - `getMutationResult(txHash)` — the same single call, plus the decoded entity keys and expiries.
582
+ *
583
+ * @throws {EntityMutationError} If the node rejects the submission (the batch never made it into
584
+ * the mempool) — in engine terms when the rejection decodes, with the node's message otherwise.
585
+ * Anything after that — inclusion, success — is yours to check.
586
+ */
587
+ async function sendMutation(client, data, options = {}) {
588
+ const { operations, expected } = await buildMutation(client, data, options);
589
+ logger("Sending execute with %d operations (no wait)", operations.length);
590
+ return {
591
+ txHash: await submitMutation(client, operations, options.txParams),
592
+ expected
593
+ };
594
+ }
595
+
596
+ //#endregion
597
+ export { buildMutation as a, mutationNeedsBlockNumber as c, getMutationResult as i, sendArkivTransaction as l, pingTransaction as n, buildEntityOperations as o, decodeMutationResult as r, collectMutationEvents as s, sendMutation as t, ENTITY_NONCE_ABI as u };
598
+ //# sourceMappingURL=advanced-8ZPTmmaN.js.map