@threadedstack/wmd-web 0.0.0-stage → 0.1.12

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 (92) hide show
  1. package/README.md +2601 -2
  2. package/RELEASE.json +123 -0
  3. package/export-page/coi-sw.js +20 -0
  4. package/export-page/index.html +17 -0
  5. package/export-page/run.css +10 -0
  6. package/export-page/run.js +236 -0
  7. package/guest/arm64/Image +4 -0
  8. package/guest/arm64/Image-4k +4 -0
  9. package/guest/arm64/initramfs.cpio.gz +0 -0
  10. package/guest/arm64/vm.wasm +0 -0
  11. package/package.json +36 -4
  12. package/page/sw.js +381 -0
  13. package/relay/control.ts +139 -0
  14. package/relay/engine.ts +787 -0
  15. package/relay/hosted.ts +660 -0
  16. package/relay/keys.ts +53 -0
  17. package/relay/local-tls.ts +121 -0
  18. package/relay/lock.ts +81 -0
  19. package/relay/logfile.ts +138 -0
  20. package/relay/main.ts +642 -0
  21. package/relay/policy.ts +241 -0
  22. package/relay/relay.ts +266 -0
  23. package/relay/token.ts +116 -0
  24. package/relay/v1.ts +107 -0
  25. package/relay/wisp.ts +615 -0
  26. package/src/base.js +325 -0
  27. package/src/boot.js +2037 -0
  28. package/src/calib-worker.js +40 -0
  29. package/src/fs/9p/codec.js +303 -0
  30. package/src/fs/9p/server.js +521 -0
  31. package/src/fs/errno.js +43 -0
  32. package/src/fs/graph.js +380 -0
  33. package/src/fs/overlay.js +1018 -0
  34. package/src/fs/pack-write.js +165 -0
  35. package/src/fs/pack.js +427 -0
  36. package/src/fs/seed.js +22 -0
  37. package/src/fs/svc-snapshot.js +65 -0
  38. package/src/fs/upper-pack.js +112 -0
  39. package/src/host/base-cache.js +195 -0
  40. package/src/host/base-file.js +328 -0
  41. package/src/host/base-io.js +93 -0
  42. package/src/host/boot-events.js +209 -0
  43. package/src/host/chan-service.js +300 -0
  44. package/src/host/chan-services.js +689 -0
  45. package/src/host/chan.js +655 -0
  46. package/src/host/ckpt-file.js +395 -0
  47. package/src/host/ckpt-io.js +207 -0
  48. package/src/host/ckpt-point.js +160 -0
  49. package/src/host/ckpt-save.js +64 -0
  50. package/src/host/ckpt.js +434 -0
  51. package/src/host/clock.js +111 -0
  52. package/src/host/ctl.js +778 -0
  53. package/src/host/errno.js +18 -0
  54. package/src/host/fs.js +167 -0
  55. package/src/host/gcnudge.js +83 -0
  56. package/src/host/i64shim.js +81 -0
  57. package/src/host/jit-cache.js +341 -0
  58. package/src/host/jit-hub-core.js +208 -0
  59. package/src/host/jit-hub.js +93 -0
  60. package/src/host/jit-snap.js +226 -0
  61. package/src/host/jit.js +1903 -0
  62. package/src/host/layout.js +100 -0
  63. package/src/host/monitor.js +110 -0
  64. package/src/host/p9mount.js +27 -0
  65. package/src/host/ram-mem.js +125 -0
  66. package/src/host/stdio.js +143 -0
  67. package/src/host/threads.js +109 -0
  68. package/src/host/wasi.js +335 -0
  69. package/src/host/wmd-imports.js +71 -0
  70. package/src/host/yamux.js +387 -0
  71. package/src/image-files.js +154 -0
  72. package/src/net/dhcp-dns.js +126 -0
  73. package/src/net/net-worker.js +172 -0
  74. package/src/net/packet.js +227 -0
  75. package/src/net/peer.js +230 -0
  76. package/src/net/proto.js +189 -0
  77. package/src/net/relay-client.js +226 -0
  78. package/src/net/stack.js +867 -0
  79. package/src/net/switch.js +160 -0
  80. package/src/net/wisp-client.js +570 -0
  81. package/src/net/wisp-transport.js +196 -0
  82. package/src/net/wisp.js +511 -0
  83. package/src/registry/client.js +176 -0
  84. package/src/registry/converter.js +68 -0
  85. package/src/registry/hub.js +221 -0
  86. package/src/registry/oci.js +76 -0
  87. package/src/registry/pack-worker.js +70 -0
  88. package/src/registry/pull.js +258 -0
  89. package/src/registry/ref.js +110 -0
  90. package/src/registry/wasi-mem.js +355 -0
  91. package/src/worker.js +315 -0
  92. package/wmdpack.wasm +0 -0
@@ -0,0 +1,196 @@
1
+ // W71: TCP streams over a Wisp relay for code in the page itself (no guest network stack), with
2
+ // the Transport interface wmn's createRelayFetch takes (TLS runs in the page; the relay carries
3
+ // ciphertext only):
4
+ //
5
+ // const t = createWispTransport({ url: 'local' }) // or 'hosted', or a ws(s):// URL
6
+ // const fetch = createRelayFetch({ transport: t }) // wmn: packages/ai/src/relay/fetch.ts
7
+ // const s = await t.connect('registry-1.docker.io', 443, signal)
8
+ // s.write(bytes); const b = await s.read(n); s.end(); s.abort()
9
+ // t.close()
10
+ //
11
+ // WispClient (wisp-client.js) does the protocol, as it does for the guest's stack; this file is the
12
+ // stack it calls back into. read(n) waits for n bytes (fewer at a clean end, undefined when nothing
13
+ // is left; with mode 1, PEEK, the bytes stay queued); a reset or a dropped relay is an error. Bytes
14
+ // taken by the reader go back to the relay as credit (wmd-credit), so a slow reader slows the relay.
15
+
16
+ import { E } from './proto.js'
17
+ import { WispClient } from './wisp-client.js'
18
+
19
+ const PEEK = 1
20
+
21
+ class StreamQueue {
22
+ constructor(onTaken) {
23
+ this.onTaken = onTaken
24
+ this.q = []
25
+ this.n = 0
26
+ this.ended = false
27
+ this.failure = null
28
+ this.want = null
29
+ }
30
+ push(b) {
31
+ if (this.ended) return
32
+ this.q.push(b)
33
+ this.n += b.length
34
+ this.#serve()
35
+ }
36
+ finish() {
37
+ this.ended = true
38
+ this.#serve()
39
+ }
40
+ fail(e) {
41
+ if (this.ended && !this.failure && !this.want) return
42
+ this.failure ??= e
43
+ this.ended = true
44
+ this.#serve()
45
+ }
46
+ read(bytes, mode = 0) {
47
+ if (this.want) return Promise.reject(new Error('a read is already waiting on this stream'))
48
+ return new Promise((resolve, reject) => {
49
+ this.want = { bytes, mode, resolve, reject }
50
+ this.#serve()
51
+ })
52
+ }
53
+ #serve() {
54
+ const w = this.want
55
+ if (!w || (this.n < w.bytes && !this.ended)) return
56
+ this.want = null
57
+ const k = Math.min(w.bytes, this.n)
58
+ if (k === 0) return this.failure ? w.reject(this.failure) : w.resolve(undefined)
59
+ const out = new Uint8Array(k)
60
+ let o = 0
61
+ let i = 0
62
+ while (o < k) {
63
+ const b = this.q[i]
64
+ const take = Math.min(b.length, k - o)
65
+ out.set(b.subarray(0, take), o)
66
+ o += take
67
+ if (w.mode !== PEEK) {
68
+ if (take === b.length) i++
69
+ else this.q[i] = b.subarray(take)
70
+ } else i++
71
+ }
72
+ if (w.mode !== PEEK) {
73
+ this.q.splice(0, i)
74
+ this.n -= k
75
+ this.onTaken(k)
76
+ }
77
+ w.resolve(out)
78
+ }
79
+ }
80
+
81
+ /**
82
+ * @param {object} o
83
+ * @param {string} o.url 'local', 'hosted' or a ws(s):// Wisp URL
84
+ * @param {WispClient} [o.client] a client to use instead (its stack is set to this transport)
85
+ * @param {(line: string) => void} [o.log]
86
+ * @returns {{connect(host: string, port: number, signal?: AbortSignal): Promise<object>, close(): void, client: WispClient}}
87
+ */
88
+ export function createWispTransport(o = {}) {
89
+ const client = o.client || new WispClient({ url: o.url, log: o.log, instance: o.instance })
90
+ const streams = new Map() // id -> {queue, opened}
91
+ let nextId = 1
92
+ let closed = false
93
+ const stack = {
94
+ onConnected(id, code, _window, why) {
95
+ const s = streams.get(id)
96
+ if (!s?.opened) return
97
+ const { resolve, reject } = s.opened
98
+ s.opened = null
99
+ if (code === E.OK) resolve()
100
+ else {
101
+ streams.delete(id)
102
+ reject(new Error(why || `the relay could not open the stream (code ${code})`))
103
+ }
104
+ },
105
+ onRelayData(id, b) {
106
+ streams.get(id)?.queue.push(b)
107
+ },
108
+ onRelayEnd(id) {
109
+ const s = streams.get(id)
110
+ if (!s) return
111
+ s.queue.finish()
112
+ s.remoteEnded = true
113
+ if (s.localEnded) {
114
+ streams.delete(id)
115
+ client.closed(id)
116
+ }
117
+ },
118
+ onRelayAbort(id, _code, why) {
119
+ const s = streams.get(id)
120
+ if (!s) return
121
+ streams.delete(id)
122
+ const e = new Error(why || 'the relay reset the stream')
123
+ if (s.opened) s.opened.reject(e)
124
+ s.queue.fail(e)
125
+ },
126
+ onRelayCredit() {},
127
+ onDnsReply() {},
128
+ onRelayDown(why) {
129
+ const e = new Error(`the relay connection dropped${why ? `: ${why}` : ''}`)
130
+ for (const [id, s] of streams) {
131
+ streams.delete(id)
132
+ if (s.opened) s.opened.reject(e)
133
+ s.queue.fail(e)
134
+ }
135
+ },
136
+ }
137
+ client.attach(stack)
138
+
139
+ return {
140
+ client,
141
+ async connect(host, port, signal) {
142
+ if (closed) throw new Error('the transport is closed')
143
+ signal?.throwIfAborted()
144
+ const id = nextId++
145
+ const s = {
146
+ queue: new StreamQueue(n => client.credit(id, n)),
147
+ opened: null,
148
+ localEnded: false,
149
+ remoteEnded: false,
150
+ }
151
+ streams.set(id, s)
152
+ const opened = new Promise((resolve, reject) => (s.opened = { resolve, reject }))
153
+ const onAbort = () => {
154
+ if (!s.opened) return
155
+ const { reject } = s.opened
156
+ s.opened = null
157
+ streams.delete(id)
158
+ client.abort(id)
159
+ reject(signal.reason ?? new Error('aborted'))
160
+ }
161
+ signal?.addEventListener('abort', onAbort, { once: true })
162
+ client.connect(id, host, port)
163
+ try {
164
+ await opened
165
+ } finally {
166
+ signal?.removeEventListener('abort', onAbort)
167
+ }
168
+ return {
169
+ read: (n, mode) => s.queue.read(n, mode),
170
+ write(b) {
171
+ if (streams.get(id) === s && !s.localEnded) client.data(id, b.slice())
172
+ },
173
+ end() {
174
+ if (s.localEnded || streams.get(id) !== s) return
175
+ s.localEnded = true
176
+ client.end(id)
177
+ if (s.remoteEnded) {
178
+ streams.delete(id)
179
+ client.closed(id)
180
+ }
181
+ },
182
+ abort() {
183
+ if (streams.get(id) !== s) return
184
+ streams.delete(id)
185
+ client.abort(id)
186
+ s.queue.fail(new Error('the stream was reset'))
187
+ },
188
+ }
189
+ },
190
+ close() {
191
+ closed = true
192
+ stack.onRelayDown('closed by the page')
193
+ client.ws?.close(1000)
194
+ },
195
+ }
196
+ }