swarpc 0.7.1 → 0.8.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/dist/client.d.ts +21 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +11 -3
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/log.d.ts +21 -13
- package/dist/log.d.ts.map +1 -1
- package/dist/log.js +26 -16
- package/dist/server.d.ts +21 -4
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +18 -10
- package/dist/types.d.ts +44 -23
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +17 -0
- package/package.json +16 -3
- package/src/client.ts +22 -4
- package/src/index.ts +5 -0
- package/src/log.ts +68 -12
- package/src/server.ts +37 -16
- package/src/types.ts +43 -31
package/dist/client.d.ts
CHANGED
|
@@ -1,13 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
1
5
|
import { type LogLevel } from "./log.js";
|
|
2
|
-
import { Hooks,
|
|
3
|
-
|
|
6
|
+
import { ClientMethod, Hooks, zProcedures, type ProceduresMap } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* The sw&rpc client instance, which provides {@link ClientMethod | methods to call procedures}.
|
|
9
|
+
* Each property of the procedures map will be a method, that accepts an input, an optional onProgress callback and an optional request ID.
|
|
10
|
+
* If you want to be able to cancel the request, you can set the request's ID yourself, and call `.abort(requestId, reason)` on the client instance to cancel it.
|
|
11
|
+
*/
|
|
12
|
+
export type SwarpcClient<Procedures extends ProceduresMap> = {
|
|
13
|
+
[zProcedures]: Procedures;
|
|
14
|
+
} & {
|
|
15
|
+
[F in keyof Procedures]: ClientMethod<Procedures[F]>;
|
|
16
|
+
};
|
|
4
17
|
/**
|
|
5
18
|
*
|
|
6
|
-
* @param procedures procedures the client will be able to call
|
|
19
|
+
* @param procedures procedures the client will be able to call, see {@link ProceduresMap}
|
|
7
20
|
* @param options various options
|
|
8
21
|
* @param options.worker if provided, the client will use this worker to post messages.
|
|
9
22
|
* @param options.hooks hooks to run on messages received from the server
|
|
10
|
-
* @returns a sw&rpc client instance. Each property of the procedures map will be a method, that accepts an input and an optional onProgress callback
|
|
23
|
+
* @returns a sw&rpc client instance. Each property of the procedures map will be a method, that accepts an input and an optional onProgress callback, see {@link ClientMethod}
|
|
24
|
+
*
|
|
25
|
+
* An example of defining and using a client:
|
|
26
|
+
* {@includeCode ../example/src/routes/+page.svelte}
|
|
11
27
|
*/
|
|
12
28
|
export declare function Client<Procedures extends ProceduresMap>(procedures: Procedures, { worker, loglevel, hooks, }?: {
|
|
13
29
|
worker?: Worker;
|
|
@@ -16,6 +32,7 @@ export declare function Client<Procedures extends ProceduresMap>(procedures: Pro
|
|
|
16
32
|
}): SwarpcClient<Procedures>;
|
|
17
33
|
/**
|
|
18
34
|
* Generate a random request ID, used to identify requests between client and server.
|
|
35
|
+
* @source
|
|
19
36
|
* @returns a 6-character hexadecimal string
|
|
20
37
|
*/
|
|
21
38
|
export declare function makeRequestId(): string;
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6B,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AACnE,OAAO,EACL,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAA6B,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AACnE,OAAO,EACL,YAAY,EACZ,KAAK,EAGL,WAAW,EACX,KAAK,aAAa,EACnB,MAAM,YAAY,CAAA;AAGnB;;;;GAIG;AACH,MAAM,MAAM,YAAY,CAAC,UAAU,SAAS,aAAa,IAAI;IAC3D,CAAC,WAAW,CAAC,EAAE,UAAU,CAAA;CAC1B,GAAG;KACD,CAAC,IAAI,MAAM,UAAU,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;CACrD,CAAA;AAkBD;;;;;;;;;;GAUG;AACH,wBAAgB,MAAM,CAAC,UAAU,SAAS,aAAa,EACrD,UAAU,EAAE,UAAU,EACtB,EACE,MAAM,EACN,QAAkB,EAClB,KAAU,GACX,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAAO,GAC1E,YAAY,CAAC,UAAU,CAAC,CA+F1B;AAmGD;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
|
package/dist/client.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
1
5
|
import { createLogger } from "./log.js";
|
|
2
|
-
import { zProcedures } from "./types.js";
|
|
6
|
+
import { zProcedures, } from "./types.js";
|
|
3
7
|
import { findTransferables } from "./utils.js";
|
|
4
8
|
/**
|
|
5
9
|
* Pending requests are stored in a map, where the key is the request ID.
|
|
@@ -11,11 +15,14 @@ const pendingRequests = new Map();
|
|
|
11
15
|
let _clientListenerStarted = false;
|
|
12
16
|
/**
|
|
13
17
|
*
|
|
14
|
-
* @param procedures procedures the client will be able to call
|
|
18
|
+
* @param procedures procedures the client will be able to call, see {@link ProceduresMap}
|
|
15
19
|
* @param options various options
|
|
16
20
|
* @param options.worker if provided, the client will use this worker to post messages.
|
|
17
21
|
* @param options.hooks hooks to run on messages received from the server
|
|
18
|
-
* @returns a sw&rpc client instance. Each property of the procedures map will be a method, that accepts an input and an optional onProgress callback
|
|
22
|
+
* @returns a sw&rpc client instance. Each property of the procedures map will be a method, that accepts an input and an optional onProgress callback, see {@link ClientMethod}
|
|
23
|
+
*
|
|
24
|
+
* An example of defining and using a client:
|
|
25
|
+
* {@includeCode ../example/src/routes/+page.svelte}
|
|
19
26
|
*/
|
|
20
27
|
export function Client(procedures, { worker, loglevel = "debug", hooks = {}, } = {}) {
|
|
21
28
|
const l = createLogger("client", loglevel);
|
|
@@ -152,6 +159,7 @@ async function startClientListener(l, worker, hooks = {}) {
|
|
|
152
159
|
}
|
|
153
160
|
/**
|
|
154
161
|
* Generate a random request ID, used to identify requests between client and server.
|
|
162
|
+
* @source
|
|
155
163
|
* @returns a 6-character hexadecimal string
|
|
156
164
|
*/
|
|
157
165
|
export function makeRequestId() {
|
package/dist/index.d.ts
CHANGED
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,cAAc,aAAa,CAAA;AAC3B,cAAc,aAAa,CAAA;AAC3B,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
package/dist/log.d.ts
CHANGED
|
@@ -1,20 +1,28 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* @ignore
|
|
7
|
+
*/
|
|
8
|
+
export declare function createLogger(side: "server" | "client", level: LogLevel): Logger;
|
|
9
|
+
export declare function createLogger(side: "server" | "client", level: LogLevel, rqid: string): RequestBoundLogger;
|
|
10
|
+
/**
|
|
11
|
+
* @ignore
|
|
12
|
+
*/
|
|
13
|
+
export type Logger = {
|
|
2
14
|
debug: (rqid: string | null, message: string, ...args: any[]) => void;
|
|
3
15
|
info: (rqid: string | null, message: string, ...args: any[]) => void;
|
|
4
16
|
warn: (rqid: string | null, message: string, ...args: any[]) => void;
|
|
5
17
|
error: (rqid: string | null, message: string, ...args: any[]) => void;
|
|
6
18
|
};
|
|
7
|
-
export type
|
|
8
|
-
|
|
19
|
+
export type RequestBoundLogger = {
|
|
20
|
+
debug: (message: string, ...args: any[]) => void;
|
|
21
|
+
info: (message: string, ...args: any[]) => void;
|
|
22
|
+
warn: (message: string, ...args: any[]) => void;
|
|
23
|
+
error: (message: string, ...args: any[]) => void;
|
|
24
|
+
};
|
|
25
|
+
/** @source */
|
|
26
|
+
export declare const LOG_LEVELS: readonly ["debug", "info", "warn", "error"];
|
|
9
27
|
export type LogLevel = (typeof LOG_LEVELS)[number];
|
|
10
|
-
/**
|
|
11
|
-
* Send log messages to the console, with a helpful prefix.
|
|
12
|
-
* @param severity
|
|
13
|
-
* @param side
|
|
14
|
-
* @param rqid request ID
|
|
15
|
-
* @param message
|
|
16
|
-
* @param args passed to console methods directly
|
|
17
|
-
*/
|
|
18
|
-
export declare function log(severity: "debug" | "info" | "warn" | "error", side: "server" | "client", rqid: string | null, message: string, ...args: any[]): void;
|
|
19
|
-
export {};
|
|
20
28
|
//# sourceMappingURL=log.d.ts.map
|
package/dist/log.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA,wBAAgB,YAAY,
|
|
1
|
+
{"version":3,"file":"log.d.ts","sourceRoot":"","sources":["../src/log.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,QAAQ,EAAE,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAA;AAChF,wBAAgB,YAAY,CAC1B,IAAI,EAAE,QAAQ,GAAG,QAAQ,EACzB,KAAK,EAAE,QAAQ,EACf,IAAI,EAAE,MAAM,GACX,kBAAkB,CAAA;AAyBrB;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG;IACnB,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IACrE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IACpE,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IACpE,KAAK,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;CACtE,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC/B,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAChD,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC/C,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC/C,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;CACjD,CAAA;AAED,cAAc;AACd,eAAO,MAAM,UAAU,6CAA8C,CAAA;AAErE,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,MAAM,CAAC,CAAA"}
|
package/dist/log.js
CHANGED
|
@@ -1,21 +1,31 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
5
|
+
export function createLogger(side, level = "debug", rqid) {
|
|
6
|
+
const lvls = LOG_LEVELS.slice(LOG_LEVELS.indexOf(level));
|
|
7
|
+
if (rqid) {
|
|
8
|
+
return {
|
|
9
|
+
debug: lvls.includes("debug") ? logger("debug", side, rqid) : () => { },
|
|
10
|
+
info: lvls.includes("info") ? logger("info", side, rqid) : () => { },
|
|
11
|
+
warn: lvls.includes("warn") ? logger("warn", side, rqid) : () => { },
|
|
12
|
+
error: lvls.includes("error") ? logger("error", side, rqid) : () => { },
|
|
13
|
+
};
|
|
14
|
+
}
|
|
3
15
|
return {
|
|
4
|
-
debug:
|
|
5
|
-
info:
|
|
6
|
-
warn:
|
|
7
|
-
error:
|
|
16
|
+
debug: lvls.includes("debug") ? logger("debug", side) : () => { },
|
|
17
|
+
info: lvls.includes("info") ? logger("info", side) : () => { },
|
|
18
|
+
warn: lvls.includes("warn") ? logger("warn", side) : () => { },
|
|
19
|
+
error: lvls.includes("error") ? logger("error", side) : () => { },
|
|
8
20
|
};
|
|
9
21
|
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
function logger(severity, side) {
|
|
18
|
-
return (rqid, message, ...args) => log(severity, side, rqid, message, ...args);
|
|
22
|
+
/** @source */
|
|
23
|
+
export const LOG_LEVELS = ["debug", "info", "warn", "error"];
|
|
24
|
+
function logger(severity, side, rqid) {
|
|
25
|
+
if (rqid === undefined) {
|
|
26
|
+
return (rqid, message, ...args) => log(severity, side, rqid, message, ...args);
|
|
27
|
+
}
|
|
28
|
+
return (message, ...args) => log(severity, side, rqid, message, ...args);
|
|
19
29
|
}
|
|
20
30
|
/**
|
|
21
31
|
* Send log messages to the console, with a helpful prefix.
|
|
@@ -25,7 +35,7 @@ function logger(severity, side) {
|
|
|
25
35
|
* @param message
|
|
26
36
|
* @param args passed to console methods directly
|
|
27
37
|
*/
|
|
28
|
-
|
|
38
|
+
function log(severity, side, rqid, message, ...args) {
|
|
29
39
|
const prefix = "[" +
|
|
30
40
|
["SWARPC", side, rqid ? `%c${rqid}%c` : ""].filter(Boolean).join(" ") +
|
|
31
41
|
"]";
|
package/dist/server.d.ts
CHANGED
|
@@ -1,12 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
1
5
|
import { type LogLevel } from "./log.js";
|
|
2
|
-
import {
|
|
3
|
-
|
|
6
|
+
import { ImplementationsMap, ProcedureImplementation, zImplementations, zProcedures, type ProceduresMap } from "./types.js";
|
|
7
|
+
/**
|
|
8
|
+
* The sw&rpc server instance, which provides methods to register {@link ProcedureImplementation | procedure implementations},
|
|
9
|
+
* and listens for incoming messages that call those procedures
|
|
10
|
+
*/
|
|
11
|
+
export type SwarpcServer<Procedures extends ProceduresMap> = {
|
|
12
|
+
[zProcedures]: Procedures;
|
|
13
|
+
[zImplementations]: ImplementationsMap<Procedures>;
|
|
14
|
+
start(self: Window | Worker): void;
|
|
15
|
+
} & {
|
|
16
|
+
[F in keyof Procedures]: (impl: ProcedureImplementation<Procedures[F]["input"], Procedures[F]["progress"], Procedures[F]["success"]>) => void;
|
|
17
|
+
};
|
|
4
18
|
/**
|
|
5
19
|
* Creates a sw&rpc server instance.
|
|
6
|
-
* @param procedures procedures the server will implement
|
|
20
|
+
* @param procedures procedures the server will implement, see {@link ProceduresMap}
|
|
7
21
|
* @param options various options
|
|
8
22
|
* @param options.worker if provided, the server will use this worker to post messages, instead of sending it to all clients
|
|
9
|
-
* @returns a SwarpcServer instance. Each property of the procedures map will be a method, that accepts a function implementing the procedure. There is also .start(), to be called after implementing all procedures.
|
|
23
|
+
* @returns a SwarpcServer instance. Each property of the procedures map will be a method, that accepts a function implementing the procedure (see {@link ProcedureImplementation}). There is also .start(), to be called after implementing all procedures.
|
|
24
|
+
*
|
|
25
|
+
* An example of defining a server:
|
|
26
|
+
* {@includeCode ../example/src/service-worker.ts}
|
|
10
27
|
*/
|
|
11
28
|
export declare function Server<Procedures extends ProceduresMap>(procedures: Procedures, { worker, loglevel }?: {
|
|
12
29
|
worker?: Worker;
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAgB,KAAK,QAAQ,EAAE,MAAM,UAAU,CAAA;AACtD,OAAO,EACL,kBAAkB,EAKlB,uBAAuB,EACvB,gBAAgB,EAChB,WAAW,EACX,KAAK,aAAa,EACnB,MAAM,YAAY,CAAA;AAGnB;;;GAGG;AACH,MAAM,MAAM,YAAY,CAAC,UAAU,SAAS,aAAa,IAAI;IAC3D,CAAC,WAAW,CAAC,EAAE,UAAU,CAAA;IACzB,CAAC,gBAAgB,CAAC,EAAE,kBAAkB,CAAC,UAAU,CAAC,CAAA;IAClD,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAA;CACnC,GAAG;KACD,CAAC,IAAI,MAAM,UAAU,GAAG,CACvB,IAAI,EAAE,uBAAuB,CAC3B,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EACtB,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,EACzB,UAAU,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CACzB,KACE,IAAI;CACV,CAAA;AAKD;;;;;;;;;GASG;AACH,wBAAgB,MAAM,CAAC,UAAU,SAAS,aAAa,EACrD,UAAU,EAAE,UAAU,EACtB,EAAE,MAAM,EAAE,QAAkB,EAAE,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,QAAQ,CAAA;CAAO,GAC5E,YAAY,CAAC,UAAU,CAAC,CA+J1B"}
|
package/dist/server.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
1
5
|
import { type } from "arktype";
|
|
2
6
|
import { createLogger } from "./log.js";
|
|
3
7
|
import { PayloadHeaderSchema, PayloadSchema, zImplementations, zProcedures, } from "./types.js";
|
|
@@ -6,10 +10,13 @@ const abortControllers = new Map();
|
|
|
6
10
|
const abortedRequests = new Set();
|
|
7
11
|
/**
|
|
8
12
|
* Creates a sw&rpc server instance.
|
|
9
|
-
* @param procedures procedures the server will implement
|
|
13
|
+
* @param procedures procedures the server will implement, see {@link ProceduresMap}
|
|
10
14
|
* @param options various options
|
|
11
15
|
* @param options.worker if provided, the server will use this worker to post messages, instead of sending it to all clients
|
|
12
|
-
* @returns a SwarpcServer instance. Each property of the procedures map will be a method, that accepts a function implementing the procedure. There is also .start(), to be called after implementing all procedures.
|
|
16
|
+
* @returns a SwarpcServer instance. Each property of the procedures map will be a method, that accepts a function implementing the procedure (see {@link ProcedureImplementation}). There is also .start(), to be called after implementing all procedures.
|
|
17
|
+
*
|
|
18
|
+
* An example of defining a server:
|
|
19
|
+
* {@includeCode ../example/src/service-worker.ts}
|
|
13
20
|
*/
|
|
14
21
|
export function Server(procedures, { worker, loglevel = "debug" } = {}) {
|
|
15
22
|
const l = createLogger("server", loglevel);
|
|
@@ -27,17 +34,15 @@ export function Server(procedures, { worker, loglevel = "debug" } = {}) {
|
|
|
27
34
|
if (!instance[zProcedures][functionName]) {
|
|
28
35
|
throw new Error(`No procedure found for function name: ${functionName}`);
|
|
29
36
|
}
|
|
30
|
-
instance[zImplementations][functionName] = (input, onProgress,
|
|
31
|
-
abortSignal?.throwIfAborted();
|
|
37
|
+
instance[zImplementations][functionName] = (input, onProgress, tools) => {
|
|
38
|
+
tools.abortSignal?.throwIfAborted();
|
|
32
39
|
return new Promise((resolve, reject) => {
|
|
33
|
-
abortSignal?.addEventListener("abort", () => {
|
|
34
|
-
let { requestId, reason } = abortSignal?.reason;
|
|
40
|
+
tools.abortSignal?.addEventListener("abort", () => {
|
|
41
|
+
let { requestId, reason } = tools.abortSignal?.reason;
|
|
35
42
|
l.debug(requestId, `Aborted ${functionName} request: ${reason}`);
|
|
36
43
|
reject({ aborted: reason });
|
|
37
44
|
});
|
|
38
|
-
implementation(input, onProgress,
|
|
39
|
-
.then(resolve)
|
|
40
|
-
.catch(reject);
|
|
45
|
+
implementation(input, onProgress, tools).then(resolve).catch(reject);
|
|
41
46
|
});
|
|
42
47
|
};
|
|
43
48
|
});
|
|
@@ -105,7 +110,10 @@ export function Server(procedures, { worker, loglevel = "debug" } = {}) {
|
|
|
105
110
|
await implementation(payload.input, async (progress) => {
|
|
106
111
|
l.debug(requestId, `Progress for ${functionName}`, progress);
|
|
107
112
|
await postMsg({ progress });
|
|
108
|
-
},
|
|
113
|
+
}, {
|
|
114
|
+
abortSignal: abortControllers.get(requestId)?.signal,
|
|
115
|
+
logger: createLogger("server", loglevel, requestId),
|
|
116
|
+
})
|
|
109
117
|
// Send errors
|
|
110
118
|
.catch(async (error) => {
|
|
111
119
|
// Handle errors caused by abortions
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
1
5
|
import { type Type } from "arktype";
|
|
6
|
+
import { RequestBoundLogger } from "./log.js";
|
|
2
7
|
/**
|
|
3
8
|
* A procedure declaration
|
|
4
9
|
*/
|
|
@@ -37,7 +42,7 @@ export type Procedure<I extends Type, P extends Type, S extends Type> = {
|
|
|
37
42
|
* const result = await request
|
|
38
43
|
* ```
|
|
39
44
|
*/
|
|
40
|
-
export type CancelablePromise<T> = {
|
|
45
|
+
export type CancelablePromise<T = unknown> = {
|
|
41
46
|
request: Promise<T>;
|
|
42
47
|
/**
|
|
43
48
|
* Abort the request.
|
|
@@ -48,9 +53,33 @@ export type CancelablePromise<T> = {
|
|
|
48
53
|
/**
|
|
49
54
|
* An implementation of a procedure
|
|
50
55
|
*/
|
|
51
|
-
export type ProcedureImplementation<I extends Type, P extends Type, S extends Type> = (
|
|
56
|
+
export type ProcedureImplementation<I extends Type, P extends Type, S extends Type> = (
|
|
57
|
+
/**
|
|
58
|
+
* Input data for the procedure
|
|
59
|
+
*/
|
|
60
|
+
input: I["inferOut"],
|
|
61
|
+
/**
|
|
62
|
+
* Callback to call with progress updates.
|
|
63
|
+
*/
|
|
64
|
+
onProgress: (progress: P["inferIn"]) => void,
|
|
65
|
+
/**
|
|
66
|
+
* Additional tools useful when implementing the procedure.
|
|
67
|
+
*/
|
|
68
|
+
tools: {
|
|
69
|
+
/**
|
|
70
|
+
* AbortSignal that can be used to handle request cancellation -- see [Make cancellable requests](https://gwennlbh.github.io/swarpc/docs/#make-cancelable-requests)
|
|
71
|
+
*/
|
|
72
|
+
abortSignal?: AbortSignal;
|
|
73
|
+
/**
|
|
74
|
+
* Logger instance to use for logging messages related to this procedure call, using the same format as SWARPC's built-in logging.
|
|
75
|
+
*/
|
|
76
|
+
logger: RequestBoundLogger;
|
|
77
|
+
}) => Promise<S["inferIn"]>;
|
|
52
78
|
/**
|
|
53
79
|
* Declarations of procedures by name.
|
|
80
|
+
*
|
|
81
|
+
* An example of declaring procedures:
|
|
82
|
+
* {@includeCode ../example/src/lib/procedures.ts}
|
|
54
83
|
*/
|
|
55
84
|
export type ProceduresMap = Record<string, Procedure<Type, Type, Type>>;
|
|
56
85
|
/**
|
|
@@ -76,6 +105,9 @@ export type Hooks<Procedures extends ProceduresMap> = {
|
|
|
76
105
|
*/
|
|
77
106
|
progress?: <Procedure extends keyof ProceduresMap>(procedure: Procedure, data: Procedures[Procedure]["progress"]["inferOut"]) => void;
|
|
78
107
|
};
|
|
108
|
+
/**
|
|
109
|
+
* @source
|
|
110
|
+
*/
|
|
79
111
|
export declare const PayloadHeaderSchema: import("arktype").Generic<[["Name", string]], {
|
|
80
112
|
readonly by: "\"sw&rpc\"";
|
|
81
113
|
readonly functionName: "Name";
|
|
@@ -86,6 +118,9 @@ export type PayloadHeader<PM extends ProceduresMap, Name extends keyof PM = keyo
|
|
|
86
118
|
functionName: Name & string;
|
|
87
119
|
requestId: string;
|
|
88
120
|
};
|
|
121
|
+
/**
|
|
122
|
+
* @source
|
|
123
|
+
*/
|
|
89
124
|
export declare const PayloadCoreSchema: import("arktype").Generic<[["I", unknown], ["P", unknown], ["S", unknown]], {
|
|
90
125
|
readonly "input?": "I";
|
|
91
126
|
readonly "progress?": "P";
|
|
@@ -112,6 +147,9 @@ export type PayloadCore<PM extends ProceduresMap, Name extends keyof PM = keyof
|
|
|
112
147
|
message: string;
|
|
113
148
|
};
|
|
114
149
|
};
|
|
150
|
+
/**
|
|
151
|
+
* @source
|
|
152
|
+
*/
|
|
115
153
|
export declare const PayloadSchema: import("arktype").Generic<[["Name", string], ["I", unknown], ["P", unknown], ["S", unknown]], readonly ["PayloadHeaderSchema<Name>", "&", "PayloadCoreSchema<I, P, S>"], {
|
|
116
154
|
PayloadCoreSchema: import("arktype/internal/scope.ts").bindGenericToScope<import("@ark/schema").GenericAst<[["I", unknown], ["P", unknown], ["S", unknown]], {
|
|
117
155
|
readonly "input?": "I";
|
|
@@ -230,31 +268,14 @@ export type ClientMethod<P extends Procedure<Type, Type, Type>> = ((input: P["in
|
|
|
230
268
|
};
|
|
231
269
|
/**
|
|
232
270
|
* Symbol used as the key for the procedures map on the server instance
|
|
271
|
+
* @internal
|
|
272
|
+
* @source
|
|
233
273
|
*/
|
|
234
274
|
export declare const zImplementations: unique symbol;
|
|
235
275
|
/**
|
|
236
276
|
* Symbol used as the key for the procedures map on instances
|
|
277
|
+
* @internal
|
|
278
|
+
* @source
|
|
237
279
|
*/
|
|
238
280
|
export declare const zProcedures: unique symbol;
|
|
239
|
-
/**
|
|
240
|
-
* The sw&rpc client instance, which provides methods to call procedures.
|
|
241
|
-
* Each property of the procedures map will be a method, that accepts an input, an optional onProgress callback and an optional request ID.
|
|
242
|
-
* If you want to be able to cancel the request, you can set the request's ID yourself, and call `.abort(requestId, reason)` on the client instance to cancel it.
|
|
243
|
-
*/
|
|
244
|
-
export type SwarpcClient<Procedures extends ProceduresMap> = {
|
|
245
|
-
[zProcedures]: Procedures;
|
|
246
|
-
} & {
|
|
247
|
-
[F in keyof Procedures]: ClientMethod<Procedures[F]>;
|
|
248
|
-
};
|
|
249
|
-
/**
|
|
250
|
-
* The sw&rpc server instance, which provides methods to register procedure implementations,
|
|
251
|
-
* and listens for incoming messages that call those procedures
|
|
252
|
-
*/
|
|
253
|
-
export type SwarpcServer<Procedures extends ProceduresMap> = {
|
|
254
|
-
[zProcedures]: Procedures;
|
|
255
|
-
[zImplementations]: ImplementationsMap<Procedures>;
|
|
256
|
-
start(self: Window | Worker): void;
|
|
257
|
-
} & {
|
|
258
|
-
[F in keyof Procedures]: (impl: ProcedureImplementation<Procedures[F]["input"], Procedures[F]["progress"], Procedures[F]["success"]>) => void;
|
|
259
|
-
};
|
|
260
281
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,IAAI,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -1,9 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
1
5
|
import { type } from "arktype";
|
|
6
|
+
/**
|
|
7
|
+
* @source
|
|
8
|
+
*/
|
|
2
9
|
export const PayloadHeaderSchema = type("<Name extends string>", {
|
|
3
10
|
by: '"sw&rpc"',
|
|
4
11
|
functionName: "Name",
|
|
5
12
|
requestId: "string >= 1",
|
|
6
13
|
});
|
|
14
|
+
/**
|
|
15
|
+
* @source
|
|
16
|
+
*/
|
|
7
17
|
export const PayloadCoreSchema = type("<I, P, S>", {
|
|
8
18
|
"input?": "I",
|
|
9
19
|
"progress?": "P",
|
|
@@ -11,6 +21,9 @@ export const PayloadCoreSchema = type("<I, P, S>", {
|
|
|
11
21
|
"abort?": { reason: "string" },
|
|
12
22
|
"error?": { message: "string" },
|
|
13
23
|
});
|
|
24
|
+
/**
|
|
25
|
+
* @source
|
|
26
|
+
*/
|
|
14
27
|
export const PayloadSchema = type
|
|
15
28
|
.scope({ PayloadCoreSchema, PayloadHeaderSchema })
|
|
16
29
|
.type("<Name extends string, I, P, S>", [
|
|
@@ -20,9 +33,13 @@ export const PayloadSchema = type
|
|
|
20
33
|
]);
|
|
21
34
|
/**
|
|
22
35
|
* Symbol used as the key for the procedures map on the server instance
|
|
36
|
+
* @internal
|
|
37
|
+
* @source
|
|
23
38
|
*/
|
|
24
39
|
export const zImplementations = Symbol("SWARPC implementations");
|
|
25
40
|
/**
|
|
26
41
|
* Symbol used as the key for the procedures map on instances
|
|
42
|
+
* @internal
|
|
43
|
+
* @source
|
|
27
44
|
*/
|
|
28
45
|
export const zProcedures = Symbol("SWARPC procedures");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "swarpc",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Full type-safe RPC library for service worker -- move things off of the UI thread with ease!",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"service-workers",
|
|
@@ -31,17 +31,30 @@
|
|
|
31
31
|
"dev": "tsc --watch",
|
|
32
32
|
"typecheck": "tsc --noEmit",
|
|
33
33
|
"test": "vitest",
|
|
34
|
-
"typedoc": "typedoc
|
|
35
|
-
"version": "kacl release && prettier -w CHANGELOG.md && git add CHANGELOG.md"
|
|
34
|
+
"typedoc": "typedoc",
|
|
35
|
+
"version": "kacl release && prettier -w CHANGELOG.md && git add CHANGELOG.md",
|
|
36
|
+
"typedoc:dev": "nodemon --watch src --watch README.md --watch typedoc.json --watch typedoc.css --exec npm run typedoc:withplugins",
|
|
37
|
+
"typedoc:serve": "npx sirv-cli --dev docs",
|
|
38
|
+
"typedoc:plugins": "node -e \"const fs=require('fs');const p=JSON.parse(fs.readFileSync('typedoc.json')).plugin||[];if(p.length)require('child_process').execSync('npm add --legacy-peer-deps -D '+p.join(' '),{stdio:'inherit'});else console.log('No plugins found');\"",
|
|
39
|
+
"typedoc:withplugins": "npm run typedoc:plugins && npm run typedoc"
|
|
36
40
|
},
|
|
37
41
|
"dependencies": {
|
|
38
42
|
"arktype": "^2.1.20"
|
|
39
43
|
},
|
|
40
44
|
"devDependencies": {
|
|
45
|
+
"@8hobbies/typedoc-plugin-plausible": "^2.2.0",
|
|
41
46
|
"@vitest/web-worker": "^3.2.4",
|
|
42
47
|
"kacl": "^1.1.1",
|
|
48
|
+
"nodemon": "^3.1.10",
|
|
43
49
|
"prettier": "^3.6.2",
|
|
50
|
+
"sirv-cli": "^3.0.1",
|
|
44
51
|
"typedoc": "^0.28.9",
|
|
52
|
+
"typedoc-material-theme": "^1.4.0",
|
|
53
|
+
"typedoc-plugin-dt-links": "^2.0.12",
|
|
54
|
+
"typedoc-plugin-extras": "^4.0.1",
|
|
55
|
+
"typedoc-plugin-inline-sources": "^1.3.0",
|
|
56
|
+
"typedoc-plugin-mdn-links": "^5.0.6",
|
|
57
|
+
"typedoc-plugin-redirect": "^1.2.0",
|
|
45
58
|
"typescript": "^5.9.2",
|
|
46
59
|
"vite": "^7.0.6",
|
|
47
60
|
"vitest": "^3.2.4"
|
package/src/client.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import { createLogger, type Logger, type LogLevel } from "./log.js"
|
|
2
7
|
import {
|
|
8
|
+
ClientMethod,
|
|
3
9
|
Hooks,
|
|
4
10
|
Payload,
|
|
5
11
|
PayloadCore,
|
|
6
12
|
zProcedures,
|
|
7
13
|
type ProceduresMap,
|
|
8
|
-
type SwarpcClient
|
|
9
14
|
} from "./types.js"
|
|
10
15
|
import { findTransferables } from "./utils.js"
|
|
11
16
|
|
|
12
|
-
|
|
17
|
+
/**
|
|
18
|
+
* The sw&rpc client instance, which provides {@link ClientMethod | methods to call procedures}.
|
|
19
|
+
* Each property of the procedures map will be a method, that accepts an input, an optional onProgress callback and an optional request ID.
|
|
20
|
+
* If you want to be able to cancel the request, you can set the request's ID yourself, and call `.abort(requestId, reason)` on the client instance to cancel it.
|
|
21
|
+
*/
|
|
22
|
+
export type SwarpcClient<Procedures extends ProceduresMap> = {
|
|
23
|
+
[zProcedures]: Procedures
|
|
24
|
+
} & {
|
|
25
|
+
[F in keyof Procedures]: ClientMethod<Procedures[F]>
|
|
26
|
+
}
|
|
13
27
|
|
|
14
28
|
/**
|
|
15
29
|
* Pending requests are stored in a map, where the key is the request ID.
|
|
@@ -29,11 +43,14 @@ let _clientListenerStarted = false
|
|
|
29
43
|
|
|
30
44
|
/**
|
|
31
45
|
*
|
|
32
|
-
* @param procedures procedures the client will be able to call
|
|
46
|
+
* @param procedures procedures the client will be able to call, see {@link ProceduresMap}
|
|
33
47
|
* @param options various options
|
|
34
48
|
* @param options.worker if provided, the client will use this worker to post messages.
|
|
35
49
|
* @param options.hooks hooks to run on messages received from the server
|
|
36
|
-
* @returns a sw&rpc client instance. Each property of the procedures map will be a method, that accepts an input and an optional onProgress callback
|
|
50
|
+
* @returns a sw&rpc client instance. Each property of the procedures map will be a method, that accepts an input and an optional onProgress callback, see {@link ClientMethod}
|
|
51
|
+
*
|
|
52
|
+
* An example of defining and using a client:
|
|
53
|
+
* {@includeCode ../example/src/routes/+page.svelte}
|
|
37
54
|
*/
|
|
38
55
|
export function Client<Procedures extends ProceduresMap>(
|
|
39
56
|
procedures: Procedures,
|
|
@@ -238,6 +255,7 @@ async function startClientListener<Procedures extends ProceduresMap>(
|
|
|
238
255
|
|
|
239
256
|
/**
|
|
240
257
|
* Generate a random request ID, used to identify requests between client and server.
|
|
258
|
+
* @source
|
|
241
259
|
* @returns a 6-character hexadecimal string
|
|
242
260
|
*/
|
|
243
261
|
export function makeRequestId(): string {
|
package/src/index.ts
CHANGED
package/src/log.ts
CHANGED
|
@@ -1,30 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @ignore
|
|
8
|
+
*/
|
|
9
|
+
export function createLogger(side: "server" | "client", level: LogLevel): Logger
|
|
1
10
|
export function createLogger(
|
|
2
11
|
side: "server" | "client",
|
|
3
|
-
level: LogLevel
|
|
12
|
+
level: LogLevel,
|
|
13
|
+
rqid: string
|
|
14
|
+
): RequestBoundLogger
|
|
15
|
+
export function createLogger(
|
|
16
|
+
side: "server" | "client",
|
|
17
|
+
level: LogLevel = "debug",
|
|
18
|
+
rqid?: string
|
|
4
19
|
) {
|
|
5
|
-
const
|
|
20
|
+
const lvls = LOG_LEVELS.slice(LOG_LEVELS.indexOf(level))
|
|
21
|
+
|
|
22
|
+
if (rqid) {
|
|
23
|
+
return {
|
|
24
|
+
debug: lvls.includes("debug") ? logger("debug", side, rqid) : () => {},
|
|
25
|
+
info: lvls.includes("info") ? logger("info", side, rqid) : () => {},
|
|
26
|
+
warn: lvls.includes("warn") ? logger("warn", side, rqid) : () => {},
|
|
27
|
+
error: lvls.includes("error") ? logger("error", side, rqid) : () => {},
|
|
28
|
+
} as RequestBoundLogger
|
|
29
|
+
}
|
|
6
30
|
|
|
7
31
|
return {
|
|
8
|
-
debug:
|
|
9
|
-
info:
|
|
10
|
-
warn:
|
|
11
|
-
error:
|
|
32
|
+
debug: lvls.includes("debug") ? logger("debug", side) : () => {},
|
|
33
|
+
info: lvls.includes("info") ? logger("info", side) : () => {},
|
|
34
|
+
warn: lvls.includes("warn") ? logger("warn", side) : () => {},
|
|
35
|
+
error: lvls.includes("error") ? logger("error", side) : () => {},
|
|
12
36
|
}
|
|
13
37
|
}
|
|
14
38
|
|
|
15
|
-
|
|
39
|
+
/**
|
|
40
|
+
* @ignore
|
|
41
|
+
*/
|
|
42
|
+
export type Logger = {
|
|
43
|
+
debug: (rqid: string | null, message: string, ...args: any[]) => void
|
|
44
|
+
info: (rqid: string | null, message: string, ...args: any[]) => void
|
|
45
|
+
warn: (rqid: string | null, message: string, ...args: any[]) => void
|
|
46
|
+
error: (rqid: string | null, message: string, ...args: any[]) => void
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type RequestBoundLogger = {
|
|
50
|
+
debug: (message: string, ...args: any[]) => void
|
|
51
|
+
info: (message: string, ...args: any[]) => void
|
|
52
|
+
warn: (message: string, ...args: any[]) => void
|
|
53
|
+
error: (message: string, ...args: any[]) => void
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** @source */
|
|
57
|
+
export const LOG_LEVELS = ["debug", "info", "warn", "error"] as const
|
|
16
58
|
|
|
17
|
-
const LOG_LEVELS = ["debug", "info", "warn", "error"] as const
|
|
18
59
|
export type LogLevel = (typeof LOG_LEVELS)[number]
|
|
19
60
|
|
|
20
61
|
/**
|
|
21
|
-
* Creates partially-applied logging functions given the first 2 args
|
|
62
|
+
* Creates partially-applied logging functions given the first 2 or 3 args
|
|
22
63
|
* @param severity
|
|
23
64
|
* @param side
|
|
65
|
+
* @param rqid request ID, or null to not bind it
|
|
24
66
|
* @returns
|
|
25
67
|
*/
|
|
26
|
-
function logger(
|
|
27
|
-
|
|
68
|
+
function logger(
|
|
69
|
+
severity: LogLevel,
|
|
70
|
+
side: "server" | "client",
|
|
71
|
+
rqid: string
|
|
72
|
+
): (message: string, ...args: any[]) => void
|
|
73
|
+
function logger(
|
|
74
|
+
severity: LogLevel,
|
|
75
|
+
side: "server" | "client"
|
|
76
|
+
): (rqid: string | null, message: string, ...args: any[]) => void
|
|
77
|
+
function logger(severity: LogLevel, side: "server" | "client", rqid?: string) {
|
|
78
|
+
if (rqid === undefined) {
|
|
79
|
+
return (rqid: string | null, message: string, ...args: any[]) =>
|
|
80
|
+
log(severity, side, rqid, message, ...args)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return (message: string, ...args: any[]) =>
|
|
28
84
|
log(severity, side, rqid, message, ...args)
|
|
29
85
|
}
|
|
30
86
|
|
|
@@ -36,7 +92,7 @@ function logger(severity: LogLevel, side: "server" | "client") {
|
|
|
36
92
|
* @param message
|
|
37
93
|
* @param args passed to console methods directly
|
|
38
94
|
*/
|
|
39
|
-
|
|
95
|
+
function log(
|
|
40
96
|
severity: "debug" | "info" | "warn" | "error",
|
|
41
97
|
side: "server" | "client",
|
|
42
98
|
rqid: string | null,
|
package/src/server.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import { type } from "arktype"
|
|
2
7
|
import { createLogger, type LogLevel } from "./log.js"
|
|
3
8
|
import {
|
|
@@ -6,24 +11,43 @@ import {
|
|
|
6
11
|
PayloadCore,
|
|
7
12
|
PayloadHeaderSchema,
|
|
8
13
|
PayloadSchema,
|
|
14
|
+
ProcedureImplementation,
|
|
9
15
|
zImplementations,
|
|
10
16
|
zProcedures,
|
|
11
17
|
type ProceduresMap,
|
|
12
|
-
type SwarpcServer,
|
|
13
18
|
} from "./types.js"
|
|
14
19
|
import { findTransferables } from "./utils.js"
|
|
15
20
|
|
|
16
|
-
|
|
21
|
+
/**
|
|
22
|
+
* The sw&rpc server instance, which provides methods to register {@link ProcedureImplementation | procedure implementations},
|
|
23
|
+
* and listens for incoming messages that call those procedures
|
|
24
|
+
*/
|
|
25
|
+
export type SwarpcServer<Procedures extends ProceduresMap> = {
|
|
26
|
+
[zProcedures]: Procedures
|
|
27
|
+
[zImplementations]: ImplementationsMap<Procedures>
|
|
28
|
+
start(self: Window | Worker): void
|
|
29
|
+
} & {
|
|
30
|
+
[F in keyof Procedures]: (
|
|
31
|
+
impl: ProcedureImplementation<
|
|
32
|
+
Procedures[F]["input"],
|
|
33
|
+
Procedures[F]["progress"],
|
|
34
|
+
Procedures[F]["success"]
|
|
35
|
+
>
|
|
36
|
+
) => void
|
|
37
|
+
}
|
|
17
38
|
|
|
18
39
|
const abortControllers = new Map<string, AbortController>()
|
|
19
40
|
const abortedRequests = new Set<string>()
|
|
20
41
|
|
|
21
42
|
/**
|
|
22
43
|
* Creates a sw&rpc server instance.
|
|
23
|
-
* @param procedures procedures the server will implement
|
|
44
|
+
* @param procedures procedures the server will implement, see {@link ProceduresMap}
|
|
24
45
|
* @param options various options
|
|
25
46
|
* @param options.worker if provided, the server will use this worker to post messages, instead of sending it to all clients
|
|
26
|
-
* @returns a SwarpcServer instance. Each property of the procedures map will be a method, that accepts a function implementing the procedure. There is also .start(), to be called after implementing all procedures.
|
|
47
|
+
* @returns a SwarpcServer instance. Each property of the procedures map will be a method, that accepts a function implementing the procedure (see {@link ProcedureImplementation}). There is also .start(), to be called after implementing all procedures.
|
|
48
|
+
*
|
|
49
|
+
* An example of defining a server:
|
|
50
|
+
* {@includeCode ../example/src/service-worker.ts}
|
|
27
51
|
*/
|
|
28
52
|
export function Server<Procedures extends ProceduresMap>(
|
|
29
53
|
procedures: Procedures,
|
|
@@ -46,22 +70,16 @@ export function Server<Procedures extends ProceduresMap>(
|
|
|
46
70
|
if (!instance[zProcedures][functionName]) {
|
|
47
71
|
throw new Error(`No procedure found for function name: ${functionName}`)
|
|
48
72
|
}
|
|
49
|
-
instance[zImplementations][functionName] = (
|
|
50
|
-
|
|
51
|
-
onProgress,
|
|
52
|
-
abortSignal
|
|
53
|
-
) => {
|
|
54
|
-
abortSignal?.throwIfAborted()
|
|
73
|
+
instance[zImplementations][functionName] = (input, onProgress, tools) => {
|
|
74
|
+
tools.abortSignal?.throwIfAborted()
|
|
55
75
|
return new Promise((resolve, reject) => {
|
|
56
|
-
abortSignal?.addEventListener("abort", () => {
|
|
57
|
-
let { requestId, reason } = abortSignal?.reason
|
|
76
|
+
tools.abortSignal?.addEventListener("abort", () => {
|
|
77
|
+
let { requestId, reason } = tools.abortSignal?.reason
|
|
58
78
|
l.debug(requestId, `Aborted ${functionName} request: ${reason}`)
|
|
59
79
|
reject({ aborted: reason })
|
|
60
80
|
})
|
|
61
81
|
|
|
62
|
-
implementation(input, onProgress,
|
|
63
|
-
.then(resolve)
|
|
64
|
-
.catch(reject)
|
|
82
|
+
implementation(input, onProgress, tools).then(resolve).catch(reject)
|
|
65
83
|
})
|
|
66
84
|
}
|
|
67
85
|
}) as SwarpcServer<Procedures>[typeof functionName]
|
|
@@ -159,7 +177,10 @@ export function Server<Procedures extends ProceduresMap>(
|
|
|
159
177
|
l.debug(requestId, `Progress for ${functionName}`, progress)
|
|
160
178
|
await postMsg({ progress })
|
|
161
179
|
},
|
|
162
|
-
|
|
180
|
+
{
|
|
181
|
+
abortSignal: abortControllers.get(requestId)?.signal,
|
|
182
|
+
logger: createLogger("server", loglevel, requestId),
|
|
183
|
+
}
|
|
163
184
|
)
|
|
164
185
|
// Send errors
|
|
165
186
|
.catch(async (error: any) => {
|
package/src/types.ts
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module
|
|
3
|
+
* @mergeModuleWith <project>
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import { type, type Type } from "arktype"
|
|
7
|
+
import { Logger, RequestBoundLogger } from "./log.js"
|
|
2
8
|
|
|
3
9
|
/**
|
|
4
10
|
* A procedure declaration
|
|
@@ -39,7 +45,7 @@ export type Procedure<I extends Type, P extends Type, S extends Type> = {
|
|
|
39
45
|
* const result = await request
|
|
40
46
|
* ```
|
|
41
47
|
*/
|
|
42
|
-
export type CancelablePromise<T> = {
|
|
48
|
+
export type CancelablePromise<T = unknown> = {
|
|
43
49
|
request: Promise<T>
|
|
44
50
|
/**
|
|
45
51
|
* Abort the request.
|
|
@@ -56,13 +62,34 @@ export type ProcedureImplementation<
|
|
|
56
62
|
P extends Type,
|
|
57
63
|
S extends Type,
|
|
58
64
|
> = (
|
|
65
|
+
/**
|
|
66
|
+
* Input data for the procedure
|
|
67
|
+
*/
|
|
59
68
|
input: I["inferOut"],
|
|
69
|
+
/**
|
|
70
|
+
* Callback to call with progress updates.
|
|
71
|
+
*/
|
|
60
72
|
onProgress: (progress: P["inferIn"]) => void,
|
|
61
|
-
|
|
73
|
+
/**
|
|
74
|
+
* Additional tools useful when implementing the procedure.
|
|
75
|
+
*/
|
|
76
|
+
tools: {
|
|
77
|
+
/**
|
|
78
|
+
* AbortSignal that can be used to handle request cancellation -- see [Make cancellable requests](https://gwennlbh.github.io/swarpc/docs/#make-cancelable-requests)
|
|
79
|
+
*/
|
|
80
|
+
abortSignal?: AbortSignal
|
|
81
|
+
/**
|
|
82
|
+
* Logger instance to use for logging messages related to this procedure call, using the same format as SWARPC's built-in logging.
|
|
83
|
+
*/
|
|
84
|
+
logger: RequestBoundLogger
|
|
85
|
+
}
|
|
62
86
|
) => Promise<S["inferIn"]>
|
|
63
87
|
|
|
64
88
|
/**
|
|
65
89
|
* Declarations of procedures by name.
|
|
90
|
+
*
|
|
91
|
+
* An example of declaring procedures:
|
|
92
|
+
* {@includeCode ../example/src/lib/procedures.ts}
|
|
66
93
|
*/
|
|
67
94
|
export type ProceduresMap = Record<string, Procedure<Type, Type, Type>>
|
|
68
95
|
|
|
@@ -104,6 +131,9 @@ export type Hooks<Procedures extends ProceduresMap> = {
|
|
|
104
131
|
) => void
|
|
105
132
|
}
|
|
106
133
|
|
|
134
|
+
/**
|
|
135
|
+
* @source
|
|
136
|
+
*/
|
|
107
137
|
export const PayloadHeaderSchema = type("<Name extends string>", {
|
|
108
138
|
by: '"sw&rpc"',
|
|
109
139
|
functionName: "Name",
|
|
@@ -119,6 +149,9 @@ export type PayloadHeader<
|
|
|
119
149
|
requestId: string
|
|
120
150
|
}
|
|
121
151
|
|
|
152
|
+
/**
|
|
153
|
+
* @source
|
|
154
|
+
*/
|
|
122
155
|
export const PayloadCoreSchema = type("<I, P, S>", {
|
|
123
156
|
"input?": "I",
|
|
124
157
|
"progress?": "P",
|
|
@@ -147,6 +180,9 @@ export type PayloadCore<
|
|
|
147
180
|
error: { message: string }
|
|
148
181
|
}
|
|
149
182
|
|
|
183
|
+
/**
|
|
184
|
+
* @source
|
|
185
|
+
*/
|
|
150
186
|
export const PayloadSchema = type
|
|
151
187
|
.scope({ PayloadCoreSchema, PayloadHeaderSchema })
|
|
152
188
|
.type("<Name extends string, I, P, S>", [
|
|
@@ -182,38 +218,14 @@ export type ClientMethod<P extends Procedure<Type, Type, Type>> = ((
|
|
|
182
218
|
|
|
183
219
|
/**
|
|
184
220
|
* Symbol used as the key for the procedures map on the server instance
|
|
221
|
+
* @internal
|
|
222
|
+
* @source
|
|
185
223
|
*/
|
|
186
224
|
export const zImplementations = Symbol("SWARPC implementations")
|
|
225
|
+
|
|
187
226
|
/**
|
|
188
227
|
* Symbol used as the key for the procedures map on instances
|
|
228
|
+
* @internal
|
|
229
|
+
* @source
|
|
189
230
|
*/
|
|
190
231
|
export const zProcedures = Symbol("SWARPC procedures")
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* The sw&rpc client instance, which provides methods to call procedures.
|
|
194
|
-
* Each property of the procedures map will be a method, that accepts an input, an optional onProgress callback and an optional request ID.
|
|
195
|
-
* If you want to be able to cancel the request, you can set the request's ID yourself, and call `.abort(requestId, reason)` on the client instance to cancel it.
|
|
196
|
-
*/
|
|
197
|
-
export type SwarpcClient<Procedures extends ProceduresMap> = {
|
|
198
|
-
[zProcedures]: Procedures
|
|
199
|
-
} & {
|
|
200
|
-
[F in keyof Procedures]: ClientMethod<Procedures[F]>
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
/**
|
|
204
|
-
* The sw&rpc server instance, which provides methods to register procedure implementations,
|
|
205
|
-
* and listens for incoming messages that call those procedures
|
|
206
|
-
*/
|
|
207
|
-
export type SwarpcServer<Procedures extends ProceduresMap> = {
|
|
208
|
-
[zProcedures]: Procedures
|
|
209
|
-
[zImplementations]: ImplementationsMap<Procedures>
|
|
210
|
-
start(self: Window | Worker): void
|
|
211
|
-
} & {
|
|
212
|
-
[F in keyof Procedures]: (
|
|
213
|
-
impl: ProcedureImplementation<
|
|
214
|
-
Procedures[F]["input"],
|
|
215
|
-
Procedures[F]["progress"],
|
|
216
|
-
Procedures[F]["success"]
|
|
217
|
-
>
|
|
218
|
-
) => void
|
|
219
|
-
}
|