@irpclib/irpc 0.0.1
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/dist/batch.d.ts +18 -0
- package/dist/batch.js +23 -0
- package/dist/call.d.ts +43 -0
- package/dist/call.js +52 -0
- package/dist/context.d.ts +40 -0
- package/dist/context.js +51 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +8 -0
- package/dist/module.d.ts +17 -0
- package/dist/module.js +156 -0
- package/dist/types.d.ts +224 -0
- package/dist/types.js +8 -0
- package/dist/utils.d.ts +17 -0
- package/dist/utils.js +26 -0
- package/package.json +52 -0
- package/readme.md +166 -0
package/dist/batch.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { IRPCCall } from "./call.js";
|
|
2
|
+
|
|
3
|
+
//#region src/batch.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Batches multiple IRPC calls together and executes them with a specified delay.
|
|
7
|
+
*
|
|
8
|
+
* This function collects IRPC calls in a queue and executes them all at once after
|
|
9
|
+
* a specified delay has passed. If multiple calls are made within the delay period,
|
|
10
|
+
* they will be grouped together in a single batch execution.
|
|
11
|
+
*
|
|
12
|
+
* @param call - The IRPC call to be added to the current batch
|
|
13
|
+
* @param handler - A function that will be called with all queued calls when the batch executes
|
|
14
|
+
* @param delay - The delay in milliseconds before executing the batch (default: 0)
|
|
15
|
+
*/
|
|
16
|
+
declare function batch(call: IRPCCall, handler: (calls: IRPCCall[]) => void, delay?: number): void;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { batch };
|
package/dist/batch.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/batch.ts
|
|
2
|
+
const IRPC_QUEUE = /* @__PURE__ */ new Set();
|
|
3
|
+
/**
|
|
4
|
+
* Batches multiple IRPC calls together and executes them with a specified delay.
|
|
5
|
+
*
|
|
6
|
+
* This function collects IRPC calls in a queue and executes them all at once after
|
|
7
|
+
* a specified delay has passed. If multiple calls are made within the delay period,
|
|
8
|
+
* they will be grouped together in a single batch execution.
|
|
9
|
+
*
|
|
10
|
+
* @param call - The IRPC call to be added to the current batch
|
|
11
|
+
* @param handler - A function that will be called with all queued calls when the batch executes
|
|
12
|
+
* @param delay - The delay in milliseconds before executing the batch (default: 0)
|
|
13
|
+
*/
|
|
14
|
+
function batch(call, handler, delay = 0) {
|
|
15
|
+
if (!IRPC_QUEUE.size) setTimeout(() => {
|
|
16
|
+
handler([...IRPC_QUEUE.values()]);
|
|
17
|
+
IRPC_QUEUE.clear();
|
|
18
|
+
}, delay);
|
|
19
|
+
IRPC_QUEUE.add(call);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
//#endregion
|
|
23
|
+
export { batch };
|
package/dist/call.d.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { IRPCPayload } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/call.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Represents an RPC call with promise-like behavior for handling asynchronous operations.
|
|
7
|
+
* Each call has a unique identifier and manages its own resolution state.
|
|
8
|
+
*/
|
|
9
|
+
declare class IRPCCall {
|
|
10
|
+
payload: IRPCPayload;
|
|
11
|
+
resolver: (value: unknown) => void;
|
|
12
|
+
rejector: (reason?: Error) => void;
|
|
13
|
+
/**
|
|
14
|
+
* Unique identifier for this RPC call, generated using shortId().
|
|
15
|
+
*/
|
|
16
|
+
id: string;
|
|
17
|
+
/**
|
|
18
|
+
* Flag indicating whether this call has been resolved or rejected.
|
|
19
|
+
* Prevents multiple resolutions of the same call.
|
|
20
|
+
*/
|
|
21
|
+
resolved: boolean;
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new IRPCCall instance.
|
|
24
|
+
* @param payload - The RPC payload containing method and parameters
|
|
25
|
+
* @param resolver - Function to resolve the associated promise with a value
|
|
26
|
+
* @param rejector - Function to reject the associated promise with an error
|
|
27
|
+
*/
|
|
28
|
+
constructor(payload: IRPCPayload, resolver: (value: unknown) => void, rejector: (reason?: Error) => void);
|
|
29
|
+
/**
|
|
30
|
+
* Resolves the RPC call with the provided value.
|
|
31
|
+
* If the call is already resolved, this method does nothing.
|
|
32
|
+
* @param value - The value to resolve the promise with
|
|
33
|
+
*/
|
|
34
|
+
resolve(value: unknown): void;
|
|
35
|
+
/**
|
|
36
|
+
* Rejects the RPC call with the provided reason.
|
|
37
|
+
* If the call is already resolved, this method does nothing.
|
|
38
|
+
* @param reason - Optional error reason for rejecting the promise
|
|
39
|
+
*/
|
|
40
|
+
reject(reason?: Error): void;
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
export { IRPCCall };
|
package/dist/call.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { shortId } from "./utils.js";
|
|
2
|
+
|
|
3
|
+
//#region src/call.ts
|
|
4
|
+
/**
|
|
5
|
+
* Represents an RPC call with promise-like behavior for handling asynchronous operations.
|
|
6
|
+
* Each call has a unique identifier and manages its own resolution state.
|
|
7
|
+
*/
|
|
8
|
+
var IRPCCall = class {
|
|
9
|
+
/**
|
|
10
|
+
* Unique identifier for this RPC call, generated using shortId().
|
|
11
|
+
*/
|
|
12
|
+
id = shortId();
|
|
13
|
+
/**
|
|
14
|
+
* Flag indicating whether this call has been resolved or rejected.
|
|
15
|
+
* Prevents multiple resolutions of the same call.
|
|
16
|
+
*/
|
|
17
|
+
resolved = false;
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new IRPCCall instance.
|
|
20
|
+
* @param payload - The RPC payload containing method and parameters
|
|
21
|
+
* @param resolver - Function to resolve the associated promise with a value
|
|
22
|
+
* @param rejector - Function to reject the associated promise with an error
|
|
23
|
+
*/
|
|
24
|
+
constructor(payload, resolver, rejector) {
|
|
25
|
+
this.payload = payload;
|
|
26
|
+
this.resolver = resolver;
|
|
27
|
+
this.rejector = rejector;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolves the RPC call with the provided value.
|
|
31
|
+
* If the call is already resolved, this method does nothing.
|
|
32
|
+
* @param value - The value to resolve the promise with
|
|
33
|
+
*/
|
|
34
|
+
resolve(value) {
|
|
35
|
+
if (this.resolved) return;
|
|
36
|
+
this.resolved = true;
|
|
37
|
+
this.resolver(value);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Rejects the RPC call with the provided reason.
|
|
41
|
+
* If the call is already resolved, this method does nothing.
|
|
42
|
+
* @param reason - Optional error reason for rejecting the promise
|
|
43
|
+
*/
|
|
44
|
+
reject(reason) {
|
|
45
|
+
if (this.resolved) return;
|
|
46
|
+
this.resolved = true;
|
|
47
|
+
this.rejector(reason);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
//#endregion
|
|
52
|
+
export { IRPCCall };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { IRPCContext, IRPCContextProvider } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/context.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Sets the global context store for the IRPC system.
|
|
7
|
+
* This store is used to manage context data across requests.
|
|
8
|
+
* @param store - The context store implementation to use
|
|
9
|
+
*/
|
|
10
|
+
declare function setContextProvider(store: IRPCContextProvider): void;
|
|
11
|
+
/**
|
|
12
|
+
* Executes a function with the provided context.
|
|
13
|
+
* If a context store is available, it runs the function within that context.
|
|
14
|
+
* Otherwise, it executes the function directly.
|
|
15
|
+
* @param ctx - The context to run the function with
|
|
16
|
+
* @param fn - The function to execute
|
|
17
|
+
* @returns The result of the executed function
|
|
18
|
+
*/
|
|
19
|
+
declare function withContext<R>(ctx: IRPCContext<string, unknown>, fn: () => R): R;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new context map with optional initial values.
|
|
22
|
+
* @param init - Optional initial key-value pairs for the context
|
|
23
|
+
* @returns A new Map instance representing the context
|
|
24
|
+
*/
|
|
25
|
+
declare function createContext<K extends string, V>(init?: [K, V][]): Map<K, V>;
|
|
26
|
+
/**
|
|
27
|
+
* Sets a value in the current context.
|
|
28
|
+
* @param key - The key to set in the context
|
|
29
|
+
* @param value - The value to associate with the key
|
|
30
|
+
*/
|
|
31
|
+
declare function setContext<V, K extends string = string>(key: K, value: V): void;
|
|
32
|
+
/**
|
|
33
|
+
* Gets a value from the current context.
|
|
34
|
+
* @param key - The key to retrieve from the context
|
|
35
|
+
* @param fallback - Optional fallback value if the key is not found
|
|
36
|
+
* @returns The value associated with the key, or the fallback value if not found
|
|
37
|
+
*/
|
|
38
|
+
declare function getContext<V, K extends string = string>(key: K, fallback?: V): V | undefined;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { createContext, getContext, setContext, setContextProvider, withContext };
|
package/dist/context.js
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//#region src/context.ts
|
|
2
|
+
let currentStore;
|
|
3
|
+
/**
|
|
4
|
+
* Sets the global context store for the IRPC system.
|
|
5
|
+
* This store is used to manage context data across requests.
|
|
6
|
+
* @param store - The context store implementation to use
|
|
7
|
+
*/
|
|
8
|
+
function setContextProvider(store) {
|
|
9
|
+
currentStore = store;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Executes a function with the provided context.
|
|
13
|
+
* If a context store is available, it runs the function within that context.
|
|
14
|
+
* Otherwise, it executes the function directly.
|
|
15
|
+
* @param ctx - The context to run the function with
|
|
16
|
+
* @param fn - The function to execute
|
|
17
|
+
* @returns The result of the executed function
|
|
18
|
+
*/
|
|
19
|
+
function withContext(ctx, fn) {
|
|
20
|
+
return currentStore?.run(ctx, fn) ?? fn();
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Creates a new context map with optional initial values.
|
|
24
|
+
* @param init - Optional initial key-value pairs for the context
|
|
25
|
+
* @returns A new Map instance representing the context
|
|
26
|
+
*/
|
|
27
|
+
function createContext(init) {
|
|
28
|
+
return new Map(init);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Sets a value in the current context.
|
|
32
|
+
* @param key - The key to set in the context
|
|
33
|
+
* @param value - The value to associate with the key
|
|
34
|
+
*/
|
|
35
|
+
function setContext(key, value) {
|
|
36
|
+
(currentStore?.getStore())?.set(key, value);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Gets a value from the current context.
|
|
40
|
+
* @param key - The key to retrieve from the context
|
|
41
|
+
* @param fallback - Optional fallback value if the key is not found
|
|
42
|
+
* @returns The value associated with the key, or the fallback value if not found
|
|
43
|
+
*/
|
|
44
|
+
function getContext(key, fallback) {
|
|
45
|
+
const result = (currentStore?.getStore())?.get(key);
|
|
46
|
+
if (typeof result === "undefined" && typeof fallback !== "undefined") return fallback;
|
|
47
|
+
return result;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
//#endregion
|
|
51
|
+
export { createContext, getContext, setContext, setContextProvider, withContext };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { IRPCArraySchema, IRPCAuthorizer, IRPCContext, IRPCContextProvider, IRPCData, IRPCDataSchema, IRPCFactory, IRPCHandler, IRPCHost, IRPCInputs, IRPCModule, IRPCNamespace, IRPCObject, IRPCObjectSchema, IRPCOutput, IRPCParseResult, IRPCPayload, IRPCPrimitive, IRPCPrimitiveSchema, IRPCRegistry, IRPCRequest, IRPCResponse, IRPCSchema, IRPCSpec, IRPCStore, IRPCTransport } from "./types.js";
|
|
2
|
+
import { IRPCCall } from "./call.js";
|
|
3
|
+
import { batch } from "./batch.js";
|
|
4
|
+
import { createContext, getContext, setContext, setContextProvider, withContext } from "./context.js";
|
|
5
|
+
import { createModule } from "./module.js";
|
|
6
|
+
import { shortId } from "./utils.js";
|
|
7
|
+
export { IRPCArraySchema, IRPCAuthorizer, IRPCCall, IRPCContext, IRPCContextProvider, IRPCData, IRPCDataSchema, IRPCFactory, IRPCHandler, IRPCHost, IRPCInputs, IRPCModule, IRPCNamespace, IRPCObject, IRPCObjectSchema, IRPCOutput, IRPCParseResult, IRPCPayload, IRPCPrimitive, IRPCPrimitiveSchema, IRPCRegistry, IRPCRequest, IRPCResponse, IRPCSchema, IRPCSpec, IRPCStore, IRPCTransport, batch, createContext, createModule, getContext, setContext, setContextProvider, shortId, withContext };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { batch } from "./batch.js";
|
|
2
|
+
import { shortId } from "./utils.js";
|
|
3
|
+
import { IRPCCall } from "./call.js";
|
|
4
|
+
import { createContext, getContext, setContext, setContextProvider, withContext } from "./context.js";
|
|
5
|
+
import { IRPCTransport } from "./types.js";
|
|
6
|
+
import { createModule } from "./module.js";
|
|
7
|
+
|
|
8
|
+
export { IRPCCall, IRPCTransport, batch, createContext, createModule, getContext, setContext, setContextProvider, shortId, withContext };
|
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { IRPCFactory, IRPCModule } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/module.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates an IRPC module with the given configuration.
|
|
7
|
+
*
|
|
8
|
+
* This function initializes a new IRPC module with a store for tracking RPC calls,
|
|
9
|
+
* a registry for mapping functions to their specifications, and various methods
|
|
10
|
+
* for managing and executing remote procedure calls.
|
|
11
|
+
*
|
|
12
|
+
* @param config - Optional partial configuration for the IRPC module, excluding 'submit' and 'transport'
|
|
13
|
+
* @returns An IRPC factory function with attached utility methods
|
|
14
|
+
*/
|
|
15
|
+
declare function createModule(config?: Partial<Omit<IRPCModule, 'submit' | 'transport'>>): IRPCFactory;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { createModule };
|
package/dist/module.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { batch } from "./batch.js";
|
|
2
|
+
import { IRPCCall } from "./call.js";
|
|
3
|
+
|
|
4
|
+
//#region src/module.ts
|
|
5
|
+
const DEFAULT_TIMEOUT = 2e4;
|
|
6
|
+
/**
|
|
7
|
+
* Creates an IRPC module with the given configuration.
|
|
8
|
+
*
|
|
9
|
+
* This function initializes a new IRPC module with a store for tracking RPC calls,
|
|
10
|
+
* a registry for mapping functions to their specifications, and various methods
|
|
11
|
+
* for managing and executing remote procedure calls.
|
|
12
|
+
*
|
|
13
|
+
* @param config - Optional partial configuration for the IRPC module, excluding 'submit' and 'transport'
|
|
14
|
+
* @returns An IRPC factory function with attached utility methods
|
|
15
|
+
*/
|
|
16
|
+
function createModule(config) {
|
|
17
|
+
const store = /* @__PURE__ */ new Map();
|
|
18
|
+
const registry = /* @__PURE__ */ new WeakMap();
|
|
19
|
+
const module = {
|
|
20
|
+
name: "irpc",
|
|
21
|
+
version: "1.0.0",
|
|
22
|
+
timeout: DEFAULT_TIMEOUT,
|
|
23
|
+
...config
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Factory function that creates IRPC handlers based on specifications.
|
|
27
|
+
* Each handler can either execute a local function or make a remote call.
|
|
28
|
+
*/
|
|
29
|
+
const factory = ((spec) => {
|
|
30
|
+
const host = { ...spec };
|
|
31
|
+
store.set(host.name, host);
|
|
32
|
+
const fn = ((...args) => {
|
|
33
|
+
if (typeof host.handler === "function") return host.handler(...args);
|
|
34
|
+
else return remoteCall(module, host, ...args);
|
|
35
|
+
});
|
|
36
|
+
registry.set(fn, host);
|
|
37
|
+
return fn;
|
|
38
|
+
});
|
|
39
|
+
/**
|
|
40
|
+
* Returns the namespace information of the module (name and version).
|
|
41
|
+
*/
|
|
42
|
+
Object.defineProperty(factory, "namespace", { get: () => ({
|
|
43
|
+
name: module.name,
|
|
44
|
+
version: module.version
|
|
45
|
+
}) });
|
|
46
|
+
/**
|
|
47
|
+
* Associates a handler function with an IRPC specification.
|
|
48
|
+
* @param irpc - The IRPC function to construct
|
|
49
|
+
* @param handler - The actual implementation of the IRPC function
|
|
50
|
+
*/
|
|
51
|
+
factory.construct = ((irpc, handler) => {
|
|
52
|
+
if (typeof irpc !== "function") throw new Error("Invalid IRPC.");
|
|
53
|
+
const host = registry.get(irpc);
|
|
54
|
+
if (!host) throw new Error("IRPC can not be found.");
|
|
55
|
+
host.handler = handler;
|
|
56
|
+
});
|
|
57
|
+
/**
|
|
58
|
+
* Sets the transport mechanism for the module.
|
|
59
|
+
* @param transport - The transport layer to use for remote calls
|
|
60
|
+
*/
|
|
61
|
+
factory.use = ((transport) => {
|
|
62
|
+
if (typeof transport?.send !== "function") throw new Error("Invalid transport.");
|
|
63
|
+
module.transport = transport;
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* Retrieves an IRPC specification by name.
|
|
67
|
+
* @param name - The name of the IRPC to retrieve
|
|
68
|
+
* @returns The IRPC specification or undefined if not found
|
|
69
|
+
*/
|
|
70
|
+
factory.get = ((name) => {
|
|
71
|
+
return store.get(name);
|
|
72
|
+
});
|
|
73
|
+
/**
|
|
74
|
+
* Updates the module configuration.
|
|
75
|
+
* @param config - Configuration properties to update
|
|
76
|
+
*/
|
|
77
|
+
factory.configure = ((config$1) => {
|
|
78
|
+
Object.assign(module, { ...config$1 });
|
|
79
|
+
});
|
|
80
|
+
/**
|
|
81
|
+
* Retrieves information about an IRPC by its request details.
|
|
82
|
+
* @param req - Request containing the name of the IRPC to look up
|
|
83
|
+
* @returns The IRPC specification or undefined if not found
|
|
84
|
+
*/
|
|
85
|
+
factory.info = ((req) => {
|
|
86
|
+
return store.get(req.name);
|
|
87
|
+
});
|
|
88
|
+
/**
|
|
89
|
+
* Resolves and executes an IRPC call with the provided arguments.
|
|
90
|
+
* @param req - Request containing the name and arguments for the IRPC call
|
|
91
|
+
* @returns The result of executing the IRPC handler
|
|
92
|
+
*/
|
|
93
|
+
factory.resolve = ((req) => {
|
|
94
|
+
const host = store.get(req.name);
|
|
95
|
+
if (!host) throw new Error("IRPC can not be found.");
|
|
96
|
+
if (!host.handler) throw new Error("IRPC handler can not be found.");
|
|
97
|
+
return host.handler(...req.args);
|
|
98
|
+
});
|
|
99
|
+
/**
|
|
100
|
+
* Submits a batch of IRPC calls for execution via the transport layer.
|
|
101
|
+
* @param calls - Array of IRPC calls to submit
|
|
102
|
+
*/
|
|
103
|
+
module.submit = ((calls) => {
|
|
104
|
+
try {
|
|
105
|
+
const promise = module.transport.send(calls);
|
|
106
|
+
if (promise instanceof Promise) promise.catch((reason) => {
|
|
107
|
+
calls.forEach((call) => {
|
|
108
|
+
call.reject(reason);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
} catch (error) {
|
|
112
|
+
calls.forEach((call) => {
|
|
113
|
+
call.reject(error);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
return factory;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Executes a remote procedure call through the configured transport layer.
|
|
121
|
+
*
|
|
122
|
+
* This function creates an IRPC call payload and sends it through the module's transport mechanism.
|
|
123
|
+
* It handles timeouts and promise resolution/rejection based on the response.
|
|
124
|
+
*
|
|
125
|
+
* @param module - The IRPC module containing transport and configuration
|
|
126
|
+
* @param spec - The IRPC specification defining the remote procedure
|
|
127
|
+
* @param args - Arguments to pass to the remote procedure
|
|
128
|
+
* @returns A promise that resolves with the remote call result or rejects with an error
|
|
129
|
+
* @throws Error if no transport is configured or if the call times out
|
|
130
|
+
*/
|
|
131
|
+
function remoteCall(module, spec, ...args) {
|
|
132
|
+
const payload = {
|
|
133
|
+
name: spec.name,
|
|
134
|
+
args
|
|
135
|
+
};
|
|
136
|
+
return new Promise((resolve, reject) => {
|
|
137
|
+
if (!module.transport) {
|
|
138
|
+
reject(/* @__PURE__ */ new Error("IRPC transport can not be found."));
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
const timeout = module.timeout ? setTimeout(() => {
|
|
142
|
+
call.reject(/* @__PURE__ */ new Error("IRPC timeout."));
|
|
143
|
+
}, module.timeout) : void 0;
|
|
144
|
+
const call = new IRPCCall(payload, (value) => {
|
|
145
|
+
resolve(value);
|
|
146
|
+
clearTimeout(timeout);
|
|
147
|
+
}, (reason) => {
|
|
148
|
+
reject(reason);
|
|
149
|
+
clearTimeout(timeout);
|
|
150
|
+
});
|
|
151
|
+
batch(call, module.submit);
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
//#endregion
|
|
156
|
+
export { createModule };
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import { IRPCCall } from "./call.js";
|
|
2
|
+
import { ZodArray, ZodBoolean, ZodNull, ZodNumber, ZodObject, ZodSafeParseResult, ZodString, ZodUndefined } from "zod/v4";
|
|
3
|
+
|
|
4
|
+
//#region src/types.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A registry that maps IRPCHandlers to their corresponding IRPCHosts.
|
|
8
|
+
* Uses WeakMap to avoid memory leaks by not preventing garbage collection of handlers.
|
|
9
|
+
*/
|
|
10
|
+
type IRPCRegistry = WeakMap<IRPCHandler, IRPCHost<IRPCInputs, IRPCOutput>>;
|
|
11
|
+
/**
|
|
12
|
+
* A store that maps string identifiers to IRPCHosts.
|
|
13
|
+
* Used to keep track of available RPC hosts by their names.
|
|
14
|
+
*/
|
|
15
|
+
type IRPCStore = Map<string, IRPCHost<IRPCInputs, IRPCOutput>>;
|
|
16
|
+
/**
|
|
17
|
+
* A function that authorizes RPC requests.
|
|
18
|
+
* Takes a Request object and returns a boolean (sync or async) indicating authorization status.
|
|
19
|
+
*/
|
|
20
|
+
type IRPCAuthorizer = (req: Request) => Promise<boolean> | boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Represents primitive data types that can be used in IRPC communications.
|
|
23
|
+
* Includes string, number, boolean, null, and undefined.
|
|
24
|
+
*/
|
|
25
|
+
type IRPCPrimitive = string | number | boolean | null | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Represents an object structure where keys are strings and values are IRPCData.
|
|
28
|
+
* Used for structured data in RPC communications.
|
|
29
|
+
*/
|
|
30
|
+
type IRPCObject = {
|
|
31
|
+
[key: string]: IRPCData;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Represents all possible data types in IRPC, including primitives, objects, and arrays.
|
|
35
|
+
* This is a recursive type that allows nested structures.
|
|
36
|
+
*/
|
|
37
|
+
type IRPCData = IRPCPrimitive | IRPCObject | IRPCData[];
|
|
38
|
+
/**
|
|
39
|
+
* Union type of all primitive Zod schema types used for validation.
|
|
40
|
+
*/
|
|
41
|
+
type IRPCPrimitiveSchema = ZodString | ZodNumber | ZodBoolean | ZodNull | ZodUndefined;
|
|
42
|
+
/**
|
|
43
|
+
* Zod object schema type used for validating structured data.
|
|
44
|
+
*/
|
|
45
|
+
type IRPCObjectSchema = ZodObject;
|
|
46
|
+
/**
|
|
47
|
+
* Zod array schema that can contain primitive schemas or object schemas.
|
|
48
|
+
*/
|
|
49
|
+
type IRPCArraySchema = ZodArray<IRPCPrimitiveSchema | IRPCObjectSchema>;
|
|
50
|
+
/**
|
|
51
|
+
* Union type of all possible Zod schema types used in IRPC for input/output validation.
|
|
52
|
+
*/
|
|
53
|
+
type IRPCDataSchema = IRPCPrimitiveSchema | IRPCObjectSchema | IRPCArraySchema;
|
|
54
|
+
/**
|
|
55
|
+
* Type representing the result of a Zod schema validation operation.
|
|
56
|
+
*/
|
|
57
|
+
type IRPCParseResult = ZodSafeParseResult<IRPCDataSchema>;
|
|
58
|
+
/**
|
|
59
|
+
* Represents an array of input schemas for an RPC function.
|
|
60
|
+
*/
|
|
61
|
+
type IRPCInputs = IRPCDataSchema[];
|
|
62
|
+
/**
|
|
63
|
+
* Represents the output schema for an RPC function.
|
|
64
|
+
*/
|
|
65
|
+
type IRPCOutput = IRPCDataSchema;
|
|
66
|
+
/**
|
|
67
|
+
* Defines the basic information about an RPC namespace.
|
|
68
|
+
*/
|
|
69
|
+
type IRPCNamespace = {
|
|
70
|
+
/** The name of the namespace */
|
|
71
|
+
name: string;
|
|
72
|
+
/** The version of the namespace */
|
|
73
|
+
version: string;
|
|
74
|
+
/** Optional description of the namespace */
|
|
75
|
+
description?: string;
|
|
76
|
+
};
|
|
77
|
+
/**
|
|
78
|
+
* Defines an RPC module which extends a namespace with execution capabilities.
|
|
79
|
+
*/
|
|
80
|
+
type IRPCModule = IRPCNamespace & {
|
|
81
|
+
/** Optional function to submit RPC calls */
|
|
82
|
+
submit?: (calls: IRPCCall[]) => Promise<IRPCResponse[]>;
|
|
83
|
+
/** Optional timeout for RPC calls */
|
|
84
|
+
timeout?: number;
|
|
85
|
+
/** Optional transport mechanism for RPC communications */
|
|
86
|
+
transport?: IRPCTransport;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* Represents the payload of an RPC call with its name and arguments.
|
|
90
|
+
*/
|
|
91
|
+
type IRPCPayload = {
|
|
92
|
+
/** The name of the RPC function to call */
|
|
93
|
+
name: string;
|
|
94
|
+
/** The arguments to pass to the RPC function */
|
|
95
|
+
args: IRPCData[];
|
|
96
|
+
};
|
|
97
|
+
/**
|
|
98
|
+
* Defines the schema for input and output validation of an RPC function.
|
|
99
|
+
*/
|
|
100
|
+
type IRPCSchema<I extends IRPCInputs, O extends IRPCOutput> = {
|
|
101
|
+
/** Optional input validation schemas */
|
|
102
|
+
input?: I;
|
|
103
|
+
/** Optional output validation schema */
|
|
104
|
+
output?: O;
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Type definition for an RPC handler function.
|
|
108
|
+
* Takes IRPCData arguments and returns a Promise resolving to IRPCData.
|
|
109
|
+
*/
|
|
110
|
+
type IRPCHandler = (...args: IRPCData[]) => Promise<IRPCData>;
|
|
111
|
+
/**
|
|
112
|
+
* Specification for an RPC function including its name, schema, and description.
|
|
113
|
+
*/
|
|
114
|
+
type IRPCSpec<I extends IRPCInputs, O extends IRPCOutput> = {
|
|
115
|
+
/** The name of the RPC function */
|
|
116
|
+
name: string;
|
|
117
|
+
/** Optional schema for input/output validation */
|
|
118
|
+
schema?: IRPCSchema<I, O>;
|
|
119
|
+
/** Optional description of the RPC function */
|
|
120
|
+
description?: string;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Host definition for an RPC function that combines the specification with execution details.
|
|
124
|
+
*/
|
|
125
|
+
type IRPCHost<I extends IRPCInputs, O extends IRPCOutput> = IRPCSpec<I, O> & {
|
|
126
|
+
/** The actual handler function that implements the RPC */
|
|
127
|
+
handler: IRPCHandler;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Factory interface for creating and managing RPC functions.
|
|
131
|
+
*/
|
|
132
|
+
interface IRPCFactory {
|
|
133
|
+
/**
|
|
134
|
+
* Creates a new RPC function with the given specification.
|
|
135
|
+
* @param spec The specification for the RPC function
|
|
136
|
+
*/
|
|
137
|
+
<F, I extends IRPCInputs = IRPCInputs, O extends IRPCOutput = IRPCOutput>(spec: IRPCSpec<I, O>): F;
|
|
138
|
+
/** The namespace associated with this factory */
|
|
139
|
+
get namespace(): IRPCNamespace;
|
|
140
|
+
/**
|
|
141
|
+
* Sets the transport mechanism for this factory.
|
|
142
|
+
* @param transport The transport to use
|
|
143
|
+
*/
|
|
144
|
+
use(transport: IRPCTransport): IRPCFactory;
|
|
145
|
+
/**
|
|
146
|
+
* Gets the specification for an RPC function by name.
|
|
147
|
+
* @param name The name of the RPC function
|
|
148
|
+
*/
|
|
149
|
+
get<I extends IRPCInputs, O extends IRPCOutput>(name: string): IRPCSpec<I, O>;
|
|
150
|
+
/**
|
|
151
|
+
* Configures the module settings for this factory.
|
|
152
|
+
* @param config Partial configuration for the module
|
|
153
|
+
*/
|
|
154
|
+
configure(config: Partial<IRPCModule>): IRPCFactory;
|
|
155
|
+
/**
|
|
156
|
+
* Constructs an RPC function with its handler.
|
|
157
|
+
* @param irpc The RPC function
|
|
158
|
+
* @param handler The handler that implements the RPC function
|
|
159
|
+
*/
|
|
160
|
+
construct<F>(irpc: F, handler: F): IRPCFactory;
|
|
161
|
+
/**
|
|
162
|
+
* Gets information about an RPC request.
|
|
163
|
+
* @param req The RPC request
|
|
164
|
+
*/
|
|
165
|
+
info<I extends IRPCInputs, O extends IRPCOutput>(req: IRPCRequest): IRPCSpec<I, O>;
|
|
166
|
+
/**
|
|
167
|
+
* Resolves an RPC request.
|
|
168
|
+
* @param req The RPC request to resolve
|
|
169
|
+
*/
|
|
170
|
+
resolve<R>(req: IRPCRequest): Promise<R>;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Represents an incoming RPC request.
|
|
174
|
+
*/
|
|
175
|
+
type IRPCRequest = {
|
|
176
|
+
/** Unique identifier for the request */
|
|
177
|
+
id: string;
|
|
178
|
+
/** Name of the RPC function being called */
|
|
179
|
+
name: string;
|
|
180
|
+
/** Arguments for the RPC function */
|
|
181
|
+
args: unknown[];
|
|
182
|
+
};
|
|
183
|
+
/**
|
|
184
|
+
* Represents an RPC response.
|
|
185
|
+
*/
|
|
186
|
+
type IRPCResponse = {
|
|
187
|
+
/** Unique identifier matching the request */
|
|
188
|
+
id: string;
|
|
189
|
+
/** Name of the RPC function that was called */
|
|
190
|
+
name: string;
|
|
191
|
+
/** Error message if the call failed */
|
|
192
|
+
error?: string;
|
|
193
|
+
/** Result of the RPC call if successful */
|
|
194
|
+
result?: unknown;
|
|
195
|
+
};
|
|
196
|
+
/**
|
|
197
|
+
* Abstract base class for RPC transport mechanisms.
|
|
198
|
+
*/
|
|
199
|
+
declare abstract class IRPCTransport {
|
|
200
|
+
/**
|
|
201
|
+
* Sends RPC calls and returns the responses.
|
|
202
|
+
* @param calls Array of RPC calls to send
|
|
203
|
+
*/
|
|
204
|
+
abstract send(calls: IRPCCall[]): Promise<IRPCResponse[]>;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Context storage mechanism for RPC operations.
|
|
208
|
+
*/
|
|
209
|
+
type IRPCContext<K, V> = Map<K, V>;
|
|
210
|
+
/**
|
|
211
|
+
* Interface for managing RPC context stores.
|
|
212
|
+
*/
|
|
213
|
+
type IRPCContextProvider = {
|
|
214
|
+
/**
|
|
215
|
+
* Runs a function within a specific context.
|
|
216
|
+
* @param ctx The context to run within
|
|
217
|
+
* @param fn The function to execute
|
|
218
|
+
*/
|
|
219
|
+
run<R, K, V>(ctx: IRPCContext<K, V>, fn: () => R): R;
|
|
220
|
+
/** Gets the current context store */
|
|
221
|
+
getStore<K, V>(): IRPCContext<K, V>;
|
|
222
|
+
};
|
|
223
|
+
//#endregion
|
|
224
|
+
export { IRPCArraySchema, IRPCAuthorizer, IRPCContext, IRPCContextProvider, IRPCData, IRPCDataSchema, IRPCFactory, IRPCHandler, IRPCHost, IRPCInputs, IRPCModule, IRPCNamespace, IRPCObject, IRPCObjectSchema, IRPCOutput, IRPCParseResult, IRPCPayload, IRPCPrimitive, IRPCPrimitiveSchema, IRPCRegistry, IRPCRequest, IRPCResponse, IRPCSchema, IRPCSpec, IRPCStore, IRPCTransport };
|
package/dist/types.js
ADDED
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/utils.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Generates a short unique identifier string.
|
|
4
|
+
*
|
|
5
|
+
* This function creates a unique ID by combining:
|
|
6
|
+
* - A timestamp in base-36 format
|
|
7
|
+
* - A sequence number in base-36 format (padded to 3 characters)
|
|
8
|
+
* - A random string in base-36 format (4 characters)
|
|
9
|
+
*
|
|
10
|
+
* The sequence number ensures uniqueness when multiple IDs are generated within the same millisecond.
|
|
11
|
+
* The random part adds additional entropy to reduce predictability.
|
|
12
|
+
*
|
|
13
|
+
* @returns A unique string identifier
|
|
14
|
+
*/
|
|
15
|
+
declare function shortId(): string;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { shortId };
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/utils.ts
|
|
2
|
+
let lastTimestamp = 0;
|
|
3
|
+
let sequence = 0;
|
|
4
|
+
/**
|
|
5
|
+
* Generates a short unique identifier string.
|
|
6
|
+
*
|
|
7
|
+
* This function creates a unique ID by combining:
|
|
8
|
+
* - A timestamp in base-36 format
|
|
9
|
+
* - A sequence number in base-36 format (padded to 3 characters)
|
|
10
|
+
* - A random string in base-36 format (4 characters)
|
|
11
|
+
*
|
|
12
|
+
* The sequence number ensures uniqueness when multiple IDs are generated within the same millisecond.
|
|
13
|
+
* The random part adds additional entropy to reduce predictability.
|
|
14
|
+
*
|
|
15
|
+
* @returns A unique string identifier
|
|
16
|
+
*/
|
|
17
|
+
function shortId() {
|
|
18
|
+
const timestamp = Date.now();
|
|
19
|
+
if (timestamp === lastTimestamp) sequence++;
|
|
20
|
+
else sequence = 0;
|
|
21
|
+
lastTimestamp = timestamp;
|
|
22
|
+
return `${timestamp.toString(36)}${sequence.toString(36).padStart(3, "0")}${Math.random().toString(36).substring(2, 6)}`;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
//#endregion
|
|
26
|
+
export { shortId };
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"name": "@irpclib/irpc",
|
|
4
|
+
"version": "0.0.1",
|
|
5
|
+
"types": "./dist/index.d.ts",
|
|
6
|
+
"module": "./dist/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"directories": {
|
|
17
|
+
"dist": "./dist"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@biomejs/biome": "2.3.3",
|
|
24
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
25
|
+
"@vitest/ui": "^3.2.4",
|
|
26
|
+
"esbuild-raw-plugin": "^0.3.1",
|
|
27
|
+
"prettier": "^3.6.2",
|
|
28
|
+
"publint": "^0.3.15",
|
|
29
|
+
"rimraf": "^6.0.1",
|
|
30
|
+
"tsdown": "^0.15.9",
|
|
31
|
+
"vite": "^7.1.12",
|
|
32
|
+
"vitest": "^3.2.4",
|
|
33
|
+
"zod": "^4.1.5",
|
|
34
|
+
"@types/bun": "1.3.1"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"typescript": "^5.9.0"
|
|
38
|
+
},
|
|
39
|
+
"optionalDependencies": {
|
|
40
|
+
"zod": "^4.1.5"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"dev": "tsdown --watch",
|
|
44
|
+
"clean": "rimraf dist",
|
|
45
|
+
"build": "tsdown && publint",
|
|
46
|
+
"format": "prettier --write .",
|
|
47
|
+
"test": "rimraf coverage && vitest --run",
|
|
48
|
+
"test:preview": "rimraf coverage && vitest --run && vite preview --outDir coverage",
|
|
49
|
+
"prepublish": "bun run format && bun run clean && tsdown && publint"
|
|
50
|
+
},
|
|
51
|
+
"license": "MIT"
|
|
52
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# IRPC - Isomorphic Remote Procedure Call
|
|
2
|
+
|
|
3
|
+
IRPC (Isomorphic Remote Procedure Call) is a revolutionary approach to distributed computing that eliminates the cognitive overhead of network communication. It enables developers to invoke remote functions with the same ergonomics as local function calls, abstracting away the transport layer entirely.
|
|
4
|
+
|
|
5
|
+
Unlike traditional approaches like REST APIs, GraphQL, or gRPC, IRPC removes the need to think about endpoints, serialization, or transport protocols. You focus on business logic while IRPC handles the communication complexity transparently.
|
|
6
|
+
|
|
7
|
+
## Learn More
|
|
8
|
+
|
|
9
|
+
For detailed documentation, visit [https://irpc.anchorlib.dev](https://irpc.anchorlib.dev)
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
### Create a Module
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { createModule } from '@irpclib/irpc';
|
|
17
|
+
|
|
18
|
+
const irpc = createModule({ name: 'my-module', version: '1.0.0' });
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Define Functions
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
export const greet = irpc<(name: string) => Promise<string>>({
|
|
25
|
+
name: 'greet'
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### Set up Transport (Client-side)
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { HTTPTransport } from '@irpclib/http';
|
|
33
|
+
|
|
34
|
+
export const transport = new HTTPTransport(
|
|
35
|
+
{
|
|
36
|
+
baseURL: 'http://localhost:3000',
|
|
37
|
+
endpoint: '/rpc',
|
|
38
|
+
},
|
|
39
|
+
irpc
|
|
40
|
+
);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Implement Handlers (Server-side)
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
irpc.construct(greet, async (name) => {
|
|
47
|
+
return `Hello, ${name}!`;
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Server Setup
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
import { setContextStore } from '@irpclib/irpc';
|
|
55
|
+
import { AsyncLocalStorage } from 'async_hooks';
|
|
56
|
+
|
|
57
|
+
setContextStore(new AsyncLocalStorage());
|
|
58
|
+
|
|
59
|
+
Bun.serve({
|
|
60
|
+
routes: {
|
|
61
|
+
[transport.endpoint]: {
|
|
62
|
+
GET: () => new Response('OK'),
|
|
63
|
+
POST: (req) => transport.respond(req),
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Client Usage
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
import { greet } from './my-module';
|
|
73
|
+
|
|
74
|
+
const message = await greet('World');
|
|
75
|
+
console.log(message); // "Hello, World!"
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Key Features
|
|
79
|
+
|
|
80
|
+
- **Isomorphic Design**: Call functions identically on client and server
|
|
81
|
+
- **Zero Boilerplate**: No REST endpoints, no GraphQL schemas, no complex serialization
|
|
82
|
+
- **Transport Agnostic**: Switch between HTTP, WebSockets, and other transports without changing your business logic
|
|
83
|
+
- **End-to-End Type Safety**: Compile-time validation from client to server
|
|
84
|
+
- **Performance Optimized**: Intelligent batching and connection reuse
|
|
85
|
+
|
|
86
|
+
## Core Components
|
|
87
|
+
|
|
88
|
+
### Module
|
|
89
|
+
|
|
90
|
+
A module is a container for your IRPC functions. It manages the registry of functions and their implementations.
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
const irpc = createModule({ name: 'fs', version: '1.0.0' });
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Function
|
|
97
|
+
|
|
98
|
+
Functions are the core building blocks of IRPC. They define the interface for remote calls and can be implemented on the server side.
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
export const readFile = irpc<(path: string) => Promise<string>>('readFile');
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### Transport
|
|
105
|
+
|
|
106
|
+
Transports handle the actual communication between client and server. IRPC is transport-agnostic, allowing you to switch between different communication protocols.
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
export const transport = new IRPCHttpTransport(
|
|
110
|
+
{
|
|
111
|
+
baseURL: 'http://localhost:3000',
|
|
112
|
+
endpoint: '/rpc',
|
|
113
|
+
timeout: 1000,
|
|
114
|
+
headers: {
|
|
115
|
+
'Content-Type': 'application/json',
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
irpc
|
|
119
|
+
);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
The transport automatically registers itself with the IRPC module during construction, so there's no need to manually register it.
|
|
123
|
+
|
|
124
|
+
## Usage
|
|
125
|
+
|
|
126
|
+
### Client
|
|
127
|
+
|
|
128
|
+
On the client side, you simply import and call your functions as if they were local:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { readFile } from './fs';
|
|
132
|
+
|
|
133
|
+
console.log(await readFile('/path/to/file'));
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Server
|
|
137
|
+
|
|
138
|
+
On the server side, you implement the actual functionality for your functions:
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
import { transport } from './fs';
|
|
142
|
+
import { setContextStore } from '@irpclib/irpc';
|
|
143
|
+
|
|
144
|
+
setContextStore(new AsyncLocalStorage());
|
|
145
|
+
|
|
146
|
+
Bun.serve({
|
|
147
|
+
routes: {
|
|
148
|
+
[transport.endpoint]: {
|
|
149
|
+
GET: () => {
|
|
150
|
+
return new Response('Ok!');
|
|
151
|
+
},
|
|
152
|
+
POST: (req) => transport.respond(req),
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### Handler
|
|
159
|
+
|
|
160
|
+
Handlers are the actual implementations of your remote functions:
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
irpc.construct(readFile, async (path) => {
|
|
164
|
+
// Implementation goes here
|
|
165
|
+
});
|
|
166
|
+
```
|