@wishcore/wish-rpc 0.6.14 → 0.6.16

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 (40) hide show
  1. package/dist/index.d.ts +71 -0
  2. package/dist/{src/index.js → index.js} +2 -0
  3. package/dist/method-registry.d.ts +60 -0
  4. package/dist/method-registry.js +135 -0
  5. package/dist/rpc-client.d.ts +59 -0
  6. package/dist/rpc-client.js +176 -0
  7. package/dist/rpc-protocol.d.ts +35 -0
  8. package/dist/rpc-protocol.js +43 -0
  9. package/dist/rpc-server.d.ts +171 -0
  10. package/dist/rpc-server.js +523 -0
  11. package/package.json +9 -4
  12. package/dist/src/index.d.ts +0 -28
  13. package/dist/src/index.js.map +0 -1
  14. package/dist/src/rpc-client.d.ts +0 -16
  15. package/dist/src/rpc-client.js +0 -109
  16. package/dist/src/rpc-client.js.map +0 -1
  17. package/dist/src/rpc-server.d.ts +0 -67
  18. package/dist/src/rpc-server.js +0 -443
  19. package/dist/src/rpc-server.js.map +0 -1
  20. package/dist/test/stream-clean.spec.d.ts +0 -1
  21. package/dist/test/stream-clean.spec.js +0 -146
  22. package/dist/test/stream-clean.spec.js.map +0 -1
  23. package/dist/test/stream.spec.d.ts +0 -1
  24. package/dist/test/stream.spec.js +0 -113
  25. package/dist/test/stream.spec.js.map +0 -1
  26. package/dist/test/test-client.d.ts +0 -1
  27. package/dist/test/test-client.js +0 -88
  28. package/dist/test/test-client.js.map +0 -1
  29. package/dist/test/test-rpc-acl.d.ts +0 -1
  30. package/dist/test/test-rpc-acl.js +0 -103
  31. package/dist/test/test-rpc-acl.js.map +0 -1
  32. package/dist/test/test-rpc.spec.d.ts +0 -1
  33. package/dist/test/test-rpc.spec.js +0 -143
  34. package/dist/test/test-rpc.spec.js.map +0 -1
  35. package/dist/test/test-session.spec.d.ts +0 -1
  36. package/dist/test/test-session.spec.js +0 -46
  37. package/dist/test/test-session.spec.js.map +0 -1
  38. package/dist/test/test-stream.d.ts +0 -1
  39. package/dist/test/test-stream.js +0 -253
  40. package/dist/test/test-stream.js.map +0 -1
@@ -0,0 +1,71 @@
1
+ export interface MethodMap {
2
+ [endpoint: string]: any;
3
+ }
4
+ export interface EndpointConfig {
5
+ doc?: string;
6
+ args?: string;
7
+ validate?: (args: any[], context: any) => any;
8
+ validateResult?: (result: any) => any;
9
+ fullname?: string;
10
+ [key: string]: any;
11
+ }
12
+ export interface BaseEndpointConfig {
13
+ doc?: string;
14
+ args?: string;
15
+ fullname?: string;
16
+ [key: string]: any;
17
+ }
18
+ export interface EndpointHandler {
19
+ (req: RpcRequest, res: RpcResponse, context?: any): any;
20
+ }
21
+ export interface RpcRequest {
22
+ args: any[];
23
+ id?: number;
24
+ op?: string;
25
+ context?: any;
26
+ end?: any;
27
+ send?: any;
28
+ }
29
+ export interface RpcResponse {
30
+ send(data?: any): void;
31
+ emit(data?: any): void;
32
+ error(data?: any): void;
33
+ close(data?: any): void;
34
+ }
35
+ export interface RequestMessage {
36
+ op: string;
37
+ args?: any[];
38
+ id?: number;
39
+ push?: number;
40
+ sig?: number;
41
+ data?: any;
42
+ end?: number;
43
+ stream?: any;
44
+ }
45
+ export interface ResponseMessage {
46
+ ack?: number;
47
+ err?: number;
48
+ sig?: number;
49
+ end?: number;
50
+ push?: number;
51
+ data?: any;
52
+ fin?: number;
53
+ }
54
+ export interface RequestContext {
55
+ id?: number;
56
+ op?: string;
57
+ args?: any[];
58
+ context?: any;
59
+ end?: any;
60
+ send?: any;
61
+ data?: any;
62
+ }
63
+ export interface RequestMap {
64
+ [clientId: string]: {
65
+ [requestId: string]: RequestContext;
66
+ };
67
+ }
68
+ export * from './rpc-client';
69
+ export * from './rpc-server';
70
+ export * from './rpc-protocol';
71
+ export * from './method-registry';
@@ -12,4 +12,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  __exportStar(require("./rpc-client"), exports);
14
14
  __exportStar(require("./rpc-server"), exports);
15
+ __exportStar(require("./rpc-protocol"), exports);
16
+ __exportStar(require("./method-registry"), exports);
15
17
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,60 @@
1
+ import { EndpointConfig, EndpointHandler, MethodMap, BaseEndpointConfig } from './index';
2
+ /**
3
+ * Manages RPC method registration and retrieval
4
+ */
5
+ export declare class MethodRegistry<T extends BaseEndpointConfig = EndpointConfig> {
6
+ private modules;
7
+ private methods;
8
+ /**
9
+ * Register a new endpoint with modern syntax
10
+ */
11
+ registerEndpoint(name: string, config: T, handler: EndpointHandler): void;
12
+ /**
13
+ * Register methods using legacy underscore-prefixed structure
14
+ */
15
+ registerLegacyMethods(methodMap: MethodMap): void;
16
+ /**
17
+ * Get all registered modules
18
+ */
19
+ getModules(): Record<string, T>;
20
+ /**
21
+ * Get all registered methods
22
+ */
23
+ getMethods(): Record<string, EndpointHandler>;
24
+ /**
25
+ * Get a specific method by name
26
+ */
27
+ getMethod(name: string): EndpointHandler | undefined;
28
+ /**
29
+ * Get a specific module config by name
30
+ */
31
+ getModule(name: string): T | undefined;
32
+ /**
33
+ * Check if a method exists
34
+ */
35
+ hasMethod(name: string): boolean;
36
+ /**
37
+ * Get method listing excluding internal fields
38
+ */
39
+ getMethodListing(): Record<string, Partial<T>>;
40
+ /**
41
+ * Recursively processes method map with underscore-prefixed descriptors
42
+ */
43
+ private processMethodMap;
44
+ /**
45
+ * Registers a single method using legacy format
46
+ */
47
+ private registerLegacyMethod;
48
+ /**
49
+ * Creates a copy of config object excluding specified fields
50
+ */
51
+ private copyConfig;
52
+ /**
53
+ * Checks if a key represents module metadata
54
+ */
55
+ private isModuleMeta;
56
+ /**
57
+ * Checks if a key is a descriptor (starts with underscore)
58
+ */
59
+ private isDescriptor;
60
+ }
@@ -0,0 +1,135 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MethodRegistry = void 0;
4
+ /**
5
+ * Manages RPC method registration and retrieval
6
+ */
7
+ class MethodRegistry {
8
+ constructor() {
9
+ this.modules = {};
10
+ this.methods = {};
11
+ }
12
+ /**
13
+ * Register a new endpoint with modern syntax
14
+ */
15
+ registerEndpoint(name, config, handler) {
16
+ if (!name || typeof name !== 'string') {
17
+ throw new Error('Endpoint name must be a non-empty string');
18
+ }
19
+ if (typeof handler !== 'function') {
20
+ throw new Error('Endpoint handler must be a function');
21
+ }
22
+ this.modules[name] = Object.assign(Object.assign({}, config), { fullname: name });
23
+ this.methods[name] = handler;
24
+ }
25
+ /**
26
+ * Register methods using legacy underscore-prefixed structure
27
+ */
28
+ registerLegacyMethods(methodMap) {
29
+ this.processMethodMap('', methodMap);
30
+ }
31
+ /**
32
+ * Get all registered modules
33
+ */
34
+ getModules() {
35
+ return Object.assign({}, this.modules);
36
+ }
37
+ /**
38
+ * Get all registered methods
39
+ */
40
+ getMethods() {
41
+ return Object.assign({}, this.methods);
42
+ }
43
+ /**
44
+ * Get a specific method by name
45
+ */
46
+ getMethod(name) {
47
+ return this.methods[name];
48
+ }
49
+ /**
50
+ * Get a specific module config by name
51
+ */
52
+ getModule(name) {
53
+ return this.modules[name];
54
+ }
55
+ /**
56
+ * Check if a method exists
57
+ */
58
+ hasMethod(name) {
59
+ return name in this.methods;
60
+ }
61
+ /**
62
+ * Get method listing excluding internal fields
63
+ */
64
+ getMethodListing() {
65
+ const result = {};
66
+ const excludeFields = new Set(['fullname']);
67
+ for (const methodName in this.modules) {
68
+ const config = this.modules[methodName];
69
+ result[methodName] = this.copyConfig(config, excludeFields);
70
+ }
71
+ return result;
72
+ }
73
+ /**
74
+ * Recursively processes method map with underscore-prefixed descriptors
75
+ */
76
+ processMethodMap(path, methodMap) {
77
+ const prefix = path ? `${path}.` : '';
78
+ for (const key in methodMap) {
79
+ if (this.isModuleMeta(key) || this.isDescriptor(key)) {
80
+ continue;
81
+ }
82
+ const descriptor = methodMap[`_${key}`];
83
+ if (!descriptor) {
84
+ continue;
85
+ }
86
+ const item = methodMap[key];
87
+ if (typeof item === 'function') {
88
+ this.registerLegacyMethod(prefix, key, descriptor, item);
89
+ }
90
+ else if (typeof item === 'object' && item !== null) {
91
+ this.processMethodMap(`${prefix}${key}`, item);
92
+ }
93
+ }
94
+ }
95
+ /**
96
+ * Registers a single method using legacy format
97
+ */
98
+ registerLegacyMethod(prefix, name, descriptor, handler) {
99
+ const fullName = prefix + (descriptor.name || name);
100
+ const config = Object.assign(Object.assign({}, descriptor), { fullname: fullName });
101
+ try {
102
+ this.modules[fullName] = config;
103
+ this.methods[fullName] = handler;
104
+ }
105
+ catch (error) {
106
+ console.error(`Failed to register method ${fullName}:`, error);
107
+ }
108
+ }
109
+ /**
110
+ * Creates a copy of config object excluding specified fields
111
+ */
112
+ copyConfig(source, excludeFields) {
113
+ const result = {};
114
+ for (const key in source) {
115
+ if (!excludeFields.has(key) && Object.prototype.hasOwnProperty.call(source, key)) {
116
+ result[key] = source[key];
117
+ }
118
+ }
119
+ return result;
120
+ }
121
+ /**
122
+ * Checks if a key represents module metadata
123
+ */
124
+ isModuleMeta(key) {
125
+ return key === '_';
126
+ }
127
+ /**
128
+ * Checks if a key is a descriptor (starts with underscore)
129
+ */
130
+ isDescriptor(key) {
131
+ return key.startsWith('_');
132
+ }
133
+ }
134
+ exports.MethodRegistry = MethodRegistry;
135
+ //# sourceMappingURL=method-registry.js.map
@@ -0,0 +1,59 @@
1
+ import { ResponseMessage } from './index';
2
+ export declare class Client {
3
+ private write;
4
+ private requests;
5
+ private id;
6
+ private mtu;
7
+ constructor(write: (msg: ResponseMessage) => void, opts?: {
8
+ mtu: number;
9
+ });
10
+ destroy(): void;
11
+ messageReceived(msg: any): void;
12
+ /**
13
+ * @deprecated Use request() without callback instead - it now returns a Promise
14
+ */
15
+ requestAsync(op: string, args: any[]): Promise<any>;
16
+ /**
17
+ * Make an RPC request.
18
+ *
19
+ * Without callback: Returns a Promise that resolves with the response.
20
+ * With callback: Returns request ID for streaming/signal subscriptions.
21
+ *
22
+ * @example
23
+ * // Promise style (recommended for one-shot requests)
24
+ * const result = await client.request('method', [arg1, arg2]);
25
+ *
26
+ * // Callback style (for streaming responses or signals)
27
+ * client.request('signals', [], (err, data, end) => {
28
+ * if (data) console.log('Signal:', data);
29
+ * });
30
+ */
31
+ request(op: string, args: any[]): Promise<any>;
32
+ request(op: string, args: any[], cb: (err: any, data: any, end?: boolean) => any): number;
33
+ private requestWithCallback;
34
+ /**
35
+ * Subscribe to signals from the server.
36
+ *
37
+ * @param event - Signal event name to filter (e.g., 'document.changed'), or null for all signals
38
+ * @param callback - Called when a matching signal is received
39
+ * @param endpoint - RPC endpoint to subscribe to (default: 'signals')
40
+ * @returns Unsubscribe function
41
+ *
42
+ * @example
43
+ * // Subscribe to specific signal
44
+ * const unsub = client.subscribe('document.changed', (data) => {
45
+ * console.log('Document changed:', data);
46
+ * });
47
+ *
48
+ * // Subscribe to all signals
49
+ * const unsub = client.subscribe(null, (event, data) => {
50
+ * console.log('Signal:', event, data);
51
+ * });
52
+ *
53
+ * // Unsubscribe when done
54
+ * unsub();
55
+ */
56
+ subscribe(event: string | null, callback: (eventOrData: any, data?: any) => void, endpoint?: string): () => void;
57
+ send(id: number, data: any): void;
58
+ end(id: number): void;
59
+ }
@@ -0,0 +1,176 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.Client = void 0;
13
+ class Client {
14
+ constructor(write, opts) {
15
+ this.write = write;
16
+ this.requests = {};
17
+ this.id = 0;
18
+ this.mtu = 65535;
19
+ if (opts && opts.mtu) {
20
+ this.mtu = opts.mtu;
21
+ }
22
+ }
23
+ destroy() {
24
+ // Reject all pending requests with disconnect error
25
+ if (this.requests) {
26
+ for (const id of Object.keys(this.requests)) {
27
+ const request = this.requests[id];
28
+ if (request && typeof request.cb === 'function' && !request.canceled) {
29
+ request.cb.call(request.context, { code: 'DISCONNECTED', msg: 'Connection closed' }, null, true);
30
+ }
31
+ }
32
+ }
33
+ this.requests = null;
34
+ this.write = null;
35
+ this.id = 0;
36
+ }
37
+ messageReceived(msg) {
38
+ //console.log("RpcClient received message", msg);
39
+ const end = !!(msg.err || msg.ack || msg.fin);
40
+ const id = msg.ack || msg.err || msg.sig || msg.fin;
41
+ const request = this.requests[id];
42
+ let retval;
43
+ if (request && typeof request.cb === 'function') {
44
+ let err;
45
+ if (msg.fin) {
46
+ // This request closed gracefully
47
+ request.cb.call(request.context, null, null, true);
48
+ }
49
+ else {
50
+ if (request.canceled) {
51
+ console.log('This request is canceled. Not calling the callback.');
52
+ }
53
+ else {
54
+ // all is good, call the callback function
55
+ err = msg.err ? msg.data : null;
56
+ retval = request.cb.call(request.context, err, msg.data, end);
57
+ }
58
+ }
59
+ }
60
+ if (end) {
61
+ //console.log("deleting this request", id);
62
+ delete this.requests[id];
63
+ }
64
+ return retval;
65
+ }
66
+ /**
67
+ * @deprecated Use request() without callback instead - it now returns a Promise
68
+ */
69
+ requestAsync(op, args) {
70
+ return __awaiter(this, void 0, void 0, function* () {
71
+ return this.request(op, args);
72
+ });
73
+ }
74
+ request(op, args, cb) {
75
+ // Promise mode when no callback provided
76
+ if (!cb) {
77
+ return new Promise((resolve, reject) => {
78
+ this.requestWithCallback(op, args, (err, data) => {
79
+ if (err) {
80
+ reject(data);
81
+ }
82
+ else {
83
+ resolve(data);
84
+ }
85
+ });
86
+ });
87
+ }
88
+ // Callback mode
89
+ return this.requestWithCallback(op, args, cb);
90
+ }
91
+ requestWithCallback(op, args, cb) {
92
+ this.id++;
93
+ const msg = { op };
94
+ if (Array.isArray(args)) {
95
+ msg.args = args;
96
+ }
97
+ msg.id = this.id;
98
+ this.requests[msg.id] = {
99
+ cb,
100
+ context: {
101
+ id: msg.id,
102
+ cancel: () => {
103
+ setTimeout(((id) => {
104
+ return () => {
105
+ if (this.requests[id]) {
106
+ console.log('rpc-client.js: timeout, the request has not been removed while it was canceled', id, this.requests[id]);
107
+ }
108
+ };
109
+ })(msg.id), 1500);
110
+ this.requests[msg.id].canceled = true;
111
+ this.write({ end: msg.id });
112
+ },
113
+ emit: (data) => {
114
+ return this.write({ sig: msg.id, data: data });
115
+ }
116
+ }
117
+ };
118
+ this.write(msg);
119
+ return msg.id;
120
+ }
121
+ /**
122
+ * Subscribe to signals from the server.
123
+ *
124
+ * @param event - Signal event name to filter (e.g., 'document.changed'), or null for all signals
125
+ * @param callback - Called when a matching signal is received
126
+ * @param endpoint - RPC endpoint to subscribe to (default: 'signals')
127
+ * @returns Unsubscribe function
128
+ *
129
+ * @example
130
+ * // Subscribe to specific signal
131
+ * const unsub = client.subscribe('document.changed', (data) => {
132
+ * console.log('Document changed:', data);
133
+ * });
134
+ *
135
+ * // Subscribe to all signals
136
+ * const unsub = client.subscribe(null, (event, data) => {
137
+ * console.log('Signal:', event, data);
138
+ * });
139
+ *
140
+ * // Unsubscribe when done
141
+ * unsub();
142
+ */
143
+ subscribe(event, callback, endpoint = 'signals') {
144
+ const requestId = this.request(endpoint, [], (err, signalData, end) => {
145
+ if (err || end)
146
+ return;
147
+ if (!signalData || !Array.isArray(signalData))
148
+ return;
149
+ const [signalEvent, ...args] = signalData;
150
+ if (event === null) {
151
+ // Pass all signals: callback(event, data)
152
+ callback(signalEvent, args.length === 1 ? args[0] : args);
153
+ }
154
+ else if (signalEvent === event) {
155
+ // Pass only matching signals: callback(data)
156
+ callback(args.length === 1 ? args[0] : args);
157
+ }
158
+ });
159
+ // Return unsubscribe function
160
+ return () => {
161
+ if (this.requests && this.requests[requestId]) {
162
+ this.requests[requestId].canceled = true;
163
+ this.write({ end: requestId });
164
+ delete this.requests[requestId];
165
+ }
166
+ };
167
+ }
168
+ send(id, data) {
169
+ this.write({ push: id, data });
170
+ }
171
+ end(id) {
172
+ this.write({ end: id });
173
+ }
174
+ }
175
+ exports.Client = Client;
176
+ //# sourceMappingURL=rpc-client.js.map
@@ -0,0 +1,35 @@
1
+ import { Server } from './rpc-server';
2
+ import { EndpointConfig, EndpointHandler } from './index';
3
+ /**
4
+ * Base class for P2P protocol handlers.
5
+ *
6
+ * Subclass to define endpoints and peer lifecycle:
7
+ *
8
+ * ```typescript
9
+ * class NotesProtocol extends Protocol {
10
+ * constructor() {
11
+ * super();
12
+ * this.endpoint('list', { doc: 'List notes' }, async (req, res) => {
13
+ * res.send(myNotes);
14
+ * });
15
+ * }
16
+ *
17
+ * online(peer: Peer, client: Client) {
18
+ * console.log('Peer online:', peer.toString());
19
+ * }
20
+ * }
21
+ * ```
22
+ *
23
+ * Generic parameters allow typed peer/client when re-exported from wish-sdk:
24
+ * - P = Peer type (defaults to any for wish-rpc standalone use)
25
+ * - C = Client type (defaults to any for wish-rpc standalone use)
26
+ */
27
+ export declare class Protocol<P = any, C = any> {
28
+ server: Server<EndpointConfig>;
29
+ /** Register an RPC endpoint */
30
+ endpoint(name: string, config: EndpointConfig, handler: EndpointHandler): void;
31
+ /** Called when a peer comes online */
32
+ online(peer: P, client: C): void;
33
+ /** Called when a peer goes offline */
34
+ offline(peer: P): void;
35
+ }
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Protocol = void 0;
4
+ const rpc_server_1 = require("./rpc-server");
5
+ /**
6
+ * Base class for P2P protocol handlers.
7
+ *
8
+ * Subclass to define endpoints and peer lifecycle:
9
+ *
10
+ * ```typescript
11
+ * class NotesProtocol extends Protocol {
12
+ * constructor() {
13
+ * super();
14
+ * this.endpoint('list', { doc: 'List notes' }, async (req, res) => {
15
+ * res.send(myNotes);
16
+ * });
17
+ * }
18
+ *
19
+ * online(peer: Peer, client: Client) {
20
+ * console.log('Peer online:', peer.toString());
21
+ * }
22
+ * }
23
+ * ```
24
+ *
25
+ * Generic parameters allow typed peer/client when re-exported from wish-sdk:
26
+ * - P = Peer type (defaults to any for wish-rpc standalone use)
27
+ * - C = Client type (defaults to any for wish-rpc standalone use)
28
+ */
29
+ class Protocol {
30
+ constructor() {
31
+ this.server = new rpc_server_1.Server();
32
+ }
33
+ /** Register an RPC endpoint */
34
+ endpoint(name, config, handler) {
35
+ this.server.endpoint(name, config, handler);
36
+ }
37
+ /** Called when a peer comes online */
38
+ online(peer, client) { }
39
+ /** Called when a peer goes offline */
40
+ offline(peer) { }
41
+ }
42
+ exports.Protocol = Protocol;
43
+ //# sourceMappingURL=rpc-protocol.js.map