@effectionx/timebox 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,27 @@
1
+ # Timebox
2
+
3
+ Constrain any operation to complete within a certain time.
4
+
5
+ ---
6
+
7
+ Very often you want to put a limit on how long an operation may run such as a
8
+ `fetch()` of an external resource, or handling a web request. To do this, you
9
+ can use the `timebox()` function. It will encapsulate the operation and either
10
+ return its result, or a otherwise a "timeout" object indicating that it did not
11
+ complete in the required time.
12
+
13
+ ```ts
14
+ import { timebox } from "@effectionx/timebox";
15
+ import { handleRequest } from "./handle-request";
16
+
17
+ // a theoretical request handler
18
+ export function* handler(request) {
19
+ // do not let the handler run for more than 10 seconds
20
+ let result = yield* timebox(10000, () => handleRequest(request));
21
+ if (result.timeout) {
22
+ return new Response(504, "Gateway Timeout");
23
+ } else {
24
+ return result.value;
25
+ }
26
+ }
27
+ ```
package/esm/mod.d.ts ADDED
@@ -0,0 +1,69 @@
1
+ import type { Operation } from "effection";
2
+ /**
3
+ * Either a succesfully computed value, or one that took too long to complete.
4
+ */
5
+ export type Timeboxed<T> = Completed<T> | Timeout;
6
+ /**
7
+ * A value successfully computed within the timeout window. It has metadata about how long it
8
+ * took.
9
+ */
10
+ export interface Completed<T> {
11
+ /**
12
+ * false: indicates that there was no timeout and that value was successfully computed
13
+ */
14
+ readonly timeout: false;
15
+ /**
16
+ * The actual value
17
+ */
18
+ readonly value: T;
19
+ /**
20
+ * The time that the operation began;
21
+ */
22
+ readonly start: DOMHighResTimeStamp;
23
+ /**
24
+ * The time that the operation succesfully returned value
25
+ */
26
+ readonly end: DOMHighResTimeStamp;
27
+ }
28
+ /**
29
+ * A value that did not compute within the alloted window.
30
+ */
31
+ export interface Timeout {
32
+ /**
33
+ * true: indicates that this is a timed out result and no value is available
34
+ */
35
+ readonly timeout: true;
36
+ /**
37
+ * The time that the operation began;
38
+ */
39
+ readonly start: DOMHighResTimeStamp;
40
+ /**
41
+ * The time that the operation succesfully returned value
42
+ */
43
+ readonly end: DOMHighResTimeStamp;
44
+ }
45
+ /**
46
+ * Constrain `operation` to complete within `limitMS` milliseconds
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { timebox } from "@effectionx/timebox";
51
+ * import { handleRequest } from "./handle-request";
52
+
53
+ * // a theoretical request handler
54
+ * export function* handler(request: Request): Operation<Response> {
55
+ * // do not let the handler run for more than 10 seconds
56
+ * let result = yield* timebox(10000, () => handleRequest(request));
57
+ * if (result.timeout) {
58
+ * return new Response(504, "Gateway Timeout");
59
+ * } else {
60
+ * return result.value;
61
+ * }
62
+ * }
63
+ * ```
64
+ * @param limitMS - the maximum allowable time for `operation` to complete
65
+ * @param operation - the operation to attempt
66
+ * @returns either a completed value or a timeout
67
+ */
68
+ export declare function timebox<T>(limitMS: number, operation: () => Operation<T>): Operation<Timeboxed<T>>;
69
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;AAElD;;;GAGG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAExB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC,GAC5B,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAEzB"}
package/esm/mod.js ADDED
@@ -0,0 +1,36 @@
1
+ import { race, sleep } from "effection";
2
+ /**
3
+ * Constrain `operation` to complete within `limitMS` milliseconds
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * import { timebox } from "@effectionx/timebox";
8
+ * import { handleRequest } from "./handle-request";
9
+
10
+ * // a theoretical request handler
11
+ * export function* handler(request: Request): Operation<Response> {
12
+ * // do not let the handler run for more than 10 seconds
13
+ * let result = yield* timebox(10000, () => handleRequest(request));
14
+ * if (result.timeout) {
15
+ * return new Response(504, "Gateway Timeout");
16
+ * } else {
17
+ * return result.value;
18
+ * }
19
+ * }
20
+ * ```
21
+ * @param limitMS - the maximum allowable time for `operation` to complete
22
+ * @param operation - the operation to attempt
23
+ * @returns either a completed value or a timeout
24
+ */
25
+ export function timebox(limitMS, operation) {
26
+ return race([complete(operation), deadline(limitMS)]);
27
+ }
28
+ function* deadline(limitMS) {
29
+ let start = performance.now();
30
+ yield* sleep(limitMS);
31
+ return { timeout: true, start, end: performance.now() };
32
+ }
33
+ function* complete(op) {
34
+ let start = performance.now();
35
+ return { timeout: false, value: yield* op(), start, end: performance.now() };
36
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "module"
3
+ }
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@effectionx/timebox",
3
+ "version": "0.1.0",
4
+ "author": "engineering@frontside.com",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/thefrontside/effectionx.git"
8
+ },
9
+ "license": "MIT",
10
+ "bugs": {
11
+ "url": "https://github.com/thefrontside/effectionx/issues"
12
+ },
13
+ "main": "./script/mod.js",
14
+ "module": "./esm/mod.js",
15
+ "exports": {
16
+ ".": {
17
+ "import": "./esm/mod.js",
18
+ "require": "./script/mod.js"
19
+ }
20
+ },
21
+ "scripts": {},
22
+ "engines": {
23
+ "node": ">= 16"
24
+ },
25
+ "sideEffects": false,
26
+ "dependencies": {
27
+ "effection": "^3"
28
+ },
29
+ "_generatedBy": "dnt@dev"
30
+ }
@@ -0,0 +1,69 @@
1
+ import type { Operation } from "effection";
2
+ /**
3
+ * Either a succesfully computed value, or one that took too long to complete.
4
+ */
5
+ export type Timeboxed<T> = Completed<T> | Timeout;
6
+ /**
7
+ * A value successfully computed within the timeout window. It has metadata about how long it
8
+ * took.
9
+ */
10
+ export interface Completed<T> {
11
+ /**
12
+ * false: indicates that there was no timeout and that value was successfully computed
13
+ */
14
+ readonly timeout: false;
15
+ /**
16
+ * The actual value
17
+ */
18
+ readonly value: T;
19
+ /**
20
+ * The time that the operation began;
21
+ */
22
+ readonly start: DOMHighResTimeStamp;
23
+ /**
24
+ * The time that the operation succesfully returned value
25
+ */
26
+ readonly end: DOMHighResTimeStamp;
27
+ }
28
+ /**
29
+ * A value that did not compute within the alloted window.
30
+ */
31
+ export interface Timeout {
32
+ /**
33
+ * true: indicates that this is a timed out result and no value is available
34
+ */
35
+ readonly timeout: true;
36
+ /**
37
+ * The time that the operation began;
38
+ */
39
+ readonly start: DOMHighResTimeStamp;
40
+ /**
41
+ * The time that the operation succesfully returned value
42
+ */
43
+ readonly end: DOMHighResTimeStamp;
44
+ }
45
+ /**
46
+ * Constrain `operation` to complete within `limitMS` milliseconds
47
+ *
48
+ * @example
49
+ * ```ts
50
+ * import { timebox } from "@effectionx/timebox";
51
+ * import { handleRequest } from "./handle-request";
52
+
53
+ * // a theoretical request handler
54
+ * export function* handler(request: Request): Operation<Response> {
55
+ * // do not let the handler run for more than 10 seconds
56
+ * let result = yield* timebox(10000, () => handleRequest(request));
57
+ * if (result.timeout) {
58
+ * return new Response(504, "Gateway Timeout");
59
+ * } else {
60
+ * return result.value;
61
+ * }
62
+ * }
63
+ * ```
64
+ * @param limitMS - the maximum allowable time for `operation` to complete
65
+ * @param operation - the operation to attempt
66
+ * @returns either a completed value or a timeout
67
+ */
68
+ export declare function timebox<T>(limitMS: number, operation: () => Operation<T>): Operation<Timeboxed<T>>;
69
+ //# sourceMappingURL=mod.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAG3C;;GAEG;AACH,MAAM,MAAM,SAAS,CAAC,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;AAElD;;;GAGG;AACH,MAAM,WAAW,SAAS,CAAC,CAAC;IAC1B;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC;IAExB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;IAElB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;CACnC;AAED;;GAEG;AACH,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IAEvB;;OAEG;IACH,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;IAEpC;;OAEG;IACH,QAAQ,CAAC,GAAG,EAAE,mBAAmB,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,OAAO,CAAC,CAAC,EACvB,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,SAAS,CAAC,CAAC,CAAC,GAC5B,SAAS,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAEzB"}
package/script/mod.js ADDED
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.timebox = timebox;
4
+ const effection_1 = require("effection");
5
+ /**
6
+ * Constrain `operation` to complete within `limitMS` milliseconds
7
+ *
8
+ * @example
9
+ * ```ts
10
+ * import { timebox } from "@effectionx/timebox";
11
+ * import { handleRequest } from "./handle-request";
12
+
13
+ * // a theoretical request handler
14
+ * export function* handler(request: Request): Operation<Response> {
15
+ * // do not let the handler run for more than 10 seconds
16
+ * let result = yield* timebox(10000, () => handleRequest(request));
17
+ * if (result.timeout) {
18
+ * return new Response(504, "Gateway Timeout");
19
+ * } else {
20
+ * return result.value;
21
+ * }
22
+ * }
23
+ * ```
24
+ * @param limitMS - the maximum allowable time for `operation` to complete
25
+ * @param operation - the operation to attempt
26
+ * @returns either a completed value or a timeout
27
+ */
28
+ function timebox(limitMS, operation) {
29
+ return (0, effection_1.race)([complete(operation), deadline(limitMS)]);
30
+ }
31
+ function* deadline(limitMS) {
32
+ let start = performance.now();
33
+ yield* (0, effection_1.sleep)(limitMS);
34
+ return { timeout: true, start, end: performance.now() };
35
+ }
36
+ function* complete(op) {
37
+ let start = performance.now();
38
+ return { timeout: false, value: yield* op(), start, end: performance.now() };
39
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }