wao 0.40.2 → 0.41.1

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 (75) hide show
  1. package/cjs/accounts-web.js +25 -0
  2. package/cjs/accounts.js +38 -0
  3. package/cjs/adaptor-base.js +504 -287
  4. package/cjs/adaptor-cf.js +42 -0
  5. package/cjs/ao-loader.js +1 -1
  6. package/cjs/ao.js +18 -6
  7. package/cjs/aoconnect-base.js +1017 -546
  8. package/cjs/aoconnect-cf.js +24 -0
  9. package/cjs/ar-remote.js +277 -0
  10. package/cjs/armem-base.js +822 -211
  11. package/cjs/armem-cf.js +128 -0
  12. package/cjs/armem.js +11 -5
  13. package/cjs/bar.js +511 -173
  14. package/cjs/car.js +37 -0
  15. package/cjs/cf-env.js +54 -0
  16. package/cjs/cf.js +76 -0
  17. package/cjs/cli.js +12 -6
  18. package/cjs/create.js +1 -1
  19. package/cjs/devs.js +53 -0
  20. package/cjs/dodb.js +116 -0
  21. package/cjs/hb.js +136 -53
  22. package/cjs/hyperbeam.js +85 -44
  23. package/cjs/keygen.js +94 -0
  24. package/cjs/run.js +4 -1
  25. package/cjs/server.js +40 -9
  26. package/cjs/storage-multi.js +525 -0
  27. package/cjs/tgql-d1.js +664 -0
  28. package/cjs/tgql.js +293 -172
  29. package/cjs/workspace/.claude/agents/tester.md +2 -2
  30. package/cjs/workspace/.claude/skills/build/SKILL.md +2 -2
  31. package/cjs/workspace/.claude/skills/test/SKILL.md +3 -2
  32. package/cjs/workspace/CLAUDE.md +2 -2
  33. package/cjs/workspace/README.md +1 -1
  34. package/cjs/workspace/docs/debug.md +9 -4
  35. package/cjs/workspace/docs/hyperbeam-devices.md +50 -1
  36. package/cjs/workspace/package.json +3 -3
  37. package/esm/accounts-web.js +14 -0
  38. package/esm/accounts.js +27 -0
  39. package/esm/adaptor-base.js +129 -31
  40. package/esm/adaptor-cf.js +11 -0
  41. package/esm/ao-loader.js +1 -1
  42. package/esm/ao.js +21 -2
  43. package/esm/aoconnect-base.js +255 -7
  44. package/esm/aoconnect-cf.js +9 -0
  45. package/esm/ar-remote.js +87 -0
  46. package/esm/armem-base.js +304 -53
  47. package/esm/armem-cf.js +67 -0
  48. package/esm/armem.js +7 -2
  49. package/esm/bar.js +126 -16
  50. package/esm/car.js +10 -0
  51. package/esm/cf-env.js +29 -0
  52. package/esm/cf.js +11 -0
  53. package/esm/cli.js +6 -2
  54. package/esm/create.js +1 -1
  55. package/esm/devs.js +15 -0
  56. package/esm/dodb.js +26 -0
  57. package/esm/hb.js +93 -16
  58. package/esm/hyperbeam.js +68 -30
  59. package/esm/keygen.js +47 -0
  60. package/esm/run.js +4 -1
  61. package/esm/server.js +29 -9
  62. package/esm/storage-multi.js +183 -0
  63. package/esm/tgql-d1.js +407 -0
  64. package/esm/tgql.js +29 -10
  65. package/esm/workspace/.claude/agents/tester.md +2 -2
  66. package/esm/workspace/.claude/skills/build/SKILL.md +2 -2
  67. package/esm/workspace/.claude/skills/test/SKILL.md +3 -2
  68. package/esm/workspace/CLAUDE.md +2 -2
  69. package/esm/workspace/README.md +1 -1
  70. package/esm/workspace/docs/debug.md +9 -4
  71. package/esm/workspace/docs/hyperbeam-devices.md +50 -1
  72. package/esm/workspace/package.json +3 -3
  73. package/package.json +10 -3
  74. package/postinstall.cjs +84 -0
  75. package/wao-0.41.1.tgz +0 -0
@@ -37,12 +37,11 @@ let onRecovery = {}
37
37
  let ongoing = {}
38
38
 
39
39
  export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
40
- return (mem, { cache, log = false, extensions = {}, hb, variant } = {}) => {
40
+ return (mem, { cache, log = false, extensions = {}, hb, variant, storage, d1, r2, kv, ar_url } = {}) => {
41
41
  const isMem = mem?.__type__ === "mem"
42
42
  if (!isMem) {
43
- let args = { cache }
43
+ let args = { cache, storage, scheduler, d1, r2, kv, ar_url }
44
44
  if (mem?.SU_URL) {
45
- args.scheduler = scheduler
46
45
  args.variant = variant
47
46
  args = mergeLeft(mem, args)
48
47
  }
@@ -78,7 +77,9 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
78
77
  scheduler: "Scheduler",
79
78
  module: "Module",
80
79
  }
81
- for (let v of __tags) v.name = cap[v.name] ?? v.name
80
+ for (let v of __tags) {
81
+ v.name = cap[v.name] ?? v.name
82
+ }
82
83
  return __tags
83
84
  }
84
85
 
@@ -168,6 +169,50 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
168
169
  await ar.postItems(item, su.jwk)
169
170
  }
170
171
 
172
+ // Remote CU — delegate WASM execution to satellite CU
173
+ if (opt._cu_url) {
174
+ const _tags = tags(opt.tags)
175
+ const ext = _tags.Extension || "WeaveDrive"
176
+ let p = {
177
+ _cu_url: opt._cu_url,
178
+ extension: ext,
179
+ format,
180
+ id,
181
+ epochs: [],
182
+ module: mod,
183
+ hash: id,
184
+ memory: null,
185
+ owner,
186
+ height: 0,
187
+ results: [id],
188
+ }
189
+ try {
190
+ const cuResult = await fetch(`${opt._cu_url}/cu/evaluate`, {
191
+ method: "POST",
192
+ headers: { "Content-Type": "application/json" },
193
+ body: JSON.stringify({
194
+ message: id,
195
+ process: id,
196
+ data: opt.data ?? "",
197
+ tags: opt.tags,
198
+ from: owner,
199
+ is_spawn: true,
200
+ }),
201
+ }).then(r => r.json())
202
+ const _msg = {
203
+ ...o(dissoc("signer"), dissoc("memory"))(opt),
204
+ res: cuResult,
205
+ msg: null,
206
+ }
207
+ await mem.set(_msg, "msgs", id)
208
+ } catch (e) {
209
+ console.log("Remote CU spawn error:", e)
210
+ }
211
+ await mem.set(p, "env", id)
212
+ delete ongoing[id]
213
+ return id
214
+ }
215
+
171
216
  const now = Date.now
172
217
  const t = tags(opt.tags)
173
218
  const ext = t.Extension || "WeaveDrive"
@@ -316,6 +361,96 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
316
361
  } else {
317
362
  await ar.postItems(item, su.jwk)
318
363
  }
364
+
365
+ // Remote CU — delegate WASM execution to satellite CU
366
+ if (p._cu_url) {
367
+ try {
368
+ let evalData = _opt?.data ?? ""
369
+ let evalTags = _opt?.tags
370
+ let evalFrom = _opt?.from ?? opt.from
371
+ if (_opt?.item) {
372
+ const decoded = base64url.decode(_opt.item.data)
373
+ evalData = typeof decoded === "string" ? decoded : Buffer.from(decoded).toString("utf-8")
374
+ evalTags = _opt.item.tags
375
+ const t = tags(evalTags)
376
+ if (t["From-Process"]) evalFrom = t["From-Process"]
377
+ if (!evalFrom) {
378
+ evalFrom = await arweave.wallets.jwkToAddress({
379
+ kty: "RSA", n: _opt.item.owner, e: "AQAB",
380
+ })
381
+ }
382
+ }
383
+ // Cranked messages historically used MU addr as From. But AOS's
384
+ // msg.reply targets msg.From, so overwriting From to mu.addr
385
+ // breaks the X-Reference round-trip for Send().receive(). Only
386
+ // override when no explicit from is supplied by the caller.
387
+ if (_opt?.for && !_opt?.from) evalFrom = mu.addr
388
+ const cuResult = await fetch(`${p._cu_url}/cu/evaluate`, {
389
+ method: "POST",
390
+ headers: { "Content-Type": "application/json" },
391
+ body: JSON.stringify({
392
+ message: opt.message,
393
+ process: opt.process,
394
+ data: evalData,
395
+ tags: evalTags,
396
+ from: evalFrom,
397
+ }),
398
+ }).then(r => r.json())
399
+ p.results.push(opt.message)
400
+ await mem.set(p, "env", opt.process)
401
+ const _msg = { ...dissoc("signer", _opt), res: cuResult, msg: null }
402
+ await mem.set(_msg, "msgs", opt.message)
403
+ // Route outbox from CU response
404
+ for (const v of cuResult?.Messages ?? []) {
405
+ const envExists = await mem.get("env", v.Target)
406
+ if (envExists) {
407
+ await message({
408
+ for: opt.message,
409
+ process: v.Target,
410
+ tags: v.Tags,
411
+ data: v.Data,
412
+ signer: mu.signer,
413
+ from: opt.process,
414
+ target: v.Target,
415
+ })
416
+ } else if (mem._remote) {
417
+ // Forward to main AR's MU for routing
418
+ const fwdTags = buildTags(null, mergeLeft(tags(v.Tags), {
419
+ "Data-Protocol": "ao",
420
+ Variant: variant ?? "ao.TN.1",
421
+ Type: "Message",
422
+ "From-Process": opt.process,
423
+ "Pushed-For": opt.message,
424
+ }))
425
+ await record({
426
+ for: opt.message,
427
+ tags: fwdTags,
428
+ data: v.Data,
429
+ signer: mu.signer,
430
+ from: opt.process,
431
+ target: v.Target,
432
+ })
433
+ }
434
+ }
435
+ for (const v of cuResult?.Spawns ?? []) {
436
+ const __tags = tags(v.Tags)
437
+ await spawn({
438
+ for: opt.message,
439
+ module: __tags.Module,
440
+ scheduler,
441
+ tags: v.Tags,
442
+ data: v.Data,
443
+ from: __tags["From-Process"],
444
+ signer: mu.signer,
445
+ })
446
+ }
447
+ return id
448
+ } catch (e) {
449
+ console.log("Remote CU assign error:", e)
450
+ return null
451
+ }
452
+ }
453
+
319
454
  try {
320
455
  let data = _opt.data ?? ""
321
456
  let _tags = _opt.tags
@@ -333,6 +468,13 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
333
468
  })
334
469
  }
335
470
  }
471
+ // Cranked messages (inter-process) historically used MU addr as
472
+ // From for AOS trust. But AOS's msg.reply uses msg.From as Target,
473
+ // so overwriting From to mu.addr breaks the X-Reference round-trip
474
+ // needed for Send().receive() coroutine resumption. Preserve the
475
+ // originating process (passed via _opt.from = opt.process from the
476
+ // outbox-dispatch loop) so replies land back on it.
477
+ if (_opt.for && !_opt.from) from = mu.addr
336
478
  // check: is owner=mu.addr right?
337
479
  const _owner = opt.message_item?.owner
338
480
  ? toAddr(opt.message_item.owner)
@@ -352,7 +494,7 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
352
494
  spawn: (await mem.getTx(p.id))?.item,
353
495
  module: await mem.getTx(mod),
354
496
  })
355
- mem.env[opt.process].handle = p.handle
497
+ if (mem.env[opt.process]) mem.env[opt.process].handle = p.handle
356
498
  }
357
499
  if (p.compressed) {
358
500
  const start = Date.now()
@@ -486,6 +628,25 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
486
628
  } catch (e) {
487
629
  console.log(e)
488
630
  }
631
+ } else if (mem._remote) {
632
+ // Remote mode: forward to main AR's MU for routing
633
+ try {
634
+ const di = await ar.dataitem({
635
+ data: v.Data ?? "",
636
+ signer: mu.signer,
637
+ tags: mergeLeft(tags(v.Tags), {
638
+ "Data-Protocol": "ao",
639
+ Variant: variant ?? "ao.TN.1",
640
+ Type: "Message",
641
+ "From-Process": opt.process,
642
+ "Pushed-For": opt.message,
643
+ }),
644
+ target: v.Target,
645
+ })
646
+ await mem._remote.postMU(di.item.getRaw())
647
+ } catch (e) {
648
+ console.log("Remote MU forward error:", e)
649
+ }
489
650
  } else {
490
651
  await record({
491
652
  for: opt.message,
@@ -608,7 +769,7 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
608
769
  spawn: (await mem.getTx(p.id))?.item,
609
770
  module: await mem.getTx(mod),
610
771
  })
611
- mem.env[opt.process].handle = p.handle
772
+ if (mem.env[opt.process]) mem.env[opt.process].handle = p.handle
612
773
  }
613
774
  if (p.compressed) {
614
775
  const start = Date.now()
@@ -738,6 +899,92 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
738
899
  return { recovered: count, pid, success }
739
900
  }
740
901
 
902
+ // Satellite CU evaluate: WASM execution only, no DataItem creation or AR posting.
903
+ // Used by cu_post_evaluate on remote CU workers.
904
+ const evaluate = async ({
905
+ message: msgId,
906
+ process: pid,
907
+ data,
908
+ tags: msgTags,
909
+ from,
910
+ is_spawn,
911
+ module: modId,
912
+ scheduler: sch,
913
+ }) => {
914
+ if (is_spawn) {
915
+ const mod = modId || tags(msgTags || []).Module
916
+ if (!mod) throw Error("module missing for evaluate spawn")
917
+ const { mod: resolvedMod, wasm, format } = await mem.getWasm(mod)
918
+ const _tags = tags(msgTags || [])
919
+ const ext = _tags.Extension || "WeaveDrive"
920
+ const wdrive = extensions[ext]
921
+ const spawnTx = await mem.getTx(pid)
922
+ const moduleTx = await mem.getTx(resolvedMod)
923
+ const handle = await AoLoader(wasm, {
924
+ format,
925
+ WeaveDrive: wdrive,
926
+ spawn: spawnTx?.item ?? spawnTx ?? null,
927
+ module: moduleTx,
928
+ })
929
+ const owner = from || mu.addr
930
+ let p = {
931
+ extension: ext,
932
+ format,
933
+ id: pid,
934
+ epochs: [],
935
+ handle,
936
+ module: resolvedMod,
937
+ hash: pid,
938
+ memory: null,
939
+ owner,
940
+ height: 0,
941
+ results: [pid],
942
+ }
943
+ let bootData = ""
944
+ if (_tags["On-Boot"] === "Data") bootData = data ?? ""
945
+ else bootData = data ?? ""
946
+ const msg = await genMsg(pid, p, bootData, msgTags || [], owner, owner, true)
947
+ const _env = await genEnv({ pid, owner, module: resolvedMod })
948
+ const res = await handle(null, msg, _env)
949
+ p.memory = res.Memory
950
+ delete res.Memory
951
+ await mem.set({ tags: msgTags, data, res, msg }, "msgs", pid)
952
+ await mem.set(p, "env", pid)
953
+ return res
954
+ }
955
+
956
+ // Message evaluation with state update
957
+ const p = await mem.get("env", pid)
958
+ if (!p) throw Error(`process ${pid} not found on satellite CU`)
959
+ if (!p.handle) {
960
+ const { format, mod, wasm } = await mem.getWasm(p.module)
961
+ const wdrive = extensions[p.extension]
962
+ const spawnTx = await mem.getTx(p.id)
963
+ const moduleTx = await mem.getTx(mod)
964
+ p.handle = await AoLoader(wasm, {
965
+ format,
966
+ WeaveDrive: wdrive,
967
+ spawn: spawnTx?.item ?? spawnTx ?? null,
968
+ module: moduleTx,
969
+ })
970
+ }
971
+ if (p.compressed) {
972
+ p.memory = mem.decompress(p.memory, p.original_size)
973
+ p.compressed = false
974
+ }
975
+ p.height += 1
976
+ const owner = from || mu.addr
977
+ const msg = await genMsg(msgId, p, data ?? "", msgTags || [], owner, owner)
978
+ const _env = await genEnv({ pid, owner: p.owner, module: p.module })
979
+ const res = await p.handle(p.memory, msg, _env)
980
+ p.memory = res.Memory
981
+ delete res.Memory
982
+ p.results.push(msgId)
983
+ await mem.set(p, "env", pid)
984
+ await mem.set({ tags: msgTags, data, from, res, msg }, "msgs", msgId)
985
+ return res
986
+ }
987
+
741
988
  const result = async opt => {
742
989
  return (await mem.get("msgs", opt.message))?.res
743
990
  }
@@ -828,7 +1075,7 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
828
1075
  spawn: (await mem.getTx(p.id)).item,
829
1076
  module: await mem.getTx(mod),
830
1077
  })
831
- mem.env[opt.process].handle = p.handle
1078
+ if (mem.env[opt.process]) mem.env[opt.process].handle = p.handle
832
1079
  }
833
1080
  if (p.compressed) {
834
1081
  const start = Date.now()
@@ -844,6 +1091,7 @@ export default ({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem } = {}) => {
844
1091
  return null
845
1092
  },
846
1093
  recover,
1094
+ evaluate,
847
1095
  mem,
848
1096
  }
849
1097
  }
@@ -0,0 +1,9 @@
1
+ import "./cf-env.js"
2
+ import base from "./aoconnect-base.js"
3
+ import AR from "./car.js"
4
+ import { mu, su, cu, acc } from "./cf.js"
5
+ import AoLoader from "./ao-loader.js"
6
+ import ArMem from "./armem-cf.js"
7
+ const scheduler = "_GQ33BkPtZrqxA84vM8Zk-N2aO0toNNu_C-l-rawrBA"
8
+
9
+ export const connect = base({ AR, scheduler, mu, su, cu, acc, AoLoader, ArMem })
@@ -0,0 +1,87 @@
1
+ export default class RemoteAR {
2
+ constructor(ar_url) {
3
+ this.url = ar_url.replace(/\/$/, "")
4
+ }
5
+
6
+ async data(id) {
7
+ const res = await fetch(`${this.url}/ar/${id}`)
8
+ if (!res.ok) return null
9
+ return new Uint8Array(await res.arrayBuffer())
10
+ }
11
+
12
+ async getTx(id) {
13
+ const query = `{ transactions(ids: ["${id}"]) {
14
+ edges { node { id owner { address key } recipient tags { name value }
15
+ anchor signature data { size type } block { id height timestamp } } }
16
+ } }`
17
+ const res = await fetch(`${this.url}/ar/graphql`, {
18
+ method: "POST",
19
+ headers: { "Content-Type": "application/json" },
20
+ body: JSON.stringify({ query }),
21
+ })
22
+ const json = await res.json()
23
+ const node = json?.data?.transactions?.edges?.[0]?.node
24
+ if (!node) return null
25
+ return {
26
+ id: node.id,
27
+ owner: node.owner?.address,
28
+ _owner_key: node.owner?.key,
29
+ recipient: node.recipient,
30
+ tags: node.tags,
31
+ anchor: node.anchor,
32
+ signature: node.signature,
33
+ _data: node.data,
34
+ block: node.block?.id,
35
+ }
36
+ }
37
+
38
+ async postTx(tx) {
39
+ const res = await fetch(`${this.url}/ar/${tx.id || "tx"}`, {
40
+ method: "POST",
41
+ headers: { "Content-Type": "application/json" },
42
+ body: JSON.stringify(tx),
43
+ })
44
+ return await res.json()
45
+ }
46
+
47
+ async postMU(rawDataItem) {
48
+ const res = await fetch(`${this.url}/mu`, {
49
+ method: "POST",
50
+ headers: { "Content-Type": "application/octet-stream" },
51
+ body: rawDataItem,
52
+ })
53
+ return await res.json()
54
+ }
55
+
56
+ async getHeight() {
57
+ const res = await fetch(`${this.url}/ar/`)
58
+ const json = await res.json()
59
+ return json.height ?? 0
60
+ }
61
+
62
+ async getAnchor() {
63
+ const res = await fetch(`${this.url}/ar/tx_anchor`)
64
+ return await res.text()
65
+ }
66
+
67
+ async graphql(query, variables) {
68
+ const res = await fetch(`${this.url}/ar/graphql`, {
69
+ method: "POST",
70
+ headers: { "Content-Type": "application/json" },
71
+ body: JSON.stringify({ query, variables }),
72
+ })
73
+ return await res.json()
74
+ }
75
+
76
+ async findSU(schedulerAddr) {
77
+ const query = `{ transactions(
78
+ owners: ["${schedulerAddr}"],
79
+ tags: [{ name: "Type", values: ["Scheduler-Location"] }],
80
+ first: 1, sort: HEIGHT_DESC
81
+ ) { edges { node { tags { name value } } } } }`
82
+ const json = await this.graphql(query)
83
+ const tags = json?.data?.transactions?.edges?.[0]?.node?.tags ?? []
84
+ const urlTag = tags.find(t => t.name === "Url")
85
+ return urlTag?.value ?? null
86
+ }
87
+ }