alemonjs 2.1.82 → 2.1.83-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/app/event-error.d.ts +2 -0
- package/lib/app/event-error.js +20 -0
- package/lib/app/event-processor-callHandler.d.ts +5 -1
- package/lib/app/event-processor-callHandler.js +18 -2
- package/lib/app/event-processor-cycleFiles.d.ts +4 -1
- package/lib/app/event-processor-cycleFiles.js +21 -6
- package/lib/app/event-processor-cycleRoute.d.ts +4 -1
- package/lib/app/event-processor-cycleRoute.js +16 -2
- package/lib/app/event-processor-event.js +2 -2
- package/lib/app/event-processor-middleware.js +2 -2
- package/lib/app/event-processor-subscribe.js +31 -3
- package/lib/app/event-processor.js +6 -1
- package/lib/app/hook-event-context.d.ts +7 -3
- package/lib/app/hook-event-context.js +24 -5
- package/lib/app/hook-use/subscribe.js +3 -1
- package/lib/app/index.js +2 -2
- package/lib/app/lifecycle-callbacks.d.ts +14 -0
- package/lib/app/lifecycle-callbacks.js +99 -0
- package/lib/app/load_modules/loadChild.js +13 -10
- package/lib/app/router/dsl.js +2 -2
- package/lib/app/store.d.ts +2 -0
- package/lib/app/store.js +31 -5
- package/lib/cbp/connects/client.js +34 -32
- package/lib/cbp/connects/platform.js +45 -68
- package/lib/cbp/normalize.d.ts +16 -0
- package/lib/cbp/normalize.js +328 -0
- package/lib/cbp/processor/actions.js +15 -13
- package/lib/cbp/processor/api.js +15 -13
- package/lib/cbp/processor/config.d.ts +8 -4
- package/lib/cbp/processor/config.js +9 -5
- package/lib/cbp/server/main.js +28 -30
- package/lib/cbp/typings.d.ts +139 -0
- package/lib/client.js +11 -7
- package/lib/core/config.d.ts +3 -3
- package/lib/index.js +2 -2
- package/lib/server/routers/router.js +111 -17
- package/lib/types/actions.d.ts +20 -1
- package/lib/types/apis.d.ts +2 -1
- package/lib/types/cycle/index.d.ts +50 -0
- package/lib/types/event/index.d.ts +1 -0
- package/lib/types/subscribe/index.d.ts +1 -0
- package/package.json +1 -1
package/lib/cbp/typings.d.ts
CHANGED
|
@@ -12,6 +12,145 @@ export type ParsedMessage = {
|
|
|
12
12
|
payload?: any;
|
|
13
13
|
[key: string]: any;
|
|
14
14
|
};
|
|
15
|
+
export type CBPProtocolRole = 'platform' | 'app-client' | 'server';
|
|
16
|
+
export type CBPMessageType = 'event' | 'action.req' | 'action.res' | 'api.req' | 'api.res' | 'control';
|
|
17
|
+
export type CBPEndpoint = {
|
|
18
|
+
role: CBPProtocolRole;
|
|
19
|
+
deviceId?: string;
|
|
20
|
+
appName?: string;
|
|
21
|
+
platform?: string;
|
|
22
|
+
};
|
|
23
|
+
export type CBPError = {
|
|
24
|
+
code: string;
|
|
25
|
+
message: string;
|
|
26
|
+
retryable?: boolean;
|
|
27
|
+
details?: unknown;
|
|
28
|
+
};
|
|
29
|
+
export type CBPResult = {
|
|
30
|
+
code: number;
|
|
31
|
+
message: string;
|
|
32
|
+
data?: unknown;
|
|
33
|
+
};
|
|
34
|
+
export type CBPCapability = 'event' | 'action' | 'api' | 'full-receive';
|
|
35
|
+
export type CBPControlPayload = {
|
|
36
|
+
op: 'hello';
|
|
37
|
+
capabilities?: CBPCapability[];
|
|
38
|
+
} | {
|
|
39
|
+
op: 'heartbeat';
|
|
40
|
+
} | {
|
|
41
|
+
op: 'goodbye';
|
|
42
|
+
reason?: string;
|
|
43
|
+
} | {
|
|
44
|
+
op: 'error';
|
|
45
|
+
code: string;
|
|
46
|
+
message: string;
|
|
47
|
+
} | {
|
|
48
|
+
op: 'sync';
|
|
49
|
+
env?: Record<string, string>;
|
|
50
|
+
};
|
|
51
|
+
export type CBPEventPayload = {
|
|
52
|
+
name: EventKeys | string;
|
|
53
|
+
event: Record<string, unknown>;
|
|
54
|
+
raw?: unknown;
|
|
55
|
+
};
|
|
56
|
+
export type CBPActionRequestPayload = {
|
|
57
|
+
action: string;
|
|
58
|
+
input: Record<string, unknown>;
|
|
59
|
+
};
|
|
60
|
+
export type CBPActionResponsePayload = {
|
|
61
|
+
results: CBPResult[] | Result[];
|
|
62
|
+
};
|
|
63
|
+
export type CBPApiRequestPayload = {
|
|
64
|
+
api: string;
|
|
65
|
+
input: Record<string, unknown>;
|
|
66
|
+
};
|
|
67
|
+
export type CBPApiResponsePayload = {
|
|
68
|
+
results: CBPResult[] | Result[];
|
|
69
|
+
};
|
|
70
|
+
export type CBPEnvelope = {
|
|
71
|
+
protocol: 'cbp';
|
|
72
|
+
version: 1;
|
|
73
|
+
type: CBPMessageType;
|
|
74
|
+
id: string;
|
|
75
|
+
replyTo?: string;
|
|
76
|
+
timestamp: number;
|
|
77
|
+
source: CBPEndpoint;
|
|
78
|
+
target?: CBPEndpoint;
|
|
79
|
+
payload?: CBPEventPayload | CBPActionRequestPayload | CBPActionResponsePayload | CBPApiRequestPayload | CBPApiResponsePayload | CBPControlPayload | unknown;
|
|
80
|
+
error?: CBPError;
|
|
81
|
+
meta?: Record<string, unknown>;
|
|
82
|
+
};
|
|
83
|
+
export type NormalizedEventMessage = {
|
|
84
|
+
kind: 'event';
|
|
85
|
+
id: string;
|
|
86
|
+
timestamp: number;
|
|
87
|
+
deviceId?: string;
|
|
88
|
+
sourceRole?: CBPProtocolRole;
|
|
89
|
+
targetRole?: CBPProtocolRole;
|
|
90
|
+
eventName: EventKeys | string;
|
|
91
|
+
event: Record<string, unknown>;
|
|
92
|
+
raw?: unknown;
|
|
93
|
+
meta?: Record<string, unknown>;
|
|
94
|
+
};
|
|
95
|
+
export type NormalizedActionRequestMessage = {
|
|
96
|
+
kind: 'action.req';
|
|
97
|
+
id: string;
|
|
98
|
+
timestamp: number;
|
|
99
|
+
deviceId?: string;
|
|
100
|
+
sourceRole?: CBPProtocolRole;
|
|
101
|
+
targetRole?: CBPProtocolRole;
|
|
102
|
+
action: string;
|
|
103
|
+
input: Record<string, unknown>;
|
|
104
|
+
meta?: Record<string, unknown>;
|
|
105
|
+
};
|
|
106
|
+
export type NormalizedActionResponseMessage = {
|
|
107
|
+
kind: 'action.res';
|
|
108
|
+
id: string;
|
|
109
|
+
replyTo: string;
|
|
110
|
+
timestamp: number;
|
|
111
|
+
deviceId?: string;
|
|
112
|
+
sourceRole?: CBPProtocolRole;
|
|
113
|
+
targetRole?: CBPProtocolRole;
|
|
114
|
+
results: Result[];
|
|
115
|
+
error?: CBPError;
|
|
116
|
+
meta?: Record<string, unknown>;
|
|
117
|
+
};
|
|
118
|
+
export type NormalizedApiRequestMessage = {
|
|
119
|
+
kind: 'api.req';
|
|
120
|
+
id: string;
|
|
121
|
+
timestamp: number;
|
|
122
|
+
deviceId?: string;
|
|
123
|
+
sourceRole?: CBPProtocolRole;
|
|
124
|
+
targetRole?: CBPProtocolRole;
|
|
125
|
+
api: string;
|
|
126
|
+
input: Record<string, unknown>;
|
|
127
|
+
meta?: Record<string, unknown>;
|
|
128
|
+
};
|
|
129
|
+
export type NormalizedApiResponseMessage = {
|
|
130
|
+
kind: 'api.res';
|
|
131
|
+
id: string;
|
|
132
|
+
replyTo: string;
|
|
133
|
+
timestamp: number;
|
|
134
|
+
deviceId?: string;
|
|
135
|
+
sourceRole?: CBPProtocolRole;
|
|
136
|
+
targetRole?: CBPProtocolRole;
|
|
137
|
+
results: Result[];
|
|
138
|
+
error?: CBPError;
|
|
139
|
+
meta?: Record<string, unknown>;
|
|
140
|
+
};
|
|
141
|
+
export type NormalizedControlMessage = {
|
|
142
|
+
kind: 'control';
|
|
143
|
+
id: string;
|
|
144
|
+
timestamp: number;
|
|
145
|
+
deviceId?: string;
|
|
146
|
+
sourceRole?: CBPProtocolRole;
|
|
147
|
+
targetRole?: CBPProtocolRole;
|
|
148
|
+
op: CBPControlPayload['op'];
|
|
149
|
+
payload?: Record<string, unknown>;
|
|
150
|
+
error?: CBPError;
|
|
151
|
+
meta?: Record<string, unknown>;
|
|
152
|
+
};
|
|
153
|
+
export type NormalizedCBPMessage = NormalizedEventMessage | NormalizedActionRequestMessage | NormalizedActionResponseMessage | NormalizedApiRequestMessage | NormalizedApiResponseMessage | NormalizedControlMessage;
|
|
15
154
|
export type CBPClientOptions = {
|
|
16
155
|
open?: () => void;
|
|
17
156
|
isFullReceive?: boolean;
|
package/lib/client.js
CHANGED
|
@@ -34,20 +34,27 @@ import './app/message-api.js';
|
|
|
34
34
|
import './process/platform.js';
|
|
35
35
|
import './process/module.js';
|
|
36
36
|
import { createServer } from './server/main.js';
|
|
37
|
+
import { dispatchDisposeAllApps } from './app/lifecycle-callbacks.js';
|
|
37
38
|
|
|
38
39
|
global.__client_loaded = true;
|
|
39
40
|
let runtimeDisposed = false;
|
|
40
|
-
const disposeRuntime = () => {
|
|
41
|
+
const disposeRuntime = async () => {
|
|
41
42
|
if (runtimeDisposed) {
|
|
42
43
|
return;
|
|
43
44
|
}
|
|
44
45
|
runtimeDisposed = true;
|
|
46
|
+
await dispatchDisposeAllApps();
|
|
45
47
|
const apps = disposeAllRuntimeApps();
|
|
46
48
|
apps.forEach(app => {
|
|
47
49
|
scheduleCancelByApp(app.name);
|
|
48
50
|
unregisterAppDir(app.name);
|
|
49
51
|
});
|
|
50
52
|
};
|
|
53
|
+
const shutdown = async (reason) => {
|
|
54
|
+
logger.info?.(`[alemonjs][${reason}] 收到信号,正在关闭...`);
|
|
55
|
+
await disposeRuntime();
|
|
56
|
+
process.exit(0);
|
|
57
|
+
};
|
|
51
58
|
const mainServer = () => {
|
|
52
59
|
const port = process.env.serverPort;
|
|
53
60
|
if (!port) {
|
|
@@ -83,13 +90,11 @@ const mainProcess = () => {
|
|
|
83
90
|
});
|
|
84
91
|
['SIGINT', 'SIGTERM', 'SIGQUIT', 'disconnect'].forEach(sig => {
|
|
85
92
|
process?.on?.(sig, () => {
|
|
86
|
-
|
|
87
|
-
disposeRuntime();
|
|
88
|
-
setImmediate(() => process.exit(0));
|
|
93
|
+
void shutdown(sig);
|
|
89
94
|
});
|
|
90
95
|
});
|
|
91
96
|
process?.on?.('exit', code => {
|
|
92
|
-
disposeRuntime();
|
|
97
|
+
void disposeRuntime();
|
|
93
98
|
logger.info?.(`[alemonjs][exit] 进程退出,code=${code}`);
|
|
94
99
|
});
|
|
95
100
|
process.on('message', msg => {
|
|
@@ -100,8 +105,7 @@ const mainProcess = () => {
|
|
|
100
105
|
mainServer();
|
|
101
106
|
}
|
|
102
107
|
else if (data?.type === 'stop') {
|
|
103
|
-
|
|
104
|
-
process.exit(0);
|
|
108
|
+
void shutdown('stop');
|
|
105
109
|
}
|
|
106
110
|
}
|
|
107
111
|
catch { }
|
package/lib/core/config.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import type { Package } from '../types';
|
|
2
2
|
type ConfigValue = {
|
|
3
3
|
[key: string]: any;
|
|
4
|
+
apps?: string[] | {
|
|
5
|
+
[key: string]: boolean;
|
|
6
|
+
};
|
|
4
7
|
master_key?: {
|
|
5
8
|
[key: string]: boolean;
|
|
6
9
|
} | string[];
|
|
@@ -35,9 +38,6 @@ type ConfigValue = {
|
|
|
35
38
|
repeated_event_time?: number;
|
|
36
39
|
repeated_user_time?: number;
|
|
37
40
|
};
|
|
38
|
-
apps?: string[] | {
|
|
39
|
-
[key: string]: boolean;
|
|
40
|
-
};
|
|
41
41
|
};
|
|
42
42
|
type ConfigListener<T extends ConfigValue = ConfigValue> = (value: T) => void;
|
|
43
43
|
declare class ConfigCore<T extends ConfigValue = ConfigValue> {
|
package/lib/index.js
CHANGED
|
@@ -5,7 +5,7 @@ export { createEventName, createHash, createResult, createUserHashKey, fastHash,
|
|
|
5
5
|
export { cbpClient } from './cbp/connects/client.js';
|
|
6
6
|
export { cbpPlatform } from './cbp/connects/platform.js';
|
|
7
7
|
export { cbpServer } from './cbp/server/main.js';
|
|
8
|
-
export { ChildrenApp, Core, Logger, Middleware, MiddlewareRouter, MiddlewareTree, ProcessorEventAutoClearMap, ProcessorEventUserAutoClearMap, Response, ResponseMiddleware, ResponseRouter, ResponseTree, State, StateSubscribe, SubscribeList, bumpStoreVersion, clearRuntimeAppKoaRouters, core, disposeAllRuntimeApps, disposeRuntimeApp, getRuntimeApp, getRuntimeAppKoaRouters, getSubscribeList, hasRuntimeAppCapability, listRuntimeAppKoaRouters, listRuntimeApps, logger, registerRuntimeApp, setRuntimeAppKoaRouters, toRuntimeAppSnapshot, updateRuntimeAppCapabilities, updateRuntimeAppStatus } from './app/store.js';
|
|
8
|
+
export { ChildrenApp, Core, Logger, Middleware, MiddlewareRouter, MiddlewareTree, ProcessorEventAutoClearMap, ProcessorEventUserAutoClearMap, Response, ResponseMiddleware, ResponseRouter, ResponseTree, State, StateSubscribe, SubscribeList, bumpStoreVersion, clearRuntimeAppKoaRouters, core, disposeAllRuntimeApps, disposeRuntimeApp, getChildrenApp, getRuntimeApp, getRuntimeAppKoaRouters, getSubscribeList, hasRuntimeAppCapability, listChildrenApps, listRuntimeAppKoaRouters, listRuntimeApps, logger, registerRuntimeApp, setRuntimeAppKoaRouters, toRuntimeAppSnapshot, updateRuntimeAppCapabilities, updateRuntimeAppStatus } from './app/store.js';
|
|
9
9
|
export { Expose, clearAllExpose, disposeExpose, registerExpose } from './app/expose.js';
|
|
10
10
|
export { loadModels, run } from './app/load_modules/load.js';
|
|
11
11
|
export { loadChildren, loadChildrenFile } from './app/load_modules/loadChild.js';
|
|
@@ -42,7 +42,7 @@ export { useUser } from './app/hook-use/user.js';
|
|
|
42
42
|
export { useObserver, useSubscribe } from './app/hook-use/subscribe.js';
|
|
43
43
|
export { createEvent, useEvent } from './app/hook-use/event.js';
|
|
44
44
|
export { clearInterval, clearTimeout, listSchedule, pauseSchedule, resumeSchedule, setCron, setInterval, setTimeout } from './app/api/schedule.js';
|
|
45
|
-
export { finishCurrentTrace, getCurrentEvent, getCurrentNext, markEventSendAttempt, markEventSendFailure, markEventSendSuccess, recordEventSendResults, withEventContext, withProcessorTrace } from './app/hook-event-context.js';
|
|
45
|
+
export { finishCurrentTrace, getCurrentAppName, getCurrentEvent, getCurrentNext, getCurrentPhase, markEventSendAttempt, markEventSendFailure, markEventSendSuccess, recordEventSendResults, withEventContext, withProcessorTrace } from './app/hook-event-context.js';
|
|
46
46
|
export { registerAppDir, scheduleCancel, scheduleCancelAll, scheduleCancelByApp, scheduleCron, scheduleInterval, scheduleList, schedulePause, scheduleResume, scheduleTimeout, unregisterAppDir } from './app/schedule-store.js';
|
|
47
47
|
export { createEventValue, createSelects, onSelects, onState, unChildren, unState, useState } from './app/event-utils.js';
|
|
48
48
|
export { MessageDirect, createDataFormat, format, getMessageIntent, sendToChannel, sendToUser } from './app/message-api.js';
|
|
@@ -10,6 +10,7 @@ import { ResultCode } from '../../core/variable.js';
|
|
|
10
10
|
import 'yaml';
|
|
11
11
|
import '../../core/utils.js';
|
|
12
12
|
import { listRuntimeApps, getRuntimeApp, toRuntimeAppSnapshot, listRuntimeAppKoaRouters, hasRuntimeAppCapability, getRuntimeAppKoaRouters } from '../../app/store.js';
|
|
13
|
+
import { dispatchHttpError } from '../../app/lifecycle-callbacks.js';
|
|
13
14
|
|
|
14
15
|
const initRequire = () => { };
|
|
15
16
|
initRequire.resolve = () => '';
|
|
@@ -37,7 +38,7 @@ const readWebRootConfig = (packageRoot) => {
|
|
|
37
38
|
};
|
|
38
39
|
const denyRuntimeAppAccess = (ctx, appName, capability) => {
|
|
39
40
|
const runtimeApp = getRuntimeApp(appName);
|
|
40
|
-
if (!runtimeApp
|
|
41
|
+
if (!runtimeApp?.enabled) {
|
|
41
42
|
ctx.status = 404;
|
|
42
43
|
ctx.body = {
|
|
43
44
|
code: 404,
|
|
@@ -104,14 +105,42 @@ const dispatchRegisteredKoaRouters = async (ctx) => {
|
|
|
104
105
|
}
|
|
105
106
|
const routers = getRuntimeAppKoaRouters(item.name);
|
|
106
107
|
for (const koaRouter of routers) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
try {
|
|
109
|
+
const matchedContext = ctx;
|
|
110
|
+
const beforeMatched = Array.isArray(matchedContext.matched) ? matchedContext.matched.length : 0;
|
|
111
|
+
await koaRouter.routes()(ctx, async () => { });
|
|
112
|
+
const afterMatched = Array.isArray(matchedContext.matched) ? matchedContext.matched.length : 0;
|
|
113
|
+
if (afterMatched <= beforeMatched) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
await koaRouter.allowedMethods()(ctx, async () => { });
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
const handled = await dispatchHttpError({
|
|
121
|
+
ctx,
|
|
122
|
+
error,
|
|
123
|
+
appName: item.name,
|
|
124
|
+
path: ctx.path,
|
|
125
|
+
method: ctx.method,
|
|
126
|
+
kind: 'koa-router'
|
|
127
|
+
});
|
|
128
|
+
if (handled) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
logger.warn({
|
|
132
|
+
code: ResultCode.Fail,
|
|
133
|
+
message: `Error request ${ctx.path}:`,
|
|
134
|
+
data: error instanceof Error ? error.message : String(error)
|
|
135
|
+
});
|
|
136
|
+
ctx.status = 500;
|
|
137
|
+
ctx.body = {
|
|
138
|
+
code: 500,
|
|
139
|
+
message: '处理 Koa Router 请求时发生错误。',
|
|
140
|
+
error: error instanceof Error ? error.message : String(error)
|
|
141
|
+
};
|
|
142
|
+
return true;
|
|
112
143
|
}
|
|
113
|
-
await koaRouter.allowedMethods()(ctx, async () => { });
|
|
114
|
-
return true;
|
|
115
144
|
}
|
|
116
145
|
}
|
|
117
146
|
return false;
|
|
@@ -239,12 +268,22 @@ router.all('app/{*path}', async (ctx) => {
|
|
|
239
268
|
await runMiddlewares(middlewares, ctx, handler);
|
|
240
269
|
}
|
|
241
270
|
catch (err) {
|
|
242
|
-
|
|
271
|
+
const handled = await dispatchHttpError({
|
|
272
|
+
ctx,
|
|
273
|
+
error: err,
|
|
274
|
+
appName: 'main',
|
|
275
|
+
path: ctx.path,
|
|
276
|
+
method: ctx.method,
|
|
277
|
+
kind: 'api'
|
|
278
|
+
});
|
|
279
|
+
if (handled) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
243
282
|
ctx.status = 500;
|
|
244
283
|
ctx.body = {
|
|
245
284
|
code: 500,
|
|
246
285
|
message: '处理 API 请求时发生错误。',
|
|
247
|
-
error: err.message
|
|
286
|
+
error: err instanceof Error ? err.message : String(err)
|
|
248
287
|
};
|
|
249
288
|
}
|
|
250
289
|
return;
|
|
@@ -264,11 +303,22 @@ router.all('app/{*path}', async (ctx) => {
|
|
|
264
303
|
root = readWebRootConfig(packageRoot);
|
|
265
304
|
}
|
|
266
305
|
catch (err) {
|
|
306
|
+
const handled = await dispatchHttpError({
|
|
307
|
+
ctx,
|
|
308
|
+
error: err,
|
|
309
|
+
appName: 'main',
|
|
310
|
+
path: ctx.path,
|
|
311
|
+
method: ctx.method,
|
|
312
|
+
kind: 'web'
|
|
313
|
+
});
|
|
314
|
+
if (handled) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
267
317
|
ctx.status = 500;
|
|
268
318
|
ctx.body = {
|
|
269
319
|
code: 500,
|
|
270
320
|
message: '加载 package.json 时发生错误。',
|
|
271
|
-
error: err.message
|
|
321
|
+
error: err instanceof Error ? err.message : String(err)
|
|
272
322
|
};
|
|
273
323
|
return;
|
|
274
324
|
}
|
|
@@ -291,6 +341,17 @@ router.all('app/{*path}', async (ctx) => {
|
|
|
291
341
|
ctx.status = 200;
|
|
292
342
|
}
|
|
293
343
|
catch (err) {
|
|
344
|
+
const handled = await dispatchHttpError({
|
|
345
|
+
ctx,
|
|
346
|
+
error: err,
|
|
347
|
+
appName: 'main',
|
|
348
|
+
path: ctx.path,
|
|
349
|
+
method: ctx.method,
|
|
350
|
+
kind: 'web'
|
|
351
|
+
});
|
|
352
|
+
if (handled) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
294
355
|
if (err?.status === 404) {
|
|
295
356
|
ctx.status = 404;
|
|
296
357
|
ctx.body = {
|
|
@@ -304,7 +365,7 @@ router.all('app/{*path}', async (ctx) => {
|
|
|
304
365
|
ctx.body = {
|
|
305
366
|
code: 500,
|
|
306
367
|
message: '加载资源时发生服务器错误。',
|
|
307
|
-
error: err.message
|
|
368
|
+
error: err instanceof Error ? err.message : String(err)
|
|
308
369
|
};
|
|
309
370
|
}
|
|
310
371
|
}
|
|
@@ -370,16 +431,27 @@ router.all('apps/:app/{*path}', async (ctx) => {
|
|
|
370
431
|
await runMiddlewares(middlewares, ctx, handler);
|
|
371
432
|
}
|
|
372
433
|
catch (err) {
|
|
434
|
+
const handled = await dispatchHttpError({
|
|
435
|
+
ctx,
|
|
436
|
+
error: err,
|
|
437
|
+
appName,
|
|
438
|
+
path: ctx.path,
|
|
439
|
+
method: ctx.method,
|
|
440
|
+
kind: 'api'
|
|
441
|
+
});
|
|
442
|
+
if (handled) {
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
373
445
|
logger.warn({
|
|
374
446
|
code: ResultCode.Fail,
|
|
375
447
|
message: `Error request ${ctx.path}:`,
|
|
376
|
-
data: err
|
|
448
|
+
data: err instanceof Error ? err.message : String(err)
|
|
377
449
|
});
|
|
378
450
|
ctx.status = 500;
|
|
379
451
|
ctx.body = {
|
|
380
452
|
code: 500,
|
|
381
453
|
message: '处理 API 请求时发生错误。',
|
|
382
|
-
error: err.message
|
|
454
|
+
error: err instanceof Error ? err.message : String(err)
|
|
383
455
|
};
|
|
384
456
|
}
|
|
385
457
|
return;
|
|
@@ -399,11 +471,22 @@ router.all('apps/:app/{*path}', async (ctx) => {
|
|
|
399
471
|
root = readWebRootConfig(packageRoot);
|
|
400
472
|
}
|
|
401
473
|
catch (err) {
|
|
474
|
+
const handled = await dispatchHttpError({
|
|
475
|
+
ctx,
|
|
476
|
+
error: err,
|
|
477
|
+
appName,
|
|
478
|
+
path: ctx.path,
|
|
479
|
+
method: ctx.method,
|
|
480
|
+
kind: 'web'
|
|
481
|
+
});
|
|
482
|
+
if (handled) {
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
402
485
|
ctx.status = 500;
|
|
403
486
|
ctx.body = {
|
|
404
487
|
code: 500,
|
|
405
488
|
message: '加载 package.json 时发生错误。',
|
|
406
|
-
error: err.message
|
|
489
|
+
error: err instanceof Error ? err.message : String(err)
|
|
407
490
|
};
|
|
408
491
|
return;
|
|
409
492
|
}
|
|
@@ -426,6 +509,17 @@ router.all('apps/:app/{*path}', async (ctx) => {
|
|
|
426
509
|
ctx.status = 200;
|
|
427
510
|
}
|
|
428
511
|
catch (err) {
|
|
512
|
+
const handled = await dispatchHttpError({
|
|
513
|
+
ctx,
|
|
514
|
+
error: err,
|
|
515
|
+
appName,
|
|
516
|
+
path: ctx.path,
|
|
517
|
+
method: ctx.method,
|
|
518
|
+
kind: 'web'
|
|
519
|
+
});
|
|
520
|
+
if (handled) {
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
429
523
|
if (err?.status === 404) {
|
|
430
524
|
ctx.status = 404;
|
|
431
525
|
ctx.body = {
|
|
@@ -438,13 +532,13 @@ router.all('apps/:app/{*path}', async (ctx) => {
|
|
|
438
532
|
logger.warn({
|
|
439
533
|
code: ResultCode.Fail,
|
|
440
534
|
message: `Error request ${ctx.path}:`,
|
|
441
|
-
data: err
|
|
535
|
+
data: err instanceof Error ? err.message : String(err)
|
|
442
536
|
});
|
|
443
537
|
ctx.status = 500;
|
|
444
538
|
ctx.body = {
|
|
445
539
|
code: 500,
|
|
446
540
|
message: `加载子应用 '${appName}' 资源时发生服务器错误。`,
|
|
447
|
-
error: err.message
|
|
541
|
+
error: err instanceof Error ? err.message : String(err)
|
|
448
542
|
};
|
|
449
543
|
}
|
|
450
544
|
}
|
package/lib/types/actions.d.ts
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
import { DataEnums } from './message';
|
|
2
2
|
import { PaginationParams } from './standard';
|
|
3
|
+
export type MessageActionName = 'message.send' | 'message.send.channel' | 'message.send.user' | 'message.delete' | 'message.edit' | 'message.pin' | 'message.unpin' | 'message.forward.user' | 'message.forward.channel' | 'message.get' | 'message.intent';
|
|
4
|
+
export type MentionActionName = 'mention.get';
|
|
5
|
+
export type ReactionActionName = 'reaction.add' | 'reaction.remove' | 'reaction.list';
|
|
6
|
+
export type FileActionName = 'file.send.channel' | 'file.send.user';
|
|
7
|
+
export type MemberActionName = 'member.info' | 'member.list' | 'member.kick' | 'member.ban' | 'member.unban' | 'member.mute' | 'member.admin' | 'member.card' | 'member.title' | 'member.search';
|
|
8
|
+
export type GuildActionName = 'guild.info' | 'guild.list' | 'guild.update' | 'guild.leave' | 'guild.mute';
|
|
9
|
+
export type ChannelActionName = 'channel.info' | 'channel.list' | 'channel.create' | 'channel.update' | 'channel.delete' | 'channel.announce';
|
|
10
|
+
export type RoleActionName = 'role.list' | 'role.create' | 'role.update' | 'role.delete' | 'role.assign' | 'role.remove';
|
|
11
|
+
export type MeActionName = 'me.info' | 'me.guilds' | 'me.threads' | 'me.friends';
|
|
12
|
+
export type RequestActionName = 'request.friend' | 'request.guild';
|
|
13
|
+
export type UserActionName = 'user.info';
|
|
14
|
+
export type MediaActionName = 'media.upload' | 'media.send.channel' | 'media.send.user';
|
|
15
|
+
export type HistoryActionName = 'history.list';
|
|
16
|
+
export type PermissionActionName = 'permission.get' | 'permission.set';
|
|
17
|
+
export type StandardActionName = MessageActionName | MentionActionName | ReactionActionName | FileActionName | MemberActionName | GuildActionName | ChannelActionName | RoleActionName | MeActionName | RequestActionName | UserActionName | MediaActionName | HistoryActionName | PermissionActionName;
|
|
3
18
|
export type ActionMessageSend = {
|
|
4
19
|
action: 'message.send';
|
|
5
20
|
payload: {
|
|
@@ -293,6 +308,10 @@ export type ActionMessageGet = {
|
|
|
293
308
|
MessageId: string;
|
|
294
309
|
};
|
|
295
310
|
};
|
|
311
|
+
export type ActionMessageIntent = {
|
|
312
|
+
action: 'message.intent';
|
|
313
|
+
payload: object;
|
|
314
|
+
};
|
|
296
315
|
export type ActionGuildUpdate = {
|
|
297
316
|
action: 'guild.update';
|
|
298
317
|
payload: {
|
|
@@ -488,7 +507,7 @@ type base = {
|
|
|
488
507
|
actionId?: string;
|
|
489
508
|
DeviceId?: string;
|
|
490
509
|
};
|
|
491
|
-
export type Actions = (ActionMessageSend | ActionMessageSendChannel | ActionMessageSendUser | ActionMessageDelete | ActionMessageEdit | ActionMessagePin | ActionMessageUnpin | ActionMentionGet | ActionReactionAdd | ActionReactionRemove | ActionFileSendChannel | ActionFileSendUser | ActionMessageForwardUser | ActionMessageForwardChannel | ActionMemberInfo | ActionMemberList | ActionMemberKick | ActionMemberBan | ActionMemberUnban | ActionGuildInfo | ActionGuildList | ActionChannelInfo | ActionChannelList | ActionChannelCreate | ActionChannelUpdate | ActionChannelDelete | ActionRoleList | ActionRoleCreate | ActionRoleUpdate | ActionRoleDelete | ActionRoleAssign | ActionRoleRemove | ActionMeInfo | ActionMeGuilds | ActionMeThreads | ActionMeFriends | ActionMessageGet | ActionGuildUpdate | ActionGuildLeave | ActionGuildMute | ActionMemberMute | ActionMemberAdmin | ActionMemberCard | ActionMemberTitle | ActionRequestFriend | ActionRequestGuild | ActionUserInfo | ActionMediaUpload | ActionMediaSendChannel | ActionMediaSendUser | ActionHistoryList | ActionPermissionGet | ActionPermissionSet | ActionReactionList | ActionMemberSearch | ActionChannelAnnounce | {
|
|
510
|
+
export type Actions = (ActionMessageSend | ActionMessageSendChannel | ActionMessageSendUser | ActionMessageDelete | ActionMessageEdit | ActionMessagePin | ActionMessageUnpin | ActionMentionGet | ActionReactionAdd | ActionReactionRemove | ActionFileSendChannel | ActionFileSendUser | ActionMessageForwardUser | ActionMessageForwardChannel | ActionMessageIntent | ActionMemberInfo | ActionMemberList | ActionMemberKick | ActionMemberBan | ActionMemberUnban | ActionGuildInfo | ActionGuildList | ActionChannelInfo | ActionChannelList | ActionChannelCreate | ActionChannelUpdate | ActionChannelDelete | ActionRoleList | ActionRoleCreate | ActionRoleUpdate | ActionRoleDelete | ActionRoleAssign | ActionRoleRemove | ActionMeInfo | ActionMeGuilds | ActionMeThreads | ActionMeFriends | ActionMessageGet | ActionGuildUpdate | ActionGuildLeave | ActionGuildMute | ActionMemberMute | ActionMemberAdmin | ActionMemberCard | ActionMemberTitle | ActionRequestFriend | ActionRequestGuild | ActionUserInfo | ActionMediaUpload | ActionMediaSendChannel | ActionMediaSendUser | ActionHistoryList | ActionPermissionGet | ActionPermissionSet | ActionReactionList | ActionMemberSearch | ActionChannelAnnounce | {
|
|
492
511
|
action: string;
|
|
493
512
|
payload: object;
|
|
494
513
|
}) & base;
|
package/lib/types/apis.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { StoreMiddlewareItem, StoreResponseItem } from '../store/res';
|
|
2
|
+
import type { Events } from '../event/map';
|
|
3
|
+
import { EventKeys } from '../event/map';
|
|
4
|
+
import type KoaRouter from 'koa-router';
|
|
2
5
|
type StroreParam = {
|
|
3
6
|
response: StoreResponseItem[];
|
|
4
7
|
responseMiddleware: {
|
|
@@ -6,10 +9,57 @@ type StroreParam = {
|
|
|
6
9
|
};
|
|
7
10
|
middleware: StoreMiddlewareItem[];
|
|
8
11
|
};
|
|
12
|
+
export type EventErrorPhase = 'middleware' | 'response' | 'subscribe' | 'route';
|
|
13
|
+
export type EventTraceReason = 'filtered' | 'completed' | 'consumed' | 'error';
|
|
14
|
+
export type RuntimeLifecycleStatus = 'discovered' | 'loading' | 'ready' | 'failed' | 'disposed';
|
|
15
|
+
export type EventStartContext<T extends EventKeys = EventKeys> = {
|
|
16
|
+
event: Events[T];
|
|
17
|
+
name: T;
|
|
18
|
+
};
|
|
19
|
+
export type EventFinishedContext<T extends EventKeys = EventKeys> = {
|
|
20
|
+
event: Events[T];
|
|
21
|
+
name: T;
|
|
22
|
+
reason: EventTraceReason;
|
|
23
|
+
duration: number;
|
|
24
|
+
hasSendAttempted: boolean;
|
|
25
|
+
hasSendSucceeded: boolean;
|
|
26
|
+
lastSendError: string | null;
|
|
27
|
+
};
|
|
28
|
+
export type EventErrorContext<T extends EventKeys = EventKeys> = {
|
|
29
|
+
event: Events[T];
|
|
30
|
+
error: unknown;
|
|
31
|
+
appName: string;
|
|
32
|
+
phase: EventErrorPhase;
|
|
33
|
+
};
|
|
34
|
+
export type HttpErrorKind = 'api' | 'web' | 'koa-router';
|
|
35
|
+
export type HttpErrorContext = {
|
|
36
|
+
ctx: KoaRouter.RouterContext;
|
|
37
|
+
error: unknown;
|
|
38
|
+
appName: string;
|
|
39
|
+
path: string;
|
|
40
|
+
method: string;
|
|
41
|
+
kind: HttpErrorKind;
|
|
42
|
+
};
|
|
43
|
+
export type RuntimeStatusChangeContext = {
|
|
44
|
+
appName: string;
|
|
45
|
+
previousStatus?: RuntimeLifecycleStatus;
|
|
46
|
+
status: RuntimeLifecycleStatus;
|
|
47
|
+
error?: {
|
|
48
|
+
message: string;
|
|
49
|
+
time: number;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
9
52
|
export type ChildrenCycle = {
|
|
10
53
|
onCreated?: () => void | Promise<void>;
|
|
11
54
|
onMounted?: (store: StroreParam) => void | Promise<void>;
|
|
55
|
+
onReady?: (store: StroreParam) => void | Promise<void>;
|
|
56
|
+
onEventStart?: <T extends EventKeys>(context: EventStartContext<T>) => void | Promise<void>;
|
|
57
|
+
onEventError?: <T extends EventKeys>(context: EventErrorContext<T>) => void | 'continue' | Promise<void | 'continue'>;
|
|
58
|
+
onEventFinished?: <T extends EventKeys>(context: EventFinishedContext<T>) => void | Promise<void>;
|
|
59
|
+
onHttpError?: (context: HttpErrorContext) => void | 'handled' | Promise<void | 'handled'>;
|
|
60
|
+
onRuntimeStatusChange?: (context: RuntimeStatusChangeContext) => void | Promise<void>;
|
|
12
61
|
unMounted?: (error: any) => void | Promise<void>;
|
|
62
|
+
onDispose?: (error?: unknown) => void | Promise<void>;
|
|
13
63
|
};
|
|
14
64
|
export type Next = (...cns: boolean[]) => void;
|
|
15
65
|
export type EventCycleEnum = 'create' | 'mount' | 'unmount';
|
|
@@ -35,6 +35,7 @@ export type OnDataFormatFunc = (...data: DataEnums[]) => DataEnums[];
|
|
|
35
35
|
export type OnGroupItem<C = any, T extends EventKeys = EventKeys> = OnResponseValue<C, T> | OnMiddlewareValue<C, T>;
|
|
36
36
|
export type OnGroupFunc = <C, T extends EventKeys, TFirst extends OnGroupItem<C, T>>(...calls: [TFirst, ...Array<TFirst>]) => TFirst;
|
|
37
37
|
export type ResponseRoute = {
|
|
38
|
+
appName?: string;
|
|
38
39
|
platform?: string | string[];
|
|
39
40
|
regular?: RegExp;
|
|
40
41
|
prefix?: string;
|