@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.
- package/README.md +0 -42
- package/dist/attr/index.cjs +33 -34
- package/dist/attr/index.d.cts +1 -1
- package/dist/attr/index.d.ts +1 -2
- package/dist/attr/index.js +1 -2
- package/dist/{attributes-Df9IsCVs.cjs → attr-BXTkpnoc.cjs} +13 -3
- package/dist/{attributes-BhY5DwJp.js → attr-tmyREHtw.js} +14 -4
- package/dist/attr-tmyREHtw.js.map +1 -0
- package/dist/chains/index.cjs +1 -1
- package/dist/chains/index.d.cts +3 -0
- package/dist/chains/index.d.cts.map +1 -1
- package/dist/chains/index.d.ts +3 -0
- package/dist/chains/index.d.ts.map +1 -1
- package/dist/chains/index.js +1 -1
- package/dist/{chains-BYRTTipa.cjs → chains-BfNQliHU.cjs} +3 -0
- package/dist/{chains-BJrZs6sG.js → chains-Du8tql7I.js} +4 -1
- package/dist/chains-Du8tql7I.js.map +1 -0
- package/dist/{arkivTransactions-NtGD6uk5.d.ts → changeOwnership-B0ar96ub.d.ts} +74 -123
- package/dist/changeOwnership-B0ar96ub.d.ts.map +1 -0
- package/dist/{arkivTransactions-D74gERHG.d.cts → changeOwnership-BofkLnXJ.d.cts} +74 -123
- package/dist/changeOwnership-BofkLnXJ.d.cts.map +1 -0
- package/dist/entity/index.cjs +9 -9
- package/dist/entity/index.d.cts +3 -3
- package/dist/entity/index.d.ts +4 -5
- package/dist/entity/index.js +5 -6
- package/dist/{entity-BYQR1uoe.js → entity-BIp_df9u.js} +1 -1
- package/dist/{entity-BYQR1uoe.js.map → entity-BIp_df9u.js.map} +1 -1
- package/dist/{key-D1Bh7MF0.js → entity-CniBgBSd.js} +31 -19
- package/dist/entity-CniBgBSd.js.map +1 -0
- package/dist/{key-WKhXnXuU.cjs → entity-DJ0Gml9c.cjs} +37 -19
- package/dist/{errors-LTe7bOYS.js → errors-D2E1GRjw.js} +2 -2
- package/dist/errors-D2E1GRjw.js.map +1 -0
- package/dist/{errors-BVbjKVMN.cjs → errors-DhV00966.cjs} +1 -1
- package/dist/{expiry-nDbCgZX4.d.ts → expiry-BxOlvVWC.d.ts} +1 -1
- package/dist/{expiry-nDbCgZX4.d.ts.map → expiry-BxOlvVWC.d.ts.map} +1 -1
- package/dist/{expiry-BELY2Kpw.cjs → expiry-CG9GhVXv.cjs} +1 -1
- package/dist/{expiry-BjpxZZQU.js → expiry-Cgdb_dbq.js} +2 -2
- package/dist/expiry-Cgdb_dbq.js.map +1 -0
- package/dist/expiry-DRV29F1r.d.cts.map +1 -1
- package/dist/{flags-CRjPpoh3.d.cts → flags-0Vl5rrHq.d.cts} +1 -1
- package/dist/{flags-CRjPpoh3.d.cts.map → flags-0Vl5rrHq.d.cts.map} +1 -1
- package/dist/{flags-kr276q6i.cjs → flags-DCD26uhe.cjs} +1 -1
- package/dist/{flags-DFBs2J94.js → flags-DUT2gHEU.js} +2 -2
- package/dist/{flags-DFBs2J94.js.map → flags-DUT2gHEU.js.map} +1 -1
- package/dist/{flags-5dTNRnow.d.ts → flags-wmcMoAnN.d.ts} +1 -1
- package/dist/{flags-5dTNRnow.d.ts.map → flags-wmcMoAnN.d.ts.map} +1 -1
- package/dist/{index-fX_XyqLp.d.ts → index-BGp2plHs.d.cts} +15 -13
- package/dist/index-BGp2plHs.d.cts.map +1 -0
- package/dist/{index-DHDud2hC.d.ts → index-BKB875Um.d.ts} +5 -7
- package/dist/{index-DHDud2hC.d.ts.map → index-BKB875Um.d.ts.map} +1 -1
- package/dist/{index-DvYvrkdk.d.ts → index-CIcHPx2j.d.cts} +110 -6
- package/dist/index-CIcHPx2j.d.cts.map +1 -0
- package/dist/{index-CV5zCdpa.d.cts → index-Cd2aaWme.d.ts} +13 -6
- package/dist/index-Cd2aaWme.d.ts.map +1 -0
- package/dist/{index-CA4V7Pdh.d.cts → index-ezMZ2-JH.d.ts} +15 -13
- package/dist/index-ezMZ2-JH.d.ts.map +1 -0
- package/dist/{index-BF7Mq9Is.d.cts → index-rINthNuU.d.cts} +5 -7
- package/dist/{index-BF7Mq9Is.d.cts.map → index-rINthNuU.d.cts.map} +1 -1
- package/dist/index.cjs +433 -139
- package/dist/index.d.cts +58 -164
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +59 -166
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +376 -75
- package/dist/index.js.map +1 -1
- package/dist/{payload-CcUj85ys.d.ts → payload-CGvVPZQX.d.ts} +61 -2
- package/dist/payload-CGvVPZQX.d.ts.map +1 -0
- package/dist/{payload-Bz6651ax.js → payload-DE7wMztL.js} +28 -3
- package/dist/payload-DE7wMztL.js.map +1 -0
- package/dist/{payload-BNoud2KZ.d.cts → payload-Dfu30njp.d.cts} +60 -1
- package/dist/payload-Dfu30njp.d.cts.map +1 -0
- package/dist/{payload-KC14SDlN.cjs → payload-DqFweqiO.cjs} +27 -2
- package/dist/query/index.cjs +5 -7
- package/dist/query/index.d.cts +4 -4
- package/dist/query/index.d.ts +4 -5
- package/dist/query/index.js +5 -7
- package/dist/{queryBuilder-DM6AWCBa.js → queryBuilder-wvA8sn--.js} +169 -23
- package/dist/queryBuilder-wvA8sn--.js.map +1 -0
- package/dist/{queryBuilder-DbUMEZln.cjs → queryBuilder-zHGhDmaG.cjs} +215 -33
- package/dist/{selection-DPg0uyJf.d.cts → selection-Bv8_o-7i.d.cts} +76 -68
- package/dist/selection-Bv8_o-7i.d.cts.map +1 -0
- package/dist/{selection-C4UhsMOO.d.ts → selection-ox7zdtVm.d.ts} +76 -69
- package/dist/selection-ox7zdtVm.d.ts.map +1 -0
- package/dist/types/index.cjs +2 -2
- package/dist/types/index.d.cts +6 -6
- package/dist/types/index.d.ts +7 -8
- package/dist/types/index.js +2 -2
- package/dist/utils/index.cjs +3 -3
- package/dist/utils/index.d.cts +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +3 -3
- package/package.json +1 -5
- package/src/actions/public/getEntity.ts +1 -0
- package/src/actions/public/predictEntityKeys.test.ts +17 -1
- package/src/actions/public/predictEntityKeys.ts +28 -14
- package/src/actions/public/query.ts +1 -5
- package/src/actions/wallet/createEntity.ts +7 -6
- package/src/actions/wallet/{mutateEntities.test.ts → executeBatch.test.ts} +7 -7
- package/src/actions/wallet/{mutateEntities.ts → executeBatch.ts} +26 -11
- package/src/actions/wallet/extendEntity.ts +1 -0
- package/src/actions/wallet/patchEntity.ts +3 -3
- package/src/attr/attributes.ts +8 -2
- package/src/attr/errors.ts +2 -2
- package/src/attr/types.ts +3 -3
- package/src/attr/values.ts +5 -1
- package/src/chains/localhost.ts +3 -0
- package/src/clients/createPublicClient.test.ts +1 -1
- package/src/clients/createPublicClient.ts +5 -5
- package/src/clients/createWalletClient.test.ts +2 -2
- package/src/clients/createWalletClient.ts +3 -5
- package/src/clients/decorators/arkivPublic.ts +13 -24
- package/src/clients/decorators/arkivWallet.ts +40 -47
- package/src/entity/create.test.ts +20 -1
- package/src/entity/errors.ts +4 -3
- package/src/entity/expiry.ts +1 -0
- package/src/entity/index.ts +2 -2
- package/src/entity/key.ts +23 -3
- package/src/entity/operations.ts +1 -0
- package/src/index.ts +0 -13
- package/src/query/engine.ts +0 -11
- package/src/query/errors.ts +1 -1
- package/src/query/expression.ts +14 -7
- package/src/query/queryBuilder.test.ts +1 -21
- package/src/query/queryBuilder.ts +3 -10
- package/src/types/index.ts +4 -4
- package/src/types/rpcSchema.ts +1 -0
- package/src/types/txParams.ts +8 -0
- package/src/utils/arkivTransactions.test.ts +7 -1
- package/src/utils/arkivTransactions.ts +114 -254
- package/src/utils/expirationTime.ts +39 -0
- package/src/utils/payload.ts +25 -0
- package/dist/actions/advanced/index.cjs +0 -13
- package/dist/actions/advanced/index.d.cts +0 -8
- package/dist/actions/advanced/index.d.ts +0 -9
- package/dist/actions/advanced/index.js +0 -9
- package/dist/advanced-8ZPTmmaN.js +0 -598
- package/dist/advanced-8ZPTmmaN.js.map +0 -1
- package/dist/advanced-fPImL6lW.cjs +0 -656
- package/dist/arkivTransactions-D74gERHG.d.cts.map +0 -1
- package/dist/arkivTransactions-NtGD6uk5.d.ts.map +0 -1
- package/dist/attributes-BhY5DwJp.js.map +0 -1
- package/dist/chains-BJrZs6sG.js.map +0 -1
- package/dist/codec-Car3KkFF.d.ts +0 -102
- package/dist/codec-Car3KkFF.d.ts.map +0 -1
- package/dist/entity-B7G8q_Eo.cjs +0 -0
- package/dist/entity-CD_qFF2M.js +0 -0
- package/dist/errors-LTe7bOYS.js.map +0 -1
- package/dist/expiry-BjpxZZQU.js.map +0 -1
- package/dist/index-B5j76711.d.ts +0 -184
- package/dist/index-B5j76711.d.ts.map +0 -1
- package/dist/index-CA4V7Pdh.d.cts.map +0 -1
- package/dist/index-CV5zCdpa.d.cts.map +0 -1
- package/dist/index-DvYvrkdk.d.ts.map +0 -1
- package/dist/index-EeUO0nnJ.d.cts +0 -184
- package/dist/index-EeUO0nnJ.d.cts.map +0 -1
- package/dist/index-fX_XyqLp.d.ts.map +0 -1
- package/dist/key-D1Bh7MF0.js.map +0 -1
- package/dist/logger-CVpvU8ik.js +0 -153
- package/dist/logger-CVpvU8ik.js.map +0 -1
- package/dist/logger-Cr15lPAQ.cjs +0 -188
- package/dist/payload-BNoud2KZ.d.cts.map +0 -1
- package/dist/payload-Bz6651ax.js.map +0 -1
- package/dist/payload-CcUj85ys.d.ts.map +0 -1
- package/dist/queryBuilder-DM6AWCBa.js.map +0 -1
- package/dist/selection-C4UhsMOO.d.ts.map +0 -1
- package/dist/selection-DPg0uyJf.d.cts.map +0 -1
- package/dist/types-Bu_ZwMbZ.js +0 -0
- package/dist/types-NRqymi6S.cjs +0 -0
- package/src/actions/advanced/advanced.test.ts +0 -258
- package/src/actions/advanced/buildMutation.ts +0 -104
- package/src/actions/advanced/getMutationResult.ts +0 -112
- package/src/actions/advanced/index.ts +0 -21
- package/src/actions/advanced/pingTransaction.ts +0 -43
- package/src/actions/advanced/sendMutation.ts +0 -59
- package/src/clients/decorators/arkivAdvanced.ts +0 -144
- /package/dist/{entity-B00Li04j.cjs → entity-B0t6sN7F.cjs} +0 -0
- /package/dist/{attr-DlmErkvR.cjs → types-Bx1EKe0v.js} +0 -0
- /package/dist/{attr-GcQKatub.js → types-CKPddlfS.cjs} +0 -0
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
import type { Address, Hex } from "viem"
|
|
2
2
|
import { getChainId } from "viem/actions"
|
|
3
3
|
import type { ArkivClient } from "../../clients/baseClient"
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
NO_SALT,
|
|
6
|
+
predictEntityKey,
|
|
7
|
+
randomSalt,
|
|
8
|
+
resolveSalt,
|
|
9
|
+
type SaltInput,
|
|
10
|
+
} from "../../entity/key"
|
|
5
11
|
import { getEntityNonce } from "./getEntityNonce"
|
|
6
12
|
|
|
7
13
|
/**
|
|
@@ -13,14 +19,18 @@ import { getEntityNonce } from "./getEntityNonce"
|
|
|
13
19
|
export type PredictedEntityKey = {
|
|
14
20
|
/** The key the create will be given. */
|
|
15
21
|
key: Hex
|
|
16
|
-
/**
|
|
22
|
+
/**
|
|
23
|
+
* The salt the create must carry for its key to come out as {@link PredictedEntityKey.key}.
|
|
24
|
+
* Always a plain `uint128` — a requested {@link NO_SALT} comes back as the `0n` it resolves to,
|
|
25
|
+
* which a create accepts just the same.
|
|
26
|
+
*/
|
|
17
27
|
salt: bigint
|
|
18
28
|
}
|
|
19
29
|
|
|
20
|
-
/** Parameters for
|
|
30
|
+
/** Parameters for `client.predictEntityKeys`. */
|
|
21
31
|
export type PredictEntityKeysParameters<
|
|
22
32
|
TCount extends number = number,
|
|
23
|
-
TSalts extends readonly
|
|
33
|
+
TSalts extends readonly SaltInput[] | undefined = readonly SaltInput[] | undefined,
|
|
24
34
|
> = {
|
|
25
35
|
/** The account that will sign the creates. Its nonce is what the keys are derived from. */
|
|
26
36
|
owner: Address
|
|
@@ -34,7 +44,8 @@ export type PredictEntityKeysParameters<
|
|
|
34
44
|
count?: TCount | undefined
|
|
35
45
|
/**
|
|
36
46
|
* The salt each create will carry, in batch order. Defaults to `count` fresh random salts —
|
|
37
|
-
* either way each key comes back paired with the salt that mints it.
|
|
47
|
+
* either way each key comes back paired with the salt that mints it. Pass {@link NO_SALT} in a
|
|
48
|
+
* slot whose create opts out of salting.
|
|
38
49
|
*/
|
|
39
50
|
salts?: TSalts
|
|
40
51
|
}
|
|
@@ -46,13 +57,13 @@ export type PredictEntityKeysParameters<
|
|
|
46
57
|
* tuple, gives a fixed-length tuple; a count computed at runtime gives a plain array.
|
|
47
58
|
*
|
|
48
59
|
* `TSalts` is wrapped in a tuple to stop the conditional distributing over it. Left naked, the
|
|
49
|
-
* `readonly
|
|
50
|
-
* which widens the length straight back to `number`.
|
|
60
|
+
* `readonly SaltInput[] | undefined` default would take both branches and union a tuple with an
|
|
61
|
+
* array, which widens the length straight back to `number`.
|
|
51
62
|
*/
|
|
52
63
|
export type PredictEntityKeysReturnType<
|
|
53
64
|
TCount extends number = number,
|
|
54
|
-
TSalts extends readonly
|
|
55
|
-
> = [TSalts] extends [readonly
|
|
65
|
+
TSalts extends readonly SaltInput[] | undefined = readonly SaltInput[] | undefined,
|
|
66
|
+
> = [TSalts] extends [readonly SaltInput[]]
|
|
56
67
|
? { -readonly [Index in keyof TSalts]: PredictedEntityKey }
|
|
57
68
|
: Repeat<PredictedEntityKey, TCount>
|
|
58
69
|
|
|
@@ -79,7 +90,7 @@ type Repeat<T, TLength extends number, TAcc extends T[] = []> = number extends T
|
|
|
79
90
|
*
|
|
80
91
|
* The prediction is valid only while nothing else from this owner is in flight. Every create that
|
|
81
92
|
* lands first takes the nonce with it and moves these keys. For a key you can rely on
|
|
82
|
-
* unconditionally, read it back from the create instead — `createEntity` and `
|
|
93
|
+
* unconditionally, read it back from the create instead — `createEntity` and `executeBatch`
|
|
83
94
|
* report the keys the engine actually minted.
|
|
84
95
|
*
|
|
85
96
|
* @param parameters - Owner, and either a count or the salts. {@link PredictEntityKeysParameters}
|
|
@@ -89,7 +100,7 @@ type Repeat<T, TLength extends number, TAcc extends T[] = []> = number extends T
|
|
|
89
100
|
* import { key } from "@arkiv-network/sdk/attr"
|
|
90
101
|
*
|
|
91
102
|
* const [parent, child] = await client.predictEntityKeys({ owner: account.address, count: 2 })
|
|
92
|
-
* await
|
|
103
|
+
* await client.executeBatch({
|
|
93
104
|
* creates: [
|
|
94
105
|
* { payload, contentType, expires, salt: parent.salt },
|
|
95
106
|
* {
|
|
@@ -104,7 +115,7 @@ type Repeat<T, TLength extends number, TAcc extends T[] = []> = number extends T
|
|
|
104
115
|
*/
|
|
105
116
|
export async function predictEntityKeys<
|
|
106
117
|
const TCount extends number = number,
|
|
107
|
-
const TSalts extends readonly
|
|
118
|
+
const TSalts extends readonly SaltInput[] | undefined = undefined,
|
|
108
119
|
>(
|
|
109
120
|
client: ArkivClient,
|
|
110
121
|
{ owner, count, salts }: PredictEntityKeysParameters<TCount, TSalts>,
|
|
@@ -121,12 +132,15 @@ export async function predictEntityKeys<
|
|
|
121
132
|
}
|
|
122
133
|
|
|
123
134
|
/** The salts to derive from: the ones given, or `count` fresh random ones. */
|
|
124
|
-
function resolveSalts(
|
|
135
|
+
function resolveSalts(
|
|
136
|
+
count: number | undefined,
|
|
137
|
+
salts: readonly SaltInput[] | undefined,
|
|
138
|
+
): bigint[] {
|
|
125
139
|
if (salts !== undefined) {
|
|
126
140
|
if (salts.length === 0) {
|
|
127
141
|
throw new Error("predictEntityKeys: `salts` is empty — there is nothing to predict")
|
|
128
142
|
}
|
|
129
|
-
return salts.map(
|
|
143
|
+
return salts.map(resolveSalt)
|
|
130
144
|
}
|
|
131
145
|
if (count === undefined) {
|
|
132
146
|
throw new Error("predictEntityKeys: pass either `count` or `salts`")
|
|
@@ -11,11 +11,7 @@ export type QueryOptions = {
|
|
|
11
11
|
atBlock?: bigint | undefined
|
|
12
12
|
/** Page size, up to the node maximum of 200. */
|
|
13
13
|
limit?: number | undefined
|
|
14
|
-
/**
|
|
15
|
-
* Cursor from a previous page. Requires that page's `blockNumber` as {@link atBlock} alongside
|
|
16
|
-
* it — the cursor is bound to the block it was issued at, so persist the two together. A cursor
|
|
17
|
-
* without a block is rejected locally rather than left to fail whenever a block lands mid-walk.
|
|
18
|
-
*/
|
|
14
|
+
/** Cursor from a previous page. */
|
|
19
15
|
cursor?: string | undefined
|
|
20
16
|
}
|
|
21
17
|
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { Hash, Hex } from "viem"
|
|
2
2
|
import type { AttributeInputs } from "../../attr"
|
|
3
3
|
import type { ArkivClient } from "../../clients/baseClient"
|
|
4
|
-
import type { CreationFlags, Expiry } from "../../entity"
|
|
4
|
+
import type { CreationFlags, Expiry, NO_SALT, SaltInput } from "../../entity"
|
|
5
5
|
import { EntityMutationError } from "../../errors"
|
|
6
6
|
import type { MimeType, TxParams } from "../../types"
|
|
7
7
|
import { sendArkivTransaction } from "../../utils/arkivTransactions"
|
|
8
|
+
import type { ExpirationTime } from "../../utils/expirationTime"
|
|
8
9
|
import { getLogger } from "../../utils/logger"
|
|
9
10
|
|
|
10
11
|
const logger = getLogger("actions:wallet:create-entity")
|
|
@@ -66,8 +67,8 @@ export type CreateEntityParameters = {
|
|
|
66
67
|
contentType: MimeType | (string & {})
|
|
67
68
|
/**
|
|
68
69
|
* The entity's queryable attributes, keyed by name. Values are the tagged constructors from
|
|
69
|
-
* `@arkiv-network/sdk/attr` — `i32`, `u256`, `dec`, `str`, `addr`, `key`, `bytes32`,
|
|
70
|
-
* a bare `boolean`, `number`, `bigint` or `string` where the type is unambiguous.
|
|
70
|
+
* `@arkiv-network/sdk/attr` — `i32`, `u64`, `u256`, `dec`, `str`, `addr`, `key`, `bytes32`,
|
|
71
|
+
* `bool` — or a bare `boolean`, `number`, `bigint` or `string` where the type is unambiguous.
|
|
71
72
|
*
|
|
72
73
|
* @throws {InvalidAttributeNameError} If a name violates the attribute-name grammar.
|
|
73
74
|
* @throws {InvalidValueError} If a value does not fit the type it names or defaults to.
|
|
@@ -82,10 +83,10 @@ export type CreateEntityParameters = {
|
|
|
82
83
|
* The salt mixed into the entity key. Defaults to 128 random bits, which makes the key
|
|
83
84
|
* unpredictable to everyone but the creator.
|
|
84
85
|
*
|
|
85
|
-
* Pass
|
|
86
|
-
* what you want only when a third party must be able to compute the key in advance.
|
|
86
|
+
* Pass {@link NO_SALT} for a key derived from the owner and nonce alone — predictable by anyone,
|
|
87
|
+
* which is what you want only when a third party must be able to compute the key in advance.
|
|
87
88
|
*/
|
|
88
|
-
salt?:
|
|
89
|
+
salt?: SaltInput | undefined
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it, vi } from "bun:test"
|
|
2
2
|
import type { ArkivClient } from "../../clients/baseClient"
|
|
3
|
-
import {
|
|
3
|
+
import { executeBatch } from "./executeBatch"
|
|
4
4
|
|
|
5
5
|
const ENTITY_KEY = `0x${"ab".repeat(32)}` as const
|
|
6
6
|
const NEW_OWNER = "0x2222222222222222222222222222222222222222"
|
|
@@ -29,7 +29,7 @@ describe("the empty-batch guard", () => {
|
|
|
29
29
|
// An ownership-only batch is a batch: it used to be rejected because the guard listed
|
|
30
30
|
// creates/updates/deletes/extensions and forgot ownershipChanges.
|
|
31
31
|
const { client, writeContract } = makeClient()
|
|
32
|
-
const result = await
|
|
32
|
+
const result = await executeBatch(client, {
|
|
33
33
|
ownershipChanges: [{ entityKey: ENTITY_KEY, newOwner: NEW_OWNER }],
|
|
34
34
|
})
|
|
35
35
|
expect(writeContract).toHaveBeenCalledTimes(1)
|
|
@@ -38,9 +38,9 @@ describe("the empty-batch guard", () => {
|
|
|
38
38
|
|
|
39
39
|
it("rejects a batch with nothing in it", async () => {
|
|
40
40
|
const { client, writeContract } = makeClient()
|
|
41
|
-
await expect(
|
|
41
|
+
await expect(executeBatch(client, {})).rejects.toThrow(/No operations/)
|
|
42
42
|
// Present but empty is just as empty — the engine would revert with EmptyBatch().
|
|
43
|
-
await expect(
|
|
43
|
+
await expect(executeBatch(client, { deletes: [], ownershipChanges: [] })).rejects.toThrow(
|
|
44
44
|
/No operations/,
|
|
45
45
|
)
|
|
46
46
|
expect(writeContract).not.toHaveBeenCalled()
|
|
@@ -52,10 +52,10 @@ describe("the empty-batch guard", () => {
|
|
|
52
52
|
// keys would score this batch as non-empty and then drop it on the way to the wire, sending
|
|
53
53
|
// execute([]) — so the guard counts the five kinds that actually reach the transaction.
|
|
54
54
|
const stale = { updates: [{ entityKey: ENTITY_KEY, set: { level: 1 } }] } as never
|
|
55
|
-
await expect(
|
|
55
|
+
await expect(executeBatch(client, stale)).rejects.toThrow(/No operations/)
|
|
56
56
|
// A typo is the same mistake with a different name.
|
|
57
57
|
await expect(
|
|
58
|
-
|
|
58
|
+
executeBatch(client, { delete: [{ entityKey: ENTITY_KEY }] } as never),
|
|
59
59
|
).rejects.toThrow(/No operations/)
|
|
60
60
|
expect(writeContract).not.toHaveBeenCalled()
|
|
61
61
|
})
|
|
@@ -65,7 +65,7 @@ describe("the empty-batch guard", () => {
|
|
|
65
65
|
// The dangerous shape: the creates apply and the transaction succeeds, so nothing surfaces the
|
|
66
66
|
// fact that the `updates` never happened. The guard cannot catch this one — only the caller's
|
|
67
67
|
// types can — but the result must at least not claim they did.
|
|
68
|
-
const result = await
|
|
68
|
+
const result = await executeBatch(client, {
|
|
69
69
|
deletes: [{ entityKey: ENTITY_KEY }],
|
|
70
70
|
updates: [{ entityKey: ENTITY_KEY, set: { level: 1 } }],
|
|
71
71
|
} as never)
|
|
@@ -1,22 +1,37 @@
|
|
|
1
1
|
import type { Hash, Hex } from "viem"
|
|
2
2
|
import type { ArkivClient } from "../../clients/baseClient"
|
|
3
3
|
import type { TxParams } from "../../types"
|
|
4
|
-
import {
|
|
4
|
+
import { sendArkivTransaction } from "../../utils/arkivTransactions"
|
|
5
5
|
import { getLogger } from "../../utils/logger"
|
|
6
|
+
import type { ChangeOwnershipParameters } from "./changeOwnership"
|
|
7
|
+
import type { CreateEntityParameters } from "./createEntity"
|
|
8
|
+
import type { DeleteEntityParameters } from "./deleteEntity"
|
|
9
|
+
import type { ExtendEntityParameters } from "./extendEntity"
|
|
10
|
+
import type { PatchEntityParameters } from "./patchEntity"
|
|
6
11
|
|
|
7
|
-
const logger = getLogger("actions:wallet:
|
|
12
|
+
const logger = getLogger("actions:wallet:execute-batch")
|
|
8
13
|
|
|
9
14
|
/**
|
|
10
|
-
* Parameters for the
|
|
11
|
-
* ({@link EntityMutationOps}), so the two surfaces cannot drift apart.
|
|
15
|
+
* Parameters for the executeBatch function.
|
|
12
16
|
*
|
|
13
17
|
* At least one operation is required; a batch with nothing in it throws rather than spending gas on
|
|
14
18
|
* an empty transaction.
|
|
15
19
|
*/
|
|
16
|
-
export type
|
|
20
|
+
export type ExecuteBatchParameters = {
|
|
21
|
+
/** The entities to create. */
|
|
22
|
+
creates?: CreateEntityParameters[]
|
|
23
|
+
/** The patches to apply. */
|
|
24
|
+
patches?: PatchEntityParameters[]
|
|
25
|
+
/** The entities to delete. */
|
|
26
|
+
deletes?: DeleteEntityParameters[]
|
|
27
|
+
/** The expiries to set. */
|
|
28
|
+
extensions?: ExtendEntityParameters[]
|
|
29
|
+
/** The ownership transfers to perform. */
|
|
30
|
+
ownershipChanges?: ChangeOwnershipParameters[]
|
|
31
|
+
}
|
|
17
32
|
|
|
18
|
-
/** Return type for the
|
|
19
|
-
export type
|
|
33
|
+
/** Return type for the executeBatch function. */
|
|
34
|
+
export type ExecuteBatchReturnType = {
|
|
20
35
|
/** The transaction hash. */
|
|
21
36
|
txHash: Hash
|
|
22
37
|
/** The keys of the created entities, in batch order. */
|
|
@@ -31,14 +46,14 @@ export type MutateEntitiesReturnType = {
|
|
|
31
46
|
ownershipChanges: Hex[]
|
|
32
47
|
}
|
|
33
48
|
|
|
34
|
-
export async function
|
|
49
|
+
export async function executeBatch(
|
|
35
50
|
client: ArkivClient,
|
|
36
|
-
data:
|
|
51
|
+
data: ExecuteBatchParameters,
|
|
37
52
|
txParams?: TxParams,
|
|
38
|
-
): Promise<
|
|
53
|
+
): Promise<ExecuteBatchReturnType> {
|
|
39
54
|
const { receipt, createdEntityKeys } = await sendArkivTransaction(client, data, txParams)
|
|
40
55
|
|
|
41
|
-
logger("Receipt from
|
|
56
|
+
logger("Receipt from executeBatch %o", receipt)
|
|
42
57
|
|
|
43
58
|
return {
|
|
44
59
|
txHash: receipt.transactionHash as Hash,
|
|
@@ -4,6 +4,7 @@ import type { Expiry } from "../../entity"
|
|
|
4
4
|
import { EntityMutationError } from "../../errors"
|
|
5
5
|
import type { TxParams } from "../../types"
|
|
6
6
|
import { sendArkivTransaction } from "../../utils/arkivTransactions"
|
|
7
|
+
import type { ExpirationTime } from "../../utils/expirationTime"
|
|
7
8
|
import { getLogger } from "../../utils/logger"
|
|
8
9
|
|
|
9
10
|
const logger = getLogger("actions:wallet:extend-entity")
|
|
@@ -38,9 +38,9 @@ export type PatchEntityParameters = {
|
|
|
38
38
|
* Attributes to write, keyed by name. An existing attribute is overwritten — including with a
|
|
39
39
|
* different type — and a name the entity does not carry yet is added.
|
|
40
40
|
*
|
|
41
|
-
* Values are the tagged constructors from `@arkiv-network/sdk/attr` — `i32`, `
|
|
42
|
-
* `addr`, `key`, `bytes32`, `bool` — or a bare `boolean`, `number`, `bigint` or
|
|
43
|
-
* type is unambiguous.
|
|
41
|
+
* Values are the tagged constructors from `@arkiv-network/sdk/attr` — `i32`, `u64`, `u256`,
|
|
42
|
+
* `dec`, `str`, `addr`, `key`, `bytes32`, `bool` — or a bare `boolean`, `number`, `bigint` or
|
|
43
|
+
* `string` where the type is unambiguous.
|
|
44
44
|
*
|
|
45
45
|
* @throws {InvalidAttributeNameError} If a name violates the attribute-name grammar.
|
|
46
46
|
* @throws {InvalidValueError} If a value does not fit the type it names or defaults to.
|
package/src/attr/attributes.ts
CHANGED
|
@@ -10,6 +10,10 @@ import { str, toValue, type ValueInput } from "./values"
|
|
|
10
10
|
*/
|
|
11
11
|
export const MAX_ATTRIBUTES = 32
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* The largest payload an entity may carry, in bytes. The payload travels as the `$payload` system
|
|
15
|
+
* cell, so this is a bound on that one attribute rather than on the operation as a whole.
|
|
16
|
+
*/
|
|
13
17
|
export const MAX_PAYLOAD_BYTES = 128 * 1024
|
|
14
18
|
|
|
15
19
|
/** The system attribute holding an entity's opaque payload. */
|
|
@@ -20,7 +24,7 @@ const CONTENT_TYPE_CELL = "$contentType"
|
|
|
20
24
|
/**
|
|
21
25
|
* The attributes written on an entity, as a plain object keyed by attribute name.
|
|
22
26
|
*
|
|
23
|
-
* Values may be tagged ({@link
|
|
27
|
+
* Values may be tagged ({@link ArkivValue}) or bare where the type is unambiguous — see
|
|
24
28
|
* {@link toValue} for the bare-form defaults.
|
|
25
29
|
*
|
|
26
30
|
* @example
|
|
@@ -141,8 +145,10 @@ export type MutationInputs = SystemCells & {
|
|
|
141
145
|
*
|
|
142
146
|
* @throws {ConflictingMutationError} If a name appears in both `set` and `unset`.
|
|
143
147
|
* @throws {InvalidAttributeNameError} If a name violates the attribute-name grammar.
|
|
148
|
+
* @throws {MissingValueError} If a value is `undefined` or `null`.
|
|
144
149
|
* @throws {InvalidValueError} If a value does not fit its type.
|
|
145
|
-
* @throws {TooManyAttributesError} If
|
|
150
|
+
* @throws {TooManyAttributesError} If the mutations exceed {@link MAX_ATTRIBUTES}.
|
|
151
|
+
* @throws {TypeError} If `unset` is not an array.
|
|
146
152
|
*/
|
|
147
153
|
export function encodeMutations({
|
|
148
154
|
set,
|
package/src/attr/errors.ts
CHANGED
|
@@ -32,8 +32,8 @@ export class UntypedValueError extends Error {
|
|
|
32
32
|
constructor(input: unknown) {
|
|
33
33
|
super(
|
|
34
34
|
`Cannot infer an Arkiv type for ${describe(input)}. ` +
|
|
35
|
-
"Attribute values must be a tagged value (i32, u256, dec, str, addr, key, bytes32,
|
|
36
|
-
"or a bare boolean, number, bigint or string.",
|
|
35
|
+
"Attribute values must be a tagged value (i32, u64, u256, dec, str, addr, key, bytes32, " +
|
|
36
|
+
"bool) or a bare boolean, number, bigint or string.",
|
|
37
37
|
)
|
|
38
38
|
this.name = "UntypedValueError"
|
|
39
39
|
this.input = input
|
package/src/attr/types.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Address, Hex } from "viem"
|
|
2
|
+
import type { decUnits } from "./values"
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* The protocol's attribute type vocabulary, mapping each short **tag** (the name used by the
|
|
@@ -54,8 +55,7 @@ export function isUserSettable(tag: TypeTag): tag is UserTypeTag {
|
|
|
54
55
|
/**
|
|
55
56
|
* Marks a value as having passed its constructor's validation. The symbol is module-private, so a
|
|
56
57
|
* hand-written object literal is not assignable to {@link ArkivValue} — every value crossing the
|
|
57
|
-
* wire has been range-, length- and format-checked by
|
|
58
|
-
* friends.
|
|
58
|
+
* wire has been range-, length- and format-checked by `i32`, `u256`, `dec`, and friends.
|
|
59
59
|
*/
|
|
60
60
|
declare const validated: unique symbol
|
|
61
61
|
|
|
@@ -89,7 +89,7 @@ export type U256Value = Value<"u256", bigint>
|
|
|
89
89
|
export type DecValue = Value<"dec", string>
|
|
90
90
|
/** 32 opaque bytes, as lowercase `0x` hex. */
|
|
91
91
|
export type Bytes32Value = Value<"bytes32", Hex>
|
|
92
|
-
/** A UTF-8 string of at most 128 bytes. */
|
|
92
|
+
/** A UTF-8 string of at most 128 bytes, free of C0 control characters and DEL. */
|
|
93
93
|
export type StrValue = Value<"str", string>
|
|
94
94
|
/** A 20-byte Ethereum address, as EIP-55 checksummed hex. */
|
|
95
95
|
export type AddrValue = Value<"addr", Address>
|
package/src/attr/values.ts
CHANGED
|
@@ -271,7 +271,11 @@ export function decFromUnits(units: bigint): DecValue {
|
|
|
271
271
|
*
|
|
272
272
|
* The limit is on **bytes**, not characters: a string of 128 emoji does not fit.
|
|
273
273
|
*
|
|
274
|
-
*
|
|
274
|
+
* C0 control characters and DEL are rejected: the query language writes a `str` as `str('...')`,
|
|
275
|
+
* whose only escape is a doubled quote, so a control character could be stored but never queried.
|
|
276
|
+
*
|
|
277
|
+
* @throws {InvalidValueError} If the value is not a string, holds a control character, or exceeds
|
|
278
|
+
* 128 UTF-8 bytes.
|
|
275
279
|
*
|
|
276
280
|
* @example
|
|
277
281
|
* str("Bob")
|
package/src/chains/localhost.ts
CHANGED
|
@@ -35,5 +35,5 @@ test("creates", () => {
|
|
|
35
35
|
expect(client.deleteEntity).not.toBeDefined()
|
|
36
36
|
expect(client.extendEntity).not.toBeDefined()
|
|
37
37
|
expect(client.changeOwnership).not.toBeDefined()
|
|
38
|
-
expect(client.
|
|
38
|
+
expect(client.executeBatch).not.toBeDefined()
|
|
39
39
|
})
|
|
@@ -23,14 +23,14 @@ export type PublicArkivClient<
|
|
|
23
23
|
>
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Creates a Public Client with a given [Transport](https://viem.sh/docs/clients/intro) configured for a [Chain](https://viem.sh/docs/
|
|
26
|
+
* Creates a Public Client with a given [Transport](https://viem.sh/docs/clients/intro) configured for a [Chain](https://viem.sh/docs/chains/introduction).
|
|
27
27
|
*
|
|
28
|
-
* -
|
|
29
|
-
*
|
|
30
|
-
*
|
|
28
|
+
* A Public Client is an interface to the "public" [Ethereum JSON-RPC API](https://ethereum.org/en/developers/docs/apis/json-rpc/)
|
|
29
|
+
* and the Arkiv JSON-RPC API — retrieving block numbers and transactions, reading from
|
|
30
|
+
* contracts, and querying entities — through {@link PublicArkivActions}.
|
|
31
31
|
*
|
|
32
32
|
* @param parameters - Configuration object for the public client (chain, transport, etc.)
|
|
33
|
-
* @returns
|
|
33
|
+
* @returns An Arkiv Public Client. {@link PublicArkivClient}
|
|
34
34
|
*
|
|
35
35
|
* @example
|
|
36
36
|
* import { createPublicClient } from "@arkiv-network/sdk"
|
|
@@ -29,6 +29,6 @@ test("creates", () => {
|
|
|
29
29
|
expect(typeof client.extendEntity).toBe("function")
|
|
30
30
|
expect(client.changeOwnership).toBeDefined()
|
|
31
31
|
expect(typeof client.changeOwnership).toBe("function")
|
|
32
|
-
expect(client.
|
|
33
|
-
expect(typeof client.
|
|
32
|
+
expect(client.executeBatch).toBeDefined()
|
|
33
|
+
expect(typeof client.executeBatch).toBe("function")
|
|
34
34
|
})
|
|
@@ -24,16 +24,14 @@ export type WalletArkivClient<
|
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Creates a Wallet Client with a given [Transport](https://viem.sh/docs/clients/intro) configured
|
|
27
|
-
* for a [Chain](https://viem.sh/docs/
|
|
28
|
-
*
|
|
29
|
-
* - Docs: https://docs.arkiv.network/ts-sdk/clients/wallet
|
|
27
|
+
* for a [Chain](https://viem.sh/docs/chains/introduction) and an account.
|
|
30
28
|
*
|
|
31
29
|
* A Wallet Client signs and sends transactions, so it carries an `account` and exposes everything
|
|
32
30
|
* that mutates state — `createEntity`, `patchEntity`, `deleteEntity`, `extendEntity`,
|
|
33
|
-
* `changeOwnership` and `
|
|
31
|
+
* `changeOwnership` and `executeBatch` — on top of the read actions a Public Client has.
|
|
34
32
|
*
|
|
35
33
|
* @param parameters - Configuration object for the wallet client (chain, transport, account, etc.)
|
|
36
|
-
* @returns
|
|
34
|
+
* @returns An Arkiv Wallet Client. {@link WalletArkivClient}
|
|
37
35
|
*
|
|
38
36
|
* @example
|
|
39
37
|
* import { createWalletClient } from "@arkiv-network/sdk"
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Account, Address, Chain, Client, Hex, PublicActions, Transport } from "viem"
|
|
2
|
-
import { getBlockTiming } from "../../actions/public/getBlockTiming"
|
|
2
|
+
import { type GetBlockTimingReturnType, getBlockTiming } from "../../actions/public/getBlockTiming"
|
|
3
3
|
import { getEntity } from "../../actions/public/getEntity"
|
|
4
4
|
import { getEntityCount } from "../../actions/public/getEntityCount"
|
|
5
5
|
import { getEntityNonce } from "../../actions/public/getEntityNonce"
|
|
@@ -13,11 +13,11 @@ import {
|
|
|
13
13
|
type WatchEntityEventsParameters,
|
|
14
14
|
watchEntityEvents,
|
|
15
15
|
} from "../../actions/public/watchEntityEvents"
|
|
16
|
+
import type { SaltInput } from "../../entity/key"
|
|
16
17
|
import type { Expression } from "../../query/expression"
|
|
17
18
|
import { SelectQueryBuilder } from "../../query/queryBuilder"
|
|
18
19
|
import type { EntitySelection, FullEntity, ProjectedEntity, SelectArg } from "../../query/selection"
|
|
19
20
|
import type { Entity } from "../../types/entity"
|
|
20
|
-
import { type PublicAdvancedActions, publicAdvancedActions } from "./arkivAdvanced"
|
|
21
21
|
|
|
22
22
|
export type PublicArkivActions<
|
|
23
23
|
transport extends Transport = Transport,
|
|
@@ -39,11 +39,15 @@ export type PublicArkivActions<
|
|
|
39
39
|
/**
|
|
40
40
|
* Returns the entity with the given key.
|
|
41
41
|
*
|
|
42
|
-
* -
|
|
42
|
+
* - JSON-RPC Methods: `arkiv_query`
|
|
43
43
|
*
|
|
44
44
|
* @param key - The entity key (hex string)
|
|
45
45
|
* @returns The entity with the given key, with every field populated. {@link FullEntity}
|
|
46
46
|
*
|
|
47
|
+
* @throws {InvalidValueError} If the key is not 32 bytes.
|
|
48
|
+
* @throws {NoEntityFoundError} If no live entity has that key — it never existed, or it was
|
|
49
|
+
* deleted or has expired.
|
|
50
|
+
*
|
|
47
51
|
* @example
|
|
48
52
|
* import { createPublicClient } from "@arkiv-network/sdk"
|
|
49
53
|
* import { cheesecake } from "@arkiv-network/sdk/chains"
|
|
@@ -70,7 +74,7 @@ export type PublicArkivActions<
|
|
|
70
74
|
* read entities. You declare up front which parts of an entity you want returned, so results
|
|
71
75
|
* always contain exactly the data you asked for.
|
|
72
76
|
*
|
|
73
|
-
* -
|
|
77
|
+
* - JSON-RPC Methods: `arkiv_query`
|
|
74
78
|
*
|
|
75
79
|
* @param selection - What to include in the results. Omit it (or pass `"*"`) to select everything,
|
|
76
80
|
* or pass an object to select specific parts (at least one field is required). Every part is
|
|
@@ -131,7 +135,7 @@ export type PublicArkivActions<
|
|
|
131
135
|
/**
|
|
132
136
|
* Runs one query and returns one page, with no builder in between.
|
|
133
137
|
*
|
|
134
|
-
* Use {@link select} for anything typed — this returns full {@link Entity} objects whatever the
|
|
138
|
+
* Use {@link PublicArkivActions.select} for anything typed — this returns full {@link Entity} objects whatever the
|
|
135
139
|
* selection, and takes a raw string as an escape hatch for a query built elsewhere. A raw string
|
|
136
140
|
* goes to the node exactly as written, with none of the name, type or operator checks the
|
|
137
141
|
* expression combinators apply.
|
|
@@ -225,7 +229,7 @@ export type PublicArkivActions<
|
|
|
225
229
|
* import { key } from "@arkiv-network/sdk/attr"
|
|
226
230
|
*
|
|
227
231
|
* const [parent, child] = await client.predictEntityKeys({ owner: account.address, count: 2 })
|
|
228
|
-
* await wallet.
|
|
232
|
+
* await wallet.executeBatch({
|
|
229
233
|
* creates: [
|
|
230
234
|
* { payload, contentType, expires, salt: parent.salt },
|
|
231
235
|
* {
|
|
@@ -240,7 +244,7 @@ export type PublicArkivActions<
|
|
|
240
244
|
*/
|
|
241
245
|
predictEntityKeys: <
|
|
242
246
|
const TCount extends number = number,
|
|
243
|
-
const TSalts extends readonly
|
|
247
|
+
const TSalts extends readonly SaltInput[] | undefined = undefined,
|
|
244
248
|
>(
|
|
245
249
|
parameters: PredictEntityKeysParameters<TCount, TSalts>,
|
|
246
250
|
) => Promise<PredictEntityKeysReturnType<TCount, TSalts>>
|
|
@@ -265,11 +269,7 @@ export type PublicArkivActions<
|
|
|
265
269
|
* // blockDuration: 2, // in seconds
|
|
266
270
|
* // }
|
|
267
271
|
*/
|
|
268
|
-
getBlockTiming: () => Promise<
|
|
269
|
-
currentBlock: bigint
|
|
270
|
-
currentBlockTime: number
|
|
271
|
-
blockDuration: number
|
|
272
|
-
}>
|
|
272
|
+
getBlockTiming: () => Promise<GetBlockTimingReturnType>
|
|
273
273
|
|
|
274
274
|
/**
|
|
275
275
|
* Watches entity events, calling the handlers you pass as they arrive.
|
|
@@ -298,16 +298,6 @@ export type PublicArkivActions<
|
|
|
298
298
|
* unwatch() // stop watching
|
|
299
299
|
*/
|
|
300
300
|
watchEntityEvents: (parameters: WatchEntityEventsParameters) => () => void
|
|
301
|
-
|
|
302
|
-
/**
|
|
303
|
-
* The read-only half of the advanced path: check on a transaction and decode its result with at
|
|
304
|
-
* most one RPC call per action — so a process that holds nothing but a transaction hash can
|
|
305
|
-
* follow it without a wallet. {@link PublicAdvancedActions}
|
|
306
|
-
*
|
|
307
|
-
* @example
|
|
308
|
-
* const { status } = await client.advanced.pingTransaction(txHash) // 1 eth_getTransactionReceipt
|
|
309
|
-
*/
|
|
310
|
-
advanced: PublicAdvancedActions
|
|
311
301
|
}
|
|
312
302
|
|
|
313
303
|
export function publicArkivActions<
|
|
@@ -325,12 +315,11 @@ export function publicArkivActions<
|
|
|
325
315
|
getEntityNonce: (owner: Address) => getEntityNonce(client, owner),
|
|
326
316
|
predictEntityKeys: <
|
|
327
317
|
const TCount extends number = number,
|
|
328
|
-
const TSalts extends readonly
|
|
318
|
+
const TSalts extends readonly SaltInput[] | undefined = undefined,
|
|
329
319
|
>(
|
|
330
320
|
parameters: PredictEntityKeysParameters<TCount, TSalts>,
|
|
331
321
|
) => predictEntityKeys(client, parameters),
|
|
332
322
|
watchEntityEvents: (parameters: WatchEntityEventsParameters) =>
|
|
333
323
|
watchEntityEvents(client, parameters),
|
|
334
|
-
advanced: publicAdvancedActions(client),
|
|
335
324
|
}
|
|
336
325
|
}
|