lanka 1.3.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/ILankaReadableVM-BoPzHEPV.d.ts +72 -0
- package/dist/{LankaScenarioLocator-CAENLhDO.d.ts → LankaScenarioLocator-Dki2Es3O.d.ts} +2 -2
- package/dist/{LankaSharedStoreLocator-zS2kLu-S.d.ts → LankaSharedStoreLocator-jsz_gnUm.d.ts} +1 -1
- package/dist/_extend/index.d.ts +228 -5
- package/dist/_extend/index.js +137 -8
- package/dist/_extend/index.js.map +1 -1
- package/dist/_internal/index.d.ts +3 -3
- package/dist/_internal/index.js +9 -3
- package/dist/_internal/index.js.map +1 -1
- package/dist/{activeRuntime-BYd2D6Lx.d.ts → activeRuntime-BO-qY0yY.d.ts} +50 -3
- package/dist/bootstrap/index.d.ts +6 -6
- package/dist/bootstrap/index.js +7 -8
- package/dist/{chunk-D27MREPB.js → chunk-7DQUF2QR.js} +2 -2
- package/dist/{chunk-UJEC7H6K.js → chunk-BHQ2SQ7P.js} +2 -2
- package/dist/chunk-EYDMBI5T.js +550 -0
- package/dist/chunk-EYDMBI5T.js.map +1 -0
- package/dist/{chunk-C2HP7CRD.js → chunk-FII3PW2G.js} +2 -2
- package/dist/{chunk-DTO27QFR.js → chunk-H5TIUKRK.js} +2 -2
- package/dist/{chunk-NDCJBO47.js → chunk-O5EUTNR6.js} +2 -2
- package/dist/{chunk-RKYKK6MN.js → chunk-RUMUFHSL.js} +2 -2
- package/dist/{chunk-UBGXDTXC.js → chunk-SZVNPK24.js} +11 -13
- package/dist/chunk-SZVNPK24.js.map +1 -0
- package/dist/chunk-UDP6IXDS.js +17 -0
- package/dist/chunk-UDP6IXDS.js.map +1 -0
- package/dist/{chunk-5MAQVBI2.js → chunk-UMPSR4US.js} +3 -3
- package/dist/{chunk-BGVDPDX4.js → chunk-XGMXT4XZ.js} +20 -3
- package/dist/chunk-XGMXT4XZ.js.map +1 -0
- package/dist/config/index.js +3 -3
- package/dist/{createLanka-NrlvN-WQ.d.ts → createLanka-x4oSMs7P.d.ts} +2 -2
- package/dist/{createLankaScope-BiFxNQgl.d.ts → createLankaScope-DomNbEvb.d.ts} +1 -1
- package/dist/errors/index.js +3 -3
- package/dist/gateway/index.js +9 -9
- package/dist/index.d.ts +5 -5
- package/dist/index.js +8 -9
- package/dist/locator/index.d.ts +2 -2
- package/dist/locator/index.js +2 -2
- package/dist/logger/index.js +3 -3
- package/dist/mock/index.js +3 -3
- package/dist/scenario/index.d.ts +25 -0
- package/dist/scenario/index.js +6 -8
- package/dist/scenario/index.js.map +1 -1
- package/dist/stream/index.d.ts +5 -5
- package/dist/viewmodel/index.d.ts +137 -27
- package/dist/viewmodel/index.js +94 -126
- package/dist/viewmodel/index.js.map +1 -1
- package/package.json +3 -4
- package/skills/lanka-core/SKILL.md +18 -16
- package/skills/lanka-core/reference.md +135 -58
- package/skills/lanka-packages/SKILL.md +94 -22
- package/dist/chunk-B7EYIAW7.js +0 -216
- package/dist/chunk-B7EYIAW7.js.map +0 -1
- package/dist/chunk-BGVDPDX4.js.map +0 -1
- package/dist/chunk-O5ROO7QF.js +0 -315
- package/dist/chunk-O5ROO7QF.js.map +0 -1
- package/dist/chunk-UBGXDTXC.js.map +0 -1
- /package/dist/{chunk-D27MREPB.js.map → chunk-7DQUF2QR.js.map} +0 -0
- /package/dist/{chunk-UJEC7H6K.js.map → chunk-BHQ2SQ7P.js.map} +0 -0
- /package/dist/{chunk-C2HP7CRD.js.map → chunk-FII3PW2G.js.map} +0 -0
- /package/dist/{chunk-DTO27QFR.js.map → chunk-H5TIUKRK.js.map} +0 -0
- /package/dist/{chunk-NDCJBO47.js.map → chunk-O5EUTNR6.js.map} +0 -0
- /package/dist/{chunk-RKYKK6MN.js.map → chunk-RUMUFHSL.js.map} +0 -0
- /package/dist/{chunk-5MAQVBI2.js.map → chunk-UMPSR4US.js.map} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { L as LankaEventBusInstance, I as ILankaScenarioVM } from './ILankaScenarioVM-DpKFL3iE.js';
|
|
2
|
-
import {
|
|
2
|
+
import { L as LankaScenariosRegistry, a as LankaScenarioVMRegistry, b as LankaGatewayLocator, c as LankaScenarioLocator } from './LankaScenarioLocator-Dki2Es3O.js';
|
|
3
3
|
import { b as ILankaRuntimeConfig } from './ILankaRuntimeConfig-Vl436GWK.js';
|
|
4
4
|
import { I as ILankaInFlightCounter } from './lankaHttpInFlight-Bk1eIuSx.js';
|
|
5
5
|
import { T as TLankaRequestMiddleware } from './lankaRequestMiddleware-DAC5kCb7.js';
|
|
6
|
-
import {
|
|
6
|
+
import { L as LankaSingletonLocator, a as LankaSharedStoreLocator } from './LankaSharedStoreLocator-jsz_gnUm.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* The pointer to the framework instance that ambient facades resolve to.
|
|
@@ -67,6 +67,26 @@ interface ILankaRuntime {
|
|
|
67
67
|
* is the bug: the last request to start would answer for all of them.
|
|
68
68
|
*/
|
|
69
69
|
type TLankaRuntimeResolver = () => ILankaRuntime | null;
|
|
70
|
+
/**
|
|
71
|
+
* How "which SCOPE is this" is answered, which is a different question.
|
|
72
|
+
*
|
|
73
|
+
* `TLankaRuntimeResolver` answers which framework INSTANCE serves a call, and on
|
|
74
|
+
* a server that is one per request. This answers which unit of work the call
|
|
75
|
+
* belongs to, and the two are not interchangeable: `runInLankaServerScope`
|
|
76
|
+
* creates its instance INSIDE the scope, and `createLanka` activates every
|
|
77
|
+
* instance it builds — so the process pointer and the scope's runtime are the
|
|
78
|
+
* same object during a request, and nothing downstream can tell "inside a
|
|
79
|
+
* scope" from "after one ended".
|
|
80
|
+
*
|
|
81
|
+
* That distinction is what a per-scope lifetime needs. Without it a call made
|
|
82
|
+
* outside every request resolves against the LAST request's runtime and is
|
|
83
|
+
* handed the last stranger's state, which is the failure a scope exists to
|
|
84
|
+
* abolish.
|
|
85
|
+
*
|
|
86
|
+
* Core ships no resolver here either, and knows only that the question exists.
|
|
87
|
+
*/
|
|
88
|
+
type TLankaScopeResolver = () => object | null;
|
|
89
|
+
declare function setActiveLankaRuntime(runtime: ILankaRuntime | null): void;
|
|
70
90
|
/**
|
|
71
91
|
* Replaces the strategy, or restores the default one with `null`.
|
|
72
92
|
*
|
|
@@ -80,5 +100,32 @@ type TLankaRuntimeResolver = () => ILankaRuntime | null;
|
|
|
80
100
|
* one answer.
|
|
81
101
|
*/
|
|
82
102
|
declare function setLankaRuntimeResolver(resolver: TLankaRuntimeResolver | null): void;
|
|
103
|
+
/**
|
|
104
|
+
* The PROCESS's own instance, read without asking the strategy.
|
|
105
|
+
*
|
|
106
|
+
* `getActiveRuntime` consults the installed resolver and is the answer for
|
|
107
|
+
* almost everything. This is the one question it cannot answer: what a call
|
|
108
|
+
* would have resolved to if nobody had installed a resolver at all.
|
|
109
|
+
*
|
|
110
|
+
* It exists for a resolver that wants to DEFER. A server's resolver answers from
|
|
111
|
+
* its request scope, and a process that also holds an ambient instance — a
|
|
112
|
+
* worker with a cache, a dev server between reloads, a suite between cases —
|
|
113
|
+
* has a right answer outside every scope that the resolver cannot see. Without
|
|
114
|
+
* this, the first request in such a process makes every later ambient call fail
|
|
115
|
+
* for the life of it.
|
|
116
|
+
*
|
|
117
|
+
* Not a fallback inside `getActiveRuntime`, deliberately: a resolver that wants
|
|
118
|
+
* to defer says so, and one that wants a call outside its scope to fail loudly
|
|
119
|
+
* goes on failing loudly. The choice belongs to whoever knows what a scope is.
|
|
120
|
+
*/
|
|
121
|
+
declare function getLankaProcessRuntime(): ILankaRuntime | null;
|
|
122
|
+
/**
|
|
123
|
+
* Installs the strategy that says which unit of work a call belongs to.
|
|
124
|
+
*
|
|
125
|
+
* Installed by whoever knows what a scope IS — `@lankajs/host` wraps a request
|
|
126
|
+
* in `AsyncLocalStorage` and answers from its store. A browser installs none,
|
|
127
|
+
* and that is the right answer there: a tab is one scope for its whole life.
|
|
128
|
+
*/
|
|
129
|
+
declare function setLankaScopeResolver(resolver: TLankaScopeResolver | null): void;
|
|
83
130
|
|
|
84
|
-
export { type ILankaRuntime as I, type TLankaRuntimeResolver as T, setLankaRuntimeResolver as s };
|
|
131
|
+
export { type ILankaRuntime as I, type TLankaRuntimeResolver as T, type TLankaScopeResolver as a, setLankaRuntimeResolver as b, setLankaScopeResolver as c, getLankaProcessRuntime as g, setActiveLankaRuntime as s };
|
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import { c as ILankaPlugin, e as ILankaServiceConfig, I as ILankaBootstrapConfig, a as ILankaInstance } from '../createLanka-
|
|
2
|
-
export { b as ILankaInstanceConfig, d as ILankaScenarioBootstrapConfig, f as createLanka } from '../createLanka-
|
|
1
|
+
import { c as ILankaPlugin, e as ILankaServiceConfig, I as ILankaBootstrapConfig, a as ILankaInstance } from '../createLanka-x4oSMs7P.js';
|
|
2
|
+
export { b as ILankaInstanceConfig, d as ILankaScenarioBootstrapConfig, f as createLanka } from '../createLanka-x4oSMs7P.js';
|
|
3
3
|
import { I as ILankaFlags, a as ILankaHost } from '../ILankaRuntimeConfig-Vl436GWK.js';
|
|
4
|
-
export { I as ILankaScope } from '../createLankaScope-
|
|
5
|
-
import '../activeRuntime-
|
|
4
|
+
export { I as ILankaScope } from '../createLankaScope-DomNbEvb.js';
|
|
5
|
+
import '../activeRuntime-BO-qY0yY.js';
|
|
6
6
|
import '../ILankaScenarioVM-DpKFL3iE.js';
|
|
7
|
-
import '../LankaScenarioLocator-
|
|
7
|
+
import '../LankaScenarioLocator-Dki2Es3O.js';
|
|
8
8
|
import '../ILankaScenarioMetadata-Dj4GCqmX.js';
|
|
9
9
|
import '../ALankaGateway-BrVPaZN5.js';
|
|
10
10
|
import '../lankaStandardValidator-BUFnysK0.js';
|
|
11
11
|
import '@standard-schema/spec';
|
|
12
12
|
import '../ILankaFieldError-D5931-vT.js';
|
|
13
|
-
import '../LankaSharedStoreLocator-
|
|
13
|
+
import '../LankaSharedStoreLocator-jsz_gnUm.js';
|
|
14
14
|
import '../ALankaSharedStore-B7uepuuk.js';
|
|
15
15
|
import 'zustand/vanilla';
|
|
16
16
|
import '../lankaHttpInFlight-Bk1eIuSx.js';
|
package/dist/bootstrap/index.js
CHANGED
|
@@ -3,16 +3,15 @@ import {
|
|
|
3
3
|
createLanka,
|
|
4
4
|
resetActiveLanka,
|
|
5
5
|
startLanka
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
9
|
-
import "../chunk-O5ROO7QF.js";
|
|
6
|
+
} from "../chunk-SZVNPK24.js";
|
|
7
|
+
import "../chunk-UMPSR4US.js";
|
|
8
|
+
import "../chunk-EYDMBI5T.js";
|
|
10
9
|
import "../chunk-XESL274R.js";
|
|
11
|
-
import "../chunk-
|
|
10
|
+
import "../chunk-BHQ2SQ7P.js";
|
|
12
11
|
import "../chunk-UE2C76OR.js";
|
|
13
|
-
import "../chunk-
|
|
14
|
-
import "../chunk-
|
|
15
|
-
import "../chunk-
|
|
12
|
+
import "../chunk-FII3PW2G.js";
|
|
13
|
+
import "../chunk-7DQUF2QR.js";
|
|
14
|
+
import "../chunk-XGMXT4XZ.js";
|
|
16
15
|
export {
|
|
17
16
|
ALankaPlugin,
|
|
18
17
|
createLanka,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getActiveRuntime
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XGMXT4XZ.js";
|
|
4
4
|
|
|
5
5
|
// src/config/get-lanka-flags/getLankaFlags.ts
|
|
6
6
|
function getLankaFlags() {
|
|
@@ -10,4 +10,4 @@ function getLankaFlags() {
|
|
|
10
10
|
export {
|
|
11
11
|
getLankaFlags
|
|
12
12
|
};
|
|
13
|
-
//# sourceMappingURL=chunk-
|
|
13
|
+
//# sourceMappingURL=chunk-7DQUF2QR.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
requireActiveRuntime
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XGMXT4XZ.js";
|
|
4
4
|
|
|
5
5
|
// src/gateway/inflight/lankaHttpInFlight.ts
|
|
6
6
|
function createInFlightCounter() {
|
|
@@ -36,4 +36,4 @@ export {
|
|
|
36
36
|
createInFlightCounter,
|
|
37
37
|
lankaHttpInFlight
|
|
38
38
|
};
|
|
39
|
-
//# sourceMappingURL=chunk-
|
|
39
|
+
//# sourceMappingURL=chunk-BHQ2SQ7P.js.map
|
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lankaLogger
|
|
3
|
+
} from "./chunk-FII3PW2G.js";
|
|
4
|
+
import {
|
|
5
|
+
getActiveRuntime,
|
|
6
|
+
requireActiveRuntime
|
|
7
|
+
} from "./chunk-XGMXT4XZ.js";
|
|
8
|
+
|
|
9
|
+
// src/scenario/event-bus/_facades/lanka-event-bus/lankaEventBus.ts
|
|
10
|
+
var bus = () => requireActiveRuntime().eventBus;
|
|
11
|
+
var lankaEventBus = Object.freeze({
|
|
12
|
+
enableLogs: () => {
|
|
13
|
+
bus().enableLogs();
|
|
14
|
+
},
|
|
15
|
+
disableLogs: () => {
|
|
16
|
+
bus().disableLogs();
|
|
17
|
+
},
|
|
18
|
+
registerEvent: (eventType, metadata) => {
|
|
19
|
+
bus().registerEvent(eventType, metadata);
|
|
20
|
+
},
|
|
21
|
+
getRegisteredEvents: () => bus().getRegisteredEvents(),
|
|
22
|
+
getEventInfo: (eventType) => bus().getEventInfo(eventType),
|
|
23
|
+
getSubscriptions: (eventType) => bus().getSubscriptions(eventType),
|
|
24
|
+
subscribe: (eventType, callback, options) => bus().subscribe(eventType, callback, options),
|
|
25
|
+
unsubscribe: (eventType, callback) => {
|
|
26
|
+
bus().unsubscribe(eventType, callback);
|
|
27
|
+
},
|
|
28
|
+
dispatch: (eventType, data, usedBy) => {
|
|
29
|
+
bus().dispatch(eventType, data, usedBy);
|
|
30
|
+
},
|
|
31
|
+
addMiddleware: (middleware) => {
|
|
32
|
+
bus().addMiddleware(middleware);
|
|
33
|
+
},
|
|
34
|
+
removeMiddleware: (middleware) => {
|
|
35
|
+
bus().removeMiddleware(middleware);
|
|
36
|
+
},
|
|
37
|
+
addObserver: (observer) => {
|
|
38
|
+
bus().addObserver(observer);
|
|
39
|
+
},
|
|
40
|
+
removeObserver: (observer) => {
|
|
41
|
+
bus().removeObserver(observer);
|
|
42
|
+
},
|
|
43
|
+
getEventLogs: (eventType, limit = 100) => bus().getEventLogs(eventType, limit),
|
|
44
|
+
clearEvent: (eventType) => {
|
|
45
|
+
bus().clearEvent(eventType);
|
|
46
|
+
},
|
|
47
|
+
clearAllEvents: () => {
|
|
48
|
+
bus().clearAllEvents();
|
|
49
|
+
},
|
|
50
|
+
reset: () => {
|
|
51
|
+
bus().reset();
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
// src/scenario/_registries/lanka-scenario-vm-registry/LankaScenarioVMRegistry.ts
|
|
56
|
+
var LankaScenarioVMRegistry = class {
|
|
57
|
+
registeredViewModels = /* @__PURE__ */ new Set();
|
|
58
|
+
/**
|
|
59
|
+
* Public: the registry belongs to a framework instance rather than to the
|
|
60
|
+
* module.
|
|
61
|
+
*/
|
|
62
|
+
constructor() {
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The active instance's registry, for callers that cannot hold one — the
|
|
66
|
+
* static `LankaScenarioBootstrap`. Instance holders read `lanka.viewModels`.
|
|
67
|
+
*/
|
|
68
|
+
static getInstance() {
|
|
69
|
+
return requireActiveRuntime().viewModels;
|
|
70
|
+
}
|
|
71
|
+
/** Whether this ViewModel is already registered. */
|
|
72
|
+
isRegistered(viewModel) {
|
|
73
|
+
return this.registeredViewModels.has(viewModel);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Registers a ViewModel.
|
|
77
|
+
*
|
|
78
|
+
* @returns `false` when it was already registered
|
|
79
|
+
*/
|
|
80
|
+
register(viewModel) {
|
|
81
|
+
if (this.registeredViewModels.has(viewModel)) {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
this.registeredViewModels.add(viewModel);
|
|
85
|
+
return true;
|
|
86
|
+
}
|
|
87
|
+
/** Removes a ViewModel from the registry. */
|
|
88
|
+
unregister(viewModel) {
|
|
89
|
+
this.registeredViewModels.delete(viewModel);
|
|
90
|
+
}
|
|
91
|
+
/** Every registered ViewModel. */
|
|
92
|
+
getAllViewModels() {
|
|
93
|
+
return Array.from(this.registeredViewModels);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Clears every registered ViewModel. Required by tests.
|
|
97
|
+
*/
|
|
98
|
+
clear() {
|
|
99
|
+
this.registeredViewModels.clear();
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Unsubscribes every registered ViewModel from its scenarios and clears the
|
|
103
|
+
* registry.
|
|
104
|
+
*
|
|
105
|
+
* Without it tests are not isolated: a subscription leaks from test to test.
|
|
106
|
+
*/
|
|
107
|
+
resetAll() {
|
|
108
|
+
this.registeredViewModels.forEach((vm) => {
|
|
109
|
+
try {
|
|
110
|
+
vm.resetScenario();
|
|
111
|
+
} catch {
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
this.clear();
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// src/scenario/_registries/lanka-scenarios-registry/LankaScenariosRegistry.ts
|
|
119
|
+
var release = (scenario) => {
|
|
120
|
+
if (!scenario.cleanup) return;
|
|
121
|
+
try {
|
|
122
|
+
scenario.cleanup();
|
|
123
|
+
} catch (error) {
|
|
124
|
+
lankaLogger.printScenarioLog(`Error cleaning up scenario "${scenario.name}":`, error);
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
var LankaScenariosRegistry = class {
|
|
128
|
+
registeredScenarios = /* @__PURE__ */ new Map();
|
|
129
|
+
scenarioMetadata = /* @__PURE__ */ new Map();
|
|
130
|
+
/**
|
|
131
|
+
* Public: the registry belongs to a framework instance rather than to the
|
|
132
|
+
* module.
|
|
133
|
+
*/
|
|
134
|
+
constructor() {
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The active instance's registry, for callers that cannot hold one:
|
|
138
|
+
* `ALankaScenario` (a base class the consumer extends) and the static
|
|
139
|
+
* `LankaScenarioBootstrap`. Instance holders read `lanka.scenarios`.
|
|
140
|
+
*/
|
|
141
|
+
static getInstance() {
|
|
142
|
+
return requireActiveRuntime().scenarios;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Registers a scenario by hand.
|
|
146
|
+
*
|
|
147
|
+
* @param scenario What to register
|
|
148
|
+
* @returns `false` when it was already registered
|
|
149
|
+
*/
|
|
150
|
+
register(scenario) {
|
|
151
|
+
if (this.registeredScenarios.has(scenario.name)) {
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
this.registeredScenarios.set(scenario.name, scenario);
|
|
155
|
+
this.scenarioMetadata.set(scenario.name, {
|
|
156
|
+
scenario,
|
|
157
|
+
name: scenario.name,
|
|
158
|
+
eventType: scenario.eventType,
|
|
159
|
+
dataTypeName: scenario.dataTypeName,
|
|
160
|
+
isRegistered: true
|
|
161
|
+
});
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Removes a scenario, calling its `cleanup` if it declared one.
|
|
166
|
+
*
|
|
167
|
+
* @param scenarioName Name of the scenario to unregister
|
|
168
|
+
* @returns true if unregistered successfully, false if not found
|
|
169
|
+
*/
|
|
170
|
+
unregister(scenarioName) {
|
|
171
|
+
const scenario = this.registeredScenarios.get(scenarioName);
|
|
172
|
+
if (!scenario) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
const metadata = this.scenarioMetadata.get(scenarioName);
|
|
176
|
+
if (metadata) {
|
|
177
|
+
metadata.isRegistered = false;
|
|
178
|
+
}
|
|
179
|
+
this.registeredScenarios.delete(scenarioName);
|
|
180
|
+
release(scenario);
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Get metadata for a specific scenario
|
|
185
|
+
* @param scenarioName Name of the scenario
|
|
186
|
+
* @returns Scenario metadata or undefined if not found
|
|
187
|
+
*/
|
|
188
|
+
getMetadata(scenarioName) {
|
|
189
|
+
return this.scenarioMetadata.get(scenarioName);
|
|
190
|
+
}
|
|
191
|
+
/** Every registered scenario. */
|
|
192
|
+
getAllScenarios() {
|
|
193
|
+
return Array.from(this.registeredScenarios.values());
|
|
194
|
+
}
|
|
195
|
+
/** Metadata of every scenario. */
|
|
196
|
+
getAllMetadata() {
|
|
197
|
+
return Array.from(this.scenarioMetadata.values());
|
|
198
|
+
}
|
|
199
|
+
/** Whether a scenario with this name is registered. */
|
|
200
|
+
isRegistered(scenarioName) {
|
|
201
|
+
return this.registeredScenarios.has(scenarioName);
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Collects every scenario that registered itself at construction.
|
|
205
|
+
*/
|
|
206
|
+
collectAutoRegisteredScenarios() {
|
|
207
|
+
const autoRegistered = ALankaScenario.getAutoRegisteredScenarios();
|
|
208
|
+
autoRegistered.forEach((scenario) => {
|
|
209
|
+
if (!this.registeredScenarios.has(scenario.name)) {
|
|
210
|
+
this.register(scenario);
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* A scenario by name.
|
|
216
|
+
*
|
|
217
|
+
* @returns `undefined` when there is none
|
|
218
|
+
*/
|
|
219
|
+
getScenarioByName(scenarioName) {
|
|
220
|
+
return this.registeredScenarios.get(scenarioName);
|
|
221
|
+
}
|
|
222
|
+
/** Every registered ViewModel. */
|
|
223
|
+
getAllViewModels() {
|
|
224
|
+
return LankaScenarioVMRegistry.getInstance().getAllViewModels();
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Removes every scenario, calling each one's `cleanup`.
|
|
228
|
+
*
|
|
229
|
+
* What `dispose()` and the between-tests reset go through: `initialize` ran
|
|
230
|
+
* for every scenario at bootstrap, and this is the one moment its mirror
|
|
231
|
+
* image can run for all of them.
|
|
232
|
+
*/
|
|
233
|
+
clear() {
|
|
234
|
+
const scenarios = [...this.registeredScenarios.values()];
|
|
235
|
+
this.registeredScenarios.clear();
|
|
236
|
+
this.scenarioMetadata.clear();
|
|
237
|
+
for (const scenario of scenarios) release(scenario);
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// src/scenario/_abstractions/lanka-scenario/ALankaScenario.ts
|
|
242
|
+
var ALankaScenario = class _ALankaScenario {
|
|
243
|
+
/** A subclass sets this to opt out of self-registration. */
|
|
244
|
+
static skipAutoRegistration;
|
|
245
|
+
/**
|
|
246
|
+
* The self-registration pool.
|
|
247
|
+
*
|
|
248
|
+
* Class-level deliberately: a registry of DEFINITIONS, not runtime state. The
|
|
249
|
+
* classes come from one barrel and both framework instances must see the same
|
|
250
|
+
* list — splitting it would be divergence, not isolation.
|
|
251
|
+
*/
|
|
252
|
+
static autoRegisteredScenarios = /* @__PURE__ */ new Set();
|
|
253
|
+
/** Registers the scenario itself unless the subclass opted out. */
|
|
254
|
+
constructor() {
|
|
255
|
+
const constructor = this.constructor;
|
|
256
|
+
if (!constructor.skipAutoRegistration) {
|
|
257
|
+
_ALankaScenario.autoRegisteredScenarios.add(this);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Every scenario that registered itself.
|
|
262
|
+
*
|
|
263
|
+
* @internal
|
|
264
|
+
*/
|
|
265
|
+
static getAutoRegisteredScenarios() {
|
|
266
|
+
return Array.from(_ALankaScenario.autoRegisteredScenarios);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Clears the auto-registration pool. Required by tests.
|
|
270
|
+
* @internal
|
|
271
|
+
*/
|
|
272
|
+
static clearAutoRegisteredScenarios() {
|
|
273
|
+
_ALankaScenario.autoRegisteredScenarios.clear();
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Registers the scenario by hand.
|
|
277
|
+
*
|
|
278
|
+
* @returns `false` when it was already registered
|
|
279
|
+
*/
|
|
280
|
+
register() {
|
|
281
|
+
return LankaScenariosRegistry.getInstance().register(this);
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Removes the scenario from the registry.
|
|
285
|
+
*
|
|
286
|
+
* @returns `false` when it was not there
|
|
287
|
+
*/
|
|
288
|
+
unregister() {
|
|
289
|
+
return LankaScenariosRegistry.getInstance().unregister(this.name);
|
|
290
|
+
}
|
|
291
|
+
trigger(data) {
|
|
292
|
+
lankaLogger.printScenarioLog("TRIGGER Scenario", this.name, data);
|
|
293
|
+
lankaEventBus.dispatch(this.eventType, data, this.name);
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Subscribes a handler and returns an unsubscribe function.
|
|
297
|
+
*
|
|
298
|
+
* Without the return, unsubscribing is possible only by callback identity, and
|
|
299
|
+
* every ViewModel factory has to keep a map of references for it.
|
|
300
|
+
*/
|
|
301
|
+
subscribe(callback, options) {
|
|
302
|
+
lankaLogger.printScenarioLog("SUBSCRIBE Scenario", this.name, this.dataTypeName);
|
|
303
|
+
return lankaEventBus.subscribe(this.eventType, callback, {
|
|
304
|
+
...options,
|
|
305
|
+
usedBy: options?.usedBy ?? this.name
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
// src/scenario/lanka-scenario-bootstrap/LankaScenarioBootstrap.ts
|
|
311
|
+
import * as ScenariosModule from "@lanka_di/Scenarios";
|
|
312
|
+
var LankaScenarioBootstrap = class {
|
|
313
|
+
/**
|
|
314
|
+
* The bootstrapped flag and the set of initialised VMs live on the INSTANCE.
|
|
315
|
+
*
|
|
316
|
+
* As static fields, a second framework in the same process would exit
|
|
317
|
+
* `bootstrap()` on someone else's flag — never starting at all, with no symptom
|
|
318
|
+
* except that no scenario works.
|
|
319
|
+
*/
|
|
320
|
+
get state() {
|
|
321
|
+
return requireActiveRuntime().scenarioState;
|
|
322
|
+
}
|
|
323
|
+
isScenarioLayerBootstrapped() {
|
|
324
|
+
return this.state.bootstrapped;
|
|
325
|
+
}
|
|
326
|
+
forceInstantiateAllScenarios() {
|
|
327
|
+
const pooled = new Set(
|
|
328
|
+
ALankaScenario.getAutoRegisteredScenarios().map((scenario) => scenario.constructor)
|
|
329
|
+
);
|
|
330
|
+
for (const exported of Object.values(ScenariosModule)) {
|
|
331
|
+
if (typeof exported !== "function") continue;
|
|
332
|
+
if (pooled.has(exported)) continue;
|
|
333
|
+
try {
|
|
334
|
+
new exported();
|
|
335
|
+
} catch {
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
registerScenarioEvents(scenarios) {
|
|
340
|
+
const registeredEventTypes = /* @__PURE__ */ new Set();
|
|
341
|
+
scenarios.forEach((scenario) => {
|
|
342
|
+
if (!registeredEventTypes.has(scenario.eventType)) {
|
|
343
|
+
registeredEventTypes.add(scenario.eventType);
|
|
344
|
+
lankaLogger.printScenarioLog("REGISTER SCENARIO EVENT", scenario.name);
|
|
345
|
+
lankaEventBus.registerEvent(scenario.eventType, {
|
|
346
|
+
dataType: scenario.dataTypeName,
|
|
347
|
+
description: `Scenario: ${scenario.name}`,
|
|
348
|
+
usedBy: [scenario.name],
|
|
349
|
+
priority: 0
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
if (scenario.initialize) {
|
|
353
|
+
lankaLogger.printScenarioLog("INITIALIZE SCENARIO", scenario.name);
|
|
354
|
+
scenario.initialize();
|
|
355
|
+
}
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
initializeAlreadyCreatedViewModels() {
|
|
359
|
+
const viewModels = LankaScenarioVMRegistry.getInstance().getAllViewModels();
|
|
360
|
+
viewModels.forEach((vm) => {
|
|
361
|
+
if (!this.state.initialized.has(vm)) {
|
|
362
|
+
this.state.initialized.add(vm);
|
|
363
|
+
vm.initializeScenario();
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Brings up the scenario layer.
|
|
369
|
+
*
|
|
370
|
+
* Constructs the scenario classes so they can be collected, declares their
|
|
371
|
+
* events on the bus, calls `initialize()` where present, and initialises
|
|
372
|
+
* ViewModels that already exist — which happens in tests and under unusual
|
|
373
|
+
* import order.
|
|
374
|
+
*
|
|
375
|
+
* Idempotent.
|
|
376
|
+
*/
|
|
377
|
+
bootstrap() {
|
|
378
|
+
if (this.state.bootstrapped) return;
|
|
379
|
+
lankaLogger.printScenarioLog("BOOTSTRAP SCENARIOS START");
|
|
380
|
+
this.forceInstantiateAllScenarios();
|
|
381
|
+
const registry = LankaScenariosRegistry.getInstance();
|
|
382
|
+
registry.collectAutoRegisteredScenarios();
|
|
383
|
+
const scenarios = registry.getAllScenarios();
|
|
384
|
+
this.registerScenarioEvents(scenarios);
|
|
385
|
+
this.state.bootstrapped = true;
|
|
386
|
+
this.adoptDeclaredViewModels();
|
|
387
|
+
this.initializeAlreadyCreatedViewModels();
|
|
388
|
+
lankaLogger.printScenarioLog("BOOTSTRAP SCENARIOS FINISH");
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Called by a ViewModel factory when the ViewModel declares scenario handlers.
|
|
392
|
+
*
|
|
393
|
+
* Registers the ViewModel and, if the layer is already up, initialises it
|
|
394
|
+
* immediately. Duplicate registration and duplicate initialisation are
|
|
395
|
+
* impossible.
|
|
396
|
+
*
|
|
397
|
+
* @param viewModel What to register
|
|
398
|
+
* @param name Name for the log
|
|
399
|
+
*/
|
|
400
|
+
/**
|
|
401
|
+
* ViewModels DECLARED in this process.
|
|
402
|
+
*
|
|
403
|
+
* Module-level deliberately, the same case as the scenario pool: a registry of
|
|
404
|
+
* DEFINITIONS, not runtime state. Splitting it between instances would be
|
|
405
|
+
* divergence, not isolation — the classes come from the same modules and both
|
|
406
|
+
* instances must see one list.
|
|
407
|
+
*
|
|
408
|
+
* Two reasons it exists:
|
|
409
|
+
*
|
|
410
|
+
* 1. Declaring a ViewModel is a declaration, not work. A screen file creates it
|
|
411
|
+
* at module level, and import order decides whether that happens before or
|
|
412
|
+
* after `createLanka()`. Requiring a live instance at declaration time
|
|
413
|
+
* requires an import order the consumer does not control.
|
|
414
|
+
* 2. Instances come one after another: every test creates its own. The list is
|
|
415
|
+
* NOT drained by the first — otherwise the second instance would know no
|
|
416
|
+
* module-level ViewModel and its `dispose()` would not remove their
|
|
417
|
+
* subscriptions, so a test would receive events the previous one subscribed
|
|
418
|
+
* to.
|
|
419
|
+
*/
|
|
420
|
+
declaredViewModels = [];
|
|
421
|
+
/**
|
|
422
|
+
* Registers everything declared into a NEW instance.
|
|
423
|
+
*
|
|
424
|
+
* Called twice, and the second call is the one that makes this work on a
|
|
425
|
+
* server: `createLanka` calls it, and so does `bootstrap()`.
|
|
426
|
+
*
|
|
427
|
+
* The reason is an order nobody can change. Where "which instance is active"
|
|
428
|
+
* is answered by a RESOLVER — one instance per request, the shape
|
|
429
|
+
* `@lankajs/host` installs — an instance becomes findable only once the CALLER
|
|
430
|
+
* has put it in its store, and a caller can only do that after `createLanka`
|
|
431
|
+
* has returned. So during creation the answer is honestly "none", and asking
|
|
432
|
+
* for it threw: every server render of an application with a module-level
|
|
433
|
+
* ViewModel failed inside the call that was creating the scope, with a message
|
|
434
|
+
* about running outside one.
|
|
435
|
+
*
|
|
436
|
+
* Skipping is safe precisely because bootstrap adopts again. It is idempotent
|
|
437
|
+
* at the other end too: `attachViewModel` returns early for a ViewModel the
|
|
438
|
+
* registry already holds.
|
|
439
|
+
*/
|
|
440
|
+
adoptDeclaredViewModels() {
|
|
441
|
+
if (!getActiveRuntime()) return;
|
|
442
|
+
for (const { viewModel, name } of [...this.declaredViewModels]) {
|
|
443
|
+
this.attachViewModel(viewModel, name);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Whether the ViewModel being built belongs to ONE scope.
|
|
448
|
+
*
|
|
449
|
+
* A module-level ViewModel is declared once and adopted by every instance
|
|
450
|
+
* ever created, which is what `declaredViewModels` is for and why it is never
|
|
451
|
+
* drained. A SCOPED one is the opposite: it belongs to the request that built
|
|
452
|
+
* it and to nothing after.
|
|
453
|
+
*
|
|
454
|
+
* Declaring one would be the defect this flag exists to prevent, and it is
|
|
455
|
+
* worth spelling out because nothing would look wrong. The array grows by an
|
|
456
|
+
* entry per request for the life of the process, and request N+1 ADOPTS
|
|
457
|
+
* request N's ViewModel — subscribing it to N+1's scenarios, so a dispatch
|
|
458
|
+
* runs N's handlers against N's gateways and writes into N's store. Every
|
|
459
|
+
* suite stays green and the leak is one user seeing another's board.
|
|
460
|
+
*/
|
|
461
|
+
isBuildingScoped = false;
|
|
462
|
+
/**
|
|
463
|
+
* Runs `build` with its declarations kept OUT of the process-wide list.
|
|
464
|
+
*
|
|
465
|
+
* Called by `resolveLankaVM` and by nothing else. A narrow seam rather than a
|
|
466
|
+
* parameter on every factory: the nine ways to build a ViewModel would each
|
|
467
|
+
* have to carry a flag through to `registerViewModel`, and eight of them have
|
|
468
|
+
* no business knowing what a scope is.
|
|
469
|
+
*/
|
|
470
|
+
buildScoped(build) {
|
|
471
|
+
const before = this.isBuildingScoped;
|
|
472
|
+
this.isBuildingScoped = true;
|
|
473
|
+
try {
|
|
474
|
+
return build();
|
|
475
|
+
} finally {
|
|
476
|
+
this.isBuildingScoped = before;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
registerViewModel(viewModel, name) {
|
|
480
|
+
if (!this.isBuildingScoped) {
|
|
481
|
+
const isKnown = this.declaredViewModels.some(
|
|
482
|
+
(declared) => declared.viewModel === viewModel
|
|
483
|
+
);
|
|
484
|
+
if (!isKnown) this.declaredViewModels.push({ viewModel, name });
|
|
485
|
+
}
|
|
486
|
+
if (!getActiveRuntime()) return;
|
|
487
|
+
this.attachViewModel(viewModel, name);
|
|
488
|
+
}
|
|
489
|
+
attachViewModel(viewModel, name) {
|
|
490
|
+
const registry = LankaScenarioVMRegistry.getInstance();
|
|
491
|
+
if (registry.isRegistered(viewModel)) {
|
|
492
|
+
if (name) {
|
|
493
|
+
lankaLogger.printViewModelLog("VM Already Registered (skipped)", name);
|
|
494
|
+
}
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
registry.register(viewModel);
|
|
498
|
+
if (name) {
|
|
499
|
+
lankaLogger.printViewModelLog("Register Scenario VM", name);
|
|
500
|
+
}
|
|
501
|
+
if (this.state.bootstrapped) {
|
|
502
|
+
if (!this.state.initialized.has(viewModel)) {
|
|
503
|
+
this.state.initialized.add(viewModel);
|
|
504
|
+
viewModel.initializeScenario();
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* Resets the whole scenario layer. Without it tests are not isolated.
|
|
510
|
+
*
|
|
511
|
+
* Clears the self-registration list, the scenario registry with its metadata,
|
|
512
|
+
* the ViewModel registry together with all their subscriptions, and the bus —
|
|
513
|
+
* events and
|
|
514
|
+
* middleware.
|
|
515
|
+
*
|
|
516
|
+
* What it does NOT clear by default is which ViewModels were DECLARED, and
|
|
517
|
+
* that default is load-bearing: a module-level ViewModel is built once per
|
|
518
|
+
* process, so the declaration is the only thing that lets a second instance
|
|
519
|
+
* find it. Drop it and its handlers bind to nothing, silently, for the rest of
|
|
520
|
+
* the process — see `declaredViewModels`.
|
|
521
|
+
*
|
|
522
|
+
* `withDeclarations` is for the case that default gets wrong: a suite that
|
|
523
|
+
* builds ViewModels inside test BODIES. Those are declared like any other and
|
|
524
|
+
* nothing un-declares them, so the next bootstrap re-adopts every one ever
|
|
525
|
+
* built and a finished test's handlers run again — against the gateway that
|
|
526
|
+
* test built, which is somebody else's double. Forgetting is not a tombstone:
|
|
527
|
+
* a ViewModel declared again afterwards is adopted again.
|
|
528
|
+
*
|
|
529
|
+
* @param config `withDeclarations` also forgets which ViewModels exist
|
|
530
|
+
*/
|
|
531
|
+
reset(config = {}) {
|
|
532
|
+
ALankaScenario.clearAutoRegisteredScenarios();
|
|
533
|
+
LankaScenariosRegistry.getInstance().clear();
|
|
534
|
+
LankaScenarioVMRegistry.getInstance().resetAll();
|
|
535
|
+
lankaEventBus.clearAllEvents();
|
|
536
|
+
this.state.bootstrapped = false;
|
|
537
|
+
this.state.initialized = /* @__PURE__ */ new WeakSet();
|
|
538
|
+
if (config.withDeclarations) this.declaredViewModels.length = 0;
|
|
539
|
+
}
|
|
540
|
+
};
|
|
541
|
+
var lankaScenarioBootstrap = new LankaScenarioBootstrap();
|
|
542
|
+
|
|
543
|
+
export {
|
|
544
|
+
lankaEventBus,
|
|
545
|
+
ALankaScenario,
|
|
546
|
+
LankaScenarioVMRegistry,
|
|
547
|
+
LankaScenariosRegistry,
|
|
548
|
+
lankaScenarioBootstrap
|
|
549
|
+
};
|
|
550
|
+
//# sourceMappingURL=chunk-EYDMBI5T.js.map
|