milkio 0.2.12 → 0.2.14

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.
@@ -2,10 +2,7 @@ import type { Meta } from "../../../src/meta";
2
2
  import type { Context } from "../../../src/context";
3
3
 
4
4
  export function defineApi<ApiT extends Api>(api: ApiT): ApiT & { isApi: true } {
5
- return {
6
- ...api,
7
- isApi: true,
8
- };
5
+ return { ...api, isApi: true };
9
6
  }
10
7
 
11
8
  export type Api = {
@@ -1,6 +1,6 @@
1
- import { loggerPushTags, loggerSubmit, useLogger, runtime, MiddlewareEvent } from "..";
1
+ import { loggerPushTags, loggerSubmit, useLogger, runtime, MiddlewareEvent, reject } from "..";
2
2
  import type { ExecuteId, MilkioApp, Mixin } from "..";
3
- import { hanldeCatchError } from "../utils/handle-catch-error";
3
+ import { handleCatchError } from "../utils/handle-catch-error";
4
4
  import { routerHandler } from "../../../src/router";
5
5
  import schema from "../../../generated/api-schema";
6
6
  import { failCode } from "../../../src/fail-code";
@@ -18,6 +18,7 @@ export type ExecuteHttpServerOptions = {
18
18
  * @returns
19
19
  */
20
20
  executeIdGenerator?: (request: Request) => string | Promise<string>;
21
+ getRealIp?: (request: Request) => string;
21
22
  };
22
23
 
23
24
  export function defineHttpHandler(app: MilkioApp, options: ExecuteHttpServerOptions = {}) {
@@ -26,7 +27,7 @@ export function defineHttpHandler(app: MilkioApp, options: ExecuteHttpServerOpti
26
27
  const executeId = (options?.executeIdGenerator ? await options.executeIdGenerator(request.request) : createUlid()) as ExecuteId;
27
28
  runtime.execute.executeIds.add(executeId);
28
29
  const logger = useLogger(executeId);
29
- const ip = (request.request.headers.get("x-forwarded-for") as string | undefined)?.split(",")[0] ?? "0.0.0.0";
30
+ const ip = options.getRealIp ? options.getRealIp(request.request) : (request.request.headers.get("X-Forwarded-For") as string | undefined)?.split(",")[0] ?? "0.0.0.0";
30
31
  const headers = request.request.headers;
31
32
 
32
33
  loggerPushTags(executeId, {
@@ -121,13 +122,13 @@ export function defineHttpHandler(app: MilkioApp, options: ExecuteHttpServerOpti
121
122
  // execute api
122
123
  // after request middleware
123
124
  await MiddlewareEvent.handle("afterHttpRequest", [headers, detail]);
125
+ const mode = headers.get("Accept") === "text/event-stream" ? "stream" : "execute";
124
126
 
125
127
  const rawbody = await request.request.text();
126
128
  loggerPushTags(executeId, {
127
129
  body: rawbody || "no body",
128
130
  });
129
131
 
130
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
131
132
  let params: any;
132
133
  if (rawbody === "") {
133
134
  params = undefined;
@@ -145,29 +146,94 @@ export function defineHttpHandler(app: MilkioApp, options: ExecuteHttpServerOpti
145
146
  params,
146
147
  });
147
148
 
148
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
149
- // @ts-ignore
150
- const result = await app._executeCoreToJson(pathstr, params, headers, {
151
- executeId,
152
- logger,
153
- detail,
154
- });
149
+ const resultsRaw = await app._call(mode, pathstr, params, headers, { executeId, logger, detail });
155
150
 
156
- // @ts-ignore
157
- // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression, @typescript-eslint/no-explicit-any
158
- if (!detail.response.body) detail.response.body = result;
151
+ let fn: any;
152
+ try {
153
+ fn = await schema.apiValidator.validate[pathstr]();
154
+ } catch (error) {
155
+ throw reject("BUSINESS_FAIL", "This is the new API, which takes effect after restarting the server or saving any changes. It will be fixed in the future.");
156
+ }
159
157
 
160
- // before response middleware
161
- const middlewareResponse = {
162
- value: detail.response.body,
163
- };
164
- await MiddlewareEvent.handle("beforeHttpResponse", [middlewareResponse, detail]);
158
+ if (mode === "execute") {
159
+ const result: string = await fn.validateResults(TSON.encode(resultsRaw.$result));
160
+ if (!detail.response.body) detail.response.body = result;
161
+
162
+ // before response middleware
163
+ const middlewareResponse = {
164
+ value: detail.response.body,
165
+ };
166
+ await MiddlewareEvent.handle("beforeHttpResponse", [middlewareResponse, detail]);
165
167
 
166
- if (!detail.response.headers["Content-Type"]) detail.response.headers["Content-Type"] = "application/json";
167
- if (!detail.response.headers["Cache-Control"]) detail.response.headers["Cache-Control"] = "no-cache";
168
- if (!detail.response.body) detail.response.body = middlewareResponse.value;
168
+ if (!detail.response.headers["Content-Type"]) detail.response.headers["Content-Type"] = "application/json";
169
+ if (!detail.response.headers["Cache-Control"]) detail.response.headers["Cache-Control"] = "no-cache";
170
+ if (!detail.response.body) detail.response.body = middlewareResponse.value;
171
+ }
172
+
173
+ if (mode === "stream") {
174
+ const generator = (resultsRaw as any).$generator as AsyncGenerator;
175
+ let stream: ReadableStream;
176
+ let control: ReadableStreamDirectController | ReadableStreamDefaultController;
177
+ // SSE has a default timeout, which helps prevent memory leaks, especially when you are writing code with a while (true) loop
178
+
179
+ if (global?.Bun) {
180
+ // bun
181
+ stream = new ReadableStream({
182
+ type: "direct",
183
+ async pull(controller: ReadableStreamDirectController) {
184
+ control = controller;
185
+ try {
186
+ for await (const value of generator) {
187
+ if (!request.request.signal.aborted) {
188
+ const result: string = JSON.stringify(TSON.encode(value));
189
+ controller.write(`data:${result}\n\n`);
190
+ } else {
191
+ generator.return(undefined);
192
+ controller.close();
193
+ }
194
+ }
195
+ } catch (error) {
196
+ controller.close();
197
+ throw error;
198
+ }
199
+ controller.close();
200
+ },
201
+ cancel() {
202
+ control.close();
203
+ },
204
+ } as unknown as UnderlyingByteSource);
205
+ } else {
206
+ // node.js or others
207
+ stream = new ReadableStream({
208
+ async pull(controller) {
209
+ control = controller;
210
+ try {
211
+ for await (const value of generator) {
212
+ if (!request.request.signal.aborted) {
213
+ const result: string = JSON.stringify(TSON.encode(value));
214
+ controller.enqueue(`data:${result}\n\n`);
215
+ } else {
216
+ generator.return(undefined);
217
+ controller.close();
218
+ }
219
+ }
220
+ } catch (error) {
221
+ controller.close();
222
+ throw error;
223
+ }
224
+ controller.close();
225
+ },
226
+ cancel() {
227
+ control.close();
228
+ },
229
+ });
230
+ }
231
+ detail.response.headers["Content-Type"] = "text/event-stream";
232
+ detail.response.headers["Cache-Control"] = "no-cache";
233
+ detail.response.body = stream;
234
+ }
169
235
  } catch (error) {
170
- const result = hanldeCatchError(error, executeId);
236
+ const result = handleCatchError(error, executeId);
171
237
  if (!response.headers["Content-Type"]) response.headers["Content-Type"] = "application/json";
172
238
  if (!response.headers["Cache-Control"]) response.headers["Cache-Control"] = "no-cache";
173
239
  if (!response.body) response.body = TSON.stringify(result);
@@ -176,7 +242,6 @@ export function defineHttpHandler(app: MilkioApp, options: ExecuteHttpServerOpti
176
242
  loggerPushTags(executeId, {
177
243
  status: response.status,
178
244
  responseHeaders: response.headers,
179
- // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing
180
245
  body: response.body?.toString() ?? "",
181
246
  timeout: new Date().getTime(),
182
247
  });
@@ -0,0 +1,146 @@
1
+ import type { Context } from "../../../src/context";
2
+ import { failCode } from "../../../src/fail-code";
3
+ import schema from "../../../generated/api-schema";
4
+ import { type ExecuteId, type ExecuteOptions, type ExecuteResult, createUlid, useLogger, runtime, loggerPushTags, headerToPlainObject, loggerSubmit, type ExecuteCoreOptions, TSON, MiddlewareEvent, reject, _validate } from "..";
5
+ import { handleCatchError } from "../utils/handle-catch-error";
6
+
7
+ const apis = new Map<string, any>();
8
+
9
+ /**
10
+ * call is a low-level API that is useful only when you want to execute the Milkio Api without using execute or httpServer.
11
+ * It only does the most basic thing internally, which is calling the API. The external handling of functions such as making executeId, logging, middleware, etc., are all handled externally.
12
+ * Both execute and httpServer essentially call call.
13
+ */
14
+ export async function _call(
15
+ mode: "execute" | "stream",
16
+ path: string,
17
+ params: unknown | string,
18
+ headersInit: Record<string, string> | Headers = {},
19
+ options: ExecuteCoreOptions,
20
+ ): Promise<{ $type: "result"; $result: ExecuteResult<unknown> } | { $type: "stream"; $result: ExecuteResult<unknown>; $generator: AsyncGenerator }> {
21
+ const executeId = options.executeId as ExecuteId;
22
+
23
+ params = TSON.decode(params);
24
+
25
+ if (!(path in schema.apiMethodsSchema)) {
26
+ const result = {
27
+ executeId,
28
+ success: false,
29
+ fail: {
30
+ code: "NOT_FOUND",
31
+ message: failCode.NOT_FOUND(),
32
+ data: undefined,
33
+ },
34
+ } as ExecuteResult<unknown>;
35
+
36
+ return { $type: "result", $result: result };
37
+ }
38
+
39
+ let headers: Headers;
40
+ if (!(headersInit instanceof Headers)) {
41
+ // @ts-ignore
42
+ headers = new Headers({
43
+ ...headersInit,
44
+ });
45
+ } else {
46
+ headers = headersInit;
47
+ }
48
+
49
+ if (options?.onAfterHeaders) {
50
+ await options.onAfterHeaders(headers);
51
+ }
52
+
53
+ const context: Context = {
54
+ executeId,
55
+ path: path as string,
56
+ headers,
57
+ logger: options.logger,
58
+ detail: options?.detail ?? {},
59
+ };
60
+
61
+ let result: { value: unknown };
62
+ try {
63
+ // before execute middleware
64
+ await MiddlewareEvent.handle("beforeExecute", [context]);
65
+
66
+ let fn: any;
67
+ // check type
68
+ try {
69
+ // @ts-ignore
70
+ fn = await schema.apiValidator.validate[path]();
71
+ } catch (error) {
72
+ throw reject("BUSINESS_FAIL", "This is the new API, which takes effect after restarting the server or saving any changes. It will be fixed in the future.");
73
+ }
74
+ params = _validate(await fn.validateParams(params));
75
+
76
+ // execute api
77
+ let api: any;
78
+ if (apis.has(path as string)) api = apis.get(path as string);
79
+ else {
80
+ // @ts-ignore
81
+ api = schema.apiMethodsSchema[path as string]();
82
+ apis.set(path as string, api);
83
+ }
84
+ const apiModuleAwaited = await api.module;
85
+ const apiMethod = apiModuleAwaited.api.action;
86
+ // @ts-ignore
87
+ result = { value: await apiMethod(params, context) };
88
+ // after execute middleware
89
+ await MiddlewareEvent.handle("afterExecute", [context, result]);
90
+
91
+ if (mode === "execute" && !(result.value as AsyncGenerator)[Symbol.asyncIterator]) return { $type: "result", $result: { executeId, success: true, data: result.value } };
92
+ if (mode === "stream" && (result.value as AsyncGenerator)[Symbol.asyncIterator]) return { $type: "stream", $result: { executeId, success: true, data: "$" }, $generator: result.value as AsyncGenerator };
93
+ throw reject("BUSINESS_FAIL", `It looks like you used the wrong syntax, for this API you should use "client.${mode}(...)"`);
94
+ } catch (error: any) {
95
+ const errorResult = handleCatchError(error, executeId);
96
+
97
+ return { $type: "result", $result: errorResult };
98
+ }
99
+ }
100
+
101
+ export async function _execute<Path extends keyof (typeof schema)["apiMethodsTypeSchema"], Result extends Awaited<ReturnType<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>>>(
102
+ path: Path,
103
+ params: Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0] | string,
104
+ headersInit: Record<string, string> | Headers = {},
105
+ options?: ExecuteOptions,
106
+ ): Promise<ExecuteResult<Result>> {
107
+ const executeId = (options?.executeId ?? createUlid()) as ExecuteId;
108
+ const logger = useLogger(executeId);
109
+ runtime.execute.executeIds.add(executeId);
110
+
111
+ loggerPushTags(executeId, {
112
+ from: "execute",
113
+ executeId,
114
+ params,
115
+ path,
116
+ });
117
+
118
+ const result = await _call("execute", path, params, headersInit, {
119
+ ...options,
120
+ executeId,
121
+ logger,
122
+ onAfterHeaders: (headers) => {
123
+ loggerPushTags(executeId, {
124
+ headers: headerToPlainObject(headers),
125
+ });
126
+ },
127
+ });
128
+
129
+ loggerPushTags(executeId, { result: result.$result });
130
+ await loggerSubmit(executeId);
131
+ runtime.execute.executeIds.delete(executeId);
132
+
133
+ return result.$result as ExecuteResult<Result>;
134
+ }
135
+
136
+ export async function _executeToJson<Path extends keyof (typeof schema)["apiMethodsTypeSchema"]>(path: Path, params: Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0] | string, headersInit: Record<string, string> | Headers = {}, options?: ExecuteOptions): Promise<string> {
137
+ const resultsRaw = await _execute(path, params, headersInit, options);
138
+ let fn: any;
139
+ try {
140
+ fn = await schema.apiValidator.validate[path]();
141
+ } catch (error) {
142
+ throw reject("BUSINESS_FAIL", "This is the new API, which takes effect after restarting the server or saving any changes. It will be fixed in the future.");
143
+ }
144
+ const results = await fn.validateResults(TSON.encode(resultsRaw));
145
+ return results;
146
+ }
package/kernel/logger.ts CHANGED
@@ -23,10 +23,10 @@ export type Logger = {
23
23
  };
24
24
 
25
25
  export const loggerController = (() => {
26
- const logs = new Map<ExecuteId, { __LOG_DEATIL__: Array<LoggerItem>; [key: string]: any }>();
26
+ const logs = new Map<ExecuteId, { __LOG_DETAIL__: Array<LoggerItem>; [key: string]: any }>();
27
27
 
28
28
  const loggerPushTags = (executeId: ExecuteId, tags: Record<string, any>) => {
29
- if (!logs.has(executeId)) logs.set(executeId, { __LOG_DEATIL__: [] });
29
+ if (!logs.has(executeId)) logs.set(executeId, { __LOG_DETAIL__: [] });
30
30
  const logItem = logs.get(executeId);
31
31
  for (const key in tags) {
32
32
  logItem![key] = tags[key];
@@ -41,11 +41,11 @@ export const loggerController = (() => {
41
41
  };
42
42
  const log = logs.get(executeId)!;
43
43
  for (const key in log) {
44
- if (key === "__LOG_DEATIL__") continue;
44
+ if (key === "__LOG_DETAIL__") continue;
45
45
  loggerSubmitOptions[key] = log[key];
46
46
  }
47
47
  logs.delete(executeId);
48
- loggerOptions.onSubmit(loggerSubmitOptions, log.__LOG_DEATIL__);
48
+ loggerOptions.onSubmit(loggerSubmitOptions, log.__LOG_DETAIL__);
49
49
  };
50
50
 
51
51
  const loggerSubmitAll = async () => {
@@ -63,7 +63,7 @@ export const loggerController = (() => {
63
63
  }
64
64
 
65
65
  for (const executeId of executeIds) {
66
- if (!logs.has(executeId as ExecuteId)) logs.set(executeId as ExecuteId, { __LOG_DEATIL__: [] });
66
+ if (!logs.has(executeId as ExecuteId)) logs.set(executeId as ExecuteId, { __LOG_DETAIL__: [] });
67
67
  const loggerItem = {
68
68
  executeId: executeId as ExecuteId,
69
69
  loggerLevel: level,
@@ -71,7 +71,7 @@ export const loggerController = (() => {
71
71
  params,
72
72
  } satisfies LoggerItem;
73
73
  if (!loggerOptions.onInsert(loggerItem)) return;
74
- logs.get(executeId as ExecuteId)!.__LOG_DEATIL__.push(loggerItem);
74
+ logs.get(executeId as ExecuteId)!.__LOG_DETAIL__.push(loggerItem);
75
75
  }
76
76
  };
77
77
 
package/kernel/milkio.ts CHANGED
@@ -1,13 +1,9 @@
1
1
  import { type MiddlewareOptions, _middlewares, MiddlewareEvent } from "./middleware";
2
2
  import schema from "../../../generated/api-schema";
3
- import type { Context } from "../../../src/context";
4
- import { failCode } from "../../../src/fail-code";
5
- import type { MilkioContext } from "./context";
6
- import { headerToPlainObject } from "../utils/header-to-plain-object";
7
- import { type Mixin, type ExecuteId, type Fail, type FailEnumerates, loggerPushTags, loggerSubmit, runtime, TSON, type Logger, useLogger, reject } from "..";
8
- import { hanldeCatchError } from "../utils/handle-catch-error";
3
+ import { runtime } from "..";
9
4
  import { createUlid } from "../utils/create-ulid";
10
5
  import { _validate } from "./validate";
6
+ import { _execute, _call, _executeToJson } from "./execute";
11
7
 
12
8
  export type MilkioAppOptions = {
13
9
  /**
@@ -45,11 +41,10 @@ export async function createMilkioApp(MilkioAppOptions: MilkioAppOptions = {}) {
45
41
  }
46
42
 
47
43
  const MilkioApp = {
44
+ randParams: _randParams,
48
45
  execute: _execute,
49
46
  executeToJson: _executeToJson,
50
- _executeCore,
51
- _executeCoreToJson,
52
- randParams: _randParams,
47
+ _call,
53
48
  };
54
49
 
55
50
  if (MilkioAppOptions.bootstraps) {
@@ -86,202 +81,6 @@ export async function createMilkioApp(MilkioAppOptions: MilkioAppOptions = {}) {
86
81
  return MilkioApp;
87
82
  }
88
83
 
89
- async function _execute<Path extends keyof (typeof schema)["apiMethodsTypeSchema"], Result extends Awaited<ReturnType<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>>>(
90
- path: Path,
91
- params: Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0] | string,
92
- headersInit: Record<string, string> | Headers = {},
93
- options?: ExecuteOptions,
94
- ): Promise<ExecuteResult<Result>> {
95
- const executeId = (options?.executeId ?? createUlid()) as ExecuteId;
96
- const logger = useLogger(executeId);
97
- runtime.execute.executeIds.add(executeId);
98
-
99
- loggerPushTags(executeId, {
100
- from: "execute",
101
- executeId,
102
- params,
103
- path,
104
- });
105
-
106
- const result: any = await _executeCore(path, params, headersInit, {
107
- ...options,
108
- executeId,
109
- logger,
110
- onAfterHeaders: (headers) => {
111
- loggerPushTags(executeId, {
112
- headers: headerToPlainObject(headers),
113
- });
114
- },
115
- });
116
-
117
- loggerPushTags(executeId, { result });
118
- await loggerSubmit(executeId);
119
- runtime.execute.executeIds.delete(executeId);
120
-
121
- return result;
122
- }
123
-
124
- /**
125
- * executeCore is a low-level API that is useful only when you want to execute the Milkio Api without using execute or httpServer.
126
- * It only does the most basic thing internally, which is calling the API. The external handling of functions such as making executeId, logging, middleware, etc., are all handled externally.
127
- * Both execute and httpServer essentially call executeCore.
128
- */
129
- async function _executeCore<Path extends keyof (typeof schema)["apiMethodsTypeSchema"], Result extends Awaited<ReturnType<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>>>(
130
- path: Path,
131
- params: Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0] | string,
132
- headersInit: Record<string, string> | Headers = {},
133
- options: ExecuteCoreOptions,
134
- ): Promise<ExecuteResult<Result>> {
135
- const executeId = options.executeId as ExecuteId;
136
-
137
- params = TSON.decode(params);
138
-
139
- if (!(path in schema.apiMethodsSchema)) {
140
- const result = {
141
- executeId,
142
- success: false,
143
- fail: {
144
- code: "NOT_FOUND",
145
- message: failCode.NOT_FOUND(),
146
- data: undefined,
147
- },
148
- } satisfies ExecuteResult<Result>;
149
-
150
- return result;
151
- }
152
-
153
- let headers: Headers;
154
- if (!(headersInit instanceof Headers)) {
155
- // @ts-ignore
156
- headers = new Headers({
157
- ...headersInit,
158
- });
159
- } else {
160
- headers = headersInit;
161
- }
162
-
163
- if (options?.onAfterHeaders) {
164
- await options.onAfterHeaders(headers);
165
- }
166
-
167
- const context: Context = {
168
- executeId,
169
- path,
170
- headers,
171
- logger: options.logger,
172
- detail: options?.detail ?? {},
173
- };
174
-
175
- let result: { value: Result };
176
- try {
177
- // before execute middleware
178
- await MiddlewareEvent.handle("beforeExecute", [context]);
179
-
180
- let fn: any;
181
- // check type
182
- // @ts-ignore
183
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
184
- try {
185
- fn = await schema.apiValidator.validate[path]();
186
- } catch (error) {
187
- throw reject("BUSINESS_FAIL", "This is the new API, which takes effect after restarting the server or saving any changes. It will be fixed in the future.");
188
- }
189
-
190
- params = _validate(await fn.validateParams(params));
191
-
192
- // execute api
193
- let api: any;
194
- if (apis.has(path)) api = apis.get(path);
195
- else {
196
- // @ts-ignore
197
- api = schema.apiMethodsSchema[path]();
198
- apis.set(path, api);
199
- }
200
- const apiModuleAwaited = await api.module;
201
-
202
- const apiMethod = apiModuleAwaited.api.action;
203
-
204
- // @ts-ignore
205
- result = { value: await apiMethod(params, context) };
206
-
207
- // after execute middleware
208
- await MiddlewareEvent.handle("afterExecute", [context, result]);
209
- } catch (error: any) {
210
- const errorResult = hanldeCatchError(error, executeId);
211
-
212
- return errorResult;
213
- }
214
-
215
- return {
216
- executeId,
217
- success: true,
218
- data: result.value,
219
- };
220
- }
221
-
222
- async function _executeToJson<Path extends keyof (typeof schema)["apiMethodsTypeSchema"]>(path: Path, params: Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0] | string, headersInit: Record<string, string> | Headers = {}, options?: ExecuteOptions): Promise<string> {
223
- const resultsRaw = await _execute(path, params, headersInit, options);
224
- let fn: any;
225
- try {
226
- fn = await schema.apiValidator.validate[path]();
227
- } catch (error) {
228
- throw reject("BUSINESS_FAIL", "This is the new API, which takes effect after restarting the server or saving any changes. It will be fixed in the future.");
229
- }
230
- const results = await fn.validateResults(TSON.encode(resultsRaw));
231
- return results;
232
- }
233
-
234
- async function _executeCoreToJson<Path extends keyof (typeof schema)["apiMethodsTypeSchema"]>(path: Path, params: Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0] | string, headersInit: Record<string, string> | Headers = {}, options: ExecuteCoreOptions): Promise<string> {
235
- const resultsRaw = await _executeCore(path, params, headersInit, options);
236
- let fn: any;
237
- try {
238
- fn = await schema.apiValidator.validate[path]();
239
- } catch (error) {
240
- throw reject("BUSINESS_FAIL", "This is the new API, which takes effect after restarting the server or saving any changes. It will be fixed in the future.");
241
- }
242
- const results = await fn.validateResults(TSON.encode(resultsRaw));
243
- return results;
244
- }
245
-
246
84
  export async function _randParams<Path extends keyof (typeof schema)["apiMethodsTypeSchema"]>(path: Path): Promise<Parameters<(typeof schema)["apiMethodsTypeSchema"][Path]["api"]["action"]>[0]> {
247
85
  return await (await schema.apiValidator.validate[path]()).randParams();
248
86
  }
249
-
250
- const apis = new Map<string, any>();
251
-
252
- export type ExecuteResult<Result> = ExecuteResultSuccess<Result> | ExecuteResultFail;
253
-
254
- export type ExecuteResultSuccess<Result> = {
255
- executeId: ExecuteId;
256
- success: true;
257
- data: Result;
258
- };
259
-
260
- export type ExecuteResultFail<FailT extends Fail<keyof FailEnumerates> = Fail<keyof FailEnumerates>> = {
261
- executeId: ExecuteId;
262
- success: false;
263
- fail: FailT;
264
- };
265
-
266
- export type ExecuteOptions = {
267
- /**
268
- * The executeId of the request
269
- * executeId may be generated by the serverless provider, if not, a random string will be generated instead
270
- */
271
- executeId?: string;
272
- /**
273
- * Additional information about the request
274
- * These are usually only fully implemented when called by an Http server
275
- * During testing or when calling between microservices, some or all of the values may be undefined
276
- */
277
- detail?: MilkioContext["detail"];
278
- };
279
-
280
- export type ExecuteCoreOptions = Mixin<
281
- ExecuteOptions,
282
- {
283
- executeId: string;
284
- logger: Logger;
285
- onAfterHeaders?: (headers: Headers) => void | Promise<void>;
286
- }
287
- >;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "milkio",
3
3
  "type": "module",
4
4
  "module": "index.ts",
5
- "version": "0.2.12",
5
+ "version": "0.2.14",
6
6
  "peerDependencies": {
7
7
  "typescript": "^5.4.2"
8
8
  },
package/types.ts CHANGED
@@ -1,6 +1,12 @@
1
- import type { createMilkioApp } from ".";
1
+ import type { Logger, MilkioContext, createMilkioApp } from ".";
2
2
  import type { failCode } from "../../src/fail-code";
3
3
 
4
+ export type Override<P, S> = Omit<P, keyof S> & S;
5
+
6
+ export type Mixin<T, U> = U & Omit<T, keyof U>;
7
+
8
+ export type GeneratorGeneric<T> = T extends AsyncGenerator<infer I> ? I : never;
9
+
4
10
  export type MilkioApp = Awaited<ReturnType<typeof createMilkioApp>>;
5
11
 
6
12
  export type ExecuteId = string | "global";
@@ -33,10 +39,6 @@ export type CookbookItem = {
33
39
  }>;
34
40
  };
35
41
 
36
- export type Override<P, S> = Omit<P, keyof S> & S;
37
-
38
- export type Mixin<T, U> = U & Omit<T, keyof U>;
39
-
40
42
  export type MilkioConfig = {
41
43
  generate?: {
42
44
  significant?: Array<string>;
@@ -47,3 +49,42 @@ export type MilkioConfig = {
47
49
  commands?: Array<{ name?: string; script?: string; icon?: string }>;
48
50
  };
49
51
  };
52
+
53
+ export type ExecuteResult<Result> = ExecuteResultSuccess<Result> | ExecuteResultFail;
54
+
55
+ export type ExecuteResultSuccess<Result> = {
56
+ executeId: ExecuteId;
57
+ success: true;
58
+ data: Result;
59
+ };
60
+
61
+ export type ExecuteResultFail<FailT extends Fail<keyof FailEnumerates> = Fail<keyof FailEnumerates>> = {
62
+ executeId: ExecuteId;
63
+ success: false;
64
+ fail: FailT;
65
+ };
66
+
67
+ export type ExecuteOptions = {
68
+ /**
69
+ * The executeId of the request
70
+ * executeId may be generated by the serverless provider, if not, a random string will be generated instead
71
+ */
72
+ executeId?: string;
73
+ /**
74
+ * Additional information about the request
75
+ * These are usually only fully implemented when called by an Http server
76
+ * During testing or when calling between microservices, some or all of the values may be undefined
77
+ */
78
+ detail?: MilkioContext["detail"];
79
+ };
80
+
81
+ export type ExecuteCoreOptions = Mixin<
82
+ ExecuteOptions,
83
+ {
84
+ executeId: string;
85
+ logger: Logger;
86
+ onAfterHeaders?: (headers: Headers) => void | Promise<void>;
87
+ }
88
+ >;
89
+
90
+ export type MilkioEvent<Result> = Awaited<GeneratorGeneric<ExecuteResultSuccess<Result>["data"] extends { $type: any } ? ExecuteResultSuccess<Result>["data"]["$type"] : never>>;
@@ -3,7 +3,7 @@ import { useLogger, type ExecuteId, type ExecuteResult } from "..";
3
3
  import { configMilkio } from "../../../src/config/milkio";
4
4
 
5
5
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
6
- export function hanldeCatchError(error: any, executeId: ExecuteId): ExecuteResult<any> {
6
+ export function handleCatchError(error: any, executeId: ExecuteId): ExecuteResult<any> {
7
7
  const logger = useLogger(executeId);
8
8
 
9
9
  if (configMilkio.debug === true) {