libmodulor 0.22.0 → 0.23.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.
Files changed (28) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +1 -1
  3. package/dist/esm/apps/Helper/src/lib/project.js +3 -3
  4. package/dist/esm/index.react.d.ts +1 -1
  5. package/dist/esm/index.react.js +1 -1
  6. package/dist/esm/std/JWTManager.d.ts +16 -1
  7. package/dist/esm/std/impl/JoseJWTManager.d.ts +3 -2
  8. package/dist/esm/std/impl/JoseJWTManager.js +4 -0
  9. package/dist/esm/std/impl/SimpleHTTPAPICaller.js +4 -2
  10. package/dist/esm/target/lib/client/consts.js +1 -0
  11. package/dist/esm/target/lib/react/UCPanel.d.ts +7 -8
  12. package/dist/esm/target/lib/react/useUC.js +11 -1
  13. package/dist/esm/target/lib/server/ServerManager.d.ts +1 -0
  14. package/dist/esm/target/lib/server/consts.js +1 -0
  15. package/dist/esm/target/lib/server-express/funcs.js +3 -2
  16. package/dist/esm/target/lib/server-node/funcs.d.ts +2 -2
  17. package/dist/esm/target/lib/server-node/funcs.js +11 -1
  18. package/dist/esm/target/lib/server-node/types.d.ts +1 -0
  19. package/dist/esm/target/node-express-server/NodeExpressServerManager.d.ts +2 -2
  20. package/dist/esm/target/node-express-server/NodeExpressServerManager.js +2 -1
  21. package/dist/esm/target/node-hono-server/NodeHonoServerManager.d.ts +2 -2
  22. package/dist/esm/target/node-hono-server/NodeHonoServerManager.js +2 -1
  23. package/dist/esm/testing/impl/newNodeAppTester.js +3 -2
  24. package/dist/esm/utils/http/NDJSONStreamManager.d.ts +2 -1
  25. package/dist/esm/utils/http/NDJSONStreamManager.js +4 -1
  26. package/dist/esm/utils/http/SSEStreamManager.d.ts +2 -1
  27. package/dist/esm/utils/http/SSEStreamManager.js +4 -1
  28. package/package.json +6 -6
package/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v0.23.0 (2025-11-11)
4
+
5
+ See all the changes here : https://github.com/c100k/libmodulor/compare/v0.22.0...master
6
+
3
7
  ## v0.22.0 (2025-10-25)
4
8
 
5
9
  **Added**
package/README.md CHANGED
@@ -17,4 +17,4 @@ If you think you can help in any way, feel free to contact me (cf. `author` in `
17
17
 
18
18
  ## ⚖️ License
19
19
 
20
- [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.22.0/LICENSE)
20
+ [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.23.0/LICENSE)
@@ -81,13 +81,13 @@ export const PACKAGE_JSON = (name) => `{
81
81
  "test": "tsc && vitest run --passWithNoTests"
82
82
  },
83
83
  "dependencies": {
84
- "inversify": "^7.10.3",
84
+ "inversify": "^7.10.4",
85
85
  "libmodulor": "latest",
86
86
  "reflect-metadata": "^0.2.2"
87
87
  },
88
88
  "devDependencies": {
89
- "@biomejs/biome": "^2.2.7",
90
- "@types/node": "^24.9.1",
89
+ "@biomejs/biome": "^2.3.4",
90
+ "@types/node": "^24.10.0",
91
91
  "@vitest/coverage-v8": "^3.2.4",
92
92
  "buffer": "^6.0.3",
93
93
  "cookie-parser": "^1.4.7",
@@ -6,7 +6,7 @@ export type { RenderUCEntrypointTouchable, RenderUCExecTouchable, UCEntrypointTo
6
6
  export { UCContainer } from './target/lib/react/UCContainer.js';
7
7
  export { UCEntrypoint } from './target/lib/react/UCEntrypoint.js';
8
8
  export { type Props as UCOutputFieldValueFragmentProps, UCOutputFieldValueFragment, } from './target/lib/react/UCOutputFieldValueFragment.js';
9
- export { UCPanel } from './target/lib/react/UCPanel.js';
9
+ export { type Props as UCPanelProps, UCPanel, } from './target/lib/react/UCPanel.js';
10
10
  export { type UseActionOpts, useAction, } from './target/lib/react/useAction.js';
11
11
  export { type CloneFunc, type DivertFunc, type RefillFunc, useUC, } from './target/lib/react/useUC.js';
12
12
  export { type AppendFunc, type RemoveFunc, type UpdateFunc, useUCOR, } from './target/lib/react/useUCOR.js';
@@ -3,7 +3,7 @@ export { StyleContext, StyleContextProvider, styleDef, useStyleContext, } from '
3
3
  export { UCContainer } from './target/lib/react/UCContainer.js';
4
4
  export { UCEntrypoint } from './target/lib/react/UCEntrypoint.js';
5
5
  export { UCOutputFieldValueFragment, } from './target/lib/react/UCOutputFieldValueFragment.js';
6
- export { UCPanel } from './target/lib/react/UCPanel.js';
6
+ export { UCPanel, } from './target/lib/react/UCPanel.js';
7
7
  export { useAction, } from './target/lib/react/useAction.js';
8
8
  export { useUC, } from './target/lib/react/useUC.js';
9
9
  export { useUCOR, } from './target/lib/react/useUCOR.js';
@@ -41,6 +41,19 @@ export interface JWTManager {
41
41
  * @param opts
42
42
  */
43
43
  decode<T extends JWTManagerPayload>(value: JWT, opts?: JWTManagerDecodeOpts): Promise<T>;
44
+ /**
45
+ * Decode the token without checking the signature
46
+ *
47
+ * IMPORTANT : IT DOES NOT CHECK THE SIGNATURE
48
+ *
49
+ * The main purpose of this method is to be used client side to decode the JWT in order to update some state including :
50
+ * - displaying the firstname in the UI
51
+ * - set the payload in some state
52
+ * - etc.
53
+ *
54
+ * @param value
55
+ */
56
+ decodeUnsafe<T extends JWTManagerPayload>(value: JWT): Promise<T>;
44
57
  /**
45
58
  * Encode the payload
46
59
  *
@@ -53,7 +66,9 @@ export interface JWTManager {
53
66
  /**
54
67
  * Check whether the token is usable or not
55
68
  *
56
- * Note that the signature is not checked. Indeed, the main purpose of this method is to be used client side to save some requests (e.g. when the token is expired).
69
+ * IMPORTANT : IT DOES NOT CHECK THE SIGNATURE
70
+ *
71
+ * The main purpose of this method is to be used client side to save some requests (e.g. when the token is expired).
57
72
  * In this case, no need to send a request that will trigger an error. Better to renew the token at the client's initiative.
58
73
  */
59
74
  isUsable(value: JWT): Promise<boolean>;
@@ -1,6 +1,6 @@
1
1
  import type { JWT } from '../../dt/index.js';
2
2
  import type { ClockManager } from '../ClockManager.js';
3
- import type { JWTManager, JWTManagerDecodeOpts, JWTManagerEncodeOpts, JWTManagerSettings } from '../JWTManager.js';
3
+ import type { JWTManager, JWTManagerDecodeOpts, JWTManagerEncodeOpts, JWTManagerPayload, JWTManagerSettings } from '../JWTManager.js';
4
4
  import type { SettingsManager } from '../SettingsManager.js';
5
5
  export type S = Omit<JWTManagerSettings, 'jwt_manager_invalidate_issued_before'>;
6
6
  export declare class JoseJWTManager implements JWTManager {
@@ -8,7 +8,8 @@ export declare class JoseJWTManager implements JWTManager {
8
8
  private settingsManager;
9
9
  constructor(clockManager: ClockManager, settingsManager: SettingsManager<S>);
10
10
  s(): S;
11
- decode<T extends object>(value: JWT, opts?: JWTManagerDecodeOpts): Promise<T>;
11
+ decode<T extends JWTManagerPayload>(value: JWT, opts?: JWTManagerDecodeOpts): Promise<T>;
12
+ decodeUnsafe<T extends JWTManagerPayload>(value: JWT): Promise<T>;
12
13
  encode<T extends object>(payload: T, opts?: JWTManagerEncodeOpts): Promise<JWT>;
13
14
  isUsable(value: JWT): Promise<boolean>;
14
15
  }
@@ -54,6 +54,10 @@ let JoseJWTManager = class JoseJWTManager {
54
54
  }
55
55
  throw new Error(`Unsupported alg ${alg}`);
56
56
  }
57
+ async decodeUnsafe(value) {
58
+ const decoded = decodeJwt(value);
59
+ return decoded;
60
+ }
57
61
  async encode(payload, opts) {
58
62
  const alg = opts?.alg ?? this.s().jwt_manager_algorithm;
59
63
  const aud = opts?.aud ?? this.s().jwt_manager_audience;
@@ -90,7 +90,7 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
90
90
  });
91
91
  const { ok, redirected } = response;
92
92
  if (ok || redirected) {
93
- return this.processResGood({ opts, outputBuilder, stream }, isFormURLEncoded, isJSON, isNDJSON, isSSE, isXML, response);
93
+ return this.processResGood({ opts, outputBuilder, stream }, abortController, isFormURLEncoded, isJSON, isNDJSON, isSSE, isXML, response);
94
94
  }
95
95
  const message = await this.processResBad({ errBuilder, opts }, isJSON, isXML, response);
96
96
  this.throwError(message ?? unknownErrorMessage, status);
@@ -173,13 +173,14 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
173
173
  return JSON.stringify(error);
174
174
  }
175
175
  }
176
- async processResGood({ opts, outputBuilder, stream, }, isFormURLEncoded, isJSON, isNDJSON, isSSE, isXML, response) {
176
+ async processResGood({ opts, outputBuilder, stream, }, abortController, isFormURLEncoded, isJSON, isNDJSON, isSSE, isXML, response) {
177
177
  let payload;
178
178
  if (isNDJSON && stream) {
179
179
  if (!response.body) {
180
180
  throw new Error(ERR_STREAM_UNAVAILABLE);
181
181
  }
182
182
  await this.ndJSONStreamManager.exec({
183
+ abortController,
183
184
  onData: async (data) => {
184
185
  if (outputBuilder) {
185
186
  stream.onData(await outputBuilder(data));
@@ -196,6 +197,7 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
196
197
  throw new Error(ERR_STREAM_UNAVAILABLE);
197
198
  }
198
199
  await this.sseStreamManager.exec({
200
+ abortController,
199
201
  onData: async (data) => {
200
202
  if (outputBuilder) {
201
203
  stream.onData(await outputBuilder(data));
@@ -2,6 +2,7 @@
2
2
  * @see TARGET_DEFAULT_SERVER_MANAGER_SETTINGS
3
3
  */
4
4
  export const TARGET_DEFAULT_SERVER_CLIENT_MANAGER_SETTINGS = {
5
+ server_cookies_name_auth: 'auth',
5
6
  server_public_api_key: 'PublicApiKeyToBeChangedWhenDeploying',
6
7
  server_public_api_key_header_name: 'X-API-Key',
7
8
  server_public_url: 'http://localhost:7443',
@@ -6,17 +6,16 @@ import type { RenderUCForm } from './form.js';
6
6
  import type { RenderUCAutoExecLoader } from './loader.js';
7
7
  import type { UCPanelCtx, UCPanelOnDone, UCPanelOnError, UCPanelOnInit, UCPanelOnStartSubmitting } from './panel.js';
8
8
  import type { RenderUCExecTouchable } from './touchable.js';
9
- type Props<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = Pick<UCPanelCtx<I, OPI0, OPI1>, 'clearAfterExec' | 'uc'> & {
10
- autoExec?: boolean;
11
- onDone?: UCPanelOnDone<I, OPI0, OPI1>;
12
- onInit?: UCPanelOnInit<I, OPI0, OPI1>;
13
- onError?: UCPanelOnError;
14
- onStartSubmitting?: UCPanelOnStartSubmitting;
9
+ export type Props<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = Pick<UCPanelCtx<I, OPI0, OPI1>, 'clearAfterExec' | 'uc'> & {
10
+ autoExec?: boolean | undefined;
11
+ onDone?: UCPanelOnDone<I, OPI0, OPI1> | undefined;
12
+ onInit?: UCPanelOnInit<I, OPI0, OPI1> | undefined;
13
+ onError?: UCPanelOnError | undefined;
14
+ onStartSubmitting?: UCPanelOnStartSubmitting | undefined;
15
15
  renderAutoExecLoader: RenderUCAutoExecLoader;
16
16
  renderExecTouchable: RenderUCExecTouchable<I, OPI0, OPI1>;
17
17
  renderForm: RenderUCForm<I, OPI0, OPI1>;
18
- sleepInMs?: UIntDuration;
18
+ sleepInMs?: UIntDuration | undefined;
19
19
  stream?: StreamConfig<UCOutputReader<I, OPI0, OPI1>> | undefined;
20
20
  };
21
21
  export declare function UCPanel<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ autoExec, clearAfterExec, onDone, onError, onInit, onStartSubmitting, renderAutoExecLoader, renderForm, renderExecTouchable, sleepInMs, stream, uc, }: Props<I, OPI0, OPI1>): ReactElement;
22
- export {};
@@ -1,4 +1,4 @@
1
- import { useState } from 'react';
1
+ import { useEffect, useState } from 'react';
2
2
  import { UC, } from '../../../uc/index.js';
3
3
  /**
4
4
  * This hook provides utilities to init a use case and perform actions on it in a React way
@@ -21,6 +21,16 @@ export function useUC(appManifest, def, auth, opts) {
21
21
  }
22
22
  return v;
23
23
  });
24
+ // biome-ignore lint/correctness/useExhaustiveDependencies(appManifest): avoid infinite re-rendering
25
+ // biome-ignore lint/correctness/useExhaustiveDependencies(def): avoid infinite re-rendering
26
+ // biome-ignore lint/correctness/useExhaustiveDependencies(opts?.fillWith): avoid infinite re-rendering
27
+ useEffect(() => {
28
+ const v = new UC(appManifest, def, auth);
29
+ if (opts?.fillWith) {
30
+ v.fill(opts?.fillWith);
31
+ }
32
+ setUC(v);
33
+ }, [auth]);
24
34
  /**
25
35
  * Get a new `UC` based on the initial one
26
36
  * @param i
@@ -27,6 +27,7 @@ export interface ServerManagerSettings extends ServerManagerAuthSettings, Settin
27
27
  server_ssl_fullchain_path: FilePath | null;
28
28
  server_ssl_key_path: FilePath | null;
29
29
  server_static_dir_path: DirPath | null;
30
+ server_stop_mode: 'aggressive' | 'patient';
30
31
  server_tmp_path: FilePath;
31
32
  }
32
33
  export interface ServerManager extends Initializable {
@@ -19,5 +19,6 @@ export const TARGET_DEFAULT_SERVER_MANAGER_SETTINGS = {
19
19
  server_ssl_fullchain_path: null,
20
20
  server_ssl_key_path: null,
21
21
  server_static_dir_path: null,
22
+ server_stop_mode: 'patient',
22
23
  server_tmp_path: 'tmp',
23
24
  };
@@ -14,7 +14,9 @@ export function buildHandler(appManifest, ucd, contract, serverRequestHandler, u
14
14
  case 'stream': {
15
15
  execOpts = {
16
16
  stream: {
17
- onClose: async () => { },
17
+ onClose: async () => {
18
+ throw new Error('execOpts.stream.onClose needs to be set in the UC ServerMain');
19
+ },
18
20
  onData: async (output) => {
19
21
  if (!output) {
20
22
  return;
@@ -31,7 +33,6 @@ export function buildHandler(appManifest, ucd, contract, serverRequestHandler, u
31
33
  }
32
34
  res.flushHeaders();
33
35
  res.on('close', async () => {
34
- res.end();
35
36
  await execOpts?.stream?.onClose();
36
37
  });
37
38
  break;
@@ -1,5 +1,5 @@
1
1
  import type { Logger, SettingsManager } from '../../../std/index.js';
2
2
  import type { EntrypointsBuilder } from '../server/EntrypointsBuilder.js';
3
- import type { ListenSettings, Server } from './types.js';
3
+ import type { ListenSettings, Server, StopSettings } from './types.js';
4
4
  export declare function listen(server: Server, entrypointsBuilder: EntrypointsBuilder, logger: Logger, settingsManager: SettingsManager<ListenSettings>): void;
5
- export declare function stop(server: Server): Promise<void>;
5
+ export declare function stop(server: Server, settingsManager: SettingsManager<StopSettings>): Promise<void>;
@@ -5,16 +5,26 @@ export function listen(server, entrypointsBuilder, logger, settingsManager) {
5
5
  logger.info(`Listening on ${entrypointsBuilder.exec().http}`);
6
6
  });
7
7
  }
8
- export async function stop(server) {
8
+ export async function stop(server, settingsManager) {
9
9
  if (!server?.listening) {
10
10
  return;
11
11
  }
12
+ const mode = settingsManager.get()('server_stop_mode');
12
13
  // As stated in the docs of `close`, only awaiting `.close` is not enough to make sure all the connections are closed.
13
14
  // Hence the wrapping in a promise, where the callback is called when the 'close' event is emitted.
14
15
  return new Promise((resolve, reject) => {
15
16
  if (!server) {
16
17
  return resolve();
17
18
  }
19
+ switch (mode) {
20
+ case 'aggressive':
21
+ server.closeAllConnections();
22
+ break;
23
+ case 'patient':
24
+ break;
25
+ default:
26
+ ((_) => { })(mode);
27
+ }
18
28
  server.close((err) => {
19
29
  if (err) {
20
30
  return reject(err);
@@ -3,3 +3,4 @@ import type https from 'node:https';
3
3
  import type { ServerManagerSettings } from '../server/ServerManager.js';
4
4
  export type Server = http.Server | https.Server;
5
5
  export type ListenSettings = Pick<ServerManagerSettings, 'server_binding_host' | 'server_binding_port'>;
6
+ export type StopSettings = Pick<ServerManagerSettings, 'server_stop_mode'>;
@@ -8,8 +8,8 @@ import type { ServerManager, ServerManagerSettings } from '../lib/server/ServerM
8
8
  import { ServerRequestHandler } from '../lib/server/ServerRequestHandler.js';
9
9
  import { ServerSSLCertLoader } from '../lib/server/ServerSSLCertLoader.js';
10
10
  import { HelmetMiddlewareBuilder } from '../lib/server-express/HelmetMiddlewareBuilder.js';
11
- import type { ListenSettings } from '../lib/server-node/types.js';
12
- type S = ListenSettings & Pick<LoggerSettings, 'logger_level'> & Pick<ServerManagerSettings, 'server_tmp_path'>;
11
+ import type { ListenSettings, StopSettings } from '../lib/server-node/types.js';
12
+ type S = ListenSettings & Pick<LoggerSettings, 'logger_level'> & Pick<ServerManagerSettings, 'server_tmp_path'> & StopSettings;
13
13
  export declare class NodeExpressServerManager implements Configurable<S>, ServerManager {
14
14
  private entrypointsBuilder;
15
15
  protected environmentManager: EnvironmentManager;
@@ -47,6 +47,7 @@ let NodeExpressServerManager = class NodeExpressServerManager {
47
47
  logger_level: this.settingsManager.get()('logger_level'),
48
48
  server_binding_host: this.settingsManager.get()('server_binding_host'),
49
49
  server_binding_port: this.settingsManager.get()('server_binding_port'),
50
+ server_stop_mode: this.settingsManager.get()('server_stop_mode'),
50
51
  server_tmp_path: this.settingsManager.get()('server_tmp_path'),
51
52
  };
52
53
  }
@@ -79,7 +80,7 @@ let NodeExpressServerManager = class NodeExpressServerManager {
79
80
  listen(this.server, this.entrypointsBuilder, this.logger, this.settingsManager);
80
81
  }
81
82
  async stop() {
82
- await stop(this.server);
83
+ await stop(this.server, this.settingsManager);
83
84
  }
84
85
  async warmUp() {
85
86
  // Nothing to do
@@ -7,8 +7,8 @@ import { EntrypointsBuilder } from '../lib/server/EntrypointsBuilder.js';
7
7
  import type { ServerManager } from '../lib/server/ServerManager.js';
8
8
  import { ServerRequestHandler } from '../lib/server/ServerRequestHandler.js';
9
9
  import { ServerSSLCertLoader } from '../lib/server/ServerSSLCertLoader.js';
10
- import type { ListenSettings } from '../lib/server-node/types.js';
11
- type S = ListenSettings;
10
+ import type { ListenSettings, StopSettings } from '../lib/server-node/types.js';
11
+ type S = ListenSettings & StopSettings;
12
12
  export declare class NodeHonoServerManager implements Configurable<S>, ServerManager {
13
13
  private entrypointsBuilder;
14
14
  protected environmentManager: EnvironmentManager;
@@ -44,6 +44,7 @@ let NodeHonoServerManager = class NodeHonoServerManager {
44
44
  return {
45
45
  server_binding_host: this.settingsManager.get()('server_binding_host'),
46
46
  server_binding_port: this.settingsManager.get()('server_binding_port'),
47
+ server_stop_mode: this.settingsManager.get()('server_stop_mode'),
47
48
  };
48
49
  }
49
50
  getRuntime() {
@@ -75,7 +76,7 @@ let NodeHonoServerManager = class NodeHonoServerManager {
75
76
  listen(this.server, this.entrypointsBuilder, this.logger, this.settingsManager);
76
77
  }
77
78
  async stop() {
78
- await stop(this.server);
79
+ await stop(this.server, this.settingsManager);
79
80
  }
80
81
  async warmUp() {
81
82
  // Nothing to do
@@ -18,8 +18,8 @@ export async function newNodeAppTester(serverPortRangeStart, idx, args) {
18
18
  const settings = {
19
19
  ...STD_DEFAULT_JWT_MANAGER_SETTINGS,
20
20
  ...TARGET_DEFAULT_SERVER_MANAGER_SETTINGS,
21
- jwt_manager_audience: 'fik',
22
- jwt_manager_issuer: 'fik',
21
+ jwt_manager_audience: 'libmodulor-test',
22
+ jwt_manager_issuer: 'libmodulor-test',
23
23
  jwt_manager_secret: new TPassword().example(),
24
24
  logger_level,
25
25
  server_basic_auth_entries: {
@@ -28,6 +28,7 @@ export async function newNodeAppTester(serverPortRangeStart, idx, args) {
28
28
  server_binding_port: serverPortRangeStart + idx,
29
29
  server_private_api_key_entries: [new TApiKey().example()],
30
30
  server_public_api_key_entries: [new TApiKey().example()],
31
+ server_stop_mode: 'aggressive',
31
32
  };
32
33
  const container = new Container(CONTAINER_OPTS);
33
34
  bindCommon(container, () => settings);
@@ -1,12 +1,13 @@
1
1
  import type { HTTPAPICallExecutorResBody, Worker } from '../../std/index.js';
2
2
  type Encoding = 'utf-8';
3
3
  interface I<D extends object = object> {
4
+ abortController: AbortController;
4
5
  encoding?: Encoding | undefined;
5
6
  onData: (data: D) => Promise<void>;
6
7
  reader: ReturnType<HTTPAPICallExecutorResBody['getReader']>;
7
8
  }
8
9
  export declare class NDJSONStreamManager implements Worker<I, Promise<void>> {
9
10
  private static DEFAULT_ENCODING;
10
- exec({ encoding, onData, reader, }: I): Promise<void>;
11
+ exec({ abortController, encoding, onData, reader, }: I): Promise<void>;
11
12
  }
12
13
  export {};
@@ -10,10 +10,13 @@ import { NDJSON_DATA_SEP } from './nd-json.js';
10
10
  let NDJSONStreamManager = class NDJSONStreamManager {
11
11
  static { NDJSONStreamManager_1 = this; }
12
12
  static DEFAULT_ENCODING = 'utf-8';
13
- async exec({ encoding = NDJSONStreamManager_1.DEFAULT_ENCODING, onData, reader, }) {
13
+ async exec({ abortController, encoding = NDJSONStreamManager_1.DEFAULT_ENCODING, onData, reader, }) {
14
14
  const decoder = new TextDecoder(encoding);
15
15
  let buffer = '';
16
16
  while (true) {
17
+ if (abortController.signal.aborted) {
18
+ return;
19
+ }
17
20
  const { done, value } = await reader.read();
18
21
  if (done) {
19
22
  return;
@@ -1,12 +1,13 @@
1
1
  import type { HTTPAPICallExecutorResBody, Worker } from '../../std/index.js';
2
2
  type Encoding = 'utf-8';
3
3
  interface I<D extends object = object> {
4
+ abortController: AbortController;
4
5
  encoding?: Encoding | undefined;
5
6
  onData: (data: D) => Promise<void>;
6
7
  reader: ReturnType<HTTPAPICallExecutorResBody['getReader']>;
7
8
  }
8
9
  export declare class SSEStreamManager implements Worker<I, Promise<void>> {
9
10
  private static DEFAULT_ENCODING;
10
- exec({ encoding, onData, reader, }: I): Promise<void>;
11
+ exec({ abortController, encoding, onData, reader, }: I): Promise<void>;
11
12
  }
12
13
  export {};
@@ -11,10 +11,13 @@ import { isSSEError, parseDataLine, SSE_DATA_SEP, SSE_MSG_SEP } from './sse.js';
11
11
  let SSEStreamManager = class SSEStreamManager {
12
12
  static { SSEStreamManager_1 = this; }
13
13
  static DEFAULT_ENCODING = 'utf-8';
14
- async exec({ encoding = SSEStreamManager_1.DEFAULT_ENCODING, onData, reader, }) {
14
+ async exec({ abortController, encoding = SSEStreamManager_1.DEFAULT_ENCODING, onData, reader, }) {
15
15
  const decoder = new TextDecoder(encoding);
16
16
  let buffer = '';
17
17
  while (true) {
18
+ if (abortController.signal.aborted) {
19
+ return;
20
+ }
18
21
  const { done, value } = await reader.read();
19
22
  if (done) {
20
23
  return;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "libmodulor",
3
3
  "description": "A TypeScript library to create platform-agnostic applications",
4
- "version": "0.22.0",
4
+ "version": "0.23.0",
5
5
  "license": "LGPL-3.0",
6
6
  "author": "Chafik H'nini <chafik.hnini@gmail.com>",
7
7
  "homepage": "https://libmodulor.c100k.eu",
@@ -81,11 +81,11 @@
81
81
  "lint:ci": "biome check"
82
82
  },
83
83
  "devDependencies": {
84
- "@biomejs/biome": "^2.2.7"
84
+ "@biomejs/biome": "^2.3.4"
85
85
  },
86
86
  "peerDependencies": {
87
- "@hono/node-server": "^1.19.5",
88
- "@modelcontextprotocol/sdk": "^1.20.1",
87
+ "@hono/node-server": "^1.19.6",
88
+ "@modelcontextprotocol/sdk": "^1.21.0",
89
89
  "@stricli/core": "^1.2.4",
90
90
  "buffer": "^6.0.3",
91
91
  "cookie-parser": "^1.4.7",
@@ -93,8 +93,8 @@
93
93
  "express-fileupload": "^1.5.2",
94
94
  "fast-check": "^4.3.0",
95
95
  "helmet": "^8.1.0",
96
- "hono": "^4.10.2",
97
- "inversify": "^7.10.3",
96
+ "hono": "^4.10.4",
97
+ "inversify": "^7.10.4",
98
98
  "jose": "^6.1.0",
99
99
  "knex": "^3.1.0",
100
100
  "next": "^15.5.6",