libmodulor 0.20.0 → 0.22.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 (110) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +1 -1
  3. package/dist/esm/apps/Helper/src/lib/project.js +7 -7
  4. package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.d.ts +1 -0
  5. package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.js +20 -13
  6. package/dist/esm/dt/DataType.d.ts +2 -1
  7. package/dist/esm/dt/DataTypes.js +1 -0
  8. package/dist/esm/dt/Validation.js +1 -1
  9. package/dist/esm/dt/final/TGitSSHURL.d.ts +4 -3
  10. package/dist/esm/dt/final/TGitSSHURL.js +1 -1
  11. package/dist/esm/dt/final/TSSHPrivateKey.js +1 -3
  12. package/dist/esm/dt/final/TTransportType.d.ts +8 -0
  13. package/dist/esm/dt/final/TTransportType.js +16 -0
  14. package/dist/esm/dt/index.d.ts +1 -0
  15. package/dist/esm/dt/index.js +1 -0
  16. package/dist/esm/error/funcs.d.ts +2 -0
  17. package/dist/esm/error/funcs.js +19 -0
  18. package/dist/esm/error/index.d.ts +1 -0
  19. package/dist/esm/error/index.js +1 -0
  20. package/dist/esm/index.d.ts +2 -0
  21. package/dist/esm/index.js +2 -0
  22. package/dist/esm/std/HTTPAPICallExecutor.d.ts +16 -7
  23. package/dist/esm/std/HTTPAPICaller.d.ts +8 -1
  24. package/dist/esm/std/LLMManager.d.ts +20 -3
  25. package/dist/esm/std/impl/ConsoleLogger.js +2 -2
  26. package/dist/esm/std/impl/FakeClockManager.d.ts +6 -0
  27. package/dist/esm/std/impl/FakeClockManager.js +19 -0
  28. package/dist/esm/std/impl/FakeHTTPAPICallExecutor.js +19 -18
  29. package/dist/esm/std/impl/FakeLLMManager.d.ts +4 -0
  30. package/dist/esm/std/impl/FakeLLMManager.js +40 -0
  31. package/dist/esm/std/impl/FetchHTTPAPICallExecutor.js +1 -1
  32. package/dist/esm/std/impl/MistralAILLMManager.js +12 -0
  33. package/dist/esm/std/impl/NodeFormDataBuilder.js +3 -1
  34. package/dist/esm/std/impl/OllamaLLMManager.d.ts +7 -2
  35. package/dist/esm/std/impl/OllamaLLMManager.js +32 -5
  36. package/dist/esm/std/impl/OpenAILLMManager.js +9 -0
  37. package/dist/esm/std/impl/SimpleHTTPAPICaller.d.ts +7 -3
  38. package/dist/esm/std/impl/SimpleHTTPAPICaller.js +67 -16
  39. package/dist/esm/target/lib/cli/CommandExecutor.js +11 -3
  40. package/dist/esm/target/lib/react/UCPanel.d.ts +4 -2
  41. package/dist/esm/target/lib/react/UCPanel.js +2 -6
  42. package/dist/esm/target/lib/react/form.d.ts +5 -6
  43. package/dist/esm/target/lib/react/form.js +7 -10
  44. package/dist/esm/target/lib/react/useUC.d.ts +4 -4
  45. package/dist/esm/target/lib/server/ServerRequestHandler.d.ts +3 -2
  46. package/dist/esm/target/lib/server/ServerRequestHandler.js +2 -2
  47. package/dist/esm/target/lib/server-express/funcs.js +52 -1
  48. package/dist/esm/target/lib/server-hono/funcs.js +65 -2
  49. package/dist/esm/target/node-mcp-server/NodeLocalStdioMCPServerManager.js +1 -0
  50. package/dist/esm/target/react-native-pure/UCForm.d.ts +1 -1
  51. package/dist/esm/target/react-native-pure/UCForm.js +2 -2
  52. package/dist/esm/target/react-native-pure/UCFormField.d.ts +1 -1
  53. package/dist/esm/target/react-native-pure/UCFormField.js +3 -4
  54. package/dist/esm/target/react-native-pure/UCFormFieldControl.js +13 -7
  55. package/dist/esm/target/react-web-pure/UCForm.d.ts +1 -1
  56. package/dist/esm/target/react-web-pure/UCForm.js +2 -2
  57. package/dist/esm/target/react-web-pure/UCFormField.d.ts +1 -1
  58. package/dist/esm/target/react-web-pure/UCFormField.js +3 -4
  59. package/dist/esm/target/react-web-pure/UCFormFieldControl.js +7 -4
  60. package/dist/esm/testing/AppTester.d.ts +1 -1
  61. package/dist/esm/testing/AppTester.js +3 -2
  62. package/dist/esm/testing/impl/SimpleHTMLAppTestReportEmitter.js +1 -1
  63. package/dist/esm/testing/impl/TypeScriptLibUCDefASTParser.js +2 -2
  64. package/dist/esm/testing/impl/VitestAppTestSuiteEmitter.js +6 -3
  65. package/dist/esm/testing/uc-input.js +13 -12
  66. package/dist/esm/testing/workers/UCExecutor.js +41 -3
  67. package/dist/esm/uc/UC.d.ts +7 -7
  68. package/dist/esm/uc/UC.js +4 -3
  69. package/dist/esm/uc/UCInputField.d.ts +6 -3
  70. package/dist/esm/uc/UCInputField.js +39 -29
  71. package/dist/esm/uc/ext.d.ts +7 -1
  72. package/dist/esm/uc/impl/HTTPUCTransporter.d.ts +2 -2
  73. package/dist/esm/uc/impl/HTTPUCTransporter.js +3 -1
  74. package/dist/esm/uc/impl/SimpleUCManager.d.ts +3 -3
  75. package/dist/esm/uc/impl/SimpleUCManager.js +23 -4
  76. package/dist/esm/uc/index.d.ts +0 -1
  77. package/dist/esm/uc/index.js +0 -1
  78. package/dist/esm/uc/input-field.d.ts +2 -19
  79. package/dist/esm/uc/input-field.js +0 -19
  80. package/dist/esm/uc/input.d.ts +13 -7
  81. package/dist/esm/uc/lifecycle/client/SendClientMain.d.ts +1 -1
  82. package/dist/esm/uc/lifecycle/client/SendClientMain.js +5 -2
  83. package/dist/esm/uc/main.d.ts +8 -1
  84. package/dist/esm/uc/manager.d.ts +11 -2
  85. package/dist/esm/uc/output.d.ts +1 -0
  86. package/dist/esm/uc/output.js +10 -1
  87. package/dist/esm/uc/transporter.d.ts +7 -1
  88. package/dist/esm/uc/utils/rInput.js +4 -3
  89. package/dist/esm/uc/utils/rVal.d.ts +5 -5
  90. package/dist/esm/uc/utils/rVal.js +1 -12
  91. package/dist/esm/uc/value.d.ts +1 -2
  92. package/dist/esm/uc/workers/UCInputFilesProcessor.js +3 -3
  93. package/dist/esm/utils/async/types.d.ts +2 -0
  94. package/dist/esm/utils/async/types.js +1 -0
  95. package/dist/esm/utils/http/NDJSONStreamManager.d.ts +12 -0
  96. package/dist/esm/utils/http/NDJSONStreamManager.js +42 -0
  97. package/dist/esm/utils/http/SSEStreamManager.d.ts +12 -0
  98. package/dist/esm/utils/http/SSEStreamManager.js +57 -0
  99. package/dist/esm/utils/http/nd-json.d.ts +1 -0
  100. package/dist/esm/utils/http/nd-json.js +2 -0
  101. package/dist/esm/utils/http/sse.d.ts +14 -0
  102. package/dist/esm/utils/http/sse.js +24 -0
  103. package/dist/esm/utils/http/status.d.ts +4 -0
  104. package/dist/esm/utils/http/status.js +9 -0
  105. package/dist/esm/utils/index.d.ts +6 -0
  106. package/dist/esm/utils/index.js +4 -0
  107. package/dist/esm/utils/streams/types.d.ts +17 -0
  108. package/dist/esm/utils/streams/types.js +1 -0
  109. package/package.json +15 -15
  110. package/pnpm-workspace.yaml +1 -0
@@ -36,6 +36,9 @@ let MistralAILLMManager = class MistralAILLMManager {
36
36
  if ('message' in error) {
37
37
  return error.message;
38
38
  }
39
+ if (typeof error.detail === 'string') {
40
+ return error.detail;
41
+ }
39
42
  return error.detail.map((d) => d.msg).join('\n');
40
43
  },
41
44
  method: 'POST',
@@ -43,6 +46,15 @@ let MistralAILLMManager = class MistralAILLMManager {
43
46
  builder: async () => req,
44
47
  envelope: 'json',
45
48
  },
49
+ stream: {
50
+ onData: (res) => {
51
+ opts?.stream?.onData?.(res);
52
+ // Beware : this won't work if/when we accept multiple choices in the request
53
+ if (res.choices[0]?.finish_reason) {
54
+ opts?.stream?.onDone();
55
+ }
56
+ },
57
+ },
46
58
  urlBuilder: async () => `${MistralAILLMManager_1.BASE_URL}/chat/completions`,
47
59
  });
48
60
  }
@@ -19,7 +19,9 @@ let NodeFormDataBuilder = class NodeFormDataBuilder {
19
19
  chunks.push(chunk);
20
20
  });
21
21
  rs.on('end', () => {
22
- fd.append(key, new Blob(chunks, { type: val.type }), basename(val.uri));
22
+ fd.append(key,
23
+ // @ts-expect-error
24
+ new Blob(chunks, { type: val.type }), basename(val.uri));
23
25
  resolve(null);
24
26
  });
25
27
  rs.on('error', (err) => {
@@ -1,7 +1,11 @@
1
1
  import type { URL } from '../../dt/index.js';
2
2
  import type { HTTPAPICaller } from '../HTTPAPICaller.js';
3
- import type { LLMManager, LLMManagerSendReq, LLMManagerSendRes } from '../LLMManager.js';
3
+ import type { LLMManager, LLMManagerSendOpts, LLMManagerSendReq, LLMManagerSendRes } from '../LLMManager.js';
4
4
  import type { Configurable, Settings, SettingsManager } from '../SettingsManager.js';
5
+ interface OllamaGenerateRes {
6
+ done: boolean;
7
+ response: string;
8
+ }
5
9
  /**
6
10
  * Unlike the "commercial" APIs, Ollama does not secure the API with an API key
7
11
  * @see https://github.com/ollama/ollama/issues/849
@@ -15,6 +19,7 @@ export declare class OllamaLLMManager implements Configurable<S>, LLMManager {
15
19
  private settingsManager;
16
20
  constructor(httpAPICaller: HTTPAPICaller, settingsManager: SettingsManager<S>);
17
21
  s(): OllamaLLMManagerSettings;
18
- send(req: LLMManagerSendReq): Promise<LLMManagerSendRes>;
22
+ send(req: LLMManagerSendReq, opts?: LLMManagerSendOpts): Promise<LLMManagerSendRes>;
23
+ toRes(stream: LLMManagerSendReq['stream'], res: OllamaGenerateRes): LLMManagerSendRes;
19
24
  }
20
25
  export {};
@@ -24,7 +24,7 @@ let OllamaLLMManager = class OllamaLLMManager {
24
24
  oll_base_url: this.settingsManager.get()('oll_base_url'),
25
25
  };
26
26
  }
27
- async send(req) {
27
+ async send(req, opts) {
28
28
  const firstMessage = req.messages[0];
29
29
  if (!firstMessage) {
30
30
  throw new IllegalArgumentError('Please provide at least one message');
@@ -32,20 +32,47 @@ let OllamaLLMManager = class OllamaLLMManager {
32
32
  return await this.httpAPICaller.exec({
33
33
  errBuilder: async (error) => error.error,
34
34
  method: 'POST',
35
- outputBuilder: async (res) => ({
36
- choices: [{ message: { content: res.response } }],
37
- }),
35
+ outputBuilder: async (res) => this.toRes(req.stream, res),
38
36
  req: {
39
37
  builder: async () => ({
40
38
  model: req.model,
41
39
  prompt: firstMessage.content,
42
- stream: false,
40
+ stream: req.stream ?? false,
43
41
  }),
44
42
  envelope: 'json',
45
43
  },
44
+ stream: {
45
+ onData: (res) => {
46
+ opts?.stream?.onData?.(res);
47
+ // Beware : this won't work if/when we accept multiple choices in the request
48
+ if (res.choices[0]?.finish_reason) {
49
+ opts?.stream?.onDone();
50
+ }
51
+ },
52
+ },
46
53
  urlBuilder: async () => `${this.s().oll_base_url}/api/generate`,
47
54
  });
48
55
  }
56
+ toRes(stream, res) {
57
+ if (stream) {
58
+ return {
59
+ choices: [
60
+ {
61
+ delta: { content: res.response },
62
+ finish_reason: res.done ? 'stop' : null,
63
+ },
64
+ ],
65
+ };
66
+ }
67
+ return {
68
+ choices: [
69
+ {
70
+ finish_reason: res.done ? 'stop' : null,
71
+ message: { content: res.response },
72
+ },
73
+ ],
74
+ };
75
+ }
49
76
  };
50
77
  OllamaLLMManager = __decorate([
51
78
  injectable(),
@@ -38,6 +38,15 @@ let OpenAILLMManager = class OpenAILLMManager {
38
38
  builder: async () => req,
39
39
  envelope: 'json',
40
40
  },
41
+ stream: {
42
+ onData: (res) => {
43
+ opts?.stream?.onData?.(res);
44
+ // Beware : this won't work if/when we accept multiple choices in the request
45
+ if (res.choices[0]?.finish_reason) {
46
+ opts?.stream?.onDone();
47
+ }
48
+ },
49
+ },
41
50
  urlBuilder: async () => `${OpenAILLMManager_1.BASE_URL}/chat/completions`,
42
51
  });
43
52
  }
@@ -1,19 +1,23 @@
1
- import { HTTPRequestBuilder } from '../../utils/index.js';
1
+ import { HTTPRequestBuilder, NDJSONStreamManager, SSEStreamManager } from '../../utils/index.js';
2
2
  import type { BufferManager } from '../BufferManager.js';
3
3
  import type { HTTPAPICallExecutor, HTTPAPICallExecutorAgentBuilder } from '../HTTPAPICallExecutor.js';
4
4
  import type { HTTPAPICaller, HTTPAPICallerInput } from '../HTTPAPICaller.js';
5
5
  import type { Logger } from '../Logger.js';
6
6
  import type { XMLManager } from '../XMLManager.js';
7
+ export declare const ERR_STREAM_UNAVAILABLE = "The internal HTTP impl (fetch ?) does not implement streaming (React Native ?)";
7
8
  export declare class SimpleHTTPAPICaller implements HTTPAPICaller {
8
9
  private bufferManager;
9
10
  private httpAPICallExecutor;
10
11
  private httpAPICallExecutorAgentBuilder;
11
12
  private httpRequestBuilder;
12
13
  private logger;
14
+ private ndJSONStreamManager;
15
+ private sseStreamManager;
13
16
  private xmlManager;
14
- constructor(bufferManager: BufferManager, httpAPICallExecutor: HTTPAPICallExecutor, httpAPICallExecutorAgentBuilder: HTTPAPICallExecutorAgentBuilder, httpRequestBuilder: HTTPRequestBuilder, logger: Logger, xmlManager: XMLManager);
15
- exec<AH extends object | undefined, Req extends object, ResBad, ResGood, O>({ additionalHeadersBuilder, authorizationHeader, basicAuth, contentType, errBuilder, method, opts, outputBuilder, req, urlBuilder, unknownErrorMessage, }: HTTPAPICallerInput<AH, Req, ResBad, ResGood, O>): Promise<O>;
17
+ constructor(bufferManager: BufferManager, httpAPICallExecutor: HTTPAPICallExecutor, httpAPICallExecutorAgentBuilder: HTTPAPICallExecutorAgentBuilder, httpRequestBuilder: HTTPRequestBuilder, logger: Logger, ndJSONStreamManager: NDJSONStreamManager, sseStreamManager: SSEStreamManager, xmlManager: XMLManager);
18
+ exec<AH extends object | undefined, Req extends object, ResBad, ResGood, O>({ additionalHeadersBuilder, authorizationHeader, basicAuth, contentType, errBuilder, method, opts, outputBuilder, registerAbort, req, stream, urlBuilder, unknownErrorMessage, }: HTTPAPICallerInput<AH, Req, ResBad, ResGood, O>): Promise<O>;
16
19
  private computeHeaders;
17
20
  private processResBad;
18
21
  private processResGood;
22
+ private throwError;
19
23
  }
@@ -12,23 +12,28 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  };
13
13
  import { inject, injectable } from 'inversify';
14
14
  import { CustomError, IllegalArgumentError } from '../../error/index.js';
15
- import { HTTPRequestBuilder } from '../../utils/index.js';
15
+ import { HTTPRequestBuilder, isClientError, NDJSONStreamManager, SSEStreamManager, } from '../../utils/index.js';
16
+ export const ERR_STREAM_UNAVAILABLE = 'The internal HTTP impl (fetch ?) does not implement streaming (React Native ?)';
16
17
  let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
17
18
  bufferManager;
18
19
  httpAPICallExecutor;
19
20
  httpAPICallExecutorAgentBuilder;
20
21
  httpRequestBuilder;
21
22
  logger;
23
+ ndJSONStreamManager;
24
+ sseStreamManager;
22
25
  xmlManager;
23
- constructor(bufferManager, httpAPICallExecutor, httpAPICallExecutorAgentBuilder, httpRequestBuilder, logger, xmlManager) {
26
+ constructor(bufferManager, httpAPICallExecutor, httpAPICallExecutorAgentBuilder, httpRequestBuilder, logger, ndJSONStreamManager, sseStreamManager, xmlManager) {
24
27
  this.bufferManager = bufferManager;
25
28
  this.httpAPICallExecutor = httpAPICallExecutor;
26
29
  this.httpAPICallExecutorAgentBuilder = httpAPICallExecutorAgentBuilder;
27
30
  this.httpRequestBuilder = httpRequestBuilder;
28
31
  this.logger = logger;
32
+ this.ndJSONStreamManager = ndJSONStreamManager;
33
+ this.sseStreamManager = sseStreamManager;
29
34
  this.xmlManager = xmlManager;
30
35
  }
31
- async exec({ additionalHeadersBuilder, authorizationHeader, basicAuth, contentType = 'application/json', errBuilder, method, opts, outputBuilder, req, urlBuilder, unknownErrorMessage = CustomError.ERROR_UNKNOWN, }) {
36
+ async exec({ additionalHeadersBuilder, authorizationHeader, basicAuth, contentType = 'application/json', errBuilder, method, opts, outputBuilder, registerAbort, req, stream, urlBuilder, unknownErrorMessage = CustomError.ERROR_UNKNOWN, }) {
32
37
  const baseURL = await urlBuilder();
33
38
  const data = (await req?.builder?.()) || {};
34
39
  const { body, url } = await this.httpRequestBuilder.exec({
@@ -46,11 +51,16 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
46
51
  const agent = this.httpAPICallExecutorAgentBuilder.exec({
47
52
  url: new URL(url),
48
53
  });
54
+ const abortController = new AbortController();
55
+ registerAbort?.(() => {
56
+ abortController.abort();
57
+ });
49
58
  const response = await this.httpAPICallExecutor.fn()(url, {
50
59
  agent,
51
60
  body,
52
61
  headers: reqHeaders,
53
62
  method,
63
+ signal: abortController.signal,
54
64
  });
55
65
  const { headers, status } = response;
56
66
  this.logger.trace('HTTPAPICaller', {
@@ -66,24 +76,24 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
66
76
  }
67
77
  // Using .startsWith instead of === because the value can look like this 'application/json; charset=utf-8'
68
78
  const responseContentType = headers.get('Content-Type');
69
- const isJSON = responseContentType?.startsWith('application/json');
70
79
  const isFormURLEncoded = responseContentType?.startsWith('application/x-www-form-urlencoded');
80
+ const isJSON = responseContentType?.startsWith('application/json');
81
+ const isNDJSON = responseContentType?.startsWith('application/x-ndjson');
82
+ const isSSE = responseContentType?.startsWith('text/event-stream');
71
83
  const isXML = responseContentType?.startsWith('text/xml');
72
84
  this.logger.trace('HTTPAPICaller', {
73
85
  isFormURLEncoded,
74
86
  isJSON,
87
+ isNDJSON,
88
+ isSSE,
75
89
  isXML,
76
90
  });
77
91
  const { ok, redirected } = response;
78
92
  if (ok || redirected) {
79
- return this.processResGood({ opts, outputBuilder }, isFormURLEncoded, isJSON, isXML, response);
80
- }
81
- const errMsg = await this.processResBad({ errBuilder, opts }, isJSON, isXML, response);
82
- const message = errMsg ?? unknownErrorMessage;
83
- if (status < 500) {
84
- throw new IllegalArgumentError(message);
93
+ return this.processResGood({ opts, outputBuilder, stream }, isFormURLEncoded, isJSON, isNDJSON, isSSE, isXML, response);
85
94
  }
86
- throw new Error(message);
95
+ const message = await this.processResBad({ errBuilder, opts }, isJSON, isXML, response);
96
+ this.throwError(message ?? unknownErrorMessage, status);
87
97
  }
88
98
  async computeHeaders({ additionalHeadersBuilder, authorizationHeader, basicAuth, contentType = 'application/json', req, }) {
89
99
  const headers = {};
@@ -163,9 +173,41 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
163
173
  return JSON.stringify(error);
164
174
  }
165
175
  }
166
- async processResGood({ opts, outputBuilder, }, isFormURLEncoded, isJSON, isXML, response) {
176
+ async processResGood({ opts, outputBuilder, stream, }, isFormURLEncoded, isJSON, isNDJSON, isSSE, isXML, response) {
167
177
  let payload;
168
- if (isJSON) {
178
+ if (isNDJSON && stream) {
179
+ if (!response.body) {
180
+ throw new Error(ERR_STREAM_UNAVAILABLE);
181
+ }
182
+ await this.ndJSONStreamManager.exec({
183
+ onData: async (data) => {
184
+ if (outputBuilder) {
185
+ stream.onData(await outputBuilder(data));
186
+ }
187
+ else {
188
+ stream.onData(data);
189
+ }
190
+ },
191
+ reader: response.body.getReader(),
192
+ });
193
+ }
194
+ else if (isSSE && stream) {
195
+ if (!response.body) {
196
+ throw new Error(ERR_STREAM_UNAVAILABLE);
197
+ }
198
+ await this.sseStreamManager.exec({
199
+ onData: async (data) => {
200
+ if (outputBuilder) {
201
+ stream.onData(await outputBuilder(data));
202
+ }
203
+ else {
204
+ stream.onData(data);
205
+ }
206
+ },
207
+ reader: response.body.getReader(),
208
+ });
209
+ }
210
+ else if (isJSON) {
169
211
  payload = await response.json();
170
212
  }
171
213
  else {
@@ -177,7 +219,7 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
177
219
  payload = {};
178
220
  // TODO : Find a better way to do this (without adding any external dependency because the code must be portable)
179
221
  new URL(`http://localhost?${asText}`).searchParams.forEach((v, k) => {
180
- // @ts-ignore
222
+ // @ts-expect-error
181
223
  payload[k] = v;
182
224
  });
183
225
  }
@@ -196,6 +238,12 @@ let SimpleHTTPAPICaller = class SimpleHTTPAPICaller {
196
238
  }
197
239
  return payload;
198
240
  }
241
+ throwError(message, status) {
242
+ if (isClientError(status)) {
243
+ throw new IllegalArgumentError(message);
244
+ }
245
+ throw new Error(message);
246
+ }
199
247
  };
200
248
  SimpleHTTPAPICaller = __decorate([
201
249
  injectable(),
@@ -204,7 +252,10 @@ SimpleHTTPAPICaller = __decorate([
204
252
  __param(2, inject('HTTPAPICallExecutorAgentBuilder')),
205
253
  __param(3, inject(HTTPRequestBuilder)),
206
254
  __param(4, inject('Logger')),
207
- __param(5, inject('XMLManager')),
208
- __metadata("design:paramtypes", [Object, Object, Object, HTTPRequestBuilder, Object, Object])
255
+ __param(5, inject(NDJSONStreamManager)),
256
+ __param(6, inject(SSEStreamManager)),
257
+ __param(7, inject('XMLManager')),
258
+ __metadata("design:paramtypes", [Object, Object, Object, HTTPRequestBuilder, Object, NDJSONStreamManager,
259
+ SSEStreamManager, Object])
209
260
  ], SimpleHTTPAPICaller);
210
261
  export { SimpleHTTPAPICaller };
@@ -14,7 +14,7 @@ var CommandExecutor_1;
14
14
  import { inject, injectable } from 'inversify';
15
15
  import { WordingManager } from '../../../i18n/index.js';
16
16
  import { FSManagerItemInfoType, } from '../../../std/index.js';
17
- import { UCInputFieldChangeOperator, ucifMustBeFilledManually, } from '../../../uc/index.js';
17
+ import { ucifMustBeFilledManually, } from '../../../uc/index.js';
18
18
  import { print, printError } from './renderer.js';
19
19
  let CommandExecutor = class CommandExecutor {
20
20
  static { CommandExecutor_1 = this; }
@@ -41,7 +41,15 @@ let CommandExecutor = class CommandExecutor {
41
41
  if (!confirmed) {
42
42
  return;
43
43
  }
44
- const ucor = await this.ucManager.execClient(uc);
44
+ const ucor = await this.ucManager.execClient(uc, {
45
+ stream: {
46
+ onClose: async () => { },
47
+ onData: async (ucor) => {
48
+ print(JSON.stringify(ucor.output()));
49
+ },
50
+ onDone: async () => { },
51
+ },
52
+ });
45
53
  const output = ucor.output();
46
54
  if (output) {
47
55
  print(JSON.stringify(output));
@@ -89,7 +97,7 @@ let CommandExecutor = class CommandExecutor {
89
97
  const invite = `${label}${help}`;
90
98
  await this.promptManager.prompt(invite, {
91
99
  validate: async (v) => {
92
- f.setValue(UCInputFieldChangeOperator.SET, v);
100
+ f.setVal(v);
93
101
  const validation = f.validate();
94
102
  const violation = validation.get();
95
103
  if (!violation) {
@@ -1,6 +1,7 @@
1
1
  import { type ReactElement } from 'react';
2
2
  import type { UIntDuration } from '../../../dt/index.js';
3
- import { type UCInput, type UCOPIBase } from '../../../uc/index.js';
3
+ import { type UCInput, type UCOPIBase, type UCOutputReader } from '../../../uc/index.js';
4
+ import { type StreamConfig } from '../../../utils/index.js';
4
5
  import type { RenderUCForm } from './form.js';
5
6
  import type { RenderUCAutoExecLoader } from './loader.js';
6
7
  import type { UCPanelCtx, UCPanelOnDone, UCPanelOnError, UCPanelOnInit, UCPanelOnStartSubmitting } from './panel.js';
@@ -15,6 +16,7 @@ type Props<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | u
15
16
  renderExecTouchable: RenderUCExecTouchable<I, OPI0, OPI1>;
16
17
  renderForm: RenderUCForm<I, OPI0, OPI1>;
17
18
  sleepInMs?: UIntDuration;
19
+ stream?: StreamConfig<UCOutputReader<I, OPI0, OPI1>> | undefined;
18
20
  };
19
- 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, uc, }: Props<I, OPI0, OPI1>): ReactElement;
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;
20
22
  export {};
@@ -5,12 +5,12 @@ import { sleep } from '../../../utils/index.js';
5
5
  import { useDIContext } from './DIContextProvider.js';
6
6
  import { UCContainer } from './UCContainer.js';
7
7
  import { useAction } from './useAction.js';
8
- export function UCPanel({ autoExec = false, clearAfterExec = true, onDone, onError, onInit, onStartSubmitting, renderAutoExecLoader, renderForm, renderExecTouchable, sleepInMs, uc, }) {
8
+ export function UCPanel({ autoExec = false, clearAfterExec = true, onDone, onError, onInit, onStartSubmitting, renderAutoExecLoader, renderForm, renderExecTouchable, sleepInMs, stream, uc, }) {
9
9
  const { container } = useDIContext();
10
10
  const [ucManager] = useState(container.get('UCManager'));
11
11
  const { exec, execState } = useAction({
12
12
  action: async () => {
13
- const ucor = await ucManager.execClient(uc);
13
+ const ucor = await ucManager.execClient(uc, { stream });
14
14
  await onDone?.(ucor);
15
15
  clear();
16
16
  },
@@ -27,9 +27,6 @@ export function UCPanel({ autoExec = false, clearAfterExec = true, onDone, onErr
27
27
  },
28
28
  sleepInMs,
29
29
  });
30
- const onChange = (f, op, v) => {
31
- f.setValue(op, v);
32
- };
33
30
  const clear = () => {
34
31
  if (!clearAfterExec) {
35
32
  return;
@@ -46,7 +43,6 @@ export function UCPanel({ autoExec = false, clearAfterExec = true, onDone, onErr
46
43
  return (_jsxs(UCContainer, { uc: uc, children: [autoExec && ctx.disabled && renderAutoExecLoader(), !autoExec && (_jsxs(_Fragment, { children: [needsInputFilling &&
47
44
  renderForm({
48
45
  ...ctx,
49
- onChange,
50
46
  onSubmit: exec,
51
47
  }), !needsInputFilling &&
52
48
  renderExecTouchable({
@@ -1,13 +1,13 @@
1
1
  import type { ReactElement } from 'react';
2
2
  import type { DataType, ErrorMessage } from '../../../dt/index.js';
3
3
  import type { I18nManager } from '../../../std/index.js';
4
- import type { UCInput, UCInputField, UCInputFieldChangeOperator, UCInputFieldValue, UCOPIBase } from '../../../uc/index.js';
4
+ import type { UCInput, UCInputField, UCOPIBase } from '../../../uc/index.js';
5
5
  import type { UCPanelCtx, UCPanelOnSubmit, UCPanelState } from './panel.js';
6
- export type UCFormFieldControlOnChange<T extends DataType = DataType> = (f: UCInputField<T>, op: UCInputFieldChangeOperator, v: UCInputFieldValue<T>) => void;
6
+ export type UCFormFieldControlOnChange = () => void;
7
7
  export type UCFormFieldControlProps<T extends DataType> = UCPanelState & {
8
8
  errMsg?: ErrorMessage | null;
9
9
  f: UCInputField<T>;
10
- onChange: UCFormFieldControlOnChange<T>;
10
+ onChange: UCFormFieldControlOnChange;
11
11
  };
12
12
  export interface UCFormFieldDescProps<T extends DataType> {
13
13
  f: UCInputField<T>;
@@ -20,15 +20,14 @@ export interface UCFormFieldLabelProps<T extends DataType> {
20
20
  }
21
21
  export declare const UC_FORM_FIELD_ELEMENTS: readonly ["control", "desc", "err", "label"];
22
22
  export type UCFormFieldElement = (typeof UC_FORM_FIELD_ELEMENTS)[number];
23
- export type UCFormFieldProps<T extends DataType> = UCFormFieldControlProps<T> & {
23
+ export type UCFormFieldProps<T extends DataType> = Omit<UCFormFieldControlProps<T>, 'onChange'> & {
24
24
  only?: UCFormFieldElement[];
25
25
  };
26
26
  export type UCFormProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
27
- onChange: UCFormFieldControlOnChange;
28
27
  onSubmit: UCPanelOnSubmit;
29
28
  };
30
29
  export type UCFormSubmitControlProps<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = UCPanelCtx<I, OPI0, OPI1> & {
31
30
  onPress?: () => Promise<void>;
32
31
  };
33
32
  export type RenderUCForm<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (props: UCFormProps<I, OPI0, OPI1>) => ReactElement;
34
- export declare function validateFormField<T extends DataType = DataType>(i18nManager: I18nManager, f: UCInputField<T>, v: UCInputFieldValue<T>): ErrorMessage | null;
33
+ export declare function validateFormField<T extends DataType = DataType>(i18nManager: I18nManager, f: UCInputField<T>): ErrorMessage | null;
@@ -5,18 +5,15 @@ export const UC_FORM_FIELD_ELEMENTS = [
5
5
  'err',
6
6
  'label',
7
7
  ];
8
- export function validateFormField(i18nManager, f, v) {
9
- if (isBlank(v)) {
8
+ export function validateFormField(i18nManager, f) {
9
+ if (isBlank(f.getValue())) {
10
10
  return null;
11
11
  }
12
- const vArr = Array.isArray(v) ? v : [v];
13
- for (const vv of vArr) {
14
- const validation = f.def.type.assign(vv).validate();
15
- const violation = validation.get();
16
- if (violation) {
17
- const [key, expected] = violation;
18
- return i18nManager.t(key, { vars: { expected } });
19
- }
12
+ const validation = f.validate();
13
+ const violation = validation.get();
14
+ if (violation) {
15
+ const [key, expected] = violation;
16
+ return i18nManager.t(key, { vars: { expected } });
20
17
  }
21
18
  return null;
22
19
  }
@@ -1,7 +1,7 @@
1
- import { type ArgsRecord, UC, type UCDef, type UCInput, type UCOPIBase } from '../../../uc/index.js';
2
- export type CloneFunc<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (i: Partial<I>) => UC<I, OPI0, OPI1>;
1
+ import { type ArgsRecord, UC, type UCDef, type UCInput, type UCInputPartial, type UCOPIBase } from '../../../uc/index.js';
2
+ export type CloneFunc<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> = (i: UCInputPartial<I>) => UC<I, OPI0, OPI1>;
3
3
  export type DivertFunc<II extends UCInput | undefined = undefined, OOPI0 extends UCOPIBase | undefined = undefined, OOPI1 extends UCOPIBase | undefined = undefined> = (siblingUCD: UCDef) => UC<II, OOPI0, OOPI1>;
4
- export type RefillFunc<I extends UCInput | undefined = undefined> = (i: Partial<I>) => void;
4
+ export type RefillFunc<I extends UCInput | undefined = undefined> = (i: UCInputPartial<I>) => void;
5
5
  /**
6
6
  * This hook provides utilities to init a use case and perform actions on it in a React way
7
7
  * @param appManifest
@@ -11,7 +11,7 @@ export type RefillFunc<I extends UCInput | undefined = undefined> = (i: Partial<
11
11
  * @returns
12
12
  */
13
13
  export declare function useUC<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>(appManifest: ArgsRecord<I, OPI0, OPI1>['appManifest'], def: ArgsRecord<I, OPI0, OPI1>['def'], auth: ArgsRecord<I, OPI0, OPI1>['auth'], opts?: {
14
- fillWith: Partial<I>;
14
+ fillWith: UCInputPartial<I>;
15
15
  }): [
16
16
  UC<I, OPI0, OPI1>,
17
17
  {
@@ -1,7 +1,7 @@
1
1
  import type { AppManifest } from '../../../app/index.js';
2
2
  import type { HTTPMethod, HTTPStatusNumber, URL, URLPath } from '../../../dt/index.js';
3
3
  import type { SettingsManager, Worker } from '../../../std/index.js';
4
- import { UCBuilder, type UCDef, type UCInput, type UCManager, type UCOPIBase, type UCOutput } from '../../../uc/index.js';
4
+ import { UCBuilder, type UCDef, type UCInput, type UCManager, type UCManagerExecServerOpts, type UCOPIBase, type UCOutput } from '../../../uc/index.js';
5
5
  import type { HTTPDataEnvelope, HTTPReqData } from '../../../utils/index.js';
6
6
  import { AuthCookieCreator, type Output as AuthCookieCreatorOutput } from './AuthCookieCreator.js';
7
7
  import { AuthenticationChecker } from './AuthenticationChecker.js';
@@ -29,6 +29,7 @@ export interface ServerRequestHandlerRes {
29
29
  interface Input<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined> {
30
30
  appManifest: AppManifest;
31
31
  envelope: HTTPDataEnvelope;
32
+ execOpts?: UCManagerExecServerOpts<OPI0, OPI1> | undefined;
32
33
  req: ServerRequestHandlerReq;
33
34
  res: ServerRequestHandlerRes;
34
35
  ucd: UCDef<I, OPI0, OPI1>;
@@ -61,7 +62,7 @@ export declare class ServerRequestHandler implements Worker<Input, Promise<Outpu
61
62
  private static X_FORWARDED_PROTO_HEADER_NAME;
62
63
  constructor(authCookieCreator: AuthCookieCreator, authenticationChecker: AuthenticationChecker, customerFacingErrorBuilder: CustomerFacingErrorBuilder, publicApiKeyChecker: PublicApiKeyChecker, requestChecker: RequestChecker, requestLogger: RequestLogger, settingsManager: SettingsManager<S>, ucBuilder: UCBuilder);
63
64
  s(): S;
64
- exec<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ appManifest, envelope, req, res, ucd, ucManager, }: Input<I, OPI0, OPI1>): Promise<Output<OPI0, OPI1>>;
65
+ exec<I extends UCInput | undefined = undefined, OPI0 extends UCOPIBase | undefined = undefined, OPI1 extends UCOPIBase | undefined = undefined>({ appManifest, envelope, execOpts, req, res, ucd, ucManager, }: Input<I, OPI0, OPI1>): Promise<Output<OPI0, OPI1>>;
65
66
  private fill;
66
67
  private applySideEffects;
67
68
  private applyClearAuthSideEffect;
@@ -47,7 +47,7 @@ let ServerRequestHandler = class ServerRequestHandler {
47
47
  server_public_api_key_header_name: this.settingsManager.get()('server_public_api_key_header_name'),
48
48
  };
49
49
  }
50
- async exec({ appManifest, envelope, req, res, ucd, ucManager, }) {
50
+ async exec({ appManifest, envelope, execOpts, req, res, ucd, ucManager, }) {
51
51
  try {
52
52
  const { bodyRaw, cookie, header, method, secure, url } = req;
53
53
  this.requestLogger.exec({
@@ -79,7 +79,7 @@ let ServerRequestHandler = class ServerRequestHandler {
79
79
  uc.auth = auth;
80
80
  }
81
81
  await this.fill(req, envelope, uc);
82
- const output = await ucManager.execServer(uc);
82
+ const output = await ucManager.execServer(uc, execOpts);
83
83
  const { status } = await this.applySideEffects(res, ucd, output);
84
84
  if (status !== undefined) {
85
85
  return {
@@ -1,12 +1,48 @@
1
1
  import cookieParser from 'cookie-parser';
2
2
  import express, {} from 'express';
3
3
  import fileUpload from 'express-fileupload';
4
+ import { fmtSingleDataMsg, fmtSSEError, isError, SSE_HEADERS, } from '../../../utils/index.js';
4
5
  export function buildHandler(appManifest, ucd, contract, serverRequestHandler, ucManager) {
5
6
  const { envelope } = contract;
6
7
  const handler = async (req, res) => {
8
+ const transportType = ucd.ext?.http?.transportType ?? 'standard';
9
+ let execOpts;
10
+ switch (transportType) {
11
+ case 'standard':
12
+ // Nothing to do
13
+ break;
14
+ case 'stream': {
15
+ execOpts = {
16
+ stream: {
17
+ onClose: async () => { },
18
+ onData: async (output) => {
19
+ if (!output) {
20
+ return;
21
+ }
22
+ res.write(fmtSingleDataMsg(output));
23
+ },
24
+ onDone: async () => {
25
+ res.end();
26
+ },
27
+ },
28
+ };
29
+ for (const [k, v] of SSE_HEADERS) {
30
+ res.setHeader(k, v);
31
+ }
32
+ res.flushHeaders();
33
+ res.on('close', async () => {
34
+ res.end();
35
+ await execOpts?.stream?.onClose();
36
+ });
37
+ break;
38
+ }
39
+ default:
40
+ ((_) => { })(transportType);
41
+ }
7
42
  const { body, status } = await serverRequestHandler.exec({
8
43
  appManifest,
9
44
  envelope,
45
+ execOpts,
10
46
  req: toReq(req),
11
47
  res: toRes(res),
12
48
  ucd,
@@ -16,7 +52,22 @@ export function buildHandler(appManifest, ucd, contract, serverRequestHandler, u
16
52
  res.status(status).send();
17
53
  return;
18
54
  }
19
- res.status(status).send(body);
55
+ switch (transportType) {
56
+ case 'standard':
57
+ res.status(status).send(body);
58
+ return;
59
+ case 'stream': {
60
+ if (isError(status)) {
61
+ res.write(fmtSSEError({
62
+ message: body.message,
63
+ status,
64
+ }));
65
+ }
66
+ return;
67
+ }
68
+ default:
69
+ ((_) => { })(transportType);
70
+ }
20
71
  };
21
72
  return handler;
22
73
  }