@arkiv-network/sdk 0.8.0-advanced.2 → 0.8.0-dev.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 (178) hide show
  1. package/README.md +0 -42
  2. package/dist/attr/index.cjs +33 -34
  3. package/dist/attr/index.d.cts +1 -1
  4. package/dist/attr/index.d.ts +1 -2
  5. package/dist/attr/index.js +1 -2
  6. package/dist/{attributes-Df9IsCVs.cjs → attr-BXTkpnoc.cjs} +13 -3
  7. package/dist/{attributes-BhY5DwJp.js → attr-tmyREHtw.js} +14 -4
  8. package/dist/attr-tmyREHtw.js.map +1 -0
  9. package/dist/chains/index.cjs +1 -1
  10. package/dist/chains/index.d.cts +3 -0
  11. package/dist/chains/index.d.cts.map +1 -1
  12. package/dist/chains/index.d.ts +3 -0
  13. package/dist/chains/index.d.ts.map +1 -1
  14. package/dist/chains/index.js +1 -1
  15. package/dist/{chains-BYRTTipa.cjs → chains-BfNQliHU.cjs} +3 -0
  16. package/dist/{chains-BJrZs6sG.js → chains-Du8tql7I.js} +4 -1
  17. package/dist/chains-Du8tql7I.js.map +1 -0
  18. package/dist/{arkivTransactions-NtGD6uk5.d.ts → changeOwnership-B0ar96ub.d.ts} +74 -123
  19. package/dist/changeOwnership-B0ar96ub.d.ts.map +1 -0
  20. package/dist/{arkivTransactions-D74gERHG.d.cts → changeOwnership-BofkLnXJ.d.cts} +74 -123
  21. package/dist/changeOwnership-BofkLnXJ.d.cts.map +1 -0
  22. package/dist/entity/index.cjs +9 -9
  23. package/dist/entity/index.d.cts +3 -3
  24. package/dist/entity/index.d.ts +4 -5
  25. package/dist/entity/index.js +5 -6
  26. package/dist/{entity-BYQR1uoe.js → entity-BIp_df9u.js} +1 -1
  27. package/dist/{entity-BYQR1uoe.js.map → entity-BIp_df9u.js.map} +1 -1
  28. package/dist/{key-D1Bh7MF0.js → entity-CniBgBSd.js} +31 -19
  29. package/dist/entity-CniBgBSd.js.map +1 -0
  30. package/dist/{key-WKhXnXuU.cjs → entity-DJ0Gml9c.cjs} +37 -19
  31. package/dist/{errors-LTe7bOYS.js → errors-D2E1GRjw.js} +2 -2
  32. package/dist/errors-D2E1GRjw.js.map +1 -0
  33. package/dist/{errors-BVbjKVMN.cjs → errors-DhV00966.cjs} +1 -1
  34. package/dist/{expiry-nDbCgZX4.d.ts → expiry-BxOlvVWC.d.ts} +1 -1
  35. package/dist/{expiry-nDbCgZX4.d.ts.map → expiry-BxOlvVWC.d.ts.map} +1 -1
  36. package/dist/{expiry-BELY2Kpw.cjs → expiry-CG9GhVXv.cjs} +1 -1
  37. package/dist/{expiry-BjpxZZQU.js → expiry-Cgdb_dbq.js} +2 -2
  38. package/dist/expiry-Cgdb_dbq.js.map +1 -0
  39. package/dist/expiry-DRV29F1r.d.cts.map +1 -1
  40. package/dist/{flags-CRjPpoh3.d.cts → flags-0Vl5rrHq.d.cts} +1 -1
  41. package/dist/{flags-CRjPpoh3.d.cts.map → flags-0Vl5rrHq.d.cts.map} +1 -1
  42. package/dist/{flags-kr276q6i.cjs → flags-DCD26uhe.cjs} +1 -1
  43. package/dist/{flags-DFBs2J94.js → flags-DUT2gHEU.js} +2 -2
  44. package/dist/{flags-DFBs2J94.js.map → flags-DUT2gHEU.js.map} +1 -1
  45. package/dist/{flags-5dTNRnow.d.ts → flags-wmcMoAnN.d.ts} +1 -1
  46. package/dist/{flags-5dTNRnow.d.ts.map → flags-wmcMoAnN.d.ts.map} +1 -1
  47. package/dist/{index-fX_XyqLp.d.ts → index-BGp2plHs.d.cts} +15 -13
  48. package/dist/index-BGp2plHs.d.cts.map +1 -0
  49. package/dist/{index-DHDud2hC.d.ts → index-BKB875Um.d.ts} +5 -7
  50. package/dist/{index-DHDud2hC.d.ts.map → index-BKB875Um.d.ts.map} +1 -1
  51. package/dist/{index-DvYvrkdk.d.ts → index-CIcHPx2j.d.cts} +110 -6
  52. package/dist/index-CIcHPx2j.d.cts.map +1 -0
  53. package/dist/{index-CV5zCdpa.d.cts → index-Cd2aaWme.d.ts} +13 -6
  54. package/dist/index-Cd2aaWme.d.ts.map +1 -0
  55. package/dist/{index-CA4V7Pdh.d.cts → index-ezMZ2-JH.d.ts} +15 -13
  56. package/dist/index-ezMZ2-JH.d.ts.map +1 -0
  57. package/dist/{index-BF7Mq9Is.d.cts → index-rINthNuU.d.cts} +5 -7
  58. package/dist/{index-BF7Mq9Is.d.cts.map → index-rINthNuU.d.cts.map} +1 -1
  59. package/dist/index.cjs +433 -139
  60. package/dist/index.d.cts +58 -164
  61. package/dist/index.d.cts.map +1 -1
  62. package/dist/index.d.ts +59 -166
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +376 -75
  65. package/dist/index.js.map +1 -1
  66. package/dist/{payload-CcUj85ys.d.ts → payload-CGvVPZQX.d.ts} +61 -2
  67. package/dist/payload-CGvVPZQX.d.ts.map +1 -0
  68. package/dist/{payload-Bz6651ax.js → payload-DE7wMztL.js} +28 -3
  69. package/dist/payload-DE7wMztL.js.map +1 -0
  70. package/dist/{payload-BNoud2KZ.d.cts → payload-Dfu30njp.d.cts} +60 -1
  71. package/dist/payload-Dfu30njp.d.cts.map +1 -0
  72. package/dist/{payload-KC14SDlN.cjs → payload-DqFweqiO.cjs} +27 -2
  73. package/dist/query/index.cjs +5 -7
  74. package/dist/query/index.d.cts +4 -4
  75. package/dist/query/index.d.ts +4 -5
  76. package/dist/query/index.js +5 -7
  77. package/dist/{queryBuilder-DM6AWCBa.js → queryBuilder-wvA8sn--.js} +169 -23
  78. package/dist/queryBuilder-wvA8sn--.js.map +1 -0
  79. package/dist/{queryBuilder-DbUMEZln.cjs → queryBuilder-zHGhDmaG.cjs} +215 -33
  80. package/dist/{selection-DPg0uyJf.d.cts → selection-Bv8_o-7i.d.cts} +76 -68
  81. package/dist/selection-Bv8_o-7i.d.cts.map +1 -0
  82. package/dist/{selection-C4UhsMOO.d.ts → selection-ox7zdtVm.d.ts} +76 -69
  83. package/dist/selection-ox7zdtVm.d.ts.map +1 -0
  84. package/dist/types/index.cjs +2 -2
  85. package/dist/types/index.d.cts +6 -6
  86. package/dist/types/index.d.ts +7 -8
  87. package/dist/types/index.js +2 -2
  88. package/dist/utils/index.cjs +3 -3
  89. package/dist/utils/index.d.cts +1 -1
  90. package/dist/utils/index.d.ts +2 -2
  91. package/dist/utils/index.js +3 -3
  92. package/package.json +1 -5
  93. package/src/actions/public/getEntity.ts +1 -0
  94. package/src/actions/public/predictEntityKeys.test.ts +17 -1
  95. package/src/actions/public/predictEntityKeys.ts +28 -14
  96. package/src/actions/public/query.ts +1 -5
  97. package/src/actions/wallet/createEntity.ts +7 -6
  98. package/src/actions/wallet/{mutateEntities.test.ts → executeBatch.test.ts} +7 -7
  99. package/src/actions/wallet/{mutateEntities.ts → executeBatch.ts} +26 -11
  100. package/src/actions/wallet/extendEntity.ts +1 -0
  101. package/src/actions/wallet/patchEntity.ts +3 -3
  102. package/src/attr/attributes.ts +8 -2
  103. package/src/attr/errors.ts +2 -2
  104. package/src/attr/types.ts +3 -3
  105. package/src/attr/values.ts +5 -1
  106. package/src/chains/localhost.ts +3 -0
  107. package/src/clients/createPublicClient.test.ts +1 -1
  108. package/src/clients/createPublicClient.ts +5 -5
  109. package/src/clients/createWalletClient.test.ts +2 -2
  110. package/src/clients/createWalletClient.ts +3 -5
  111. package/src/clients/decorators/arkivPublic.ts +13 -24
  112. package/src/clients/decorators/arkivWallet.ts +40 -47
  113. package/src/entity/create.test.ts +20 -1
  114. package/src/entity/errors.ts +4 -3
  115. package/src/entity/expiry.ts +1 -0
  116. package/src/entity/index.ts +2 -2
  117. package/src/entity/key.ts +23 -3
  118. package/src/entity/operations.ts +1 -0
  119. package/src/index.ts +0 -13
  120. package/src/query/engine.ts +0 -11
  121. package/src/query/errors.ts +1 -1
  122. package/src/query/expression.ts +14 -7
  123. package/src/query/queryBuilder.test.ts +1 -21
  124. package/src/query/queryBuilder.ts +3 -10
  125. package/src/types/index.ts +4 -4
  126. package/src/types/rpcSchema.ts +1 -0
  127. package/src/types/txParams.ts +8 -0
  128. package/src/utils/arkivTransactions.test.ts +7 -1
  129. package/src/utils/arkivTransactions.ts +114 -254
  130. package/src/utils/expirationTime.ts +39 -0
  131. package/src/utils/payload.ts +25 -0
  132. package/dist/actions/advanced/index.cjs +0 -13
  133. package/dist/actions/advanced/index.d.cts +0 -8
  134. package/dist/actions/advanced/index.d.ts +0 -9
  135. package/dist/actions/advanced/index.js +0 -9
  136. package/dist/advanced-8ZPTmmaN.js +0 -598
  137. package/dist/advanced-8ZPTmmaN.js.map +0 -1
  138. package/dist/advanced-fPImL6lW.cjs +0 -656
  139. package/dist/arkivTransactions-D74gERHG.d.cts.map +0 -1
  140. package/dist/arkivTransactions-NtGD6uk5.d.ts.map +0 -1
  141. package/dist/attributes-BhY5DwJp.js.map +0 -1
  142. package/dist/chains-BJrZs6sG.js.map +0 -1
  143. package/dist/codec-Car3KkFF.d.ts +0 -102
  144. package/dist/codec-Car3KkFF.d.ts.map +0 -1
  145. package/dist/entity-B7G8q_Eo.cjs +0 -0
  146. package/dist/entity-CD_qFF2M.js +0 -0
  147. package/dist/errors-LTe7bOYS.js.map +0 -1
  148. package/dist/expiry-BjpxZZQU.js.map +0 -1
  149. package/dist/index-B5j76711.d.ts +0 -184
  150. package/dist/index-B5j76711.d.ts.map +0 -1
  151. package/dist/index-CA4V7Pdh.d.cts.map +0 -1
  152. package/dist/index-CV5zCdpa.d.cts.map +0 -1
  153. package/dist/index-DvYvrkdk.d.ts.map +0 -1
  154. package/dist/index-EeUO0nnJ.d.cts +0 -184
  155. package/dist/index-EeUO0nnJ.d.cts.map +0 -1
  156. package/dist/index-fX_XyqLp.d.ts.map +0 -1
  157. package/dist/key-D1Bh7MF0.js.map +0 -1
  158. package/dist/logger-CVpvU8ik.js +0 -153
  159. package/dist/logger-CVpvU8ik.js.map +0 -1
  160. package/dist/logger-Cr15lPAQ.cjs +0 -188
  161. package/dist/payload-BNoud2KZ.d.cts.map +0 -1
  162. package/dist/payload-Bz6651ax.js.map +0 -1
  163. package/dist/payload-CcUj85ys.d.ts.map +0 -1
  164. package/dist/queryBuilder-DM6AWCBa.js.map +0 -1
  165. package/dist/selection-C4UhsMOO.d.ts.map +0 -1
  166. package/dist/selection-DPg0uyJf.d.cts.map +0 -1
  167. package/dist/types-Bu_ZwMbZ.js +0 -0
  168. package/dist/types-NRqymi6S.cjs +0 -0
  169. package/src/actions/advanced/advanced.test.ts +0 -258
  170. package/src/actions/advanced/buildMutation.ts +0 -104
  171. package/src/actions/advanced/getMutationResult.ts +0 -112
  172. package/src/actions/advanced/index.ts +0 -21
  173. package/src/actions/advanced/pingTransaction.ts +0 -43
  174. package/src/actions/advanced/sendMutation.ts +0 -59
  175. package/src/clients/decorators/arkivAdvanced.ts +0 -144
  176. /package/dist/{entity-B00Li04j.cjs → entity-B0t6sN7F.cjs} +0 -0
  177. /package/dist/{attr-DlmErkvR.cjs → types-Bx1EKe0v.js} +0 -0
  178. /package/dist/{attr-GcQKatub.js → types-CKPddlfS.cjs} +0 -0
@@ -14,20 +14,19 @@ import type {
14
14
  DeleteEntityReturnType,
15
15
  } from "../../actions/wallet/deleteEntity"
16
16
  import { deleteEntity } from "../../actions/wallet/deleteEntity"
17
+ import type {
18
+ ExecuteBatchParameters,
19
+ ExecuteBatchReturnType,
20
+ } from "../../actions/wallet/executeBatch"
21
+ import { executeBatch } from "../../actions/wallet/executeBatch"
17
22
  import type {
18
23
  ExtendEntityParameters,
19
24
  ExtendEntityReturnType,
20
25
  } from "../../actions/wallet/extendEntity"
21
26
  import { extendEntity } from "../../actions/wallet/extendEntity"
22
- import type {
23
- MutateEntitiesParameters,
24
- MutateEntitiesReturnType,
25
- } from "../../actions/wallet/mutateEntities"
26
- import { mutateEntities } from "../../actions/wallet/mutateEntities"
27
27
  import type { PatchEntityParameters, PatchEntityReturnType } from "../../actions/wallet/patchEntity"
28
28
  import { patchEntity } from "../../actions/wallet/patchEntity"
29
29
  import type { TxParams } from "../../types"
30
- import { type WalletAdvancedActions, walletAdvancedActions } from "./arkivAdvanced"
31
30
 
32
31
  export type WalletArkivActions<
33
32
  transport extends Transport = Transport,
@@ -51,12 +50,12 @@ export type WalletArkivActions<
51
50
  /**
52
51
  * Creates a new entity.
53
52
  *
54
- * - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/createEntity
55
- * - JSON-RPC Methods: [`eth_sendRawTransaction`](https://docs.arkiv.network/dev/json-rpc-api/#mutateEntities)
53
+ * - JSON-RPC Methods: `eth_sendRawTransaction`
56
54
  *
57
55
  * @param data - The entity creation parameters
58
56
  * @param txParams - Optional transaction parameters
59
- * @returns The created entity with transaction hash
57
+ * @returns The new entity's key, the transaction hash, and the block it is expected to
58
+ * expire at. {@link CreateEntityReturnType}
60
59
  *
61
60
  * @throws {InvalidExpiryError} If the expiry exceeds a protocol bound or would leave the
62
61
  * entity dead on arrival.
@@ -68,8 +67,10 @@ export type WalletArkivActions<
68
67
  * import { i32 } from "@arkiv-network/sdk/attr"
69
68
  * import { cheesecake } from "@arkiv-network/sdk/chains"
70
69
  * import { http } from "viem"
70
+ * import { privateKeyToAccount } from "viem/accounts"
71
71
  *
72
72
  * const client = createWalletClient({
73
+ * account: privateKeyToAccount("0x..."),
73
74
  * chain: cheesecake,
74
75
  * transport: http(),
75
76
  * })
@@ -89,12 +90,11 @@ export type WalletArkivActions<
89
90
  * Applies a patch to the entity with the given key: sets some fields, unsets others, and leaves
90
91
  * everything it does not name alone.
91
92
  *
92
- * - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/patchEntity
93
- * - JSON-RPC Methods: [`eth_sendRawTransaction`](https://docs.arkiv.network/dev/json-rpc-api/#mutateEntities)
93
+ * - JSON-RPC Methods: `eth_sendRawTransaction`
94
94
  *
95
95
  * @param data - The entity key and the mutations to apply
96
96
  * @param txParams - Optional transaction parameters
97
- * @returns The entity key and the transaction hash
97
+ * @returns The patched entity's key and the transaction hash. {@link PatchEntityReturnType}
98
98
  *
99
99
  * @throws {EmptyPatchError} If the patch has nothing to apply.
100
100
  * @throws {ConflictingMutationError} If a name appears in both `set` and `unset`.
@@ -106,8 +106,10 @@ export type WalletArkivActions<
106
106
  * import { i32 } from "@arkiv-network/sdk/attr"
107
107
  * import { cheesecake } from "@arkiv-network/sdk/chains"
108
108
  * import { http } from "viem"
109
+ * import { privateKeyToAccount } from "viem/accounts"
109
110
  *
110
111
  * const client = createWalletClient({
112
+ * account: privateKeyToAccount("0x..."),
111
113
  * chain: cheesecake,
112
114
  * transport: http(),
113
115
  * })
@@ -127,19 +129,20 @@ export type WalletArkivActions<
127
129
  /**
128
130
  * Deletes the entity with the given key.
129
131
  *
130
- * - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/deleteEntity
131
- * - JSON-RPC Methods: [`eth_sendRawTransaction`](https://docs.arkiv.network/dev/json-rpc-api/#mutateEntities)
132
+ * - JSON-RPC Methods: `eth_sendRawTransaction`
132
133
  *
133
134
  * @param data - The entity deletion parameters
134
135
  * @param txParams - Optional transaction parameters
135
- * @returns The deleted entity with transaction hash
136
+ * @returns The deleted entity's key and the transaction hash. {@link DeleteEntityReturnType}
136
137
  *
137
138
  * @example
138
139
  * import { createWalletClient } from "@arkiv-network/sdk"
139
140
  * import { cheesecake } from "@arkiv-network/sdk/chains"
140
141
  * import { http } from "viem"
142
+ * import { privateKeyToAccount } from "viem/accounts"
141
143
  *
142
144
  * const client = createWalletClient({
145
+ * account: privateKeyToAccount("0x..."),
143
146
  * chain: cheesecake,
144
147
  * transport: http(),
145
148
  * })
@@ -158,12 +161,12 @@ export type WalletArkivActions<
158
161
  * than adding to what the entity has left, and `atBlock` / `atDate` pin an absolute deadline.
159
162
  * The engine rejects an extension that would not move the expiry later.
160
163
  *
161
- * - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/extendEntity
162
- * - JSON-RPC Methods: [`eth_sendRawTransaction`](https://docs.arkiv.network/dev/json-rpc-api/#mutateEntities)
164
+ * - JSON-RPC Methods: `eth_sendRawTransaction`
163
165
  *
164
166
  * @param data - The entity key and its new lifetime
165
167
  * @param txParams - Optional transaction parameters
166
- * @returns The entity key, transaction hash, and the block it is now expected to expire at
168
+ * @returns The entity's key, the transaction hash, and the block it is now expected to expire
169
+ * at. {@link ExtendEntityReturnType}
167
170
  *
168
171
  * @throws {InvalidExpiryError} If the expiry is malformed, exceeds a protocol bound, or would
169
172
  * leave the entity dead on arrival.
@@ -172,8 +175,10 @@ export type WalletArkivActions<
172
175
  * import { createWalletClient, ExpirationTime } from "@arkiv-network/sdk"
173
176
  * import { cheesecake } from "@arkiv-network/sdk/chains"
174
177
  * import { http } from "viem"
178
+ * import { privateKeyToAccount } from "viem/accounts"
175
179
  *
176
180
  * const client = createWalletClient({
181
+ * account: privateKeyToAccount("0x..."),
177
182
  * chain: cheesecake,
178
183
  * transport: http(),
179
184
  * })
@@ -188,14 +193,13 @@ export type WalletArkivActions<
188
193
  ) => Promise<ExtendEntityReturnType>
189
194
 
190
195
  /**
191
- * Changes the ownership of the entity with the given address.
196
+ * Hands the entity with the given key to a new owner.
192
197
  *
193
- * - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/changeOwnership
194
- * - JSON-RPC Methods: [`eth_sendRawTransaction`](https://docs.arkiv.network/dev/json-rpc-api/#mutateEntities)
198
+ * - JSON-RPC Methods: `eth_sendRawTransaction`
195
199
  *
196
200
  * @param data - The ownership change parameters
197
201
  * @param txParams - Optional transaction parameters
198
- * @returns The entity with updated ownership and transaction hash
202
+ * @returns The entity's key and the transaction hash. {@link ChangeOwnershipReturnType}
199
203
  */
200
204
  changeOwnership: (
201
205
  data: ChangeOwnershipParameters,
@@ -203,17 +207,18 @@ export type WalletArkivActions<
203
207
  ) => Promise<ChangeOwnershipReturnType>
204
208
 
205
209
  /**
206
- * Mutates the entities with the given keys.
210
+ * Applies a batch of entity operations — creates, patches, deletes, extensions and ownership
211
+ * transfers — in one transaction.
207
212
  *
208
- * - Docs: https://docs.arkiv.network/ts-sdk/actions/wallet/mutateEntities
209
- * - JSON-RPC Methods: [`eth_sendRawTransaction`](https://docs.arkiv.network/dev/json-rpc-api/#mutateEntities)
213
+ * - JSON-RPC Methods: `eth_sendRawTransaction`
210
214
  *
211
215
  * Every operation lands in one transaction, so the whole batch applies or none of it does.
212
216
  * At least one operation is required.
213
217
  *
214
- * @param data - The mutation parameters (creates, patches, deletes, extensions, ownershipChanges)
218
+ * @param data - The batch parameters (creates, patches, deletes, extensions, ownershipChanges)
215
219
  * @param txParams - Optional transaction parameters
216
- * @returns The mutation result with transaction hash
220
+ * @returns The transaction hash, plus the keys touched by each kind of operation.
221
+ * {@link ExecuteBatchReturnType}
217
222
  *
218
223
  * @throws {InvalidExpiryError} If an expiry exceeds a protocol bound or would leave the entity
219
224
  * dead on arrival.
@@ -223,12 +228,14 @@ export type WalletArkivActions<
223
228
  * import { createWalletClient, ExpirationTime, jsonToPayload } from "@arkiv-network/sdk"
224
229
  * import { cheesecake } from "@arkiv-network/sdk/chains"
225
230
  * import { http } from "viem"
231
+ * import { privateKeyToAccount } from "viem/accounts"
226
232
  *
227
233
  * const client = createWalletClient({
234
+ * account: privateKeyToAccount("0x..."),
228
235
  * chain: cheesecake,
229
236
  * transport: http(),
230
237
  * })
231
- * const { txHash, createdEntities } = await client.mutateEntities({
238
+ * const { txHash, createdEntities } = await client.executeBatch({
232
239
  * creates: [{
233
240
  * payload: jsonToPayload({ entityType: "testType", entityId: "testId" }),
234
241
  * contentType: "application/json",
@@ -244,23 +251,10 @@ export type WalletArkivActions<
244
251
  * ownershipChanges: [{ entityKey: keyToHandOver, newOwner }],
245
252
  * })
246
253
  */
247
- mutateEntities: (
248
- data: MutateEntitiesParameters,
254
+ executeBatch: (
255
+ data: ExecuteBatchParameters,
249
256
  txParams?: TxParams,
250
- ) => Promise<MutateEntitiesReturnType>
251
-
252
- /**
253
- * The advanced path: build, send, ping and read mutation results as separate steps, each
254
- * costing the minimum number of RPC calls. Use it when you are optimising your RPC budget;
255
- * the everyday actions above remain the right default. {@link WalletAdvancedActions}
256
- *
257
- * @example
258
- * const { txHash } = await client.advanced.sendMutation({ creates: [entity] }) // no waiting
259
- * // ... later, one eth_getTransactionReceipt on your own schedule:
260
- * const result = await client.advanced.getMutationResult(txHash)
261
- * if (result.status === "success") console.log(result.createdEntities)
262
- */
263
- advanced: WalletAdvancedActions
257
+ ) => Promise<ExecuteBatchReturnType>
264
258
  }
265
259
 
266
260
  export function walletArkivActions<
@@ -279,8 +273,7 @@ export function walletArkivActions<
279
273
  extendEntity(client, data, txParams),
280
274
  changeOwnership: (data: ChangeOwnershipParameters, txParams?: TxParams) =>
281
275
  changeOwnership(client, data, txParams),
282
- mutateEntities: (data: MutateEntitiesParameters, txParams?: TxParams) =>
283
- mutateEntities(client, data, txParams),
284
- advanced: walletAdvancedActions(client),
276
+ executeBatch: (data: ExecuteBatchParameters, txParams?: TxParams) =>
277
+ executeBatch(client, data, txParams),
285
278
  }
286
279
  }
@@ -4,7 +4,7 @@ import { encodeAttributes } from "../attr/attributes"
4
4
  import { dec, i32, str, u256 } from "../attr/values"
5
5
  import { InvalidCreationFlagsError } from "./errors"
6
6
  import { decodeCreationFlags, encodeCreationFlags } from "./flags"
7
- import { MAX_SALT, predictEntityKey, randomSalt, validateSalt } from "./key"
7
+ import { MAX_SALT, NO_SALT, predictEntityKey, randomSalt, resolveSalt, validateSalt } from "./key"
8
8
  import { createOperation } from "./operations"
9
9
  import { OperationType } from "./params"
10
10
 
@@ -73,6 +73,18 @@ describe("salt", () => {
73
73
  expect(() => validateSalt(MAX_SALT + 1n)).toThrow(/uint128/)
74
74
  expect(() => validateSalt(-1n)).toThrow(/uint128/)
75
75
  })
76
+
77
+ it("resolves NO_SALT to the zero, and passes anything else through", () => {
78
+ expect(resolveSalt(NO_SALT)).toBe(0n)
79
+ expect(resolveSalt(0n)).toBe(0n)
80
+ expect(resolveSalt(42n)).toBe(42n)
81
+ expect(() => resolveSalt(MAX_SALT + 1n)).toThrow(/uint128/)
82
+ })
83
+
84
+ it("reports a salt it cannot use without choking on a symbol", () => {
85
+ // @ts-expect-error
86
+ expect(() => validateSalt(Symbol("nope"))).toThrow(/Invalid salt/)
87
+ })
76
88
  })
77
89
 
78
90
  describe("predictEntityKey", () => {
@@ -86,6 +98,13 @@ describe("predictEntityKey", () => {
86
98
  ).not.toBe(predictEntityKey(base))
87
99
  })
88
100
 
101
+ it("derives the same key from NO_SALT as from an explicit zero", () => {
102
+ const base = { owner: OWNER, nonce: 3n, chainId: 1 } as const
103
+ expect(predictEntityKey({ ...base, salt: NO_SALT })).toBe(
104
+ predictEntityKey({ ...base, salt: 0n }),
105
+ )
106
+ })
107
+
89
108
  it("separates chains through the domain", () => {
90
109
  const base = { owner: OWNER, nonce: 0n, salt: 0n } as const
91
110
  expect(predictEntityKey({ ...base, chainId: 1 })).not.toBe(
@@ -16,10 +16,11 @@ export class InvalidCreationFlagsError extends Error {
16
16
 
17
17
  /** A key salt was outside the `uint128` the wire carries. */
18
18
  export class InvalidSaltError extends Error {
19
- constructor(salt: bigint) {
19
+ constructor(salt: unknown) {
20
20
  super(
21
- `Invalid salt ${salt}. A salt is a uint128, so it must be between 0 and ` +
22
- `${2n ** 128n - 1n}. Omit it to get 128 random bits, or pass 0 for a predictable key.`,
21
+ `Invalid salt ${String(salt)}. A salt is a uint128, so it must be between 0 and ` +
22
+ `${2n ** 128n - 1n}. Omit it to get 128 random bits, or pass NO_SALT for a key derived ` +
23
+ `from the owner and nonce alone.`,
23
24
  )
24
25
  this.name = "InvalidSaltError"
25
26
  }
@@ -1,4 +1,5 @@
1
1
  import { BLOCK_TIME } from "../consts"
2
+ import type { ExpirationTime } from "../utils/expirationTime"
2
3
  import { InvalidExpiryError } from "./errors"
3
4
  import { MAX_EXPIRES_AT } from "./params"
4
5
 
@@ -10,6 +10,6 @@ export type { EncodedExpiry, Expiry, ExpiryContext, Lifetime, ResolvedExpiry } f
10
10
  export { resolveExpiry, toBlocks } from "./expiry"
11
11
  export type { CreationFlags, ResolvedCreationFlags } from "./flags"
12
12
  export { decodeCreationFlags, encodeCreationFlags } from "./flags"
13
- export { MAX_SALT, predictEntityKey, randomSalt } from "./key"
14
- export type { Operation } from "./operations"
13
+ export type { SaltInput } from "./key"
14
+ export { MAX_SALT, NO_SALT, predictEntityKey, randomSalt } from "./key"
15
15
  export { MAX_EXPIRES_AT, OperationType } from "./params"
package/src/entity/key.ts CHANGED
@@ -1,10 +1,23 @@
1
1
  import { type Address, encodePacked, type Hex, keccak256 } from "viem"
2
+ import type { CreateEntityParameters } from "../actions/wallet/createEntity"
2
3
  import { ARKIV_ADDRESS } from "../consts"
3
4
  import { InvalidSaltError, NoRandomSourceError } from "./errors"
4
5
 
5
6
  /** The widest salt the `uint128` wire field carries. */
6
7
  export const MAX_SALT = 2n ** 128n - 1n
7
8
 
9
+ /**
10
+ * Opts a create out of salting, as {@link CreateEntityParameters.salt}: the key is then derived
11
+ * from the owner and its nonce alone, so anyone who knows both can work it out before the create
12
+ * lands.
13
+ */
14
+ export const NO_SALT = Symbol("NO_SALT")
15
+
16
+ /**
17
+ * A salt as a caller expresses it: an explicit `uint128`, or {@link NO_SALT} to opt out of salting.
18
+ */
19
+ export type SaltInput = bigint | typeof NO_SALT
20
+
8
21
  /**
9
22
  * A cryptographically random 128-bit salt — what {@link CreateEntityParameters.salt} defaults to.
10
23
  *
@@ -25,6 +38,13 @@ export function randomSalt(): bigint {
25
38
  return salt
26
39
  }
27
40
 
41
+ /**
42
+ * Resolves a caller-supplied salt to a `uint128`.
43
+ */
44
+ export function resolveSalt(salt: SaltInput): bigint {
45
+ return salt === NO_SALT ? 0n : validateSalt(salt)
46
+ }
47
+
28
48
  /** Validates a caller-supplied salt against the `uint128` wire field. */
29
49
  export function validateSalt(salt: bigint): bigint {
30
50
  if (typeof salt !== "bigint" || salt < 0n || salt > MAX_SALT) {
@@ -54,15 +74,15 @@ export function predictEntityKey({
54
74
  * create in a batch uses `nonce + n`.
55
75
  */
56
76
  nonce: bigint
57
- /** The salt the create will carry. */
58
- salt: bigint
77
+ /** The salt the create will carry, or {@link NO_SALT} if it carries none. */
78
+ salt: SaltInput
59
79
  /** The chain the entity is being created on — half of the derivation domain. */
60
80
  chainId: number
61
81
  }): Hex {
62
82
  return keccak256(
63
83
  encodePacked(
64
84
  ["uint256", "address", "address", "uint64", "uint128"],
65
- [BigInt(chainId), ARKIV_ADDRESS, owner, nonce, validateSalt(salt)],
85
+ [BigInt(chainId), ARKIV_ADDRESS, owner, nonce, resolveSalt(salt)],
66
86
  ),
67
87
  )
68
88
  }
@@ -1,6 +1,7 @@
1
1
  import { type Address, encodeAbiParameters, type Hex, parseAbi, parseAbiParameters } from "viem"
2
2
  import type { AbiAttribute } from "../attr/codec"
3
3
  import type { EncodedExpiry } from "./expiry"
4
+ import type { predictEntityKey } from "./key"
4
5
  import { OperationType } from "./params"
5
6
 
6
7
  /**
package/src/index.ts CHANGED
@@ -2,8 +2,6 @@
2
2
  * @module main
3
3
  */
4
4
 
5
- // the advanced path: build, send, ping and read mutation results as separate minimal-RPC steps
6
- export * from "./actions/advanced"
7
5
  // the attribute type system
8
6
  export * from "./attr"
9
7
  // export main arkiv stuff
@@ -12,10 +10,6 @@ export type { PublicArkivClient } from "./clients/createPublicClient"
12
10
  export { createPublicClient } from "./clients/createPublicClient"
13
11
  export type { WalletArkivClient } from "./clients/createWalletClient"
14
12
  export { createWalletClient } from "./clients/createWalletClient"
15
- export type {
16
- PublicAdvancedActions,
17
- WalletAdvancedActions,
18
- } from "./clients/decorators/arkivAdvanced"
19
13
  export type { PublicArkivActions } from "./clients/decorators/arkivPublic"
20
14
  export type { WalletArkivActions } from "./clients/decorators/arkivWallet"
21
15
  // entity lifetimes, flags, keys and the protocol parameters behind them
@@ -24,13 +18,6 @@ export * from "./entity"
24
18
  export * from "./errors"
25
19
  // re-export arkiv types in main index file
26
20
  export * from "./types"
27
- // the building blocks behind the advanced path, for callers that go even lower
28
- export type { EntityMutationOps, MutationEvents } from "./utils/arkivTransactions"
29
- export {
30
- buildEntityOperations,
31
- collectMutationEvents,
32
- mutationNeedsBlockNumber,
33
- } from "./utils/arkivTransactions"
34
21
  // re-export chosen utils
35
22
  export { chainFromName } from "./utils/chains"
36
23
  // every create needs an expiry, and this is the only way to build one
@@ -41,17 +41,6 @@ export type QueryResponse = {
41
41
  export async function runQuery(client: ArkivClient, request: QueryRequest): Promise<QueryResponse> {
42
42
  const { query, select, limit, cursor, atBlock } = request
43
43
 
44
- // A cursor is bound to the block it was issued at; without a block the node reads at the head,
45
- // and the resume breaks whenever a block has landed in between — an intermittent failure this
46
- // turns into a deterministic one. (Pages chained through `QueryResult.next` inherit the block
47
- // automatically; this catches a cursor resumed by hand.)
48
- if (cursor !== undefined && atBlock === undefined) {
49
- throw new Error(
50
- "a cursor must be resumed with `atBlock` set to the `blockNumber` of the page it came " +
51
- "from — persist the two together.",
52
- )
53
- }
54
-
55
44
  if (limit !== undefined) {
56
45
  if (!Number.isInteger(limit) || limit < 1) {
57
46
  throw new Error(`limit must be a positive integer, got ${limit}.`)
@@ -10,7 +10,7 @@ import type { TypeTag } from "../attr"
10
10
  * | | `=` `!=` | `<` `<=` `>` `>=` | `STARTSWITH` |
11
11
  * | --- | --- | --- | --- |
12
12
  * | `bool` | yes | no | no |
13
- * | `i32` `u256` `dec` | yes | yes | no |
13
+ * | `i32` `u64` `u256` `dec` | yes | yes | no |
14
14
  * | `str` | yes | no | yes |
15
15
  * | `addr` `key` `bytes32` | yes | no | no |
16
16
  */
@@ -12,6 +12,10 @@ import {
12
12
  import { TYPE_IDS } from "../attr/types"
13
13
  import { InvalidPredicateError, UnsupportedOperatorError } from "./errors"
14
14
 
15
+ /**
16
+ * The comparison operators the query language defines. `<` `<=` `>` `>=` need an ordered type —
17
+ * `i32`, `u64`, `u256` or `dec`; every type accepts `=` and `!=`.
18
+ */
15
19
  export type ComparisonOperator = "=" | "!=" | "<" | "<=" | ">" | ">="
16
20
 
17
21
  /** A comparison between an attribute and a typed literal. */
@@ -216,7 +220,7 @@ export function ne(name: string, value: ValueInput): ComparisonNode {
216
220
  }
217
221
 
218
222
  /**
219
- * Attribute is greater than value. Ordered types only (`i32`, `u256`, `dec`).
223
+ * Attribute is greater than value. Ordered types only (`i32`, `u64`, `u256`, `dec`).
220
224
  *
221
225
  * @throws {UnsupportedOperatorError} If the value's type carries no ordered index.
222
226
  *
@@ -229,7 +233,7 @@ export function gt(name: string, value: ValueInput): ComparisonNode {
229
233
  }
230
234
 
231
235
  /**
232
- * Attribute is greater than or equal to value. Ordered types only (`i32`, `u256`, `dec`).
236
+ * Attribute is greater than or equal to value. Ordered types only (`i32`, `u64`, `u256`, `dec`).
233
237
  *
234
238
  * @throws {UnsupportedOperatorError} If the value's type carries no ordered index.
235
239
  *
@@ -241,7 +245,7 @@ export function gte(name: string, value: ValueInput): ComparisonNode {
241
245
  }
242
246
 
243
247
  /**
244
- * Attribute is less than value. Ordered types only (`i32`, `u256`, `dec`).
248
+ * Attribute is less than value. Ordered types only (`i32`, `u64`, `u256`, `dec`).
245
249
  *
246
250
  * @throws {UnsupportedOperatorError} If the value's type carries no ordered index.
247
251
  *
@@ -253,7 +257,7 @@ export function lt(name: string, value: ValueInput): ComparisonNode {
253
257
  }
254
258
 
255
259
  /**
256
- * Attribute is less than or equal to value. Ordered types only (`i32`, `u256`, `dec`).
260
+ * Attribute is less than or equal to value. Ordered types only (`i32`, `u64`, `u256`, `dec`).
257
261
  *
258
262
  * @throws {UnsupportedOperatorError} If the value's type carries no ordered index.
259
263
  *
@@ -271,7 +275,9 @@ export function lte(name: string, value: ValueInput): ComparisonNode {
271
275
  * `startsWith("name", "é")` matches only the same byte sequence, not another normal form of it.
272
276
  *
273
277
  * @param prefix - The prefix, as a bare string or a `str` value.
274
- * @throws {UnsupportedOperatorError} If given a value that is not a `str`.
278
+ * @throws {InvalidPredicateError} If the name is not a queryable attribute.
279
+ * @throws {UnsupportedOperatorError} If given a value that is not a `str`, or a system attribute
280
+ * (none of which is a `str`).
275
281
  *
276
282
  * @example
277
283
  * startsWith("desc", "ab") // desc STARTSWITH str('ab')
@@ -325,7 +331,8 @@ export function exists(name: string): ExistsNode {
325
331
  * Useful when the same name is written with different types across entities — a comparison already
326
332
  * asserts the type, so this is for asking about the type alone.
327
333
  *
328
- * @param tag - The type tag: `bool`, `i32`, `u256`, `dec`, `bytes32`, `str`, `addr` or `key`.
334
+ * @param tag - The type tag: `bool`, `i32`, `u64`, `u256`, `dec`, `bytes32`, `str`, `addr` or
335
+ * `key`.
329
336
  * @throws {InvalidPredicateError} If the tag is not a settable type, or the name is a system
330
337
  * attribute (whose type is fixed).
331
338
  *
@@ -344,7 +351,7 @@ export function hasType(name: string, tag: UserTypeTag): TypeOfNode {
344
351
  if (!isUserTypeTag(tag)) {
345
352
  throw new InvalidPredicateError(
346
353
  `"${tag}" is not a settable attribute type. Use one of ` +
347
- "bool, i32, u256, dec, bytes32, str, addr, key.",
354
+ "bool, i32, u64, u256, dec, bytes32, str, addr, key.",
348
355
  name,
349
356
  )
350
357
  }
@@ -242,27 +242,7 @@ describe("pagination", () => {
242
242
 
243
243
  expect(sent(request, 1).query).toBe("a = i32(1)")
244
244
  expect(sent(request, 1).options).not.toHaveProperty("limit")
245
- // The block page 2 reads at is the one page 1 was served from, not the builder's later edit.
246
- expect(sent(request, 1).options).toMatchObject({ atBlock: "0x8e1ff" })
247
- })
248
-
249
- it("pins the rest of the walk to the block the first page was read at", async () => {
250
- const { client, request } = makeClient(
251
- page("b64:1", "0x1"),
252
- page("b64:2", "0x2"),
253
- page(undefined, "0x3"),
254
- )
255
- // No atBlock on the builder: the first page reads at the head, and every page after it reads
256
- // at the block that page came back with. Otherwise a block mined mid-walk moves the head on
257
- // and the node rejects a cursor bound to the earlier one.
258
- const first = await new SelectQueryBuilder(client, { key: true }).where(eq("a", 1)).fetch()
259
- expect(sent(request, 0).options).not.toHaveProperty("atBlock")
260
-
261
- const second = await first.next()
262
- expect(sent(request, 1).options).toMatchObject({ cursor: "b64:1", atBlock: "0x8e1ff" })
263
-
264
- await second.next()
265
- expect(sent(request, 2).options).toMatchObject({ cursor: "b64:2", atBlock: "0x8e1ff" })
245
+ expect(sent(request, 1).options).not.toHaveProperty("atBlock")
266
246
  })
267
247
 
268
248
  it("walks every page through the async iterator", async () => {
@@ -5,7 +5,7 @@ import type { Entity } from "../types/entity"
5
5
  import type { RpcSelect } from "../types/rpcSchema"
6
6
  import { type QueryRequest, runQuery } from "./engine"
7
7
  import { InvalidPredicateError } from "./errors"
8
- import { and, type Expression, eq } from "./expression"
8
+ import { and, type Expression, eq, type or } from "./expression"
9
9
  import { QueryResult } from "./queryResult"
10
10
  import { type SelectArg, toRpcSelect } from "./selection"
11
11
 
@@ -110,9 +110,7 @@ export class SelectQueryBuilder<TEntity = Entity> {
110
110
  *
111
111
  * Pagination normally goes through {@link QueryResult.next}, which carries the cursor for you;
112
112
  * this is for resuming a walk in a later process. A cursor is bound to the query, block and
113
- * selection it came from, so it must be used with an identically-built query — {@link atBlock}
114
- * set to the `blockNumber` of the page the cursor came from is required (persist the two
115
- * together), and a fetch with a cursor but no block rejects locally.
113
+ * selection it came from, so it must be used with an identically-built query.
116
114
  */
117
115
  cursor(cursor: string): this {
118
116
  this._cursor = cursor
@@ -205,17 +203,12 @@ async function fetchPage<TEntity>(
205
203
  ): Promise<QueryResult<TEntity>> {
206
204
  const response = await runQuery(client, { ...request, cursor })
207
205
 
208
- // Pin the rest of the walk to the block this page was read at. Without a block the node reads
209
- // at the head, and a block mined between two pages would leave the cursor bound to the previous
210
- // one — a `kind: "cursor"` rejection mid-walk on an otherwise valid page-through.
211
- const pinned = Object.freeze({ ...request, atBlock: response.blockNumber })
212
-
213
206
  return new QueryResult<TEntity>(
214
207
  // Every row decodes to a full Entity; the static narrowing to the selected fields comes from
215
208
  // `client.select()`'s inference and nothing at runtime depends on it.
216
209
  response.entities as unknown as TEntity[],
217
210
  response.blockNumber,
218
211
  response.cursor,
219
- (next) => fetchPage<TEntity>(client, pinned, next),
212
+ (next) => fetchPage<TEntity>(client, request, next),
220
213
  )
221
214
  }
@@ -12,11 +12,11 @@ export type {
12
12
  } from "../actions/wallet/changeOwnership"
13
13
  export type { CreateEntityParameters, CreateEntityReturnType } from "../actions/wallet/createEntity"
14
14
  export type { DeleteEntityParameters, DeleteEntityReturnType } from "../actions/wallet/deleteEntity"
15
- export type { ExtendEntityParameters, ExtendEntityReturnType } from "../actions/wallet/extendEntity"
16
15
  export type {
17
- MutateEntitiesParameters,
18
- MutateEntitiesReturnType,
19
- } from "../actions/wallet/mutateEntities"
16
+ ExecuteBatchParameters,
17
+ ExecuteBatchReturnType,
18
+ } from "../actions/wallet/executeBatch"
19
+ export type { ExtendEntityParameters, ExtendEntityReturnType } from "../actions/wallet/extendEntity"
20
20
  export type { PatchEntityParameters, PatchEntityReturnType } from "../actions/wallet/patchEntity"
21
21
  export type { EntityFields } from "./entity"
22
22
  export { Entity } from "./entity"
@@ -69,6 +69,7 @@ export type RpcSelect = {
69
69
  attributes?: boolean | Record<string, boolean>
70
70
  }
71
71
 
72
+ /** The second parameter of `arkiv_query` — what to return, and where in the results to start. */
72
73
  export type RpcQueryOptions = {
73
74
  /** Block height to read at, as a hex quantity. Defaults to the head, and must be within the node's retained range. */
74
75
  atBlock?: Hex
@@ -1,3 +1,11 @@
1
+ /**
2
+ * Transaction fields a write action passes through to the wallet, for the cases where the defaults
3
+ * are not what you want.
4
+ *
5
+ * Fee style is either/or: give `gasPrice` for a legacy transaction, or `maxFeePerGas` /
6
+ * `maxPriorityFeePerGas` for an EIP-1559 one. Mixing the two does not typecheck. Anything left out
7
+ * is estimated.
8
+ */
1
9
  export type TxParams =
2
10
  | {
3
11
  gas?: bigint
@@ -23,7 +23,7 @@ import {
23
23
  } from "../attr"
24
24
  import type { ArkivClient } from "../clients/baseClient"
25
25
  import { ARKIV_ADDRESS } from "../consts"
26
- import { InvalidExpiryError } from "../entity"
26
+ import { InvalidExpiryError, NO_SALT } from "../entity"
27
27
  import { ENTITY_EVENTS_ABI, type EntityEventName } from "../entity/events"
28
28
  import { MAX_EXPIRES_AT, OperationType } from "../entity/params"
29
29
  import { EmptyPatchError, EntityMutationError } from "../errors"
@@ -304,6 +304,12 @@ describe("creation flags and salt", () => {
304
304
  expect(sentCreate(w2).salt).toBe(0n)
305
305
  })
306
306
 
307
+ it("sends a zero salt for a create that opts out with NO_SALT", async () => {
308
+ const { client, writeContract } = makeClient()
309
+ await sendArkivTransaction(client, { creates: [{ ...validCreate, salt: NO_SALT }] })
310
+ expect(sentCreate(writeContract).salt).toBe(0n)
311
+ })
312
+
307
313
  it("rejects a salt wider than the uint128 field", async () => {
308
314
  const { client } = makeClient()
309
315
  await expect(