@arkiv-network/sdk 0.8.1-dev.1 → 0.9.0-next.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 (184) hide show
  1. package/README.md +180 -61
  2. package/dist/chains/index.d.ts +17 -17
  3. package/dist/changeOwnership-Cy9gfyjN.d.cts +1160 -0
  4. package/dist/changeOwnership-Cy9gfyjN.d.cts.map +1 -0
  5. package/dist/changeOwnership-gXf-lBqI.d.ts +1160 -0
  6. package/dist/changeOwnership-gXf-lBqI.d.ts.map +1 -0
  7. package/dist/entity/index.cjs +4 -10
  8. package/dist/entity/index.d.cts +3 -3
  9. package/dist/entity/index.d.ts +3 -3
  10. package/dist/entity/index.js +3 -4
  11. package/dist/entity-BM1unrQf.cjs +41 -0
  12. package/dist/{entity-DJ0Gml9c.cjs → entity-BgaFJSaV.cjs} +4 -4
  13. package/dist/entity-CFAI1KyG.js +36 -0
  14. package/dist/entity-CFAI1KyG.js.map +1 -0
  15. package/dist/{entity-CniBgBSd.js → entity-CGqx_AU0.js} +4 -4
  16. package/dist/entity-CGqx_AU0.js.map +1 -0
  17. package/dist/{payload-AfUfSctb.d.ts → expirationTime-C7PZK49K.d.ts} +8 -37
  18. package/dist/expirationTime-C7PZK49K.d.ts.map +1 -0
  19. package/dist/expirationTime-CkIGNAg8.cjs +140 -0
  20. package/dist/{payload-D167BlJR.d.cts → expirationTime-DOB8V4B8.d.cts} +8 -37
  21. package/dist/expirationTime-DOB8V4B8.d.cts.map +1 -0
  22. package/dist/{expiry-Cgdb_dbq.js → expirationTime-UKPuA-LM.js} +62 -27
  23. package/dist/expirationTime-UKPuA-LM.js.map +1 -0
  24. package/dist/expiry-B48I-yTA.d.cts +40 -0
  25. package/dist/expiry-B48I-yTA.d.cts.map +1 -0
  26. package/dist/expiry-S2PUL8Hg.d.ts +40 -0
  27. package/dist/expiry-S2PUL8Hg.d.ts.map +1 -0
  28. package/dist/index-C-mMF5WZ.d.cts +735 -0
  29. package/dist/index-C-mMF5WZ.d.cts.map +1 -0
  30. package/dist/{index-BkqSnGJH.d.ts → index-C4zZqJ9S.d.ts} +5 -27
  31. package/dist/index-C4zZqJ9S.d.ts.map +1 -0
  32. package/dist/{index-CLhsFyVH.d.cts → index-CcVWYB6v.d.cts} +5 -27
  33. package/dist/index-CcVWYB6v.d.cts.map +1 -0
  34. package/dist/index-DCx2XC6S.d.ts +489 -0
  35. package/dist/index-DCx2XC6S.d.ts.map +1 -0
  36. package/dist/index-DLb7BfIw.d.ts +735 -0
  37. package/dist/index-DLb7BfIw.d.ts.map +1 -0
  38. package/dist/index-DzriOUm8.d.cts +489 -0
  39. package/dist/index-DzriOUm8.d.cts.map +1 -0
  40. package/dist/index.cjs +162 -146
  41. package/dist/index.d.cts +180 -133
  42. package/dist/index.d.cts.map +1 -1
  43. package/dist/index.d.ts +180 -133
  44. package/dist/index.d.ts.map +1 -1
  45. package/dist/index.js +93 -83
  46. package/dist/index.js.map +1 -1
  47. package/dist/params-BuIrJA9a.cjs +45 -0
  48. package/dist/params-DDJOnsNi.js +22 -0
  49. package/dist/params-DDJOnsNi.js.map +1 -0
  50. package/dist/query/index.cjs +9 -4
  51. package/dist/query/index.d.cts +6 -6
  52. package/dist/query/index.d.ts +6 -6
  53. package/dist/query/index.js +4 -5
  54. package/dist/query-D0KtuFh2.cjs +1625 -0
  55. package/dist/query-DpRDozmj.js +1417 -0
  56. package/dist/query-DpRDozmj.js.map +1 -0
  57. package/dist/schema/index.cjs +46 -0
  58. package/dist/schema/index.d.cts +2 -0
  59. package/dist/schema/index.d.ts +2 -0
  60. package/dist/schema/index.js +3 -0
  61. package/dist/{attr-BXTkpnoc.cjs → schema-B9AyXcgU.cjs} +513 -246
  62. package/dist/{attr-tmyREHtw.js → schema-DY4sqehl.js} +427 -244
  63. package/dist/schema-DY4sqehl.js.map +1 -0
  64. package/dist/types/index.cjs +1 -1
  65. package/dist/types/index.d.cts +5 -5
  66. package/dist/types/index.d.ts +5 -5
  67. package/dist/types/index.js +1 -1
  68. package/dist/utils/index.cjs +3 -5
  69. package/dist/utils/index.d.cts +3 -3
  70. package/dist/utils/index.d.ts +3 -3
  71. package/dist/utils/index.js +3 -3
  72. package/package.json +9 -12
  73. package/src/actions/public/getEntity.test.ts +69 -0
  74. package/src/actions/public/getEntity.ts +34 -20
  75. package/src/actions/public/predictEntityKeys.ts +8 -7
  76. package/src/actions/public/query.test.ts +58 -0
  77. package/src/actions/public/query.ts +41 -13
  78. package/src/actions/wallet/createEntity.ts +34 -63
  79. package/src/actions/wallet/executeBatch.test.ts +38 -0
  80. package/src/actions/wallet/executeBatch.ts +26 -9
  81. package/src/actions/wallet/extendEntity.ts +9 -8
  82. package/src/actions/wallet/patchEntity.ts +43 -52
  83. package/src/clients/createPublicClient.test.ts +10 -2
  84. package/src/clients/createWalletClient.ts +4 -1
  85. package/src/clients/decorators/arkivPublic.ts +123 -80
  86. package/src/clients/decorators/arkivWallet.ts +113 -65
  87. package/src/entity/create.test.ts +25 -21
  88. package/src/entity/expiry.ts +8 -6
  89. package/src/entity/flags.ts +1 -1
  90. package/src/entity/index.ts +2 -4
  91. package/src/entity/key.ts +3 -3
  92. package/src/entity/operations.ts +1 -1
  93. package/src/errors.ts +2 -11
  94. package/src/index.ts +18 -6
  95. package/src/query/builderBase.ts +166 -0
  96. package/src/query/countBuilder.test.ts +91 -0
  97. package/src/query/countBuilder.ts +67 -0
  98. package/src/query/engine.ts +9 -3
  99. package/src/query/errors.ts +24 -14
  100. package/src/query/expression.test.ts +129 -21
  101. package/src/query/expression.ts +323 -94
  102. package/src/query/index.ts +26 -4
  103. package/src/query/injection.test.ts +5 -11
  104. package/src/query/queryBuilder.test.ts +467 -58
  105. package/src/query/queryBuilder.ts +191 -98
  106. package/src/query/queryResult.ts +35 -9
  107. package/src/query/selection.test.ts +278 -24
  108. package/src/query/selection.ts +427 -86
  109. package/src/schema/attributes.test.ts +266 -0
  110. package/src/schema/attributes.ts +212 -0
  111. package/src/{attr → schema}/codec.test.ts +37 -5
  112. package/src/{attr → schema}/codec.ts +40 -11
  113. package/src/schema/column.ts +193 -0
  114. package/src/{attr → schema}/errors.ts +67 -10
  115. package/src/schema/index.ts +76 -0
  116. package/src/{attr → schema}/names.ts +4 -2
  117. package/src/schema/schema.test.ts +171 -0
  118. package/src/schema/schema.ts +250 -0
  119. package/src/{attr → schema}/types.ts +36 -30
  120. package/src/{attr → schema}/values.test.ts +62 -3
  121. package/src/{attr → schema}/values.ts +246 -65
  122. package/src/types/entity.test.ts +1 -44
  123. package/src/types/entity.ts +9 -55
  124. package/src/types/events.ts +1 -1
  125. package/src/types/index.ts +11 -4
  126. package/src/types/rpcSchema.ts +22 -16
  127. package/src/utils/arkivTransactions.test.ts +356 -116
  128. package/src/utils/arkivTransactions.ts +30 -38
  129. package/src/utils/entities.ts +10 -9
  130. package/src/utils/expirationTime.ts +5 -5
  131. package/src/utils/index.ts +0 -1
  132. package/src/utils/logger.test.ts +45 -0
  133. package/src/utils/logger.ts +5 -39
  134. package/src/utils/revert.test.ts +25 -0
  135. package/src/utils/revert.ts +28 -3
  136. package/dist/attr/index.cjs +0 -34
  137. package/dist/attr/index.d.cts +0 -2
  138. package/dist/attr/index.d.ts +0 -2
  139. package/dist/attr/index.js +0 -3
  140. package/dist/attr-tmyREHtw.js.map +0 -1
  141. package/dist/entity-B0t6sN7F.cjs +0 -71
  142. package/dist/entity-BIp_df9u.js +0 -67
  143. package/dist/entity-BIp_df9u.js.map +0 -1
  144. package/dist/entity-CniBgBSd.js.map +0 -1
  145. package/dist/expiry-BxOlvVWC.d.ts +0 -79
  146. package/dist/expiry-BxOlvVWC.d.ts.map +0 -1
  147. package/dist/expiry-CG9GhVXv.cjs +0 -135
  148. package/dist/expiry-Cgdb_dbq.js.map +0 -1
  149. package/dist/expiry-DRV29F1r.d.cts +0 -79
  150. package/dist/expiry-DRV29F1r.d.cts.map +0 -1
  151. package/dist/flags-DCD26uhe.cjs +0 -43
  152. package/dist/flags-DUT2gHEU.js +0 -33
  153. package/dist/flags-DUT2gHEU.js.map +0 -1
  154. package/dist/index-BkqSnGJH.d.ts.map +0 -1
  155. package/dist/index-C7fbakoI.d.cts +0 -278
  156. package/dist/index-C7fbakoI.d.cts.map +0 -1
  157. package/dist/index-CIcHPx2j.d.cts +0 -424
  158. package/dist/index-CIcHPx2j.d.cts.map +0 -1
  159. package/dist/index-CLhsFyVH.d.cts.map +0 -1
  160. package/dist/index-Cd2aaWme.d.ts +0 -424
  161. package/dist/index-Cd2aaWme.d.ts.map +0 -1
  162. package/dist/index-Cq6fa8AI.d.ts +0 -278
  163. package/dist/index-Cq6fa8AI.d.ts.map +0 -1
  164. package/dist/index-DaNeJUw8.d.ts +0 -955
  165. package/dist/index-DaNeJUw8.d.ts.map +0 -1
  166. package/dist/index-Dv16LO2s.d.cts +0 -955
  167. package/dist/index-Dv16LO2s.d.cts.map +0 -1
  168. package/dist/payload-AfUfSctb.d.ts.map +0 -1
  169. package/dist/payload-D167BlJR.d.cts.map +0 -1
  170. package/dist/payload-DE7wMztL.js +0 -92
  171. package/dist/payload-DE7wMztL.js.map +0 -1
  172. package/dist/payload-DqFweqiO.cjs +0 -108
  173. package/dist/query-9oojUdM7.cjs +0 -1128
  174. package/dist/query-Ber-lOJQ.js +0 -968
  175. package/dist/query-Ber-lOJQ.js.map +0 -1
  176. package/src/actions/public/getEntityCount.ts +0 -10
  177. package/src/attr/attributes.test.ts +0 -120
  178. package/src/attr/attributes.ts +0 -196
  179. package/src/attr/index.ts +0 -50
  180. package/src/types/mimeTypes.ts +0 -27
  181. package/src/utils/compression.test.ts +0 -32
  182. package/src/utils/compression.ts +0 -102
  183. package/src/utils/payload.ts +0 -36
  184. /package/src/{attr → schema}/decimal.ts +0 -0
package/README.md CHANGED
@@ -85,12 +85,52 @@ npm install @arkiv-network/sdk viem
85
85
  This command will update your `package.json` with a section like:
86
86
  ```json
87
87
  "dependencies": {
88
- "@arkiv-network/sdk": "^0.6.0",
88
+ "@arkiv-network/sdk": "^0.9.0",
89
89
  "viem": "^2.38.2"
90
90
  }
91
91
  ```
92
92
  It will also create a `node_modules` directory with all dependencies installed.
93
93
 
94
+ ### Define a Schema
95
+
96
+ Arkiv stores entities, and an entity is a set of named, typed attributes. You describe them once in a
97
+ schema, much as you would describe a table's columns in SQL, and choose per column whether the node
98
+ indexes it. Only indexed columns can be filtered on; the rest are stored and selectable, and do not
99
+ pay for an index.
100
+
101
+ The examples below use this schema for blog posts. Each example declares it at the top of its own
102
+ file, so that it runs as a single file under Node.js, Bun or `tsc` alike:
103
+
104
+ ```typescript
105
+ import { addr, bytes, dec, defineSchema, str } from "@arkiv-network/sdk/schema"
106
+
107
+ // Called with no arguments, a type constructor describes a column.
108
+ const Posts = defineSchema("posts", {
109
+ author: addr().indexed(),
110
+ category: str().indexed(),
111
+ score: dec().indexed(),
112
+ title: str(), // stored, not indexed
113
+ body: bytes(), // a blob; bytes can never be indexed
114
+ thumbnail: bytes().optional(), // any number of bytes columns; this one may be absent
115
+ mimeType: str().default("text/markdown"), // written on create when left out
116
+ })
117
+ ```
118
+
119
+ The type constructors are `bool`, `i32`, `u64`, `u256`, `dec`, `str`, `addr`, `key`, `bytes32` and
120
+ `bytes`. Each column may be refined with `.indexed()` (every type but `bytes`), `.optional()` and
121
+ `.default(...)`.
122
+
123
+ The same constructors, called with a value, make a typed value: `dec("4.1")` is a decimal, the way SQL
124
+ has `DECIMAL` as a type and `DECIMAL '4.1'` as a literal.
125
+
126
+ A schema is an SDK-side convention: the node sees only attributes, each with a type and an indexed
127
+ flag. The schema is what types your writes and reads, and checks them at runtime.
128
+
129
+ The name, `"posts"`, is optional but recommended. A named schema tags every entity it creates with
130
+ an indexed `arkiv.schema` attribute holding its name, and a query through it only matches entities
131
+ with that tag — the way a collection keeps one model's documents apart from another's. For that
132
+ reason `arkiv.schema` cannot be used as a column name.
133
+
94
134
  ### Public Client Example (Query Data)
95
135
 
96
136
  You can now use Arkiv's public client to query data. Paste the following in `read_example.ts`:
@@ -98,31 +138,41 @@ You can now use Arkiv's public client to query data. Paste the following in `rea
98
138
  ```typescript
99
139
  import { createPublicClient } from "@arkiv-network/sdk"
100
140
  import { tiramisu } from "@arkiv-network/sdk/chains"
101
- import { eq } from "@arkiv-network/sdk/query"
141
+ import { and, eq, gt } from "@arkiv-network/sdk/query"
142
+ import { addr, bytes, dec, defineSchema, str } from "@arkiv-network/sdk/schema"
102
143
  import { http } from "viem"
103
144
 
145
+ // The schema from "Define a Schema" above
146
+ const Posts = defineSchema("posts", {
147
+ author: addr().indexed(),
148
+ category: str().indexed(),
149
+ score: dec().indexed(),
150
+ title: str(),
151
+ body: bytes(),
152
+ thumbnail: bytes().optional(),
153
+ mimeType: str().default("text/markdown"),
154
+ })
155
+
104
156
  const publicClient = createPublicClient({
105
157
  chain: tiramisu, // "tiramisu" is Arkiv's testnet
106
158
  transport: http(),
107
159
  });
108
160
 
109
- // Get chain ID
110
- const chainId = await publicClient.getChainId();
111
- console.log('Chain ID:', chainId);
161
+ // Get an entity by key, read through the schema
162
+ const post = await publicClient.getEntity('0xcadb830a3414251d65e5c92cd28ecb648d9e73d85f2203eff631839d5421f9d7', Posts);
163
+ console.log('Title:', post.title.value);
112
164
 
113
- // Get entity by key
114
- const entity = await publicClient.getEntity('0xcadb830a3414251d65e5c92cd28ecb648d9e73d85f2203eff631839d5421f9d7');
115
- console.log('Entity:', entity);
116
-
117
- // Build and execute a query using select()
165
+ // Build and execute a query: select what to return, name the schema, then filter
118
166
  const result = await publicClient
119
- .select({ owner: true, attributes: true, payload: true })
120
- .where(eq('category', 'documentation'))
121
- .ownedBy('0x6186B0DbA9652262942d5A465d49686eb560834C')
167
+ .select({ $key: true, author: true, title: true, body: true })
168
+ .from(Posts)
169
+ .where(and(eq('category', 'docs'), gt('score', dec('4.0'))))
122
170
  .limit(10)
123
171
  .fetch();
124
172
 
125
- console.log('Found entities:', result.entities);
173
+ for (const row of result.entities) {
174
+ console.log(row.$key, row.author.value, row.title.value);
175
+ }
126
176
 
127
177
  // Pagination
128
178
  if (result.hasNextPage()) {
@@ -131,46 +181,107 @@ if (result.hasNextPage()) {
131
181
  }
132
182
 
133
183
  // Or walk every page at once
134
- for await (const entity of publicClient
135
- .select({ key: true })
136
- .where(eq('category', 'documentation'))) {
137
- console.log(entity.key);
184
+ for await (const row of publicClient
185
+ .select({ $key: true, title: true })
186
+ .from(Posts)
187
+ .where(eq('category', 'docs'))) {
188
+ console.log(row.$key, row.title.value);
138
189
  }
139
190
  ```
140
191
 
141
192
  #### Selecting fields with `select()`
142
193
 
143
- Pass nothing (or `"*"`) to fetch everything, or pass an object to fetch only specific fields:
194
+ Pass nothing (or `"*"`) to fetch everything — through a schema, every entity field and every
195
+ column — or pass an object to fetch only specific fields. The selection names entity fields and
196
+ attributes side by side, and each result is a flat row. Entity fields start with `$`, as they do in
197
+ `where`: `$key`, `$owner`, `$creator`, `$createdAt`, `$updatedAt`, `$expiresAt` and
198
+ `$creationFlags`. Any other name is an attribute. An attribute name cannot start with `$`, so the
199
+ two never collide — an attribute called `owner` is just `owner`:
144
200
 
145
201
  ```typescript
146
- // All fields
147
- await publicClient.select().where(eq("category", "docs")).fetch();
202
+ // Every entity field and every column
203
+ await publicClient.select().from(Posts).where(eq("category", "docs")).fetch();
148
204
 
149
205
  // Only the fields you need
150
- await publicClient.select({ key: true, owner: true, payload: true }).where(eq("category", "docs")).fetch();
206
+ await publicClient.select({ $key: true, title: true }).from(Posts).where(eq("category", "docs")).fetch();
151
207
  ```
152
208
 
153
209
  **Select only what you need.** Every selected field is fetched over the network, so requesting
154
210
  data you won't use makes queries slower. Narrowing the selection keeps responses small and fast.
155
211
 
156
- The result type is inferred from your selection: reading a field you didn't select is a compile error. The `toText()` / `toJson()` payload
157
- helpers are available only when you select `payload`.
212
+ The result type is inferred from your selection and schema: each column is typed as the schema
213
+ declares it, and reading a field you didn't select is a compile error.
158
214
 
159
215
  ```typescript
160
- const [entity] = (
161
- await publicClient.select({ owner: true, payload: true }).where(eq("category", "docs")).fetch()
162
- ).entities;
163
- entity.owner; // ✅ Hex
164
- entity.toJson(); // ✅ payload was selected
165
- entity.creator; // ❌ compile error — not selected
216
+ const row = (
217
+ await publicClient.select({ $owner: true, score: true }).from(Posts).where(eq("category", "docs")).fetch()
218
+ ).entities[0]!;
219
+ row.$owner; // ✅ Hex
220
+ row.score; // ✅ DecValue — row.score.value is "4.1"
221
+ row.title; // ❌ compile error — not selected
166
222
  ```
167
223
 
224
+ `where` is checked against the schema too. It takes the schema's indexed columns and the system
225
+ attributes `$key`, `$owner`, `$creator` and `$expiresAt`. Filtering on a column the schema does not
226
+ index, or comparing a column against a value of another type, is a compile error:
227
+
228
+ ```typescript
229
+ .where(eq("title", "x")) // ❌ title is not indexed
230
+ .where(eq("score", 5)) // ❌ score is a dec, 5 is an i32 — write dec(5)
231
+ .where(between("score", dec(1), 5)) // ❌ both bounds need one type
232
+ ```
233
+
234
+ A named schema needs no `where` at all — `select().from(Posts)` matches every post: `fetch()`
235
+ returns the first page, and `for await` walks them all. An unnamed schema types a query without
236
+ filtering it, so `where` alone decides which entities match.
237
+
238
+ Only what you select is checked. An entity that matches but does not fit the schema — a selected
239
+ column that is required but missing or holds another type, or, for a named schema, another schema's
240
+ tag — is left out of the page. Anyone can write an entity a query matches, so one that does not
241
+ fit never fails the read of the others. A page can then hold fewer rows than its limit, and reports
242
+ how many it left out as `skipped`. Pass `{ onMismatch: "throw" }` to fail the fetch with a
243
+ `SchemaMismatchError` instead:
244
+
245
+ ```typescript
246
+ const page = await publicClient.select().from(Posts).where(eq("category", "docs")).fetch();
247
+ page.skipped; // matching entities on this page that did not fit Posts
248
+ ```
249
+
250
+ A query reads the same without a schema — say, to explore what a node holds. Leave out
251
+ `.from(...)` and the selection means what it did (save `"*"`, below), and the rows keep their
252
+ shape. Only the checking is gone, along with a named schema's tag filter: each attribute comes back
253
+ as whatever value the entity holds, or `undefined`, and `where` takes any attribute:
254
+
255
+ ```typescript
256
+ const row = (
257
+ await publicClient.select({ $key: true, title: true }).where(eq("category", "docs")).fetch()
258
+ ).entities[0]!;
259
+ row.title; // ArkivValue | undefined — e.g. { type: "str", value: "Hello" }
260
+ ```
261
+
262
+ To read every attribute without naming them, select `$attributes`, a map of all of them. `"*"` (or
263
+ nothing) fetches it alongside the entity fields when there is no schema, since there are no columns
264
+ to list.
265
+
266
+ `$attributeSchema` is for finding out what entities hold without fetching their values: each
267
+ attribute's name, its type, and whether it is indexed. Values can be large — a `bytes` attribute
268
+ holds up to 128 KiB — and an RPC endpoint may cap how big a response it sends, so a page of 100
269
+ entities with every attribute can be more than it will return. Fetch the schema first, then select
270
+ the attributes you need by name. It is never part of `"*"`; select it by name:
271
+
272
+ ```typescript
273
+ const page = await publicClient.select({ $key: true, $attributeSchema: true }).where(eq("category", "docs")).fetch();
274
+ page.entities[0]?.$attributeSchema; // { title: { type: "str", indexed: false }, body: { type: "bytes", indexed: false } }
275
+ ```
276
+
277
+ Both work through a schema too.
278
+
168
279
  > **Footgun:** pass the selection inline. A selection stored in a variable widens its `true` values
169
- > to `boolean`, so the result type can't be narrowed (you get `{}` and a compile error on every
170
- > field). If you need to reuse one, annotate it `as const`:
280
+ > to `boolean`, so which fields come back is only known at runtime and every field of the result is
281
+ > optional. If you need to reuse one, annotate it `as const`:
171
282
  > ```typescript
172
- > const fields = { owner: true, payload: true } as const;
173
- > await publicClient.select(fields).where(eq("category", "docs")).fetch();
283
+ > const fields = { $owner: true, title: true } as const;
284
+ > await publicClient.select(fields).from(Posts).where(eq("category", "docs")).fetch();
174
285
  > ```
175
286
 
176
287
  ### Running the Example
@@ -208,19 +319,29 @@ You have several options to run your TypeScript sample:
208
319
  node dist/read_example.js
209
320
  ```
210
321
 
211
- ### Wallet Client Example (Create Entity)
322
+ ### Wallet Client Example (Create an Entity)
212
323
 
213
324
  Now let's add storage (write) functionality.
214
325
  Create a file named `write_example.ts` with the following content:
215
326
 
216
327
  ```typescript
217
- import { createPublicClient, createWalletClient } from "@arkiv-network/sdk"
218
- import { dec, i32 } from "@arkiv-network/sdk/attr"
328
+ import { createPublicClient, createWalletClient, ExpirationTime } from "@arkiv-network/sdk"
219
329
  import { tiramisu } from "@arkiv-network/sdk/chains"
220
- import { ExpirationTime, jsonToPayload } from "@arkiv-network/sdk/utils"
221
- import { http } from "viem"
330
+ import { addr, bytes, dec, defineSchema, str } from "@arkiv-network/sdk/schema"
331
+ import { http, stringToBytes } from "viem"
222
332
  import { privateKeyToAccount } from "viem/accounts"
223
333
 
334
+ // The schema from "Define a Schema" above
335
+ const Posts = defineSchema("posts", {
336
+ author: addr().indexed(),
337
+ category: str().indexed(),
338
+ score: dec().indexed(),
339
+ title: str(),
340
+ body: bytes(),
341
+ thumbnail: bytes().optional(),
342
+ mimeType: str().default("text/markdown"),
343
+ })
344
+
224
345
  // Create a public client
225
346
  const publicClient = createPublicClient({
226
347
  chain: tiramisu, // tiramisu is the Arkiv testnet
@@ -233,32 +354,30 @@ const client = createWalletClient({
233
354
  account: privateKeyToAccount('0x...'), // Replace with your private key
234
355
  });
235
356
 
236
- // Create an entity
237
- const { entityKey, txHash } = await client.createEntity({
238
- payload: jsonToPayload({
239
- entity: {
240
- entityType: 'document',
241
- entityId: 'doc-123',
242
- entityContent: "Hello from DevConnect Hackathon 2025! Arkiv chain wishes you all the best!"
243
- },
244
- }),
245
- contentType: 'application/json',
246
- // Attributes are keyed by name. Values carry their type: use the tagged constructors from
247
- // "@arkiv-network/sdk/attr" (i32, u64, u256, dec, str, addr, key, bytes32, bool), or pass a bare
248
- // boolean, number, bigint or string where the type is unambiguous.
249
- attributes: {
250
- category: 'documentation', // bare string -> str
251
- version: i32(1),
357
+ // Create an entity. Every required column must be given; a defaulted one (mimeType) left out is
358
+ // written with its default. Values carry their type: use the constructors from
359
+ // "@arkiv-network/sdk/schema", or a bare string, boolean, number, bigint or Uint8Array where it is
360
+ // unambiguous (string -> str, Uint8Array -> bytes, ...).
361
+ const { entityKey, txHash } = await client.createEntity(
362
+ Posts,
363
+ {
364
+ author: addr(client.account.address),
365
+ category: 'docs',
252
366
  score: dec('4.5'),
367
+ title: 'Hello from Arkiv',
368
+ body: stringToBytes('# Hello\n\nArkiv wishes you all the best!'),
253
369
  },
254
- expires: ExpirationTime.fromDays(30), // Entity expires in 30 days
255
- });
370
+ { expiration: ExpirationTime.fromDays(30) }, // Entity expires in 30 days
371
+ );
256
372
 
257
373
  console.log('Created entity:', entityKey);
258
374
  console.log('Transaction hash:', txHash);
259
375
 
260
- const newEntity = await publicClient.getEntity(entityKey);
261
- console.log('Entity:', newEntity);
376
+ // Change one column, leaving the rest alone
377
+ await client.patchEntity(Posts, entityKey, { set: { score: dec('4.7') } });
378
+
379
+ const post = await publicClient.getEntity(entityKey, Posts);
380
+ console.log('Post:', post);
262
381
  ```
263
382
 
264
383
  Now you can run it in the same way as in the previous example:
@@ -356,12 +475,12 @@ For more information about refer to:
356
475
 
357
476
  ## Verbose Logging
358
477
 
359
- The SDK uses [debug](https://www.npmjs.com/package/debug) under the hood. Set the `DEBUG` environment variable to view verbose logs:
478
+ Set the `DEBUG` environment variable (or, in a browser, the `DEBUG` key in `localStorage`) to view verbose logs:
360
479
 
361
480
  ```bash
362
481
  DEBUG=arkiv:* bun run your-script
363
482
  ```
364
483
 
365
- Adjust the namespace (for example, `arkiv:rpc` or `arkiv:query`) to target specific log sources. Unset `DEBUG` to silence debug output.
484
+ Adjust the namespace (for example, `arkiv:query:*` or `arkiv:actions:wallet:*`) to target specific log sources, and prefix one with `-` to exclude it. Unset `DEBUG` to silence debug output.
366
485
 
367
486
 
@@ -1,4 +1,4 @@
1
- import * as viem8 from "viem";
1
+ import * as viem0 from "viem";
2
2
 
3
3
  //#region src/chains/localhost.d.ts
4
4
  /**
@@ -19,13 +19,13 @@ declare const localhost: {
19
19
  } | undefined | undefined;
20
20
  blockTime?: number | undefined | undefined;
21
21
  contracts?: {
22
- [x: string]: viem8.ChainContract | {
23
- [sourceId: number]: viem8.ChainContract | undefined;
22
+ [x: string]: viem0.ChainContract | {
23
+ [sourceId: number]: viem0.ChainContract | undefined;
24
24
  } | undefined;
25
- ensRegistry?: viem8.ChainContract | undefined;
26
- ensUniversalResolver?: viem8.ChainContract | undefined;
27
- multicall3?: viem8.ChainContract | undefined;
28
- erc6492Verifier?: viem8.ChainContract | undefined;
25
+ ensRegistry?: viem0.ChainContract | undefined;
26
+ ensUniversalResolver?: viem0.ChainContract | undefined;
27
+ multicall3?: viem0.ChainContract | undefined;
28
+ erc6492Verifier?: viem0.ChainContract | undefined;
29
29
  } | undefined;
30
30
  ensTlds?: readonly string[] | undefined;
31
31
  id: 1337;
@@ -44,9 +44,9 @@ declare const localhost: {
44
44
  sourceId?: number | undefined | undefined;
45
45
  testnet?: boolean | undefined | undefined;
46
46
  custom?: Record<string, unknown> | undefined;
47
- fees?: viem8.ChainFees<undefined> | undefined;
47
+ fees?: viem0.ChainFees<undefined> | undefined;
48
48
  formatters?: undefined;
49
- serializers?: viem8.ChainSerializers<undefined, viem8.TransactionSerializable> | undefined;
49
+ serializers?: viem0.ChainSerializers<undefined, viem0.TransactionSerializable> | undefined;
50
50
  };
51
51
  //#endregion
52
52
  //#region src/chains/tiramisu.d.ts
@@ -68,13 +68,13 @@ declare const tiramisu: {
68
68
  } | undefined | undefined;
69
69
  blockTime?: number | undefined | undefined;
70
70
  contracts?: {
71
- [x: string]: viem8.ChainContract | {
72
- [sourceId: number]: viem8.ChainContract | undefined;
71
+ [x: string]: viem0.ChainContract | {
72
+ [sourceId: number]: viem0.ChainContract | undefined;
73
73
  } | undefined;
74
- ensRegistry?: viem8.ChainContract | undefined;
75
- ensUniversalResolver?: viem8.ChainContract | undefined;
76
- multicall3?: viem8.ChainContract | undefined;
77
- erc6492Verifier?: viem8.ChainContract | undefined;
74
+ ensRegistry?: viem0.ChainContract | undefined;
75
+ ensUniversalResolver?: viem0.ChainContract | undefined;
76
+ multicall3?: viem0.ChainContract | undefined;
77
+ erc6492Verifier?: viem0.ChainContract | undefined;
78
78
  } | undefined;
79
79
  ensTlds?: readonly string[] | undefined;
80
80
  id: 7738577;
@@ -94,9 +94,9 @@ declare const tiramisu: {
94
94
  sourceId?: number | undefined | undefined;
95
95
  testnet: true;
96
96
  custom?: Record<string, unknown> | undefined;
97
- fees?: viem8.ChainFees<undefined> | undefined;
97
+ fees?: viem0.ChainFees<undefined> | undefined;
98
98
  formatters?: undefined;
99
- serializers?: viem8.ChainSerializers<undefined, viem8.TransactionSerializable> | undefined;
99
+ serializers?: viem0.ChainSerializers<undefined, viem0.TransactionSerializable> | undefined;
100
100
  readonly network: "tiramisu";
101
101
  };
102
102
  //#endregion