wao 0.5.6 → 0.6.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.
package/esm/ar.js CHANGED
@@ -2,7 +2,7 @@ import _Arweave from "arweave"
2
2
  const Arweave = _Arweave.default ?? _Arweave
3
3
  import { ArweaveSigner, bundleAndSignData, createData } from "arbundles"
4
4
  import { buildTags, tag, isLocalhost } from "./utils.js"
5
- import { is } from "ramda"
5
+ import { is, isNil } from "ramda"
6
6
  import GQL from "./gql.js"
7
7
 
8
8
  class AR {
@@ -258,9 +258,15 @@ class AR {
258
258
  return (await this.gql.txs({ id: txid }))[0] ?? null
259
259
  }
260
260
 
261
- async data(txid, string = false) {
261
+ async data(txid, _string = false) {
262
+ let decode = true
263
+ let string = _string
264
+ if (is(Object, _string)) {
265
+ if (!isNil(_string.decode)) decode = _string.decode
266
+ if (!isNil(_string.string)) string = _string.string
267
+ }
262
268
  const _data = await this.arweave.transactions.getData(txid, {
263
- decode: true,
269
+ decode,
264
270
  string,
265
271
  })
266
272
  return _data
package/esm/armem.js CHANGED
@@ -50,6 +50,7 @@ export default class ArMem {
50
50
  "Output-Encoding": "JSON-V1",
51
51
  "Memory-Limit": "1-gb",
52
52
  "Compute-Limit": "9000000000000",
53
+ Extension: "WeaveDrive",
53
54
  }),
54
55
  }
55
56
  }
package/esm/gql.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { includes, map, is, isNil, last, clone } from "ramda"
2
2
 
3
- const full = `id anchor signature recipient owner { address key } fee { winston ar } quantity { winston ar } data { size type } tags { name value } block { id timestamp height previous } parent { id }`
3
+ const full = `id anchor signature recipient owner { address key } fee { winston ar } quantity { winston ar } data { size type } tags { name value } block { id timestamp height previous } parent { id } bundledIn { id }`
4
4
  const full_blocks = `id timestamp height previous`
5
5
 
6
6
  const subs = {
@@ -11,6 +11,7 @@ const subs = {
11
11
  tags: ["name", "value"],
12
12
  block: ["id", "timestamp", "height", "previous"],
13
13
  parent: ["id"],
14
+ bundledIn: ["id"],
14
15
  }
15
16
  const field = (key, val = true) => {
16
17
  if (includes(key, ["id", "anchor", "signature", "recipient"])) {
@@ -98,8 +99,11 @@ const query = (opt = {}) => {
98
99
  }
99
100
  if (opt.first) cond.push(`first: ${opt.first}`)
100
101
  if (opt.after) cond.push(`after: "${opt.after}"`)
101
- if (opt.asc) cond.push(`sort: HEIGHT_ASC`)
102
-
102
+ if (opt.asc) {
103
+ cond.push(`sort: HEIGHT_ASC`)
104
+ } else {
105
+ cond.push(`sort: HEIGHT_DESC`)
106
+ }
103
107
  let _cond = ""
104
108
  if (cond.length > 0) _cond = `(${cond.join(", ")})`
105
109
  let fields = []
@@ -124,6 +128,7 @@ const query = (opt = {}) => {
124
128
  let _fields = fields.length > 0 ? fields.join(" ") : full
125
129
  return `query {
126
130
  transactions ${_cond}{
131
+ pageInfo { hasNextPage }
127
132
  edges { cursor node { ${_fields} } }
128
133
  }
129
134
  }`
@@ -176,6 +181,7 @@ const query_blocks = (opt = {}) => {
176
181
  let _fields = fields.length > 0 ? fields.join(" ") : full_blocks
177
182
  return `query {
178
183
  blocks ${_cond}{
184
+ pageInfo { hasNextPage }
179
185
  edges { cursor node { ${_fields} } }
180
186
  }
181
187
  }`
@@ -191,13 +197,16 @@ export default class GQL {
191
197
  headers: { "Content-Type": "application/json" },
192
198
  body: JSON.stringify({ query }),
193
199
  }).then(r => r.json())
194
- return map(v => ({ cursor: v.cursor, ...v.node }))(json.data[tar].edges)
200
+ return {
201
+ isNext: json.data[tar].pageInfo.hasNextPage,
202
+ data: map(v => ({ cursor: v.cursor, ...v.node }))(json.data[tar].edges),
203
+ }
195
204
  }
196
205
  async fetch(opt = {}, query, tar = "transactions") {
197
- const data = await this._fetch(query, tar)
206
+ const { isNext, data } = await this._fetch(query, tar)
198
207
  if (opt.next === true) {
199
208
  let cursor = null
200
- if (data.length > 0) cursor = last(data).cursor
209
+ if (isNext && data.length > 0) cursor = last(data).cursor
201
210
  const next = !cursor
202
211
  ? null
203
212
  : async () => {
package/esm/helpers.js CHANGED
@@ -22,6 +22,13 @@ export class Src {
22
22
  this.dir = dir
23
23
  if (!dir) dirname().then(v => (this.dir = resolve(v, "lua")))
24
24
  }
25
+ async init(dir) {
26
+ if (!this.dir) {
27
+ dir ??= await dirname()
28
+ this.dir = resolve(dir, "lua")
29
+ }
30
+ return this
31
+ }
25
32
  data(file, ext = "lua") {
26
33
  return readFileSync(
27
34
  `${this.dir}/${file}.${ext}`,
@@ -34,6 +41,47 @@ export class Src {
34
41
  }
35
42
  }
36
43
 
44
+ export class Testnet {
45
+ constructor({ port = 4000, arweave, aoconnect, docker = false } = {}) {
46
+ this.docker = docker
47
+ this.arweave = arweave ?? { port }
48
+ this.aoconnect = aoconnect ?? {
49
+ MU_URL: `http://localhost:${port + 2}`,
50
+ SU_URL: `http://localhost:${port + 3}`,
51
+ CU_URL: `http://localhost:${port + 4}`,
52
+ GATEWAY_URL: `http://localhost:${port}`,
53
+ }
54
+ this.ar = new AR(this.arweave)
55
+ }
56
+ async init(jwk) {
57
+ this.authority = (
58
+ await fetch(this.aoconnect.SU_URL).then(r => r.json())
59
+ ).address
60
+ this.src = await new Src({ ar: this.ar }).init()
61
+ await this.ar.init(jwk)
62
+ this.jwk = this.ar.jwk
63
+ this.addr = this.ar.a
64
+ this.gql = this.ar.gql
65
+ this.module_src = await this.src.upload("aos2_0_1", "wasm")
66
+ this.ao = await new AO({
67
+ ar: this.ar,
68
+ aoconnect: this.aoconnect,
69
+ authority: this.authority,
70
+ }).init(this.ar.jwk)
71
+ const { id } = await this.ao.postModule({
72
+ data: await this.ar.data(this.module_src),
73
+ overwrite: true,
74
+ })
75
+ this.module = id
76
+ const { scheduler } = await this.ao.postScheduler({
77
+ url: this.docker ? "http://su" : this.aoconnect.SU_URL,
78
+ overwrite: true,
79
+ })
80
+ this.scheduler = scheduler
81
+ return this
82
+ }
83
+ }
84
+
37
85
  export const setup = async ({
38
86
  aoconnect,
39
87
  arweave,
@@ -61,7 +109,7 @@ export const setup = async ({
61
109
 
62
110
  if (opt) {
63
111
  const ar = await new AR(opt.ar).init(opt.jwk)
64
- const src = new Src({ ar, readFileSync, dir })
112
+ const src = new Src({ ar, dir })
65
113
  const ao = await new AO(opt.ao).init(opt.jwk)
66
114
  const ao2 = await new AO(opt.ao2).init(opt.jwk)
67
115
  console.log("cache:\t", optPath)
@@ -78,7 +126,7 @@ export const setup = async ({
78
126
  }
79
127
  const ar = new AR(arweave)
80
128
  await ar.gen("10")
81
- const src = new Src({ ar, readFileSync, dir })
129
+ const src = new Src({ ar, dir })
82
130
  opt = { ar: { ...arweave }, jwk: ar.jwk }
83
131
  if (!auth && /localhost/.test(aoconnect?.CU_URL ?? "")) {
84
132
  auth = (await fetch(aoconnect.CU_URL).then(r => r.json())).address
Binary file
package/esm/run.js CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  import Server from "./server.js"
4
4
 
5
- const main = async () => new Server()
5
+ const main = async () => new Server({ log: true })
6
6
 
7
7
  main()
package/esm/server.js CHANGED
@@ -2,176 +2,21 @@ import express from "express"
2
2
  import cors from "cors"
3
3
  import base64url from "base64url"
4
4
  import { DataItem } from "arbundles"
5
- import { tags } from "./utils.js"
5
+ import { tags, toGraphObj } from "./utils.js"
6
6
  import { connect } from "./aoconnect.js"
7
7
  import { GQL, cu, su, mu } from "./test.js"
8
8
  import bodyParser from "body-parser"
9
- import { graphql, parse, validate, buildSchema } from "graphql"
10
9
  import { keys, map, reverse } from "ramda"
11
- const schema = buildSchema(`
12
- schema {
13
- query: Query
14
- }
15
-
16
- type Query {
17
- transactions(
18
- ids: [ID!]
19
- tags: [TagFilter!]
20
- block: BlockFilter
21
- after: String
22
- first: Int
23
- ): TransactionConnection!
24
-
25
- block(id: ID, height: Int): Block
26
- }
27
-
28
- type TransactionConnection {
29
- edges: [TransactionEdge!]!
30
- pageInfo: PageInfo!
31
- }
32
-
33
- type TransactionEdge {
34
- cursor: String!
35
- node: Transaction!
36
- }
37
-
38
- type Transaction {
39
- id: ID!
40
- anchor: String
41
- signature: String!
42
- recipient: String
43
- owner: Owner!
44
- fee: Quantity!
45
- quantity: Quantity!
46
- data: Data!
47
- tags: [Tag!]!
48
- block: Block
49
- parent: Transaction
50
- }
51
-
52
- type Owner {
53
- address: String!
54
- key: String!
55
- }
56
-
57
- type Quantity {
58
- winston: String!
59
- ar: String!
60
- }
61
-
62
- type Data {
63
- size: String!
64
- type: String
65
- }
66
-
67
- type Tag {
68
- name: String!
69
- value: String!
70
- }
71
-
72
- type Block {
73
- id: ID!
74
- timestamp: Int!
75
- height: Int!
76
- previous: String
77
- transactions: [Transaction!]!
78
- miner: String!
79
- reward: String!
80
- tags: [Tag!]!
81
- indepHash: String!
82
- nonce: String!
83
- }
84
-
85
- type PageInfo {
86
- hasNextPage: Boolean!
87
- }
88
-
89
- input TagFilter {
90
- name: String!
91
- values: [String!]!
92
- }
93
-
94
- input BlockFilter {
95
- min: Int
96
- max: Int
97
- }
98
- `)
99
-
100
- const root = {
101
- transactions: ({ first }) => ({
102
- edges: [],
103
- pageInfo: {
104
- hasNextPage: false,
105
- },
106
- }),
107
- block: ({ id }) => ({
108
- id,
109
- timestamp: Date.now(),
110
- height: 123456,
111
- previous: "previous-block-id",
112
- transactions: [],
113
- miner: "example-miner",
114
- reward: "1000",
115
- tags: [],
116
- indepHash: "example-indep-hash",
117
- nonce: "000000",
118
- }),
119
- }
120
-
121
- const mapParsed = (parsedQuery, variables) => {
122
- const operation = parsedQuery.definitions[0]
123
-
124
- if (operation.operation !== "query") {
125
- throw new Error("Only 'query' operations are supported.")
126
- }
127
-
128
- const rootField = operation.selectionSet.selections[0]
129
- const rootFieldName = rootField.name.value
130
-
131
- const parseArgumentValue = argValue => {
132
- if (argValue.kind === "Variable") {
133
- return variables[argValue.name.value]
134
- }
135
-
136
- if (argValue.kind === "ListValue") {
137
- return argValue.values.map(value => parseArgumentValue(value))
138
- }
139
-
140
- if (argValue.kind === "ObjectValue") {
141
- return argValue.fields.reduce((obj, field) => {
142
- obj[field.name.value] = parseArgumentValue(field.value)
143
- return obj
144
- }, {})
145
- }
146
-
147
- return argValue.value
148
- }
149
-
150
- const args = rootField.arguments.reduce((acc, arg) => {
151
- acc[arg.name.value] = parseArgumentValue(arg.value)
152
- return acc
153
- }, {})
154
-
155
- const extractFields = selectionSet => {
156
- return selectionSet.selections.map(selection => {
157
- const fieldName = selection.name.value
158
-
159
- if (selection.selectionSet) {
160
- return {
161
- [fieldName]: extractFields(selection.selectionSet),
162
- }
163
- }
164
- return fieldName
165
- })
166
- }
167
-
168
- const fields = extractFields(rootField.selectionSet)
169
-
170
- return { rootFieldName, args, fields }
171
- }
172
10
 
173
11
  class Server {
174
- constructor({ ar = 4000, mu = 4002, su = 4003, cu = 4004, aoconnect } = {}) {
12
+ constructor({
13
+ ar = 4000,
14
+ mu = 4002,
15
+ su = 4003,
16
+ cu = 4004,
17
+ aoconnect,
18
+ log = false,
19
+ } = {}) {
175
20
  const {
176
21
  ar: _ar,
177
22
  message,
@@ -182,7 +27,7 @@ class Server {
182
27
  mem,
183
28
  monitor,
184
29
  unmonitor,
185
- } = connect(aoconnect)
30
+ } = connect(aoconnect, log)
186
31
  this.monitor = monitor
187
32
  this.unmonitor = unmonitor
188
33
  this.spawn = spawn
@@ -207,7 +52,7 @@ class Server {
207
52
  app.get("/wallet/:id/balance", (req, res) => res.send("0"))
208
53
  app.get("/mint/:id/:amount", (req, res) => res.json({ id: "0" }))
209
54
  app.get("/tx/:id/offset", async (req, res) => {
210
- res.status(500)
55
+ res.status(400)
211
56
  res.send(null)
212
57
  })
213
58
  app.get("/tx_anchor", async (req, res) => {
@@ -229,26 +74,24 @@ class Server {
229
74
  res.send("0")
230
75
  })
231
76
  app.post("/graphql", async (req, res) => {
232
- const { query, variables } = req.body
233
- const parsedQuery = parse(query)
234
- const errors = validate(schema, parsedQuery)
235
- const parsed = mapParsed(parsedQuery, variables)
236
- const tar = parsed.rootFieldName
237
- const fields = parsed.fields[0].edges[0].node
238
- const args = parsed.args
239
- if (args.tags) {
240
- let _tags = {}
241
- for (const v of args.tags) _tags[v.name] = v.values
242
- args.tags = _tags
243
- }
244
- let res2 = null
245
- if (tar === "transactions") {
246
- res2 = await this.gql.txs({ ...args })
247
- } else if (tar === "blocks") {
248
- res2 = await this.gql.blocks()
77
+ try {
78
+ const { query, variables } = req.body
79
+ const { tar, args } = toGraphObj({ query, variables })
80
+ let res2 = null
81
+ if (tar === "transactions") {
82
+ res2 = await this.gql.txs({ ...args })
83
+ } else if (tar === "blocks") {
84
+ res2 = await this.gql.blocks({ ...args })
85
+ }
86
+ const edges = map(v => ({ node: v, cursor: v.cursor }), res2)
87
+ res.json({
88
+ data: { transactions: { pageInfo: { hasNextPage: true }, edges } },
89
+ })
90
+ } catch (e) {
91
+ console.log(e)
92
+ res.status(400)
93
+ res.json({ error: "bad request" })
249
94
  }
250
- const edges = map(v => ({ node: v, cursor: v.cursor }), res2)
251
- res.json({ data: { transactions: { edges } } })
252
95
  })
253
96
  let data = {}
254
97
  app.post("/:id", async (req, res) => {
@@ -325,7 +168,7 @@ class Server {
325
168
  err = true
326
169
  }
327
170
  if (err) {
328
- res.status(500)
171
+ res.status(400)
329
172
  res.send({ err })
330
173
  } else {
331
174
  res.send({ id: item.id })
@@ -407,7 +250,7 @@ class Server {
407
250
  const { Id: id, Owner: owner, Tags: tags, Data: data } = req.body
408
251
  const res2 = await this.dryrun({ id, owner, tags, data, process })
409
252
  if (!res2) {
410
- res.status(500)
253
+ res.status(400)
411
254
  res.json({ err: true })
412
255
  } else {
413
256
  delete res2.Memory
package/esm/tao.js CHANGED
@@ -77,7 +77,7 @@ class AO extends MAO {
77
77
  this.message = message
78
78
  this.spawn = async (...opt) => {
79
79
  const res = await spawn(...opt)
80
- //await this.load({ data: log, pid: res })
80
+ await this.load({ data: log, pid: res })
81
81
  return res
82
82
  }
83
83
  this.dryrun = async (...opt) => {
@@ -111,11 +111,13 @@ class AO extends MAO {
111
111
  "Memory-Limit": "1-gb",
112
112
  "Compute-Limit": "9000000000000",
113
113
  })
114
-
115
- const _tags = buildTags(null, t)
116
114
  const signer = createDataItemSigner(jwk)
117
- const { id, owner } = await this.ar.dataitem({ tags: _tags, data, signer })
118
- await this.ar.post({ data, tags: t, jwk })
115
+ const { id, owner, item } = await this.ar.dataitem({
116
+ tags: t,
117
+ data,
118
+ signer,
119
+ })
120
+ await this.ar.postItems(item, jwk)
119
121
  this.mem.wasms[id] = { data, format: t["Module-Format"] }
120
122
  return { id }
121
123
  }