wao 0.4.11 → 0.5.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/armem.js CHANGED
@@ -1,20 +1,15 @@
1
1
  import Arweave from "arweave"
2
2
  import { last } from "ramda"
3
-
3
+ import { buildTags } from "./utils.js"
4
4
  export default class ArMem {
5
- constructor() {
5
+ constructor({ MU_URL, CU_URL, SU_URL, GATEWAY_URL, scheduler } = {}) {
6
6
  this.__type__ = "mem"
7
7
  this.arweave = Arweave.init()
8
- this.arweave.transactions.getTransactionAnchor = () => {
9
- return this.blocks.length === 0
10
- ? ""
11
- : last(this.blockmap[last(this.blocks)].txs)
12
- }
8
+ this.arweave.transactions.getTransactionAnchor = () => this.getAnchor()
13
9
  this.arweave.transactions.getPrice = () => 0
14
10
  this.addrmap = {}
15
11
  this.txs = {}
16
12
  this.jwks = {}
17
- this.height = 0
18
13
  this.blocks = []
19
14
  this.blockmap = {}
20
15
  this.env = {}
@@ -39,5 +34,55 @@ export default class ArMem {
39
34
  format: "wasm64-unknown-emscripten-draft_2024_02_15",
40
35
  },
41
36
  }
37
+ let txs = []
38
+ for (const k in this.modules) {
39
+ const key = this.modules[k]
40
+ txs.push(key)
41
+ this.txs[key] = {
42
+ id: key,
43
+ block: 0,
44
+ tags: buildTags(null, {
45
+ "Data-Protocol": "ao",
46
+ Variant: "ao.TN.1",
47
+ Type: "Module",
48
+ "Module-Format": "wasm64-unknown-emscripten-draft_2024_02_15",
49
+ "Input-Encoding": "JSON-V1",
50
+ "Output-Encoding": "JSON-V1",
51
+ "Memory-Limit": "1-gb",
52
+ "Compute-Limit": "9000000000000",
53
+ }),
54
+ }
55
+ }
56
+ if (scheduler && SU_URL) {
57
+ const key = scheduler
58
+ txs.push(key)
59
+ this.addrmap[scheduler] = { address: scheduler }
60
+ this.txs[key] = {
61
+ id: key,
62
+ block: 0,
63
+ owner: scheduler,
64
+ tags: buildTags(null, {
65
+ "Data-Protocol": "ao",
66
+ Variant: "ao.TN.1",
67
+ Type: "Scheduler-Location",
68
+ Url: SU_URL,
69
+ "Time-To-Live": 1000 * 60 * 60 * 24 * 365 * 10,
70
+ }),
71
+ }
72
+ }
73
+ this.blockmap["0"] = {
74
+ txs,
75
+ timestamp: Date.now(),
76
+ height: 0,
77
+ previous: "",
78
+ id: "0",
79
+ }
80
+ this.blocks.push("0")
81
+ this.height = 1
82
+ }
83
+ getAnchor() {
84
+ return this.blocks.length === 0
85
+ ? "Do_Uc2Sju_ffp6Ev0AnLVdPtot15rvMjP-a9VVaA5fM"
86
+ : last(this.blockmap[last(this.blocks)].txs)
42
87
  }
43
88
  }
package/esm/run.js ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env -S node --experimental-wasm-memory64
2
+
3
+ import Server from "./server.js"
4
+
5
+ const main = async () => new Server()
6
+
7
+ main()
package/esm/server.js ADDED
@@ -0,0 +1,375 @@
1
+ import express from "express"
2
+ import base64url from "base64url"
3
+ import { DataItem } from "arbundles"
4
+ import { tags } from "./utils.js"
5
+ import { connect } from "./aoconnect.js"
6
+ import { GQL, cu, su, mu } from "./test.js"
7
+ import bodyParser from "body-parser"
8
+ import { graphql, parse, validate, buildSchema } from "graphql"
9
+ import { map } from "ramda"
10
+ const schema = buildSchema(`
11
+ schema {
12
+ query: Query
13
+ }
14
+
15
+ type Query {
16
+ transactions(
17
+ ids: [ID!]
18
+ tags: [TagFilter!]
19
+ block: BlockFilter
20
+ after: String
21
+ first: Int
22
+ ): TransactionConnection!
23
+
24
+ block(id: ID, height: Int): Block
25
+ }
26
+
27
+ type TransactionConnection {
28
+ edges: [TransactionEdge!]!
29
+ pageInfo: PageInfo!
30
+ }
31
+
32
+ type TransactionEdge {
33
+ cursor: String!
34
+ node: Transaction!
35
+ }
36
+
37
+ type Transaction {
38
+ id: ID!
39
+ anchor: String
40
+ signature: String!
41
+ recipient: String
42
+ owner: Owner!
43
+ fee: Quantity!
44
+ quantity: Quantity!
45
+ data: Data!
46
+ tags: [Tag!]!
47
+ block: Block
48
+ parent: Transaction
49
+ }
50
+
51
+ type Owner {
52
+ address: String!
53
+ key: String!
54
+ }
55
+
56
+ type Quantity {
57
+ winston: String!
58
+ ar: String!
59
+ }
60
+
61
+ type Data {
62
+ size: String!
63
+ type: String
64
+ }
65
+
66
+ type Tag {
67
+ name: String!
68
+ value: String!
69
+ }
70
+
71
+ type Block {
72
+ id: ID!
73
+ timestamp: Int!
74
+ height: Int!
75
+ previous: String
76
+ transactions: [Transaction!]!
77
+ miner: String!
78
+ reward: String!
79
+ tags: [Tag!]!
80
+ indepHash: String!
81
+ nonce: String!
82
+ }
83
+
84
+ type PageInfo {
85
+ hasNextPage: Boolean!
86
+ }
87
+
88
+ input TagFilter {
89
+ name: String!
90
+ values: [String!]!
91
+ }
92
+
93
+ input BlockFilter {
94
+ min: Int
95
+ max: Int
96
+ }
97
+ `)
98
+
99
+ const root = {
100
+ transactions: ({ first }) => ({
101
+ edges: [],
102
+ pageInfo: {
103
+ hasNextPage: false,
104
+ },
105
+ }),
106
+ block: ({ id }) => ({
107
+ id,
108
+ timestamp: Date.now(),
109
+ height: 123456,
110
+ previous: "previous-block-id",
111
+ transactions: [],
112
+ miner: "example-miner",
113
+ reward: "1000",
114
+ tags: [],
115
+ indepHash: "example-indep-hash",
116
+ nonce: "000000",
117
+ }),
118
+ }
119
+
120
+ const mapParsed = (parsedQuery, variables) => {
121
+ const operation = parsedQuery.definitions[0]
122
+
123
+ if (operation.operation !== "query") {
124
+ throw new Error("Only 'query' operations are supported.")
125
+ }
126
+
127
+ const rootField = operation.selectionSet.selections[0]
128
+ const rootFieldName = rootField.name.value
129
+
130
+ const parseArgumentValue = argValue => {
131
+ if (argValue.kind === "Variable") {
132
+ return variables[argValue.name.value]
133
+ }
134
+
135
+ if (argValue.kind === "ListValue") {
136
+ return argValue.values.map(value => parseArgumentValue(value))
137
+ }
138
+
139
+ if (argValue.kind === "ObjectValue") {
140
+ return argValue.fields.reduce((obj, field) => {
141
+ obj[field.name.value] = parseArgumentValue(field.value)
142
+ return obj
143
+ }, {})
144
+ }
145
+
146
+ return argValue.value
147
+ }
148
+
149
+ const args = rootField.arguments.reduce((acc, arg) => {
150
+ acc[arg.name.value] = parseArgumentValue(arg.value)
151
+ return acc
152
+ }, {})
153
+
154
+ const extractFields = selectionSet => {
155
+ return selectionSet.selections.map(selection => {
156
+ const fieldName = selection.name.value
157
+
158
+ if (selection.selectionSet) {
159
+ return {
160
+ [fieldName]: extractFields(selection.selectionSet),
161
+ }
162
+ }
163
+ return fieldName
164
+ })
165
+ }
166
+
167
+ const fields = extractFields(rootField.selectionSet)
168
+
169
+ return { rootFieldName, args, fields }
170
+ }
171
+
172
+ class Server {
173
+ constructor({ ar = 4000, mu = 4002, su = 4003, cu = 4004, aoconnect } = {}) {
174
+ const {
175
+ ar: _ar,
176
+ message,
177
+ spawn,
178
+ dryrun,
179
+ result,
180
+ results,
181
+ mem,
182
+ monitor,
183
+ unmonitor,
184
+ } = connect(aoconnect)
185
+ this.monitor = monitor
186
+ this.unmonitor = unmonitor
187
+ this.spawn = spawn
188
+ this._ar = _ar
189
+ this.message = message
190
+ this.dryrun = dryrun
191
+ this.result = result
192
+ this.results = results
193
+ this.mem = mem
194
+ this.gql = new GQL({ mem })
195
+ this.ports = { ar, mu, su, cu }
196
+ this.servers = []
197
+ this.ar()
198
+ this.mu()
199
+ this.su()
200
+ this.cu()
201
+ }
202
+ ar() {
203
+ const app = express()
204
+ app.use(bodyParser.json({ limit: "100mb" }))
205
+ app.get("/tx/:id/offset", async (req, res) => {
206
+ res.status(500)
207
+ res.send(null)
208
+ })
209
+ app.get("/tx_anchor", async (req, res) => {
210
+ res.send(this.mem.getAnchor())
211
+ })
212
+ app.get("/mine", async (req, res) => {
213
+ res.json(req.params)
214
+ })
215
+ app.get("/:id", async (req, res) => {
216
+ const _data = await this._ar.data(req.params.id)
217
+ if (!_data) {
218
+ res.status(404)
219
+ res.send(null)
220
+ } else {
221
+ res.send(Buffer.from(_data, "base64"))
222
+ }
223
+ })
224
+ app.get("/price/:id", async (req, res) => {
225
+ res.send("0")
226
+ })
227
+ app.post("/graphql", async (req, res) => {
228
+ const { query, variables } = req.body
229
+ const parsedQuery = parse(query)
230
+ const errors = validate(schema, parsedQuery)
231
+ const parsed = mapParsed(parsedQuery, variables)
232
+ const tar = parsed.rootFieldName
233
+ const fields = parsed.fields[0].edges[0].node
234
+ const args = parsed.args
235
+ let res2 = null
236
+ if (tar === "transactions") {
237
+ res2 = await this.gql.txs({ ...args })
238
+ } else if (tar === "blocks") {
239
+ res2 = await this.gql.blocks()
240
+ }
241
+ const edges = map(v => ({ node: v, cursor: v.cursor }), res2)
242
+ res.json({ data: { transactions: { edges } } })
243
+ })
244
+
245
+ let data = {}
246
+ app.post("/:id", async (req, res) => {
247
+ if (req.body.chunk) {
248
+ if (data[req.body.data_root]) {
249
+ data[req.body.data_root].data += req.body.chunk
250
+ const buf = Buffer.from(req.body.chunk, "base64")
251
+ if (!data[req.body.data_root].chunks) {
252
+ data[req.body.data_root].chunks = buf
253
+ } else {
254
+ data[req.body.data_root].chunks = Buffer.concat([
255
+ data[req.body.data_root].chunks,
256
+ buf,
257
+ ])
258
+ }
259
+ delete req.body.chunk
260
+ if (
261
+ data[req.body.data_root].data_size <=
262
+ data[req.body.data_root].chunks.length
263
+ ) {
264
+ data[req.body.data_root].data =
265
+ data[req.body.data_root].chunks.toString("base64")
266
+ await this._ar.postTx(data[req.body.data_root])
267
+ delete data[req.body.data_root]
268
+ }
269
+ }
270
+ res.json({ id: req.body.id })
271
+ } else {
272
+ if (req.body.data_root && req.body.data === "") {
273
+ data[req.body.data_root] = req.body
274
+ } else {
275
+ await this._ar.postTx(req.body)
276
+ }
277
+ res.json({ id: req.body.id })
278
+ }
279
+ })
280
+ app.post("/tx", async (req, res) => {
281
+ await this._ar.postTx(req.body)
282
+ res.json({ id: req.body.id })
283
+ })
284
+ const server = app.listen(this.ports.ar, () => {
285
+ console.log(`AR on port ${this.ports.ar}`)
286
+ })
287
+ this.servers.push(server)
288
+ }
289
+ mu() {
290
+ const app = express()
291
+ app.use(express.raw({ type: "*/*" }))
292
+ app.get("/", (req, res) => res.send("ao messenger unit"))
293
+ app.post("/monitor/:id", async (req, res) => {
294
+ await this.monitor({ process: req.params.id })
295
+ res.json({ id: req.params.id, messag: "cron monitored!" })
296
+ })
297
+ app.delete("/monitor/:id", async (req, res) => {
298
+ await this.unmonitor({ process: req.params.id })
299
+ res.json({ id: req.params.id, message: "cron deleted!" })
300
+ })
301
+ app.post("/", async (req, res) => {
302
+ const binary = req.body
303
+ let valid = await DataItem.verify(binary)
304
+ let type = null
305
+ let item = null
306
+ if (valid) item = new DataItem(binary)
307
+ const _tags = tags(item.tags)
308
+ let err = null
309
+ if (_tags.Type === "Process") {
310
+ await this.spawn({
311
+ item,
312
+ module: _tags.Module,
313
+ scheduler: _tags.Scheduler,
314
+ })
315
+ } else if (_tags.Type === "Message") {
316
+ await this.message({ item, process: item.target })
317
+ } else {
318
+ err = true
319
+ }
320
+ if (err) res.status(500)
321
+ res.send({ id: item.id })
322
+ })
323
+ const server = app.listen(this.ports.mu, () =>
324
+ console.log(`MU on port ${this.ports.mu}`),
325
+ )
326
+ this.servers.push(server)
327
+ }
328
+ su() {
329
+ const app = express()
330
+ app.use(bodyParser.json())
331
+ app.get("/", (req, res) => res.json({ timestamp: Date.now() }))
332
+ const server = app.listen(this.ports.su, () =>
333
+ console.log(`SU on port ${this.ports.su}`),
334
+ )
335
+ this.servers.push(server)
336
+ }
337
+ cu() {
338
+ const app = express()
339
+ app.use(bodyParser.json())
340
+ app.get("/", (req, res) => res.json({ timestamp: Date.now() }))
341
+ app.get("/result/:mid", async (req, res) => {
342
+ const res2 = await this.result({
343
+ message: req.params.mid,
344
+ process: req.query["process-id"],
345
+ })
346
+ res.json(res2)
347
+ })
348
+ app.post("/dry-run", async (req, res) => {
349
+ const process = req.query["process-id"]
350
+ const { Id: id, Owner: owner, Tags: tags, Data: data } = req.body
351
+ const res2 = await this.dryrun({ id, owner, tags, data, process })
352
+ delete res2.Memory
353
+ res.json(res2)
354
+ })
355
+ const server = app.listen(this.ports.cu, () =>
356
+ console.log(`CU on port ${this.ports.cu}`),
357
+ )
358
+ this.servers.push(server)
359
+ }
360
+ end() {
361
+ return new Promise(res => {
362
+ let count = 0
363
+ for (const v of this.servers)
364
+ v.close(() => {
365
+ count += 1
366
+ if (count >= 4) {
367
+ console.log("servers closed!", count)
368
+ res()
369
+ }
370
+ })
371
+ })
372
+ }
373
+ }
374
+
375
+ export default Server
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) => {
@@ -117,7 +117,7 @@ class AO extends MAO {
117
117
  const { id, owner } = await this.ar.dataitem({ tags: _tags, data, signer })
118
118
  await this.ar.post({ data, tags: t, jwk })
119
119
  this.mem.wasms[id] = { data, format: t["Module-Format"] }
120
- return id
120
+ return { id }
121
121
  }
122
122
  }
123
123
 
package/esm/tar.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import MAR from "./ar.js"
2
- import { buildTags } from "./utils.js"
2
+ import { buildTags, tags as t } from "./utils.js"
3
3
  import * as WarpArBundles from "warp-arbundles"
4
4
  const pkg = WarpArBundles.default ?? WarpArBundles
5
5
  const { DataItem } = pkg
@@ -17,16 +17,21 @@ class AR extends MAR {
17
17
  this.arweave = this.mem.arweave
18
18
  }
19
19
 
20
- async dataitem({ target = "", data = "1984", tags = {}, signer }) {
21
- const _tags = buildTags(tags)
22
- const item = await signer({ data, tags: _tags, target })
23
- const di = new DataItem(item.raw)
20
+ async dataitem({ target = "", data = "1984", tags = {}, signer, item }) {
21
+ let di = item
22
+ if (!di) {
23
+ const _tags = buildTags(tags)
24
+ const _item = await signer({ data, tags: _tags, target })
25
+ di = new DataItem(_item.raw)
26
+ } else {
27
+ tags = t(di.tags)
28
+ }
24
29
  const raw_owner = di.rawOwner
25
30
  const hashBuffer = Buffer.from(
26
31
  await crypto.subtle.digest("SHA-256", raw_owner),
27
32
  )
28
33
  const owner = base64url.encode(hashBuffer)
29
- return { id: item.id, owner, item }
34
+ return { id: await di.id, owner, item: di, tags }
30
35
  }
31
36
 
32
37
  async post({ data = "1984", tags = {}, jwk }) {
@@ -43,11 +48,13 @@ class AR extends MAR {
43
48
  })
44
49
  }
45
50
 
46
- async postItem(item, jwk) {
47
- const tx = await this.mem.arweave.createTransaction({ data: item.raw }, jwk)
51
+ async postItem(di, jwk) {
52
+ const tx = await this.mem.arweave.createTransaction(
53
+ { data: di.binary },
54
+ jwk,
55
+ )
48
56
  tx.addTag("Bundle-Format", "binary")
49
57
  tx.addTag("Bundle-Version", "2.0.0")
50
- const di = new DataItem(item.raw)
51
58
  const data_size = Buffer.byteLength(di.rawData).toString()
52
59
  let data_type = ""
53
60
  for (const t of di.tags) if (t.name === "Content-Type") data_type = t.value
@@ -66,33 +73,33 @@ class AR extends MAR {
66
73
  anchor: di.anchor,
67
74
  signature: di.signature,
68
75
  recipient: di.target,
69
- id: item.id,
76
+ id: await di.id,
70
77
  item: di,
71
78
  owner,
72
79
  tags: di.tags,
73
80
  data,
74
81
  }
75
- this.mem.txs[item.id] = _item
82
+ this.mem.txs[await di.id] = _item
76
83
  return await this.postTx(tx, jwk, _item)
77
84
  }
78
85
 
79
86
  async postTx(tx, jwk, item) {
80
87
  let [res, err] = [null, null]
81
- await this.mem.arweave.transactions.sign(tx, jwk)
88
+ if (!tx.id) await this.mem.arweave.transactions.sign(tx, jwk)
89
+ this.mem.height += 1
90
+ let block = {
91
+ id: tx.id,
92
+ timestamp: Date.now(),
93
+ height: this.mem.height,
94
+ previous: last(this.mem.blocks) ?? "",
95
+ }
82
96
  if (item) {
83
- this.mem.height += 1
84
- const block = {
85
- id: tx.id,
86
- timestamp: Date.now(),
87
- height: this.mem.height,
88
- previous: last(this.mem.blocks) ?? "",
89
- }
90
97
  if (!item.id) {
91
98
  item.id = tx.id
92
- this.mem.txs[item.id] = item
93
- this.mem.txs[item.id].parent = null
94
- this.mem.txs[item.id].signature = tx.signature
95
- this.mem.txs[item.id].anchor = tx.last_tx
99
+ this.mem.txs[tx.id] = item
100
+ this.mem.txs[tx.id].parent = null
101
+ this.mem.txs[tx.id].signature = tx.signature
102
+ this.mem.txs[tx.id].anchor = tx.last_tx
96
103
  let data_type = ""
97
104
  for (const v of tx.tags) {
98
105
  if (
@@ -101,27 +108,45 @@ class AR extends MAR {
101
108
  data_type = v.get("value", { decode: true, string: true })
102
109
  }
103
110
  }
104
- this.mem.txs[item.id]._data = { size: tx.data_size, type: data_type }
111
+ this.mem.txs[tx.id]._data = { size: tx.data_size, type: data_type }
105
112
  } else {
106
113
  this.mem.txs[item.id].parent = { id: block.id }
107
114
  }
108
115
  block.txs = [item.id]
109
116
  this.mem.txs[item.id].block = block.id
110
- this.mem.blocks.push(block.id)
111
- this.mem.blockmap[block.id] = block
117
+ } else {
118
+ let _tags = []
119
+ for (const v of tx.tags) {
120
+ _tags.push({
121
+ name: base64url.decode(v.name),
122
+ value: base64url.decode(v.value),
123
+ })
124
+ }
125
+ tx.tags = _tags
126
+ this.mem.txs[tx.id] = tx
127
+ block.txs = [tx.id]
128
+ this.mem.txs[tx.id].block = block.id
129
+ }
130
+ this.mem.blocks.push(block.id)
131
+ this.mem.blockmap[block.id] = block
132
+
133
+ if (jwk) {
134
+ const owner = await this.arweave.wallets.jwkToAddress(jwk)
135
+ this.mem.addrmap[owner] = jwk.n
112
136
  }
113
137
  res = { id: tx.id, status: 200, statusText: "200" }
114
- const owner = await this.arweave.wallets.jwkToAddress(jwk)
115
- this.mem.addrmap[owner] = jwk.n
116
138
  return { res, err, id: tx.id }
117
139
  }
118
140
 
119
- tx(id) {
141
+ async tx(id) {
120
142
  return this.mem.txs[id]
121
143
  }
122
144
 
123
- data(id) {
124
- return this.mem.txs[id].data
145
+ async data(id, string) {
146
+ let tx = this.mem.txs[id]
147
+ let _data = this.mem.txs[id]?.data ?? null
148
+ if (tx.format === 2 && _data && string) _data = base64url.decode(_data)
149
+ return _data
125
150
  }
126
151
  }
127
152
 
package/esm/test.js CHANGED
@@ -8,12 +8,15 @@ import GQL from "./tgql.js"
8
8
  import ArMem from "./armem.js"
9
9
  import { dirname } from "./utils.js"
10
10
  import { Src, setup, ok, fail } from "./helpers.js"
11
+ import Server from "./server.js"
12
+
11
13
  const blueprint = async pkg => {
12
14
  return readFileSync(resolve(await dirname(), `lua/${pkg}.lua`), "utf8")
13
15
  }
14
- const scheduler = "GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA"
16
+ const scheduler = "_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA"
15
17
 
16
18
  export {
19
+ Server,
17
20
  GQL,
18
21
  ArMem,
19
22
  AO,
package/esm/tgql.js CHANGED
@@ -80,7 +80,6 @@ export default class GQL {
80
80
  let ids = null
81
81
  if (is(Array, opt.ids)) ids = opt.ids
82
82
  else if (is(String, opt.id)) ids = [opt.id]
83
-
84
83
  let data = []
85
84
  let blocks = this.mem.blocks
86
85
  if (opt.asc !== true) blocks = reverse(blocks)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wao",
3
- "version": "0.4.11",
3
+ "version": "0.5.0",
4
4
  "description": "",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -27,6 +27,16 @@
27
27
  "arbundles": "^0.11.1",
28
28
  "arweave": "^1.15.1",
29
29
  "base64url": "^3.0.1",
30
+ "body-parser": "^1.20.3",
31
+ "express": "^4.21.2",
32
+ "graphql": "^16.10.0",
30
33
  "ramda": "^0.30.1"
34
+ },
35
+ "bin": {
36
+ "wao": "./cjs/run.js",
37
+ "wao-esm": "./esm/run.js"
38
+ },
39
+ "scripts": {
40
+ "server": "node --experimental-wasm-memory64 cjs/run.js"
31
41
  }
32
42
  }