alemonjs 2.1.81 → 2.1.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/store.d.ts +2 -0
- package/lib/app/store.js +35 -12
- 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 +109 -16
- 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
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { getChildrenApp } from './store.js';
|
|
2
|
+
import { showErrorModule } from '../core/utils.js';
|
|
3
|
+
|
|
4
|
+
const dispatchEventError = async (context) => {
|
|
5
|
+
const app = getChildrenApp(context.appName);
|
|
6
|
+
const onEventError = app?.cycle?.onEventError;
|
|
7
|
+
if (!onEventError) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
try {
|
|
11
|
+
const result = await onEventError(context);
|
|
12
|
+
return result === 'continue';
|
|
13
|
+
}
|
|
14
|
+
catch (error) {
|
|
15
|
+
showErrorModule(error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'onEventError failed'));
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export { dispatchEventError };
|
|
@@ -1 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
import type { EventErrorPhase } from '../types';
|
|
2
|
+
export declare const createCallHandler: (valueEvent: any) => (currents: any, nextEvent: any, meta?: {
|
|
3
|
+
appName?: string;
|
|
4
|
+
phase?: EventErrorPhase;
|
|
5
|
+
}) => void;
|
|
@@ -3,9 +3,10 @@ import 'path';
|
|
|
3
3
|
import 'yaml';
|
|
4
4
|
import { showErrorModule } from '../core/utils.js';
|
|
5
5
|
import { withEventContext, finishCurrentTrace } from './hook-event-context.js';
|
|
6
|
+
import { dispatchEventError } from './event-error.js';
|
|
6
7
|
|
|
7
8
|
const createCallHandler = valueEvent => {
|
|
8
|
-
const callHandler = (currents, nextEvent) => {
|
|
9
|
+
const callHandler = (currents, nextEvent, meta) => {
|
|
9
10
|
let index = 0;
|
|
10
11
|
let isClose = false;
|
|
11
12
|
let isNext = false;
|
|
@@ -24,7 +25,10 @@ const createCallHandler = valueEvent => {
|
|
|
24
25
|
isNext = true;
|
|
25
26
|
nextEvent(...cns);
|
|
26
27
|
};
|
|
27
|
-
const res = await withEventContext(valueEvent, nextFn, () => currents[index](valueEvent, nextFn)
|
|
28
|
+
const res = await withEventContext(valueEvent, nextFn, () => currents[index](valueEvent, nextFn), {
|
|
29
|
+
appName: meta?.appName,
|
|
30
|
+
phase: meta?.phase
|
|
31
|
+
});
|
|
28
32
|
if (res !== true) {
|
|
29
33
|
if (!isNext) {
|
|
30
34
|
finishCurrentTrace('consumed');
|
|
@@ -35,7 +39,19 @@ const createCallHandler = valueEvent => {
|
|
|
35
39
|
}
|
|
36
40
|
catch (err) {
|
|
37
41
|
finishCurrentTrace('error');
|
|
42
|
+
const shouldContinue = meta?.appName && meta?.phase
|
|
43
|
+
? await dispatchEventError({
|
|
44
|
+
event: valueEvent,
|
|
45
|
+
error: err,
|
|
46
|
+
appName: meta.appName,
|
|
47
|
+
phase: meta.phase
|
|
48
|
+
})
|
|
49
|
+
: false;
|
|
38
50
|
showErrorModule(err);
|
|
51
|
+
if (shouldContinue) {
|
|
52
|
+
nextEvent();
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
39
55
|
return;
|
|
40
56
|
}
|
|
41
57
|
++index;
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { Next, Events, EventKeys, FileTreeNode, StoreResponseItem } from '../types';
|
|
2
2
|
export declare const clearModuleCache: (path?: string) => void;
|
|
3
3
|
export declare const createNextStep: <T extends EventKeys>(valueEvent: Events[T], select: T, next: Next, files: StoreResponseItem[], callHandler: (currents: any, nextEvent: any) => void) => Next;
|
|
4
|
-
export declare const createFileTreeStep: <T extends EventKeys>(valueEvent: Events[T], select: T, next: Next, root: FileTreeNode, callHandler: (currents: any, nextEvent: any
|
|
4
|
+
export declare const createFileTreeStep: <T extends EventKeys>(valueEvent: Events[T], select: T, next: Next, root: FileTreeNode, callHandler: (currents: any, nextEvent: any, meta?: {
|
|
5
|
+
appName?: string;
|
|
6
|
+
phase?: "middleware" | "response";
|
|
7
|
+
}) => void, phase: "middleware" | "response") => Next;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getCachedRegExp, showErrorModule } from '../core/utils.js';
|
|
2
2
|
import { EventMessageText } from '../core/variable.js';
|
|
3
|
+
import { dispatchEventError } from './event-error.js';
|
|
3
4
|
|
|
4
5
|
const moduleCache = new Map();
|
|
5
6
|
const shouldSkipFile = (file, select, valueEvent) => {
|
|
@@ -37,7 +38,7 @@ const loadModule = async (filePath) => {
|
|
|
37
38
|
moduleCache.set(filePath, mod);
|
|
38
39
|
return mod;
|
|
39
40
|
};
|
|
40
|
-
const callHandlerFile = async (valueEvent, select, file, nextStep, callback) => {
|
|
41
|
+
const callHandlerFile = async (valueEvent, select, file, nextStep, callback, phase) => {
|
|
41
42
|
try {
|
|
42
43
|
const app = await loadModule(file.path);
|
|
43
44
|
if (!app?.default?.current || !app?.default?.select) {
|
|
@@ -60,8 +61,16 @@ const callHandlerFile = async (valueEvent, select, file, nextStep, callback) =>
|
|
|
60
61
|
callback(app);
|
|
61
62
|
}
|
|
62
63
|
catch (err) {
|
|
64
|
+
const shouldContinue = await dispatchEventError({
|
|
65
|
+
event: valueEvent,
|
|
66
|
+
error: err,
|
|
67
|
+
appName: file.appName,
|
|
68
|
+
phase
|
|
69
|
+
});
|
|
63
70
|
showErrorModule(err);
|
|
64
|
-
|
|
71
|
+
if (shouldContinue) {
|
|
72
|
+
nextStep();
|
|
73
|
+
}
|
|
65
74
|
}
|
|
66
75
|
};
|
|
67
76
|
const createNextStep = (valueEvent, select, next, files, callHandler) => {
|
|
@@ -94,14 +103,14 @@ const createNextStep = (valueEvent, select, next, files, callHandler) => {
|
|
|
94
103
|
}, app => {
|
|
95
104
|
const currentsItem = Array.isArray(app.default.current) ? app.default.current : [app.default.current];
|
|
96
105
|
currents.push(...currentsItem);
|
|
97
|
-
});
|
|
106
|
+
}, 'response');
|
|
98
107
|
if (currents.length > 0) {
|
|
99
108
|
callHandler(currents, nextStep);
|
|
100
109
|
}
|
|
101
110
|
};
|
|
102
111
|
return nextStep;
|
|
103
112
|
};
|
|
104
|
-
const createFileTreeStep = (valueEvent, select, next, root, callHandler) => {
|
|
113
|
+
const createFileTreeStep = (valueEvent, select, next, root, callHandler, phase) => {
|
|
105
114
|
const processNode = (node, done) => {
|
|
106
115
|
if (node.middleware?.path) {
|
|
107
116
|
void checkMiddleware(node, done);
|
|
@@ -123,7 +132,7 @@ const createFileTreeStep = (valueEvent, select, next, root, callHandler) => {
|
|
|
123
132
|
matched = true;
|
|
124
133
|
const items = Array.isArray(app.default.current) ? app.default.current : [app.default.current];
|
|
125
134
|
mwCurrents.push(...items);
|
|
126
|
-
});
|
|
135
|
+
}, 'middleware');
|
|
127
136
|
if (matched) {
|
|
128
137
|
if (mwCurrents.length === 0) {
|
|
129
138
|
void processContent(node, done);
|
|
@@ -141,6 +150,9 @@ const createFileTreeStep = (valueEvent, select, next, root, callHandler) => {
|
|
|
141
150
|
return;
|
|
142
151
|
}
|
|
143
152
|
void processContent(node, done);
|
|
153
|
+
}, {
|
|
154
|
+
appName: node.middleware?.appName,
|
|
155
|
+
phase
|
|
144
156
|
});
|
|
145
157
|
}
|
|
146
158
|
};
|
|
@@ -174,8 +186,11 @@ const createFileTreeStep = (valueEvent, select, next, root, callHandler) => {
|
|
|
174
186
|
else {
|
|
175
187
|
processFiles(node, idx + 1, filesDone, treeDone);
|
|
176
188
|
}
|
|
189
|
+
}, {
|
|
190
|
+
appName: file.appName,
|
|
191
|
+
phase
|
|
177
192
|
});
|
|
178
|
-
});
|
|
193
|
+
}, phase);
|
|
179
194
|
};
|
|
180
195
|
const processChildNodes = (node, done) => {
|
|
181
196
|
const childKeys = Array.from(node.children.keys());
|
|
@@ -1,2 +1,5 @@
|
|
|
1
1
|
import { Next, Events, EventKeys, ResponseRoute } from '../types';
|
|
2
|
-
export declare const createRouteProcessChildren: <T extends EventKeys>(valueEvent: Events[T], select: T, nextCycle: Next, callHandler: (currents: any, nextEvent: any
|
|
2
|
+
export declare const createRouteProcessChildren: <T extends EventKeys>(valueEvent: Events[T], select: T, nextCycle: Next, callHandler: (currents: any, nextEvent: any, meta?: {
|
|
3
|
+
appName?: string;
|
|
4
|
+
phase?: "route";
|
|
5
|
+
}) => void, phase: "route") => (nodes: ResponseRoute[], _pending: any[], next: () => Promise<void> | void) => void;
|
|
@@ -3,6 +3,7 @@ import 'fs';
|
|
|
3
3
|
import 'path';
|
|
4
4
|
import 'yaml';
|
|
5
5
|
import { getCachedRegExp, showErrorModule } from '../core/utils.js';
|
|
6
|
+
import { dispatchEventError } from './event-error.js';
|
|
6
7
|
|
|
7
8
|
const AsyncFunction = (async () => { }).constructor;
|
|
8
9
|
function isAsyncFunction(fn) {
|
|
@@ -11,7 +12,7 @@ function isAsyncFunction(fn) {
|
|
|
11
12
|
function isFunction(value) {
|
|
12
13
|
return isAsyncFunction(value) || typeof value === 'function' || value instanceof Function;
|
|
13
14
|
}
|
|
14
|
-
const createRouteProcessChildren = (valueEvent, select, nextCycle, callHandler) => {
|
|
15
|
+
const createRouteProcessChildren = (valueEvent, select, nextCycle, callHandler, phase) => {
|
|
15
16
|
const handlerResultCache = new Map();
|
|
16
17
|
const collectHandlers = (tail) => {
|
|
17
18
|
const result = [];
|
|
@@ -126,11 +127,24 @@ const createRouteProcessChildren = (valueEvent, select, nextCycle, callHandler)
|
|
|
126
127
|
return;
|
|
127
128
|
}
|
|
128
129
|
void nextNode();
|
|
130
|
+
}, {
|
|
131
|
+
appName: node.appName,
|
|
132
|
+
phase
|
|
129
133
|
});
|
|
130
134
|
}
|
|
131
135
|
catch (err) {
|
|
136
|
+
const shouldContinue = typeof node.appName === 'string'
|
|
137
|
+
? await dispatchEventError({
|
|
138
|
+
event: valueEvent,
|
|
139
|
+
error: err,
|
|
140
|
+
appName: node.appName,
|
|
141
|
+
phase
|
|
142
|
+
})
|
|
143
|
+
: false;
|
|
132
144
|
showErrorModule(err);
|
|
133
|
-
|
|
145
|
+
if (shouldContinue) {
|
|
146
|
+
void nextNode();
|
|
147
|
+
}
|
|
134
148
|
}
|
|
135
149
|
};
|
|
136
150
|
void nextNode();
|
|
@@ -8,10 +8,10 @@ const responseRouterSingleton = new ResponseRouter();
|
|
|
8
8
|
const expendEvent = (valueEvent, select, next) => {
|
|
9
9
|
const root = responseTreeSingleton.value;
|
|
10
10
|
const callHandler = createCallHandler(valueEvent);
|
|
11
|
-
const nextEvent = createFileTreeStep(valueEvent, select, next, root, callHandler);
|
|
11
|
+
const nextEvent = createFileTreeStep(valueEvent, select, next, root, callHandler, 'response');
|
|
12
12
|
const routes = responseRouterSingleton.value;
|
|
13
13
|
const callRouteHandler = createCallHandler(valueEvent);
|
|
14
|
-
const processChildren = createRouteProcessChildren(valueEvent, select, nextEvent, callRouteHandler);
|
|
14
|
+
const processChildren = createRouteProcessChildren(valueEvent, select, nextEvent, callRouteHandler, 'route');
|
|
15
15
|
void processChildren(routes, [], nextEvent);
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -8,10 +8,10 @@ const middlewareRouterSingleton = new MiddlewareRouter();
|
|
|
8
8
|
const expendMiddleware = (valueEvent, select, next) => {
|
|
9
9
|
const root = middlewareTreeSingleton.value;
|
|
10
10
|
const callHandler = createCallHandler(valueEvent);
|
|
11
|
-
const nextMiddleware = createFileTreeStep(valueEvent, select, next, root, callHandler);
|
|
11
|
+
const nextMiddleware = createFileTreeStep(valueEvent, select, next, root, callHandler, 'middleware');
|
|
12
12
|
const routes = middlewareRouterSingleton.value;
|
|
13
13
|
const callRouteHandler = createCallHandler(valueEvent);
|
|
14
|
-
const processChildren = createRouteProcessChildren(valueEvent, select, nextMiddleware, callRouteHandler);
|
|
14
|
+
const processChildren = createRouteProcessChildren(valueEvent, select, nextMiddleware, callRouteHandler, 'route');
|
|
15
15
|
void processChildren(routes, [], nextMiddleware);
|
|
16
16
|
};
|
|
17
17
|
|
|
@@ -5,6 +5,7 @@ import { showErrorModule } from '../core/utils.js';
|
|
|
5
5
|
import { getSubscribeList } from './store.js';
|
|
6
6
|
import { SubscribeStatus } from './config.js';
|
|
7
7
|
import { withEventContext, finishCurrentTrace } from './hook-event-context.js';
|
|
8
|
+
import { dispatchEventError } from './event-error.js';
|
|
8
9
|
|
|
9
10
|
const expendSubscribe = (valueEvent, select, next, choose) => {
|
|
10
11
|
const subListValue = getSubscribeList(choose, select);
|
|
@@ -64,15 +65,29 @@ const expendSubscribe = (valueEvent, select, next, choose) => {
|
|
|
64
65
|
}
|
|
65
66
|
};
|
|
66
67
|
try {
|
|
67
|
-
const result = withEventContext(valueEvent, Continue, () => item.data.current(valueEvent, Continue)
|
|
68
|
+
const result = withEventContext(valueEvent, Continue, () => item.data.current(valueEvent, Continue), {
|
|
69
|
+
appName: item.data.appName,
|
|
70
|
+
phase: 'subscribe'
|
|
71
|
+
});
|
|
68
72
|
if (result && typeof result.then === 'function') {
|
|
69
73
|
void result.then(() => {
|
|
70
74
|
if (!isContinue) {
|
|
71
75
|
finishCurrentTrace('consumed');
|
|
72
76
|
}
|
|
73
|
-
}, error => {
|
|
77
|
+
}, async (error) => {
|
|
74
78
|
finishCurrentTrace('error');
|
|
79
|
+
const shouldContinue = typeof item.data.appName === 'string'
|
|
80
|
+
? await dispatchEventError({
|
|
81
|
+
event: valueEvent,
|
|
82
|
+
error,
|
|
83
|
+
appName: item.data.appName,
|
|
84
|
+
phase: 'subscribe'
|
|
85
|
+
})
|
|
86
|
+
: false;
|
|
75
87
|
showErrorModule(error);
|
|
88
|
+
if (shouldContinue) {
|
|
89
|
+
nextObserver(true);
|
|
90
|
+
}
|
|
76
91
|
});
|
|
77
92
|
return;
|
|
78
93
|
}
|
|
@@ -82,7 +97,20 @@ const expendSubscribe = (valueEvent, select, next, choose) => {
|
|
|
82
97
|
}
|
|
83
98
|
catch (error) {
|
|
84
99
|
finishCurrentTrace('error');
|
|
85
|
-
|
|
100
|
+
void (async () => {
|
|
101
|
+
const shouldContinue = typeof item.data.appName === 'string'
|
|
102
|
+
? await dispatchEventError({
|
|
103
|
+
event: valueEvent,
|
|
104
|
+
error,
|
|
105
|
+
appName: item.data.appName,
|
|
106
|
+
phase: 'subscribe'
|
|
107
|
+
})
|
|
108
|
+
: false;
|
|
109
|
+
showErrorModule(error);
|
|
110
|
+
if (shouldContinue) {
|
|
111
|
+
nextObserver(true);
|
|
112
|
+
}
|
|
113
|
+
})();
|
|
86
114
|
}
|
|
87
115
|
};
|
|
88
116
|
nextObserver();
|
|
@@ -4,6 +4,7 @@ import { expendCycle } from './event-processor-cycle.js';
|
|
|
4
4
|
import { withProcessorTrace, finishCurrentTrace } from './hook-event-context.js';
|
|
5
5
|
import { ProcessorEventAutoClearMap, ProcessorEventUserAutoClearMap } from './store.js';
|
|
6
6
|
import { getCachedRegExp, matchIn, fastHash } from '../core/utils.js';
|
|
7
|
+
import { dispatchEventStart } from './lifecycle-callbacks.js';
|
|
7
8
|
|
|
8
9
|
const filter = ({ Now, store, INTERVAL }, MessageId) => {
|
|
9
10
|
if (store.has(MessageId)) {
|
|
@@ -59,8 +60,12 @@ const callback = () => {
|
|
|
59
60
|
};
|
|
60
61
|
setTimeout(callback, processorRepeatedClearTimeMin);
|
|
61
62
|
const onProcessor = (name, event, data) => {
|
|
62
|
-
withProcessorTrace(name, event, () => {
|
|
63
|
+
void withProcessorTrace(name, event, async () => {
|
|
63
64
|
try {
|
|
65
|
+
await dispatchEventStart({
|
|
66
|
+
event,
|
|
67
|
+
name
|
|
68
|
+
});
|
|
64
69
|
const value = getConfigValue();
|
|
65
70
|
const disabledTextRegular = value?.disabled_text_regular;
|
|
66
71
|
if (disabledTextRegular && event['MessageText']) {
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
import { Result } from '../core';
|
|
2
|
-
import { EventKeys, Events } from '../types';
|
|
3
|
-
export
|
|
4
|
-
|
|
2
|
+
import { EventErrorPhase, EventKeys, Events, EventTraceReason } from '../types';
|
|
3
|
+
export declare const withEventContext: <T extends EventKeys, R>(event: Events[T], next: (...args: boolean[]) => void, runner: () => R, options?: {
|
|
4
|
+
appName?: string;
|
|
5
|
+
phase?: EventErrorPhase;
|
|
6
|
+
}) => R;
|
|
5
7
|
export declare const withProcessorTrace: <T extends EventKeys, R>(select: T, event: Events[T], runner: () => R) => R;
|
|
6
8
|
export declare const getCurrentEvent: <T extends EventKeys>() => Events[T] | undefined;
|
|
7
9
|
export declare const getCurrentNext: () => ((...args: boolean[]) => void) | undefined;
|
|
10
|
+
export declare const getCurrentAppName: () => string | undefined;
|
|
11
|
+
export declare const getCurrentPhase: () => EventErrorPhase | undefined;
|
|
8
12
|
export declare const finishCurrentTrace: (reason: EventTraceReason) => void;
|
|
9
13
|
export declare const markEventSendAttempt: <T extends EventKeys>(event?: Events[T]) => void;
|
|
10
14
|
export declare const markEventSendSuccess: <T extends EventKeys>(event?: Events[T]) => void;
|
|
@@ -2,6 +2,7 @@ import { AsyncLocalStorage } from 'node:async_hooks';
|
|
|
2
2
|
import { performance } from 'node:perf_hooks';
|
|
3
3
|
import { getConfigValue } from '../core/config.js';
|
|
4
4
|
import { ResultCode } from '../core/variable.js';
|
|
5
|
+
import { dispatchEventFinished } from './lifecycle-callbacks.js';
|
|
5
6
|
|
|
6
7
|
const eventStore = new AsyncLocalStorage();
|
|
7
8
|
const shouldShowLog = (event) => {
|
|
@@ -61,19 +62,31 @@ const createEventTrace = (select) => {
|
|
|
61
62
|
message: 'event processor finished',
|
|
62
63
|
data: createLogData(event, trace.select, reason, duration)
|
|
63
64
|
});
|
|
64
|
-
return;
|
|
65
65
|
}
|
|
66
|
-
|
|
66
|
+
else {
|
|
67
|
+
logger.info(createLogText(event, trace.select, reason, duration));
|
|
68
|
+
}
|
|
69
|
+
void dispatchEventFinished({
|
|
70
|
+
event,
|
|
71
|
+
name: trace.select,
|
|
72
|
+
reason,
|
|
73
|
+
duration,
|
|
74
|
+
hasSendAttempted: event._sendAttempted === true || event._has_send_attempt === true,
|
|
75
|
+
hasSendSucceeded: event._sendSucceeded === true || event._has_send_success === true,
|
|
76
|
+
lastSendError: event._lastSendError ?? event._last_send_error ?? null
|
|
77
|
+
});
|
|
67
78
|
}
|
|
68
79
|
};
|
|
69
80
|
return trace;
|
|
70
81
|
};
|
|
71
|
-
const withEventContext = (event, next, runner) => {
|
|
82
|
+
const withEventContext = (event, next, runner, options) => {
|
|
72
83
|
const current = eventStore.getStore();
|
|
73
84
|
return eventStore.run({
|
|
74
85
|
event,
|
|
75
86
|
next,
|
|
76
|
-
trace: current?.trace
|
|
87
|
+
trace: current?.trace,
|
|
88
|
+
appName: options?.appName ?? current?.appName,
|
|
89
|
+
phase: options?.phase ?? current?.phase
|
|
77
90
|
}, runner);
|
|
78
91
|
};
|
|
79
92
|
const withProcessorTrace = (select, event, runner) => {
|
|
@@ -90,6 +103,12 @@ const getCurrentEvent = () => {
|
|
|
90
103
|
const getCurrentNext = () => {
|
|
91
104
|
return eventStore.getStore()?.next;
|
|
92
105
|
};
|
|
106
|
+
const getCurrentAppName = () => {
|
|
107
|
+
return eventStore.getStore()?.appName;
|
|
108
|
+
};
|
|
109
|
+
const getCurrentPhase = () => {
|
|
110
|
+
return eventStore.getStore()?.phase;
|
|
111
|
+
};
|
|
93
112
|
const finishCurrentTrace = (reason) => {
|
|
94
113
|
eventStore.getStore()?.trace?.finish(reason);
|
|
95
114
|
};
|
|
@@ -144,4 +163,4 @@ const recordEventSendResults = (results, event) => {
|
|
|
144
163
|
}
|
|
145
164
|
};
|
|
146
165
|
|
|
147
|
-
export { finishCurrentTrace, getCurrentEvent, getCurrentNext, markEventSendAttempt, markEventSendFailure, markEventSendSuccess, recordEventSendResults, withEventContext, withProcessorTrace };
|
|
166
|
+
export { finishCurrentTrace, getCurrentAppName, getCurrentEvent, getCurrentNext, getCurrentPhase, markEventSendAttempt, markEventSendFailure, markEventSendSuccess, recordEventSendResults, withEventContext, withProcessorTrace };
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { ResultCode } from '../../core/variable.js';
|
|
2
2
|
import { SubscribeList } from '../store.js';
|
|
3
3
|
import { SubscribeStatus } from '../config.js';
|
|
4
|
-
import { getCurrentEvent } from '../hook-event-context.js';
|
|
4
|
+
import { getCurrentEvent, getCurrentAppName } from '../hook-event-context.js';
|
|
5
5
|
|
|
6
6
|
function useSubscribe(eventOrSelects, maybeSelects) {
|
|
7
7
|
const selects = (maybeSelects === undefined ? eventOrSelects : maybeSelects);
|
|
8
8
|
const event = (maybeSelects === undefined ? undefined : eventOrSelects);
|
|
9
9
|
const valueEvent = event ?? getCurrentEvent();
|
|
10
|
+
const appName = getCurrentAppName();
|
|
10
11
|
if (typeof valueEvent !== 'object' || valueEvent === null) {
|
|
11
12
|
logger.error({
|
|
12
13
|
code: ResultCode.FailParams,
|
|
@@ -50,6 +51,7 @@ function useSubscribe(eventOrSelects, maybeSelects) {
|
|
|
50
51
|
}
|
|
51
52
|
}
|
|
52
53
|
subList.value.append({
|
|
54
|
+
appName,
|
|
53
55
|
choose,
|
|
54
56
|
selects: curSelects,
|
|
55
57
|
keys: values,
|
package/lib/app/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
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 './store.js';
|
|
1
|
+
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 './store.js';
|
|
2
2
|
export { Expose, clearAllExpose, disposeExpose, registerExpose } from './expose.js';
|
|
3
3
|
export { loadModels, run } from './load_modules/load.js';
|
|
4
4
|
export { loadChildren, loadChildrenFile } from './load_modules/loadChild.js';
|
|
@@ -35,7 +35,7 @@ export { useUser } from './hook-use/user.js';
|
|
|
35
35
|
export { useObserver, useSubscribe } from './hook-use/subscribe.js';
|
|
36
36
|
export { createEvent, useEvent } from './hook-use/event.js';
|
|
37
37
|
export { clearInterval, clearTimeout, listSchedule, pauseSchedule, resumeSchedule, setCron, setInterval, setTimeout } from './api/schedule.js';
|
|
38
|
-
export { finishCurrentTrace, getCurrentEvent, getCurrentNext, markEventSendAttempt, markEventSendFailure, markEventSendSuccess, recordEventSendResults, withEventContext, withProcessorTrace } from './hook-event-context.js';
|
|
38
|
+
export { finishCurrentTrace, getCurrentAppName, getCurrentEvent, getCurrentNext, getCurrentPhase, markEventSendAttempt, markEventSendFailure, markEventSendSuccess, recordEventSendResults, withEventContext, withProcessorTrace } from './hook-event-context.js';
|
|
39
39
|
export { registerAppDir, scheduleCancel, scheduleCancelAll, scheduleCancelByApp, scheduleCron, scheduleInterval, scheduleList, schedulePause, scheduleResume, scheduleTimeout, unregisterAppDir } from './schedule-store.js';
|
|
40
40
|
export { createEventValue, createSelects, onSelects, onState, unChildren, unState, useState } from './event-utils.js';
|
|
41
41
|
export { MessageDirect, createDataFormat, format, getMessageIntent, sendToChannel, sendToUser } from './message-api.js';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { EventFinishedContext, EventStartContext, HttpErrorContext, RuntimeStatusChangeContext } from '../types';
|
|
2
|
+
export declare const dispatchEventStart: (context: EventStartContext) => Promise<void>;
|
|
3
|
+
export declare const dispatchEventFinished: (context: EventFinishedContext) => Promise<void>;
|
|
4
|
+
export declare const dispatchHttpError: (context: HttpErrorContext) => Promise<boolean>;
|
|
5
|
+
export declare const dispatchRuntimeStatusChange: (context: RuntimeStatusChangeContext) => Promise<void>;
|
|
6
|
+
export declare const dispatchAppReady: (appName: string, store: {
|
|
7
|
+
response: any[];
|
|
8
|
+
responseMiddleware: {
|
|
9
|
+
[key: string]: any;
|
|
10
|
+
};
|
|
11
|
+
middleware: any[];
|
|
12
|
+
}) => Promise<void>;
|
|
13
|
+
export declare const dispatchAppDispose: (appName: string, error?: unknown) => Promise<void>;
|
|
14
|
+
export declare const dispatchDisposeAllApps: (error?: unknown) => Promise<void>;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { showErrorModule } from '../core/utils.js';
|
|
2
|
+
|
|
3
|
+
const swallowLifecycleError = (error) => {
|
|
4
|
+
showErrorModule(error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Unknown lifecycle error'));
|
|
5
|
+
};
|
|
6
|
+
const getChildrenApps = () => {
|
|
7
|
+
return Object.values(global.alemonjsCore?.storeChildrenApp ?? {});
|
|
8
|
+
};
|
|
9
|
+
const getChildrenApp = (name) => {
|
|
10
|
+
return global.alemonjsCore?.storeChildrenApp?.[name] ?? null;
|
|
11
|
+
};
|
|
12
|
+
const dispatchEventStart = async (context) => {
|
|
13
|
+
const apps = getChildrenApps();
|
|
14
|
+
for (const app of apps) {
|
|
15
|
+
try {
|
|
16
|
+
await app.cycle?.onEventStart?.(context);
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
swallowLifecycleError(error);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
const dispatchEventFinished = async (context) => {
|
|
24
|
+
const apps = getChildrenApps();
|
|
25
|
+
for (const app of apps) {
|
|
26
|
+
try {
|
|
27
|
+
await app.cycle?.onEventFinished?.(context);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
swallowLifecycleError(error);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
const dispatchHttpError = async (context) => {
|
|
35
|
+
const app = getChildrenApp(context.appName);
|
|
36
|
+
const handler = app?.cycle?.onHttpError;
|
|
37
|
+
if (!handler) {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const result = await handler(context);
|
|
42
|
+
return result === 'handled';
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
swallowLifecycleError(error);
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
};
|
|
49
|
+
const dispatchRuntimeStatusChange = async (context) => {
|
|
50
|
+
const app = getChildrenApp(context.appName);
|
|
51
|
+
const handler = app?.cycle?.onRuntimeStatusChange;
|
|
52
|
+
if (!handler) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
await handler(context);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
swallowLifecycleError(error);
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
const dispatchAppReady = async (appName, store) => {
|
|
63
|
+
const app = getChildrenApp(appName);
|
|
64
|
+
const handler = app?.cycle?.onReady;
|
|
65
|
+
if (!handler) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
await handler(store);
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
const dispatchAppDispose = async (appName, error) => {
|
|
76
|
+
const app = getChildrenApp(appName);
|
|
77
|
+
if (!app?.cycle) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
if (app.cycle.onDispose) {
|
|
82
|
+
await app.cycle.onDispose(error);
|
|
83
|
+
}
|
|
84
|
+
if (app.cycle.unMounted) {
|
|
85
|
+
await app.cycle.unMounted(error);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
catch (disposeError) {
|
|
89
|
+
swallowLifecycleError(disposeError);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
const dispatchDisposeAllApps = async (error) => {
|
|
93
|
+
const apps = getChildrenApps();
|
|
94
|
+
for (const app of apps) {
|
|
95
|
+
await dispatchAppDispose(app.name, error);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
export { dispatchAppDispose, dispatchAppReady, dispatchDisposeAllApps, dispatchEventFinished, dispatchEventStart, dispatchHttpError, dispatchRuntimeStatusChange };
|
|
@@ -6,6 +6,7 @@ import { registerExpose } from '../expose.js';
|
|
|
6
6
|
import { ResultCode, fileSuffixMiddleware } from '../../core/variable.js';
|
|
7
7
|
import { registerAppDir, scheduleCancelByApp, unregisterAppDir } from '../schedule-store.js';
|
|
8
8
|
import module$1 from 'module';
|
|
9
|
+
import { dispatchRuntimeStatusChange, dispatchAppDispose, dispatchAppReady } from '../lifecycle-callbacks.js';
|
|
9
10
|
|
|
10
11
|
const initRequire = () => { };
|
|
11
12
|
initRequire.resolve = () => '';
|
|
@@ -89,21 +90,19 @@ const loadChildren = async (mainPath, appName) => {
|
|
|
89
90
|
app = await moduleApp.default.callback();
|
|
90
91
|
}
|
|
91
92
|
App.pushCycle(app);
|
|
93
|
+
await dispatchRuntimeStatusChange({
|
|
94
|
+
appName,
|
|
95
|
+
previousStatus: 'discovered',
|
|
96
|
+
status: 'loading'
|
|
97
|
+
});
|
|
92
98
|
const unMounted = async (e) => {
|
|
93
99
|
showErrorModule(e);
|
|
94
100
|
clearRuntimeAppKoaRouters(appName);
|
|
95
101
|
updateRuntimeAppStatus(appName, 'failed', e);
|
|
96
102
|
scheduleCancelByApp(appName);
|
|
97
103
|
unregisterAppDir(appName);
|
|
104
|
+
await dispatchAppDispose(appName, e);
|
|
98
105
|
App.un();
|
|
99
|
-
try {
|
|
100
|
-
if (app?.unMounted) {
|
|
101
|
-
await app.unMounted(e);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
catch (e) {
|
|
105
|
-
showErrorModule(e);
|
|
106
|
-
}
|
|
107
106
|
};
|
|
108
107
|
try {
|
|
109
108
|
if (app?.onCreated) {
|
|
@@ -133,10 +132,12 @@ const loadChildren = async (mainPath, appName) => {
|
|
|
133
132
|
expose: hasExposeCapability
|
|
134
133
|
});
|
|
135
134
|
App.on();
|
|
135
|
+
const emptyStore = { response: [], responseMiddleware: {}, middleware: [] };
|
|
136
136
|
try {
|
|
137
137
|
if (app?.onMounted) {
|
|
138
|
-
await app.onMounted(
|
|
138
|
+
await app.onMounted(emptyStore);
|
|
139
139
|
}
|
|
140
|
+
await dispatchAppReady(appName, emptyStore);
|
|
140
141
|
updateRuntimeAppStatus(appName, 'ready');
|
|
141
142
|
}
|
|
142
143
|
catch (e) {
|
|
@@ -202,10 +203,12 @@ const loadChildren = async (mainPath, appName) => {
|
|
|
202
203
|
event: resData.length > 0 || Object.keys(resAndMwData).length > 0 || mwData.length > 0
|
|
203
204
|
});
|
|
204
205
|
App.on();
|
|
206
|
+
const mountedStore = { response: resData, responseMiddleware: resAndMwData, middleware: mwData };
|
|
205
207
|
try {
|
|
206
208
|
if (app?.onMounted) {
|
|
207
|
-
await app.onMounted(
|
|
209
|
+
await app.onMounted(mountedStore);
|
|
208
210
|
}
|
|
211
|
+
await dispatchAppReady(appName, mountedStore);
|
|
209
212
|
updateRuntimeAppStatus(appName, 'ready');
|
|
210
213
|
}
|
|
211
214
|
catch (e) {
|
package/lib/app/store.d.ts
CHANGED
|
@@ -187,6 +187,8 @@ export declare class ChildrenApp {
|
|
|
187
187
|
un(): void;
|
|
188
188
|
get value(): import("../types").StoreChildrenApp;
|
|
189
189
|
}
|
|
190
|
+
export declare const getChildrenApp: (name: string) => import("../types").StoreChildrenApp;
|
|
191
|
+
export declare const listChildrenApps: () => import("../types").StoreChildrenApp[];
|
|
190
192
|
export declare const ProcessorEventAutoClearMap: Map<any, any>;
|
|
191
193
|
export declare const ProcessorEventUserAutoClearMap: Map<any, any>;
|
|
192
194
|
export declare const logger: any;
|
package/lib/app/store.js
CHANGED
|
@@ -2,6 +2,7 @@ import { SinglyLinkedList } from './SinglyLinkedList.js';
|
|
|
2
2
|
import { mkdirSync } from 'node:fs';
|
|
3
3
|
import log4js from 'log4js';
|
|
4
4
|
import { disposeExpose } from './expose.js';
|
|
5
|
+
import { dispatchRuntimeStatusChange } from './lifecycle-callbacks.js';
|
|
5
6
|
|
|
6
7
|
const createLogger = () => {
|
|
7
8
|
if (process.env.BROWSER_ENV === 'browser') {
|
|
@@ -157,11 +158,7 @@ const normalizeRuntimeAppError = (error) => {
|
|
|
157
158
|
};
|
|
158
159
|
};
|
|
159
160
|
const sameRuntimeAppCapabilities = (left, right) => {
|
|
160
|
-
return (left.event === right.event &&
|
|
161
|
-
left.httpApi === right.httpApi &&
|
|
162
|
-
left.web === right.web &&
|
|
163
|
-
left.schedule === right.schedule &&
|
|
164
|
-
left.expose === right.expose);
|
|
161
|
+
return (left.event === right.event && left.httpApi === right.httpApi && left.web === right.web && left.schedule === right.schedule && left.expose === right.expose);
|
|
165
162
|
};
|
|
166
163
|
const sameRuntimeAppError = (left, right) => {
|
|
167
164
|
if (!left && !right) {
|
|
@@ -205,7 +202,7 @@ const registerRuntimeApp = (record) => {
|
|
|
205
202
|
updatedAt: now
|
|
206
203
|
};
|
|
207
204
|
if (!current || current.status !== record.status) {
|
|
208
|
-
logRuntimeAppStatus('
|
|
205
|
+
logRuntimeAppStatus(record.status === 'failed' ? 'warn' : 'debug', runtimeApps[record.name]);
|
|
209
206
|
}
|
|
210
207
|
return runtimeApps[record.name];
|
|
211
208
|
};
|
|
@@ -216,13 +213,26 @@ const updateRuntimeAppStatus = (name, status, error) => {
|
|
|
216
213
|
return;
|
|
217
214
|
}
|
|
218
215
|
const normalizedError = normalizeRuntimeAppError(error);
|
|
216
|
+
const previousStatus = current.status;
|
|
219
217
|
if (current.status === status && sameRuntimeAppError(current.error, normalizedError)) {
|
|
220
218
|
return current;
|
|
221
219
|
}
|
|
222
220
|
current.status = status;
|
|
223
221
|
current.updatedAt = Date.now();
|
|
224
222
|
current.error = normalizedError;
|
|
225
|
-
|
|
223
|
+
const level = status === 'failed' ? 'warn' : status === 'disposed' ? 'info' : 'debug';
|
|
224
|
+
logRuntimeAppStatus(level, current);
|
|
225
|
+
void dispatchRuntimeStatusChange({
|
|
226
|
+
appName: name,
|
|
227
|
+
previousStatus,
|
|
228
|
+
status,
|
|
229
|
+
error: normalizedError
|
|
230
|
+
? {
|
|
231
|
+
message: normalizedError.message,
|
|
232
|
+
time: normalizedError.time
|
|
233
|
+
}
|
|
234
|
+
: undefined
|
|
235
|
+
});
|
|
226
236
|
return current;
|
|
227
237
|
};
|
|
228
238
|
const updateRuntimeAppCapabilities = (name, capabilities) => {
|
|
@@ -411,6 +421,13 @@ function mergeFileTree(target, source) {
|
|
|
411
421
|
}
|
|
412
422
|
}
|
|
413
423
|
}
|
|
424
|
+
const attachRouteAppName = (appName, routes = []) => {
|
|
425
|
+
return routes.map(route => ({
|
|
426
|
+
...route,
|
|
427
|
+
appName,
|
|
428
|
+
children: route.children ? attachRouteAppName(appName, route.children) : route.children
|
|
429
|
+
}));
|
|
430
|
+
};
|
|
414
431
|
class MiddlewareTree {
|
|
415
432
|
#cache = null;
|
|
416
433
|
#cacheVersion = -1;
|
|
@@ -459,10 +476,10 @@ class ResponseRouter {
|
|
|
459
476
|
return [];
|
|
460
477
|
}
|
|
461
478
|
if (alemonjsCore.storeChildrenApp[key].register?.responseRouter) {
|
|
462
|
-
return alemonjsCore.storeChildrenApp[key].register?.responseRouter?.current ?? [];
|
|
479
|
+
return attachRouteAppName(key, alemonjsCore.storeChildrenApp[key].register?.responseRouter?.current ?? []);
|
|
463
480
|
}
|
|
464
481
|
if (alemonjsCore.storeChildrenApp[key].register?.response) {
|
|
465
|
-
return alemonjsCore.storeChildrenApp[key].register?.response?.current ?? [];
|
|
482
|
+
return attachRouteAppName(key, alemonjsCore.storeChildrenApp[key].register?.response?.current ?? []);
|
|
466
483
|
}
|
|
467
484
|
return [];
|
|
468
485
|
});
|
|
@@ -483,10 +500,10 @@ class MiddlewareRouter {
|
|
|
483
500
|
return [];
|
|
484
501
|
}
|
|
485
502
|
if (alemonjsCore.storeChildrenApp[key].register?.middlewareRouter) {
|
|
486
|
-
return alemonjsCore.storeChildrenApp[key].register?.middlewareRouter?.current ?? [];
|
|
503
|
+
return attachRouteAppName(key, alemonjsCore.storeChildrenApp[key].register?.middlewareRouter?.current ?? []);
|
|
487
504
|
}
|
|
488
505
|
if (alemonjsCore.storeChildrenApp[key].register?.middleware) {
|
|
489
|
-
return alemonjsCore.storeChildrenApp[key].register?.middleware?.current ?? [];
|
|
506
|
+
return attachRouteAppName(key, alemonjsCore.storeChildrenApp[key].register?.middleware?.current ?? []);
|
|
490
507
|
}
|
|
491
508
|
return [];
|
|
492
509
|
});
|
|
@@ -635,6 +652,12 @@ class ChildrenApp {
|
|
|
635
652
|
return alemonjsCore.storeChildrenApp[this.#name];
|
|
636
653
|
}
|
|
637
654
|
}
|
|
655
|
+
const getChildrenApp = (name) => {
|
|
656
|
+
return alemonjsCore.storeChildrenApp[name] ?? null;
|
|
657
|
+
};
|
|
658
|
+
const listChildrenApps = () => {
|
|
659
|
+
return Object.values(alemonjsCore.storeChildrenApp);
|
|
660
|
+
};
|
|
638
661
|
const ProcessorEventAutoClearMap = new Map();
|
|
639
662
|
const ProcessorEventUserAutoClearMap = new Map();
|
|
640
663
|
const logger = new Logger().value;
|
|
@@ -648,4 +671,4 @@ process?.on?.('exit', code => {
|
|
|
648
671
|
logger.info?.(`[alemonjs][exit] 进程退出,code=${code}`);
|
|
649
672
|
});
|
|
650
673
|
|
|
651
|
-
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 };
|
|
674
|
+
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 };
|
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 = () => '';
|
|
@@ -104,14 +105,41 @@ 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 beforeMatched = Array.isArray(ctx.matched) ? ctx.matched.length : 0;
|
|
110
|
+
await koaRouter.routes()(ctx, async () => { });
|
|
111
|
+
const afterMatched = Array.isArray(ctx.matched) ? ctx.matched.length : 0;
|
|
112
|
+
if (afterMatched <= beforeMatched) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
await koaRouter.allowedMethods()(ctx, async () => { });
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
const handled = await dispatchHttpError({
|
|
120
|
+
ctx,
|
|
121
|
+
error,
|
|
122
|
+
appName: item.name,
|
|
123
|
+
path: ctx.path,
|
|
124
|
+
method: ctx.method,
|
|
125
|
+
kind: 'koa-router'
|
|
126
|
+
});
|
|
127
|
+
if (handled) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
logger.warn({
|
|
131
|
+
code: ResultCode.Fail,
|
|
132
|
+
message: `Error request ${ctx.path}:`,
|
|
133
|
+
data: error instanceof Error ? error.message : String(error)
|
|
134
|
+
});
|
|
135
|
+
ctx.status = 500;
|
|
136
|
+
ctx.body = {
|
|
137
|
+
code: 500,
|
|
138
|
+
message: '处理 Koa Router 请求时发生错误。',
|
|
139
|
+
error: error instanceof Error ? error.message : String(error)
|
|
140
|
+
};
|
|
141
|
+
return true;
|
|
112
142
|
}
|
|
113
|
-
await koaRouter.allowedMethods()(ctx, async () => { });
|
|
114
|
-
return true;
|
|
115
143
|
}
|
|
116
144
|
}
|
|
117
145
|
return false;
|
|
@@ -239,12 +267,22 @@ router.all('app/{*path}', async (ctx) => {
|
|
|
239
267
|
await runMiddlewares(middlewares, ctx, handler);
|
|
240
268
|
}
|
|
241
269
|
catch (err) {
|
|
242
|
-
|
|
270
|
+
const handled = await dispatchHttpError({
|
|
271
|
+
ctx,
|
|
272
|
+
error: err,
|
|
273
|
+
appName: 'main',
|
|
274
|
+
path: ctx.path,
|
|
275
|
+
method: ctx.method,
|
|
276
|
+
kind: 'api'
|
|
277
|
+
});
|
|
278
|
+
if (handled) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
243
281
|
ctx.status = 500;
|
|
244
282
|
ctx.body = {
|
|
245
283
|
code: 500,
|
|
246
284
|
message: '处理 API 请求时发生错误。',
|
|
247
|
-
error: err.message
|
|
285
|
+
error: err instanceof Error ? err.message : String(err)
|
|
248
286
|
};
|
|
249
287
|
}
|
|
250
288
|
return;
|
|
@@ -264,11 +302,22 @@ router.all('app/{*path}', async (ctx) => {
|
|
|
264
302
|
root = readWebRootConfig(packageRoot);
|
|
265
303
|
}
|
|
266
304
|
catch (err) {
|
|
305
|
+
const handled = await dispatchHttpError({
|
|
306
|
+
ctx,
|
|
307
|
+
error: err,
|
|
308
|
+
appName: 'main',
|
|
309
|
+
path: ctx.path,
|
|
310
|
+
method: ctx.method,
|
|
311
|
+
kind: 'web'
|
|
312
|
+
});
|
|
313
|
+
if (handled) {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
267
316
|
ctx.status = 500;
|
|
268
317
|
ctx.body = {
|
|
269
318
|
code: 500,
|
|
270
319
|
message: '加载 package.json 时发生错误。',
|
|
271
|
-
error: err.message
|
|
320
|
+
error: err instanceof Error ? err.message : String(err)
|
|
272
321
|
};
|
|
273
322
|
return;
|
|
274
323
|
}
|
|
@@ -291,6 +340,17 @@ router.all('app/{*path}', async (ctx) => {
|
|
|
291
340
|
ctx.status = 200;
|
|
292
341
|
}
|
|
293
342
|
catch (err) {
|
|
343
|
+
const handled = await dispatchHttpError({
|
|
344
|
+
ctx,
|
|
345
|
+
error: err,
|
|
346
|
+
appName: 'main',
|
|
347
|
+
path: ctx.path,
|
|
348
|
+
method: ctx.method,
|
|
349
|
+
kind: 'web'
|
|
350
|
+
});
|
|
351
|
+
if (handled) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
294
354
|
if (err?.status === 404) {
|
|
295
355
|
ctx.status = 404;
|
|
296
356
|
ctx.body = {
|
|
@@ -304,7 +364,7 @@ router.all('app/{*path}', async (ctx) => {
|
|
|
304
364
|
ctx.body = {
|
|
305
365
|
code: 500,
|
|
306
366
|
message: '加载资源时发生服务器错误。',
|
|
307
|
-
error: err.message
|
|
367
|
+
error: err instanceof Error ? err.message : String(err)
|
|
308
368
|
};
|
|
309
369
|
}
|
|
310
370
|
}
|
|
@@ -370,16 +430,27 @@ router.all('apps/:app/{*path}', async (ctx) => {
|
|
|
370
430
|
await runMiddlewares(middlewares, ctx, handler);
|
|
371
431
|
}
|
|
372
432
|
catch (err) {
|
|
433
|
+
const handled = await dispatchHttpError({
|
|
434
|
+
ctx,
|
|
435
|
+
error: err,
|
|
436
|
+
appName,
|
|
437
|
+
path: ctx.path,
|
|
438
|
+
method: ctx.method,
|
|
439
|
+
kind: 'api'
|
|
440
|
+
});
|
|
441
|
+
if (handled) {
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
373
444
|
logger.warn({
|
|
374
445
|
code: ResultCode.Fail,
|
|
375
446
|
message: `Error request ${ctx.path}:`,
|
|
376
|
-
data: err
|
|
447
|
+
data: err instanceof Error ? err.message : String(err)
|
|
377
448
|
});
|
|
378
449
|
ctx.status = 500;
|
|
379
450
|
ctx.body = {
|
|
380
451
|
code: 500,
|
|
381
452
|
message: '处理 API 请求时发生错误。',
|
|
382
|
-
error: err.message
|
|
453
|
+
error: err instanceof Error ? err.message : String(err)
|
|
383
454
|
};
|
|
384
455
|
}
|
|
385
456
|
return;
|
|
@@ -399,11 +470,22 @@ router.all('apps/:app/{*path}', async (ctx) => {
|
|
|
399
470
|
root = readWebRootConfig(packageRoot);
|
|
400
471
|
}
|
|
401
472
|
catch (err) {
|
|
473
|
+
const handled = await dispatchHttpError({
|
|
474
|
+
ctx,
|
|
475
|
+
error: err,
|
|
476
|
+
appName,
|
|
477
|
+
path: ctx.path,
|
|
478
|
+
method: ctx.method,
|
|
479
|
+
kind: 'web'
|
|
480
|
+
});
|
|
481
|
+
if (handled) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
402
484
|
ctx.status = 500;
|
|
403
485
|
ctx.body = {
|
|
404
486
|
code: 500,
|
|
405
487
|
message: '加载 package.json 时发生错误。',
|
|
406
|
-
error: err.message
|
|
488
|
+
error: err instanceof Error ? err.message : String(err)
|
|
407
489
|
};
|
|
408
490
|
return;
|
|
409
491
|
}
|
|
@@ -426,6 +508,17 @@ router.all('apps/:app/{*path}', async (ctx) => {
|
|
|
426
508
|
ctx.status = 200;
|
|
427
509
|
}
|
|
428
510
|
catch (err) {
|
|
511
|
+
const handled = await dispatchHttpError({
|
|
512
|
+
ctx,
|
|
513
|
+
error: err,
|
|
514
|
+
appName,
|
|
515
|
+
path: ctx.path,
|
|
516
|
+
method: ctx.method,
|
|
517
|
+
kind: 'web'
|
|
518
|
+
});
|
|
519
|
+
if (handled) {
|
|
520
|
+
return;
|
|
521
|
+
}
|
|
429
522
|
if (err?.status === 404) {
|
|
430
523
|
ctx.status = 404;
|
|
431
524
|
ctx.body = {
|
|
@@ -438,13 +531,13 @@ router.all('apps/:app/{*path}', async (ctx) => {
|
|
|
438
531
|
logger.warn({
|
|
439
532
|
code: ResultCode.Fail,
|
|
440
533
|
message: `Error request ${ctx.path}:`,
|
|
441
|
-
data: err
|
|
534
|
+
data: err instanceof Error ? err.message : String(err)
|
|
442
535
|
});
|
|
443
536
|
ctx.status = 500;
|
|
444
537
|
ctx.body = {
|
|
445
538
|
code: 500,
|
|
446
539
|
message: `加载子应用 '${appName}' 资源时发生服务器错误。`,
|
|
447
|
-
error: err.message
|
|
540
|
+
error: err instanceof Error ? err.message : String(err)
|
|
448
541
|
};
|
|
449
542
|
}
|
|
450
543
|
}
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { StoreMiddlewareItem, StoreResponseItem } from '../store/res';
|
|
2
|
+
import { Events } from '../event';
|
|
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;
|