crx-rpc 2.0.0 → 2.1.0

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,657 +1,152 @@
1
- # Chrome Extension RPC (crx-rpc)
1
+ # crx-rpc
2
2
 
3
- A lightweight, type-safe RPC framework for Chrome Extensions supporting communication between web pages, content scripts, and background scripts. Built with TypeScript for maximum type safety and developer experience.
3
+ A type-safe RPC implementation for Chrome Extensions, supporting communication between Content Scripts, Background, Popup/Sidepanel, and Web Pages.
4
4
 
5
5
  ## Features
6
6
 
7
- - 🔒 **Type Safety**: Full TypeScript type support with automatic proxy type generation
8
- - 🚀 **Easy to Use**: Auto-generated client proxies based on interfaces
9
- - 🔄 **Bidirectional Communication**: Supports web page content script ↔ background script
10
- - 📦 **Zero Configuration**: No manual method binding required
11
- - 🎯 **Observable Support**: Built-in support for reactive data streams with RemoteSubject
12
- - 🛡️ **Error Handling**: Preserves stack traces and error types across boundaries
13
- - 🧹 **Resource Management**: Built-in disposable pattern for clean resource cleanup
14
-
15
- ## Installation
16
-
17
- ```bash
18
- npm install crx-rpc
19
- # or
20
- pnpm add crx-rpc
21
- # or
22
- yarn add crx-rpc
23
- ```
7
+ - **Type-safe**: Built with TypeScript.
8
+ - **Flexible**: Supports various communication paths within a Chrome Extension.
9
+ - **Observable**: Supports RxJS-like observables for real-time updates.
24
10
 
25
- ## Quick Start
11
+ ## Communication Architecture
26
12
 
27
- ### 1. Define Service Interface
13
+ The library facilitates communication between different parts of a Chrome Extension.
28
14
 
29
- ```typescript
30
- // services/math.ts
31
- import { createIdentifier } from 'crx-rpc';
15
+ ### Service Providers
32
16
 
33
- interface IMathService {
34
- add(a: number, b: number): Promise<number>;
35
- subtract(a: number, b: number): Promise<number>;
36
- multiply(a: number, b: number): Promise<number>;
37
- divide(a: number, b: number): Promise<number>;
38
- }
17
+ Services can be hosted in two locations:
39
18
 
40
- // Create service identifier
41
- export const IMathService = createIdentifier<IMathService>('MathService');
42
- ```
19
+ 1. **Background**: Hosted using `BackgroundRPCHost`. Handles requests from Content Scripts and Web Pages.
20
+ 2. **Content Script**: Hosted using `ContentRPCHost`. Handles requests from Background and Popup/Sidepanel.
43
21
 
44
- ### 2. Implement Service (Background Script)
22
+ ### Callers
45
23
 
46
- ```typescript
47
- // background.ts
48
- import { BackgroundRPC } from 'crx-rpc';
49
- import { IMathService } from './services/math';
24
+ Callers can be:
50
25
 
51
- class MathService implements IMathService {
52
- async add(a: number, b: number): Promise<number> {
53
- return a + b;
54
- }
55
-
56
- async subtract(a: number, b: number): Promise<number> {
57
- return a - b;
58
- }
59
-
60
- async multiply(a: number, b: number): Promise<number> {
61
- return a * b;
62
- }
63
-
64
- async divide(a: number, b: number): Promise<number> {
65
- if (b === 0) throw new Error('Division by zero');
66
- return a / b;
67
- }
68
- }
69
-
70
- // Register service with optional logging
71
- const rpc = new BackgroundRPC(true); // Enable logging
72
- // const rpc = new BackgroundRPC(); // Disable logging (default)
73
- rpc.register(IMathService, new MathService());
74
- ```
75
-
76
- ### 3. Initialize Content Script
26
+ 1. **Runtime**: Content Scripts, Popup, Sidepanel.
27
+ 2. **Web**: Injected scripts in the web page.
77
28
 
78
- Content scripts can work in two modes:
29
+ ### Supported Flows
79
30
 
80
- #### Option A: As a Bridge (for web page communication)
81
-
82
- ```typescript
83
- // content.ts
84
- import { ContentRPC } from 'crx-rpc';
85
-
86
- // Initialize RPC bridge for web page ↔ background communication
87
- const contentRpc = new ContentRPC();
88
-
89
- // Remember to dispose when cleanup is needed
90
- // contentRpc.dispose();
91
- ```
92
-
93
- #### Option B: As a Direct Client
94
-
95
- ```typescript
96
- // content.ts
97
- import { ContentRPCClient } from 'crx-rpc';
98
- import { IMathService } from './services/math';
99
-
100
- // Use content script as a direct RPC client
101
- const client = new ContentRPCClient();
102
- const mathService = client.createWebRPCService(IMathService);
103
-
104
- // Direct calls to background services
105
- const result = await mathService.add(5, 3);
106
- console.log('Result from content script:', result);
107
-
108
- // Remember to dispose when cleanup is needed
109
- // client.dispose();
110
- ```
111
-
112
- #### Option C: Both Bridge and Client
113
-
114
- ```typescript
115
- // content.ts
116
- import { ContentRPC, ContentRPCClient } from 'crx-rpc';
117
- import { IMathService } from './services/math';
31
+ | Caller | Target | Client | Host | Note |
32
+ | :--- | :--- | :--- | :--- | :--- |
33
+ | **Content Script** | **Background** | `RuntimeRPCClient` | `BackgroundRPCHost` | Standard Runtime -> Background communication. |
34
+ | **Web Page** | **Background** | `WebRPCClient` | `BackgroundRPCHost` | Relayed via Content Script (`Web2BackgroundProxy`). |
35
+ | **Background** | **Content Script** | `TabRPCClient` | `ContentRPCHost` | Targets a specific tab. |
36
+ | **Popup/Sidepanel** | **Content Script** | `TabRPCClient` | `ContentRPCHost` | Targets a specific tab. |
118
37
 
119
- // Initialize bridge for web pages
120
- const bridge = new ContentRPC();
38
+ > **Note**: Direct communication from Popup/Sidepanel to Background using `RuntimeRPCClient` is currently not supported by `BackgroundRPCHost` as it requires a sender tab ID.
121
39
 
122
- // Also use as direct client
123
- const client = new ContentRPCClient();
124
- const mathService = client.createWebRPCService(IMathService);
40
+ ## Usage
125
41
 
126
- // Content script can make its own RPC calls
127
- const result = await mathService.multiply(2, 3);
128
- console.log('Content script calculation:', result);
129
- ```
42
+ ### 1. Define API
130
43
 
131
- ### 4. Use Client (Web Page)
44
+ Define your service interface and create an identifier.
132
45
 
133
46
  ```typescript
134
- // web-page.ts
135
- import { WebRPCClient } from 'crx-rpc';
136
- import { IMathService } from './services/math';
137
-
138
- async function calculate() {
139
- // Create RPC client
140
- const client = new WebRPCClient();
141
-
142
- // Create type-safe service proxy
143
- const mathService = client.createWebRPCService(IMathService);
144
-
145
- // Type-safe method calls
146
- const sum = await mathService.add(1, 2); // TypeScript knows this returns Promise<number>
147
- const difference = await mathService.subtract(10, 5);
148
- const product = await mathService.multiply(3, 4);
149
- const quotient = await mathService.divide(15, 3);
150
-
151
- console.log('Results:', { sum, difference, product, quotient });
47
+ import { createIdentifier } from 'crx-rpc';
152
48
 
153
- // Remember to dispose when cleanup is needed
154
- // client.dispose();
49
+ export interface IMathService {
50
+ add(a: number, b: number): Promise<number>;
155
51
  }
156
- ```
157
52
 
158
- ## Architecture
159
-
160
- ### Complete Communication Topology
161
-
162
- ```mermaid
163
- graph TB
164
- subgraph WebPage["Web Page Context"]
165
- WC[WebRPCClient]
166
- WO[WebObservable]
167
- end
168
-
169
- subgraph ContentScript["Content Script Context"]
170
- CR[ContentRPC<br/>Bridge Mode]
171
- CC[ContentRPCClient<br/>Direct Mode]
172
- CO[ContentObservable]
173
- end
174
-
175
- subgraph Background["Background Script Context"]
176
- BR[BackgroundRPC]
177
- MS[MathService]
178
- US[UserService]
179
- RS[RemoteSubject]
180
- RSM[RemoteSubjectManager]
181
- end
182
-
183
- subgraph ExtPage["Extension Page Context<br/>(Popup/Options/Sidepanel)"]
184
- EC[ExtPageRPCClient]
185
- EO[ExtPageObservable]
186
- end
187
-
188
- subgraph TabContext["Tab-specific Access"]
189
- TC[TabRPCClient]
190
- end
191
-
192
- %% RPC Calls
193
- WC -->|"CustomEvent<br/>.add(1,2)"| CR
194
- CR -->|"chrome.runtime<br/>Forward"| BR
195
- CC -->|"chrome.runtime<br/>.multiply(2,3)"| BR
196
- EC -->|"chrome.runtime<br/>.divide(10,2)"| BR
197
- TC -->|"chrome.tabs<br/>Access Content Service"| CC
198
-
199
- BR -->|Response| CR
200
- CR -->|CustomEvent| WC
201
- BR -->|Response| CC
202
- BR -->|Response| EC
203
-
204
- BR -.->|Manages| MS
205
- BR -.->|Manages| US
206
-
207
- %% Observable Streams
208
- WO -.->|Subscribe| CR
209
- CR -.->|Forward| RSM
210
- CO -.->|Subscribe| RSM
211
- EO -.->|Subscribe| RSM
212
- RSM -.->|Broadcast| RS
213
- RS -.->|Updates| CR
214
- CR -.->|Updates| WO
215
- RS -.->|Updates| CO
216
- RS -.->|Updates| EO
217
-
218
- style WC fill:#e1f5ff
219
- style CC fill:#e1f5ff
220
- style EC fill:#e1f5ff
221
- style TC fill:#e1f5ff
222
- style BR fill:#fff4e6
223
- style MS fill:#f0f0f0
224
- style US fill:#f0f0f0
225
- style RS fill:#ffe6f0
226
- style RSM fill:#ffe6f0
227
- style CR fill:#e8f5e9
53
+ export const IMathService = createIdentifier<IMathService>('math-service', 'background');
228
54
  ```
229
55
 
230
- ### Communication Paths
231
-
232
- | Path | Method | Description |
233
- |------|--------|-------------|
234
- | **Web Page → Background** | CustomEvent + chrome.runtime | Through ContentRPC bridge |
235
- | **Content Script → Background** | chrome.runtime | Direct communication |
236
- | **Extension Page → Background** | chrome.runtime | Direct communication |
237
- | **Extension Page → Content Script** | chrome.tabs + TabRPCClient | Tab-specific access |
238
- | **Background → All Contexts** | RemoteSubject broadcast | Real-time data streaming |
239
-
240
- ### Key Components
241
-
242
- - **WebRPCClient**: Client for web pages using window events
243
- - **ContentRPC**: Bridge that forwards messages between web and background
244
- - **ContentRPCClient**: Direct RPC client for content scripts (bypasses bridge)
245
- - **BackgroundRPC**: Service registry and handler in the background script
246
- - **RPCClient**: Base client with service proxy generation
56
+ ### 2. Implement & Host Service
247
57
 
248
- ## Logging Support
249
-
250
- The framework includes built-in logging support for debugging and monitoring RPC calls.
251
-
252
- ### Enable Logging
253
-
254
- ```typescript
255
- // Enable logging in BackgroundRPC
256
- const rpc = new BackgroundRPC(true); // Enable logging
257
- // const rpc = new BackgroundRPC(); // Disable logging (default)
258
-
259
- // Example output:
260
- // [RPC] Call: MathService.add { id: "123", args: [5, 3], senderId: 456, timestamp: "2025-09-01T10:00:00.000Z" }
261
- // [RPC] Success: MathService.add { id: "123", result: 8, timestamp: "2025-09-01T10:00:00.001Z" }
262
-
263
- // For errors:
264
- // [RPC] Error: MathService.divide { id: "124", error: "Division by zero", timestamp: "2025-09-01T10:00:01.000Z" }
265
- ```
266
-
267
- ### Log Output
268
-
269
- When logging is enabled, the following information is logged:
270
-
271
- - **Function Calls**: Service name, method name, arguments, sender ID, and timestamp
272
- - **Success Responses**: Service name, method name, result, and timestamp
273
- - **Error Responses**: Service name, method name, error message, and timestamp
274
- - **Unknown Services/Methods**: Warnings for invalid service or method calls
275
-
276
- ### Use Cases
277
-
278
- - **Development**: Debug RPC communication during development
279
- - **Production Monitoring**: Track RPC usage patterns and performance
280
- - **Troubleshooting**: Identify failed calls and error patterns
281
- - **Security Auditing**: Monitor RPC access patterns
282
-
283
- ## Observable Support
284
-
285
- The framework includes built-in support for reactive data streams using `RemoteSubject` and `Observable` patterns with a centralized message management system.
286
-
287
- ### Remote Subject Manager & Remote Subject (Background Script)
288
-
289
- The `RemoteSubjectManager` acts as a centralized message hub that handles all subscription management and message routing, while `RemoteSubject` focuses purely on state management.
58
+ #### In Background
290
59
 
291
60
  ```typescript
292
61
  // background.ts
293
- import { BackgroundRPC, RemoteSubjectManager, createIdentifier } from 'crx-rpc';
294
-
295
- interface ICounterObservable {
296
- value: number;
297
- }
298
-
299
- const ICounterObservable = createIdentifier<ICounterObservable>('Counter');
300
-
301
- const rpc = new BackgroundRPC();
302
-
303
- // Create a centralized subject manager
304
- const subjectManager = new RemoteSubjectManager();
305
-
306
- // Create a remote subject through the manager
307
- const counterSubject = subjectManager.createSubject(
308
- ICounterObservable,
309
- 'main',
310
- { value: 0 }
311
- );
312
-
313
- // Update value and broadcast to all subscribers
314
- setInterval(() => {
315
- const newValue = { value: Math.floor(Math.random() * 100) };
316
- counterSubject.next(newValue);
317
- }, 1000);
318
-
319
- // The manager handles:
320
- // - Message routing and subscription management
321
- // - Queuing subscriptions that arrive before subjects are created
322
- // - Automatic cleanup when tabs are closed
323
- // - Broadcasting to multiple subscribers
324
-
325
- // Cleanup
326
- // subjectManager.dispose(); // This will dispose all subjects
327
- ```
328
-
329
- ### Key Features of RemoteSubjectManager
330
-
331
- - **Centralized Message Hub**: All observable-related messages are handled by the manager
332
- - **Queue Management**: Subscriptions received before subject creation are queued and processed later
333
- - **Resource Management**: Automatic cleanup of subscriptions when tabs are closed
334
- - **Type Safety**: Full TypeScript support with proper typing throughout
335
-
336
- ### Architecture
337
-
338
- ```
339
- ┌─────────────────┐ ┌──────────────────────────────────────┐ ┌─────────────────┐
340
- │ Web Page │ │ Background Script │ │ Content Script │
341
- ├─────────────────┤ ├──────────────────────────────────────┤ ├─────────────────┤
342
- │ WebObservable │ │ RemoteSubjectManager │ │ContentObservable│
343
- │ │ │ ┌─────────────────────────────────┐ │ │ │
344
- │ subscribe() ────┼───▶│ │ Message Routing & Queue Mgmt │ │◄───┤ subscribe() │
345
- │ │◄───│ │ │ │ │ │
346
- └─────────────────┘ │ └─────────────────────────────────┘ │ └─────────────────┘
347
- │ │ │
348
- │ ┌─────────────▼─────────────────┐ │
349
- │ │ RemoteSubject │ │
350
- │ │ (Pure State Management) │ │
351
- │ │ │ │
352
- │ │ next() ─────────────────────▶ │ │
353
- │ │ complete() ─────────────────▶ │ │
354
- │ └───────────────────────────────┘ │
355
- └──────────────────────────────────────┘
356
- ```
62
+ import { BackgroundRPCHost } from 'crx-rpc';
63
+ import { IMathService } from './api';
357
64
 
358
- ### Subscribing from Web Page
359
-
360
- ```typescript
361
- // web-page.ts
362
- import { WebObservable, createIdentifier } from 'crx-rpc';
363
-
364
- interface ICounterObservable {
365
- value: number;
65
+ class MathService implements IMathService {
66
+ async add(a: number, b: number) {
67
+ return a + b;
68
+ }
366
69
  }
367
70
 
368
- const ICounterObservable = createIdentifier<ICounterObservable>('Counter');
369
-
370
- // Subscribe to remote observable
371
- const observable = new WebObservable(
372
- ICounterObservable,
373
- 'main',
374
- (value) => {
375
- console.log('Counter updated:', value.value);
376
- }
377
- );
378
-
379
- // Cleanup when done
380
- // observable.dispose();
71
+ const host = new BackgroundRPCHost();
72
+ host.register(IMathService, new MathService());
381
73
  ```
382
74
 
383
- ### Subscribing from Content Script
75
+ #### In Content Script
384
76
 
385
77
  ```typescript
386
78
  // content.ts
387
- import { ContentObservable, createIdentifier } from 'crx-rpc';
388
-
389
- interface ICounterObservable {
390
- value: number;
391
- }
392
-
393
- const ICounterObservable = createIdentifier<ICounterObservable>('Counter');
394
-
395
- // Content script can directly subscribe to observables
396
- const observable = new ContentObservable(
397
- ICounterObservable,
398
- 'main',
399
- (value) => {
400
- console.log('Counter from content script:', value.value);
401
- // Content script can react to real-time updates
402
- updateUI(value.value);
403
- }
404
- );
405
-
406
- // Cleanup when done
407
- // observable.dispose();
408
- ```
409
-
410
- ### Subscribing from Extension Page
79
+ import { ContentRPCHost, createIdentifier } from 'crx-rpc';
411
80
 
412
- ```typescript
413
- // popup.ts / options.ts
414
- import { ExtPageObservable, createIdentifier } from 'crx-rpc';
415
-
416
- interface ICounterObservable {
417
- value: number;
81
+ export interface IPageService {
82
+ doSomething(): void;
418
83
  }
84
+ export const IPageService = createIdentifier<IPageService>('page-service', 'content');
419
85
 
420
- const ICounterObservable = createIdentifier<ICounterObservable>('Counter');
421
-
422
- // Extension page can subscribe to background observables
423
- const observable = new ExtPageObservable(
424
- ICounterObservable,
425
- 'main',
426
- (value) => {
427
- console.log('Counter from extension page:', value.value);
428
- document.getElementById('counter').textContent = value.value.toString();
429
- }
430
- );
431
-
432
- // Cleanup when done
433
- window.addEventListener('unload', () => {
434
- observable.dispose();
435
- });
86
+ const host = new ContentRPCHost();
87
+ host.register(IPageService, new PageService());
436
88
  ```
437
89
 
438
- ### Observable Communication Patterns
90
+ ### 3. Call Service
439
91
 
440
- The Observable system supports multiple communication patterns with centralized management:
92
+ #### From Content Script (to Background)
441
93
 
442
94
  ```typescript
443
- // Pattern 1: Background Web Page (via Content Script bridge)
444
- // Background: RemoteSubjectManager creates and manages RemoteSubject
445
- // Background: RemoteSubject.next() → Manager routes to subscribers
446
- // Web Page: WebObservable.subscribe()
447
-
448
- // Pattern 2: Background → Content Script (direct)
449
- // Background: RemoteSubject.next() → Manager routes directly
450
- // Content Script: ContentObservable.subscribe()
451
-
452
- // Pattern 3: Background → Both Web Page and Content Script
453
- // Background: RemoteSubject.next() → Manager broadcasts to all subscribers
454
- // Web Page: WebObservable.subscribe()
455
- // Content Script: ContentObservable.subscribe()
456
-
457
- // Pattern 4: Subscription before Subject Creation (Queue Management)
458
- // Subscriber: WebObservable.subscribe() → Manager queues subscription
459
- // Background: Later creates RemoteSubject → Manager processes queued subscriptions
460
- // Result: No missed initial values, proper subscription ordering
461
- ```
95
+ import { RuntimeRPCClient } from 'crx-rpc';
96
+ import { IMathService } from './api';
462
97
 
463
- ## Advanced Usage
98
+ const client = new RuntimeRPCClient();
99
+ const mathService = client.createRPCService(IMathService);
464
100
 
465
- ### Resource Management with Disposables
101
+ await mathService.add(1, 2);
102
+ ```
466
103
 
467
- All RPC components extend the `Disposable` class for proper cleanup:
104
+ #### From Web Page (to Background)
468
105
 
469
106
  ```typescript
470
- import { WebRPCClient, ContentRPC, BackgroundRPC } from 'crx-rpc';
107
+ import { WebRPCClient } from 'crx-rpc';
108
+ import { IMathService } from './api';
471
109
 
472
110
  const client = new WebRPCClient();
473
- const contentRpc = new ContentRPC();
474
- const backgroundRpc = new BackgroundRPC();
475
-
476
- // Proper cleanup
477
- function cleanup() {
478
- client.dispose();
479
- contentRpc.dispose();
480
- backgroundRpc.dispose();
481
- }
111
+ const mathService = client.createRPCService(IMathService);
482
112
 
483
- // Check if already disposed
484
- if (!client.isDisposed()) {
485
- const service = client.createWebRPCService(IMathService);
486
- // Use service...
487
- }
113
+ await mathService.add(1, 2);
488
114
  ```
489
115
 
490
- ### Extension Page Accessing Content Script Services
491
-
492
- Extension pages can access content script services using `TabRPCClient` by specifying the target tab ID:
116
+ *Note: Requires `Web2BackgroundProxy` to be active in the content script.*
493
117
 
494
118
  ```typescript
495
- // popup.ts
496
- import { TabRPCClient } from 'crx-rpc';
497
- import { IContentService } from './services';
498
-
499
- // Get current active tab
500
- const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
501
-
502
- if (tab.id) {
503
- // Create RPC client for specific tab
504
- const tabClient = new TabRPCClient(tab.id);
505
-
506
- // Access content script services in that tab
507
- const contentService = tabClient.createWebRPCService(IContentService);
508
-
509
- // Call content script methods
510
- const result = await contentService.getDOMInfo();
511
- console.log('DOM info from content script:', result);
512
-
513
- // Cleanup when done
514
- window.addEventListener('unload', () => {
515
- tabClient.dispose();
516
- });
517
- }
119
+ // content.ts
120
+ import { Web2BackgroundProxy } from 'crx-rpc';
121
+ const proxy = new Web2BackgroundProxy();
518
122
  ```
519
123
 
520
- #### Use Cases for Extension Page → Content Script Communication:
521
-
522
- 1. **DOM Inspection**: Popup queries content script for page information
523
- 2. **User Actions**: Options page triggers content script actions on specific tabs
524
- 3. **Multi-tab Management**: Sidepanel coordinates actions across multiple tabs
525
- 4. **Live Preview**: Extension page gets real-time updates from content script
526
-
527
- #### Complete Example: Popup with Tab-specific Services
124
+ #### From Background/Popup (to Content)
528
125
 
529
126
  ```typescript
530
- // content.ts - Register services in content script
531
- import { ContentRPCHost } from 'crx-rpc';
532
- import { IPageService } from './services';
533
-
534
- class PageService implements IPageService {
535
- async getTitle(): Promise<string> {
536
- return document.title;
537
- }
538
-
539
- async getSelection(): Promise<string> {
540
- return window.getSelection()?.toString() || '';
541
- }
542
-
543
- async highlightText(text: string): Promise<void> {
544
- // Highlight logic...
545
- }
546
- }
547
-
548
- const contentHost = new ContentRPCHost();
549
- contentHost.register(IPageService, new PageService());
550
-
551
- // popup.ts - Access content script from popup
552
- import { TabRPCClient, ExtPageRPCClient } from 'crx-rpc';
553
- import { IPageService, IMathService } from './services';
554
-
555
- // Access background services
556
- const bgClient = new ExtPageRPCClient();
557
- const mathService = bgClient.createWebRPCService(IMathService);
558
-
559
- // Access content script services in active tab
560
- const [tab] = await chrome.tabs.query({ active: true, currentWindow: true });
561
- if (tab.id) {
562
- const tabClient = new TabRPCClient(tab.id);
563
- const pageService = tabClient.createWebRPCService(IPageService);
564
-
565
- // Get page info from content script
566
- const title = await pageService.getTitle();
567
- const selection = await pageService.getSelection();
568
-
569
- // Process with background service
570
- const result = await mathService.calculate(selection.length);
571
-
572
- // Update popup UI
573
- document.getElementById('title').textContent = title;
574
- document.getElementById('result').textContent = result.toString();
575
- }
576
- ```
577
-
578
- ## Usage Scenarios
579
-
580
- ### Scenario 1: Web Page Only
581
- - Web pages need to communicate with background services
582
- - Use: `WebRPCClient` + `ContentRPC` bridge
583
-
584
- ### Scenario 2: Content Script Only
585
- - Content scripts need direct access to background services
586
- - Use: `ContentRPCClient` directly (no bridge needed)
127
+ import { TabRPCClient } from 'crx-rpc';
128
+ import { IPageService } from './api';
587
129
 
588
- ### Scenario 3: Both Web Page and Content Script
589
- - Both contexts need RPC access
590
- - Use: `ContentRPC` bridge + `ContentRPCClient` for direct access
130
+ const tabId = 123; // Target Tab ID
131
+ const client = new TabRPCClient(tabId);
132
+ const pageService = client.createRPCService(IPageService);
591
133
 
592
- ### Scenario 4: Real-time Data Streaming
593
- - Background needs to push updates to multiple contexts
594
- - Use: `RemoteSubject` + `WebObservable`/`ContentObservable`
134
+ await pageService.doSomething();
135
+ ```
595
136
 
596
137
  ## API Reference
597
138
 
598
- ### Core Classes
599
-
600
- - **`BackgroundRPC`**: Service registry and message handler for background scripts
601
- - **`ContentRPC`**: Message bridge between web pages and background scripts
602
- - **`WebRPCClient`**: RPC client for web pages
603
- - **`ContentRPCClient`**: Direct RPC client for content scripts
604
- - **`RemoteSubjectManager`**: Centralized observable message management system
605
-
606
- ### Observable Classes
607
-
608
- - **`RemoteSubjectManager`**: Centralized message hub that manages subscriptions and message routing for all observables
609
- - **`RemoteSubject<T>`**: Pure state management observable that works with the manager to broadcast updates
610
- - **`WebObservable<T>`**: Observable subscriber for web pages
611
- - **`ContentObservable<T>`**: Observable subscriber for content scripts
612
-
613
- ### Utility Functions
614
-
615
- - **`createIdentifier<T>(key: string)`**: Creates a type-safe service identifier
616
-
617
- ### Interfaces
618
-
619
- - **`Identifier<T>`**: Type-safe service identifier interface
620
- - **`RpcRequest`**: RPC request message structure
621
- - **`RpcResponse`**: RPC response message structure
622
- - **`IMessageAdapter`**: Message transport abstraction interface
623
- - **`IDisposable`**: Resource management interface
624
-
625
- ## Best Practices
626
-
627
- 1. **Service Interface Design**
628
- - Use clear method names and proper TypeScript types
629
- - Return Promise types for async operation support
630
- - Define detailed parameter and return value types
631
- - Keep interfaces focused and cohesive
632
-
633
- 2. **Resource Management**
634
- - Always call `dispose()` on RPC instances when cleanup is needed
635
- - Check `isDisposed()` before using disposed instances
636
- - Use proper cleanup in component unmount/destroy lifecycle
139
+ ### Hosts
637
140
 
638
- 3. **Error Handling**
639
- - Implement proper error handling in service methods
640
- - Throw meaningful errors with descriptive messages
641
- - Handle RPC errors appropriately on the client side
141
+ - `BackgroundRPCHost`: Handles RPC requests in the background script.
142
+ - `ContentRPCHost`: Handles RPC requests in the content script.
642
143
 
643
- 4. **Performance Optimization**
644
- - Avoid frequent small data transfers
645
- - Consider batching operations when possible
646
- - Use Observable pattern for real-time data updates with `RemoteSubjectManager` for efficient message routing
647
- - Implement caching strategies where appropriate
648
- - The manager automatically handles subscription queuing to prevent race conditions
144
+ ### Clients
649
145
 
650
- 5. **Security Considerations**
651
- - Validate input parameters in service implementations
652
- - Don't expose sensitive operations through RPC
653
- - Consider rate limiting for resource-intensive operations
146
+ - `RuntimeRPCClient`: Used in Content Scripts to call Background services.
147
+ - `WebRPCClient`: Used in Web Pages to call Background services (via relay).
148
+ - `TabRPCClient`: Used in Background/Popup to call Content Script services for a specific tab.
654
149
 
655
- ## License
150
+ ### Proxies
656
151
 
657
- MIT
152
+ - `Web2BackgroundProxy`: Relays messages from Web Page to Background. Must be instantiated in the Content Script.