@nmtjs/protocol 0.6.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.
Files changed (67) hide show
  1. package/LICENSE.md +7 -0
  2. package/README.md +9 -0
  3. package/dist/client/events.js +41 -0
  4. package/dist/client/events.js.map +1 -0
  5. package/dist/client/format.js +2 -0
  6. package/dist/client/format.js.map +1 -0
  7. package/dist/client/index.js +4 -0
  8. package/dist/client/index.js.map +1 -0
  9. package/dist/client/protocol.js +311 -0
  10. package/dist/client/protocol.js.map +1 -0
  11. package/dist/client/stream.js +99 -0
  12. package/dist/client/stream.js.map +1 -0
  13. package/dist/common/binary.js +25 -0
  14. package/dist/common/binary.js.map +1 -0
  15. package/dist/common/blob.js +42 -0
  16. package/dist/common/blob.js.map +1 -0
  17. package/dist/common/enums.js +44 -0
  18. package/dist/common/enums.js.map +1 -0
  19. package/dist/common/index.js +4 -0
  20. package/dist/common/index.js.map +1 -0
  21. package/dist/common/types.js +1 -0
  22. package/dist/common/types.js.map +1 -0
  23. package/dist/server/api.js +1 -0
  24. package/dist/server/api.js.map +1 -0
  25. package/dist/server/connection.js +21 -0
  26. package/dist/server/connection.js.map +1 -0
  27. package/dist/server/constants.js +1 -0
  28. package/dist/server/constants.js.map +1 -0
  29. package/dist/server/format.js +48 -0
  30. package/dist/server/format.js.map +1 -0
  31. package/dist/server/index.js +10 -0
  32. package/dist/server/index.js.map +1 -0
  33. package/dist/server/injectables.js +22 -0
  34. package/dist/server/injectables.js.map +1 -0
  35. package/dist/server/protocol.js +293 -0
  36. package/dist/server/protocol.js.map +1 -0
  37. package/dist/server/registry.js +19 -0
  38. package/dist/server/registry.js.map +1 -0
  39. package/dist/server/stream.js +30 -0
  40. package/dist/server/stream.js.map +1 -0
  41. package/dist/server/transport.js +7 -0
  42. package/dist/server/transport.js.map +1 -0
  43. package/dist/server/utils.js +10 -0
  44. package/dist/server/utils.js.map +1 -0
  45. package/lib/client/events.ts +66 -0
  46. package/lib/client/format.ts +22 -0
  47. package/lib/client/index.ts +4 -0
  48. package/lib/client/protocol.ts +440 -0
  49. package/lib/client/stream.ts +116 -0
  50. package/lib/common/binary.ts +60 -0
  51. package/lib/common/blob.ts +70 -0
  52. package/lib/common/enums.ts +46 -0
  53. package/lib/common/index.ts +4 -0
  54. package/lib/common/types.ts +64 -0
  55. package/lib/server/api.ts +47 -0
  56. package/lib/server/connection.ts +57 -0
  57. package/lib/server/constants.ts +4 -0
  58. package/lib/server/format.ts +107 -0
  59. package/lib/server/index.ts +10 -0
  60. package/lib/server/injectables.ts +51 -0
  61. package/lib/server/protocol.ts +422 -0
  62. package/lib/server/registry.ts +24 -0
  63. package/lib/server/stream.ts +43 -0
  64. package/lib/server/transport.ts +36 -0
  65. package/lib/server/utils.ts +22 -0
  66. package/package.json +39 -0
  67. package/tsconfig.json +3 -0
package/LICENSE.md ADDED
@@ -0,0 +1,7 @@
1
+ Copyright (c) 2024 Denis Ilchyshyn
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ # NeemataJS - RPC application server for real-time applications (proof of concept)
2
+
3
+ ### Built with following in mind:
4
+ - transport-agnostic (like WebSockets, WebTransport, .etc)
5
+ - format-agnostic (like JSON, MessagePack, BSON, .etc)
6
+ - binary data streaming and event subscriptions
7
+ - contract-based API
8
+ - end-to-end type safety
9
+ - CPU-intensive task execution on separate workers
@@ -0,0 +1,41 @@
1
+ export function untilAborted(signal) {
2
+ return new Promise((_, reject)=>{
3
+ const handler = ()=>reject(new Error('aborted'));
4
+ const options = {
5
+ once: true
6
+ };
7
+ signal.addEventListener('abort', handler, options);
8
+ });
9
+ }
10
+ export function onAbort(signal, listener) {
11
+ signal.addEventListener('abort', listener, {
12
+ once: true
13
+ });
14
+ return ()=>signal.removeEventListener('abort', listener);
15
+ }
16
+ export class EventEmitter {
17
+ #target = new EventTarget();
18
+ #listeners = new Map();
19
+ on(event, listener, options) {
20
+ const wrapper = (event)=>listener(...event.detail);
21
+ this.#listeners.set(listener, wrapper);
22
+ this.#target.addEventListener(event, wrapper, options);
23
+ return ()=>this.#target.removeEventListener(event, wrapper);
24
+ }
25
+ once(event, listener, options) {
26
+ return this.on(event, listener, {
27
+ ...options,
28
+ once: true
29
+ });
30
+ }
31
+ off(event, listener) {
32
+ const wrapper = this.#listeners.get(listener);
33
+ if (wrapper) this.#target.removeEventListener(event, wrapper);
34
+ }
35
+ emit(event, ...args) {
36
+ return this.#target.dispatchEvent(new CustomEvent(event, {
37
+ detail: args
38
+ }));
39
+ }
40
+ }
41
+ export const once = (ee, event)=>new Promise((resolve)=>ee.once(event, resolve));
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../lib/client/events.ts"],"sourcesContent":["import type { Callback } from '@nmtjs/common'\n\nexport type EventMap = { [K: string]: any[] }\n\nexport function untilAborted(signal: AbortSignal) {\n return new Promise((_, reject) => {\n const handler = () => reject(new Error('aborted'))\n const options = { once: true }\n signal.addEventListener('abort', handler, options)\n })\n}\n\nexport function onAbort(signal: AbortSignal, listener: () => void) {\n signal.addEventListener('abort', listener, { once: true })\n return () => signal.removeEventListener('abort', listener)\n}\n\n/**\n * Very simple node-like event emitter wrapper around EventTarget\n *\n * @todo add errors and promise rejections handling\n */\nexport class EventEmitter<\n Events extends EventMap = EventMap,\n EventNames extends Extract<keyof Events, string> = Extract<\n keyof Events,\n string\n >,\n> {\n #target = new EventTarget()\n #listeners = new Map<Callback, Callback>()\n\n on<E extends EventNames>(\n event: E | (Object & string),\n listener: (...args: Events[E]) => void,\n options?: AddEventListenerOptions,\n ) {\n const wrapper = (event) => listener(...event.detail)\n this.#listeners.set(listener, wrapper)\n this.#target.addEventListener(event, wrapper, options)\n return () => this.#target.removeEventListener(event, wrapper)\n }\n\n once<E extends EventNames>(\n event: E | (Object & string),\n listener: (...args: Events[E]) => void,\n options?: AddEventListenerOptions,\n ) {\n return this.on(event, listener, { ...options, once: true })\n }\n\n off(event: EventNames | (Object & string), listener: Callback) {\n const wrapper = this.#listeners.get(listener)\n if (wrapper) this.#target.removeEventListener(event, wrapper)\n }\n\n emit<E extends EventNames | (Object & string)>(\n event: E,\n ...args: E extends EventEmitter ? Events[E] : any[]\n ) {\n return this.#target.dispatchEvent(new CustomEvent(event, { detail: args }))\n }\n}\n\nexport const once = (ee: EventEmitter, event: string) =>\n new Promise((resolve) => ee.once(event, resolve))\n"],"names":["untilAborted","signal","Promise","_","reject","handler","Error","options","once","addEventListener","onAbort","listener","removeEventListener","EventEmitter","EventTarget","Map","on","event","wrapper","detail","set","off","get","emit","args","dispatchEvent","CustomEvent","ee","resolve"],"mappings":"AAIA,OAAO,SAASA,aAAaC,MAAmB;IAC9C,OAAO,IAAIC,QAAQ,CAACC,GAAGC;QACrB,MAAMC,UAAU,IAAMD,OAAO,IAAIE,MAAM;QACvC,MAAMC,UAAU;YAAEC,MAAM;QAAK;QAC7BP,OAAOQ,gBAAgB,CAAC,SAASJ,SAASE;IAC5C;AACF;AAEA,OAAO,SAASG,QAAQT,MAAmB,EAAEU,QAAoB;IAC/DV,OAAOQ,gBAAgB,CAAC,SAASE,UAAU;QAAEH,MAAM;IAAK;IACxD,OAAO,IAAMP,OAAOW,mBAAmB,CAAC,SAASD;AACnD;AAOA,OAAO,MAAME;IAOX,CAAA,MAAO,GAAG,IAAIC,cAAa;IAC3B,CAAA,SAAU,GAAG,IAAIC,MAAyB;IAE1CC,GACEC,KAA4B,EAC5BN,QAAsC,EACtCJ,OAAiC,EACjC;QACA,MAAMW,UAAU,CAACD,QAAUN,YAAYM,MAAME,MAAM;QACnD,IAAI,CAAC,CAAA,SAAU,CAACC,GAAG,CAACT,UAAUO;QAC9B,IAAI,CAAC,CAAA,MAAO,CAACT,gBAAgB,CAACQ,OAAOC,SAASX;QAC9C,OAAO,IAAM,IAAI,CAAC,CAAA,MAAO,CAACK,mBAAmB,CAACK,OAAOC;IACvD;IAEAV,KACES,KAA4B,EAC5BN,QAAsC,EACtCJ,OAAiC,EACjC;QACA,OAAO,IAAI,CAACS,EAAE,CAACC,OAAON,UAAU;YAAE,GAAGJ,OAAO;YAAEC,MAAM;QAAK;IAC3D;IAEAa,IAAIJ,KAAqC,EAAEN,QAAkB,EAAE;QAC7D,MAAMO,UAAU,IAAI,CAAC,CAAA,SAAU,CAACI,GAAG,CAACX;QACpC,IAAIO,SAAS,IAAI,CAAC,CAAA,MAAO,CAACN,mBAAmB,CAACK,OAAOC;IACvD;IAEAK,KACEN,KAAQ,EACR,GAAGO,IAAgD,EACnD;QACA,OAAO,IAAI,CAAC,CAAA,MAAO,CAACC,aAAa,CAAC,IAAIC,YAAYT,OAAO;YAAEE,QAAQK;QAAK;IAC1E;AACF;AAEA,OAAO,MAAMhB,OAAO,CAACmB,IAAkBV,QACrC,IAAIf,QAAQ,CAAC0B,UAAYD,GAAGnB,IAAI,CAACS,OAAOW,UAAS"}
@@ -0,0 +1,2 @@
1
+ export class BaseClientFormat {
2
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../lib/client/format.ts"],"sourcesContent":["import type {\n BaseClientDecoder,\n BaseClientEncoder,\n DecodeRPCContext,\n EncodeRPCContext,\n ProtocolRPC,\n ProtocolRPCResponse,\n} from '../common/types.ts'\n\nexport abstract class BaseClientFormat\n implements BaseClientDecoder, BaseClientEncoder\n{\n abstract contentType: string\n\n abstract encode(data: any): ArrayBuffer\n abstract encodeRPC(rpc: ProtocolRPC, context: EncodeRPCContext): ArrayBuffer\n abstract decode(buffer: ArrayBuffer): any\n abstract decodeRPC(\n buffer: ArrayBuffer,\n context: DecodeRPCContext,\n ): ProtocolRPCResponse\n}\n"],"names":["BaseClientFormat"],"mappings":"AASA,OAAO,MAAeA;AAYtB"}
@@ -0,0 +1,4 @@
1
+ export * from "./protocol.js";
2
+ export * from "./events.js";
3
+ export * from "./stream.js";
4
+ export * from "./format.js";
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../lib/client/index.ts"],"sourcesContent":["export * from './protocol.ts'\nexport * from './events.ts'\nexport * from './stream.ts'\nexport * from './format.ts'\n"],"names":[],"mappings":"AAAA,cAAc,gBAAe;AAC7B,cAAc,cAAa;AAC3B,cAAc,cAAa;AAC3B,cAAc,cAAa"}
@@ -0,0 +1,311 @@
1
+ import { createPromise } from '@nmtjs/common';
2
+ import { concat, decodeNumber, encodeNumber } from "../common/binary.js";
3
+ import { ClientMessageType, ServerMessageType } from "../common/enums.js";
4
+ import { EventEmitter } from "./events.js";
5
+ import { ProtocolClientBlobStream, ProtocolServerBlobStream, ProtocolServerStream } from "./stream.js";
6
+ export class ProtocolError extends Error {
7
+ code;
8
+ data;
9
+ constructor(code, message, data){
10
+ super(message);
11
+ this.code = code;
12
+ this.data = data;
13
+ }
14
+ get message() {
15
+ return `${this.code} ${super.message}`;
16
+ }
17
+ toString() {
18
+ return `${this.code} ${this.message}`;
19
+ }
20
+ toJSON() {
21
+ return {
22
+ code: this.code,
23
+ message: this.message,
24
+ data: this.data
25
+ };
26
+ }
27
+ }
28
+ export class ProtocolClientStreams {
29
+ #collection = new Map();
30
+ get(streamId) {
31
+ const stream = this.#collection.get(streamId);
32
+ if (!stream) throw new Error('Stream not found');
33
+ return stream;
34
+ }
35
+ add(source, streamId, metadata) {
36
+ const stream = new ProtocolClientBlobStream(source, streamId, metadata);
37
+ this.#collection.set(streamId, stream);
38
+ return stream;
39
+ }
40
+ remove(streamId) {
41
+ this.#collection.delete(streamId);
42
+ }
43
+ abort(streamId) {
44
+ const stream = this.get(streamId);
45
+ stream.abort();
46
+ this.remove(streamId);
47
+ }
48
+ pull(streamId, size) {
49
+ const stream = this.get(streamId);
50
+ return stream.read(size);
51
+ }
52
+ end(streamId) {
53
+ const stream = this.get(streamId);
54
+ stream.end();
55
+ this.remove(streamId);
56
+ }
57
+ }
58
+ export class ProtocolServerStreams {
59
+ #collection = new Map();
60
+ has(streamId) {
61
+ return this.#collection.has(streamId);
62
+ }
63
+ get(streamId) {
64
+ const stream = this.#collection.get(streamId);
65
+ if (!stream) throw new Error('Stream not found');
66
+ return stream;
67
+ }
68
+ add(streamId, stream) {
69
+ this.#collection.set(streamId, stream);
70
+ return stream;
71
+ }
72
+ remove(streamId) {
73
+ this.#collection.delete(streamId);
74
+ }
75
+ abort(streamId) {
76
+ if (this.has(streamId)) {
77
+ const stream = this.get(streamId);
78
+ stream.abort();
79
+ this.remove(streamId);
80
+ }
81
+ }
82
+ async push(streamId, chunk) {
83
+ const stream = this.get(streamId);
84
+ return await stream.push(chunk);
85
+ }
86
+ end(streamId) {
87
+ const stream = this.get(streamId);
88
+ stream.end();
89
+ this.remove(streamId);
90
+ }
91
+ }
92
+ export class ProtocolBaseTransformer {
93
+ encodeRPC(namespace, procedure, payload) {
94
+ return payload;
95
+ }
96
+ decodeRPC(namespace, procedure, payload) {
97
+ return payload;
98
+ }
99
+ decodeRPCChunk(namespace, procedure, payload) {
100
+ return payload;
101
+ }
102
+ decodeEvent(namespace, event, payload) {
103
+ return payload;
104
+ }
105
+ }
106
+ export class ProtocolBaseClient extends EventEmitter {
107
+ transport;
108
+ format;
109
+ transformer;
110
+ #clientStreams;
111
+ #serverStreams;
112
+ #serverRPCStreams;
113
+ #serverRPCStreamCalls;
114
+ #calls;
115
+ #callId;
116
+ #streamId;
117
+ constructor(transport, format, transformer = new ProtocolBaseTransformer()){
118
+ super();
119
+ this.transport = transport;
120
+ this.format = format;
121
+ this.transformer = transformer;
122
+ this.#serverRPCStreamCalls = new Map();
123
+ this.#calls = new Map();
124
+ this.#callId = 0;
125
+ this.#streamId = 0;
126
+ this.#clientStreams = new ProtocolClientStreams();
127
+ this.#serverStreams = new ProtocolServerStreams();
128
+ this.#serverRPCStreams = new ProtocolServerStreams();
129
+ this.transport.on(`${ServerMessageType.Event}`, (buffer)=>{
130
+ const [namespace, event, payload] = this.format.decode(buffer);
131
+ const name = `${namespace}/${event}`;
132
+ const transformed = this.transformer.decodeEvent(namespace, event, payload);
133
+ this.emit(name, transformed);
134
+ });
135
+ this.transport.on(`${ServerMessageType.RpcResponse}`, (buffer)=>{
136
+ const { call, error, payload } = this.#handleResponse(buffer);
137
+ if (error) call.reject(error);
138
+ else call.resolve(payload);
139
+ });
140
+ this.transport.on(`${ServerMessageType.RpcStreamResponse}`, (buffer)=>{
141
+ const { call, response, payload, error } = this.#handleResponse(buffer);
142
+ if (error) return call.reject(error);
143
+ console.log('Creating RPC stream', response);
144
+ const stream = new ProtocolServerStream();
145
+ this.#serverRPCStreams.add(response.callId, stream);
146
+ this.#serverRPCStreamCalls.set(response.callId, {
147
+ namespace: call.namespace,
148
+ procedure: call.procedure
149
+ });
150
+ call.resolve([
151
+ payload,
152
+ stream
153
+ ]);
154
+ });
155
+ this.transport.on(`${ServerMessageType.RpcStreamChunk}`, async (buffer)=>{
156
+ const callId = decodeNumber(buffer, 'Uint32');
157
+ console.log('RPC stream chunk', callId);
158
+ const chunk = buffer.slice(Uint32Array.BYTES_PER_ELEMENT);
159
+ if (chunk.byteLength === 0) {
160
+ this.#serverRPCStreams.end(callId);
161
+ this.#serverRPCStreamCalls.delete(callId);
162
+ } else {
163
+ const call = this.#serverRPCStreamCalls.get(callId);
164
+ console.log('RPC stream call', call);
165
+ if (call) {
166
+ const payload = this.format.decode(chunk);
167
+ console.log('RPC stream payload', payload);
168
+ try {
169
+ const transformed = this.transformer.decodeRPCChunk(call.namespace, call.procedure, payload);
170
+ await this.#serverRPCStreams.push(callId, transformed);
171
+ } catch (error) {
172
+ this._send(ClientMessageType.RpcStreamAbort, encodeNumber(callId, 'Uint32'));
173
+ this.#serverRPCStreams.remove(callId);
174
+ this.#serverRPCStreamCalls.delete(callId);
175
+ }
176
+ }
177
+ }
178
+ });
179
+ this.transport.on(`${ServerMessageType.RpcStreamAbort}`, (buffer)=>{
180
+ const callId = decodeNumber(buffer, 'Uint32');
181
+ console.log('RPC stream abort', callId);
182
+ const call = this.#calls.get(callId);
183
+ if (call) {
184
+ this.#serverStreams.end(callId);
185
+ this.#serverRPCStreams.abort(callId);
186
+ }
187
+ });
188
+ this.transport.on(`${ServerMessageType.ServerStreamPush}`, async (buffer)=>{
189
+ const streamId = decodeNumber(buffer, 'Uint32');
190
+ const chunk = buffer.slice(Uint32Array.BYTES_PER_ELEMENT);
191
+ console.log('Server stream push', streamId, chunk.byteLength);
192
+ try {
193
+ await this.#serverStreams.push(streamId, chunk);
194
+ this._send(ClientMessageType.ServerStreamPull, encodeNumber(streamId, 'Uint32'));
195
+ } catch (error) {
196
+ this._send(ClientMessageType.ServerStreamAbort, encodeNumber(streamId, 'Uint32'));
197
+ this.#serverStreams.remove(streamId);
198
+ }
199
+ });
200
+ this.transport.on(`${ServerMessageType.ServerStreamEnd}`, (buffer)=>{
201
+ const streamId = decodeNumber(buffer, 'Uint32');
202
+ console.log('Server stream end', streamId);
203
+ this.#serverStreams.end(streamId);
204
+ });
205
+ this.transport.on(`${ServerMessageType.ServerStreamAbort}`, (buffer)=>{
206
+ const streamId = decodeNumber(buffer, 'Uint32');
207
+ console.log('Server stream abort', streamId);
208
+ this.#serverStreams.abort(streamId);
209
+ });
210
+ this.transport.on(`${ServerMessageType.ClientStreamAbort}`, (buffer)=>{
211
+ const streamId = decodeNumber(buffer, 'Uint32');
212
+ console.log('Client stream abort', streamId);
213
+ this.#clientStreams.abort(streamId);
214
+ });
215
+ this.transport.on(`${ServerMessageType.ClientStreamPull}`, async (buffer)=>{
216
+ const streamId = decodeNumber(buffer, 'Uint32');
217
+ console.log('Client stream pull', streamId);
218
+ const size = decodeNumber(buffer, 'Uint32', Uint32Array.BYTES_PER_ELEMENT);
219
+ const streamIdEncoded = encodeNumber(streamId, 'Uint32');
220
+ try {
221
+ const chunk = await this.#clientStreams.pull(streamId, size);
222
+ if (chunk) {
223
+ this._send(ClientMessageType.ClientStreamPush, concat(streamIdEncoded, chunk));
224
+ } else {
225
+ this._send(ClientMessageType.ClientStreamEnd, streamIdEncoded);
226
+ this.#clientStreams.end(streamId);
227
+ }
228
+ } catch (error) {
229
+ console.error(error);
230
+ this._send(ClientMessageType.ClientStreamAbort, streamIdEncoded);
231
+ }
232
+ });
233
+ }
234
+ async connect(auth) {
235
+ return await this.transport.connect(auth, this.format.contentType);
236
+ }
237
+ async disconnect() {
238
+ return await this.transport.disconnect();
239
+ }
240
+ async _send(messageType, buffer) {
241
+ console.log('Client transport send', ClientMessageType[messageType], buffer.byteLength);
242
+ return await this.transport.send(messageType, buffer);
243
+ }
244
+ async _call(namespace, procedure, payload, options = {}) {
245
+ const callId = ++this.#callId;
246
+ const call = Object.assign(createPromise(), {
247
+ namespace,
248
+ procedure
249
+ });
250
+ const buffer = this.format.encodeRPC({
251
+ callId,
252
+ namespace,
253
+ procedure,
254
+ payload: this.transformer.encodeRPC(namespace, procedure, payload)
255
+ }, {
256
+ addStream: (blob)=>{
257
+ const streamId = ++this.#streamId;
258
+ const stream = this.#clientStreams.add(blob.source, streamId, blob.metadata);
259
+ return stream;
260
+ },
261
+ getStream: (id)=>{
262
+ const stream = this.#clientStreams.get(id);
263
+ return stream;
264
+ }
265
+ });
266
+ this.transport.send(ClientMessageType.Rpc, buffer).catch(console.error);
267
+ this.#calls.set(callId, call);
268
+ return call.promise;
269
+ }
270
+ #handleResponse(buffer) {
271
+ const callStreams = [];
272
+ const response = this.format.decodeRPC(buffer, {
273
+ addStream: (id, metadata)=>{
274
+ console.log('Client transport blob stream', id, metadata);
275
+ const stream = new ProtocolServerBlobStream(id, metadata, ()=>{
276
+ this._send(ClientMessageType.ServerStreamPull, encodeNumber(id, 'Uint32'));
277
+ });
278
+ callStreams.push(stream);
279
+ this.#serverStreams.add(id, stream);
280
+ return stream;
281
+ },
282
+ getStream: (id)=>{
283
+ return this.#serverStreams.get(id);
284
+ }
285
+ });
286
+ console.log('Client transport response', response);
287
+ const call = this.#calls.get(response.callId);
288
+ if (call) {
289
+ this.#calls.delete(response.callId);
290
+ if (response.error) {
291
+ const error = new ProtocolError(response.error.code, response.error.message, response.error.data);
292
+ return {
293
+ call,
294
+ response,
295
+ error
296
+ };
297
+ } else {
298
+ const payload = this.transformer.decodeRPC(call.namespace, call.procedure, response.payload);
299
+ return {
300
+ call,
301
+ response,
302
+ payload
303
+ };
304
+ }
305
+ }
306
+ for (const stream of callStreams){
307
+ this.#serverStreams.abort(stream.id);
308
+ }
309
+ throw new Error('Call not found');
310
+ }
311
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../lib/client/protocol.ts"],"sourcesContent":["import { type InteractivePromise, createPromise } from '@nmtjs/common'\nimport { concat, decodeNumber, encodeNumber } from '../common/binary.ts'\nimport type { ProtocolBlobMetadata } from '../common/blob.ts'\nimport { ClientMessageType, ServerMessageType } from '../common/enums.ts'\nimport type { ProtocolRPC } from '../common/types.ts'\nimport { EventEmitter } from './events.ts'\nimport type { BaseClientFormat } from './format.ts'\nimport {\n ProtocolClientBlobStream,\n ProtocolServerBlobStream,\n ProtocolServerStream,\n} from './stream.ts'\n\nexport class ProtocolError extends Error {\n code: string\n data?: any\n\n constructor(code: string, message?: string, data?: any) {\n super(message)\n this.code = code\n this.data = data\n }\n\n get message() {\n return `${this.code} ${super.message}`\n }\n\n toString() {\n return `${this.code} ${this.message}`\n }\n\n toJSON() {\n return {\n code: this.code,\n message: this.message,\n data: this.data,\n }\n }\n}\n\nexport class ProtocolClientStreams {\n readonly #collection = new Map<number, ProtocolClientBlobStream>()\n\n get(streamId: number) {\n const stream = this.#collection.get(streamId)\n if (!stream) throw new Error('Stream not found')\n return stream\n }\n\n add(\n source: ReadableStream,\n streamId: number,\n metadata: ProtocolBlobMetadata,\n ) {\n const stream = new ProtocolClientBlobStream(source, streamId, metadata)\n this.#collection.set(streamId, stream)\n return stream\n }\n\n remove(streamId: number) {\n this.#collection.delete(streamId)\n }\n\n abort(streamId: number) {\n const stream = this.get(streamId)\n stream.abort()\n this.remove(streamId)\n }\n\n pull(streamId: number, size: number) {\n const stream = this.get(streamId)\n return stream.read(size)\n }\n\n end(streamId: number) {\n const stream = this.get(streamId)\n stream.end()\n this.remove(streamId)\n }\n}\n\nexport class ProtocolServerStreams {\n readonly #collection = new Map<number, ProtocolServerStream>()\n\n has(streamId: number) {\n return this.#collection.has(streamId)\n }\n\n get(streamId: number) {\n const stream = this.#collection.get(streamId)\n if (!stream) throw new Error('Stream not found')\n return stream\n }\n\n add(streamId: number, stream: ProtocolServerStream) {\n this.#collection.set(streamId, stream)\n return stream\n }\n\n remove(streamId: number) {\n this.#collection.delete(streamId)\n }\n\n abort(streamId: number) {\n if (this.has(streamId)) {\n const stream = this.get(streamId)\n stream.abort()\n this.remove(streamId)\n }\n }\n\n async push(streamId: number, chunk: ArrayBuffer) {\n const stream = this.get(streamId)\n return await stream.push(chunk)\n }\n\n end(streamId: number) {\n const stream = this.get(streamId)\n stream.end()\n this.remove(streamId)\n }\n}\n\nexport interface ProtocolTransport\n extends EventEmitter<{\n [K in `${ServerMessageType}`]: [ArrayBuffer]\n }> {\n connect(\n auth: any,\n contentType: BaseClientFormat['contentType'],\n ): Promise<void>\n disconnect(): Promise<void>\n send(messageType: ClientMessageType, buffer: ArrayBuffer): Promise<void>\n}\n\nexport class ProtocolBaseTransformer {\n encodeRPC(namespace: string, procedure: string, payload: any) {\n return payload\n }\n decodeRPC(namespace: string, procedure: string, payload: any) {\n return payload\n }\n decodeRPCChunk(namespace: string, procedure: string, payload: any) {\n return payload\n }\n decodeEvent(namespace: string, event: string, payload: any) {\n return payload\n }\n}\n\nexport type ProtocolClientCall = InteractivePromise<any> &\n Pick<ProtocolRPC, 'namespace' | 'procedure'>\n\nexport abstract class ProtocolBaseClient<\n T extends Record<string, Record<string, any>>,\n> extends EventEmitter<\n {\n [N in keyof T]: {\n [E in keyof T[N] as `${Extract<N, string>}/${Extract<E, string>}`]: [\n payload: T[N][E],\n ]\n }\n }[keyof T]\n> {\n readonly #clientStreams: ProtocolClientStreams\n readonly #serverStreams: ProtocolServerStreams\n readonly #serverRPCStreams: ProtocolServerStreams\n readonly #serverRPCStreamCalls = new Map<\n number,\n Pick<ProtocolRPC, 'namespace' | 'procedure'>\n >()\n readonly #calls = new Map<number, ProtocolClientCall>()\n\n #callId = 0\n #streamId = 0\n\n constructor(\n protected readonly transport: ProtocolTransport,\n protected readonly format: BaseClientFormat,\n protected readonly transformer: ProtocolBaseTransformer = new ProtocolBaseTransformer(),\n ) {\n super()\n\n this.#clientStreams = new ProtocolClientStreams()\n this.#serverStreams = new ProtocolServerStreams()\n this.#serverRPCStreams = new ProtocolServerStreams()\n\n this.transport.on(`${ServerMessageType.Event}`, (buffer) => {\n const [namespace, event, payload] = this.format.decode(buffer)\n const name = `${namespace}/${event}`\n const transformed = this.transformer.decodeEvent(\n namespace,\n event,\n payload,\n )\n this.emit(name, transformed)\n })\n\n this.transport.on(`${ServerMessageType.RpcResponse}`, (buffer) => {\n const { call, error, payload } = this.#handleResponse(buffer)\n if (error) call.reject(error)\n else call.resolve(payload)\n })\n\n this.transport.on(`${ServerMessageType.RpcStreamResponse}`, (buffer) => {\n const { call, response, payload, error } = this.#handleResponse(buffer)\n if (error) return call.reject(error)\n console.log('Creating RPC stream', response)\n const stream = new ProtocolServerStream()\n this.#serverRPCStreams.add(response.callId, stream)\n this.#serverRPCStreamCalls.set(response.callId, {\n namespace: call.namespace,\n procedure: call.procedure,\n })\n call.resolve([payload, stream])\n })\n\n this.transport.on(`${ServerMessageType.RpcStreamChunk}`, async (buffer) => {\n const callId = decodeNumber(buffer, 'Uint32')\n console.log('RPC stream chunk', callId)\n\n const chunk = buffer.slice(Uint32Array.BYTES_PER_ELEMENT)\n if (chunk.byteLength === 0) {\n this.#serverRPCStreams.end(callId)\n this.#serverRPCStreamCalls.delete(callId)\n } else {\n const call = this.#serverRPCStreamCalls.get(callId)\n console.log('RPC stream call', call)\n if (call) {\n const payload = this.format.decode(chunk)\n console.log('RPC stream payload', payload)\n try {\n const transformed = this.transformer.decodeRPCChunk(\n call.namespace,\n call.procedure,\n payload,\n )\n await this.#serverRPCStreams.push(callId, transformed)\n } catch (error) {\n this._send(\n ClientMessageType.RpcStreamAbort,\n encodeNumber(callId, 'Uint32'),\n )\n this.#serverRPCStreams.remove(callId)\n this.#serverRPCStreamCalls.delete(callId)\n }\n }\n }\n })\n\n this.transport.on(`${ServerMessageType.RpcStreamAbort}`, (buffer) => {\n const callId = decodeNumber(buffer, 'Uint32')\n console.log('RPC stream abort', callId)\n const call = this.#calls.get(callId)\n if (call) {\n this.#serverStreams.end(callId)\n this.#serverRPCStreams.abort(callId)\n }\n })\n\n this.transport.on(\n `${ServerMessageType.ServerStreamPush}`,\n async (buffer) => {\n const streamId = decodeNumber(buffer, 'Uint32')\n const chunk = buffer.slice(Uint32Array.BYTES_PER_ELEMENT)\n console.log('Server stream push', streamId, chunk.byteLength)\n try {\n await this.#serverStreams.push(streamId, chunk)\n this._send(\n ClientMessageType.ServerStreamPull,\n encodeNumber(streamId, 'Uint32'),\n )\n } catch (error) {\n this._send(\n ClientMessageType.ServerStreamAbort,\n encodeNumber(streamId, 'Uint32'),\n )\n this.#serverStreams.remove(streamId)\n }\n },\n )\n\n this.transport.on(`${ServerMessageType.ServerStreamEnd}`, (buffer) => {\n const streamId = decodeNumber(buffer, 'Uint32')\n console.log('Server stream end', streamId)\n this.#serverStreams.end(streamId)\n })\n\n this.transport.on(`${ServerMessageType.ServerStreamAbort}`, (buffer) => {\n const streamId = decodeNumber(buffer, 'Uint32')\n console.log('Server stream abort', streamId)\n this.#serverStreams.abort(streamId)\n })\n\n this.transport.on(`${ServerMessageType.ClientStreamAbort}`, (buffer) => {\n const streamId = decodeNumber(buffer, 'Uint32')\n console.log('Client stream abort', streamId)\n this.#clientStreams.abort(streamId)\n })\n\n this.transport.on(\n `${ServerMessageType.ClientStreamPull}`,\n async (buffer) => {\n const streamId = decodeNumber(buffer, 'Uint32')\n console.log('Client stream pull', streamId)\n const size = decodeNumber(\n buffer,\n 'Uint32',\n Uint32Array.BYTES_PER_ELEMENT,\n )\n const streamIdEncoded = encodeNumber(streamId, 'Uint32')\n try {\n const chunk = await this.#clientStreams.pull(streamId, size)\n if (chunk) {\n this._send(\n ClientMessageType.ClientStreamPush,\n concat(streamIdEncoded, chunk),\n )\n } else {\n this._send(ClientMessageType.ClientStreamEnd, streamIdEncoded)\n this.#clientStreams.end(streamId)\n }\n } catch (error) {\n console.error(error)\n this._send(ClientMessageType.ClientStreamAbort, streamIdEncoded)\n }\n },\n )\n }\n\n async connect(auth: any) {\n return await this.transport.connect(auth, this.format.contentType)\n }\n\n async disconnect() {\n return await this.transport.disconnect()\n }\n\n protected async _send(messageType: ClientMessageType, buffer: ArrayBuffer) {\n console.log(\n 'Client transport send',\n ClientMessageType[messageType],\n buffer.byteLength,\n )\n return await this.transport.send(messageType, buffer)\n }\n\n protected async _call(\n namespace: string,\n procedure: string,\n payload: any,\n options = {},\n ) {\n const callId = ++this.#callId\n const call = Object.assign(createPromise(), {\n namespace,\n procedure,\n })\n const buffer = this.format.encodeRPC(\n {\n callId,\n namespace,\n procedure,\n payload: this.transformer.encodeRPC(namespace, procedure, payload),\n },\n {\n addStream: (blob) => {\n const streamId = ++this.#streamId\n const stream = this.#clientStreams.add(\n blob.source,\n streamId,\n blob.metadata,\n )\n return stream\n },\n getStream: (id) => {\n const stream = this.#clientStreams.get(id)\n return stream\n },\n },\n )\n\n this.transport.send(ClientMessageType.Rpc, buffer).catch(console.error)\n\n this.#calls.set(callId, call)\n\n return call.promise\n }\n\n #handleResponse(buffer: ArrayBuffer) {\n const callStreams: ProtocolServerBlobStream[] = []\n const response = this.format.decodeRPC(buffer, {\n addStream: (id, metadata) => {\n console.log('Client transport blob stream', id, metadata)\n const stream = new ProtocolServerBlobStream(id, metadata, () => {\n this._send(\n ClientMessageType.ServerStreamPull,\n encodeNumber(id, 'Uint32'),\n )\n })\n callStreams.push(stream)\n this.#serverStreams.add(id, stream)\n return stream\n },\n getStream: (id) => {\n return this.#serverStreams.get(id)\n },\n })\n\n console.log('Client transport response', response)\n\n const call = this.#calls.get(response.callId)\n\n if (call) {\n this.#calls.delete(response.callId)\n\n if (response.error) {\n const error = new ProtocolError(\n response.error.code,\n response.error.message,\n response.error.data,\n )\n return { call, response, error }\n } else {\n const payload = this.transformer.decodeRPC(\n call.namespace,\n call.procedure,\n response.payload,\n )\n return { call, response, payload }\n }\n }\n\n for (const stream of callStreams) {\n this.#serverStreams.abort(stream.id)\n }\n\n throw new Error('Call not found')\n }\n}\n"],"names":["createPromise","concat","decodeNumber","encodeNumber","ClientMessageType","ServerMessageType","EventEmitter","ProtocolClientBlobStream","ProtocolServerBlobStream","ProtocolServerStream","ProtocolError","Error","code","data","constructor","message","toString","toJSON","ProtocolClientStreams","Map","get","streamId","stream","add","source","metadata","set","remove","delete","abort","pull","size","read","end","ProtocolServerStreams","has","push","chunk","ProtocolBaseTransformer","encodeRPC","namespace","procedure","payload","decodeRPC","decodeRPCChunk","decodeEvent","event","ProtocolBaseClient","transport","format","transformer","on","Event","buffer","decode","name","transformed","emit","RpcResponse","call","error","reject","resolve","RpcStreamResponse","response","console","log","callId","RpcStreamChunk","slice","Uint32Array","BYTES_PER_ELEMENT","byteLength","_send","RpcStreamAbort","ServerStreamPush","ServerStreamPull","ServerStreamAbort","ServerStreamEnd","ClientStreamAbort","ClientStreamPull","streamIdEncoded","ClientStreamPush","ClientStreamEnd","connect","auth","contentType","disconnect","messageType","send","_call","options","Object","assign","addStream","blob","getStream","id","Rpc","catch","promise","callStreams"],"mappings":"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"}
@@ -0,0 +1,99 @@
1
+ import { defer } from '@nmtjs/common';
2
+ import { encodeText } from "../common/binary.js";
3
+ export class ProtocolClientBlobStream extends TransformStream {
4
+ source;
5
+ id;
6
+ metadata;
7
+ #queue;
8
+ #reader;
9
+ constructor(source, id, metadata){
10
+ super({
11
+ start: ()=>{
12
+ defer(()=>source.pipeThrough(this));
13
+ },
14
+ transform: (chunk, controller)=>{
15
+ if (chunk instanceof ArrayBuffer) {
16
+ controller.enqueue(chunk);
17
+ } else if (chunk instanceof Uint8Array) {
18
+ controller.enqueue(chunk.buffer);
19
+ } else if (typeof chunk === 'string') {
20
+ controller.enqueue(encodeText(chunk));
21
+ } else {
22
+ throw new Error('Invalid chunk data type. Expected ArrayBuffer, Uint8Array, or string.');
23
+ }
24
+ }
25
+ });
26
+ this.source = source;
27
+ this.id = id;
28
+ this.metadata = metadata;
29
+ this.#queue = new ArrayBuffer(0);
30
+ this.#reader = this.readable.getReader();
31
+ }
32
+ async read(size) {
33
+ if (this.#queue.byteLength >= size) {
34
+ const chunk = this.#queue.slice(0, size);
35
+ const remaining = this.#queue.slice(size);
36
+ this.#queue = remaining;
37
+ return chunk;
38
+ } else {
39
+ const { done, value } = await this.#reader.read();
40
+ if (!done) {
41
+ const buffer = value;
42
+ const chunk = buffer.slice(0, size);
43
+ const remaining = buffer.slice(size);
44
+ this.#queue = remaining;
45
+ return chunk;
46
+ }
47
+ return null;
48
+ }
49
+ }
50
+ abort(error = new Error('Stream aborted')) {
51
+ this.#reader.cancel(error);
52
+ }
53
+ async end() {
54
+ if (!this.writable.locked && await this.writable.getWriter().closed) {
55
+ await this.writable.close();
56
+ }
57
+ }
58
+ }
59
+ export class ProtocolServerStream extends TransformStream {
60
+ #writer;
61
+ constructor(start){
62
+ super({
63
+ start
64
+ });
65
+ this.#writer = this.writable.getWriter();
66
+ }
67
+ async *[Symbol.asyncIterator]() {
68
+ const reader = this.readable.getReader();
69
+ while(true){
70
+ const { done, value } = await reader.read();
71
+ if (!done) yield value;
72
+ else return void 0;
73
+ }
74
+ }
75
+ async push(chunk) {
76
+ await this.#writer.write(chunk);
77
+ }
78
+ async end() {
79
+ await this.#writer.close();
80
+ }
81
+ abort(error = new Error('Stream aborted')) {
82
+ this.#writer.abort(error);
83
+ }
84
+ }
85
+ export class ProtocolServerBlobStream extends ProtocolServerStream {
86
+ id;
87
+ metadata;
88
+ constructor(id, metadata, start){
89
+ super(start);
90
+ this.id = id;
91
+ this.metadata = metadata;
92
+ }
93
+ push(chunk) {
94
+ return super.push(chunk);
95
+ }
96
+ end() {
97
+ return super.end();
98
+ }
99
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../lib/client/stream.ts"],"sourcesContent":["import { type Callback, defer } from '@nmtjs/common'\nimport { encodeText } from '../common/binary.ts'\nimport type { ProtocolBlobMetadata } from '../common/blob.ts'\n\nexport class ProtocolClientBlobStream extends TransformStream<\n any,\n ArrayBuffer\n> {\n #queue: ArrayBuffer\n #reader: ReadableStreamDefaultReader\n\n constructor(\n readonly source: ReadableStream,\n readonly id: number,\n readonly metadata: ProtocolBlobMetadata,\n ) {\n super({\n start: () => {\n defer(() => source.pipeThrough(this))\n },\n transform: (chunk, controller) => {\n if (chunk instanceof ArrayBuffer) {\n controller.enqueue(chunk)\n } else if (chunk instanceof Uint8Array) {\n controller.enqueue(chunk.buffer)\n } else if (typeof chunk === 'string') {\n controller.enqueue(encodeText(chunk))\n } else {\n throw new Error(\n 'Invalid chunk data type. Expected ArrayBuffer, Uint8Array, or string.',\n )\n }\n },\n })\n\n this.#queue = new ArrayBuffer(0)\n this.#reader = this.readable.getReader()\n }\n\n async read(size: number) {\n if (this.#queue.byteLength >= size) {\n const chunk = this.#queue.slice(0, size)\n const remaining = this.#queue.slice(size)\n this.#queue = remaining\n return chunk\n } else {\n const { done, value } = await this.#reader.read()\n if (!done) {\n const buffer = value as ArrayBuffer\n const chunk = buffer.slice(0, size)\n const remaining = buffer.slice(size)\n this.#queue = remaining\n return chunk\n }\n return null\n }\n }\n\n abort(error = new Error('Stream aborted')) {\n this.#reader.cancel(error)\n }\n\n async end() {\n if (!this.writable.locked && (await this.writable.getWriter().closed)) {\n await this.writable.close()\n }\n }\n}\n\nexport class ProtocolServerStream<T = any> extends TransformStream<any, T> {\n #writer: WritableStreamDefaultWriter\n\n constructor(start?: Callback) {\n super({ start })\n this.#writer = this.writable.getWriter()\n }\n\n async *[Symbol.asyncIterator]() {\n const reader = this.readable.getReader()\n while (true) {\n const { done, value } = await reader.read()\n if (!done) yield value\n else return void 0\n }\n }\n\n async push(chunk: any) {\n await this.#writer.write(chunk)\n }\n\n async end() {\n await this.#writer.close()\n }\n\n abort(error = new Error('Stream aborted')) {\n this.#writer.abort(error)\n }\n}\n\nexport class ProtocolServerBlobStream extends ProtocolServerStream<ArrayBuffer> {\n constructor(\n readonly id: number,\n readonly metadata: ProtocolBlobMetadata,\n start: Callback,\n ) {\n super(start)\n }\n\n push(chunk: ArrayBuffer) {\n return super.push(chunk)\n }\n\n end() {\n return super.end()\n }\n}\n"],"names":["defer","encodeText","ProtocolClientBlobStream","TransformStream","constructor","source","id","metadata","start","pipeThrough","transform","chunk","controller","ArrayBuffer","enqueue","Uint8Array","buffer","Error","readable","getReader","read","size","byteLength","slice","remaining","done","value","abort","error","cancel","end","writable","locked","getWriter","closed","close","ProtocolServerStream","Symbol","asyncIterator","reader","push","write","ProtocolServerBlobStream"],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ const utf8decoder = new TextDecoder();
2
+ const utf8encoder = new TextEncoder();
3
+ export const encodeNumber = (value, type, littleEndian = false)=>{
4
+ const bytesNeeded = globalThis[`${type}Array`].BYTES_PER_ELEMENT;
5
+ const ab = new ArrayBuffer(bytesNeeded);
6
+ const dv = new DataView(ab);
7
+ dv[`set${type}`](0, value, littleEndian);
8
+ return ab;
9
+ };
10
+ export const decodeNumber = (buffer, type, offset = 0, littleEndian = false)=>{
11
+ const view = new DataView(buffer);
12
+ return view[`get${type}`](offset, littleEndian);
13
+ };
14
+ export const encodeText = (text)=>new Uint8Array(utf8encoder.encode(text)).buffer;
15
+ export const decodeText = (buffer)=>utf8decoder.decode(buffer);
16
+ export const concat = (...buffers)=>{
17
+ const totalLength = buffers.reduce((acc, buffer)=>acc + buffer.byteLength, 0);
18
+ const view = new Uint8Array(totalLength);
19
+ let offset = 0;
20
+ for (const buffer of buffers){
21
+ view.set(new Uint8Array(buffer), offset);
22
+ offset += buffer.byteLength;
23
+ }
24
+ return view.buffer;
25
+ };
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../lib/common/binary.ts"],"sourcesContent":["// TODO: get rid of lib DOM somehow...\n/// <reference lib=\"dom\" />\n\nconst utf8decoder = new TextDecoder()\nconst utf8encoder = new TextEncoder()\n\nexport type BinaryTypes = {\n Int8: number\n Int16: number\n Int32: number\n Uint8: number\n Uint16: number\n Uint32: number\n Float32: number\n Float64: number\n BigInt64: bigint\n BigUint64: bigint\n}\n\nexport const encodeNumber = <T extends keyof BinaryTypes>(\n value: BinaryTypes[T],\n type: T,\n littleEndian = false,\n) => {\n const bytesNeeded = globalThis[`${type}Array`].BYTES_PER_ELEMENT\n const ab = new ArrayBuffer(bytesNeeded)\n const dv = new DataView(ab)\n dv[`set${type}`](0, value as never, littleEndian)\n return ab\n}\n\nexport const decodeNumber = <T extends keyof BinaryTypes>(\n buffer: ArrayBuffer,\n type: T,\n offset = 0,\n littleEndian = false,\n): BinaryTypes[T] => {\n const view = new DataView(buffer)\n return view[`get${type}`](offset, littleEndian) as BinaryTypes[T]\n}\n\nexport const encodeText = (text: string) =>\n new Uint8Array(utf8encoder.encode(text)).buffer as ArrayBuffer\n\nexport const decodeText = (buffer: Parameters<typeof utf8decoder.decode>[0]) =>\n utf8decoder.decode(buffer)\n\nexport const concat = (...buffers: ArrayBuffer[]) => {\n const totalLength = buffers.reduce(\n (acc, buffer) => acc + buffer.byteLength,\n 0,\n )\n const view = new Uint8Array(totalLength)\n let offset = 0\n for (const buffer of buffers) {\n view.set(new Uint8Array(buffer), offset)\n offset += buffer.byteLength\n }\n return view.buffer\n}\n"],"names":["utf8decoder","TextDecoder","utf8encoder","TextEncoder","encodeNumber","value","type","littleEndian","bytesNeeded","globalThis","BYTES_PER_ELEMENT","ab","ArrayBuffer","dv","DataView","decodeNumber","buffer","offset","view","encodeText","text","Uint8Array","encode","decodeText","decode","concat","buffers","totalLength","reduce","acc","byteLength","set"],"mappings":"AAGA,MAAMA,cAAc,IAAIC;AACxB,MAAMC,cAAc,IAAIC;AAexB,OAAO,MAAMC,eAAe,CAC1BC,OACAC,MACAC,eAAe,KAAK;IAEpB,MAAMC,cAAcC,UAAU,CAAC,CAAC,EAAEH,KAAK,KAAK,CAAC,CAAC,CAACI,iBAAiB;IAChE,MAAMC,KAAK,IAAIC,YAAYJ;IAC3B,MAAMK,KAAK,IAAIC,SAASH;IACxBE,EAAE,CAAC,CAAC,GAAG,EAAEP,KAAK,CAAC,CAAC,CAAC,GAAGD,OAAgBE;IACpC,OAAOI;AACT,EAAC;AAED,OAAO,MAAMI,eAAe,CAC1BC,QACAV,MACAW,SAAS,CAAC,EACVV,eAAe,KAAK;IAEpB,MAAMW,OAAO,IAAIJ,SAASE;IAC1B,OAAOE,IAAI,CAAC,CAAC,GAAG,EAAEZ,KAAK,CAAC,CAAC,CAACW,QAAQV;AACpC,EAAC;AAED,OAAO,MAAMY,aAAa,CAACC,OACzB,IAAIC,WAAWnB,YAAYoB,MAAM,CAACF,OAAOJ,MAAM,CAAe;AAEhE,OAAO,MAAMO,aAAa,CAACP,SACzBhB,YAAYwB,MAAM,CAACR,QAAO;AAE5B,OAAO,MAAMS,SAAS,CAAC,GAAGC;IACxB,MAAMC,cAAcD,QAAQE,MAAM,CAChC,CAACC,KAAKb,SAAWa,MAAMb,OAAOc,UAAU,EACxC;IAEF,MAAMZ,OAAO,IAAIG,WAAWM;IAC5B,IAAIV,SAAS;IACb,KAAK,MAAMD,UAAUU,QAAS;QAC5BR,KAAKa,GAAG,CAAC,IAAIV,WAAWL,SAASC;QACjCA,UAAUD,OAAOc,UAAU;IAC7B;IACA,OAAOZ,KAAKF,MAAM;AACpB,EAAC"}
@@ -0,0 +1,42 @@
1
+ export class ProtocolBlob {
2
+ metadata;
3
+ source;
4
+ constructor(source, size = -1, type = 'application/octet-stream', filename){
5
+ if (size < -1 || size === 0) throw new Error('Blob size is invalid');
6
+ this.source = source;
7
+ this.metadata = {
8
+ size,
9
+ type,
10
+ filename
11
+ };
12
+ }
13
+ static from(source, metadata = {}) {
14
+ let _source = undefined;
15
+ if (source instanceof globalThis.ReadableStream) {
16
+ _source = source;
17
+ } else if ('File' in globalThis && source instanceof globalThis.File) {
18
+ _source = source.stream();
19
+ metadata.size = source.size;
20
+ metadata.filename = source.name;
21
+ } else if (source instanceof globalThis.Blob) {
22
+ _source = source.stream();
23
+ metadata.size = source.size;
24
+ } else if (typeof source === 'string') {
25
+ const blob = new Blob([
26
+ source
27
+ ]);
28
+ _source = blob.stream();
29
+ metadata.size = blob.size;
30
+ metadata.type = metadata.type || 'text/plain';
31
+ } else if (source instanceof globalThis.ArrayBuffer) {
32
+ const blob = new Blob([
33
+ source
34
+ ]);
35
+ _source = blob.stream();
36
+ metadata.size = blob.size;
37
+ } else {
38
+ _source = source;
39
+ }
40
+ return new ProtocolBlob(_source, metadata.size, metadata.type, metadata.filename);
41
+ }
42
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../lib/common/blob.ts"],"sourcesContent":["export type ProtocolBlobMetadata = {\n type: string\n size: number\n filename?: string\n}\n\nexport interface ProtocolBlobInterface {\n readonly metadata: ProtocolBlobMetadata\n}\n\nexport class ProtocolBlob implements ProtocolBlobInterface {\n public readonly metadata: ProtocolBlobMetadata\n public readonly source: any\n\n constructor(\n source: any,\n size = -1,\n type = 'application/octet-stream',\n filename?: string,\n ) {\n if (size < -1 || size === 0) throw new Error('Blob size is invalid')\n\n this.source = source\n this.metadata = {\n size,\n type,\n filename,\n }\n }\n\n static from(\n source: any,\n metadata: {\n size?: number\n type?: string\n filename?: string\n } = {},\n ) {\n let _source: any = undefined\n\n if (source instanceof globalThis.ReadableStream) {\n _source = source\n } else if ('File' in globalThis && source instanceof globalThis.File) {\n _source = source.stream()\n metadata.size = source.size\n metadata.filename = source.name\n } else if (source instanceof globalThis.Blob) {\n _source = source.stream()\n metadata.size = source.size\n } else if (typeof source === 'string') {\n const blob = new Blob([source])\n _source = blob.stream()\n metadata.size = blob.size\n metadata.type = metadata.type || 'text/plain'\n } else if (source instanceof globalThis.ArrayBuffer) {\n const blob = new Blob([source])\n _source = blob.stream()\n metadata.size = blob.size\n } else {\n _source = source\n }\n\n return new ProtocolBlob(\n _source,\n metadata.size,\n metadata.type,\n metadata.filename,\n )\n }\n}\n"],"names":["ProtocolBlob","metadata","source","constructor","size","type","filename","Error","from","_source","undefined","globalThis","ReadableStream","File","stream","name","Blob","blob","ArrayBuffer"],"mappings":"AAUA,OAAO,MAAMA;IACKC,SAA8B;IAC9BC,OAAW;IAE3BC,YACED,MAAW,EACXE,OAAO,CAAC,CAAC,EACTC,OAAO,0BAA0B,EACjCC,QAAiB,CACjB;QACA,IAAIF,OAAO,CAAC,KAAKA,SAAS,GAAG,MAAM,IAAIG,MAAM;QAE7C,IAAI,CAACL,MAAM,GAAGA;QACd,IAAI,CAACD,QAAQ,GAAG;YACdG;YACAC;YACAC;QACF;IACF;IAEA,OAAOE,KACLN,MAAW,EACXD,WAII,CAAC,CAAC,EACN;QACA,IAAIQ,UAAeC;QAEnB,IAAIR,kBAAkBS,WAAWC,cAAc,EAAE;YAC/CH,UAAUP;QACZ,OAAO,IAAI,UAAUS,cAAcT,kBAAkBS,WAAWE,IAAI,EAAE;YACpEJ,UAAUP,OAAOY,MAAM;YACvBb,SAASG,IAAI,GAAGF,OAAOE,IAAI;YAC3BH,SAASK,QAAQ,GAAGJ,OAAOa,IAAI;QACjC,OAAO,IAAIb,kBAAkBS,WAAWK,IAAI,EAAE;YAC5CP,UAAUP,OAAOY,MAAM;YACvBb,SAASG,IAAI,GAAGF,OAAOE,IAAI;QAC7B,OAAO,IAAI,OAAOF,WAAW,UAAU;YACrC,MAAMe,OAAO,IAAID,KAAK;gBAACd;aAAO;YAC9BO,UAAUQ,KAAKH,MAAM;YACrBb,SAASG,IAAI,GAAGa,KAAKb,IAAI;YACzBH,SAASI,IAAI,GAAGJ,SAASI,IAAI,IAAI;QACnC,OAAO,IAAIH,kBAAkBS,WAAWO,WAAW,EAAE;YACnD,MAAMD,OAAO,IAAID,KAAK;gBAACd;aAAO;YAC9BO,UAAUQ,KAAKH,MAAM;YACrBb,SAASG,IAAI,GAAGa,KAAKb,IAAI;QAC3B,OAAO;YACLK,UAAUP;QACZ;QAEA,OAAO,IAAIF,aACTS,SACAR,SAASG,IAAI,EACbH,SAASI,IAAI,EACbJ,SAASK,QAAQ;IAErB;AACF"}