@arkiv-network/sdk 0.1.1-dev.0 → 0.1.3-dev.0

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 (58) hide show
  1. package/README.md +22 -10
  2. package/dist/chains/index.d.ts +25 -25
  3. package/dist/chains/index.d.ts.map +1 -1
  4. package/dist/index.cjs +30 -9
  5. package/dist/index.js +30 -16
  6. package/dist/index.js.map +1 -1
  7. package/dist/utils/index.d.ts.map +1 -1
  8. package/package.json +22 -8
  9. package/src/accounts/index.ts +1 -0
  10. package/src/actions/public/buildQuery.ts +6 -0
  11. package/src/actions/public/getBlockTiming.ts +20 -0
  12. package/src/actions/public/getEntity.ts +18 -0
  13. package/src/actions/public/getEntityCount.ts +10 -0
  14. package/src/actions/public/query.ts +13 -0
  15. package/src/actions/public/subscribeEntityEvents.ts +105 -0
  16. package/src/actions/wallet/changeOwnership.ts +40 -0
  17. package/src/actions/wallet/createEntity.ts +45 -0
  18. package/src/actions/wallet/deleteEntity.ts +39 -0
  19. package/src/actions/wallet/extendEntity.ts +41 -0
  20. package/src/actions/wallet/mutateEntities.ts +100 -0
  21. package/src/actions/wallet/updateEntity.ts +47 -0
  22. package/src/chains/index.ts +3 -0
  23. package/src/chains/kaolin.ts +26 -0
  24. package/src/chains/localhost.ts +14 -0
  25. package/src/chains/marketplace.ts +26 -0
  26. package/src/clients/baseClient.ts +9 -0
  27. package/src/clients/createPublicClient.test.ts +22 -0
  28. package/src/clients/createPublicClient.ts +65 -0
  29. package/src/clients/createWalletClient.test.ts +23 -0
  30. package/src/clients/createWalletClient.ts +70 -0
  31. package/src/clients/decorators/arkivPublic.ts +203 -0
  32. package/src/clients/decorators/arkivWallet.ts +250 -0
  33. package/src/consts.ts +2 -0
  34. package/src/index.ts +21 -0
  35. package/src/query/engine.test.ts +288 -0
  36. package/src/query/engine.ts +112 -0
  37. package/src/query/errors.ts +23 -0
  38. package/src/query/index.ts +4 -0
  39. package/src/query/predicate.test.ts +418 -0
  40. package/src/query/predicate.ts +140 -0
  41. package/src/query/queryBuilder.test.ts +537 -0
  42. package/src/query/queryBuilder.ts +209 -0
  43. package/src/query/queryResult.test.ts +270 -0
  44. package/src/query/queryResult.ts +61 -0
  45. package/src/types/attributes.ts +4 -0
  46. package/src/types/entity.ts +36 -0
  47. package/src/types/events.ts +34 -0
  48. package/src/types/index.ts +4 -0
  49. package/src/types/mimeTypes.ts +27 -0
  50. package/src/types/rpcSchema.ts +61 -0
  51. package/src/types/txParams.ts +15 -0
  52. package/src/utils/arkivTransactions.ts +100 -0
  53. package/src/utils/compression.test.ts +32 -0
  54. package/src/utils/compression.ts +99 -0
  55. package/src/utils/entities.ts +23 -0
  56. package/src/utils/expirationTime.ts +13 -0
  57. package/src/utils/index.ts +3 -0
  58. package/src/utils/payload.ts +9 -0
@@ -0,0 +1,61 @@
1
+ import type { Hex, PublicRpcSchema } from "viem"
2
+ import type { MimeType } from "./mimeTypes"
3
+
4
+ export type RpcEntity = {
5
+ key: Hex
6
+ contentType: MimeType
7
+ value: string
8
+ expiresAt: bigint
9
+ owner: Hex
10
+ stringAttributes?: [{ key: string; value: string }]
11
+ numericAttributes?: [{ key: string; value: number }]
12
+ }
13
+
14
+ export type RpcQueryOptions = {
15
+ atBlock?: number
16
+ includeData?: RpcIncludeData
17
+ resultsPerPage?: number
18
+ cursor?: string
19
+ }
20
+
21
+ export type RpcIncludeData = {
22
+ key: boolean
23
+ attributes: boolean
24
+ payload: boolean
25
+ contentType: boolean
26
+ expiration: boolean
27
+ owner: boolean
28
+ }
29
+
30
+ export type ArkivRpcSchema = [
31
+ {
32
+ Method: "golembase_getStorageValue"
33
+ Parameters?: [entityId: Hex]
34
+ ReturnType: string
35
+ },
36
+ {
37
+ Method: "arkiv_query"
38
+ Parameters?: [query: string, queryOptions?: RpcQueryOptions]
39
+ ReturnType: {
40
+ data: [RpcEntity]
41
+ blockNumber: bigint
42
+ cursor: string
43
+ }
44
+ },
45
+ {
46
+ Method: "arkiv_getBlockTiming"
47
+ Parameters?: []
48
+ ReturnType: {
49
+ current_block: bigint
50
+ current_block_time: number
51
+ duration: number
52
+ }
53
+ },
54
+ {
55
+ Method: "arkiv_getEntityCount"
56
+ Parameters?: []
57
+ ReturnType: number
58
+ },
59
+ ]
60
+
61
+ export type PublicArkivRpcSchema = [...PublicRpcSchema, ...ArkivRpcSchema]
@@ -0,0 +1,15 @@
1
+ export type TxParams =
2
+ | {
3
+ gas?: bigint
4
+ nonce?: number
5
+ gasPrice?: bigint
6
+ maxFeePerGas?: never
7
+ maxPriorityFeePerGas?: never
8
+ }
9
+ | {
10
+ gas?: bigint
11
+ nonce?: number
12
+ maxFeePerGas?: bigint
13
+ maxPriorityFeePerGas?: bigint
14
+ gasPrice?: never
15
+ }
@@ -0,0 +1,100 @@
1
+ import { type Hex, toBytes, toHex, toRlp } from "viem"
2
+ import type { ChangeOwnershipParameters } from "../actions/wallet/changeOwnership"
3
+ import type { CreateEntityParameters } from "../actions/wallet/createEntity"
4
+ import type { DeleteEntityParameters } from "../actions/wallet/deleteEntity"
5
+ import type { ExtendEntityParameters } from "../actions/wallet/extendEntity"
6
+ import type { UpdateEntityParameters } from "../actions/wallet/updateEntity"
7
+ import type { ArkivClient } from "../clients/baseClient"
8
+ import type { WalletArkivClient } from "../clients/createWalletClient"
9
+ import { ARKIV_ADDRESS, BLOCK_TIME } from "../consts"
10
+ import type { TxParams } from "../types"
11
+ import { compress } from "./compression"
12
+
13
+ export function opsToTxData({
14
+ creates,
15
+ updates,
16
+ deletes,
17
+ extensions,
18
+ ownershipChanges,
19
+ }: {
20
+ creates?: CreateEntityParameters[]
21
+ updates?: UpdateEntityParameters[]
22
+ deletes?: DeleteEntityParameters[]
23
+ extensions?: ExtendEntityParameters[]
24
+ ownershipChanges?: ChangeOwnershipParameters[]
25
+ }) {
26
+ function formatAttributes<T extends string | number | bigint | boolean>(attribute: {
27
+ key: string
28
+ value: T
29
+ }): [Hex, Hex] {
30
+ return [toHex(attribute.key), toHex(attribute.value)]
31
+ }
32
+
33
+ const payload = [
34
+ //creates
35
+ (creates ?? []).map((item) => [
36
+ toHex(item.expiresIn / BLOCK_TIME),
37
+ toHex(item.contentType),
38
+ toHex(item.payload),
39
+ item.attributes
40
+ .filter((attribute) => typeof attribute.value === "string")
41
+ .map(formatAttributes),
42
+ item.attributes
43
+ .filter((attribute) => typeof attribute.value === "number")
44
+ .map(formatAttributes),
45
+ ]),
46
+ //updates
47
+ (updates ?? []).map((item) => [
48
+ item.entityKey,
49
+ toHex(item.contentType),
50
+ toHex(item.expiresIn / BLOCK_TIME),
51
+ toHex(item.payload),
52
+ item.attributes
53
+ .filter((attribute) => typeof attribute.value === "string")
54
+ .map(formatAttributes),
55
+ item.attributes
56
+ .filter((attribute) => typeof attribute.value === "number")
57
+ .map(formatAttributes),
58
+ ]),
59
+ //deletes
60
+ (deletes ?? []).map((item) => item.entityKey),
61
+ //extends
62
+ (extensions ?? []).map((item) => [item.entityKey, toHex(item.expiresIn / BLOCK_TIME)]),
63
+ //ownershipChanges TODO
64
+ (ownershipChanges ?? []).map((item) => [item.entityKey, item.newOwner]),
65
+ ]
66
+
67
+ console.debug("txData to send as RLP", payload, payload.length)
68
+
69
+ return toRlp(payload)
70
+ }
71
+
72
+ export async function sendArkivTransaction(client: ArkivClient, data: Hex, txParams?: TxParams) {
73
+ if (!client.account) throw new Error("Account required")
74
+ const walletClient = client as WalletArkivClient
75
+
76
+ console.debug("Sending transaction", {
77
+ account: client.account,
78
+ chain: client.chain,
79
+ to: ARKIV_ADDRESS,
80
+ value: 0n,
81
+ data,
82
+ ...txParams,
83
+ })
84
+
85
+ const compressed = await compress(toBytes(data))
86
+ const txHash = await walletClient.sendTransaction({
87
+ account: client.account,
88
+ chain: client.chain,
89
+ to: ARKIV_ADDRESS,
90
+ value: 0n,
91
+ data: toHex(compressed),
92
+ ...txParams,
93
+ })
94
+
95
+ const receipt = await walletClient.waitForTransactionReceipt({ hash: txHash })
96
+
97
+ console.debug("Tx receipt", receipt)
98
+
99
+ return receipt
100
+ }
@@ -0,0 +1,32 @@
1
+ import { describe, expect, it } from "bun:test"
2
+ import { compress, decompress } from "./compression"
3
+
4
+ describe("compression", () => {
5
+ it("should compress data", async () => {
6
+ const originalData = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
7
+ const compressed = await compress(originalData)
8
+
9
+ expect(compressed).toBeInstanceOf(Uint8Array)
10
+ expect(compressed.length).toBeGreaterThan(0)
11
+ // Compressed data should be different from original
12
+ expect(compressed).not.toEqual(originalData)
13
+ })
14
+
15
+ it("should compress data with large payload into smaller size", async () => {
16
+ const originalData = new Uint8Array(1000).fill(1)
17
+ const compressed = await compress(originalData)
18
+
19
+ expect(compressed).toBeInstanceOf(Uint8Array)
20
+ expect(compressed.length).toBeGreaterThan(0)
21
+ expect(compressed.length).toBeLessThan(originalData.length)
22
+ })
23
+
24
+ it("should decompress data", async () => {
25
+ const originalData = new Uint8Array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
26
+ const compressed = await compress(originalData)
27
+ const decompressed = await decompress(compressed)
28
+
29
+ expect(decompressed).toBeInstanceOf(Uint8Array)
30
+ expect(decompressed).toEqual(originalData)
31
+ })
32
+ })
@@ -0,0 +1,99 @@
1
+ // src/utils/compression.ts
2
+
3
+ import type { BrotliWasmType } from "brotli-wasm"
4
+
5
+ // Detect if we're in Node.js environment
6
+ const isNode = typeof process !== "undefined" && process.versions?.node != null
7
+
8
+ let zlib: typeof import("zlib") | null = null
9
+ let brotli: BrotliWasmType | null = null
10
+
11
+ // Lazy load zlib (Node.js only)
12
+ async function getZlib(): Promise<typeof import("zlib") | null> {
13
+ if (!isNode) return null
14
+
15
+ if (!zlib) {
16
+ try {
17
+ zlib = await import("zlib")
18
+ } catch (error) {
19
+ console.error("Error importing zlib", error)
20
+ return null
21
+ }
22
+ }
23
+ return zlib
24
+ }
25
+
26
+ // Lazy load brotli-wasm (browser/fallback)
27
+ async function getBrotli(): Promise<BrotliWasmType | null> {
28
+ if (brotli) return brotli
29
+
30
+ try {
31
+ const brotliModule = await import("brotli-wasm")
32
+ brotli = brotliModule.default || brotliModule
33
+ } catch (error) {
34
+ console.error("Error importing brotli-wasm", error)
35
+ return null
36
+ }
37
+
38
+ return brotli
39
+ }
40
+
41
+ export async function compress(data: Uint8Array): Promise<Uint8Array> {
42
+ console.debug(`Compressing data (size: ${data.length})`)
43
+
44
+ // Try Node.js zlib first (if available)
45
+ if (isNode) {
46
+ const zlibModule = await getZlib()
47
+ if (zlibModule) {
48
+ try {
49
+ // zlib.brotliCompress expects Buffer, returns Buffer
50
+ const buffer = Buffer.from(data)
51
+ const compressed = zlibModule.brotliCompressSync(buffer)
52
+ const result = new Uint8Array(compressed)
53
+ console.debug(`Brotli compressed with zlib (size: ${result.length})`)
54
+ return result
55
+ } catch (error) {
56
+ console.warn("zlib compression failed, falling back to brotli-wasm", error)
57
+ }
58
+ }
59
+ }
60
+
61
+ // Fallback to brotli-wasm (browser or if zlib fails)
62
+ const brotliInstance = await getBrotli()
63
+ if (!brotliInstance) {
64
+ console.warn("Brotli instance not found, not compressing data")
65
+ return data
66
+ }
67
+
68
+ const brotliCompressed = brotliInstance.compress(data)
69
+ console.debug(`Brotli compressed with wasm (size: ${brotliCompressed.length})`)
70
+ return brotliCompressed
71
+ }
72
+
73
+ export async function decompress(data: Uint8Array): Promise<Uint8Array> {
74
+ // Try Node.js zlib first (if available)
75
+ if (isNode) {
76
+ const zlibModule = await getZlib()
77
+ if (zlibModule) {
78
+ try {
79
+ // zlib.brotliDecompress expects Buffer, returns Buffer
80
+ const buffer = Buffer.from(data)
81
+ const decompressed = zlibModule.brotliDecompressSync(buffer)
82
+ const result = new Uint8Array(decompressed)
83
+ console.debug(`Brotli decompressed with zlib (size: ${result.length})`)
84
+ return result
85
+ } catch (error) {
86
+ console.warn("zlib decompression failed, falling back to brotli-wasm", error)
87
+ }
88
+ }
89
+ }
90
+
91
+ // Fallback to brotli-wasm (browser or if zlib fails)
92
+ const brotliInstance = await getBrotli()
93
+ if (!brotliInstance) {
94
+ console.warn("Brotli instance not found, not decompressing data")
95
+ return data
96
+ }
97
+
98
+ return brotliInstance.decompress(data)
99
+ }
@@ -0,0 +1,23 @@
1
+ import { toBytes } from "viem"
2
+ import { Entity } from "../types/entity"
3
+ import type { RpcEntity } from "../types/rpcSchema"
4
+
5
+ export async function entityFromRpcResult(rpcEntity: RpcEntity) {
6
+ return new Entity(
7
+ rpcEntity.key,
8
+ rpcEntity.contentType,
9
+ rpcEntity.owner,
10
+ rpcEntity.expiresAt,
11
+ toBytes(rpcEntity.value),
12
+ [
13
+ ...(rpcEntity.stringAttributes ?? []).map(({ key, value }) => ({
14
+ key,
15
+ value,
16
+ })),
17
+ ...(rpcEntity.numericAttributes ?? []).map(({ key, value }) => ({
18
+ key,
19
+ value: Number(value),
20
+ })),
21
+ ],
22
+ )
23
+ }
@@ -0,0 +1,13 @@
1
+ import { BLOCK_TIME } from "../consts"
2
+
3
+ export const ExpirationTime = {
4
+ fromSeconds: (seconds: number) => seconds,
5
+ fromMinutes: (minutes: number) => minutes * 60,
6
+ fromHours: (hours: number) => hours * 60 * 60,
7
+ fromDays: (days: number) => days * 24 * 60 * 60,
8
+ fromWeeks: (weeks: number) => weeks * 7 * 24 * 60 * 60,
9
+ fromMonths: (months: number) => months * 30 * 24 * 60 * 60,
10
+ fromYears: (years: number) => years * 365 * 24 * 60 * 60,
11
+ fromBlocks: (blocks: number) => blocks * BLOCK_TIME,
12
+ fromDate: (date: Date) => Math.floor(date.getTime() / 1000) - Math.floor(Date.now() / 1000),
13
+ }
@@ -0,0 +1,3 @@
1
+ export * from "viem/utils"
2
+ export * from "./expirationTime"
3
+ export * from "./payload"
@@ -0,0 +1,9 @@
1
+ import { toBytes } from "viem"
2
+
3
+ export function jsonToPayload(json: object): Uint8Array {
4
+ return toBytes(JSON.stringify(json))
5
+ }
6
+
7
+ export function stringToPayload(data: string): Uint8Array {
8
+ return toBytes(data)
9
+ }