akanjs 2.3.9-rc.2 → 2.3.9-rc.3
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/local/apps/serverLifecycle/serverLifecycle-local.db +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local.db-wal +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-shm +0 -0
- package/local/apps/serverLifecycle/serverLifecycle-local_solid.db-wal +0 -0
- package/package.json +1 -1
- package/server/di/diLifecycle.ts +58 -30
- package/server/di/utils.ts +64 -0
- package/signal/internalInfo.ts +1 -2
- package/types/server/di/utils.d.ts +13 -0
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
package/server/di/diLifecycle.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { BaseEnv } from "akanjs/base";
|
|
2
|
-
import { Logger
|
|
2
|
+
import { Logger } from "akanjs/common";
|
|
3
3
|
import {
|
|
4
4
|
type Adaptor,
|
|
5
5
|
type AdaptorCls,
|
|
@@ -26,29 +26,17 @@ import type { SignalRoutes, WebsocketRoutes } from "../types";
|
|
|
26
26
|
import { getPredefinedAdaptor, predefinedAdaptorRole } from "./predefinedAdaptor";
|
|
27
27
|
import { collectAdaptors, resolveAdaptorHierarchy } from "./resolveAdaptorHierarchy";
|
|
28
28
|
import { resolveServiceHierarchy } from "./resolveServiceHierarchy";
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const normalizeServiceRefName = (refName: string) => {
|
|
42
|
-
const normalized = lowerlize(refName);
|
|
43
|
-
return normalized.endsWith("Service") ? normalized.slice(0, -"Service".length) : normalized;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
const normalizeSignalRefName = (refName: string) => {
|
|
47
|
-
const normalized = lowerlize(refName);
|
|
48
|
-
return normalized.endsWith("Signal") ? normalized : `${normalized}Signal`;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
const normalizeAdaptorRefName = (refName: string) => lowerlize(refName);
|
|
29
|
+
import {
|
|
30
|
+
type DiModuleCandidate,
|
|
31
|
+
getModuleDependencyRefNames,
|
|
32
|
+
isDestroyableUse,
|
|
33
|
+
normalizeAdaptorRefName,
|
|
34
|
+
normalizeServiceRefName,
|
|
35
|
+
normalizeSignalRefName,
|
|
36
|
+
reasonMessage,
|
|
37
|
+
runStage,
|
|
38
|
+
toError,
|
|
39
|
+
} from "./utils";
|
|
52
40
|
|
|
53
41
|
/**
|
|
54
42
|
* Owns the app's DI container state (registry + live maps + init order) and
|
|
@@ -88,25 +76,32 @@ export class DiLifecycle {
|
|
|
88
76
|
this.#middleware.set(middleware.refName, middleware);
|
|
89
77
|
});
|
|
90
78
|
this.webProxies.push(...defaultOption.getWebProxies());
|
|
79
|
+
const databaseCandidates = new Map<string, DiModuleCandidate>();
|
|
80
|
+
const serviceCandidates = new Map<string, DiModuleCandidate>();
|
|
91
81
|
libs.forEach((lib) => {
|
|
92
82
|
lib.option.getMiddlewares().forEach((middleware) => {
|
|
93
83
|
this.#middleware.set(middleware.refName, middleware);
|
|
94
84
|
});
|
|
95
85
|
this.webProxies.push(...lib.option.getWebProxies());
|
|
96
86
|
lib.database.forEach((mod) => {
|
|
97
|
-
|
|
98
|
-
if (!mod.service.srv.enabled) return;
|
|
99
|
-
this.#database.set(mod.constant.refName, mod);
|
|
87
|
+
databaseCandidates.set(mod.constant.refName, { refName: mod.constant.refName, module: mod });
|
|
100
88
|
});
|
|
101
89
|
lib.service.forEach((mod) => {
|
|
102
|
-
|
|
103
|
-
if (!mod.service.srv.enabled) return;
|
|
104
|
-
this.#service.set(mod.service.srv.refName, mod);
|
|
90
|
+
serviceCandidates.set(mod.service.srv.refName, { refName: mod.service.srv.refName, module: mod });
|
|
105
91
|
});
|
|
106
92
|
lib.scalar.forEach((mod) => {
|
|
107
93
|
this.#scalar.set(mod.constant.refName, mod);
|
|
108
94
|
});
|
|
109
95
|
});
|
|
96
|
+
const disabledModules = this.#resolveDisabledModules(databaseCandidates, serviceCandidates);
|
|
97
|
+
databaseCandidates.forEach(({ refName, module }) => {
|
|
98
|
+
if (disabledModules.has(refName)) return;
|
|
99
|
+
this.#database.set(refName, module as DatabaseModule);
|
|
100
|
+
});
|
|
101
|
+
serviceCandidates.forEach(({ refName, module }) => {
|
|
102
|
+
if (disabledModules.has(refName)) return;
|
|
103
|
+
this.#service.set(refName, module as ServiceModule);
|
|
104
|
+
});
|
|
110
105
|
this.#database.forEach((mod) => {
|
|
111
106
|
const databaseAdaptor = DatabaseResolver.resolveDatabase(mod.constant, mod.database);
|
|
112
107
|
this.#adaptor.set(databaseAdaptor.refName, databaseAdaptor);
|
|
@@ -120,6 +115,39 @@ export class DiLifecycle {
|
|
|
120
115
|
}
|
|
121
116
|
}
|
|
122
117
|
|
|
118
|
+
#resolveDisabledModules(
|
|
119
|
+
databaseCandidates: Map<string, DiModuleCandidate>,
|
|
120
|
+
serviceCandidates: Map<string, DiModuleCandidate>,
|
|
121
|
+
) {
|
|
122
|
+
const candidates = new Map<string, DiModuleCandidate>([...databaseCandidates, ...serviceCandidates]);
|
|
123
|
+
const disabledReasons = new Map<string, string>();
|
|
124
|
+
|
|
125
|
+
candidates.forEach(({ refName, module }) => {
|
|
126
|
+
if (!module.service.srv.enabled) disabledReasons.set(refName, "service disabled");
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
let changed = true;
|
|
130
|
+
while (changed) {
|
|
131
|
+
changed = false;
|
|
132
|
+
candidates.forEach(({ refName, module }) => {
|
|
133
|
+
if (disabledReasons.has(refName)) return;
|
|
134
|
+
for (const dependencyRefName of getModuleDependencyRefNames(module)) {
|
|
135
|
+
if (dependencyRefName === refName) continue;
|
|
136
|
+
const dependencyReason = disabledReasons.get(dependencyRefName);
|
|
137
|
+
if (!dependencyReason) continue;
|
|
138
|
+
disabledReasons.set(refName, `depends on disabled module "${dependencyRefName}"`);
|
|
139
|
+
changed = true;
|
|
140
|
+
break;
|
|
141
|
+
}
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
disabledReasons.forEach((reason, refName) => {
|
|
146
|
+
this.logger.verbose(`Skipping disabled module "${refName}": ${reason}`);
|
|
147
|
+
});
|
|
148
|
+
return new Set(disabledReasons.keys());
|
|
149
|
+
}
|
|
150
|
+
|
|
123
151
|
/** Run every init stage in dependency order and collect the generated routes. */
|
|
124
152
|
async initializeAll(): Promise<SignalRoutes> {
|
|
125
153
|
await this.#initializeUses();
|
package/server/di/utils.ts
CHANGED
|
@@ -1,8 +1,72 @@
|
|
|
1
|
+
import { INJECT_META } from "akanjs/base";
|
|
2
|
+
import { lowerlize } from "akanjs/common";
|
|
3
|
+
import type { InjectInfo } from "akanjs/service";
|
|
4
|
+
import type { DatabaseModule, ServiceModule } from "../akanLib";
|
|
5
|
+
|
|
1
6
|
interface StageTask {
|
|
2
7
|
label: string;
|
|
3
8
|
run: () => Promise<unknown>;
|
|
4
9
|
}
|
|
5
10
|
|
|
11
|
+
interface DestroyableUse {
|
|
12
|
+
onDestroy(): Promise<void> | void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
type InjectableCls = { [INJECT_META]?: unknown };
|
|
16
|
+
|
|
17
|
+
export interface DiModuleCandidate {
|
|
18
|
+
refName: string;
|
|
19
|
+
module: DatabaseModule | ServiceModule;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const isDestroyableUse = (value: unknown): value is DestroyableUse =>
|
|
23
|
+
typeof value === "object" &&
|
|
24
|
+
value !== null &&
|
|
25
|
+
"onDestroy" in value &&
|
|
26
|
+
typeof (value as { onDestroy?: unknown }).onDestroy === "function";
|
|
27
|
+
|
|
28
|
+
export const normalizeServiceRefName = (refName: string) => {
|
|
29
|
+
const normalized = lowerlize(refName);
|
|
30
|
+
return normalized.endsWith("Service") ? normalized.slice(0, -"Service".length) : normalized;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const normalizeSignalRefName = (refName: string) => {
|
|
34
|
+
const normalized = lowerlize(refName);
|
|
35
|
+
return normalized.endsWith("Signal") ? normalized : `${normalized}Signal`;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const normalizeAdaptorRefName = (refName: string) => lowerlize(refName);
|
|
39
|
+
|
|
40
|
+
const normalizeInjectedServiceRefName = (propKey: string) =>
|
|
41
|
+
propKey.endsWith("Service") ? propKey.slice(0, -"Service".length) : propKey;
|
|
42
|
+
|
|
43
|
+
const normalizeInjectedDatabaseRefName = (propKey: string) =>
|
|
44
|
+
propKey.endsWith("Model") ? propKey.slice(0, -"Model".length) : propKey;
|
|
45
|
+
|
|
46
|
+
const normalizeInjectedSignalRefName = (propKey: string) => {
|
|
47
|
+
const normalized = lowerlize(propKey);
|
|
48
|
+
return normalized.endsWith("Signal") ? normalized.slice(0, -"Signal".length) : normalized;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const getModuleInjectables = (mod: DatabaseModule | ServiceModule): InjectableCls[] => {
|
|
52
|
+
const injectables: InjectableCls[] = [mod.service.srv, mod.signal.internal, mod.signal.endpoint, mod.signal.server];
|
|
53
|
+
if ("constant" in mod) injectables.push(mod.signal.slice);
|
|
54
|
+
return injectables;
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
export const getModuleDependencyRefNames = (mod: DatabaseModule | ServiceModule) => {
|
|
58
|
+
const dependencies = new Set<string>();
|
|
59
|
+
for (const injectable of getModuleInjectables(mod)) {
|
|
60
|
+
const injectMap = (injectable[INJECT_META] ?? {}) as Record<string, InjectInfo>;
|
|
61
|
+
for (const [propKey, injectInfo] of Object.entries(injectMap)) {
|
|
62
|
+
if (injectInfo.type === "service") dependencies.add(normalizeInjectedServiceRefName(propKey));
|
|
63
|
+
else if (injectInfo.type === "database") dependencies.add(normalizeInjectedDatabaseRefName(propKey));
|
|
64
|
+
else if (injectInfo.type === "signal") dependencies.add(normalizeInjectedSignalRefName(propKey));
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return dependencies;
|
|
68
|
+
};
|
|
69
|
+
|
|
6
70
|
/**
|
|
7
71
|
* Run every task in parallel and, if any rejects, throw a single
|
|
8
72
|
* `AggregateError` that enumerates every failing label + cause. This replaces
|
package/signal/internalInfo.ts
CHANGED
|
@@ -212,8 +212,7 @@ export const buildInternal = {
|
|
|
212
212
|
resolveField: <Returns extends ConstantFieldTypeInput, Nullable extends boolean = false>(
|
|
213
213
|
returnRef: Returns,
|
|
214
214
|
signalOption?: Pick<SignalOption<Returns, Nullable>, "nullable">,
|
|
215
|
-
) =>
|
|
216
|
-
new InternalInfo("resolveField", returnRef, signalOption),
|
|
215
|
+
) => new InternalInfo("resolveField", returnRef, signalOption),
|
|
217
216
|
interval: (scheduleTime: number, signalOption?: SignalOption) =>
|
|
218
217
|
new InternalInfo("interval", Any, {
|
|
219
218
|
enabled: true,
|
|
@@ -1,7 +1,20 @@
|
|
|
1
|
+
import type { DatabaseModule, ServiceModule } from "../akanLib.d.ts";
|
|
1
2
|
interface StageTask {
|
|
2
3
|
label: string;
|
|
3
4
|
run: () => Promise<unknown>;
|
|
4
5
|
}
|
|
6
|
+
interface DestroyableUse {
|
|
7
|
+
onDestroy(): Promise<void> | void;
|
|
8
|
+
}
|
|
9
|
+
export interface DiModuleCandidate {
|
|
10
|
+
refName: string;
|
|
11
|
+
module: DatabaseModule | ServiceModule;
|
|
12
|
+
}
|
|
13
|
+
export declare const isDestroyableUse: (value: unknown) => value is DestroyableUse;
|
|
14
|
+
export declare const normalizeServiceRefName: (refName: string) => string;
|
|
15
|
+
export declare const normalizeSignalRefName: (refName: string) => string;
|
|
16
|
+
export declare const normalizeAdaptorRefName: (refName: string) => string;
|
|
17
|
+
export declare const getModuleDependencyRefNames: (mod: DatabaseModule | ServiceModule) => Set<string>;
|
|
5
18
|
/**
|
|
6
19
|
* Run every task in parallel and, if any rejects, throw a single
|
|
7
20
|
* `AggregateError` that enumerates every failing label + cause. This replaces
|