toiljs 0.0.68 → 0.0.70

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 (62) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/build/cli/.tsbuildinfo +1 -1
  3. package/build/client/.tsbuildinfo +1 -1
  4. package/build/client/rpc.js +10 -4
  5. package/build/client/stream/client.js +108 -5
  6. package/build/compiler/.tsbuildinfo +1 -1
  7. package/build/compiler/index.d.ts +2 -0
  8. package/build/compiler/index.js +282 -2
  9. package/build/compiler/toil-docs.generated.js +3 -2
  10. package/build/compiler/vite.js +8 -0
  11. package/build/devserver/.tsbuildinfo +1 -1
  12. package/build/devserver/daemon/host.d.ts +1 -7
  13. package/build/devserver/daemon/host.js +5 -59
  14. package/build/devserver/daemon/index.d.ts +1 -0
  15. package/build/devserver/daemon/index.js +17 -4
  16. package/build/devserver/db/database.js +1 -1
  17. package/build/devserver/db/routeKinds.d.ts +6 -0
  18. package/build/devserver/db/routeKinds.js +40 -0
  19. package/build/devserver/index.d.ts +0 -1
  20. package/build/devserver/index.js +0 -1
  21. package/build/devserver/runtime/module.d.ts +1 -0
  22. package/build/devserver/runtime/module.js +18 -2
  23. package/build/devserver/stream/index.js +4 -3
  24. package/build/devserver/wasm/surface.d.ts +2 -0
  25. package/build/devserver/wasm/surface.js +35 -4
  26. package/docs/derive.md +159 -0
  27. package/docs/index.md +1 -1
  28. package/docs/streams.md +49 -18
  29. package/examples/basic/server/services/Stats.ts +11 -3
  30. package/examples/basic/server/services/remotes.ts +8 -2
  31. package/package.json +3 -2
  32. package/server/runtime/exports/index.ts +8 -1
  33. package/server/runtime/index.ts +1 -0
  34. package/server/runtime/rpc/Rpc.ts +66 -0
  35. package/src/client/rpc.ts +21 -12
  36. package/src/client/stream/client.ts +138 -8
  37. package/src/compiler/index.ts +352 -2
  38. package/src/compiler/toil-docs.generated.ts +3 -2
  39. package/src/compiler/vite.ts +16 -0
  40. package/src/devserver/daemon/host.ts +10 -110
  41. package/src/devserver/daemon/index.ts +19 -6
  42. package/src/devserver/db/database.ts +1 -1
  43. package/src/devserver/db/routeKinds.ts +44 -0
  44. package/src/devserver/index.ts +0 -1
  45. package/src/devserver/runtime/host.ts +3 -7
  46. package/src/devserver/runtime/module.ts +30 -4
  47. package/src/devserver/stream/index.ts +8 -4
  48. package/src/devserver/wasm/surface.ts +33 -4
  49. package/test/daemon-build.test.ts +53 -0
  50. package/test/daemon-catalog.test.ts +78 -3
  51. package/test/daemon-emulation.test.ts +27 -29
  52. package/test/devserver-database.test.ts +93 -0
  53. package/test/fixtures/bignum-wire/spec.ts +3 -5
  54. package/test/fixtures/daemon-app.ts +25 -21
  55. package/test/fixtures/stream-typed.ts +41 -0
  56. package/test/rpc-dispatch.test.ts +132 -0
  57. package/test/rpc-kinds.test.ts +18 -0
  58. package/test/rpc.test.ts +20 -4
  59. package/test/stream-emulation.test.ts +39 -0
  60. package/build/devserver/mstore/store.d.ts +0 -18
  61. package/build/devserver/mstore/store.js +0 -82
  62. package/src/devserver/mstore/store.ts +0 -121
@@ -1,7 +1,7 @@
1
1
  function restMissingStub(path) {
2
2
  const call = () => {
3
3
  throw new Error(`toiljs REST: ${path}() is unavailable. The generated REST client has not loaded - ` +
4
- `import a type from your 'shared/server' (so the client attaches), or run 'npm run build:server'.`);
4
+ `run 'npm run build:server' to generate shared/server.ts; the client then attaches automatically.`);
5
5
  };
6
6
  return new Proxy(call, {
7
7
  get(_target, prop) {
@@ -17,7 +17,7 @@ function restMissingStub(path) {
17
17
  function streamMissingStub(path) {
18
18
  const call = () => {
19
19
  throw new Error(`toiljs Stream: ${path}() is unavailable. The generated stream client has not loaded - ` +
20
- `import a type from your 'shared/server' (so the client attaches), or run 'npm run build:server'.`);
20
+ `run 'npm run build:server' to generate shared/server.ts; the client then attaches automatically.`);
21
21
  };
22
22
  return new Proxy(call, {
23
23
  get(_target, prop) {
@@ -32,8 +32,8 @@ function streamMissingStub(path) {
32
32
  }
33
33
  function rpcStub(path) {
34
34
  const call = () => {
35
- throw new Error(`toiljs RPC: ${path}() is not available yet. The client<->server transport ` +
36
- `is not wired; this is a generated stub. Remote calls will work once transport lands.`);
35
+ throw new Error(`toiljs RPC: ${path}() is unavailable. The generated RPC client has not loaded - ` +
36
+ `run 'npm run build:server' to generate shared/server.ts; the client then attaches automatically.`);
37
37
  };
38
38
  return new Proxy(call, {
39
39
  get(_target, prop) {
@@ -47,6 +47,11 @@ function rpcStub(path) {
47
47
  const stream = globalThis.__toilStream;
48
48
  return stream !== undefined ? stream : streamMissingStub('Server.Stream');
49
49
  }
50
+ if (path === 'Server') {
51
+ const rpc = globalThis.__toilRpc;
52
+ if (rpc !== undefined && prop in rpc)
53
+ return rpc[prop];
54
+ }
50
55
  return rpcStub(`${path}.${prop}`);
51
56
  },
52
57
  apply() {
@@ -55,3 +60,4 @@ function rpcStub(path) {
55
60
  });
56
61
  }
57
62
  export const Server = rpcStub('Server');
63
+ globalThis.Server = Server;
@@ -5,9 +5,13 @@ function connectStream(url, encode) {
5
5
  let opened = false;
6
6
  let messageCb;
7
7
  let closeCb;
8
+ const pending = [];
8
9
  const channel = {
9
10
  onMessage: (cb) => {
10
11
  messageCb = cb;
12
+ for (const m of pending)
13
+ cb(m);
14
+ pending.length = 0;
11
15
  },
12
16
  onClose: (cb) => {
13
17
  closeCb = cb;
@@ -16,7 +20,11 @@ function connectStream(url, encode) {
16
20
  if (ws.readyState !== WebSocket.OPEN)
17
21
  return;
18
22
  const bytes = encode ? encode(data) : data;
19
- ws.send(bytes);
23
+ try {
24
+ ws.send(bytes);
25
+ }
26
+ catch {
27
+ }
20
28
  },
21
29
  close: () => {
22
30
  ws.close();
@@ -27,8 +35,13 @@ function connectStream(url, encode) {
27
35
  resolve(channel);
28
36
  });
29
37
  ws.addEventListener('message', (event) => {
30
- if (event.data instanceof ArrayBuffer)
31
- messageCb?.(new Uint8Array(event.data));
38
+ if (!(event.data instanceof ArrayBuffer))
39
+ return;
40
+ const bytes = new Uint8Array(event.data);
41
+ if (messageCb)
42
+ messageCb(bytes);
43
+ else
44
+ pending.push(bytes);
32
45
  });
33
46
  ws.addEventListener('close', (event) => {
34
47
  if (!opened)
@@ -42,17 +55,107 @@ function connectStream(url, encode) {
42
55
  });
43
56
  });
44
57
  }
58
+ function connectStreamWT(url, encode) {
59
+ return new Promise((resolve, reject) => {
60
+ if (!('WebTransport' in globalThis)) {
61
+ reject(new Error('WebTransport is not available in this browser'));
62
+ return;
63
+ }
64
+ let transport;
65
+ try {
66
+ transport = new WebTransport(url);
67
+ }
68
+ catch (e) {
69
+ reject(e instanceof Error ? e : new Error(String(e)));
70
+ return;
71
+ }
72
+ let messageCb;
73
+ let closeCb;
74
+ let writer;
75
+ let opened = false;
76
+ const pending = [];
77
+ const channel = {
78
+ onMessage: (cb) => {
79
+ messageCb = cb;
80
+ for (const m of pending)
81
+ cb(m);
82
+ pending.length = 0;
83
+ },
84
+ onClose: (cb) => {
85
+ closeCb = cb;
86
+ },
87
+ send: (data) => {
88
+ if (!writer)
89
+ return;
90
+ const bytes = encode ? encode(data) : data;
91
+ void writer.write(bytes).catch(() => { });
92
+ },
93
+ close: () => {
94
+ try {
95
+ transport.close();
96
+ }
97
+ catch {
98
+ }
99
+ },
100
+ };
101
+ transport.closed
102
+ .then((info) => {
103
+ if (opened)
104
+ closeCb?.(info?.closeCode ?? 0);
105
+ })
106
+ .catch(() => {
107
+ if (opened)
108
+ closeCb?.(1);
109
+ });
110
+ transport.ready
111
+ .then(() => {
112
+ opened = true;
113
+ writer = transport.datagrams.writable.getWriter();
114
+ const reader = transport.datagrams.readable.getReader();
115
+ void (async () => {
116
+ try {
117
+ for (;;) {
118
+ const { value, done } = await reader.read();
119
+ if (done)
120
+ break;
121
+ const bytes = value instanceof Uint8Array
122
+ ? value
123
+ : new Uint8Array(value);
124
+ if (messageCb)
125
+ messageCb(bytes);
126
+ else
127
+ pending.push(bytes);
128
+ }
129
+ }
130
+ catch {
131
+ }
132
+ })();
133
+ resolve(channel);
134
+ })
135
+ .catch((e) => reject(e instanceof Error ? e : new Error(String(e))));
136
+ });
137
+ }
138
+ function openChannel(url, encode) {
139
+ return url.startsWith('https://')
140
+ ? connectStreamWT(url, encode)
141
+ : connectStream(url, encode);
142
+ }
45
143
  function defaultOrigin() {
46
144
  const loc = globalThis.location;
47
145
  return `${loc.protocol === 'https:' ? 'wss:' : 'ws:'}//${loc.host}`;
48
146
  }
147
+ function resolveStreamOrigin() {
148
+ const override = globalThis.__TOIL_STREAM_ORIGIN__;
149
+ if (typeof override === 'string' && override.length > 0)
150
+ return override;
151
+ return defaultOrigin();
152
+ }
49
153
  export function makeStreamClient(routes, origin, encoders) {
50
- const base = origin ?? defaultOrigin();
51
154
  const client = {};
52
155
  for (const [name, route] of Object.entries(routes)) {
53
156
  const encode = encoders?.[name];
54
157
  client[name] = {
55
- connect: (path = '') => connectStream(`${base}${route}${path}`, encode),
158
+ connect: (path = '') => openChannel(`${origin ?? resolveStreamOrigin()}${route}${path}`, encode),
56
159
  };
57
160
  }
58
161
  return client;