@livequery/rpc 2.0.101 → 2.0.104

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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @livequery/rpc
2
2
 
3
- Lightweight RxJS-based RPC utilities for exposing services from a `SharedWorker` and consuming them from the main thread with typed proxies.
3
+ Lightweight RxJS-based RPC utilities for exposing services from a `SharedWorker` or an extension background runtime and consuming them from the main thread with typed proxies.
4
4
 
5
5
  ## AI Agent Notes
6
6
 
@@ -29,6 +29,7 @@ bun add @livequery/rpc rxjs
29
29
  ## What It Exports
30
30
 
31
31
  ```ts
32
+ export * from "./ExtensionChannel"
32
33
  export * from "./RpcChannel"
33
34
  export * from "./SharedWorkerChannel"
34
35
  export * from "./ServiceLinker"
@@ -49,6 +50,41 @@ ServiceLinker --(RpcMessage)--> SharedWorkerChannel --> WorkerManager --> your s
49
50
  |--------------------(response stream)-----------------------|
50
51
  ```
51
52
 
53
+ For extension Manifest V3, the same flow can run over `ExtensionChannel` and `chrome.runtime` messaging instead of `SharedWorker`.
54
+
55
+ ## Extension MV3 Example
56
+
57
+ ### Background service worker
58
+
59
+ ```ts
60
+ import { ExtensionChannel, WorkerManager } from "@livequery/rpc"
61
+ import { CounterService } from "./CounterService"
62
+
63
+ const channel = new ExtensionChannel()
64
+ const manager = new WorkerManager(channel)
65
+
66
+ manager.exposeService("counter", new CounterService())
67
+ ```
68
+
69
+ ### Popup, options page, or content script
70
+
71
+ ```ts
72
+ import { ExtensionChannel, ServiceLinker, type WorkerService } from "@livequery/rpc"
73
+ import type { CounterService } from "./CounterService"
74
+
75
+ const channel = new ExtensionChannel()
76
+ const linker = new ServiceLinker(channel)
77
+
78
+ const counter = linker.linkService<WorkerService<CounterService>>("counter")
79
+ ```
80
+
81
+ `ExtensionChannel` auto-detects its context at construction time:
82
+
83
+ - **Background service worker** (`typeof window === 'undefined'`): listens on `chrome.runtime.onMessage` and routes responses back to the originating tab via `chrome.tabs.sendMessage`, or falls back to `chrome.runtime.sendMessage` when the message did not originate from a tab.
84
+ - **Foreground context** (popup, options page, content script): listens on `chrome.runtime.onMessage` for responses arriving from the background and sends requests with `chrome.runtime.sendMessage`.
85
+
86
+ If `chrome` is not available (e.g. during SSR), all operations silently no-op.
87
+
52
88
  ## When To Use This Package
53
89
 
54
90
  Use it when you want to:
@@ -275,6 +311,29 @@ const worker = new SharedWorker(new URL("./worker.ts", import.meta.url), { type:
275
311
  const channel = new SharedWorkerChannel(worker)
276
312
  ```
277
313
 
314
+ ### `ExtensionChannel`
315
+
316
+ Concrete `RpcChannel` implementation for Chrome extension Manifest V3 messaging.
317
+
318
+ Auto-detects its context at construction time — no argument is required.
319
+
320
+ ```ts
321
+ const channel = new ExtensionChannel()
322
+ ```
323
+
324
+ **Background service worker** (`typeof window === 'undefined'`):
325
+
326
+ - listens on `chrome.runtime.onMessage`
327
+ - responds to tab-originated messages via `chrome.tabs.sendMessage(tabId, …)`
328
+ - responds to non-tab messages via `chrome.runtime.sendMessage(…)`
329
+
330
+ **Foreground context** (popup, options page, content script):
331
+
332
+ - listens on `chrome.runtime.onMessage` for responses from the background
333
+ - sends requests with `chrome.runtime.sendMessage`
334
+
335
+ If `chrome` is unavailable (e.g. during SSR), all operations silently no-op.
336
+
278
337
  ### `WorkerManager`
279
338
 
280
339
  Registers named services and routes incoming RPC requests.
@@ -0,0 +1,7 @@
1
+ import { RpcChannel, type RpcMessage } from "./RpcChannel.js";
2
+ export declare class ExtensionChannel extends RpcChannel {
3
+ #private;
4
+ constructor();
5
+ send(message: RpcMessage): void;
6
+ }
7
+ //# sourceMappingURL=ExtensionChannel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExtensionChannel.d.ts","sourceRoot":"","sources":["../src/ExtensionChannel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAyB7D,qBAAa,gBAAiB,SAAQ,UAAU;;;IAmD5C,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;CAIlC"}
@@ -0,0 +1,62 @@
1
+ import { RpcChannel } from "./RpcChannel.js";
2
+ const chrome = globalThis.chrome;
3
+ function isRpcMessage(value) {
4
+ return !!value && typeof value === "object" && "id" in value;
5
+ }
6
+ export class ExtensionChannel extends RpcChannel {
7
+ constructor() {
8
+ super();
9
+ if (typeof window == 'undefined') {
10
+ this.#initBackground();
11
+ }
12
+ else {
13
+ this.#initForegound();
14
+ }
15
+ }
16
+ #initForegound() {
17
+ if (!chrome)
18
+ return;
19
+ const runtime = chrome.runtime;
20
+ runtime?.onMessage.addListener((message, sender, sendResponse) => {
21
+ if (!isRpcMessage(message))
22
+ return;
23
+ const respond = (response) => {
24
+ runtime?.sendMessage({
25
+ id: message.id,
26
+ response
27
+ });
28
+ };
29
+ this.next({ ...message, respond });
30
+ });
31
+ }
32
+ #initBackground() {
33
+ if (!chrome)
34
+ return;
35
+ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
36
+ if (!isRpcMessage(message))
37
+ return;
38
+ const tabId = sender.tab?.id;
39
+ const respond = (response) => {
40
+ if (tabId) {
41
+ chrome.tabs.sendMessage(tabId, {
42
+ id: message.id,
43
+ response
44
+ });
45
+ }
46
+ else {
47
+ chrome.runtime.sendMessage({
48
+ id: message.id,
49
+ response
50
+ });
51
+ }
52
+ };
53
+ this.next({ ...message, respond });
54
+ });
55
+ }
56
+ send(message) {
57
+ if (!chrome)
58
+ return;
59
+ chrome.runtime.sendMessage(message);
60
+ }
61
+ }
62
+ //# sourceMappingURL=ExtensionChannel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ExtensionChannel.js","sourceRoot":"","sources":["../src/ExtensionChannel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAmB,MAAM,iBAAiB,CAAA;AAY7D,MAAM,MAAM,GAAI,UAOd,CAAC,MAAM,CAAA;AAET,SAAS,YAAY,CAAC,KAAc;IAChC,OAAO,CAAC,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,IAAI,IAAI,KAAK,CAAA;AAChE,CAAC;AAED,MAAM,OAAO,gBAAiB,SAAQ,UAAU;IAI5C;QACI,KAAK,EAAE,CAAA;QACP,IAAI,OAAO,MAAM,IAAI,WAAW,EAAE,CAAC;YAC/B,IAAI,CAAC,eAAe,EAAE,CAAA;QAC1B,CAAC;aAAM,CAAC;YACJ,IAAI,CAAC,cAAc,EAAE,CAAA;QACzB,CAAC;IACL,CAAC;IAED,cAAc;QACV,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAA;QAC9B,OAAO,EAAE,SAAS,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE;YAC7D,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;gBAAE,OAAM;YAClC,MAAM,OAAO,GAAG,CAAC,QAAgC,EAAE,EAAE;gBACjD,OAAO,EAAE,WAAW,CAAC;oBACjB,EAAE,EAAE,OAAO,CAAC,EAAE;oBACd,QAAQ;iBACU,CAAC,CAAA;YAC3B,CAAC,CAAA;YACD,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;QACtC,CAAC,CAAC,CAAC;IACP,CAAC;IAED,eAAe;QACX,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE;YACnE,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;gBAAE,OAAM;YAClC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,EAAE,EAAE,CAAA;YAC5B,MAAM,OAAO,GAAG,CAAC,QAAgC,EAAE,EAAE;gBACjD,IAAI,KAAK,EAAE,CAAC;oBACR,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE;wBAC3B,EAAE,EAAE,OAAO,CAAC,EAAE;wBACd,QAAQ;qBACU,CAAC,CAAA;gBAC3B,CAAC;qBAAM,CAAC;oBACJ,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC;wBACvB,EAAE,EAAE,OAAO,CAAC,EAAE;wBACd,QAAQ;qBACU,CAAC,CAAA;gBAC3B,CAAC;YACL,CAAC,CAAA;YACD,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;QACtC,CAAC,CAAC,CAAC;IACP,CAAC;IAGD,IAAI,CAAC,OAAmB;QACpB,IAAI,CAAC,MAAM;YAAE,OAAM;QACnB,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IACvC,CAAC;CACJ"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./RpcChannel.js";
2
+ export * from "./ExtensionChannel.js";
2
3
  export * from "./SharedWorkerChannel.js";
3
4
  export * from "./ServiceLinker.js";
4
5
  export * from "./WorkerService.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export * from "./RpcChannel.js";
2
+ export * from "./ExtensionChannel.js";
2
3
  export * from "./SharedWorkerChannel.js";
3
4
  export * from "./ServiceLinker.js";
4
5
  export * from "./WorkerService.js";
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,0BAA0B,CAAA;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAA;AAC/B,cAAc,uBAAuB,CAAA;AACrC,cAAc,0BAA0B,CAAA;AACxC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,oBAAoB,CAAA;AAClC,cAAc,uBAAuB,CAAA;AACrC,cAAc,6BAA6B,CAAA;AAC3C,cAAc,gBAAgB,CAAA"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@livequery/rpc",
3
- "version": "2.0.101",
3
+ "version": "2.0.104",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -21,6 +21,11 @@
21
21
  "import": "./dist/index.js",
22
22
  "default": "./dist/index.js"
23
23
  },
24
+ "./ExtensionChannel": {
25
+ "types": "./dist/ExtensionChannel.d.ts",
26
+ "import": "./dist/ExtensionChannel.js",
27
+ "default": "./dist/ExtensionChannel.js"
28
+ },
24
29
  "./RpcChannel": {
25
30
  "types": "./dist/RpcChannel.d.ts",
26
31
  "import": "./dist/RpcChannel.js",