@arcanejs/toolkit 8.0.0 → 9.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.
Files changed (71) hide show
  1. package/dist/backend/components/base.d.mts +2 -1
  2. package/dist/backend/components/base.d.ts +2 -1
  3. package/dist/backend/components/base.js +2 -2
  4. package/dist/backend/components/base.mjs +1 -1
  5. package/dist/backend/components/button.d.mts +2 -1
  6. package/dist/backend/components/button.d.ts +2 -1
  7. package/dist/backend/components/button.js +3 -3
  8. package/dist/backend/components/button.mjs +2 -2
  9. package/dist/backend/components/group.d.mts +2 -1
  10. package/dist/backend/components/group.d.ts +2 -1
  11. package/dist/backend/components/group.js +3 -3
  12. package/dist/backend/components/group.mjs +2 -2
  13. package/dist/backend/components/label.d.mts +2 -1
  14. package/dist/backend/components/label.d.ts +2 -1
  15. package/dist/backend/components/label.js +3 -3
  16. package/dist/backend/components/label.mjs +2 -2
  17. package/dist/backend/components/rect.d.mts +2 -1
  18. package/dist/backend/components/rect.d.ts +2 -1
  19. package/dist/backend/components/rect.js +3 -3
  20. package/dist/backend/components/rect.mjs +2 -2
  21. package/dist/backend/components/slider-button.d.mts +2 -1
  22. package/dist/backend/components/slider-button.d.ts +2 -1
  23. package/dist/backend/components/slider-button.js +3 -3
  24. package/dist/backend/components/slider-button.mjs +2 -2
  25. package/dist/backend/components/switch.d.mts +2 -1
  26. package/dist/backend/components/switch.d.ts +2 -1
  27. package/dist/backend/components/switch.js +3 -3
  28. package/dist/backend/components/switch.mjs +2 -2
  29. package/dist/backend/components/tabs.d.mts +2 -1
  30. package/dist/backend/components/tabs.d.ts +2 -1
  31. package/dist/backend/components/tabs.js +3 -3
  32. package/dist/backend/components/tabs.mjs +2 -2
  33. package/dist/backend/components/text-input.d.mts +2 -1
  34. package/dist/backend/components/text-input.d.ts +2 -1
  35. package/dist/backend/components/text-input.js +3 -3
  36. package/dist/backend/components/text-input.mjs +2 -2
  37. package/dist/backend/components/timeline.d.mts +2 -1
  38. package/dist/backend/components/timeline.d.ts +2 -1
  39. package/dist/backend/components/timeline.js +3 -3
  40. package/dist/backend/components/timeline.mjs +2 -2
  41. package/dist/{chunk-IV3AE3CW.js → chunk-2R23ER4K.js} +3 -3
  42. package/dist/{chunk-R5OA7LLZ.mjs → chunk-5K7DK7CW.mjs} +1 -1
  43. package/dist/{chunk-RJLYYTZ6.mjs → chunk-7WTSYZOS.mjs} +1 -1
  44. package/dist/{chunk-2K4UT5QB.js → chunk-AYMITMVR.js} +3 -3
  45. package/dist/{chunk-K6V55JTG.mjs → chunk-KO24S32V.mjs} +1 -1
  46. package/dist/{chunk-XSKWLJOQ.js → chunk-KRGLXKY2.js} +4 -4
  47. package/dist/{chunk-JHWFQLLE.mjs → chunk-MNEFCU3M.mjs} +1 -1
  48. package/dist/{chunk-TF7N4O5G.js → chunk-NEFCI6N6.js} +2 -2
  49. package/dist/{chunk-TULW7CRV.mjs → chunk-NJW4ZG4X.mjs} +1 -1
  50. package/dist/{chunk-MHSAHTVN.mjs → chunk-QBZB56TQ.mjs} +1 -1
  51. package/dist/{chunk-UHEZQR2Q.js → chunk-QHCNKTKW.js} +2 -2
  52. package/dist/{chunk-4AGKM5NT.js → chunk-RELZ3VTJ.js} +3 -3
  53. package/dist/{chunk-7MQHRTBE.mjs → chunk-RGLKNCJ3.mjs} +1 -1
  54. package/dist/{chunk-A3RWE7HZ.js → chunk-SPYBETRJ.js} +3 -3
  55. package/dist/{chunk-GONHNB6V.mjs → chunk-UTTTCTUQ.mjs} +26 -5
  56. package/dist/{chunk-GXJ3JRRK.mjs → chunk-VD6S32ED.mjs} +1 -1
  57. package/dist/{chunk-5B65Q7RL.js → chunk-VTNAO4KC.js} +2 -2
  58. package/dist/{chunk-6PS3Q66F.mjs → chunk-Y3NPWW27.mjs} +1 -1
  59. package/dist/{chunk-CVY55KAR.js → chunk-Y5FC42KD.js} +3 -3
  60. package/dist/{chunk-WN3GXVUE.js → chunk-YNOJTE3G.js} +26 -5
  61. package/dist/frontend/entrypoint.js +42 -1
  62. package/dist/frontend/entrypoint.js.map +2 -2
  63. package/dist/frontend/index.js +69 -12
  64. package/dist/frontend/index.mjs +69 -12
  65. package/dist/index.d.mts +3 -2
  66. package/dist/index.d.ts +3 -2
  67. package/dist/index.js +190 -64
  68. package/dist/index.mjs +161 -35
  69. package/dist/{toolkit-Bglbv3ix.d.ts → toolkit-0nxr5FpP.d.ts} +116 -93
  70. package/dist/{toolkit-BPqxbDbk.d.mts → toolkit-BYE-VOhF.d.mts} +116 -93
  71. package/package.json +16 -16
package/dist/index.mjs CHANGED
@@ -1,38 +1,38 @@
1
1
  import {
2
2
  Tab,
3
3
  Tabs
4
- } from "./chunk-R5OA7LLZ.mjs";
4
+ } from "./chunk-5K7DK7CW.mjs";
5
5
  import {
6
6
  TextInput
7
- } from "./chunk-GXJ3JRRK.mjs";
7
+ } from "./chunk-VD6S32ED.mjs";
8
8
  import {
9
9
  Timeline
10
- } from "./chunk-6PS3Q66F.mjs";
10
+ } from "./chunk-Y3NPWW27.mjs";
11
11
  import {
12
12
  IDMap
13
13
  } from "./chunk-RGHJEMWG.mjs";
14
14
  import {
15
15
  Button
16
- } from "./chunk-7MQHRTBE.mjs";
16
+ } from "./chunk-RGLKNCJ3.mjs";
17
17
  import {
18
18
  Group,
19
19
  GroupHeader
20
- } from "./chunk-TULW7CRV.mjs";
20
+ } from "./chunk-NJW4ZG4X.mjs";
21
21
  import {
22
22
  Label
23
- } from "./chunk-JHWFQLLE.mjs";
23
+ } from "./chunk-MNEFCU3M.mjs";
24
24
  import {
25
25
  Rect
26
- } from "./chunk-RJLYYTZ6.mjs";
26
+ } from "./chunk-7WTSYZOS.mjs";
27
27
  import {
28
28
  SliderButton
29
- } from "./chunk-K6V55JTG.mjs";
29
+ } from "./chunk-KO24S32V.mjs";
30
30
  import {
31
31
  Switch
32
- } from "./chunk-MHSAHTVN.mjs";
32
+ } from "./chunk-QBZB56TQ.mjs";
33
33
  import {
34
34
  EventEmitter
35
- } from "./chunk-GONHNB6V.mjs";
35
+ } from "./chunk-UTTTCTUQ.mjs";
36
36
  import {
37
37
  __require
38
38
  } from "./chunk-Y6FXYEAI.mjs";
@@ -69,15 +69,26 @@ var distDir = () => {
69
69
  throw new Error(`Server running from unknown location: ${__dirname}`);
70
70
  }
71
71
  };
72
+ var UPLOAD_URL = /^\/upload\/([0-9a-f]+)$/;
73
+ var DOWNLOAD_URL = /^\/download\/([0-9a-f]+)$/;
72
74
  var Server = class {
73
- constructor(options, onNewConnection, onClosedConnection, onMessage, log) {
75
+ constructor(options, onNewConnection, onClosedConnection, onMessage, onUpload, onDownload, log) {
74
76
  this.options = options;
75
77
  this.onNewConnection = onNewConnection;
76
78
  this.onClosedConnection = onClosedConnection;
77
79
  this.onMessage = onMessage;
80
+ this.onUpload = onUpload;
81
+ this.onDownload = onDownload;
78
82
  this.log = log;
79
83
  this.title = options.title ?? "@arcanejs";
80
84
  }
85
+ options;
86
+ onNewConnection;
87
+ onClosedConnection;
88
+ onMessage;
89
+ onUpload;
90
+ onDownload;
91
+ log;
81
92
  staticFiles = null;
82
93
  htmlContext = null;
83
94
  staticFilesInitPromise = null;
@@ -273,8 +284,45 @@ var Server = class {
273
284
  }
274
285
  }
275
286
  }
276
- res.writeHead(404, { "Content-Type": "text/plain" });
277
- res.end("not found", "utf-8");
287
+ const [uploadMatch, downloadMatch] = [
288
+ UPLOAD_URL.exec(pathname),
289
+ DOWNLOAD_URL.exec(pathname)
290
+ ];
291
+ if (uploadMatch?.[1]) {
292
+ const id = uploadMatch[1];
293
+ this.log?.debug("Upload request for id: %s", id);
294
+ this.onUpload(id, req).then(() => {
295
+ res.writeHead(200, { "Content-Type": "text/plain" });
296
+ res.end("Upload successful", "utf-8");
297
+ }).catch((cause) => {
298
+ const error = new Error(`Error handling upload for id ${id}`, {
299
+ cause
300
+ });
301
+ this.log?.error(error);
302
+ res.writeHead(500, { "Content-Type": "text/plain" });
303
+ res.end("Error handling upload", "utf-8");
304
+ });
305
+ } else if (downloadMatch?.[1]) {
306
+ const id = downloadMatch[1];
307
+ this.log?.debug("Download request for id: %s", id);
308
+ this.onDownload(id).then((handler) => handler()).then(({ stream, headers }) => {
309
+ res.writeHead(200, {
310
+ "Content-Type": "application/octet-stream",
311
+ ...headers
312
+ });
313
+ stream.pipe(res);
314
+ }).catch((cause) => {
315
+ const error = new Error(`Error handling download for id ${id}`, {
316
+ cause
317
+ });
318
+ this.log?.error(error);
319
+ res.writeHead(500, { "Content-Type": "text/plain" });
320
+ res.end("Error handling download", "utf-8");
321
+ });
322
+ } else {
323
+ res.writeHead(404, { "Content-Type": "text/plain" });
324
+ res.end("not found", "utf-8");
325
+ }
278
326
  };
279
327
  parsePathname = (url) => {
280
328
  if (!url) return "";
@@ -327,6 +375,7 @@ var Server = class {
327
375
  import { WebSocketServer } from "ws";
328
376
  import { createServer } from "http";
329
377
  import { v4 as uuidv4 } from "uuid";
378
+ import { randomBytes } from "crypto";
330
379
  var normalizeClockSyncOptions = (clockSync) => {
331
380
  if (!clockSync) {
332
381
  return null;
@@ -353,6 +402,8 @@ var Toolkit = class {
353
402
  /** @hidden */
354
403
  events = new EventEmitter();
355
404
  server;
405
+ uploads = /* @__PURE__ */ new Map();
406
+ downloads = /* @__PURE__ */ new Map();
356
407
  constructor(options = {}) {
357
408
  this.options = {
358
409
  ...DEFAULT_LIGHT_DESK_OPTIONS,
@@ -369,6 +420,8 @@ var Toolkit = class {
369
420
  this.onNewConnection,
370
421
  this.onClosedConnection,
371
422
  this.onMessage,
423
+ this.onUpload,
424
+ this.onDownload,
372
425
  this.options.log
373
426
  );
374
427
  }
@@ -502,6 +555,25 @@ var Toolkit = class {
502
555
  const con = this.connections.get(connection);
503
556
  this.connections.delete(connection);
504
557
  if (con) {
558
+ let inProgressUploads = 0;
559
+ let inProgressDownloads = 0;
560
+ for (const [id, upload] of this.uploads.entries()) {
561
+ if (upload.connection === connection) {
562
+ this.uploads.delete(id);
563
+ inProgressUploads++;
564
+ }
565
+ }
566
+ for (const [id, download] of this.downloads.entries()) {
567
+ if (download.connection === connection) {
568
+ this.downloads.delete(id);
569
+ inProgressDownloads++;
570
+ }
571
+ }
572
+ if (inProgressUploads > 0 || inProgressDownloads > 0) {
573
+ this.log()?.info(
574
+ `Connection closed with ${inProgressUploads} in-progress uploads and ${inProgressDownloads} in-progress downloads`
575
+ );
576
+ }
505
577
  this.events.emit("closed-connection", con.publicConnection);
506
578
  }
507
579
  };
@@ -509,12 +581,32 @@ var Toolkit = class {
509
581
  try {
510
582
  const rg = this.rootGroup;
511
583
  if (rg) {
512
- const returnValue = await new Promise(
584
+ const handlerValue = await new Promise(
513
585
  (resolve2, reject) => rg.routeCall(this.componentIDMap, call, publicConnection, {
514
586
  resolve: resolve2,
515
587
  reject
516
588
  })
517
589
  );
590
+ let returnValue;
591
+ if (call.type === "component-call") {
592
+ returnValue = handlerValue;
593
+ } else if (call.type === "component-call-upload") {
594
+ const uploadHandler = handlerValue;
595
+ const secureId = randomBytes(32).toString("hex");
596
+ this.uploads.set(secureId, {
597
+ connection,
598
+ handler: uploadHandler
599
+ });
600
+ returnValue = secureId;
601
+ } else if (call.type === "component-call-download") {
602
+ const downloadHandler = handlerValue;
603
+ const secureId = randomBytes(32).toString("hex");
604
+ this.downloads.set(secureId, {
605
+ connection,
606
+ handler: downloadHandler
607
+ });
608
+ returnValue = secureId;
609
+ }
518
610
  connection.sendMessage({
519
611
  type: "call-response",
520
612
  namespace: call.namespace,
@@ -525,13 +617,15 @@ var Toolkit = class {
525
617
  } else {
526
618
  throw new Error("No root group set");
527
619
  }
528
- } catch (err) {
620
+ } catch (cause) {
621
+ const error = new Error(`Error handling call`, { cause });
622
+ this.log()?.error(error);
529
623
  connection.sendMessage({
530
624
  type: "call-response",
531
625
  namespace: call.namespace,
532
626
  requestId: call.requestId,
533
627
  success: false,
534
- errorMessage: `${err}`
628
+ errorMessage: `${cause}`
535
629
  });
536
630
  }
537
631
  };
@@ -547,25 +641,57 @@ var Toolkit = class {
547
641
  message,
548
642
  publicConnection.uuid
549
643
  );
550
- switch (message.type) {
551
- case "component-message":
552
- if (this.rootGroup)
553
- this.rootGroup.routeMessage(
554
- this.componentIDMap,
555
- message,
556
- publicConnection
557
- );
558
- break;
559
- case "component-call":
560
- this.handleCall(connection, publicConnection, message);
561
- break;
562
- case "ping": {
563
- connection.sendMessage({
564
- type: "pong",
565
- pingId: message.pingId,
566
- serverTimeMillis: Date.now()
567
- });
568
- break;
644
+ try {
645
+ switch (message.type) {
646
+ case "component-message":
647
+ if (this.rootGroup)
648
+ this.rootGroup.routeMessage(
649
+ this.componentIDMap,
650
+ message,
651
+ publicConnection
652
+ );
653
+ break;
654
+ case "component-call":
655
+ case "component-call-upload":
656
+ case "component-call-download":
657
+ this.handleCall(connection, publicConnection, message);
658
+ break;
659
+ case "ping": {
660
+ connection.sendMessage({
661
+ type: "pong",
662
+ pingId: message.pingId,
663
+ serverTimeMillis: Date.now()
664
+ });
665
+ break;
666
+ }
667
+ }
668
+ } catch (cause) {
669
+ const error = new Error(
670
+ `Error handling message: ${JSON.stringify(message)}`,
671
+ { cause }
672
+ );
673
+ this.log()?.error(error);
674
+ }
675
+ };
676
+ onUpload = async (id, data) => {
677
+ const upload = this.uploads.get(id);
678
+ if (!upload) {
679
+ throw new Error(`No upload handler found for id: ${id}`);
680
+ }
681
+ await upload.handler(data);
682
+ this.uploads.delete(id);
683
+ };
684
+ onDownload = async (id) => {
685
+ const download = this.downloads.get(id);
686
+ if (!download) {
687
+ throw new Error(`No download handler found for id: ${id}`);
688
+ }
689
+ return download.handler;
690
+ };
691
+ sendNotification = (notification, filter) => {
692
+ for (const [connection, meta] of this.connections.entries()) {
693
+ if (!filter || filter(meta.publicConnection)) {
694
+ connection.sendMessage(notification);
569
695
  }
570
696
  }
571
697
  };
@@ -4,10 +4,115 @@ import _ from 'lodash';
4
4
  import * as http from 'http';
5
5
  import { Application } from 'express';
6
6
  import { WebSocket } from 'ws';
7
- import { ClientMessage, ServerMessage, BaseComponentProto, AnyClientComponentMessage, AnyClientComponentCall, ReturnForPair } from '@arcanejs/protocol';
7
+ import { BaseComponentProto, AnyClientComponentMessage, AnyClientComponentCall, AnyClientComponentCallUpload, AnyClientComponentCallDownload, ReturnForPair, ServerMessage, ClientMessage, BaseNotificationMessage } from '@arcanejs/protocol';
8
+ import { Readable } from 'node:stream';
9
+ import { I as IDMap } from './id-map-DxQ3_gyA.js';
8
10
  import * as proto from '@arcanejs/protocol/core';
9
11
  import { GroupComponentStyle } from '@arcanejs/protocol/styles';
10
- import { I as IDMap } from './id-map-DxQ3_gyA.js';
12
+
13
+ type CallUploadResponse = (data: Readable) => Promise<void>;
14
+ type CallDownloadResponse = () => Promise<{
15
+ stream: Readable;
16
+ headers: Record<string, string>;
17
+ }>;
18
+ declare abstract class Base<Namespace extends string, Proto extends BaseComponentProto<Namespace, string>, Props, CallPairs = any, CallActions extends string & keyof CallPairs = any> {
19
+ /** @hidden */
20
+ private parent;
21
+ /** @hidden */
22
+ private readonly defaultProps;
23
+ /** @hidden */
24
+ private _props;
25
+ /** @hidden */
26
+ private _onPropsUpdated;
27
+ constructor(defaultProps: Props, props?: Partial<Props>, options?: {
28
+ onPropsUpdated?: (oldProps: Props) => void;
29
+ });
30
+ /**
31
+ * Call if
32
+ */
33
+ triggerInitialPropsUpdate: () => void;
34
+ log: () => Logger | null;
35
+ get props(): Props;
36
+ set props(props: Partial<Props>);
37
+ setProps: (props: Partial<Props>) => void;
38
+ updateProps: (updates: Partial<Props>) => void;
39
+ /** @hidden */
40
+ setParent(parent: Parent | null): void;
41
+ /** @hidden */
42
+ updateTree(): void;
43
+ /** @hidden */
44
+ abstract getProtoInfo(idMap: IDMap, context: ToolkitRenderContext): Proto;
45
+ /** @hidden */
46
+ handleMessage(_message: AnyClientComponentMessage, _connection: ToolkitConnection): void;
47
+ /** @hidden */
48
+ handleAnyCall(message: AnyClientComponentCall | AnyClientComponentCallUpload | AnyClientComponentCallDownload, _connection: ToolkitConnection): Promise<ReturnForPair<CallPairs, CallActions> | CallUploadResponse | CallDownloadResponse>;
49
+ /** @hidden */
50
+ handleCall(_call: AnyClientComponentCall, _connection: ToolkitConnection): Promise<ReturnForPair<CallPairs, CallActions>>;
51
+ /** @hidden */
52
+ handleCallUpload(_call: AnyClientComponentCallUpload, _connection: ToolkitConnection): Promise<CallUploadResponse>;
53
+ /** @hidden */
54
+ handleCallDownload(_call: AnyClientComponentCallDownload, _connection: ToolkitConnection): Promise<CallDownloadResponse>;
55
+ routeMessage(_idMap: IDMap, _message: AnyClientComponentMessage, _connection: ToolkitConnection): void;
56
+ routeCall(_idMap: IDMap, _call: AnyClientComponentCall | AnyClientComponentCallUpload | AnyClientComponentCallDownload, _connection: ToolkitConnection, _callbacks: {
57
+ resolve: (result: unknown) => void;
58
+ reject: (error: unknown) => void;
59
+ }): void;
60
+ }
61
+ type AnyComponent = Base<string, BaseComponentProto<string, string>, any>;
62
+ /** @hidden */
63
+ interface Parent {
64
+ updateTree(): void;
65
+ removeChild(component: AnyComponent): void;
66
+ log(): Logger | null;
67
+ }
68
+ declare abstract class BaseParent<Namespace extends string, Proto extends BaseComponentProto<Namespace, string>, T, CallPairs = any, CallActions extends string & keyof CallPairs = any> extends Base<Namespace, Proto, T, CallPairs, CallActions> implements Parent {
69
+ /** @hidden */
70
+ private children;
71
+ abstract validateChildren(children: AnyComponent[]): void;
72
+ appendChildren: <CS extends AnyComponent[]>(...children: CS) => CS;
73
+ appendChild: <C extends AnyComponent>(child: C) => C;
74
+ removeChild: (component: AnyComponent) => void;
75
+ removeAllChildren: () => void;
76
+ /**
77
+ * Return all children components that messages need to be routed to
78
+ */
79
+ getChildren: () => readonly AnyComponent[];
80
+ /**
81
+ * TODO: we can do this better, right now it broadcasts the message to all
82
+ * components of the tree
83
+ *
84
+ * @hidden
85
+ */
86
+ routeMessage(idMap: IDMap, message: AnyClientComponentMessage, connection: ToolkitConnection): void;
87
+ routeCall(idMap: IDMap, call: AnyClientComponentCall | AnyClientComponentCallUpload | AnyClientComponentCallDownload, connection: ToolkitConnection, callbacks: {
88
+ resolve: (result: unknown) => void;
89
+ reject: (error: unknown) => void;
90
+ }): Promise<void>;
91
+ insertBefore(child: AnyComponent, beforeChild: AnyComponent): void;
92
+ }
93
+ interface Listenable<Map extends Record<string, (...args: any[]) => void>> {
94
+ addListener<T extends keyof Map>(type: T, listener: Map[T]): void;
95
+ removeListener<T extends keyof Map>(type: T, listener: Map[T]): void;
96
+ }
97
+ declare class EventEmitter<Map extends Record<string, (...args: any[]) => void>> implements Listenable<Map> {
98
+ private readonly listeners;
99
+ addListener: <T extends keyof Map>(type: T, listener: Map[T]) => void;
100
+ removeListener: <T extends keyof Map>(type: T, listener: Map[T]) => void;
101
+ emit: <T extends keyof Map>(type: T, ...args: Parameters<Map[T]>) => Promise<ReturnType<Map[T]>[]>;
102
+ /**
103
+ * Like {@link emit},
104
+ * but ensures only a single listener exists and returns its result.
105
+ */
106
+ call: <T extends keyof Map>(type: T, ...args: Parameters<Map[T]>) => Promise<ReturnType<Map[T]>>;
107
+ /**
108
+ * Process prop changes to update listeners
109
+ */
110
+ processPropChanges: <Mapping extends Record<string, keyof Map>, Props extends { [key in keyof Mapping]?: Map[Mapping[key]] | null | undefined; }>(
111
+ /**
112
+ * Mapping from prop key to event name
113
+ */
114
+ mapping: Mapping, oldProps: Props, newProps: Props) => void;
115
+ }
11
116
 
12
117
  interface Connection {
13
118
  sendMessage(msg: ServerMessage): void;
@@ -17,12 +122,14 @@ declare class Server<TAdditionalFiles extends ToolkitAdditionalFiles = Record<ne
17
122
  private readonly onNewConnection;
18
123
  private readonly onClosedConnection;
19
124
  private readonly onMessage;
125
+ private readonly onUpload;
126
+ private readonly onDownload;
20
127
  private readonly log?;
21
128
  private staticFiles;
22
129
  private htmlContext;
23
130
  private staticFilesInitPromise;
24
131
  private readonly title;
25
- constructor(options: ToolkitOptions<TAdditionalFiles>, onNewConnection: (connection: Connection) => void, onClosedConnection: (connection: Connection) => void, onMessage: (connection: Connection, message: ClientMessage) => void, log?: Logger | undefined);
132
+ constructor(options: ToolkitOptions<TAdditionalFiles>, onNewConnection: (connection: Connection) => void, onClosedConnection: (connection: Connection) => void, onMessage: (connection: Connection, message: ClientMessage) => void, onUpload: (id: string, data: Readable) => Promise<void>, onDownload: (id: string) => Promise<CallDownloadResponse>, log?: Logger | undefined);
26
133
  private getEntrypointPaths;
27
134
  private fileExists;
28
135
  private ensureStaticFilesInitialized;
@@ -147,95 +254,6 @@ type InitializationOptions<TAdditionalFiles extends ToolkitAdditionalFiles = Rec
147
254
  setup: (server: Server<TAdditionalFiles>) => void;
148
255
  };
149
256
 
150
- declare abstract class Base<Namespace extends string, Proto extends BaseComponentProto<Namespace, string>, Props, CallPairs = any, CallActions extends string & keyof CallPairs = any> {
151
- /** @hidden */
152
- private parent;
153
- /** @hidden */
154
- private readonly defaultProps;
155
- /** @hidden */
156
- private _props;
157
- /** @hidden */
158
- private _onPropsUpdated;
159
- constructor(defaultProps: Props, props?: Partial<Props>, options?: {
160
- onPropsUpdated?: (oldProps: Props) => void;
161
- });
162
- /**
163
- * Call if
164
- */
165
- triggerInitialPropsUpdate: () => void;
166
- log: () => Logger | null;
167
- get props(): Props;
168
- set props(props: Partial<Props>);
169
- setProps: (props: Partial<Props>) => void;
170
- updateProps: (updates: Partial<Props>) => void;
171
- /** @hidden */
172
- setParent(parent: Parent | null): void;
173
- /** @hidden */
174
- updateTree(): void;
175
- /** @hidden */
176
- abstract getProtoInfo(idMap: IDMap, context: ToolkitRenderContext): Proto;
177
- /** @hidden */
178
- handleMessage(_message: AnyClientComponentMessage, _connection: ToolkitConnection): void;
179
- /** @hidden */
180
- handleCall(_call: AnyClientComponentCall, _connection: ToolkitConnection): Promise<ReturnForPair<CallPairs, CallActions>>;
181
- routeMessage(_idMap: IDMap, _message: AnyClientComponentMessage, _connection: ToolkitConnection): void;
182
- routeCall(_idMap: IDMap, _call: AnyClientComponentCall, _connection: ToolkitConnection, _callbacks: {
183
- resolve: (result: unknown) => void;
184
- reject: (error: unknown) => void;
185
- }): void;
186
- }
187
- type AnyComponent = Base<string, BaseComponentProto<string, string>, any>;
188
- /** @hidden */
189
- interface Parent {
190
- updateTree(): void;
191
- removeChild(component: AnyComponent): void;
192
- log(): Logger | null;
193
- }
194
- declare abstract class BaseParent<Namespace extends string, Proto extends BaseComponentProto<Namespace, string>, T, CallPairs = any, CallActions extends string & keyof CallPairs = any> extends Base<Namespace, Proto, T, CallPairs, CallActions> implements Parent {
195
- /** @hidden */
196
- private children;
197
- abstract validateChildren(children: AnyComponent[]): void;
198
- appendChildren: <CS extends AnyComponent[]>(...children: CS) => CS;
199
- appendChild: <C extends AnyComponent>(child: C) => C;
200
- removeChild: (component: AnyComponent) => void;
201
- removeAllChildren: () => void;
202
- /**
203
- * Return all children components that messages need to be routed to
204
- */
205
- getChildren: () => readonly AnyComponent[];
206
- /**
207
- * TODO: we can do this better, right now it broadcasts the message to all
208
- * components of the tree
209
- *
210
- * @hidden
211
- */
212
- routeMessage(idMap: IDMap, message: AnyClientComponentMessage, connection: ToolkitConnection): void;
213
- routeCall(idMap: IDMap, call: AnyClientComponentCall, connection: ToolkitConnection, callbacks: {
214
- resolve: (result: unknown) => void;
215
- reject: (error: unknown) => void;
216
- }): Promise<void>;
217
- insertBefore(child: AnyComponent, beforeChild: AnyComponent): void;
218
- }
219
- interface Listenable<Map extends Record<string, (...args: any[]) => void>> {
220
- addListener<T extends keyof Map>(type: T, listener: Map[T]): void;
221
- removeListener<T extends keyof Map>(type: T, listener: Map[T]): void;
222
- }
223
- declare class EventEmitter<Map extends Record<string, (...args: any[]) => void>> implements Listenable<Map> {
224
- private readonly listeners;
225
- addListener: <T extends keyof Map>(type: T, listener: Map[T]) => void;
226
- removeListener: <T extends keyof Map>(type: T, listener: Map[T]) => void;
227
- emit: <T extends keyof Map>(type: T, ...args: Parameters<Map[T]>) => Promise<ReturnType<Map[T]>[]>;
228
- /**
229
- * Like {@link emit},
230
- * but ensures only a single listener exists and returns its result.
231
- */
232
- call: <T extends keyof Map>(type: T, ...args: Parameters<Map[T]>) => Promise<ReturnType<Map[T]>>;
233
- /**
234
- * Process prop changes to update listeners
235
- */
236
- processPropChanges: <Mapping extends Record<string, keyof Map>, Props extends { [key in keyof Mapping]?: Map[Mapping[key]] | null | undefined; }>(mapping: Mapping, oldProps: Props, newProps: Props) => void;
237
- }
238
-
239
257
  type Events$2 = {
240
258
  click: (connection: ToolkitConnection) => void | Promise<void>;
241
259
  };
@@ -338,6 +356,8 @@ declare class Toolkit<TAdditionalFiles extends ToolkitAdditionalFiles = Record<n
338
356
  /** @hidden */
339
357
  private readonly events;
340
358
  private readonly server;
359
+ private readonly uploads;
360
+ private readonly downloads;
341
361
  constructor(options?: Partial<ToolkitOptions<TAdditionalFiles>>);
342
362
  addListener: <T extends keyof Events>(type: T, listener: Events[T]) => void;
343
363
  removeListener: <T extends keyof Events>(type: T, listener: Events[T]) => void;
@@ -352,6 +372,9 @@ declare class Toolkit<TAdditionalFiles extends ToolkitAdditionalFiles = Record<n
352
372
  private onClosedConnection;
353
373
  private handleCall;
354
374
  private onMessage;
375
+ private onUpload;
376
+ private onDownload;
377
+ sendNotification: (notification: BaseNotificationMessage<string, string>, filter?: (connection: ToolkitConnection) => boolean) => void;
355
378
  }
356
379
 
357
- export { type AnyComponent as A, Button as B, EventEmitter as E, Group as G, type InternalProps$1 as I, type Listenable as L, type Parent as P, Toolkit as T, type ToolkitConnection as a, type ToolkitRenderContext as b, type ToolkitServerListenerOptions as c, type ToolkitServerListener as d, type ToolkitAdditionalFiles as e, type ToolkitClockSyncOptions as f, type ToolkitCoreAssetRelativePath as g, type ToolkitHtmlPageContext as h, type ToolkitOptions as i, type ToolkitStaticFile as j, type ToolkitStaticFileResolver as k, GroupHeader as l, Base as m, BaseParent as n, type Events$2 as o, type ButtonMode as p, type Props$1 as q, type Events$1 as r, type InternalProps as s, type Props as t };
380
+ export { type AnyComponent as A, Button as B, type CallDownloadResponse as C, EventEmitter as E, Group as G, type InternalProps$1 as I, type Listenable as L, type Parent as P, Toolkit as T, GroupHeader as a, type ToolkitAdditionalFiles as b, type ToolkitClockSyncOptions as c, type ToolkitConnection as d, type ToolkitCoreAssetRelativePath as e, type ToolkitHtmlPageContext as f, type ToolkitOptions as g, type ToolkitRenderContext as h, type ToolkitServerListener as i, type ToolkitServerListenerOptions as j, type ToolkitStaticFile as k, type ToolkitStaticFileResolver as l, Base as m, BaseParent as n, type CallUploadResponse as o, type ButtonMode as p, type Events$2 as q, type Props$1 as r, type Events$1 as s, type InternalProps as t, type Props as u };