@telperion/messenger 7.6.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 (136) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +600 -0
  3. package/broadcast/default-channel-name.cjs +4 -0
  4. package/broadcast/default-channel-name.d.ts +1 -0
  5. package/broadcast/default-channel-name.js +3 -0
  6. package/broadcast/default-channel-name.js.map +1 -0
  7. package/broadcast/index.cjs +13 -0
  8. package/broadcast/index.d.ts +5 -0
  9. package/broadcast/index.js +7 -0
  10. package/broadcast/index.js.map +1 -0
  11. package/broadcast/message-client.cjs +26 -0
  12. package/broadcast/message-client.d.ts +12 -0
  13. package/broadcast/message-client.js +24 -0
  14. package/broadcast/message-client.js.map +1 -0
  15. package/broadcast/message-host.cjs +28 -0
  16. package/broadcast/message-host.d.ts +9 -0
  17. package/broadcast/message-host.js +26 -0
  18. package/broadcast/message-host.js.map +1 -0
  19. package/broadcast/message-service.cjs +13 -0
  20. package/broadcast/message-service.d.ts +8 -0
  21. package/broadcast/message-service.js +11 -0
  22. package/broadcast/message-service.js.map +1 -0
  23. package/chrome/default-connection-name.cjs +4 -0
  24. package/chrome/default-connection-name.d.ts +1 -0
  25. package/chrome/default-connection-name.js +3 -0
  26. package/chrome/default-connection-name.js.map +1 -0
  27. package/chrome/index.cjs +11 -0
  28. package/chrome/index.d.ts +4 -0
  29. package/chrome/index.js +6 -0
  30. package/chrome/index.js.map +1 -0
  31. package/chrome/message-client.cjs +41 -0
  32. package/chrome/message-client.d.ts +15 -0
  33. package/chrome/message-client.js +39 -0
  34. package/chrome/message-client.js.map +1 -0
  35. package/chrome/message-host.cjs +43 -0
  36. package/chrome/message-host.d.ts +9 -0
  37. package/chrome/message-host.js +41 -0
  38. package/chrome/message-host.js.map +1 -0
  39. package/docs/images/broadcast-communication.svg +87 -0
  40. package/docs/images/chrome-extension-communication.svg +110 -0
  41. package/docs/images/core-architecture.svg +59 -0
  42. package/docs/images/iframe-communication.svg +74 -0
  43. package/docs/images/worker-communication.svg +75 -0
  44. package/iframe/channel-path-splitter.cjs +4 -0
  45. package/iframe/channel-path-splitter.d.ts +1 -0
  46. package/iframe/channel-path-splitter.js +3 -0
  47. package/iframe/channel-path-splitter.js.map +1 -0
  48. package/iframe/default-channel-name.cjs +4 -0
  49. package/iframe/default-channel-name.d.ts +1 -0
  50. package/iframe/default-channel-name.js +3 -0
  51. package/iframe/default-channel-name.js.map +1 -0
  52. package/iframe/iframe.type.cjs +2 -0
  53. package/iframe/iframe.type.d.ts +1 -0
  54. package/iframe/iframe.type.js +3 -0
  55. package/iframe/iframe.type.js.map +1 -0
  56. package/iframe/index.cjs +13 -0
  57. package/iframe/index.d.ts +6 -0
  58. package/iframe/index.js +7 -0
  59. package/iframe/index.js.map +1 -0
  60. package/iframe/message-client.cjs +50 -0
  61. package/iframe/message-client.d.ts +14 -0
  62. package/iframe/message-client.js +48 -0
  63. package/iframe/message-client.js.map +1 -0
  64. package/iframe/message-host.cjs +63 -0
  65. package/iframe/message-host.d.ts +11 -0
  66. package/iframe/message-host.js +61 -0
  67. package/iframe/message-host.js.map +1 -0
  68. package/iframe/message-service.cjs +13 -0
  69. package/iframe/message-service.d.ts +9 -0
  70. package/iframe/message-service.js +11 -0
  71. package/iframe/message-service.js.map +1 -0
  72. package/iframe/source-id-splitter.cjs +4 -0
  73. package/iframe/source-id-splitter.d.ts +1 -0
  74. package/iframe/source-id-splitter.js +3 -0
  75. package/iframe/source-id-splitter.js.map +1 -0
  76. package/iframe/upcoming-message.cjs +2 -0
  77. package/iframe/upcoming-message.d.ts +4 -0
  78. package/iframe/upcoming-message.js +3 -0
  79. package/iframe/upcoming-message.js.map +1 -0
  80. package/index.cjs +13 -0
  81. package/index.d.ts +7 -0
  82. package/index.js +7 -0
  83. package/index.js.map +1 -0
  84. package/listen.decorator.cjs +20 -0
  85. package/listen.decorator.d.ts +6 -0
  86. package/listen.decorator.js +19 -0
  87. package/listen.decorator.js.map +1 -0
  88. package/listener-storage.type.cjs +2 -0
  89. package/listener-storage.type.d.ts +2 -0
  90. package/listener-storage.type.js +3 -0
  91. package/listener-storage.type.js.map +1 -0
  92. package/message-client.cjs +10 -0
  93. package/message-client.d.ts +23 -0
  94. package/message-client.js +8 -0
  95. package/message-client.js.map +1 -0
  96. package/message-host.cjs +58 -0
  97. package/message-host.d.ts +26 -0
  98. package/message-host.js +56 -0
  99. package/message-host.js.map +1 -0
  100. package/message-response.type.cjs +2 -0
  101. package/message-response.type.d.ts +16 -0
  102. package/message-response.type.js +3 -0
  103. package/message-response.type.js.map +1 -0
  104. package/message.interface.cjs +2 -0
  105. package/message.interface.d.ts +6 -0
  106. package/message.interface.js +3 -0
  107. package/message.interface.js.map +1 -0
  108. package/package.json +158 -0
  109. package/request.decorator.cjs +20 -0
  110. package/request.decorator.d.ts +1 -0
  111. package/request.decorator.js +19 -0
  112. package/request.decorator.js.map +1 -0
  113. package/selectors.cjs +10 -0
  114. package/selectors.d.ts +7 -0
  115. package/selectors.js +9 -0
  116. package/selectors.js.map +1 -0
  117. package/worker/index.cjs +13 -0
  118. package/worker/index.d.ts +5 -0
  119. package/worker/index.js +7 -0
  120. package/worker/index.js.map +1 -0
  121. package/worker/initializer.cjs +39 -0
  122. package/worker/initializer.d.ts +12 -0
  123. package/worker/initializer.js +38 -0
  124. package/worker/initializer.js.map +1 -0
  125. package/worker/message-client.cjs +158 -0
  126. package/worker/message-client.d.ts +131 -0
  127. package/worker/message-client.js +156 -0
  128. package/worker/message-client.js.map +1 -0
  129. package/worker/message-host.cjs +165 -0
  130. package/worker/message-host.d.ts +131 -0
  131. package/worker/message-host.js +163 -0
  132. package/worker/message-host.js.map +1 -0
  133. package/worker/message-service.cjs +123 -0
  134. package/worker/message-service.d.ts +117 -0
  135. package/worker/message-service.js +121 -0
  136. package/worker/message-service.js.map +1 -0
@@ -0,0 +1,12 @@
1
+ import { Subject } from "rxjs";
2
+ import { MessageClient } from "../message-client";
3
+ import { MessageResponse } from "../message-response.type";
4
+ import { Message } from "../message.interface";
5
+ import { GET_NEW_ID, RESPONSES$, SEND } from "../selectors";
6
+ export declare class BroadcastMessageClient extends MessageClient {
7
+ #private;
8
+ protected [RESPONSES$]: Subject<MessageResponse>;
9
+ constructor(channelName?: string);
10
+ protected [SEND]<T>(message: Message<T>): void;
11
+ protected [GET_NEW_ID](): string;
12
+ }
@@ -0,0 +1,24 @@
1
+ import { Subject } from "rxjs";
2
+ import { MessageClient } from "../message-client";
3
+ import { GET_NEW_ID, RESPONSES$, SEND } from "../selectors";
4
+ import { DEFAULT_CHANNEL_NAME } from "./default-channel-name";
5
+ export class BroadcastMessageClient extends MessageClient {
6
+ [RESPONSES$] = new Subject();
7
+ #channel;
8
+ constructor(channelName = DEFAULT_CHANNEL_NAME) {
9
+ super();
10
+ this.#channel = new BroadcastChannel(channelName);
11
+ this.#channel.addEventListener('message', this.#handler);
12
+ }
13
+ [SEND](message) {
14
+ this.#channel.postMessage(message);
15
+ }
16
+ #handler = (event) => {
17
+ this[RESPONSES$].next(event.data);
18
+ };
19
+ [GET_NEW_ID]() {
20
+ return crypto.randomUUID();
21
+ }
22
+ }
23
+
24
+ //# sourceMappingURL=message-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../libs/messenger/src/broadcast/message-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAM9D,MAAM,OAAO,sBAAuB,SAAQ,aAAa;IAC7C,CAAC,UAAU,CAAC,GAAG,IAAI,OAAO,EAAmB,CAAC;IAExD,QAAQ,CAAmB;IAE3B,YAAY,WAAW,GAAG,oBAAoB;QAC5C,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAElD,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAES,CAAC,IAAI,CAAC,CAAI,OAAmB;QACrC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,QAAQ,GAAG,CAAC,KAAoC,EAAE,EAAE;QAClD,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC,CAAC;IAEQ,CAAC,UAAU,CAAC;QACpB,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC;IAC7B,CAAC;CACF","file":"message-client.js","sourcesContent":["import { Subject } from \"rxjs\";\nimport { MessageClient } from \"../message-client\";\nimport { MessageResponse } from \"../message-response.type\";\nimport { Message } from \"../message.interface\";\nimport { GET_NEW_ID, RESPONSES$, SEND } from \"../selectors\";\nimport { DEFAULT_CHANNEL_NAME } from \"./default-channel-name\";\n\ninterface MessageEvent<T> {\n data: T;\n}\n\nexport class BroadcastMessageClient extends MessageClient {\n protected [RESPONSES$] = new Subject<MessageResponse>();\n\n #channel: BroadcastChannel;\n\n constructor(channelName = DEFAULT_CHANNEL_NAME) {\n super();\n\n this.#channel = new BroadcastChannel(channelName);\n\n this.#channel.addEventListener('message', this.#handler);\n }\n\n protected [SEND]<T>(message: Message<T>) {\n this.#channel.postMessage(message);\n }\n\n #handler = (event: MessageEvent<MessageResponse>) => {\n this[RESPONSES$].next(event.data);\n };\n\n protected [GET_NEW_ID](): string {\n return crypto.randomUUID();\n }\n}"]}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BroadcastMessageHost = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const message_host_1 = require("../message-host");
6
+ const default_channel_name_1 = require("./default-channel-name");
7
+ const selectors_1 = require("../selectors");
8
+ class BroadcastMessageHost extends message_host_1.MessageHost {
9
+ #requests$ = new rxjs_1.Subject();
10
+ #channel;
11
+ constructor(channelName = default_channel_name_1.DEFAULT_CHANNEL_NAME) {
12
+ super();
13
+ this.#channel = new BroadcastChannel(channelName);
14
+ this.#channel.addEventListener('message', this.#handler);
15
+ this[selectors_1.LISTEN](this.#requests$);
16
+ }
17
+ [selectors_1.RESPONSE](message) {
18
+ this.#channel.postMessage(message);
19
+ }
20
+ terminate() {
21
+ this.#channel.removeEventListener('message', this.#handler);
22
+ this.#channel.close();
23
+ }
24
+ #handler = (event) => {
25
+ this.#requests$.next(event.data);
26
+ };
27
+ }
28
+ exports.BroadcastMessageHost = BroadcastMessageHost;
@@ -0,0 +1,9 @@
1
+ import { MessageHost } from "../message-host";
2
+ import { MessageResponse } from "../message-response.type";
3
+ import { RESPONSE } from "../selectors";
4
+ export declare class BroadcastMessageHost extends MessageHost {
5
+ #private;
6
+ constructor(channelName?: string);
7
+ protected [RESPONSE](message: MessageResponse): void;
8
+ terminate(): void;
9
+ }
@@ -0,0 +1,26 @@
1
+ import { Subject } from "rxjs";
2
+ import { MessageHost } from "../message-host";
3
+ import { DEFAULT_CHANNEL_NAME } from "./default-channel-name";
4
+ import { LISTEN, RESPONSE } from "../selectors";
5
+ export class BroadcastMessageHost extends MessageHost {
6
+ #requests$ = new Subject();
7
+ #channel;
8
+ constructor(channelName = DEFAULT_CHANNEL_NAME) {
9
+ super();
10
+ this.#channel = new BroadcastChannel(channelName);
11
+ this.#channel.addEventListener('message', this.#handler);
12
+ this[LISTEN](this.#requests$);
13
+ }
14
+ [RESPONSE](message) {
15
+ this.#channel.postMessage(message);
16
+ }
17
+ terminate() {
18
+ this.#channel.removeEventListener('message', this.#handler);
19
+ this.#channel.close();
20
+ }
21
+ #handler = (event) => {
22
+ this.#requests$.next(event.data);
23
+ };
24
+ }
25
+
26
+ //# sourceMappingURL=message-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../libs/messenger/src/broadcast/message-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAMhD,MAAM,OAAO,oBAAqB,SAAQ,WAAW;IACnD,UAAU,GAAG,IAAI,OAAO,EAAW,CAAC;IACpC,QAAQ,CAAmB;IAE3B,YAAY,WAAW,GAAG,oBAAoB;QAC5C,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,QAAQ,GAAG,IAAI,gBAAgB,CAAC,WAAW,CAAC,CAAC;QAElD,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzD,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IAES,CAAC,QAAQ,CAAC,CAAC,OAAwB;QAC3C,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAED,SAAS;QACP,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5D,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;IACxB,CAAC;IAED,QAAQ,GAAG,CAAC,KAA4B,EAAE,EAAE;QAC1C,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,CAAC,CAAC;CACH","file":"message-host.js","sourcesContent":["import { Subject } from \"rxjs\";\nimport { MessageHost } from \"../message-host\";\nimport { MessageResponse } from \"../message-response.type\";\nimport { Message } from \"../message.interface\";\nimport { DEFAULT_CHANNEL_NAME } from \"./default-channel-name\";\nimport { LISTEN, RESPONSE } from \"../selectors\";\n\ninterface MessageEvent<T> {\n data: T;\n}\n\nexport class BroadcastMessageHost extends MessageHost {\n #requests$ = new Subject<Message>();\n #channel: BroadcastChannel;\n\n constructor(channelName = DEFAULT_CHANNEL_NAME) {\n super();\n\n this.#channel = new BroadcastChannel(channelName);\n\n this.#channel.addEventListener('message', this.#handler);\n this[LISTEN](this.#requests$);\n }\n\n protected [RESPONSE](message: MessageResponse) {\n this.#channel.postMessage(message);\n }\n\n terminate() {\n this.#channel.removeEventListener('message', this.#handler);\n this.#channel.close();\n }\n\n #handler = (event: MessageEvent<Message>) => {\n this.#requests$.next(event.data);\n };\n}\n"]}
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BroadcastMessageService = void 0;
4
+ const mixin_1 = require("@telperion/js-utils/class/mixin");
5
+ const default_channel_name_1 = require("./default-channel-name");
6
+ const message_client_1 = require("./message-client");
7
+ const message_host_1 = require("./message-host");
8
+ class BroadcastMessageService extends (0, mixin_1.mixin)(message_host_1.BroadcastMessageHost, message_client_1.BroadcastMessageClient) {
9
+ constructor(channelName = default_channel_name_1.DEFAULT_CHANNEL_NAME) {
10
+ super([channelName], [channelName]);
11
+ }
12
+ }
13
+ exports.BroadcastMessageService = BroadcastMessageService;
@@ -0,0 +1,8 @@
1
+ import { BroadcastMessageClient } from "./message-client";
2
+ declare const BroadcastMessageService_base: new (args_0: [channelName?: string | undefined], args_1: [channelName?: string | undefined]) => {
3
+ terminate: () => void;
4
+ } & BroadcastMessageClient;
5
+ export declare class BroadcastMessageService extends BroadcastMessageService_base {
6
+ constructor(channelName?: string);
7
+ }
8
+ export {};
@@ -0,0 +1,11 @@
1
+ import { mixin } from "@telperion/js-utils/class/mixin";
2
+ import { DEFAULT_CHANNEL_NAME } from "./default-channel-name";
3
+ import { BroadcastMessageClient } from "./message-client";
4
+ import { BroadcastMessageHost } from "./message-host";
5
+ export class BroadcastMessageService extends mixin(BroadcastMessageHost, BroadcastMessageClient) {
6
+ constructor(channelName = DEFAULT_CHANNEL_NAME) {
7
+ super([channelName], [channelName]);
8
+ }
9
+ }
10
+
11
+ //# sourceMappingURL=message-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../libs/messenger/src/broadcast/message-service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,iCAAiC,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEtD,MAAM,OAAO,uBAAwB,SAAQ,KAAK,CAAC,oBAAoB,EAAE,sBAAsB,CAAC;IAC9F,YAAY,WAAW,GAAG,oBAAoB;QAC5C,KAAK,CAAC,CAAC,WAAW,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC;IACtC,CAAC;CACF","file":"message-service.js","sourcesContent":["import { mixin } from \"@telperion/js-utils/class/mixin\";\nimport { DEFAULT_CHANNEL_NAME } from \"./default-channel-name\";\nimport { BroadcastMessageClient } from \"./message-client\";\nimport { BroadcastMessageHost } from \"./message-host\";\n\nexport class BroadcastMessageService extends mixin(BroadcastMessageHost, BroadcastMessageClient) {\n constructor(channelName = DEFAULT_CHANNEL_NAME) {\n super([channelName], [channelName]);\n }\n}\n"]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DEFAULT_CONNECTION_NAME = void 0;
4
+ exports.DEFAULT_CONNECTION_NAME = 'MESSENGER_DEFAULT_CONNECTION';
@@ -0,0 +1 @@
1
+ export declare const DEFAULT_CONNECTION_NAME = "MESSENGER_DEFAULT_CONNECTION";
@@ -0,0 +1,3 @@
1
+ export const DEFAULT_CONNECTION_NAME = 'MESSENGER_DEFAULT_CONNECTION';
2
+
3
+ //# sourceMappingURL=default-connection-name.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../libs/messenger/src/chrome/default-connection-name.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG,8BAA8B,CAAC","file":"default-connection-name.js","sourcesContent":["export const DEFAULT_CONNECTION_NAME = 'MESSENGER_DEFAULT_CONNECTION';\n"]}
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChromeMessageHost = exports.ChromeMessageClient = exports.Listen = exports.Request = void 0;
4
+ var request_decorator_1 = require("../request.decorator");
5
+ Object.defineProperty(exports, "Request", { enumerable: true, get: function () { return request_decorator_1.Request; } });
6
+ var listen_decorator_1 = require("../listen.decorator");
7
+ Object.defineProperty(exports, "Listen", { enumerable: true, get: function () { return listen_decorator_1.Listen; } });
8
+ var message_client_1 = require("./message-client");
9
+ Object.defineProperty(exports, "ChromeMessageClient", { enumerable: true, get: function () { return message_client_1.ChromeMessageClient; } });
10
+ var message_host_1 = require("./message-host");
11
+ Object.defineProperty(exports, "ChromeMessageHost", { enumerable: true, get: function () { return message_host_1.ChromeMessageHost; } });
@@ -0,0 +1,4 @@
1
+ export { Request } from '../request.decorator';
2
+ export { Listen } from '../listen.decorator';
3
+ export { ChromeMessageClient } from './message-client';
4
+ export { ChromeMessageHost } from './message-host';
@@ -0,0 +1,6 @@
1
+ export { Request } from '../request.decorator';
2
+ export { Listen } from '../listen.decorator';
3
+ export { ChromeMessageClient } from './message-client';
4
+ export { ChromeMessageHost } from './message-host';
5
+
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../libs/messenger/src/chrome/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC","file":"index.js","sourcesContent":["export { Request } from '../request.decorator';\nexport { Listen } from '../listen.decorator';\nexport { ChromeMessageClient } from './message-client';\nexport { ChromeMessageHost } from './message-host';\n"]}
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChromeMessageClient = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const operators_1 = require("rxjs/operators");
6
+ const message_client_1 = require("../message-client");
7
+ const selectors_1 = require("../selectors");
8
+ const default_connection_name_1 = require("./default-connection-name");
9
+ const RANDOM_ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
10
+ const RANDOM_ID_CHARS_LENGTH = RANDOM_ID_CHARS.length;
11
+ const PORT = Symbol('Port');
12
+ class ChromeMessageClient extends message_client_1.MessageClient {
13
+ static connections = {};
14
+ [selectors_1.RESPONSES$];
15
+ [PORT];
16
+ constructor(name = default_connection_name_1.DEFAULT_CONNECTION_NAME) {
17
+ super();
18
+ if (!(name in ChromeMessageClient.connections)) {
19
+ const port = chrome.runtime.connect({ name });
20
+ const responses = new rxjs_1.Observable(subscriber => {
21
+ port.onMessage.addListener((message) => {
22
+ subscriber.next(message);
23
+ });
24
+ }).pipe((0, operators_1.share)());
25
+ ChromeMessageClient.connections[name] = { port, responses };
26
+ }
27
+ this[PORT] = ChromeMessageClient.connections[name].port;
28
+ this[selectors_1.RESPONSES$] = ChromeMessageClient.connections[name].responses;
29
+ }
30
+ [selectors_1.SEND](message) {
31
+ this[PORT].postMessage(message);
32
+ }
33
+ [selectors_1.GET_NEW_ID]() {
34
+ let result = '' + Date.now();
35
+ for (let i = 0; i < 10; i++) {
36
+ result += RANDOM_ID_CHARS.charAt(Math.floor(Math.random() * RANDOM_ID_CHARS_LENGTH));
37
+ }
38
+ return result;
39
+ }
40
+ }
41
+ exports.ChromeMessageClient = ChromeMessageClient;
@@ -0,0 +1,15 @@
1
+ import { Observable } from 'rxjs';
2
+ import { MessageClient } from '../message-client';
3
+ import { MessageResponse } from '../message-response.type';
4
+ import { Message } from '../message.interface';
5
+ import { GET_NEW_ID, RESPONSES$, SEND } from '../selectors';
6
+ declare const PORT: unique symbol;
7
+ export declare class ChromeMessageClient extends MessageClient {
8
+ private static readonly connections;
9
+ [RESPONSES$]: Observable<MessageResponse>;
10
+ private [PORT];
11
+ constructor(name?: string);
12
+ [SEND]<T>(message: Message<T>): void;
13
+ protected [GET_NEW_ID](): string;
14
+ }
15
+ export {};
@@ -0,0 +1,39 @@
1
+ import { Observable } from 'rxjs';
2
+ import { share } from 'rxjs/operators';
3
+ import { MessageClient } from '../message-client';
4
+ import { GET_NEW_ID, RESPONSES$, SEND } from '../selectors';
5
+ import { DEFAULT_CONNECTION_NAME } from './default-connection-name';
6
+ const RANDOM_ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
7
+ const RANDOM_ID_CHARS_LENGTH = RANDOM_ID_CHARS.length;
8
+ const PORT = Symbol('Port');
9
+ export class ChromeMessageClient extends MessageClient {
10
+ static connections = {};
11
+ [RESPONSES$];
12
+ [PORT];
13
+ constructor(name = DEFAULT_CONNECTION_NAME) {
14
+ super();
15
+ if (!(name in ChromeMessageClient.connections)) {
16
+ const port = chrome.runtime.connect({ name });
17
+ const responses = new Observable(subscriber => {
18
+ port.onMessage.addListener((message) => {
19
+ subscriber.next(message);
20
+ });
21
+ }).pipe(share());
22
+ ChromeMessageClient.connections[name] = { port, responses };
23
+ }
24
+ this[PORT] = ChromeMessageClient.connections[name].port;
25
+ this[RESPONSES$] = ChromeMessageClient.connections[name].responses;
26
+ }
27
+ [SEND](message) {
28
+ this[PORT].postMessage(message);
29
+ }
30
+ [GET_NEW_ID]() {
31
+ let result = '' + Date.now();
32
+ for (let i = 0; i < 10; i++) {
33
+ result += RANDOM_ID_CHARS.charAt(Math.floor(Math.random() * RANDOM_ID_CHARS_LENGTH));
34
+ }
35
+ return result;
36
+ }
37
+ }
38
+
39
+ //# sourceMappingURL=message-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../libs/messenger/src/chrome/message-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAClC,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAEvC,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AAEpE,MAAM,eAAe,GAAG,gEAAgE,CAAC;AACzF,MAAM,sBAAsB,GAAG,eAAe,CAAC,MAAM,CAAC;AACtD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;AAO5B,MAAM,OAAO,mBAAoB,SAAQ,aAAa;IAC5C,MAAM,CAAU,WAAW,GAAkC,EAAE,CAAC;IAEjE,CAAC,UAAU,CAAC,CAA8B;IACzC,CAAC,IAAI,CAAC,CAAsB;IAEpC,YAAY,IAAI,GAAG,uBAAuB;QACxC,KAAK,EAAE,CAAC;QAER,IAAI,CAAC,CAAC,IAAI,IAAI,mBAAmB,CAAC,WAAW,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;YAC9C,MAAM,SAAS,GAAG,IAAI,UAAU,CAAkB,UAAU,CAAC,EAAE;gBAC7D,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,OAAwB,EAAE,EAAE;oBACtD,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBAC3B,CAAC,CAAC,CAAC;YACL,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC;YAEjB,mBAAmB,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC9D,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,GAAG,mBAAmB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC;QACxD,IAAI,CAAC,UAAU,CAAC,GAAG,mBAAmB,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC;IACrE,CAAC;IAEM,CAAC,IAAI,CAAC,CAAI,OAAmB;QAClC,IAAI,CAAC,IAAI,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IAClC,CAAC;IAES,CAAC,UAAU,CAAC;QACpB,IAAI,MAAM,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,IAAI,eAAe,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,sBAAsB,CAAC,CAAC,CAAC;QACvF,CAAC;QAED,OAAO,MAAM,CAAC;IAChB,CAAC","file":"message-client.js","sourcesContent":["import { Observable } from 'rxjs';\nimport { share } from 'rxjs/operators';\n\nimport { MessageClient } from '../message-client';\nimport { MessageResponse } from '../message-response.type';\nimport { Message } from '../message.interface';\nimport { GET_NEW_ID, RESPONSES$, SEND } from '../selectors';\nimport { DEFAULT_CONNECTION_NAME } from './default-connection-name';\n\nconst RANDOM_ID_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\nconst RANDOM_ID_CHARS_LENGTH = RANDOM_ID_CHARS.length;\nconst PORT = Symbol('Port');\n\ninterface Connection {\n port: chrome.runtime.Port;\n responses: Observable<MessageResponse>;\n}\n\nexport class ChromeMessageClient extends MessageClient {\n private static readonly connections: { [key: string]: Connection } = {};\n\n public [RESPONSES$]: Observable<MessageResponse>;\n private [PORT]: chrome.runtime.Port;\n\n constructor(name = DEFAULT_CONNECTION_NAME) {\n super();\n\n if (!(name in ChromeMessageClient.connections)) {\n const port = chrome.runtime.connect({ name });\n const responses = new Observable<MessageResponse>(subscriber => {\n port.onMessage.addListener((message: MessageResponse) => {\n subscriber.next(message);\n });\n }).pipe(share());\n\n ChromeMessageClient.connections[name] = { port, responses };\n }\n\n this[PORT] = ChromeMessageClient.connections[name].port;\n this[RESPONSES$] = ChromeMessageClient.connections[name].responses;\n }\n\n public [SEND]<T>(message: Message<T>) {\n this[PORT].postMessage(message);\n }\n\n protected [GET_NEW_ID](): string {\n let result = '' + Date.now();\n\n for (let i = 0; i < 10; i++) {\n result += RANDOM_ID_CHARS.charAt(Math.floor(Math.random() * RANDOM_ID_CHARS_LENGTH));\n }\n\n return result;\n }\n}\n"]}
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ChromeMessageHost = void 0;
4
+ const rxjs_1 = require("rxjs");
5
+ const message_host_1 = require("../message-host");
6
+ const default_connection_name_1 = require("./default-connection-name");
7
+ const selectors_1 = require("../selectors");
8
+ class ChromeMessageHost extends message_host_1.MessageHost {
9
+ static PORT_IDENTIFIER = 'portIdentifier';
10
+ #ports = {};
11
+ #requests = new rxjs_1.Subject();
12
+ constructor(name = default_connection_name_1.DEFAULT_CONNECTION_NAME) {
13
+ super();
14
+ chrome.runtime.onConnect.addListener((port) => {
15
+ if (port.name !== name) {
16
+ return;
17
+ }
18
+ port.onMessage.addListener((message, incomingMessagePort) => {
19
+ if (!this.#ports[incomingMessagePort.sender.tab.id]) {
20
+ this.#ports[incomingMessagePort.sender.tab.id] = incomingMessagePort;
21
+ incomingMessagePort.onDisconnect.addListener(disconnectedPort => {
22
+ delete this.#ports[disconnectedPort.sender.tab.id];
23
+ this[selectors_1.TERMINATE_MESSAGE$].next(message.id);
24
+ });
25
+ }
26
+ const newMessage = {
27
+ ...message,
28
+ id: `${message.id}&${ChromeMessageHost.PORT_IDENTIFIER}=${incomingMessagePort.sender.tab.id}`,
29
+ };
30
+ this.#requests.next(newMessage);
31
+ });
32
+ });
33
+ this[selectors_1.LISTEN](this.#requests);
34
+ }
35
+ [selectors_1.RESPONSE](message) {
36
+ const [messageId, portId] = message.id.split(`&${ChromeMessageHost.PORT_IDENTIFIER}=`);
37
+ message.id = messageId;
38
+ if (this.#ports[portId]) {
39
+ this.#ports[portId].postMessage(message);
40
+ }
41
+ }
42
+ }
43
+ exports.ChromeMessageHost = ChromeMessageHost;
@@ -0,0 +1,9 @@
1
+ import { MessageHost } from '../message-host';
2
+ import { SuccessfulMessageResponse } from '../message-response.type';
3
+ import { RESPONSE } from '../selectors';
4
+ export declare class ChromeMessageHost extends MessageHost {
5
+ #private;
6
+ private static readonly PORT_IDENTIFIER;
7
+ constructor(name?: string);
8
+ protected [RESPONSE](message: SuccessfulMessageResponse): void;
9
+ }
@@ -0,0 +1,41 @@
1
+ import { Subject } from 'rxjs';
2
+ import { MessageHost } from '../message-host';
3
+ import { DEFAULT_CONNECTION_NAME } from './default-connection-name';
4
+ import { LISTEN, RESPONSE, TERMINATE_MESSAGE$ } from '../selectors';
5
+ export class ChromeMessageHost extends MessageHost {
6
+ static PORT_IDENTIFIER = 'portIdentifier';
7
+ #ports = {};
8
+ #requests = new Subject();
9
+ constructor(name = DEFAULT_CONNECTION_NAME) {
10
+ super();
11
+ chrome.runtime.onConnect.addListener((port) => {
12
+ if (port.name !== name) {
13
+ return;
14
+ }
15
+ port.onMessage.addListener((message, incomingMessagePort) => {
16
+ if (!this.#ports[incomingMessagePort.sender.tab.id]) {
17
+ this.#ports[incomingMessagePort.sender.tab.id] = incomingMessagePort;
18
+ incomingMessagePort.onDisconnect.addListener(disconnectedPort => {
19
+ delete this.#ports[disconnectedPort.sender.tab.id];
20
+ this[TERMINATE_MESSAGE$].next(message.id);
21
+ });
22
+ }
23
+ const newMessage = {
24
+ ...message,
25
+ id: `${message.id}&${ChromeMessageHost.PORT_IDENTIFIER}=${incomingMessagePort.sender.tab.id}`,
26
+ };
27
+ this.#requests.next(newMessage);
28
+ });
29
+ });
30
+ this[LISTEN](this.#requests);
31
+ }
32
+ [RESPONSE](message) {
33
+ const [messageId, portId] = message.id.split(`&${ChromeMessageHost.PORT_IDENTIFIER}=`);
34
+ message.id = messageId;
35
+ if (this.#ports[portId]) {
36
+ this.#ports[portId].postMessage(message);
37
+ }
38
+ }
39
+ }
40
+
41
+ //# sourceMappingURL=message-host.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../../libs/messenger/src/chrome/message-host.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAE/B,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAG9C,OAAO,EAAE,uBAAuB,EAAE,MAAM,2BAA2B,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,OAAO,iBAAkB,SAAQ,WAAW;IACxC,MAAM,CAAU,eAAe,GAAG,gBAAgB,CAAC;IAE3D,MAAM,GAAyC,EAAE,CAAC;IAClD,SAAS,GAAG,IAAI,OAAO,EAAW,CAAC;IAEnC,YAAY,IAAI,GAAG,uBAAuB;QACxC,KAAK,EAAE,CAAC;QAER,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE;YAC5C,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI,EAAE,CAAC;gBACvB,OAAO;YACT,CAAC;YAED,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,OAAgB,EAAE,mBAAwC,EAAE,EAAE;gBACxF,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAO,CAAC,GAAI,CAAC,EAAG,CAAC,EAAE,CAAC;oBACvD,IAAI,CAAC,MAAM,CAAC,mBAAmB,CAAC,MAAO,CAAC,GAAI,CAAC,EAAG,CAAC,GAAG,mBAAmB,CAAC;oBAExE,mBAAmB,CAAC,YAAY,CAAC,WAAW,CAAC,gBAAgB,CAAC,EAAE;wBAC9D,OAAO,IAAI,CAAC,MAAM,CAAC,gBAAgB,CAAC,MAAO,CAAC,GAAI,CAAC,EAAG,CAAC,CAAC;wBACtD,IAAI,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;oBAC5C,CAAC,CAAC,CAAC;gBACL,CAAC;gBAED,MAAM,UAAU,GAAG;oBACjB,GAAG,OAAO;oBACV,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,IAAI,iBAAiB,CAAC,eAAe,IAAI,mBAAmB,CAAC,MAAO,CAAC,GAAI,CAAC,EAAG,EAAE;iBACjG,CAAC;gBAEF,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAClC,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;IAES,CAAC,QAAQ,CAAC,CAAC,OAAkC;QACrD,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,IAAI,iBAAiB,CAAC,eAAe,GAAG,CAAC,CAAC;QAEvF,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC;QAEvB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;QAC3C,CAAC;IACH,CAAC","file":"message-host.js","sourcesContent":["import { Subject } from 'rxjs';\n\nimport { MessageHost } from '../message-host';\nimport { SuccessfulMessageResponse } from '../message-response.type';\nimport { Message } from '../message.interface';\nimport { DEFAULT_CONNECTION_NAME } from './default-connection-name';\nimport { LISTEN, RESPONSE, TERMINATE_MESSAGE$ } from '../selectors';\n\nexport class ChromeMessageHost extends MessageHost {\n private static readonly PORT_IDENTIFIER = 'portIdentifier';\n\n #ports: {[key: string]: chrome.runtime.Port} = {};\n #requests = new Subject<Message>();\n\n constructor(name = DEFAULT_CONNECTION_NAME) {\n super();\n\n chrome.runtime.onConnect.addListener((port) => {\n if (port.name !== name) {\n return;\n }\n\n port.onMessage.addListener((message: Message, incomingMessagePort: chrome.runtime.Port) => {\n if (!this.#ports[incomingMessagePort.sender!.tab!.id!]) {\n this.#ports[incomingMessagePort.sender!.tab!.id!] = incomingMessagePort;\n\n incomingMessagePort.onDisconnect.addListener(disconnectedPort => {\n delete this.#ports[disconnectedPort.sender!.tab!.id!];\n this[TERMINATE_MESSAGE$].next(message.id);\n });\n }\n\n const newMessage = {\n ...message,\n id: `${message.id}&${ChromeMessageHost.PORT_IDENTIFIER}=${incomingMessagePort.sender!.tab!.id!}`,\n };\n\n this.#requests.next(newMessage);\n });\n });\n\n this[LISTEN](this.#requests);\n }\n\n protected [RESPONSE](message: SuccessfulMessageResponse): void {\n const [messageId, portId] = message.id.split(`&${ChromeMessageHost.PORT_IDENTIFIER}=`);\n\n message.id = messageId;\n\n if (this.#ports[portId]) {\n this.#ports[portId].postMessage(message);\n }\n }\n}\n"]}
@@ -0,0 +1,87 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 600">
2
+ <defs>
3
+ <style>
4
+ .title { font: bold 24px sans-serif; fill: #2c3e50; }
5
+ .subtitle { font: 16px sans-serif; fill: #7f8c8d; }
6
+ .label { font: 14px sans-serif; fill: #34495e; }
7
+ .code { font: 11px monospace; fill: #2c3e50; }
8
+ .tab { fill: #ecf0f1; stroke: #95a5a6; stroke-width: 3; }
9
+ .service { fill: #9b59b6; stroke: #8e44ad; stroke-width: 2; }
10
+ .channel { fill: none; stroke: #e74c3c; stroke-width: 4; stroke-dasharray: 10,5; }
11
+ .arrow { stroke: #3498db; stroke-width: 2; fill: none; marker-end: url(#arrowhead); }
12
+ .broadcast-wave { fill: none; stroke: #e74c3c; stroke-width: 2; opacity: 0.6; }
13
+ text { text-anchor: middle; }
14
+ </style>
15
+ <marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
16
+ <polygon points="0 0, 10 3, 0 6" fill="#3498db" />
17
+ </marker>
18
+ </defs>
19
+
20
+ <!-- Title -->
21
+ <text x="450" y="35" class="title">Broadcast Channel Communication</text>
22
+ <text x="450" y="60" class="subtitle">Multi-tab/window messaging within same origin</text>
23
+
24
+ <!-- Central Channel -->
25
+ <circle cx="450" cy="320" r="80" class="channel"/>
26
+ <text x="450" y="310" class="label" style="font-weight: bold; font-size: 18px; fill: #e74c3c;">Broadcast</text>
27
+ <text x="450" y="335" class="label" style="font-weight: bold; font-size: 18px; fill: #e74c3c;">Channel</text>
28
+ <text x="450" y="360" class="code" style="fill: #e74c3c;">"my-app-channel"</text>
29
+
30
+ <!-- Broadcast waves -->
31
+ <circle cx="450" cy="320" r="100" class="broadcast-wave"/>
32
+ <circle cx="450" cy="320" r="120" class="broadcast-wave"/>
33
+ <circle cx="450" cy="320" r="140" class="broadcast-wave"/>
34
+
35
+ <!-- Tab 1 (Top Left) -->
36
+ <rect x="50" y="100" width="250" height="140" rx="8" class="tab"/>
37
+ <rect x="50" y="100" width="250" height="25" rx="8" style="fill: #3498db;"/>
38
+ <text x="175" y="118" class="label" style="fill: white; font-weight: bold;">Tab 1 🌐</text>
39
+
40
+ <rect x="70" y="145" width="210" height="80" rx="5" class="service"/>
41
+ <text x="175" y="170" class="label" style="fill: white; font-weight: bold; font-size: 13px;">BroadcastMessageService</text>
42
+ <text x="175" y="192" class="code" style="fill: #f39c12;">@Request('sync')</text>
43
+ <text x="175" y="210" class="code" style="fill: #2ecc71;">@Listen('notification')</text>
44
+
45
+ <!-- Tab 2 (Top Right) -->
46
+ <rect x="600" y="100" width="250" height="140" rx="8" class="tab"/>
47
+ <rect x="600" y="100" width="250" height="25" rx="8" style="fill: #3498db;"/>
48
+ <text x="725" y="118" class="label" style="fill: white; font-weight: bold;">Tab 2 🌐</text>
49
+
50
+ <rect x="620" y="145" width="210" height="80" rx="5" class="service"/>
51
+ <text x="725" y="170" class="label" style="fill: white; font-weight: bold; font-size: 13px;">BroadcastMessageService</text>
52
+ <text x="725" y="192" class="code" style="fill: #2ecc71;">@Listen('sync')</text>
53
+ <text x="725" y="210" class="code" style="fill: #f39c12;">@Request('notification')</text>
54
+
55
+ <!-- Tab 3 (Bottom Left) -->
56
+ <rect x="50" y="420" width="250" height="140" rx="8" class="tab"/>
57
+ <rect x="50" y="420" width="250" height="25" rx="8" style="fill: #3498db;"/>
58
+ <text x="175" y="438" class="label" style="fill: white; font-weight: bold;">Tab 3 🌐</text>
59
+
60
+ <rect x="70" y="465" width="210" height="80" rx="5" class="service"/>
61
+ <text x="175" y="490" class="label" style="fill: white; font-weight: bold; font-size: 13px;">BroadcastMessageService</text>
62
+ <text x="175" y="512" class="code" style="fill: #2ecc71;">@Listen('sync')</text>
63
+ <text x="175" y="530" class="code" style="fill: #2ecc71;">@Listen('notification')</text>
64
+
65
+ <!-- Tab 4 (Bottom Right) -->
66
+ <rect x="600" y="420" width="250" height="140" rx="8" class="tab"/>
67
+ <rect x="600" y="420" width="250" height="25" rx="8" style="fill: #3498db;"/>
68
+ <text x="725" y="438" class="label" style="fill: white; font-weight: bold;">Tab 4 🌐</text>
69
+
70
+ <rect x="620" y="465" width="210" height="80" rx="5" class="service"/>
71
+ <text x="725" y="490" class="label" style="fill: white; font-weight: bold; font-size: 13px;">BroadcastMessageService</text>
72
+ <text x="725" y="512" class="code" style="fill: #f39c12;">@Request('sync')</text>
73
+ <text x="725" y="530" class="code" style="fill: #f39c12;">@Request('notification')</text>
74
+
75
+ <!-- Arrows connecting tabs to channel -->
76
+ <path d="M 240 240 L 400 280" class="arrow"/>
77
+ <path d="M 650 240 L 490 280" class="arrow"/>
78
+ <path d="M 240 420 L 400 360" class="arrow"/>
79
+ <path d="M 650 420 L 490 360" class="arrow"/>
80
+
81
+ <!-- Info Box -->
82
+ <rect x="325" y="140" width="250" height="90" rx="5" style="fill: #34495e; stroke: #2c3e50; stroke-width: 2;"/>
83
+ <text x="450" y="165" class="label" style="fill: white; font-weight: bold;">All tabs share the channel</text>
84
+ <text x="450" y="190" class="label" style="fill: #ecf0f1; font-size: 12px;">Messages sent by one tab</text>
85
+ <text x="450" y="210" class="label" style="fill: #ecf0f1; font-size: 12px;">are received by all other tabs</text>
86
+
87
+ </svg>
@@ -0,0 +1,110 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 900 600">
2
+ <defs>
3
+ <style>
4
+ .title { font: bold 24px sans-serif; fill: #2c3e50; }
5
+ .subtitle { font: 16px sans-serif; fill: #7f8c8d; }
6
+ .label { font: 14px sans-serif; fill: #34495e; }
7
+ .code { font: 11px monospace; fill: #2c3e50; }
8
+ .context { fill: #ecf0f1; stroke: #95a5a6; stroke-width: 3; }
9
+ .client { fill: #3498db; stroke: #2980b9; stroke-width: 2; }
10
+ .host { fill: #2ecc71; stroke: #27ae60; stroke-width: 2; }
11
+ .service { fill: #9b59b6; stroke: #8e44ad; stroke-width: 2; }
12
+ .arrow { stroke: #e74c3c; stroke-width: 2.5; fill: none; marker-end: url(#arrowhead); }
13
+ .arrow-back { stroke: #f39c12; stroke-width: 2.5; fill: none; marker-end: url(#arrowhead-back); }
14
+ text { text-anchor: middle; }
15
+ </style>
16
+ <marker id="arrowhead" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
17
+ <polygon points="0 0, 10 3, 0 6" fill="#e74c3c" />
18
+ </marker>
19
+ <marker id="arrowhead-back" markerWidth="10" markerHeight="10" refX="9" refY="3" orient="auto">
20
+ <polygon points="0 0, 10 3, 0 6" fill="#f39c12" />
21
+ </marker>
22
+ </defs>
23
+
24
+ <!-- Title -->
25
+ <text x="450" y="35" class="title">Chrome Extension Communication</text>
26
+ <text x="450" y="60" class="subtitle">Background script ↔ Content scripts, Popups, DevTools</text>
27
+
28
+ <!-- Background Script (Center/Hub) -->
29
+ <rect x="325" y="240" width="250" height="120" rx="8" class="context"/>
30
+ <text x="450" y="270" class="label" style="font-weight: bold; font-size: 16px;">Background Script</text>
31
+ <text x="450" y="290" class="label" style="font-size: 11px; fill: #7f8c8d;">(Service Worker)</text>
32
+
33
+ <rect x="345" y="305" width="210" height="45" rx="5" class="host"/>
34
+ <text x="450" y="325" class="label" style="fill: white; font-weight: bold; font-size: 13px;">ChromeMessageHost</text>
35
+ <text x="450" y="343" class="code" style="fill: white;">@Listen('fetchData')</text>
36
+
37
+ <!-- Content Script (Left) -->
38
+ <rect x="50" y="100" width="200" height="140" rx="8" class="context"/>
39
+ <text x="150" y="130" class="label" style="font-weight: bold;">Content Script</text>
40
+ <text x="150" y="148" class="label" style="font-size: 10px; fill: #7f8c8d;">(webpage)</text>
41
+
42
+ <rect x="70" y="165" width="160" height="60" rx="5" class="client"/>
43
+ <text x="150" y="185" class="label" style="fill: white; font-weight: bold; font-size: 12px;">ChromeMessageClient</text>
44
+ <text x="150" y="205" class="code" style="fill: white;">@Request('fetchData')</text>
45
+ <text x="150" y="220" class="code" style="fill: white;">@Request('saveSettings')</text>
46
+
47
+ <!-- Popup (Top Right) -->
48
+ <rect x="650" y="100" width="200" height="140" rx="8" class="context"/>
49
+ <text x="750" y="130" class="label" style="font-weight: bold;">Popup / Action</text>
50
+ <text x="750" y="148" class="label" style="font-size: 10px; fill: #7f8c8d;">(browser action)</text>
51
+
52
+ <rect x="670" y="165" width="160" height="60" rx="5" class="client"/>
53
+ <text x="750" y="185" class="label" style="fill: white; font-weight: bold; font-size: 12px;">ChromeMessageClient</text>
54
+ <text x="750" y="205" class="code" style="fill: white;">@Request('getState')</text>
55
+ <text x="750" y="220" class="code" style="fill: white;">@Request('updateBadge')</text>
56
+
57
+ <!-- DevTools (Bottom Left) -->
58
+ <rect x="50" y="420" width="200" height="140" rx="8" class="context"/>
59
+ <text x="150" y="450" class="label" style="font-weight: bold;">DevTools Panel</text>
60
+ <text x="150" y="468" class="label" style="font-size: 10px; fill: #7f8c8d;">(devtools page)</text>
61
+
62
+ <rect x="70" y="485" width="160" height="60" rx="5" class="client"/>
63
+ <text x="150" y="505" class="label" style="fill: white; font-weight: bold; font-size: 12px;">ChromeMessageClient</text>
64
+ <text x="150" y="525" class="code" style="fill: white;">@Request('inspect')</text>
65
+
66
+ <!-- Options Page (Bottom Right) -->
67
+ <rect x="650" y="420" width="200" height="140" rx="8" class="context"/>
68
+ <text x="750" y="450" class="label" style="font-weight: bold;">Options Page</text>
69
+ <text x="750" y="468" class="label" style="font-size: 10px; fill: #7f8c8d;">(settings)</text>
70
+
71
+ <rect x="670" y="485" width="160" height="60" rx="5" class="service"/>
72
+ <text x="750" y="505" class="label" style="fill: white; font-weight: bold; font-size: 12px;">ChromeMessageService</text>
73
+ <text x="750" y="525" class="code" style="fill: white;">@Request + @Listen</text>
74
+
75
+ <!-- Arrows from contexts to background -->
76
+ <!-- Content Script to Background -->
77
+ <path d="M 250 180 L 325 280" class="arrow"/>
78
+ <text x="270" y="220" class="code" style="fill: #e74c3c; font-size: 10px;">chrome.runtime</text>
79
+ <text x="270" y="235" class="code" style="fill: #e74c3c; font-size: 10px;">.sendMessage</text>
80
+
81
+ <!-- Background to Content Script -->
82
+ <path d="M 345 295 L 260 200" class="arrow-back"/>
83
+
84
+ <!-- Popup to Background -->
85
+ <path d="M 650 190 L 575 285" class="arrow"/>
86
+ <text x="630" y="225" class="code" style="fill: #e74c3c; font-size: 10px;">chrome.runtime</text>
87
+ <text x="630" y="240" class="code" style="fill: #e74c3c; font-size: 10px;">.sendMessage</text>
88
+
89
+ <!-- Background to Popup -->
90
+ <path d="M 555 290 L 660 200" class="arrow-back"/>
91
+
92
+ <!-- DevTools to Background -->
93
+ <path d="M 250 500 L 340 350" class="arrow"/>
94
+
95
+ <!-- Background to DevTools -->
96
+ <path d="M 355 360 L 260 520" class="arrow-back"/>
97
+
98
+ <!-- Options to Background -->
99
+ <path d="M 650 510 L 575 330" class="arrow"/>
100
+
101
+ <!-- Background to Options -->
102
+ <path d="M 555 335 L 660 520" class="arrow-back"/>
103
+
104
+ <!-- Legend -->
105
+ <rect x="320" y="470" width="260" height="90" rx="5" style="fill: #34495e; stroke: #2c3e50; stroke-width: 2;"/>
106
+ <text x="450" y="495" class="label" style="fill: white; font-weight: bold; font-size: 13px;">Chrome Runtime API</text>
107
+ <text x="340" y="520" class="code" style="fill: #3498db; text-anchor: start;">chrome.runtime.sendMessage()</text>
108
+ <text x="340" y="540" class="code" style="fill: #2ecc71; text-anchor: start;">chrome.runtime.onMessage</text>
109
+
110
+ </svg>