@tstdl/base 0.90.82 → 0.90.83
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.
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Creates a new context provider
|
|
3
|
+
* @param name name of of the context used for function names
|
|
4
|
+
*/
|
|
5
|
+
export declare function createContextProvider<Context, const Name extends string>(name: Name): { [P in `getCurrent${Name}Context`]: {
|
|
6
|
+
(required: true, debugFn: Function): Context;
|
|
7
|
+
(required?: false | undefined, debugFn?: Function): Context | null;
|
|
8
|
+
(required: boolean, debugFn: Function): Context | null;
|
|
9
|
+
}; } & { [P_1 in `setCurrent${Name}Context`]: (context: Context | null) => Context | null; } & { [P_2 in `runIn${Name}Context`]: <ReturnT>(context: Context, fn: () => ReturnT) => ReturnT; } & { [P_3 in `isIn${Name}Context`]: {
|
|
10
|
+
(required: true, debugFn: Function): Context;
|
|
11
|
+
(required?: false | undefined, debugFn?: Function): Context | null;
|
|
12
|
+
(required: boolean, debugFn: Function): Context | null;
|
|
13
|
+
}; } & { [P_4 in `assertIn${Name}Context`]: {
|
|
14
|
+
(required: true, debugFn: Function): Context;
|
|
15
|
+
(required?: false | undefined, debugFn?: Function): Context | null;
|
|
16
|
+
(required: boolean, debugFn: Function): Context | null;
|
|
17
|
+
}; } extends infer T extends import("../types.js").Record<PropertyKey, any> ? { [K in keyof T]: ({ [P in `getCurrent${Name}Context`]: {
|
|
18
|
+
(required: true, debugFn: Function): Context;
|
|
19
|
+
(required?: false | undefined, debugFn?: Function): Context | null;
|
|
20
|
+
(required: boolean, debugFn: Function): Context | null;
|
|
21
|
+
}; } & { [P_1 in `setCurrent${Name}Context`]: (context: Context | null) => Context | null; } & { [P_2 in `runIn${Name}Context`]: <ReturnT>(context: Context, fn: () => ReturnT) => ReturnT; } & { [P_3 in `isIn${Name}Context`]: {
|
|
22
|
+
(required: true, debugFn: Function): Context;
|
|
23
|
+
(required?: false | undefined, debugFn?: Function): Context | null;
|
|
24
|
+
(required: boolean, debugFn: Function): Context | null;
|
|
25
|
+
}; } & { [P_4 in `assertIn${Name}Context`]: {
|
|
26
|
+
(required: true, debugFn: Function): Context;
|
|
27
|
+
(required?: false | undefined, debugFn?: Function): Context | null;
|
|
28
|
+
(required: boolean, debugFn: Function): Context | null;
|
|
29
|
+
}; })[K]; } : never;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { isNotNull } from '../utils/type-guards.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates a new context provider
|
|
4
|
+
* @param name name of of the context used for function names
|
|
5
|
+
*/
|
|
6
|
+
export function createContextProvider(name) {
|
|
7
|
+
let currentContext = null;
|
|
8
|
+
function getCurrentContext(required = false, debugFn) {
|
|
9
|
+
if (required) {
|
|
10
|
+
assertInContext(debugFn);
|
|
11
|
+
}
|
|
12
|
+
return currentContext;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Manually set the context. Usually runInContext is preferred, as no manual cleanup is required.
|
|
16
|
+
* @param context context to set
|
|
17
|
+
* @returns previous context, if any
|
|
18
|
+
*/
|
|
19
|
+
function setCurrentContext(context) {
|
|
20
|
+
const previous = currentContext;
|
|
21
|
+
currentContext = context;
|
|
22
|
+
return previous;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Runs the given function with the given {@link Context} as context.
|
|
26
|
+
*
|
|
27
|
+
* @param context the context to provide while `fn` is executing
|
|
28
|
+
* @param fn the function to run with the provided context
|
|
29
|
+
* @returns the return value of the function, if any
|
|
30
|
+
*/
|
|
31
|
+
function runInContext(context, fn) {
|
|
32
|
+
const previousContext = setCurrentContext(context);
|
|
33
|
+
try {
|
|
34
|
+
return fn();
|
|
35
|
+
}
|
|
36
|
+
finally {
|
|
37
|
+
setCurrentContext(previousContext);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Whether the current stack is in a context
|
|
42
|
+
*/
|
|
43
|
+
function isInContext() {
|
|
44
|
+
return isNotNull(currentContext);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Asserts that the current stack is within an context
|
|
48
|
+
*
|
|
49
|
+
* @param debugFn a reference to the function making the assertion (used for the error message).
|
|
50
|
+
*/
|
|
51
|
+
function assertInContext(debugFn) {
|
|
52
|
+
if (!isInContext()) {
|
|
53
|
+
throw new Error(`${debugFn.name}() can only be used within an ${name}Context via \`runIn${name}Context\`.`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
[`getCurrent${name}Context`]: getCurrentContext,
|
|
58
|
+
[`setCurrent${name}Context`]: setCurrentContext,
|
|
59
|
+
[`runIn${name}Context`]: runInContext,
|
|
60
|
+
[`isIn${name}Context`]: getCurrentContext,
|
|
61
|
+
[`assertIn${name}Context`]: getCurrentContext
|
|
62
|
+
};
|
|
63
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './context.js';
|
package/context/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './context.js';
|
|
@@ -6,6 +6,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
6
6
|
};
|
|
7
7
|
/* eslint-disable max-classes-per-file */
|
|
8
8
|
import '../../polyfills.js';
|
|
9
|
+
import { Agent } from 'undici';
|
|
9
10
|
import { compileClient } from '../../api/client/client.js';
|
|
10
11
|
import { defineApi } from '../../api/index.js';
|
|
11
12
|
import { apiController, configureApiServer } from '../../api/server/index.js';
|
|
@@ -17,13 +18,14 @@ import { HttpServerResponse } from '../../http/server/index.js';
|
|
|
17
18
|
import { configureNodeHttpServer } from '../../http/server/node/index.js';
|
|
18
19
|
import { inject } from '../../injector/inject.js';
|
|
19
20
|
import { WebServerModule } from '../../module/modules/web-server.module.js';
|
|
21
|
+
import { configureDefaultSignalsImplementation } from '../../signals/implementation/configure.js';
|
|
20
22
|
import { ServerSentEvents, ServerSentEventsSource } from '../../sse/index.js';
|
|
21
23
|
import { decodeTextStream, encodeUtf8Stream } from '../../utils/encoding.js';
|
|
22
24
|
import { getReadableStreamFromIterable, getReadableStreamIterable } from '../../utils/stream/index.js';
|
|
23
25
|
import { cancelableTimeout, timeout } from '../../utils/timing.js';
|
|
24
26
|
import { isDefined } from '../../utils/type-guards.js';
|
|
25
|
-
import { Agent } from 'undici';
|
|
26
27
|
configureTstdl();
|
|
28
|
+
configureDefaultSignalsImplementation();
|
|
27
29
|
const logger = getGlobalInjector().resolve(CORE_LOGGER);
|
|
28
30
|
const streamingApiDefinition = defineApi({
|
|
29
31
|
resource: 'streams', // /api/:version/users
|
|
@@ -82,22 +84,21 @@ async function clientTest() {
|
|
|
82
84
|
}
|
|
83
85
|
await Application.shutdown();
|
|
84
86
|
}
|
|
85
|
-
function
|
|
87
|
+
function bootstrap() {
|
|
86
88
|
configureNodeHttpServer();
|
|
87
89
|
configureApiServer({ controllers: [StreamingApi] });
|
|
88
90
|
configureUndiciHttpClientAdapter({ dispatcher: new Agent({ keepAliveMaxTimeout: 1 }) });
|
|
89
91
|
configureHttpClient({ baseUrl: 'http://localhost:8000' });
|
|
90
|
-
Application.run(WebServerModule, clientTest);
|
|
91
92
|
}
|
|
92
|
-
|
|
93
|
+
Application.run({ bootstrap }, WebServerModule, clientTest);
|
|
93
94
|
function eventsSource() {
|
|
94
95
|
const events = new ServerSentEventsSource();
|
|
95
96
|
void (async () => {
|
|
96
97
|
for (let i = 1; i <= 10; i++) {
|
|
97
|
-
if (events.closed || isDefined(events.error)) {
|
|
98
|
+
if (events.closed() || isDefined(events.error())) {
|
|
98
99
|
return;
|
|
99
100
|
}
|
|
100
|
-
await events.sendJson({ name: 'time', id: i.toString(), data: { dateTime:
|
|
101
|
+
await events.sendJson({ name: 'time', id: i.toString(), data: { dateTime: new Date().toLocaleString(), uptime: performance.now() }, retry: 1000 });
|
|
101
102
|
await timeout(1000);
|
|
102
103
|
}
|
|
103
104
|
await events.close();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tstdl/base",
|
|
3
|
-
"version": "0.90.
|
|
3
|
+
"version": "0.90.83",
|
|
4
4
|
"author": "Patrick Hein",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
"luxon": "^3.4",
|
|
112
112
|
"reflect-metadata": "^0.2",
|
|
113
113
|
"rxjs": "^7.8",
|
|
114
|
-
"type-fest": "4.
|
|
114
|
+
"type-fest": "4.20"
|
|
115
115
|
},
|
|
116
116
|
"devDependencies": {
|
|
117
117
|
"@mxssfd/typedoc-theme": "1.1",
|
|
@@ -123,6 +123,7 @@
|
|
|
123
123
|
"@types/mjml": "4.7",
|
|
124
124
|
"@types/node": "20",
|
|
125
125
|
"@types/nodemailer": "6.4",
|
|
126
|
+
"@typescript-eslint/eslint-plugin": "7.12",
|
|
126
127
|
"concurrently": "8.2",
|
|
127
128
|
"eslint": "8.57",
|
|
128
129
|
"eslint-import-resolver-typescript": "3.6",
|
|
@@ -130,8 +131,7 @@
|
|
|
130
131
|
"tsc-alias": "1.8",
|
|
131
132
|
"typedoc": "0.25",
|
|
132
133
|
"typedoc-plugin-missing-exports": "2.2",
|
|
133
|
-
"typescript": "5.4"
|
|
134
|
-
"typescript-eslint": "7.11"
|
|
134
|
+
"typescript": "5.4"
|
|
135
135
|
},
|
|
136
136
|
"peerDependencies": {
|
|
137
137
|
"@elastic/elasticsearch": "^8.13",
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import type { ServerSentJsonEvent, ServerSentTextEvent } from './model.js';
|
|
2
2
|
export declare class ServerSentEventsSource {
|
|
3
|
-
private
|
|
4
|
-
private readonly writer;
|
|
5
|
-
private _closed;
|
|
6
|
-
private _error;
|
|
3
|
+
#private;
|
|
7
4
|
readonly readable: ReadableStream<string>;
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
readonly closed: import("../signals/api.js").Signal<boolean>;
|
|
6
|
+
readonly error: import("../signals/api.js").Signal<Error | undefined>;
|
|
10
7
|
constructor();
|
|
11
8
|
close(): Promise<void>;
|
|
12
9
|
sendComment(comment: string): Promise<void>;
|
|
@@ -1,33 +1,28 @@
|
|
|
1
|
+
import { signal } from '../signals/api.js';
|
|
1
2
|
import { isDefined } from '../utils/type-guards.js';
|
|
2
3
|
export class ServerSentEventsSource {
|
|
3
|
-
writable;
|
|
4
|
-
writer;
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
#writable;
|
|
5
|
+
#writer;
|
|
6
|
+
#closed = signal(false);
|
|
7
|
+
#error = signal(undefined);
|
|
7
8
|
readable;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
get error() {
|
|
12
|
-
return this._error;
|
|
13
|
-
}
|
|
9
|
+
closed = this.#closed.asReadonly();
|
|
10
|
+
error = this.#error.asReadonly();
|
|
14
11
|
constructor() {
|
|
15
12
|
const { writable, readable } = new TransformStream();
|
|
16
|
-
this
|
|
13
|
+
this.#writable = writable;
|
|
17
14
|
this.readable = readable;
|
|
18
|
-
this
|
|
19
|
-
this.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
.then(() => (this._closed = true))
|
|
23
|
-
.catch((error) => (this._error = error));
|
|
15
|
+
this.#writer = this.#writable.getWriter();
|
|
16
|
+
this.#writer.closed
|
|
17
|
+
.then(() => (this.#closed.set(true)))
|
|
18
|
+
.catch((error) => this.#error.set(error));
|
|
24
19
|
}
|
|
25
20
|
async close() {
|
|
26
|
-
await this
|
|
21
|
+
await this.#writer.close();
|
|
27
22
|
}
|
|
28
23
|
async sendComment(comment) {
|
|
29
24
|
const text = formatText(comment, '');
|
|
30
|
-
await this
|
|
25
|
+
await this.#writer.write(text);
|
|
31
26
|
}
|
|
32
27
|
async sendText({ name, data, id, retry }) {
|
|
33
28
|
let message = '';
|
|
@@ -44,7 +39,7 @@ export class ServerSentEventsSource {
|
|
|
44
39
|
message += formatText(retry.toString(), 'retry');
|
|
45
40
|
}
|
|
46
41
|
message += '\n';
|
|
47
|
-
await this
|
|
42
|
+
await this.#writer.write(message);
|
|
48
43
|
}
|
|
49
44
|
async sendJson({ name, data, id, retry }) {
|
|
50
45
|
return this.sendText({
|