@livequery/rpc 2.0.100 → 2.0.102

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,10 @@
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
+
5
+ ## AI Agent Notes
6
+
7
+ Repository-specific guidance for coding agents lives in `AGENTS.md`.
4
8
 
5
9
  This package is built for a simple model:
6
10
 
@@ -25,6 +29,7 @@ bun add @livequery/rpc rxjs
25
29
  ## What It Exports
26
30
 
27
31
  ```ts
32
+ export * from "./ExtensionChannel"
28
33
  export * from "./RpcChannel"
29
34
  export * from "./SharedWorkerChannel"
30
35
  export * from "./ServiceLinker"
@@ -45,6 +50,36 @@ ServiceLinker --(RpcMessage)--> SharedWorkerChannel --> WorkerManager --> your s
45
50
  |--------------------(response stream)-----------------------|
46
51
  ```
47
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` is a transport for extension contexts such as a background service worker, popup, options page, or content script. Its current implementation listens on `chrome.runtime.onMessage` and sends messages with `chrome.runtime.sendMessage`.
82
+
48
83
  ## When To Use This Package
49
84
 
50
85
  Use it when you want to:
@@ -157,7 +192,7 @@ In practice:
157
192
 
158
193
  ## BehaviorSubject Mirroring
159
194
 
160
- If your service exposes a property with a `getValue()` method, `WorkerManager` will include its initial value during service initialization.
195
+ If your service exposes a `BehaviorSubject` property, the client can treat it like remote reactive state.
161
196
 
162
197
  This is what allows a worker-side `BehaviorSubject` to feel usable on the client:
163
198
 
@@ -177,24 +212,12 @@ settings.theme.subscribe((theme) => {
177
212
 
178
213
  Notes:
179
214
 
180
- - the initial snapshot is fetched through an internal `____initialize____` call
181
- - later updates are streamed by subscribing to the remote property
215
+ - `ServiceLinker` special-cases only `subscribe()`, `pipe()`, and `getValue()` on remote properties
216
+ - updates are fetched by subscribing to the remote property path, not through a separate initialization API
217
+ - `getValue()` reads the locally cached value, so subscribe first if you need the current worker value to be populated locally
182
218
  - this pattern is designed around `BehaviorSubject`-like objects
183
219
 
184
- ## Waiting For Multiple Services To Initialize
185
-
186
- `ServiceLinker` exposes a helper for waiting until all linked services have loaded their initial state.
187
-
188
- ```ts
189
- const counter = linker.linkService<WorkerService<CounterService>>("counter")
190
- const settings = linker.linkService<WorkerService<SettingsService>>("settings")
191
-
192
- ServiceLinker.ready$({ counter, settings }).subscribe((ready) => {
193
- if (ready) {
194
- console.log("all services initialized")
195
- }
196
- })
197
- ```
220
+ There is currently no built-in readiness helper in `ServiceLinker`.
198
221
 
199
222
  ## Nested Access
200
223
 
@@ -310,7 +333,6 @@ Creates and caches client-side proxies.
310
333
  class ServiceLinker {
311
334
  constructor(channel: RpcChannel)
312
335
  linkService<T>(name: string): WorkerService<T>
313
- static ready$(services: Record<string, any>): Observable<boolean>
314
336
  }
315
337
  ```
316
338
 
@@ -320,7 +342,7 @@ Behavior:
320
342
  - assigns incrementing request ids
321
343
  - returns an `Observable` that is also `PromiseLike`
322
344
  - sends cancellation when a request is unsubscribed early
323
- - initializes `BehaviorSubject`-style values via `____initialize____`
345
+ - special-cases `subscribe`, `pipe`, and `getValue` for remote observable-like properties
324
346
 
325
347
  ### `WorkerService<T>`
326
348
 
@@ -330,7 +352,7 @@ Rules:
330
352
 
331
353
  - `BehaviorSubject<T>` stays `BehaviorSubject<T>`
332
354
  - `Observable<T>` stays `Observable<T>`
333
- - methods become async call signatures
355
+ - methods become async call signatures unless their awaited return type is already an `Observable`
334
356
 
335
357
  Example:
336
358
 
@@ -422,8 +444,6 @@ bun run build
422
444
  Other scripts:
423
445
 
424
446
  - `bun run clean`
425
- - `bun run build:js`
426
- - `bun run build:types`
427
447
  - `bun run build:watch`
428
448
 
429
449
  ## Package Output
@@ -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;AA4B7D,qBAAa,gBAAiB,SAAQ,UAAU;;;IAqB5C,IAAI,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI;CAGlC"}
@@ -0,0 +1,32 @@
1
+ import { RpcChannel } from "./RpcChannel.js";
2
+ const runtime = (() => {
3
+ const runtime = globalThis.chrome?.runtime;
4
+ if (!runtime) {
5
+ throw new Error("chrome.runtime is not available");
6
+ }
7
+ return runtime;
8
+ })();
9
+ function isRpcMessage(value) {
10
+ return !!value && typeof value === "object" && "id" in value;
11
+ }
12
+ export class ExtensionChannel extends RpcChannel {
13
+ constructor() {
14
+ super();
15
+ runtime.onMessage.addListener(this.#onMessage);
16
+ }
17
+ #onMessage = (message) => {
18
+ if (!isRpcMessage(message))
19
+ return;
20
+ const respond = (response) => {
21
+ runtime.sendMessage({
22
+ id: message.id,
23
+ response
24
+ });
25
+ };
26
+ this.next({ ...message, respond });
27
+ };
28
+ send(message) {
29
+ runtime.sendMessage(message);
30
+ }
31
+ }
32
+ //# 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,OAAO,GAAG,CAAC,GAAG,EAAE;IAClB,MAAM,OAAO,GAAI,UAEf,CAAC,MAAM,EAAE,OAAO,CAAA;IAElB,IAAI,CAAC,OAAO,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACtD,CAAC;IAED,OAAO,OAAO,CAAA;AAClB,CAAC,CAAC,EAAE,CAAA;AAEJ,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;IAE5C;QACI,KAAK,EAAE,CAAA;QAEP,OAAO,CAAC,SAAS,CAAC,WAAW,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;IAClD,CAAC;IAED,UAAU,GAAG,CAAC,OAAgB,EAAE,EAAE;QAC9B,IAAI,CAAC,YAAY,CAAC,OAAO,CAAC;YAAE,OAAM;QAElC,MAAM,OAAO,GAAG,CAAC,QAAgC,EAAE,EAAE;YACjD,OAAO,CAAC,WAAW,CAAC;gBAChB,EAAE,EAAE,OAAO,CAAC,EAAE;gBACd,QAAQ;aACU,CAAC,CAAA;QAC3B,CAAC,CAAA;QAED,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,CAAC,CAAA;IACtC,CAAC,CAAA;IAED,IAAI,CAAC,OAAmB;QACpB,OAAO,CAAC,WAAW,CAAC,OAAO,CAAC,CAAA;IAChC,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.100",
3
+ "version": "2.0.102",
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",