@lesomnus/grpc-dgram 0.0.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.
- package/LICENSE +202 -0
- package/README.md +245 -0
- package/dist/conn-DOmx4nbt.mjs +849 -0
- package/dist/conn-DTWG9vIx.d.mts +331 -0
- package/dist/desc-BMF2FBqk.d.mts +72 -0
- package/dist/index.d.mts +27 -0
- package/dist/index.mjs +1079 -0
- package/dist/protocol-K4Zy8MuQ.mjs +156 -0
- package/dist/server-xIr1mwqq.d.mts +112 -0
- package/dist/status-DZwMDWIn.mjs +63 -0
- package/dist/transport/connect.d.mts +6 -0
- package/dist/transport/connect.mjs +122 -0
- package/dist/transport/node-udp.d.mts +42 -0
- package/dist/transport/node-udp.mjs +144 -0
- package/dist/transport/port.d.mts +52 -0
- package/dist/transport/port.mjs +240 -0
- package/dist/transport/protobuf-es.d.mts +19 -0
- package/dist/transport/protobuf-es.mjs +27 -0
- package/dist/transport/webrtc.d.mts +56 -0
- package/dist/transport/webrtc.mjs +240 -0
- package/dist/transport/websocket.d.mts +59 -0
- package/dist/transport/websocket.mjs +324 -0
- package/dist/wasm/worker.d.mts +8 -0
- package/dist/wasm/worker.mjs +73 -0
- package/dist/wasm.d.mts +36 -0
- package/dist/wasm.mjs +156 -0
- package/dist/wire-BR8KiyRg.mjs +876 -0
- package/package.json +73 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { $ as unpack, F as Latch, G as noop, R as abortListener, X as unrefTimer, c as decodeEnvelop, u as encodeEnvelop } from "../wire-BR8KiyRg.mjs";
|
|
2
|
+
import { n as MessageTooLargeError, r as StatusError } from "../status-DZwMDWIn.mjs";
|
|
3
|
+
import { n as Conn } from "../conn-DOmx4nbt.mjs";
|
|
4
|
+
//#region src/transport/websocket/index.ts
|
|
5
|
+
const CONNECTING = 0;
|
|
6
|
+
const OPEN = 1;
|
|
7
|
+
const CLOSING = 2;
|
|
8
|
+
const CLOSED = 3;
|
|
9
|
+
const DefaultMaxMessageSize = 0;
|
|
10
|
+
const DefaultMaxBufferedAmount = 1 << 20;
|
|
11
|
+
const DefaultKeepaliveIntervalMs = 2e4;
|
|
12
|
+
const DefaultKeepaliveTimeoutMs = 3e4;
|
|
13
|
+
const bufferedPollMs = 25;
|
|
14
|
+
const closeCodesClean = /* @__PURE__ */ new Set([
|
|
15
|
+
1e3,
|
|
16
|
+
1001,
|
|
17
|
+
1005
|
|
18
|
+
]);
|
|
19
|
+
function wire(ws, type, fn) {
|
|
20
|
+
if (typeof ws.addEventListener === "function") ws.addEventListener(type, fn);
|
|
21
|
+
else ws[`on${type}`] = fn;
|
|
22
|
+
}
|
|
23
|
+
function errorOf(ev) {
|
|
24
|
+
const e = ev;
|
|
25
|
+
if (e?.error !== void 0 && e.error !== null) return e.error;
|
|
26
|
+
if (typeof e?.message === "string") return /* @__PURE__ */ new Error(`websocket: ${e.message}`);
|
|
27
|
+
return /* @__PURE__ */ new Error("websocket: transport error");
|
|
28
|
+
}
|
|
29
|
+
function closeCauseOf(ev) {
|
|
30
|
+
const e = ev;
|
|
31
|
+
const code = typeof e?.code === "number" ? e.code : 1005;
|
|
32
|
+
if (closeCodesClean.has(code)) return void 0;
|
|
33
|
+
const reason = typeof e?.reason === "string" && e.reason !== "" ? `: ${e.reason}` : "";
|
|
34
|
+
return /* @__PURE__ */ new Error(`websocket: closed with code ${code}${reason}`);
|
|
35
|
+
}
|
|
36
|
+
function wakeAll(waiters) {
|
|
37
|
+
if (waiters.length === 0) return;
|
|
38
|
+
const ws = waiters.splice(0);
|
|
39
|
+
for (const w of ws) w();
|
|
40
|
+
}
|
|
41
|
+
var Socket = class {
|
|
42
|
+
ws;
|
|
43
|
+
max;
|
|
44
|
+
high;
|
|
45
|
+
stallMs;
|
|
46
|
+
kaIntervalMs;
|
|
47
|
+
kaTimeoutMs;
|
|
48
|
+
opened = new Latch();
|
|
49
|
+
dead = new Latch();
|
|
50
|
+
err;
|
|
51
|
+
rx = [];
|
|
52
|
+
rxWaiters = [];
|
|
53
|
+
kaTimer;
|
|
54
|
+
kaDeadline;
|
|
55
|
+
constructor(ws, o) {
|
|
56
|
+
this.ws = ws;
|
|
57
|
+
this.max = o.maxMessageSize ?? 0;
|
|
58
|
+
this.high = o.maxBufferedAmount ?? 1048576;
|
|
59
|
+
this.kaIntervalMs = o.keepaliveIntervalMs ?? 2e4;
|
|
60
|
+
this.kaTimeoutMs = o.keepaliveTimeoutMs ?? 3e4;
|
|
61
|
+
this.stallMs = o.sendStallTimeoutMs ?? this.kaTimeoutMs;
|
|
62
|
+
try {
|
|
63
|
+
ws.binaryType = "arraybuffer";
|
|
64
|
+
} catch {}
|
|
65
|
+
wire(ws, "open", () => this.onOpen());
|
|
66
|
+
wire(ws, "error", (ev) => this.fail(errorOf(ev)));
|
|
67
|
+
wire(ws, "close", (ev) => this.fail(closeCauseOf(ev)));
|
|
68
|
+
wire(ws, "message", (ev) => this.onMessage(ev));
|
|
69
|
+
if (ws.readyState === OPEN) this.onOpen();
|
|
70
|
+
else if (ws.readyState === CLOSING || ws.readyState === CLOSED) this.fail(void 0);
|
|
71
|
+
}
|
|
72
|
+
fail(err) {
|
|
73
|
+
if (!this.dead.tripped && this.err === void 0) this.err = err;
|
|
74
|
+
this.dead.trip();
|
|
75
|
+
this.stopKeepalive();
|
|
76
|
+
wakeAll(this.rxWaiters);
|
|
77
|
+
}
|
|
78
|
+
deathErr() {
|
|
79
|
+
return this.err;
|
|
80
|
+
}
|
|
81
|
+
closedErr() {
|
|
82
|
+
const e = new StatusError(14, `websocket: socket closed${this.err instanceof Error ? `: ${this.err.message}` : ""}`);
|
|
83
|
+
if (this.err !== void 0) e.cause = this.err;
|
|
84
|
+
return e;
|
|
85
|
+
}
|
|
86
|
+
onOpen() {
|
|
87
|
+
if (this.dead.tripped) return;
|
|
88
|
+
this.opened.trip();
|
|
89
|
+
this.startKeepalive();
|
|
90
|
+
}
|
|
91
|
+
startKeepalive() {
|
|
92
|
+
if (this.kaTimer !== void 0 || this.dead.tripped) return;
|
|
93
|
+
if (this.kaIntervalMs <= 0 || this.kaTimeoutMs <= 0) return;
|
|
94
|
+
const ws = this.ws;
|
|
95
|
+
if (typeof ws.ping !== "function" || typeof ws.on !== "function") return;
|
|
96
|
+
ws.on("pong", () => this.progress());
|
|
97
|
+
const t = setInterval(() => {
|
|
98
|
+
try {
|
|
99
|
+
ws.ping?.();
|
|
100
|
+
} catch (e) {
|
|
101
|
+
this.fail(new Error(`websocket: keepalive ping: ${e instanceof Error ? e.message : String(e)}`, { cause: e }));
|
|
102
|
+
}
|
|
103
|
+
}, this.kaIntervalMs);
|
|
104
|
+
unrefTimer(t);
|
|
105
|
+
this.kaTimer = t;
|
|
106
|
+
this.progress();
|
|
107
|
+
}
|
|
108
|
+
progress() {
|
|
109
|
+
if (this.kaDeadline !== void 0) clearTimeout(this.kaDeadline);
|
|
110
|
+
this.kaDeadline = void 0;
|
|
111
|
+
if (this.kaTimer === void 0 || this.dead.tripped) return;
|
|
112
|
+
const t = setTimeout(() => this.fail(/* @__PURE__ */ new Error(`websocket: no read progress within ${this.kaTimeoutMs}ms`)), this.kaTimeoutMs);
|
|
113
|
+
unrefTimer(t);
|
|
114
|
+
this.kaDeadline = t;
|
|
115
|
+
}
|
|
116
|
+
stopKeepalive() {
|
|
117
|
+
if (this.kaTimer !== void 0) clearInterval(this.kaTimer);
|
|
118
|
+
if (this.kaDeadline !== void 0) clearTimeout(this.kaDeadline);
|
|
119
|
+
this.kaTimer = void 0;
|
|
120
|
+
this.kaDeadline = void 0;
|
|
121
|
+
}
|
|
122
|
+
onMessage(ev) {
|
|
123
|
+
if (this.dead.tripped) return;
|
|
124
|
+
this.progress();
|
|
125
|
+
const data = ev.data;
|
|
126
|
+
if (data instanceof ArrayBuffer) this.rx.push(new Uint8Array(data));
|
|
127
|
+
else if (ArrayBuffer.isView(data)) this.rx.push(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
|
|
128
|
+
else return;
|
|
129
|
+
wakeAll(this.rxWaiters);
|
|
130
|
+
}
|
|
131
|
+
async send(frames, signal) {
|
|
132
|
+
const data = encodeEnvelop(frames);
|
|
133
|
+
if (this.max > 0 && data.length > this.max) throw new MessageTooLargeError(`websocket: ${data.length}-byte envelop over the ${this.max}-byte limit`);
|
|
134
|
+
const stalled = new Latch();
|
|
135
|
+
let stallTimer;
|
|
136
|
+
if (this.stallMs > 0) {
|
|
137
|
+
stallTimer = setTimeout(() => stalled.trip(), this.stallMs);
|
|
138
|
+
unrefTimer(stallTimer);
|
|
139
|
+
}
|
|
140
|
+
let disposeAbort = noop;
|
|
141
|
+
const signalAborted = new Latch();
|
|
142
|
+
if (signal !== void 0) if (signal.aborted) signalAborted.trip();
|
|
143
|
+
else disposeAbort = abortListener(signal, () => signalAborted.trip());
|
|
144
|
+
try {
|
|
145
|
+
while (!this.opened.tripped) {
|
|
146
|
+
await Promise.race([
|
|
147
|
+
this.opened.wait(),
|
|
148
|
+
stalled.wait(),
|
|
149
|
+
this.dead.wait(),
|
|
150
|
+
signalAborted.wait()
|
|
151
|
+
]);
|
|
152
|
+
if (this.opened.tripped) break;
|
|
153
|
+
if (this.dead.tripped) throw this.closedErr();
|
|
154
|
+
if (stalled.tripped) {
|
|
155
|
+
const err = /* @__PURE__ */ new Error(`websocket: send stalled: socket not open within ${this.stallMs}ms`);
|
|
156
|
+
this.fail(err);
|
|
157
|
+
throw err;
|
|
158
|
+
}
|
|
159
|
+
if (signalAborted.tripped) throw new Error("websocket: send aborted");
|
|
160
|
+
}
|
|
161
|
+
while (this.high > 0 && this.ws.bufferedAmount >= this.high) {
|
|
162
|
+
if (this.dead.tripped) throw this.closedErr();
|
|
163
|
+
await Promise.race([
|
|
164
|
+
poll(),
|
|
165
|
+
stalled.wait(),
|
|
166
|
+
this.dead.wait(),
|
|
167
|
+
signalAborted.wait()
|
|
168
|
+
]);
|
|
169
|
+
if (this.dead.tripped) throw this.closedErr();
|
|
170
|
+
if (stalled.tripped) {
|
|
171
|
+
const err = /* @__PURE__ */ new Error(`websocket: send stalled at the buffered-amount mark for ${this.stallMs}ms`);
|
|
172
|
+
this.fail(err);
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
if (signalAborted.tripped) throw new Error("websocket: send aborted");
|
|
176
|
+
}
|
|
177
|
+
if (this.dead.tripped) throw this.closedErr();
|
|
178
|
+
try {
|
|
179
|
+
this.ws.send(data);
|
|
180
|
+
} catch (e) {
|
|
181
|
+
this.fail(e);
|
|
182
|
+
throw this.closedErr();
|
|
183
|
+
}
|
|
184
|
+
} finally {
|
|
185
|
+
if (stallTimer !== void 0) clearTimeout(stallTimer);
|
|
186
|
+
disposeAbort();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
async pump(h, ctx) {
|
|
190
|
+
const dctl = new AbortController();
|
|
191
|
+
this.dead.wait().then(() => dctl.abort(this.closedErr()));
|
|
192
|
+
const dctx = {
|
|
193
|
+
...ctx,
|
|
194
|
+
signal: dctl.signal
|
|
195
|
+
};
|
|
196
|
+
for (;;) {
|
|
197
|
+
const data = this.rx.shift();
|
|
198
|
+
if (data !== void 0) {
|
|
199
|
+
let frames;
|
|
200
|
+
try {
|
|
201
|
+
frames = decodeEnvelop(data);
|
|
202
|
+
} catch {
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
await unpack(frames, h, dctx);
|
|
206
|
+
continue;
|
|
207
|
+
}
|
|
208
|
+
if (this.dead.tripped) return this.err;
|
|
209
|
+
await Promise.race([this.rxReadable(), this.dead.wait()]);
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
rxReadable() {
|
|
213
|
+
if (this.rx.length > 0) return Promise.resolve();
|
|
214
|
+
return new Promise((res) => this.rxWaiters.push(res));
|
|
215
|
+
}
|
|
216
|
+
close() {
|
|
217
|
+
this.fail(void 0);
|
|
218
|
+
try {
|
|
219
|
+
if (this.ws.readyState === CONNECTING || this.ws.readyState === OPEN) this.ws.close(1e3, "");
|
|
220
|
+
} catch {}
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
function poll() {
|
|
224
|
+
return new Promise((res) => {
|
|
225
|
+
unrefTimer(setTimeout(res, bufferedPollMs));
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
var WebSocketTransport = class {
|
|
229
|
+
sock;
|
|
230
|
+
attached = false;
|
|
231
|
+
closed = false;
|
|
232
|
+
constructor(ws, opts = {}) {
|
|
233
|
+
this.sock = new Socket(ws, opts);
|
|
234
|
+
}
|
|
235
|
+
reliable() {
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
attachConn(conn) {
|
|
239
|
+
if (this.attached) throw new Error("websocket: transport already attached to a Conn");
|
|
240
|
+
this.attached = true;
|
|
241
|
+
(async () => {
|
|
242
|
+
const err = await this.sock.pump(conn, {});
|
|
243
|
+
conn.close(err);
|
|
244
|
+
this.close();
|
|
245
|
+
})();
|
|
246
|
+
}
|
|
247
|
+
handle(f, ctx = {}) {
|
|
248
|
+
return this.sock.send([f], ctx.signal);
|
|
249
|
+
}
|
|
250
|
+
close() {
|
|
251
|
+
if (this.closed) return;
|
|
252
|
+
this.closed = true;
|
|
253
|
+
this.sock.close();
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
var WebSocketGateway = class {
|
|
257
|
+
o;
|
|
258
|
+
next = 0;
|
|
259
|
+
socks = /* @__PURE__ */ new Map();
|
|
260
|
+
peers = /* @__PURE__ */ new Map();
|
|
261
|
+
constructor(opts = {}) {
|
|
262
|
+
this.o = opts;
|
|
263
|
+
}
|
|
264
|
+
reliable() {
|
|
265
|
+
return true;
|
|
266
|
+
}
|
|
267
|
+
bind(ws) {
|
|
268
|
+
this.bindSocket(ws);
|
|
269
|
+
}
|
|
270
|
+
bindSocket(ws) {
|
|
271
|
+
let b = this.socks.get(ws);
|
|
272
|
+
if (b === void 0) {
|
|
273
|
+
b = {
|
|
274
|
+
sock: new Socket(ws, this.o),
|
|
275
|
+
key: ++this.next,
|
|
276
|
+
served: false
|
|
277
|
+
};
|
|
278
|
+
this.socks.set(ws, b);
|
|
279
|
+
this.peers.set(b.key, b.sock);
|
|
280
|
+
}
|
|
281
|
+
return b;
|
|
282
|
+
}
|
|
283
|
+
drop(ws, b) {
|
|
284
|
+
b.sock.fail(void 0);
|
|
285
|
+
this.socks.delete(ws);
|
|
286
|
+
this.peers.delete(b.key);
|
|
287
|
+
}
|
|
288
|
+
async servePeer(server, ws, opts = {}) {
|
|
289
|
+
const b = this.bindSocket(ws);
|
|
290
|
+
if (b.served) throw new Error("websocket: socket already served");
|
|
291
|
+
b.served = true;
|
|
292
|
+
let disposeAbort = noop;
|
|
293
|
+
if (opts.signal !== void 0) if (opts.signal.aborted) b.sock.close();
|
|
294
|
+
else disposeAbort = abortListener(opts.signal, () => b.sock.close());
|
|
295
|
+
try {
|
|
296
|
+
const err = await b.sock.pump(server, {
|
|
297
|
+
peer: b.key,
|
|
298
|
+
reliable: true
|
|
299
|
+
});
|
|
300
|
+
server.disconnectPeer(b.key, err);
|
|
301
|
+
return err;
|
|
302
|
+
} finally {
|
|
303
|
+
disposeAbort();
|
|
304
|
+
this.drop(ws, b);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
handle(f, ctx = {}) {
|
|
308
|
+
const key = ctx.peer;
|
|
309
|
+
if (typeof key !== "number") return Promise.reject(/* @__PURE__ */ new Error(`websocket: no gateway peer in context (got ${String(key)})`));
|
|
310
|
+
const sock = this.peers.get(key);
|
|
311
|
+
if (sock === void 0) return Promise.reject(/* @__PURE__ */ new Error(`websocket: peer ${key} is disconnected`));
|
|
312
|
+
return sock.send([f], ctx.signal);
|
|
313
|
+
}
|
|
314
|
+
close() {
|
|
315
|
+
for (const b of [...this.socks.values()]) b.sock.close();
|
|
316
|
+
}
|
|
317
|
+
};
|
|
318
|
+
function dialWebSocket(url, opts = {}) {
|
|
319
|
+
const ctor = globalThis.WebSocket;
|
|
320
|
+
if (ctor === void 0) throw new Error("websocket: this runtime has no global WebSocket; construct one (e.g. from the 'ws' package) and pass it to new WebSocketTransport()");
|
|
321
|
+
return new Conn(new WebSocketTransport(new ctor(url, opts.protocols), opts), opts);
|
|
322
|
+
}
|
|
323
|
+
//#endregion
|
|
324
|
+
export { DefaultKeepaliveIntervalMs, DefaultKeepaliveTimeoutMs, DefaultMaxBufferedAmount, DefaultMaxMessageSize, WebSocketGateway, WebSocketTransport, dialWebSocket };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
//#region src/wasm/worker.d.ts
|
|
2
|
+
interface WorkerScope {
|
|
3
|
+
addEventListener(type: string, fn: (ev: unknown) => void): void;
|
|
4
|
+
postMessage(message: unknown): void;
|
|
5
|
+
}
|
|
6
|
+
declare function serveIn(scope: WorkerScope): void;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { WorkerScope, serveIn };
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { o as startInstance, t as isPageMessage } from "../protocol-K4Zy8MuQ.mjs";
|
|
2
|
+
//#region src/wasm/worker.ts
|
|
3
|
+
const GOODBYE = /* @__PURE__ */ new Uint8Array(0);
|
|
4
|
+
function serveIn(scope) {
|
|
5
|
+
const ports = /* @__PURE__ */ new Set();
|
|
6
|
+
let instance;
|
|
7
|
+
let gone = false;
|
|
8
|
+
const bury = () => {
|
|
9
|
+
gone = true;
|
|
10
|
+
for (const port of ports) farewell(port);
|
|
11
|
+
ports.clear();
|
|
12
|
+
};
|
|
13
|
+
scope.addEventListener("message", (ev) => {
|
|
14
|
+
const msg = ev.data;
|
|
15
|
+
if (!isPageMessage(msg)) return;
|
|
16
|
+
if (msg.drpc === "start") {
|
|
17
|
+
if (instance !== void 0) return;
|
|
18
|
+
instance = startInstance(msg.app, {
|
|
19
|
+
entryPoint: msg.entryPoint,
|
|
20
|
+
readyTimeoutMs: msg.readyTimeoutMs,
|
|
21
|
+
wasmExec: msg.wasmExec
|
|
22
|
+
});
|
|
23
|
+
instance.then((inst) => {
|
|
24
|
+
scope.postMessage({ drpc: "ready" });
|
|
25
|
+
inst.exited.then((cause) => {
|
|
26
|
+
bury();
|
|
27
|
+
scope.postMessage({
|
|
28
|
+
drpc: "exited",
|
|
29
|
+
message: reason(cause)
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
}, (e) => {
|
|
33
|
+
bury();
|
|
34
|
+
scope.postMessage({
|
|
35
|
+
drpc: "error",
|
|
36
|
+
message: reason(e)
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const port = ev.ports?.[0];
|
|
42
|
+
if (port === void 0) return;
|
|
43
|
+
if (gone || instance === void 0) {
|
|
44
|
+
farewell(port);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
ports.add(port);
|
|
48
|
+
instance.then((inst) => {
|
|
49
|
+
try {
|
|
50
|
+
inst.serve(port);
|
|
51
|
+
} catch {
|
|
52
|
+
ports.delete(port);
|
|
53
|
+
farewell(port);
|
|
54
|
+
}
|
|
55
|
+
}, () => {});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
function farewell(port) {
|
|
59
|
+
try {
|
|
60
|
+
port.postMessage(GOODBYE);
|
|
61
|
+
} catch {}
|
|
62
|
+
try {
|
|
63
|
+
port.close();
|
|
64
|
+
} catch {}
|
|
65
|
+
}
|
|
66
|
+
function reason(cause) {
|
|
67
|
+
if (cause instanceof Error && cause.message !== "") return cause.message;
|
|
68
|
+
return String(cause);
|
|
69
|
+
}
|
|
70
|
+
const g = globalThis;
|
|
71
|
+
if (g.self === g && g.document === void 0 && typeof g.postMessage === "function") serveIn(g);
|
|
72
|
+
//#endregion
|
|
73
|
+
export { serveIn };
|
package/dist/wasm.d.mts
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { n as Conn, r as ConnOptions } from "./conn-DTWG9vIx.mjs";
|
|
2
|
+
import { PortOptions } from "./transport/port.mjs";
|
|
3
|
+
//#region src/wasm/instance.d.ts
|
|
4
|
+
declare const DefaultEntryPoint = "drpcServe";
|
|
5
|
+
declare const DefaultReadyTimeoutMs = 10000;
|
|
6
|
+
declare const DefaultWasmExec = "/wasm_exec.js";
|
|
7
|
+
interface GoLike {
|
|
8
|
+
readonly importObject: WebAssembly.Imports;
|
|
9
|
+
run(instance: WebAssembly.Instance): Promise<void>;
|
|
10
|
+
}
|
|
11
|
+
type WasmApp = string | URL | BufferSource | WebAssembly.Module;
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/wasm/index.d.ts
|
|
14
|
+
interface WasmWorker {
|
|
15
|
+
postMessage(message: unknown, transfer?: unknown[]): void;
|
|
16
|
+
addEventListener(type: string, fn: (ev: unknown) => void): void;
|
|
17
|
+
removeEventListener(type: string, fn: (ev: unknown) => void): void;
|
|
18
|
+
terminate(): void;
|
|
19
|
+
}
|
|
20
|
+
interface OpenOptions extends PortOptions {
|
|
21
|
+
worker?: boolean | WasmWorker;
|
|
22
|
+
workerUrl?: string | URL;
|
|
23
|
+
wasmExec?: string | URL;
|
|
24
|
+
entryPoint?: string;
|
|
25
|
+
readyTimeoutMs?: number;
|
|
26
|
+
go?: GoLike;
|
|
27
|
+
}
|
|
28
|
+
interface WasmSock {
|
|
29
|
+
readonly worker?: WasmWorker;
|
|
30
|
+
readonly exited: Promise<unknown>;
|
|
31
|
+
dial(opts?: ConnOptions): Conn;
|
|
32
|
+
close(): void;
|
|
33
|
+
}
|
|
34
|
+
declare function open(app: WasmApp, opts?: OpenOptions): Promise<WasmSock>;
|
|
35
|
+
//#endregion
|
|
36
|
+
export { DefaultEntryPoint, DefaultReadyTimeoutMs, DefaultWasmExec, type GoLike, OpenOptions, type WasmApp, WasmSock, WasmWorker, open };
|
package/dist/wasm.mjs
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { n as Conn } from "./conn-DOmx4nbt.mjs";
|
|
2
|
+
import { PortTransport } from "./transport/port.mjs";
|
|
3
|
+
import { a as DefaultWasmExec, i as DefaultReadyTimeoutMs, n as isWorkerMessage, o as startInstance, r as DefaultEntryPoint } from "./protocol-K4Zy8MuQ.mjs";
|
|
4
|
+
//#region src/wasm/index.ts
|
|
5
|
+
async function open(app, opts = {}) {
|
|
6
|
+
if (opts.worker === false) return new HereSock(await startInstance(app, opts), opts);
|
|
7
|
+
if (opts.go !== void 0) throw new Error("wasm: opts.go builds the Go instance in this realm, and it cannot be posted to a worker — pass { worker: false } with it, or drop it");
|
|
8
|
+
const given = typeof opts.worker === "object" && opts.worker !== null ? opts.worker : void 0;
|
|
9
|
+
const sock = new WorkerSock(given ?? spawn(opts.workerUrl), given === void 0, opts);
|
|
10
|
+
try {
|
|
11
|
+
await sock.start(app, opts);
|
|
12
|
+
} catch (e) {
|
|
13
|
+
sock.close();
|
|
14
|
+
throw e;
|
|
15
|
+
}
|
|
16
|
+
return sock;
|
|
17
|
+
}
|
|
18
|
+
function spawn(url) {
|
|
19
|
+
const ctor = globalThis.Worker;
|
|
20
|
+
if (typeof ctor !== "function") throw new Error("wasm: this realm has no Worker — pass { worker: false } to run the instance here (node, tests), or a worker you made yourself");
|
|
21
|
+
return new ctor(url ?? new URL("./wasm/worker.mjs", import.meta.url), { type: "module" });
|
|
22
|
+
}
|
|
23
|
+
var Sock = class {
|
|
24
|
+
o;
|
|
25
|
+
exited;
|
|
26
|
+
txs = /* @__PURE__ */ new Set();
|
|
27
|
+
dead;
|
|
28
|
+
closed = false;
|
|
29
|
+
announce;
|
|
30
|
+
constructor(o) {
|
|
31
|
+
this.o = o;
|
|
32
|
+
this.exited = new Promise((res) => {
|
|
33
|
+
this.announce = res;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
dial(opts = {}) {
|
|
37
|
+
if (this.dead !== void 0) {
|
|
38
|
+
const what = this.closed ? "this sock is closed" : "the wasm instance has exited";
|
|
39
|
+
throw new Error(`wasm: ${what}${this.dead.cause instanceof Error ? `: ${this.dead.cause.message}` : ""}`);
|
|
40
|
+
}
|
|
41
|
+
const tx = this.connect();
|
|
42
|
+
this.txs.add(tx);
|
|
43
|
+
return new Conn(tx, opts);
|
|
44
|
+
}
|
|
45
|
+
close() {
|
|
46
|
+
if (this.closed) return;
|
|
47
|
+
this.closed = true;
|
|
48
|
+
this.bury(/* @__PURE__ */ new Error("the wasm sock was closed"));
|
|
49
|
+
this.stop();
|
|
50
|
+
}
|
|
51
|
+
channelTo(handover) {
|
|
52
|
+
const ch = new MessageChannel();
|
|
53
|
+
let tx;
|
|
54
|
+
try {
|
|
55
|
+
tx = new PortTransport(ch.port1, this.o);
|
|
56
|
+
handover(ch.port2);
|
|
57
|
+
return tx;
|
|
58
|
+
} catch (e) {
|
|
59
|
+
tx?.close(e);
|
|
60
|
+
ch.port1.close();
|
|
61
|
+
ch.port2.close();
|
|
62
|
+
throw e;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
bury(cause) {
|
|
66
|
+
if (this.dead !== void 0) return;
|
|
67
|
+
this.dead = { cause };
|
|
68
|
+
for (const tx of this.txs) tx.close(cause);
|
|
69
|
+
this.txs.clear();
|
|
70
|
+
this.announce(cause);
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
var WorkerSock = class extends Sock {
|
|
74
|
+
worker;
|
|
75
|
+
own;
|
|
76
|
+
readiness;
|
|
77
|
+
ready;
|
|
78
|
+
failed;
|
|
79
|
+
detach = [];
|
|
80
|
+
serving = false;
|
|
81
|
+
constructor(worker, own, o) {
|
|
82
|
+
super(o);
|
|
83
|
+
this.worker = worker;
|
|
84
|
+
this.own = own;
|
|
85
|
+
this.readiness = new Promise((res, rej) => {
|
|
86
|
+
this.ready = res;
|
|
87
|
+
this.failed = rej;
|
|
88
|
+
});
|
|
89
|
+
this.listen("message", (ev) => this.onMessage(ev));
|
|
90
|
+
this.listen("error", (ev) => {
|
|
91
|
+
if (this.serving) return;
|
|
92
|
+
const detail = ev.message;
|
|
93
|
+
this.die(/* @__PURE__ */ new Error(`wasm: the worker itself failed${typeof detail === "string" && detail !== "" ? `: ${detail}` : ""} — is workerUrl the module this package ships?`));
|
|
94
|
+
});
|
|
95
|
+
this.listen("messageerror", () => {});
|
|
96
|
+
}
|
|
97
|
+
start(app, opts) {
|
|
98
|
+
const start = {
|
|
99
|
+
drpc: "start",
|
|
100
|
+
app,
|
|
101
|
+
wasmExec: String(opts.wasmExec ?? "/wasm_exec.js"),
|
|
102
|
+
entryPoint: opts.entryPoint ?? "drpcServe",
|
|
103
|
+
readyTimeoutMs: opts.readyTimeoutMs ?? 1e4
|
|
104
|
+
};
|
|
105
|
+
this.worker.postMessage(start);
|
|
106
|
+
return this.readiness;
|
|
107
|
+
}
|
|
108
|
+
connect() {
|
|
109
|
+
const serve = { drpc: "serve" };
|
|
110
|
+
return this.channelTo((port) => this.worker.postMessage(serve, [port]));
|
|
111
|
+
}
|
|
112
|
+
stop() {
|
|
113
|
+
if (this.own) this.worker.terminate();
|
|
114
|
+
for (const off of this.detach.splice(0)) off();
|
|
115
|
+
}
|
|
116
|
+
listen(type, fn) {
|
|
117
|
+
this.worker.addEventListener(type, fn);
|
|
118
|
+
this.detach.push(() => this.worker.removeEventListener(type, fn));
|
|
119
|
+
}
|
|
120
|
+
onMessage(ev) {
|
|
121
|
+
const msg = ev.data;
|
|
122
|
+
if (!isWorkerMessage(msg)) return;
|
|
123
|
+
switch (msg.drpc) {
|
|
124
|
+
case "ready":
|
|
125
|
+
this.serving = true;
|
|
126
|
+
this.ready();
|
|
127
|
+
break;
|
|
128
|
+
case "error":
|
|
129
|
+
this.failed(/* @__PURE__ */ new Error(`wasm: ${msg.message}`));
|
|
130
|
+
break;
|
|
131
|
+
case "exited":
|
|
132
|
+
this.die(new Error(msg.message));
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
die(cause) {
|
|
137
|
+
this.failed(cause);
|
|
138
|
+
this.bury(cause);
|
|
139
|
+
for (const off of this.detach.splice(0)) off();
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
var HereSock = class extends Sock {
|
|
143
|
+
inst;
|
|
144
|
+
worker = void 0;
|
|
145
|
+
constructor(inst, o) {
|
|
146
|
+
super(o);
|
|
147
|
+
this.inst = inst;
|
|
148
|
+
inst.exited.then((cause) => this.bury(cause));
|
|
149
|
+
}
|
|
150
|
+
connect() {
|
|
151
|
+
return this.channelTo((port) => this.inst.serve(port));
|
|
152
|
+
}
|
|
153
|
+
stop() {}
|
|
154
|
+
};
|
|
155
|
+
//#endregion
|
|
156
|
+
export { DefaultEntryPoint, DefaultReadyTimeoutMs, DefaultWasmExec, open };
|