crx-rpc 1.0.4 → 1.0.6

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
@@ -67,8 +67,9 @@ class MathService implements IMathService {
67
67
  }
68
68
  }
69
69
 
70
- // Register service
71
- const rpc = new BackgroundRPC();
70
+ // Register service with optional logging
71
+ const rpc = new BackgroundRPC(true); // Enable logging
72
+ // const rpc = new BackgroundRPC(); // Disable logging (default)
72
73
  rpc.register(IMathService, new MathService());
73
74
  ```
74
75
 
@@ -179,35 +180,40 @@ async function calculate() {
179
180
  - **BackgroundRPC**: Service registry and handler in the background script
180
181
  - **RPCClient**: Base client with service proxy generation
181
182
 
182
- ## Error Handling
183
+ ## Logging Support
184
+
185
+ The framework includes built-in logging support for debugging and monitoring RPC calls.
183
186
 
184
- The framework preserves error details including stack traces and error types:
187
+ ### Enable Logging
185
188
 
186
189
  ```typescript
187
- const client = new WebRPCClient();
188
- const mathService = client.createWebRPCService(IMathService);
190
+ // Enable logging in BackgroundRPC
191
+ const rpc = new BackgroundRPC(true); // Enable logging
192
+ // const rpc = new BackgroundRPC(); // Disable logging (default)
189
193
 
190
- try {
191
- const result = await mathService.divide(10, 0);
192
- } catch (error) {
193
- console.error('RPC Error:', error.message);
194
- console.error('Stack trace:', error.stack);
195
- console.error('Error name:', error.name);
196
- // Error preserves original stack trace and error type from the background script
197
- }
194
+ // Example output:
195
+ // [RPC] Call: MathService.add { id: "123", args: [5, 3], senderId: 456, timestamp: "2025-09-01T10:00:00.000Z" }
196
+ // [RPC] Success: MathService.add { id: "123", result: 8, timestamp: "2025-09-01T10:00:00.001Z" }
197
+
198
+ // For errors:
199
+ // [RPC] Error: MathService.divide { id: "124", error: "Division by zero", timestamp: "2025-09-01T10:00:01.000Z" }
198
200
  ```
199
201
 
200
- ### Error Structure
202
+ ### Log Output
201
203
 
202
- Errors are transmitted with full details:
204
+ When logging is enabled, the following information is logged:
203
205
 
204
- ```typescript
205
- interface RpcErrorDetails {
206
- message: string;
207
- stack?: string;
208
- name?: string;
209
- }
210
- ```
206
+ - **Function Calls**: Service name, method name, arguments, sender ID, and timestamp
207
+ - **Success Responses**: Service name, method name, result, and timestamp
208
+ - **Error Responses**: Service name, method name, error message, and timestamp
209
+ - **Unknown Services/Methods**: Warnings for invalid service or method calls
210
+
211
+ ### Use Cases
212
+
213
+ - **Development**: Debug RPC communication during development
214
+ - **Production Monitoring**: Track RPC usage patterns and performance
215
+ - **Troubleshooting**: Identify failed calls and error patterns
216
+ - **Security Auditing**: Monitor RPC access patterns
211
217
 
212
218
  ## Observable Support
213
219
 
package/README.zh-CN.md CHANGED
@@ -62,13 +62,14 @@ class MathService implements IMathService {
62
62
  }
63
63
 
64
64
  async divide(a: number, b: number): Promise<number> {
65
- if (b === 0) throw new Error('除零错误');
65
+ if (b === 0) throw new Error('Division by zero');
66
66
  return a / b;
67
67
  }
68
68
  }
69
69
 
70
- // 注册服务
71
- const rpc = new BackgroundRPC();
70
+ // 注册服务,可选择启用日志
71
+ const rpc = new BackgroundRPC(true); // 启用日志
72
+ // const rpc = new BackgroundRPC(); // 禁用日志(默认)
72
73
  rpc.register(IMathService, new MathService());
73
74
  ```
74
75
 
@@ -195,35 +196,40 @@ async function calculate() {
195
196
  - **BackgroundRPC**: 背景脚本中的服务注册表和处理器
196
197
  - **RPCClient**: 具有服务代理生成功能的基础客户端
197
198
 
198
- ## 错误处理
199
+ ## 日志支持
200
+
201
+ 框架包含内置的日志支持,用于调试和监控RPC调用。
199
202
 
200
- 框架保留错误详细信息,包括堆栈跟踪和错误类型:
203
+ ### 启用日志
201
204
 
202
205
  ```typescript
203
- const client = new WebRPCClient();
204
- const mathService = client.createWebRPCService(IMathService);
206
+ // 在BackgroundRPC中启用日志
207
+ const rpc = new BackgroundRPC(true); // 启用日志
208
+ // const rpc = new BackgroundRPC(); // 禁用日志(默认)
205
209
 
206
- try {
207
- const result = await mathService.divide(10, 0);
208
- } catch (error) {
209
- console.error('RPC错误:', error.message);
210
- console.error('堆栈跟踪:', error.stack);
211
- console.error('错误名称:', error.name);
212
- // 错误保留了来自背景脚本的原始堆栈跟踪和错误类型
213
- }
210
+ // 示例输出:
211
+ // [RPC] Call: MathService.add { id: "123", args: [5, 3], senderId: 456, timestamp: "2025-09-01T10:00:00.000Z" }
212
+ // [RPC] Success: MathService.add { id: "123", result: 8, timestamp: "2025-09-01T10:00:00.001Z" }
213
+
214
+ // 对于错误:
215
+ // [RPC] Error: MathService.divide { id: "124", error: "Division by zero", timestamp: "2025-09-01T10:00:01.000Z" }
214
216
  ```
215
217
 
216
- ### 错误结构
218
+ ### 日志输出
217
219
 
218
- 错误会传输完整的详细信息:
220
+ 启用日志时,会记录以下信息:
219
221
 
220
- ```typescript
221
- interface RpcErrorDetails {
222
- message: string;
223
- stack?: string;
224
- name?: string;
225
- }
226
- ```
222
+ - **函数调用**: 服务名、方法名、参数、发送者ID和时间戳
223
+ - **成功响应**: 服务名、方法名、结果和时间戳
224
+ - **错误响应**: 服务名、方法名、错误消息和时间戳
225
+ - **未知服务/方法**: 无效服务或方法调用的警告
226
+
227
+ ### 使用场景
228
+
229
+ - **开发**: 在开发期间调试RPC通信
230
+ - **生产监控**: 跟踪RPC使用模式和性能
231
+ - **故障排除**: 识别失败的调用和错误模式
232
+ - **安全审计**: 监控RPC访问模式
227
233
 
228
234
  ## Observable支持
229
235
 
@@ -2,8 +2,9 @@ import type { Identifier } from './id';
2
2
  import type { SubjectLike, RpcObservableUpdateMessage } from './types';
3
3
  import { Disposable } from './disposable';
4
4
  export declare class BackgroundRPC extends Disposable {
5
+ private log;
5
6
  private services;
6
- constructor();
7
+ constructor(log?: boolean);
7
8
  register<T>(service: Identifier<T>, serviceInstance: T): void;
8
9
  }
9
10
  export declare class RemoteSubject<T> extends Disposable implements SubjectLike<T> {
@@ -1,13 +1,19 @@
1
1
  import { OBSERVABLE_EVENT, RPC_EVENT_NAME, RPC_RESPONSE_EVENT_NAME, SUBSCRIBABLE_OBSERVABLE, UNSUBSCRIBE_OBSERVABLE } from './const';
2
2
  import { Disposable } from './disposable';
3
3
  export class BackgroundRPC extends Disposable {
4
+ log;
4
5
  services = {};
5
- constructor() {
6
+ constructor(log = false) {
6
7
  super();
8
+ this.log = log;
7
9
  const handler = ((msg, sender) => {
8
10
  if (msg.type !== RPC_EVENT_NAME)
9
11
  return;
10
- const senderId = sender.tab.id;
12
+ const senderId = sender.tab?.id;
13
+ if (!senderId) {
14
+ console.warn('Received RPC request from unknown sender, ignoring.', msg);
15
+ return;
16
+ }
11
17
  const sendResponse = (response) => {
12
18
  chrome.tabs.sendMessage(senderId, {
13
19
  ...response,
@@ -16,7 +22,18 @@ export class BackgroundRPC extends Disposable {
16
22
  };
17
23
  const { id, method, args, service } = msg;
18
24
  const serviceInstance = this.services[service];
25
+ if (this.log) {
26
+ console.log(`[RPC] Call: ${service}.${method}`, {
27
+ id,
28
+ args,
29
+ senderId,
30
+ timestamp: new Date().toISOString()
31
+ });
32
+ }
19
33
  if (!serviceInstance) {
34
+ if (this.log) {
35
+ console.warn(`[RPC] Unknown service: ${service}`);
36
+ }
20
37
  const resp = {
21
38
  id,
22
39
  error: { message: `Unknown service: ${service}` },
@@ -27,6 +44,9 @@ export class BackgroundRPC extends Disposable {
27
44
  return true;
28
45
  }
29
46
  if (!(method in serviceInstance)) {
47
+ if (this.log) {
48
+ console.warn(`[RPC] Unknown method: ${service}.${method}`);
49
+ }
30
50
  const resp = {
31
51
  id,
32
52
  error: { message: `Unknown method: ${method}` },
@@ -38,22 +58,40 @@ export class BackgroundRPC extends Disposable {
38
58
  }
39
59
  Promise.resolve()
40
60
  .then(() => serviceInstance[method](...args))
41
- .then((result) => sendResponse({
42
- id,
43
- result,
44
- service,
45
- method
46
- }))
47
- .catch((err) => sendResponse({
48
- id,
49
- error: {
50
- message: err.message,
51
- stack: err.stack,
52
- name: err.name
53
- },
54
- service,
55
- method
56
- }));
61
+ .then((result) => {
62
+ if (this.log) {
63
+ console.log(`[RPC] Success: ${service}.${method}`, {
64
+ id,
65
+ result,
66
+ timestamp: new Date().toISOString()
67
+ });
68
+ }
69
+ sendResponse({
70
+ id,
71
+ result,
72
+ service,
73
+ method
74
+ });
75
+ })
76
+ .catch((err) => {
77
+ if (this.log) {
78
+ console.error(`[RPC] Error: ${service}.${method}`, {
79
+ id,
80
+ error: err.message,
81
+ timestamp: new Date().toISOString()
82
+ });
83
+ }
84
+ sendResponse({
85
+ id,
86
+ error: {
87
+ message: err.message,
88
+ stack: err.stack,
89
+ name: err.name
90
+ },
91
+ service,
92
+ method
93
+ });
94
+ });
57
95
  return true; // 异步 sendResponse
58
96
  });
59
97
  chrome.runtime.onMessage.addListener(handler);
@@ -115,9 +153,11 @@ export class RemoteSubjectManager extends Disposable {
115
153
  constructor() {
116
154
  super();
117
155
  const handleMessage = (msg, sender) => {
118
- const senderId = sender.tab.id;
119
- if (!senderId)
156
+ const senderId = sender.tab?.id;
157
+ if (!senderId) {
158
+ console.warn('Received RPC request from unknown sender, ignoring.', msg);
120
159
  return;
160
+ }
121
161
  if (msg.type === SUBSCRIBABLE_OBSERVABLE) {
122
162
  const { key } = msg;
123
163
  this.handleSubscription(key, senderId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "crx-rpc",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
4
4
  "description": "A lightweight RPC framework for Chrome Extension (background <-> content <-> web)",
5
5
  "repository": {
6
6
  "type": "git",
package/src/background.ts CHANGED
@@ -6,11 +6,15 @@ import { Disposable } from './disposable';
6
6
  export class BackgroundRPC extends Disposable {
7
7
  private services: Record<string, RpcService> = {};
8
8
 
9
- constructor() {
9
+ constructor(private log: boolean = false) {
10
10
  super();
11
11
  const handler = ((msg: RpcRequest & { type?: string }, sender: chrome.runtime.MessageSender) => {
12
12
  if (msg.type !== RPC_EVENT_NAME) return;
13
- const senderId = sender.tab!.id!;
13
+ const senderId = sender.tab?.id;
14
+ if (!senderId) {
15
+ console.warn('Received RPC request from unknown sender, ignoring.', msg);
16
+ return;
17
+ }
14
18
  const sendResponse = (response: RpcResponse) => {
15
19
  chrome.tabs.sendMessage(senderId, {
16
20
  ...response,
@@ -21,7 +25,19 @@ export class BackgroundRPC extends Disposable {
21
25
  const { id, method, args, service } = msg;
22
26
  const serviceInstance = this.services[service];
23
27
 
28
+ if (this.log) {
29
+ console.log(`[RPC] Call: ${service}.${method}`, {
30
+ id,
31
+ args,
32
+ senderId,
33
+ timestamp: new Date().toISOString()
34
+ });
35
+ }
36
+
24
37
  if (!serviceInstance) {
38
+ if (this.log) {
39
+ console.warn(`[RPC] Unknown service: ${service}`);
40
+ }
25
41
  const resp: RpcResponse = {
26
42
  id,
27
43
  error: { message: `Unknown service: ${service}` },
@@ -33,6 +49,9 @@ export class BackgroundRPC extends Disposable {
33
49
  }
34
50
 
35
51
  if (!(method in serviceInstance)) {
52
+ if (this.log) {
53
+ console.warn(`[RPC] Unknown method: ${service}.${method}`);
54
+ }
36
55
  const resp: RpcResponse = {
37
56
  id,
38
57
  error: { message: `Unknown method: ${method}` },
@@ -45,22 +64,40 @@ export class BackgroundRPC extends Disposable {
45
64
 
46
65
  Promise.resolve()
47
66
  .then(() => serviceInstance[method](...args))
48
- .then((result) => sendResponse({
49
- id,
50
- result,
51
- service,
52
- method
53
- }))
54
- .catch((err) => sendResponse({
55
- id,
56
- error: {
57
- message: err.message,
58
- stack: err.stack,
59
- name: err.name
60
- },
61
- service,
62
- method
63
- }));
67
+ .then((result) => {
68
+ if (this.log) {
69
+ console.log(`[RPC] Success: ${service}.${method}`, {
70
+ id,
71
+ result,
72
+ timestamp: new Date().toISOString()
73
+ });
74
+ }
75
+ sendResponse({
76
+ id,
77
+ result,
78
+ service,
79
+ method
80
+ });
81
+ })
82
+ .catch((err) => {
83
+ if (this.log) {
84
+ console.error(`[RPC] Error: ${service}.${method}`, {
85
+ id,
86
+ error: err.message,
87
+ timestamp: new Date().toISOString()
88
+ });
89
+ }
90
+ sendResponse({
91
+ id,
92
+ error: {
93
+ message: err.message,
94
+ stack: err.stack,
95
+ name: err.name
96
+ },
97
+ service,
98
+ method
99
+ });
100
+ });
64
101
 
65
102
  return true; // 异步 sendResponse
66
103
  });
@@ -130,8 +167,11 @@ export class RemoteSubjectManager extends Disposable {
130
167
  super();
131
168
 
132
169
  const handleMessage = (msg: RpcObservableSubscribeMessage, sender: chrome.runtime.MessageSender) => {
133
- const senderId = sender.tab!.id!;
134
- if (!senderId) return;
170
+ const senderId = sender.tab?.id;
171
+ if (!senderId) {
172
+ console.warn('Received RPC request from unknown sender, ignoring.', msg);
173
+ return;
174
+ }
135
175
 
136
176
  if (msg.type === SUBSCRIBABLE_OBSERVABLE) {
137
177
  const { key } = msg;