@kirill.konshin/utils 0.0.14 → 0.0.15

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 (107) hide show
  1. package/.ctirc +2 -1
  2. package/.turbo/turbo-build.log +18 -13
  3. package/.turbo/turbo-test.log +78 -25
  4. package/CHANGELOG.md +6 -0
  5. package/README.md +1 -1
  6. package/demo/{cache-demo-clean.ts → worker-demo.ts} +1 -1
  7. package/dist/bootstrap/controls.d.ts +5 -2
  8. package/dist/bootstrap/controls.d.ts.map +1 -1
  9. package/dist/bootstrap/controls.js +1 -0
  10. package/dist/bootstrap/controls.js.map +1 -1
  11. package/dist/bootstrap/controls.stories.d.ts +9 -0
  12. package/dist/bootstrap/controls.stories.d.ts.map +1 -0
  13. package/dist/bootstrap/error.stories.d.ts +8 -0
  14. package/dist/bootstrap/error.stories.d.ts.map +1 -0
  15. package/dist/bootstrap/field.stories.d.ts +8 -0
  16. package/dist/bootstrap/field.stories.d.ts.map +1 -0
  17. package/dist/bootstrap/globalLoading.stories.d.ts +7 -0
  18. package/dist/bootstrap/globalLoading.stories.d.ts.map +1 -0
  19. package/dist/bootstrap/index.js +2 -1
  20. package/dist/bootstrap/loading.stories.d.ts +9 -0
  21. package/dist/bootstrap/loading.stories.d.ts.map +1 -0
  22. package/dist/bootstrap/screen.stories.d.ts +14 -0
  23. package/dist/bootstrap/screen.stories.d.ts.map +1 -0
  24. package/dist/bootstrap/toaster.stories.d.ts +8 -0
  25. package/dist/bootstrap/toaster.stories.d.ts.map +1 -0
  26. package/dist/bootstrap/useModal.stories.d.ts +9 -0
  27. package/dist/bootstrap/useModal.stories.d.ts.map +1 -0
  28. package/dist/core/cache.d.ts +7 -8
  29. package/dist/core/cache.d.ts.map +1 -1
  30. package/dist/core/cache.js +7 -4
  31. package/dist/core/cache.js.map +1 -1
  32. package/dist/core/cache.test.d.ts +2 -0
  33. package/dist/core/cache.test.d.ts.map +1 -0
  34. package/dist/core/files.d.ts +3 -0
  35. package/dist/core/files.d.ts.map +1 -0
  36. package/dist/core/files.js +27 -0
  37. package/dist/core/files.js.map +1 -0
  38. package/dist/core/index.d.ts +4 -0
  39. package/dist/core/index.d.ts.map +1 -1
  40. package/dist/core/index.js +14 -2
  41. package/dist/core/index.js.map +1 -1
  42. package/dist/core/ls.d.ts +6 -0
  43. package/dist/core/ls.d.ts.map +1 -0
  44. package/dist/core/ls.js +12 -0
  45. package/dist/core/ls.js.map +1 -0
  46. package/dist/core/worker.d.ts +23 -9
  47. package/dist/core/worker.d.ts.map +1 -1
  48. package/dist/core/worker.js +93 -90
  49. package/dist/core/worker.js.map +1 -1
  50. package/dist/core/worker.test.d.ts +2 -0
  51. package/dist/core/worker.test.d.ts.map +1 -0
  52. package/dist/core/workerUtils.d.ts +3 -0
  53. package/dist/core/workerUtils.d.ts.map +1 -0
  54. package/dist/core/workerUtils.js +31 -0
  55. package/dist/core/workerUtils.js.map +1 -0
  56. package/dist/core/wrpc.d.ts +45 -0
  57. package/dist/core/wrpc.d.ts.map +1 -0
  58. package/dist/core/wrpc.fixture.d.ts +29 -0
  59. package/dist/core/wrpc.fixture.d.ts.map +1 -0
  60. package/dist/core/wrpc.js +242 -0
  61. package/dist/core/wrpc.js.map +1 -0
  62. package/dist/core/wrpc.test.d.ts +1 -0
  63. package/dist/core/wrpc.test.d.ts.map +1 -0
  64. package/dist/mui/formControlFieldset.stories.d.ts +7 -0
  65. package/dist/mui/formControlFieldset.stories.d.ts.map +1 -0
  66. package/dist/react/form/form.d.ts +7 -6
  67. package/dist/react/form/form.d.ts.map +1 -1
  68. package/dist/react/form/form.js +14 -20
  69. package/dist/react/form/form.js.map +1 -1
  70. package/dist/react/index.d.ts +1 -0
  71. package/dist/react/index.d.ts.map +1 -1
  72. package/dist/react/index.js +8 -2
  73. package/dist/react/index.js.map +1 -1
  74. package/dist/react/keyboard.d.ts +11 -0
  75. package/dist/react/keyboard.d.ts.map +1 -0
  76. package/dist/react/keyboard.js +38 -0
  77. package/dist/react/keyboard.js.map +1 -0
  78. package/package.json +5 -2
  79. package/src/bootstrap/controls.stories.tsx +2 -2
  80. package/src/bootstrap/controls.tsx +3 -3
  81. package/src/bootstrap/error.stories.tsx +3 -3
  82. package/src/bootstrap/field.stories.tsx +2 -2
  83. package/src/bootstrap/globalLoading.stories.tsx +2 -2
  84. package/src/bootstrap/loading.stories.tsx +2 -2
  85. package/src/bootstrap/screen.stories.tsx +2 -2
  86. package/src/bootstrap/toaster.stories.tsx +2 -2
  87. package/src/bootstrap/useModal.stories.tsx +3 -3
  88. package/src/core/README.md +91 -0
  89. package/src/core/cache.ts +12 -12
  90. package/src/core/files.ts +24 -0
  91. package/src/core/index.ts +4 -0
  92. package/src/core/ls.ts +11 -0
  93. package/src/core/worker.test.ts +197 -0
  94. package/src/core/worker.ts +106 -93
  95. package/src/core/workerUtils.ts +32 -0
  96. package/src/core/wrpc.fixture.ts +72 -0
  97. package/src/core/wrpc.test.ts +225 -0
  98. package/src/core/wrpc.ts +359 -0
  99. package/src/mui/formControlFieldset.stories.tsx +1 -1
  100. package/src/react/form/form.tsx +53 -33
  101. package/src/react/index.ts +1 -0
  102. package/src/react/keyboard.tsx +49 -0
  103. package/src/tailwind/README.md +8 -0
  104. package/tsconfig.json +2 -1
  105. package/vite.config.ts +10 -3
  106. package/vite.exports.ts +3 -3
  107. package/demo/cache-demo.ts +0 -343
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=cache.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cache.test.d.ts","sourceRoot":"","sources":["../../src/core/cache.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export declare const downloadFile: (filename: any, text: any, type?: string) => Promise<void>;
2
+ export declare const openFile: () => Promise<string>;
3
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/core/files.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY,4DAGxB,CAAC;AAEF,eAAO,MAAM,QAAQ,QAAO,OAAO,CAAC,MAAM,CAgBpC,CAAC"}
@@ -0,0 +1,27 @@
1
+ import { saveAs } from "file-saver";
2
+ const downloadFile = async (filename, text, type = "application/json") => {
3
+ saveAs(new Blob([text], { type }), filename);
4
+ };
5
+ const openFile = () => new Promise((res, rej) => {
6
+ const input = document.createElement("input");
7
+ input.type = "file";
8
+ input.addEventListener("change", function readFile(e) {
9
+ input.removeEventListener("change", readFile);
10
+ const [file] = e.target.files;
11
+ if (!file) return;
12
+ const reader = new FileReader();
13
+ reader.onload = (e2) => {
14
+ var _a;
15
+ return res((_a = e2.target) == null ? void 0 : _a.result);
16
+ };
17
+ reader.onerror = rej;
18
+ reader.onabort = rej;
19
+ reader.readAsText(file);
20
+ });
21
+ input.click();
22
+ });
23
+ export {
24
+ downloadFile,
25
+ openFile
26
+ };
27
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sources":["../../src/core/files.ts"],"sourcesContent":["import { saveAs } from 'file-saver';\n\nexport const downloadFile = async (filename, text, type = 'application/json') => {\n //FIXME https://github.com/eligrey/FileSaver.js/issues/731\n saveAs(new Blob([text], { type }), filename);\n};\n\nexport const openFile = (): Promise<string> =>\n new Promise((res, rej) => {\n const input = document.createElement('input');\n input.type = 'file';\n input.addEventListener('change', function readFile(e) {\n input.removeEventListener('change', readFile);\n // @ts-expect-error file is always there\n const [file] = e.target.files;\n if (!file) return;\n const reader = new FileReader();\n reader.onload = (e) => res(e.target?.result as string);\n reader.onerror = rej;\n reader.onabort = rej;\n reader.readAsText(file);\n });\n input.click();\n });\n"],"names":["e"],"mappings":";AAEO,MAAM,eAAe,OAAO,UAAU,MAAM,OAAO,uBAAuB;AAEtE,SAAA,IAAI,KAAK,CAAC,IAAI,GAAG,EAAE,KAAA,CAAM,GAAG,QAAQ;AAC/C;AAEO,MAAM,WAAW,MACpB,IAAI,QAAQ,CAAC,KAAK,QAAQ;AAChB,QAAA,QAAQ,SAAS,cAAc,OAAO;AAC5C,QAAM,OAAO;AACb,QAAM,iBAAiB,UAAU,SAAS,SAAS,GAAG;AAC5C,UAAA,oBAAoB,UAAU,QAAQ;AAE5C,UAAM,CAAC,IAAI,IAAI,EAAE,OAAO;AACxB,QAAI,CAAC,KAAM;AACL,UAAA,SAAS,IAAI,WAAW;AAC9B,WAAO,SAAS,CAACA,OAAAA;;AAAM,kBAAIA,QAAE,WAAFA,mBAAU,MAAgB;AAAA;AACrD,WAAO,UAAU;AACjB,WAAO,UAAU;AACjB,WAAO,WAAW,IAAI;AAAA,EAAA,CACzB;AACD,QAAM,MAAM;AAChB,CAAC;"}
@@ -1,6 +1,10 @@
1
1
  export * from './cache';
2
2
  export * from './errors';
3
+ export * from './files';
4
+ export * from './ls';
3
5
  export * from './measure';
4
6
  export * from './mutex';
5
7
  export * from './worker';
8
+ export * from './workerUtils';
9
+ export * from './wrpc';
6
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAC;AACxB,cAAc,MAAM,CAAC;AACrB,cAAc,WAAW,CAAC;AAC1B,cAAc,SAAS,CAAC;AACxB,cAAc,UAAU,CAAC;AACzB,cAAc,eAAe,CAAC;AAC9B,cAAc,QAAQ,CAAC"}
@@ -1,10 +1,15 @@
1
1
  import { ANY, TransformerMap, createTracker, equal, memo, shallowCompare } from "./cache.js";
2
2
  import { catchErrors } from "./errors.js";
3
+ import { downloadFile, openFile } from "./files.js";
4
+ import { getStorage } from "./ls.js";
3
5
  import { colored, createMeasurer, uncolored } from "./measure.js";
4
6
  import { Mutex } from "./mutex.js";
5
- import { RespondersBase, WorkerDialog, isTransferable } from "./worker.js";
7
+ import { RespondersBase, WorkerDialog } from "./worker.js";
8
+ import { getTransferrable, isTransferable } from "./workerUtils.js";
9
+ import { LogLevel, deriveController, rejectOnSignal, wrpc } from "./wrpc.js";
6
10
  export {
7
11
  ANY,
12
+ LogLevel,
8
13
  Mutex,
9
14
  RespondersBase,
10
15
  TransformerMap,
@@ -13,10 +18,17 @@ export {
13
18
  colored,
14
19
  createMeasurer,
15
20
  createTracker,
21
+ deriveController,
22
+ downloadFile,
16
23
  equal,
24
+ getStorage,
25
+ getTransferrable,
17
26
  isTransferable,
18
27
  memo,
28
+ openFile,
29
+ rejectOnSignal,
19
30
  shallowCompare,
20
- uncolored
31
+ uncolored,
32
+ wrpc
21
33
  };
22
34
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;"}
@@ -0,0 +1,6 @@
1
+ export declare function getStorage(pref: string): {
2
+ read: (key: string) => any;
3
+ write: (key: string, value: any) => void;
4
+ remove: (key: string) => void;
5
+ };
6
+ //# sourceMappingURL=ls.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ls.d.ts","sourceRoot":"","sources":["../../src/core/ls.ts"],"names":[],"mappings":"AAAA,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM;gBAKhB,MAAM;iBACL,MAAM,SAAS,GAAG;kBACjB,MAAM;EAG9B"}
@@ -0,0 +1,12 @@
1
+ function getStorage(pref) {
2
+ const prefix = (key) => `${pref}-${key}`;
3
+ const ls = typeof window !== "undefined" ? localStorage : null;
4
+ const read = (key) => JSON.parse((ls == null ? void 0 : ls.getItem(prefix(key))) || "null");
5
+ const write = (key, value) => ls == null ? void 0 : ls.setItem(prefix(key), JSON.stringify(value));
6
+ const remove = (key) => ls == null ? void 0 : ls.removeItem(prefix(key));
7
+ return { read, write, remove };
8
+ }
9
+ export {
10
+ getStorage
11
+ };
12
+ //# sourceMappingURL=ls.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ls.js","sources":["../../src/core/ls.ts"],"sourcesContent":["export function getStorage(pref: string) {\n const prefix = (key) => `${pref}-${key}`;\n\n const ls = (typeof window !== 'undefined' ? localStorage : null) as Storage;\n\n const read = (key: string) => JSON.parse(ls?.getItem(prefix(key)) || 'null');\n const write = (key: string, value: any) => ls?.setItem(prefix(key), JSON.stringify(value));\n const remove = (key: string) => ls?.removeItem(prefix(key));\n\n return { read, write, remove };\n}\n"],"names":[],"mappings":"AAAO,SAAS,WAAW,MAAc;AACrC,QAAM,SAAS,CAAC,QAAQ,GAAG,IAAI,IAAI,GAAG;AAEtC,QAAM,KAAM,OAAO,WAAW,cAAc,eAAe;AAErD,QAAA,OAAO,CAAC,QAAgB,KAAK,OAAM,yBAAI,QAAQ,OAAO,GAAG,OAAM,MAAM;AAC3E,QAAM,QAAQ,CAAC,KAAa,UAAe,yBAAI,QAAQ,OAAO,GAAG,GAAG,KAAK,UAAU,KAAK;AACxF,QAAM,SAAS,CAAC,QAAgB,yBAAI,WAAW,OAAO,GAAG;AAElD,SAAA,EAAE,MAAM,OAAO,OAAO;AACjC;"}
@@ -1,4 +1,3 @@
1
- export declare function isTransferable(obj: any): boolean;
2
1
  type WebWorker = Worker | (Window & typeof globalThis) | (WorkerGlobalScope & typeof globalThis);
3
2
  type MethodReturn<R, M extends keyof R> = R[M] extends (...args: any[]) => any ? Partial<Awaited<ReturnType<R[M]>>> : never;
4
3
  type MethodArg<R, M extends keyof R> = R[M] extends (arg: infer A, ...args: any[]) => any ? Partial<A> : never;
@@ -6,6 +5,7 @@ export type Ctx<R, K extends keyof R> = {
6
5
  id: string;
7
6
  parentId?: string;
8
7
  message: K;
8
+ done: boolean;
9
9
  };
10
10
  type Data<R, M extends keyof R> = MethodReturn<R, M> | MethodArg<R, M> | Error;
11
11
  type Event<R, M extends keyof R> = MessageEvent<{
@@ -17,9 +17,12 @@ export declare class WorkerDialog<R extends RespondersBase<any>> {
17
17
  worker: WebWorker;
18
18
  responders: R;
19
19
  name: string;
20
+ debug: number;
20
21
  readonly contexts: Set<Context<R, keyof R>>;
21
22
  protected closed: boolean;
22
- constructor(worker: WebWorker, responders: R, name: string);
23
+ protected currentId: number;
24
+ constructor(worker: WebWorker, responders: R, name: string, debug?: number);
25
+ getID(): string;
23
26
  close(): void;
24
27
  withMessage<M extends keyof R>(message: M): RequestContext<R, M>;
25
28
  }
@@ -37,8 +40,17 @@ declare abstract class Context<R, M extends keyof R> {
37
40
  abstract withMessage<M2 extends keyof R>(message: M2, id?: string): Context<R, M2>;
38
41
  close(reason?: string): void;
39
42
  get info(): string;
40
- protected postMessage(data?: Data<R, M>): Data<R, M> | undefined;
41
- send(data?: Data<R, M>): Data<R, M> | undefined;
43
+ get debugInfo(): {
44
+ id: string | undefined;
45
+ parentId: string | undefined;
46
+ message: M;
47
+ closed: boolean;
48
+ type: string;
49
+ listeners: number;
50
+ };
51
+ abstract type: 'request' | 'response' | string;
52
+ protected postMessage(data?: Data<R, M>, done?: boolean): Data<R, M> | undefined;
53
+ send(data?: Data<R, M>, done?: boolean): Data<R, M> | undefined;
42
54
  /**
43
55
  * Does not automatically close, assumes consumer will close
44
56
  *
@@ -55,12 +67,13 @@ declare abstract class Context<R, M extends keyof R> {
55
67
  * un(); // closes
56
68
  * ```
57
69
  */
58
- listen(callback: Listener<R, M>): () => void;
70
+ listen(callback: Listener<R, M>, done?: boolean): () => void;
59
71
  }
60
72
  declare class RequestContext<R, M extends keyof R> extends Context<R, M> {
73
+ type: string;
61
74
  withMessage<M2 extends keyof R>(message: M2, id?: string): RequestContext<R, M2>;
62
- send(data?: MethodArg<R, M>): MethodArg<R, M>;
63
- listen(callback: Listener<R, M, MethodReturn<R, M>, RequestContext<R, M>>): () => void;
75
+ send(data?: MethodArg<R, M>, done?: boolean): MethodArg<R, M>;
76
+ listen(callback: Listener<R, M, MethodReturn<R, M>, RequestContext<R, M>>, done?: boolean): () => void;
64
77
  /**
65
78
  * Returns response
66
79
  * If you need to work with ctx, use callback
@@ -76,9 +89,10 @@ declare class RequestContext<R, M extends keyof R> extends Context<R, M> {
76
89
  protected expect(): Promise<MethodReturn<R, M>>;
77
90
  }
78
91
  declare class ResponseContext<R, M extends keyof R> extends Context<R, M> {
92
+ type: string;
79
93
  withMessage<M2 extends keyof R>(message: M2, id?: string): ResponseContext<R, M2>;
80
- listen(callback: Listener<R, M, MethodArg<R, M>, ResponseContext<R, M>>): () => void;
81
- send(data?: MethodReturn<R, M>): MethodReturn<R, M>;
94
+ listen(callback: Listener<R, M, MethodArg<R, M>, ResponseContext<R, M>>, done?: boolean): () => void;
95
+ send(data?: MethodReturn<R, M>, done?: boolean): MethodReturn<R, M>;
82
96
  }
83
97
  export {};
84
98
  //# sourceMappingURL=worker.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/core/worker.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../src/core/worker.ts"],"names":[],"mappings":"AAIA,KAAK,SAAS,GAAG,MAAM,GAAG,CAAC,MAAM,GAAG,OAAO,UAAU,CAAC,GAAG,CAAC,iBAAiB,GAAG,OAAO,UAAU,CAAC,CAAC;AAEjG,KAAK,YAAY,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GACxE,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAClC,KAAK,CAAC;AAEZ,KAAK,SAAS,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,GAAG,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC;AAE/G,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI;IACpC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,CAAC,CAAC;IACX,IAAI,EAAE,OAAO,CAAC;CACjB,CAAC;AAEF,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,KAAK,CAAC;AAE/E,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,IAAI,YAAY,CAAC;IAAE,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;CAAE,CAAC,CAAC;AAEtF,KAAK,QAAQ,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,SAAS,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,SAAS,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAC9G,IAAI,EAAE,CAAC,EACP,IAAI,EAAE,CAAC,EACP,KAAK,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KACjB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAkB1B,qBAAa,YAAY,CAAC,CAAC,SAAS,cAAc,CAAC,GAAG,CAAC;IAMxC,MAAM,EAAE,SAAS;IACjB,UAAU,EAAE,CAAC;IACb,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,MAAM;IARxB,QAAQ,CAAC,QAAQ,2BAAkC;IACnD,SAAS,CAAC,MAAM,UAAS;IACzB,SAAS,CAAC,SAAS,SAAK;gBAGb,MAAM,EAAE,SAAS,EACjB,UAAU,EAAE,CAAC,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAU;IAsC5B,KAAK;IAIL,KAAK;IAKL,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CAG5C;AAED,qBAAa,cAAc,CAAC,CAAC;IACzB,MAAM,CAAC,CAAC,SAAS,MAAM,CAAC,EAAE,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,EACnF,OAAO,EAAE,CAAC,EACV,SAAS,EAAE,CAAC,GACb,CAAC;CAIP;AAGD,uBAAe,OAAO,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC;IAKnC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC;IACrC,OAAO,EAAE,CAAC;IACV,EAAE,EAAE,MAAM,GAAG,SAAS;IACtB,MAAM,EAAE,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,IAAI;IAPzD,SAAS,CAAC,QAAQ,CAAC,KAAK,YAAiB,IAAI,EAAI;IACjD,SAAS,CAAC,MAAM,UAAS;gBAGF,MAAM,EAAE,YAAY,CAAC,GAAG,CAAC,EACrC,OAAO,EAAE,CAAC,EACV,EAAE,EAAE,MAAM,GAAG,SAAS,EACtB,MAAM,GAAE,OAAO,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,GAAG,SAAS,GAAG,IAAW;IAUhE,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,EAAE,EAAE,CAAC;IAElF,KAAK,CAAC,MAAM,GAAE,MAAmB;IAkBjC,IAAI,IAAI,WAEP;IAED,IAAI,SAAS;;;;;;;MASZ;IAED,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,UAAU,GAAG,MAAM,CAAC;IAE/C,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,UAAQ;IAoBrD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,UAAQ;IAIpC;;;;;;;;;;;;;;;OAeG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,UAAQ,GAAG,MAAM,IAAI;CA6C7D;AAED,cAAM,cAAc,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5D,IAAI,SAAa;IAEjB,WAAW,CAAC,EAAE,SAAS,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,cAAc,CAAC,CAAC,EAAE,EAAE,CAAC;IAIhF,IAAI,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,UAAQ,GAAG,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;IAI3D,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,UAAQ,GAAG,MAAM,IAAI;IAIpG;;;;;;;;;;OAUG;IACG,KAAK,CACP,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EACtB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,GACnD,OAAO,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;cAiBd,MAAM;CAkBzB;AAED,cAAM,eAAe,CAAC,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC;IAC7D,IAAI,SAAc;IAElB,WAAW,CAAC,EAAE,SAAS,MAAM,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC,CAAC,EAAE,EAAE,CAAC;IAIjF,MAAM,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,UAAQ,GAAG,MAAM,IAAI;IAIlG,IAAI,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,IAAI,UAAQ,GAAG,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;CAGpE"}
@@ -1,102 +1,84 @@
1
1
  var __defProp = Object.defineProperty;
2
2
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
3
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
- function isTransferable(obj) {
5
- return transferrable.some((t) => obj instanceof t) ? obj : null;
6
- }
7
- function getTransferrable(data = {}) {
8
- if (!data) return [];
9
- return Object.values(data).reduce((r, v) => {
10
- return Array.isArray(v) ? [...r, ...v.map(isTransferable)] : [...r, isTransferable(v)];
11
- }, []).filter(Boolean);
12
- }
13
- const transferrable = typeof window !== "undefined" ? [
14
- ArrayBuffer,
15
- MessagePort,
16
- ReadableStream,
17
- WritableStream,
18
- TransformStream,
19
- // WebTransportReceiveStream, // ReferenceError: WebTransportReceiveStream is not defined
20
- // WebTransportSendStream, // ReferenceError: WebTransportReceiveStream is not defined
21
- // AudioData, // TS2304: Cannot find name AudioData
22
- ImageBitmap,
23
- VideoFrame,
24
- OffscreenCanvas,
25
- RTCDataChannel,
26
- MediaSourceHandle
27
- // MIDIAccess, // ReferenceError: MIDIAccess is not defined
28
- ].filter(Boolean) : [];
4
+ import { getTransferrable } from "./workerUtils.js";
29
5
  const ALL = "*";
30
- let id = 0;
31
- function getID() {
32
- return (++id).toString();
33
- }
6
+ const RESPONDER = Symbol("responder");
34
7
  function checkClosed(obj, label = "external") {
35
- if (obj == null ? void 0 : obj.closed) throw new Error(`Context is closed ${this.info} (${label})`, { cause: obj });
8
+ if (obj == null ? void 0 : obj.closed) throw new Error(`Context ${obj.id} is closed (${label})`, { cause: obj });
36
9
  }
37
10
  function checkMessage(obj, message) {
38
11
  if (!message) throw new Error("New context must have message", { cause: obj });
39
12
  }
40
13
  class WorkerDialog {
41
- constructor(worker, responders, name) {
14
+ // IDs are intentionally not global
15
+ constructor(worker, responders, name, debug = 0) {
42
16
  __publicField(this, "contexts", /* @__PURE__ */ new Set());
43
17
  __publicField(this, "closed", false);
18
+ __publicField(this, "currentId", 0);
19
+ var _a, _b;
44
20
  this.worker = worker;
45
21
  this.responders = responders;
46
22
  this.name = name;
23
+ this.debug = debug;
47
24
  if (!this.worker) return;
48
25
  for (const message in this.responders) {
49
- if (["constructor", "create"].includes(message)) continue;
26
+ if (!((_b = (_a = this.responders) == null ? void 0 : _a[message]) == null ? void 0 : _b[RESPONDER])) continue;
50
27
  const rootContext = new ResponseContext(this, message, ALL);
51
28
  rootContext.listen(async (data, context, event) => {
52
29
  const responseContext = context.withMessage(message, event.data.ctx.id);
53
- console.log("Root Listener", rootContext.info, {
54
- rootContext: context,
55
- data,
56
- responseContext,
57
- event,
58
- responder: this.responders[message]
59
- });
30
+ if (this.debug)
31
+ console.log("Root Listener", rootContext.info, {
32
+ rootContext: context,
33
+ data,
34
+ responseContext,
35
+ event,
36
+ responder: this.responders[message]
37
+ });
60
38
  try {
61
- responseContext.send(await this.responders[message](data, responseContext));
39
+ responseContext.send(await this.responders[message](data, responseContext), true);
62
40
  responseContext.close("root.listener");
63
41
  } catch (e) {
64
- console.error(`Error in responder ${responseContext.info}`, { e });
65
- responseContext.send(e);
42
+ if (this.debug) console.error(`Error in responder ${responseContext.info}`, { e });
43
+ responseContext.send(e, true);
66
44
  }
67
- });
45
+ }, true);
68
46
  }
69
47
  }
48
+ getID() {
49
+ return (++this.currentId).toString();
50
+ }
70
51
  close() {
71
52
  for (const context of this.contexts) context.close("root");
72
53
  this.contexts.clear();
73
- this.worker.onmessage = null;
74
54
  }
75
55
  withMessage(message) {
76
- return new RequestContext(this, message, getID());
56
+ return new RequestContext(this, message, this.getID());
77
57
  }
78
58
  }
79
59
  class RespondersBase {
80
60
  create(message, responder) {
61
+ responder[RESPONDER] = true;
81
62
  return responder;
82
63
  }
83
64
  }
84
65
  class Context {
85
- constructor(dialog, message, id2, parent = null) {
66
+ constructor(dialog, message, id, parent = null) {
86
67
  __publicField(this, "unsub", /* @__PURE__ */ new Set());
87
68
  __publicField(this, "closed", false);
88
- var _a;
89
69
  this.dialog = dialog;
90
70
  this.message = message;
91
- this.id = id2;
71
+ this.id = id;
92
72
  this.parent = parent;
93
- checkClosed(this.dialog, "newContext");
94
- checkClosed(this.parent, "newContext");
73
+ checkClosed(dialog, "newContext");
74
+ checkClosed(parent, "newContext");
95
75
  checkMessage(this, message);
96
- this.id = (parent == null ? void 0 : parent.id) === ALL ? getID() : id2 ? id2 : (_a = this.parent) == null ? void 0 : _a.id;
76
+ this.id = id ?? (parent == null ? void 0 : parent.id);
97
77
  if (!this.id) throw new Error("ID is required", { cause: this });
78
+ this.dialog.contexts.add(this);
98
79
  }
99
80
  close(reason = "external") {
81
+ if (this.dialog.debug >= 2) console.log("Closing", this.info, reason, this);
100
82
  this.dialog.contexts.delete(this);
101
83
  for (const unsub of this.unsub) unsub();
102
84
  this.unsub.clear();
@@ -108,27 +90,35 @@ class Context {
108
90
  }
109
91
  get info() {
110
92
  var _a;
111
- return this.dialog.name + "." + ((_a = this.parent) == null ? void 0 : _a.id) + "." + this.id + "." + this.message.toString();
93
+ return `${this.dialog.name}:${((_a = this.parent) == null ? void 0 : _a.id) ?? ALL}/${this.id}:${this.message.toString()}[${this.closed ? "closed" : "open"},${this.type}]`;
94
+ }
95
+ get debugInfo() {
96
+ var _a;
97
+ return {
98
+ id: this.id,
99
+ parentId: (_a = this.parent) == null ? void 0 : _a.id,
100
+ message: this.message,
101
+ closed: this.closed,
102
+ type: this.type,
103
+ listeners: this.unsub.size
104
+ };
112
105
  }
113
- postMessage(data) {
106
+ postMessage(data, done = false) {
114
107
  var _a;
115
108
  checkClosed(this, "postMessage");
116
109
  const transfer = getTransferrable(data);
117
- this.dialog.worker.postMessage(
118
- {
119
- data,
120
- ctx: {
121
- id: this.id,
122
- parentId: (_a = this.parent) == null ? void 0 : _a.id,
123
- message: this.message
124
- }
125
- },
126
- transfer
127
- );
110
+ const ctx = {
111
+ done,
112
+ id: this.id,
113
+ parentId: (_a = this.parent) == null ? void 0 : _a.id,
114
+ message: this.message
115
+ };
116
+ if (this.dialog.debug >= 3) console.log("postMessage", this.info, { ctx, data, transfer }, this);
117
+ this.dialog.worker.postMessage({ data, ctx }, transfer);
128
118
  return data;
129
119
  }
130
- send(data) {
131
- return this.postMessage(data);
120
+ send(data, done = false) {
121
+ return this.postMessage(data, done);
132
122
  }
133
123
  /**
134
124
  * Does not automatically close, assumes consumer will close
@@ -146,26 +136,29 @@ class Context {
146
136
  * un(); // closes
147
137
  * ```
148
138
  */
149
- listen(callback) {
139
+ listen(callback, done = false) {
150
140
  checkClosed(this, "listen");
151
- let workerListener;
141
+ const controller = new AbortController();
152
142
  this.dialog.worker.addEventListener(
153
143
  "message",
154
- workerListener = async (event) => {
144
+ async (event) => {
155
145
  try {
156
146
  const {
157
147
  data: { ctx, data }
158
148
  } = event;
159
- if (!ctx || this.id !== ALL && this.id !== ctx.id || this.message !== ctx.message) return;
160
- console.log("Shared listener event", this.info, this, event);
149
+ if (!ctx || this.id !== ALL && this.id !== ctx.id || this.message !== ctx.message || done && !ctx.done)
150
+ return;
151
+ if (this.dialog.debug) console.log("Listener event", this.info, event, this);
161
152
  await callback(data, this, event);
162
153
  } catch (e) {
163
- console.error(`Error in listener ${this.info}`, this, { event, e });
154
+ if (this.dialog.debug) console.error(`Error in listener ${this.info}`, this, { event, e });
164
155
  }
165
- }
156
+ },
157
+ { signal: controller.signal }
166
158
  );
167
159
  const unsub = () => {
168
- this.dialog.worker.removeEventListener("message", workerListener);
160
+ if (this.dialog.debug >= 2) console.log("Stop listening", this.info, this);
161
+ controller.abort();
169
162
  this.unsub.delete(unsub);
170
163
  };
171
164
  this.unsub.add(unsub);
@@ -173,14 +166,18 @@ class Context {
173
166
  }
174
167
  }
175
168
  class RequestContext extends Context {
176
- withMessage(message, id2) {
177
- return new RequestContext(this.dialog, message, id2, this);
169
+ constructor() {
170
+ super(...arguments);
171
+ __publicField(this, "type", "request");
172
+ }
173
+ withMessage(message, id) {
174
+ return new RequestContext(this.dialog, message, id, this);
178
175
  }
179
- send(data) {
180
- return super.send(data);
176
+ send(data, done = false) {
177
+ return super.send(data, done);
181
178
  }
182
- listen(callback) {
183
- return super.listen(callback);
179
+ listen(callback, done = false) {
180
+ return super.listen(callback, done);
184
181
  }
185
182
  /**
186
183
  * Returns response
@@ -194,12 +191,14 @@ class RequestContext extends Context {
194
191
  * })
195
192
  */
196
193
  async fetch(data, callback) {
194
+ checkClosed(this, "fetch");
197
195
  const res = await Promise.all([
198
196
  callback == null ? void 0 : callback(this),
199
197
  this.expect(),
200
198
  // will be closed in expect -> listener -> unsub
201
- this.send(data)
199
+ this.send(data, true)
202
200
  ]);
201
+ if (this.dialog.debug >= 2) console.log("Fetch", this.info, this);
203
202
  this.close("fetch");
204
203
  return res[1];
205
204
  }
@@ -210,28 +209,32 @@ class RequestContext extends Context {
210
209
  try {
211
210
  if (data instanceof Error) throw data;
212
211
  responseListener();
212
+ if (this.dialog.debug >= 3) console.log("Expect", this.info, data, this);
213
213
  resolve(data);
214
214
  } catch (e) {
215
215
  reject(e);
216
216
  }
217
- });
217
+ }, true);
218
218
  });
219
219
  }
220
220
  }
221
221
  class ResponseContext extends Context {
222
- withMessage(message, id2) {
223
- return new ResponseContext(this.dialog, message, id2, this);
222
+ constructor() {
223
+ super(...arguments);
224
+ __publicField(this, "type", "response");
225
+ }
226
+ withMessage(message, id) {
227
+ return new ResponseContext(this.dialog, message, id, this);
224
228
  }
225
- listen(callback) {
226
- return super.listen(callback);
229
+ listen(callback, done = false) {
230
+ return super.listen(callback, done);
227
231
  }
228
- send(data) {
229
- return super.send(data);
232
+ send(data, done = false) {
233
+ return super.send(data, done);
230
234
  }
231
235
  }
232
236
  export {
233
237
  RespondersBase,
234
- WorkerDialog,
235
- isTransferable
238
+ WorkerDialog
236
239
  };
237
240
  //# sourceMappingURL=worker.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker.js","sources":["../../src/core/worker.ts"],"sourcesContent":["export function isTransferable(obj: any): boolean {\n return transferrable.some((t) => obj instanceof t) ? obj : null;\n}\n\nfunction getTransferrable(data: any = {}): Transferable[] {\n if (!data) return [];\n return Object.values<any>(data)\n .reduce((r, v) => {\n return Array.isArray(v) ? [...r, ...v.map(isTransferable)] : [...r, isTransferable(v)];\n }, [])\n .filter(Boolean);\n}\n\n// @see https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects\nconst transferrable =\n typeof window !== 'undefined'\n ? [\n ArrayBuffer,\n MessagePort,\n ReadableStream,\n WritableStream,\n TransformStream,\n // WebTransportReceiveStream, // ReferenceError: WebTransportReceiveStream is not defined\n // WebTransportSendStream, // ReferenceError: WebTransportReceiveStream is not defined\n // AudioData, // TS2304: Cannot find name AudioData\n ImageBitmap,\n VideoFrame,\n OffscreenCanvas,\n RTCDataChannel,\n MediaSourceHandle,\n // MIDIAccess, // ReferenceError: MIDIAccess is not defined\n ].filter(Boolean)\n : [];\n\ntype WebWorker = Worker | (Window & typeof globalThis) | (WorkerGlobalScope & typeof globalThis);\n\ntype MethodReturn<R, M extends keyof R> = R[M] extends (...args: any[]) => any\n ? Partial<Awaited<ReturnType<R[M]>>>\n : never;\n\ntype MethodArg<R, M extends keyof R> = R[M] extends (arg: infer A, ...args: any[]) => any ? Partial<A> : never;\n\nexport type Ctx<R, K extends keyof R> = {\n id: string;\n parentId?: string;\n message: K;\n};\n\ntype Data<R, M extends keyof R> = MethodReturn<R, M> | MethodArg<R, M> | Error;\n\ntype Event<R, M extends keyof R> = MessageEvent<{ data: Data<R, M>; ctx: Ctx<R, M> }>;\n\ntype Listener<R, M extends keyof R, D extends Data<R, M> = Data<R, M>, S extends Context<R, M> = Context<R, M>> = (\n data: D,\n self: S,\n event: Event<R, M>,\n) => void | Promise<void>;\n\nconst ALL = '*';\n\nlet id = 0;\n\nfunction getID() {\n return (++id).toString();\n}\n\nfunction checkClosed(obj: any, label: string = 'external') {\n if (obj?.closed) throw new Error(`Context is closed ${this.info} (${label})`, { cause: obj });\n}\n\nfunction checkMessage(obj: any, message: any) {\n if (!message) throw new Error('New context must have message', { cause: obj });\n}\n\nexport class WorkerDialog<R extends RespondersBase<any>> {\n readonly contexts = new Set<Context<R, keyof R>>();\n protected closed = false;\n\n constructor(\n public worker: WebWorker,\n public responders: R,\n public name: string,\n ) {\n if (!this.worker) return; // Next.js SSR\n\n for (const message in this.responders) {\n if (['constructor', 'create'].includes(message)) continue;\n\n // root context with id=all\n const rootContext = new ResponseContext<R, typeof message>(this, message, ALL);\n\n //TODO: unsub(); ? Probably not needed, root must be always listening until closed by WorkerDialog\n rootContext.listen(async (data, context, event) => {\n // create sub context with ID\n const responseContext = context.withMessage(message, event.data.ctx.id);\n\n console.log('Root Listener', rootContext.info, {\n rootContext: context,\n data,\n responseContext,\n event,\n responder: this.responders[message],\n });\n\n try {\n responseContext.send(await (this.responders[message] as any)(data, responseContext));\n responseContext.close('root.listener');\n } catch (e) {\n console.error(`Error in responder ${responseContext.info}`, { e });\n responseContext.send(e);\n }\n });\n }\n }\n\n close() {\n for (const context of this.contexts) context.close('root');\n this.contexts.clear();\n this.worker.onmessage = null;\n }\n\n withMessage<M extends keyof R>(message: M) {\n return new RequestContext<R, M>(this, message, getID());\n }\n}\n\nexport class RespondersBase<R> {\n create<M extends keyof R, F extends (input: any, context: ResponseContext<R, M>) => any>(\n message: M,\n responder: F,\n ): F {\n return responder as any;\n }\n}\n\n// can only be used to create actual contexts, carries the context data\nabstract class Context<R, M extends keyof R> {\n protected readonly unsub = new Set<() => void>();\n protected closed = false;\n\n constructor(\n protected readonly dialog: WorkerDialog<any>,\n public message: M,\n public id: string | undefined,\n public parent: Context<R, keyof R> | undefined | null = null,\n ) {\n checkClosed(this.dialog, 'newContext');\n checkClosed(this.parent, 'newContext');\n checkMessage(this, message);\n this.id = parent?.id === ALL ? getID() : id ? id : this.parent?.id;\n if (!this.id) throw new Error('ID is required', { cause: this });\n }\n\n abstract withMessage<M2 extends keyof R>(message: M2, id?: string): Context<R, M2>;\n\n close(reason: string = 'external') {\n // console.log('Closing', this.id, reason, this);\n\n this.dialog.contexts.delete(this);\n\n // Unsubscribe from all listeners\n for (const unsub of this.unsub) unsub();\n this.unsub.clear();\n\n // Remove all child contexts\n this.dialog.contexts.forEach((context) => {\n if (context.parent?.id === this.id) context.close('parent');\n });\n\n this.closed = true;\n }\n\n get info() {\n return this.dialog.name + '.' + this.parent?.id + '.' + this.id + '.' + this.message.toString();\n }\n\n protected postMessage(data?: Data<R, M>) {\n checkClosed(this, 'postMessage');\n\n const transfer = getTransferrable(data);\n\n // console.log('postMessage', this.id, this, { mergedCtx, data, transfer });\n\n this.dialog.worker.postMessage(\n {\n data,\n ctx: {\n id: this.id,\n parentId: this.parent?.id,\n message: this.message,\n },\n },\n transfer,\n );\n\n return data;\n }\n\n send(data?: Data<R, M>) {\n return this.postMessage(data);\n }\n\n /**\n * Does not automatically close, assumes consumer will close\n *\n * ```ts\n * dialog.request('x').fetch((c) => {\n * c.response('x').listen(() => { ... }); // listens to \"x\", will be closed by upper level fetch\n * c.request('x').fetcH(y, (c) => { ... }); // closes\n * }) // closes\n *\n * const un = dialog.context('x').listen((e) => { ... }); // listens to 'x'\n * un(); // closes\n *\n * const un = dialog.context('x').listen((e) => { ... }); // listens to 'x'\n * un(); // closes\n * ```\n */\n listen(callback: Listener<R, M>): () => void {\n checkClosed(this, 'listen');\n\n let workerListener: any;\n\n this.dialog.worker.addEventListener(\n 'message',\n (workerListener = async (event: Event<R, M>) => {\n try {\n const {\n data: { ctx, data },\n } = event;\n\n if (!ctx || (this.id !== ALL && this.id !== ctx.id) || this.message !== ctx.message) return; // unknown message from devtools etc., or different context\n\n console.log('Shared listener event', this.info, this, event);\n\n await callback(data, this, event); // Requests can come here, but they're typed in responders\n } catch (e) {\n console.error(`Error in listener ${this.info}`, this, { event, e });\n }\n }),\n );\n\n const unsub = () => {\n // console.log('Stop listening', this.id, this);\n this.dialog.worker.removeEventListener('message', workerListener);\n this.unsub.delete(unsub);\n };\n\n this.unsub.add(unsub);\n\n return unsub;\n }\n}\n\nclass RequestContext<R, M extends keyof R> extends Context<R, M> {\n withMessage<M2 extends keyof R>(message: M2, id?: string): RequestContext<R, M2> {\n return new RequestContext<R, M2>(this.dialog, message, id, this);\n }\n\n send(data?: MethodArg<R, M>): MethodArg<R, M> {\n return super.send(data) as any;\n }\n\n listen(callback: Listener<R, M, MethodReturn<R, M>, RequestContext<R, M>>): () => void {\n return super.listen(callback);\n }\n\n /**\n * Returns response\n * If you need to work with ctx, use callback\n * Closed automatically on response\n *\n * dialog.fetch('x', (c) => {\n * c.listen(() => { ... }); // will be closed by upper level fetch\n * c.fetcH(y, (c) => { ... }); // closes c\n * c.context().fetcH(y, (c) => { ... }); // closes sub, not closes c, will be closed by upper level fetch\n * })\n */\n async fetch(\n data?: MethodArg<R, M>,\n callback?: (context: RequestContext<R, M>) => void,\n ): Promise<MethodReturn<R, M>> {\n const res = await Promise.all([\n callback?.(this),\n this.expect(), // will be closed in expect -> listener -> unsub\n this.send(data),\n ]);\n\n // console.log('Fetch', this.id, this.contexts, this.ownContexts);\n\n this.close('fetch');\n\n return res[1];\n }\n\n protected async expect() {\n checkClosed(this, 'expect');\n\n //FIXME Manual promise type\n return new Promise<MethodReturn<R, M>>((resolve, reject) => {\n const responseListener = this.listen(async (data) => {\n try {\n if ((data as any) instanceof Error) throw data;\n responseListener();\n // console.log('Expect', this.id, this, eventData);\n resolve(data as any);\n } catch (e) {\n reject(e);\n }\n });\n });\n }\n}\n\nclass ResponseContext<R, M extends keyof R> extends Context<R, M> {\n withMessage<M2 extends keyof R>(message: M2, id?: string): ResponseContext<R, M2> {\n return new ResponseContext<R, M2>(this.dialog, message, id, this);\n }\n\n listen(callback: Listener<R, M, MethodArg<R, M>, ResponseContext<R, M>>): () => void {\n return super.listen(callback);\n }\n\n send(data?: MethodReturn<R, M>): MethodReturn<R, M> {\n return super.send(data) as any;\n }\n}\n"],"names":["id"],"mappings":"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"}
1
+ {"version":3,"file":"worker.js","sources":["../../src/core/worker.ts"],"sourcesContent":["import { getTransferrable } from './workerUtils';\n\n// Types\n\ntype WebWorker = Worker | (Window & typeof globalThis) | (WorkerGlobalScope & typeof globalThis);\n\ntype MethodReturn<R, M extends keyof R> = R[M] extends (...args: any[]) => any\n ? Partial<Awaited<ReturnType<R[M]>>>\n : never;\n\ntype MethodArg<R, M extends keyof R> = R[M] extends (arg: infer A, ...args: any[]) => any ? Partial<A> : never;\n\nexport type Ctx<R, K extends keyof R> = {\n id: string;\n parentId?: string;\n message: K;\n done: boolean;\n};\n\ntype Data<R, M extends keyof R> = MethodReturn<R, M> | MethodArg<R, M> | Error;\n\ntype Event<R, M extends keyof R> = MessageEvent<{ data: Data<R, M>; ctx: Ctx<R, M> }>;\n\ntype Listener<R, M extends keyof R, D extends Data<R, M> = Data<R, M>, S extends Context<R, M> = Context<R, M>> = (\n data: D,\n self: S,\n event: Event<R, M>,\n) => void | Promise<void>;\n\n// Constants\n\nconst ALL = '*';\n\nconst RESPONDER = Symbol('responder');\n\nfunction checkClosed(obj: any, label: string = 'external') {\n if (obj?.closed) throw new Error(`Context ${obj.id} is closed (${label})`, { cause: obj });\n}\n\nfunction checkMessage(obj: any, message: any) {\n if (!message) throw new Error('New context must have message', { cause: obj });\n}\n\n// Classes\n\nexport class WorkerDialog<R extends RespondersBase<any>> {\n readonly contexts = new Set<Context<R, keyof R>>();\n protected closed = false;\n protected currentId = 0; // IDs are intentionally not global\n\n constructor(\n public worker: WebWorker,\n public responders: R,\n public name: string,\n public debug: number = 0, // 0 - none, 1 - general messages, 2 - sub/unsub, 3 - transport TODO Object?\n ) {\n if (!this.worker) return; // Next.js SSR\n\n for (const message in this.responders) {\n if (!this.responders?.[message]?.[RESPONDER]) continue;\n\n // root context with id=all\n const rootContext = new ResponseContext<R, typeof message>(this, message, ALL);\n\n //TODO: unsub(); ? Probably not needed, root must be always listening until closed by WorkerDialog\n rootContext.listen(async (data, context, event) => {\n // create sub context with ID\n const responseContext = context.withMessage(message, event.data.ctx.id);\n\n /* v8 ignore start */\n if (this.debug)\n console.log('Root Listener', rootContext.info, {\n rootContext: context,\n data,\n responseContext,\n event,\n responder: this.responders[message],\n });\n /* v8 ignore stop */\n\n try {\n responseContext.send(await (this.responders[message] as any)(data, responseContext), true);\n responseContext.close('root.listener');\n } catch (e) {\n /* v8 ignore next */\n if (this.debug) console.error(`Error in responder ${responseContext.info}`, { e });\n responseContext.send(e, true);\n }\n }, true);\n }\n }\n\n getID() {\n return (++this.currentId).toString();\n }\n\n close() {\n for (const context of this.contexts) context.close('root');\n this.contexts.clear();\n }\n\n withMessage<M extends keyof R>(message: M) {\n return new RequestContext<R, M>(this, message, this.getID()); // always new context\n }\n}\n\nexport class RespondersBase<R> {\n create<M extends keyof R, F extends (input: any, context: ResponseContext<R, M>) => any>(\n message: M,\n responder: F,\n ): F {\n responder[RESPONDER] = true;\n return responder as any;\n }\n}\n\n// can only be used to create actual contexts, carries the context data\nabstract class Context<R, M extends keyof R> {\n protected readonly unsub = new Set<() => void>();\n protected closed = false;\n\n constructor(\n protected readonly dialog: WorkerDialog<any>,\n public message: M,\n public id: string | undefined,\n public parent: Context<R, keyof R> | undefined | null = null,\n ) {\n checkClosed(dialog, 'newContext');\n checkClosed(parent, 'newContext');\n checkMessage(this, message);\n this.id = id ?? parent?.id;\n if (!this.id) throw new Error('ID is required', { cause: this });\n this.dialog.contexts.add(this);\n }\n\n abstract withMessage<M2 extends keyof R>(message: M2, id?: string): Context<R, M2>;\n\n close(reason: string = 'external') {\n /* v8 ignore next */\n if (this.dialog.debug >= 2) console.log('Closing', this.info, reason, this);\n\n this.dialog.contexts.delete(this);\n\n // Unsubscribe from all listeners\n for (const unsub of this.unsub) unsub();\n this.unsub.clear();\n\n // Remove all child contexts\n this.dialog.contexts.forEach((context) => {\n if (context.parent?.id === this.id) context.close('parent');\n });\n\n this.closed = true;\n }\n\n get info() {\n return `${this.dialog.name}:${this.parent?.id ?? ALL}/${this.id}:${this.message.toString()}[${this.closed ? 'closed' : 'open'},${this.type}]`;\n }\n\n get debugInfo() {\n return {\n id: this.id,\n parentId: this.parent?.id,\n message: this.message,\n closed: this.closed,\n type: this.type,\n listeners: this.unsub.size,\n };\n }\n\n abstract type: 'request' | 'response' | string;\n\n protected postMessage(data?: Data<R, M>, done = false) {\n checkClosed(this, 'postMessage');\n\n const transfer = getTransferrable(data);\n\n const ctx = {\n done,\n id: this.id,\n parentId: this.parent?.id,\n message: this.message,\n };\n\n /* v8 ignore next */\n if (this.dialog.debug >= 3) console.log('postMessage', this.info, { ctx, data, transfer }, this);\n\n this.dialog.worker.postMessage({ data, ctx }, transfer);\n\n return data;\n }\n\n send(data?: Data<R, M>, done = false) {\n return this.postMessage(data, done);\n }\n\n /**\n * Does not automatically close, assumes consumer will close\n *\n * ```ts\n * dialog.request('x').fetch((c) => {\n * c.response('x').listen(() => { ... }); // listens to \"x\", will be closed by upper level fetch\n * c.request('x').fetcH(y, (c) => { ... }); // closes\n * }) // closes\n *\n * const un = dialog.context('x').listen((e) => { ... }); // listens to 'x'\n * un(); // closes\n *\n * const un = dialog.context('x').listen((e) => { ... }); // listens to 'x'\n * un(); // closes\n * ```\n */\n listen(callback: Listener<R, M>, done = false): () => void {\n checkClosed(this, 'listen');\n\n const controller = new AbortController();\n\n this.dialog.worker.addEventListener(\n 'message',\n async (event: Event<R, M>) => {\n try {\n const {\n data: { ctx, data },\n } = event;\n\n if (\n !ctx ||\n (this.id !== ALL && this.id !== ctx.id) ||\n this.message !== ctx.message ||\n (done && !ctx.done)\n )\n return; // unknown message from devtools etc., or different context\n\n /* v8 ignore next */\n if (this.dialog.debug) console.log('Listener event', this.info, event, this);\n\n await callback(data, this, event); // Requests can come here, but they're typed in responders\n } catch (e) {\n /* v8 ignore next */\n if (this.dialog.debug) console.error(`Error in listener ${this.info}`, this, { event, e });\n //TODO Respond with error?\n }\n },\n { signal: controller.signal },\n );\n\n const unsub = () => {\n /* v8 ignore next */\n if (this.dialog.debug >= 2) console.log('Stop listening', this.info, this);\n controller.abort();\n this.unsub.delete(unsub);\n };\n\n this.unsub.add(unsub);\n\n return unsub;\n }\n}\n\nclass RequestContext<R, M extends keyof R> extends Context<R, M> {\n type = 'request';\n\n withMessage<M2 extends keyof R>(message: M2, id?: string): RequestContext<R, M2> {\n return new RequestContext<R, M2>(this.dialog, message, id, this);\n }\n\n send(data?: MethodArg<R, M>, done = false): MethodArg<R, M> {\n return super.send(data, done) as any;\n }\n\n listen(callback: Listener<R, M, MethodReturn<R, M>, RequestContext<R, M>>, done = false): () => void {\n return super.listen(callback, done);\n }\n\n /**\n * Returns response\n * If you need to work with ctx, use callback\n * Closed automatically on response\n *\n * dialog.fetch('x', (c) => {\n * c.listen(() => { ... }); // will be closed by upper level fetch\n * c.fetcH(y, (c) => { ... }); // closes c\n * c.context().fetcH(y, (c) => { ... }); // closes sub, not closes c, will be closed by upper level fetch\n * })\n */\n async fetch(\n data?: MethodArg<R, M>,\n callback?: (context: RequestContext<R, M>) => void,\n ): Promise<MethodReturn<R, M>> {\n checkClosed(this, 'fetch');\n\n const res = await Promise.all([\n callback?.(this),\n this.expect(), // will be closed in expect -> listener -> unsub\n this.send(data, true),\n ]);\n\n /* v8 ignore next */\n if (this.dialog.debug >= 2) console.log('Fetch', this.info, this);\n\n this.close('fetch');\n\n return res[1];\n }\n\n protected async expect() {\n checkClosed(this, 'expect');\n\n //FIXME Manual promise type\n return new Promise<MethodReturn<R, M>>((resolve, reject) => {\n const responseListener = this.listen(async (data) => {\n try {\n if ((data as any) instanceof Error) throw data;\n responseListener();\n /* v8 ignore next */\n if (this.dialog.debug >= 3) console.log('Expect', this.info, data, this);\n resolve(data as any);\n } catch (e) {\n reject(e);\n }\n }, true);\n });\n }\n}\n\nclass ResponseContext<R, M extends keyof R> extends Context<R, M> {\n type = 'response';\n\n withMessage<M2 extends keyof R>(message: M2, id?: string): ResponseContext<R, M2> {\n return new ResponseContext<R, M2>(this.dialog, message, id, this);\n }\n\n listen(callback: Listener<R, M, MethodArg<R, M>, ResponseContext<R, M>>, done = false): () => void {\n return super.listen(callback, done);\n }\n\n send(data?: MethodReturn<R, M>, done = false): MethodReturn<R, M> {\n return super.send(data, done) as any;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=worker.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker.test.d.ts","sourceRoot":"","sources":["../../src/core/worker.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,3 @@
1
+ export declare function isTransferable(obj: any): boolean;
2
+ export declare function getTransferrable(data?: any): Transferable[];
3
+ //# sourceMappingURL=workerUtils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workerUtils.d.ts","sourceRoot":"","sources":["../../src/core/workerUtils.ts"],"names":[],"mappings":"AAoBA,wBAAgB,cAAc,CAAC,GAAG,EAAE,GAAG,GAAG,OAAO,CAEhD;AAED,wBAAgB,gBAAgB,CAAC,IAAI,GAAE,GAAQ,GAAG,YAAY,EAAE,CAO/D"}