lanka 2.1.0 → 2.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{ILankaScenario-DQd9ZfUw.d.ts → ILankaScenario-7J3MoKiY.d.ts} +9 -0
- package/dist/{ILankaScenarioMetadata-BsDp0Bzm.d.ts → ILankaScenarioMetadata-DgOxvpwx.d.ts} +1 -1
- package/dist/LankaScenarioVMRegistry-CFzCpIFd.d.ts +46 -0
- package/dist/{LankaScenarioVMRegistry-DySAOaj2.d.ts → LankaScenariosRegistry-DiLN9xwy.d.ts} +3 -46
- package/dist/_extend/index.d.ts +27 -6
- package/dist/_extend/index.js +45 -39
- package/dist/_extend/index.js.map +1 -1
- package/dist/_internal/index.d.ts +5 -4
- package/dist/_internal/index.js +3 -1
- package/dist/_internal/index.js.map +1 -1
- package/dist/{activeRuntime-ByucLPhj.d.ts → activeRuntime-DxB62KN4.d.ts} +8 -4
- package/dist/bootstrap/index.d.ts +8 -7
- package/dist/bootstrap/index.js +11 -11
- package/dist/chunk-2ICKGQXS.js +21 -0
- package/dist/chunk-2ICKGQXS.js.map +1 -0
- package/dist/{chunk-MKKMTLOY.js → chunk-4VFVACSL.js} +38 -5
- package/dist/{chunk-MKKMTLOY.js.map → chunk-4VFVACSL.js.map} +1 -1
- package/dist/{chunk-SO7D5E7O.js → chunk-532WVMAF.js} +16 -16
- package/dist/chunk-532WVMAF.js.map +1 -0
- package/dist/{chunk-FII3PW2G.js → chunk-AMLUKB6A.js} +2 -2
- package/dist/{chunk-O5EUTNR6.js → chunk-DKLOCKS4.js} +2 -2
- package/dist/{chunk-42CWYVZJ.js → chunk-EH5WZSRJ.js} +5 -5
- package/dist/{chunk-RUMUFHSL.js → chunk-JGJBFELR.js} +2 -2
- package/dist/{chunk-NWEHOMTS.js → chunk-L27FF2IH.js} +3 -3
- package/dist/chunk-M4BK6GBV.js +90 -0
- package/dist/chunk-M4BK6GBV.js.map +1 -0
- package/dist/{chunk-BHQ2SQ7P.js → chunk-NMFNEVNE.js} +2 -2
- package/dist/{chunk-7DQUF2QR.js → chunk-SP5OUTWF.js} +2 -2
- package/dist/chunk-XTVEHYIZ.js +89 -0
- package/dist/chunk-XTVEHYIZ.js.map +1 -0
- package/dist/config/index.js +3 -3
- package/dist/{createLanka-DvUGu9Hl.d.ts → createLanka-AuiMfPL9.d.ts} +4 -4
- package/dist/{createLankaScope-CVoV0EwO.d.ts → createLankaScope-DeElRH-E.d.ts} +7 -1
- package/dist/errors/index.js +3 -3
- package/dist/gateway/index.js +6 -6
- package/dist/index.d.ts +8 -7
- package/dist/index.js +14 -14
- package/dist/locator/index.d.ts +111 -109
- package/dist/locator/index.js +35 -9
- package/dist/locator/index.js.map +1 -1
- package/dist/locator/scenario/lanka-scenario-locator/LankaScenarioLocator.d.ts +1 -1
- package/dist/locator/scenario/lanka-scenario-locator/LankaScenarioLocator.js +5 -5
- package/dist/logger/index.js +3 -3
- package/dist/mock/index.js +3 -3
- package/dist/scenario/index.d.ts +18 -4
- package/dist/scenario/index.js +5 -5
- package/dist/stream/index.d.ts +8 -7
- package/dist/viewmodel/index.d.ts +1 -1
- package/dist/viewmodel/index.js +7 -6
- package/dist/viewmodel/index.js.map +1 -1
- package/package.json +2 -2
- package/skills/lanka-core/SKILL.md +3 -1
- package/skills/lanka-core/reference.md +21 -1
- package/skills/lanka-packages/SKILL.md +1 -1
- package/dist/chunk-H5TIUKRK.js +0 -59
- package/dist/chunk-H5TIUKRK.js.map +0 -1
- package/dist/chunk-SBITVBF7.js +0 -49
- package/dist/chunk-SBITVBF7.js.map +0 -1
- package/dist/chunk-SO7D5E7O.js.map +0 -1
- package/dist/chunk-XGMXT4XZ.js +0 -46
- package/dist/chunk-XGMXT4XZ.js.map +0 -1
- /package/dist/{chunk-FII3PW2G.js.map → chunk-AMLUKB6A.js.map} +0 -0
- /package/dist/{chunk-O5EUTNR6.js.map → chunk-DKLOCKS4.js.map} +0 -0
- /package/dist/{chunk-42CWYVZJ.js.map → chunk-EH5WZSRJ.js.map} +0 -0
- /package/dist/{chunk-RUMUFHSL.js.map → chunk-JGJBFELR.js.map} +0 -0
- /package/dist/{chunk-NWEHOMTS.js.map → chunk-L27FF2IH.js.map} +0 -0
- /package/dist/{chunk-BHQ2SQ7P.js.map → chunk-NMFNEVNE.js.map} +0 -0
- /package/dist/{chunk-7DQUF2QR.js.map → chunk-SP5OUTWF.js.map} +0 -0
package/dist/bootstrap/index.js
CHANGED
|
@@ -3,21 +3,21 @@ import {
|
|
|
3
3
|
createLanka,
|
|
4
4
|
resetActiveLanka,
|
|
5
5
|
startLanka
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-532WVMAF.js";
|
|
7
|
+
import "../chunk-M4BK6GBV.js";
|
|
8
8
|
import "../chunk-BMF4TM2Z.js";
|
|
9
|
-
import "../chunk-
|
|
10
|
-
import "../chunk-MKKMTLOY.js";
|
|
11
|
-
import "../chunk-NWEHOMTS.js";
|
|
12
|
-
import "../chunk-XESL274R.js";
|
|
13
|
-
import "../chunk-BHQ2SQ7P.js";
|
|
14
|
-
import "../chunk-3R2NO47A.js";
|
|
9
|
+
import "../chunk-EH5WZSRJ.js";
|
|
15
10
|
import "../chunk-24MUFFHF.js";
|
|
11
|
+
import "../chunk-3R2NO47A.js";
|
|
16
12
|
import "../chunk-JZJ6GXX3.js";
|
|
17
13
|
import "../chunk-N3275IPH.js";
|
|
18
|
-
import "../chunk-
|
|
19
|
-
import "../chunk-
|
|
20
|
-
import "../chunk-
|
|
14
|
+
import "../chunk-4VFVACSL.js";
|
|
15
|
+
import "../chunk-L27FF2IH.js";
|
|
16
|
+
import "../chunk-XESL274R.js";
|
|
17
|
+
import "../chunk-NMFNEVNE.js";
|
|
18
|
+
import "../chunk-AMLUKB6A.js";
|
|
19
|
+
import "../chunk-SP5OUTWF.js";
|
|
20
|
+
import "../chunk-XTVEHYIZ.js";
|
|
21
21
|
export {
|
|
22
22
|
ALankaPlugin,
|
|
23
23
|
createLanka,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// src/locator/_factories/create-lanka-locator-proxy/createLankaLocatorProxy.ts
|
|
2
|
+
function createLankaLocatorProxy(config) {
|
|
3
|
+
const { locator, protectedProperties = [], errorPrefix = "Cannot access" } = config;
|
|
4
|
+
return new Proxy(locator, {
|
|
5
|
+
get(target, prop) {
|
|
6
|
+
if (typeof prop !== "string") {
|
|
7
|
+
throw new Error(`${errorPrefix} with symbol property: ${String(prop)}`);
|
|
8
|
+
}
|
|
9
|
+
const internalProps = ["_", "constructor", "prototype", ...protectedProperties];
|
|
10
|
+
if (prop.startsWith("_") || internalProps.some((internalProp) => prop === internalProp)) {
|
|
11
|
+
throw new Error(`${errorPrefix} with property: ${prop}`);
|
|
12
|
+
}
|
|
13
|
+
return target.get(prop);
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
createLankaLocatorProxy
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=chunk-2ICKGQXS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/locator/_factories/create-lanka-locator-proxy/createLankaLocatorProxy.ts"],"sourcesContent":["import type { ILankaLocator } from \"../../_interfaces/ILankaLocator\";\n\n/**\n * Configuration of the global locator proxy.\n */\nexport interface ILankaLocatorProxyConfig<TInstance> {\n\t/** The locator that actually resolves instances. */\n\tlocator: ILankaLocator<TInstance>;\n\t/** Properties whose access must throw. */\n\tprotectedProperties?: string[];\n\t/** Prefix of the message thrown for an unknown property. */\n\terrorPrefix?: string;\n}\n\n/**\n * Creates a Proxy for dynamic access to instances with type safety.\n * Converts camelCase property access to PascalCase instance names.\n *\n * @param config Proxy configuration\n * @returns Proxy object typed as TType\n */\nexport function createLankaLocatorProxy<TInstance, TType extends Record<string, TInstance>>(\n\tconfig: ILankaLocatorProxyConfig<TInstance>,\n): TType {\n\tconst { locator, protectedProperties = [], errorPrefix = \"Cannot access\" } = config;\n\n\treturn new Proxy(locator, {\n\t\tget(target, prop: string | symbol): TInstance {\n\t\t\t// Symbols such as `Symbol.iterator` are not instance names.\n\t\t\tif (typeof prop !== \"string\") {\n\t\t\t\tthrow new Error(`${errorPrefix} with symbol property: ${String(prop)}`);\n\t\t\t}\n\n\t\t\t// Internal properties are rejected.\n\t\t\tconst internalProps = [\"_\", \"constructor\", \"prototype\", ...protectedProperties];\n\n\t\t\tif (\n\t\t\t\tprop.startsWith(\"_\") ||\n\t\t\t\tinternalProps.some((internalProp) => prop === internalProp)\n\t\t\t) {\n\t\t\t\tthrow new Error(`${errorPrefix} with property: ${prop}`);\n\t\t\t}\n\n\t\t\t// The instance for a camelCase property name.\n\t\t\treturn target.get(prop);\n\t\t},\n\t}) as unknown as TType;\n}\n"],"mappings":";AAqBO,SAAS,wBACf,QACQ;AACR,QAAM,EAAE,SAAS,sBAAsB,CAAC,GAAG,cAAc,gBAAgB,IAAI;AAE7E,SAAO,IAAI,MAAM,SAAS;AAAA,IACzB,IAAI,QAAQ,MAAkC;AAE7C,UAAI,OAAO,SAAS,UAAU;AAC7B,cAAM,IAAI,MAAM,GAAG,WAAW,0BAA0B,OAAO,IAAI,CAAC,EAAE;AAAA,MACvE;AAGA,YAAM,gBAAgB,CAAC,KAAK,eAAe,aAAa,GAAG,mBAAmB;AAE9E,UACC,KAAK,WAAW,GAAG,KACnB,cAAc,KAAK,CAAC,iBAAiB,SAAS,YAAY,GACzD;AACD,cAAM,IAAI,MAAM,GAAG,WAAW,mBAAmB,IAAI,EAAE;AAAA,MACxD;AAGA,aAAO,OAAO,IAAI,IAAI;AAAA,IACvB;AAAA,EACD,CAAC;AACF;","names":[]}
|
|
@@ -3,14 +3,14 @@ import {
|
|
|
3
3
|
LankaScenarioVMRegistry,
|
|
4
4
|
LankaScenariosRegistry,
|
|
5
5
|
lankaEventBus
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-L27FF2IH.js";
|
|
7
7
|
import {
|
|
8
8
|
lankaLogger
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-AMLUKB6A.js";
|
|
10
10
|
import {
|
|
11
11
|
getActiveRuntime,
|
|
12
12
|
requireActiveRuntime
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-XTVEHYIZ.js";
|
|
14
14
|
|
|
15
15
|
// src/scenario/lanka-scenario-bootstrap/LankaScenarioBootstrap.ts
|
|
16
16
|
var LankaScenarioBootstrap = class {
|
|
@@ -163,6 +163,8 @@ var LankaScenarioBootstrap = class {
|
|
|
163
163
|
* suite stays green and the leak is one user seeing another's board.
|
|
164
164
|
*/
|
|
165
165
|
isBuildingScoped = false;
|
|
166
|
+
/** Who is told about each scoped registration while `buildScoped` runs. */
|
|
167
|
+
scopedRegistrations = null;
|
|
166
168
|
/**
|
|
167
169
|
* Runs `build` with its declarations kept OUT of the process-wide list.
|
|
168
170
|
*
|
|
@@ -171,16 +173,47 @@ var LankaScenarioBootstrap = class {
|
|
|
171
173
|
* have to carry a flag through to `registerViewModel`, and eight of them have
|
|
172
174
|
* no business knowing what a scope is.
|
|
173
175
|
*/
|
|
174
|
-
buildScoped(build) {
|
|
176
|
+
buildScoped(build, onRegistered) {
|
|
175
177
|
const before = this.isBuildingScoped;
|
|
178
|
+
const beforeRegistrations = this.scopedRegistrations;
|
|
176
179
|
this.isBuildingScoped = true;
|
|
180
|
+
this.scopedRegistrations = onRegistered ?? null;
|
|
177
181
|
try {
|
|
178
182
|
return build();
|
|
179
183
|
} finally {
|
|
180
184
|
this.isBuildingScoped = before;
|
|
185
|
+
this.scopedRegistrations = beforeRegistrations;
|
|
181
186
|
}
|
|
182
187
|
}
|
|
188
|
+
/**
|
|
189
|
+
* The scoped state as it is NOW, as a runner that re-enters it later.
|
|
190
|
+
*
|
|
191
|
+
* For a build that is deferred past the window `buildScoped` opened — a lazy
|
|
192
|
+
* ViewModel builds on its first read, after `resolveLankaVM` has returned.
|
|
193
|
+
* Without it that build would run under whatever state is current at the
|
|
194
|
+
* read: outside every scope, so a scoped ViewModel would join the
|
|
195
|
+
* process-wide list every later instance adopts; or inside SOMEBODY ELSE'S,
|
|
196
|
+
* so a module-level one first read during another scope's build would die
|
|
197
|
+
* with that scope. Captured at creation, it belongs where it was declared.
|
|
198
|
+
*/
|
|
199
|
+
captureScoped() {
|
|
200
|
+
const captured = this.isBuildingScoped;
|
|
201
|
+
const capturedRegistrations = this.scopedRegistrations;
|
|
202
|
+
return (build) => {
|
|
203
|
+
const before = this.isBuildingScoped;
|
|
204
|
+
const beforeRegistrations = this.scopedRegistrations;
|
|
205
|
+
this.isBuildingScoped = captured;
|
|
206
|
+
this.scopedRegistrations = capturedRegistrations;
|
|
207
|
+
try {
|
|
208
|
+
return build();
|
|
209
|
+
} finally {
|
|
210
|
+
this.isBuildingScoped = before;
|
|
211
|
+
this.scopedRegistrations = beforeRegistrations;
|
|
212
|
+
}
|
|
213
|
+
};
|
|
214
|
+
}
|
|
183
215
|
registerViewModel(viewModel, name) {
|
|
216
|
+
this.scopedRegistrations?.(viewModel);
|
|
184
217
|
if (!this.isBuildingScoped) {
|
|
185
218
|
const isKnown = this.declaredViewModels.some(
|
|
186
219
|
(declared) => declared.viewModel === viewModel
|
|
@@ -247,4 +280,4 @@ var lankaScenarioBootstrap = new LankaScenarioBootstrap();
|
|
|
247
280
|
export {
|
|
248
281
|
lankaScenarioBootstrap
|
|
249
282
|
};
|
|
250
|
-
//# sourceMappingURL=chunk-
|
|
283
|
+
//# sourceMappingURL=chunk-4VFVACSL.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/scenario/lanka-scenario-bootstrap/LankaScenarioBootstrap.ts"],"sourcesContent":["import type { ILankaScenario } from \"../_interfaces/ILankaScenario\";\nimport type { ILankaScenarioVM } from \"../_interfaces/ILankaScenarioVM\";\nimport type { ILankaScenarioResetConfig } from \"../_interfaces/ILankaScenarioResetConfig\";\nimport { LankaScenariosRegistry } from \"../_registries/lanka-scenarios-registry/LankaScenariosRegistry\";\nimport { LankaScenarioVMRegistry } from \"../_registries/lanka-scenario-vm-registry/LankaScenarioVMRegistry\";\nimport { ALankaScenario } from \"../_abstractions/lanka-scenario/ALankaScenario\";\nimport { lankaLogger } from \"../../logger/lanka-logger/LankaLogger\";\n\n/**\n * Brings up the scenario layer — deliberately React-free.\n *\n * Two jobs: declare every scenario's events on the bus as early as possible,\n * before the first ViewModel exists; and let a ViewModel raise its own\n * subscriptions at construction.\n *\n * Called from the application entry point before ViewModels are imported.\n */\n\nimport { lankaEventBus } from \"../event-bus/_facades/lanka-event-bus/lankaEventBus\";\nimport {\n\tgetActiveRuntime,\n\trequireActiveRuntime,\n} from \"../../_internal/active-runtime/activeRuntime\";\n\n/**\n * Bootstrapping the scenario layer, for callers with no instance in hand.\n *\n * An ordinary class with an ordinary instance: the declared-ViewModel list below\n * is deliberately shared across instances — every test builds a new framework and\n * module-level ViewModels are declared once — so the single instance IS the\n * shared list, and a second one would be a second list nobody adopts.\n */\nexport class LankaScenarioBootstrap {\n\t/**\n\t * The bootstrapped flag and the set of initialised VMs live on the INSTANCE.\n\t *\n\t * As static fields, a second framework in the same process would exit\n\t * `bootstrap()` on someone else's flag — never starting at all, with no symptom\n\t * except that no scenario works.\n\t */\n\tprivate get state() {\n\t\treturn requireActiveRuntime().scenarioState;\n\t}\n\n\tpublic isScenarioLayerBootstrapped(): boolean {\n\t\treturn this.state.bootstrapped;\n\t}\n\n\tprivate forceInstantiateAllScenarios(): void {\n\t\t// Every class the pool already holds an instance of. Constructing it again\n\t\t// would add a second instance to a pool nothing ever drains: each bootstrap\n\t\t// — one per framework instance, one per test — grew it by the whole barrel,\n\t\t// and both `collectAutoRegisteredScenarios` and the locator's fallback walk\n\t\t// it in full.\n\t\tconst pooled = new Set(\n\t\t\tALankaScenario.getAutoRegisteredScenarios().map((scenario) => scenario.constructor),\n\t\t);\n\n\t\t// The list of declared scenario classes comes from the LOCATOR, which is the\n\t\t// one module that reads `@lanka_di/Scenarios`.\n\t\t//\n\t\t// It was read here too until 2.0.1, and that is the whole reason this line\n\t\t// has a comment. The framework reading a consumer barrel puts the module\n\t\t// that does it inside a cycle — barrel → consumer's class → back into the\n\t\t// framework — and this module lives in `lanka/scenario`, which is where a\n\t\t// consumer's scenario class imports `ALankaScenario` from. A bundler orders\n\t\t// the chunks behind that entry as it pleases; with the barrel-reading one\n\t\t// first, the consumer's class extended `undefined` and no application with a\n\t\t// scenario started at all. `lanka/locator` holds the cycle now, and nothing\n\t\t// a barrel exports imports `lanka/locator`.\n\t\t//\n\t\t// Via the runtime rather than an import, because that is the direction that\n\t\t// already exists: this is an ambient facade and reaches its instance exactly\n\t\t// as it reaches `scenarioState` above.\n\t\tconst declared = requireActiveRuntime().locators.scenarios.getDeclaredScenarioClasses();\n\n\t\tfor (const Scenario of declared) {\n\t\t\tif (pooled.has(Scenario)) continue;\n\n\t\t\ttry {\n\t\t\t\t// Constructing an ALankaScenario subclass puts it into the\n\t\t\t\t// self-registration pool — see ALankaScenario.\n\t\t\t\tnew Scenario();\n\t\t\t} catch {\n\t\t\t\t// Not every export is constructible; skip those.\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate registerScenarioEvents(scenarios: ILankaScenario<unknown>[]): void {\n\t\tconst registeredEventTypes = new Set<string>();\n\n\t\tscenarios.forEach((scenario) => {\n\t\t\tif (!registeredEventTypes.has(scenario.eventType)) {\n\t\t\t\tregisteredEventTypes.add(scenario.eventType);\n\n\t\t\t\tlankaLogger.printScenarioLog(\"REGISTER SCENARIO EVENT\", scenario.name);\n\t\t\t\tlankaEventBus.registerEvent(scenario.eventType, {\n\t\t\t\t\tdataType: scenario.dataTypeName,\n\t\t\t\t\tdescription: `Scenario: ${scenario.name}`,\n\t\t\t\t\tusedBy: [scenario.name],\n\t\t\t\t\tpriority: 0,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (scenario.initialize) {\n\t\t\t\tlankaLogger.printScenarioLog(\"INITIALIZE SCENARIO\", scenario.name);\n\t\t\t\tscenario.initialize();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate initializeAlreadyCreatedViewModels(): void {\n\t\tconst viewModels = LankaScenarioVMRegistry.getInstance().getAllViewModels();\n\t\tviewModels.forEach((vm) => {\n\t\t\tif (!this.state.initialized.has(vm)) {\n\t\t\t\tthis.state.initialized.add(vm);\n\t\t\t\tvm.initializeScenario();\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Brings up the scenario layer.\n\t *\n\t * Constructs the scenario classes so they can be collected, declares their\n\t * events on the bus, calls `initialize()` where present, and initialises\n\t * ViewModels that already exist — which happens in tests and under unusual\n\t * import order.\n\t *\n\t * Idempotent.\n\t */\n\tpublic bootstrap(): void {\n\t\tif (this.state.bootstrapped) return;\n\n\t\tlankaLogger.printScenarioLog(\"BOOTSTRAP SCENARIOS START\");\n\n\t\t// Instances must exist, or the registry has nothing to collect.\n\t\tthis.forceInstantiateAllScenarios();\n\n\t\tconst registry = LankaScenariosRegistry.getInstance();\n\t\tregistry.collectAutoRegisteredScenarios();\n\n\t\tconst scenarios = registry.getAllScenarios();\n\t\tthis.registerScenarioEvents(scenarios);\n\n\t\tthis.state.bootstrapped = true;\n\n\t\t// The second adoption. On a server this is the FIRST one that can succeed:\n\t\t// the instance is in its caller's store by now, and creation's attempt was\n\t\t// made before it could be. In a browser it is a no-op — creation adopted\n\t\t// already, and attaching is idempotent.\n\t\tthis.adoptDeclaredViewModels();\n\n\t\t// Some ViewModels may predate bootstrap — in tests, or under unusual import\n\t\t// order; initialise them now.\n\t\tthis.initializeAlreadyCreatedViewModels();\n\n\t\tlankaLogger.printScenarioLog(\"BOOTSTRAP SCENARIOS FINISH\");\n\t}\n\n\t/**\n\t * Called by a ViewModel factory when the ViewModel declares scenario handlers.\n\t *\n\t * Registers the ViewModel and, if the layer is already up, initialises it\n\t * immediately. Duplicate registration and duplicate initialisation are\n\t * impossible.\n\t *\n\t * @param viewModel What to register\n\t * @param name Name for the log\n\t */\n\t/**\n\t * ViewModels DECLARED in this process.\n\t *\n\t * Module-level deliberately, the same case as the scenario pool: a registry of\n\t * DEFINITIONS, not runtime state. Splitting it between instances would be\n\t * divergence, not isolation — the classes come from the same modules and both\n\t * instances must see one list.\n\t *\n\t * Two reasons it exists:\n\t *\n\t * 1. Declaring a ViewModel is a declaration, not work. A screen file creates it\n\t * at module level, and import order decides whether that happens before or\n\t * after `createLanka()`. Requiring a live instance at declaration time\n\t * requires an import order the consumer does not control.\n\t * 2. Instances come one after another: every test creates its own. The list is\n\t * NOT drained by the first — otherwise the second instance would know no\n\t * module-level ViewModel and its `dispose()` would not remove their\n\t * subscriptions, so a test would receive events the previous one subscribed\n\t * to.\n\t */\n\tprivate readonly declaredViewModels: { viewModel: ILankaScenarioVM; name?: string }[] = [];\n\n\t/**\n\t * Registers everything declared into a NEW instance.\n\t *\n\t * Called twice, and the second call is the one that makes this work on a\n\t * server: `createLanka` calls it, and so does `bootstrap()`.\n\t *\n\t * The reason is an order nobody can change. Where \"which instance is active\"\n\t * is answered by a RESOLVER — one instance per request, the shape\n\t * `@lankajs/host` installs — an instance becomes findable only once the CALLER\n\t * has put it in its store, and a caller can only do that after `createLanka`\n\t * has returned. So during creation the answer is honestly \"none\", and asking\n\t * for it threw: every server render of an application with a module-level\n\t * ViewModel failed inside the call that was creating the scope, with a message\n\t * about running outside one.\n\t *\n\t * Skipping is safe precisely because bootstrap adopts again. It is idempotent\n\t * at the other end too: `attachViewModel` returns early for a ViewModel the\n\t * registry already holds.\n\t */\n\tpublic adoptDeclaredViewModels(): void {\n\t\tif (!getActiveRuntime()) return;\n\n\t\tfor (const { viewModel, name } of [...this.declaredViewModels]) {\n\t\t\tthis.attachViewModel(viewModel, name);\n\t\t}\n\t}\n\n\t/**\n\t * Whether the ViewModel being built belongs to ONE scope.\n\t *\n\t * A module-level ViewModel is declared once and adopted by every instance\n\t * ever created, which is what `declaredViewModels` is for and why it is never\n\t * drained. A SCOPED one is the opposite: it belongs to the request that built\n\t * it and to nothing after.\n\t *\n\t * Declaring one would be the defect this flag exists to prevent, and it is\n\t * worth spelling out because nothing would look wrong. The array grows by an\n\t * entry per request for the life of the process, and request N+1 ADOPTS\n\t * request N's ViewModel — subscribing it to N+1's scenarios, so a dispatch\n\t * runs N's handlers against N's gateways and writes into N's store. Every\n\t * suite stays green and the leak is one user seeing another's board.\n\t */\n\tprivate isBuildingScoped = false;\n\n\t/**\n\t * Runs `build` with its declarations kept OUT of the process-wide list.\n\t *\n\t * Called by `resolveLankaVM` and by nothing else. A narrow seam rather than a\n\t * parameter on every factory: the nine ways to build a ViewModel would each\n\t * have to carry a flag through to `registerViewModel`, and eight of them have\n\t * no business knowing what a scope is.\n\t */\n\tpublic buildScoped<TBuilt>(build: () => TBuilt): TBuilt {\n\t\tconst before = this.isBuildingScoped;\n\n\t\tthis.isBuildingScoped = true;\n\n\t\ttry {\n\t\t\treturn build();\n\t\t} finally {\n\t\t\tthis.isBuildingScoped = before;\n\t\t}\n\t}\n\n\tpublic registerViewModel(viewModel: ILankaScenarioVM, name?: string): void {\n\t\tif (!this.isBuildingScoped) {\n\t\t\tconst isKnown = this.declaredViewModels.some(\n\t\t\t\t(declared) => declared.viewModel === viewModel,\n\t\t\t);\n\t\t\tif (!isKnown) this.declaredViewModels.push({ viewModel, name });\n\t\t}\n\n\t\t// No instance yet: the declaration came before bootstrap, and whoever\n\t\t// bootstraps will pick it up.\n\t\tif (!getActiveRuntime()) return;\n\n\t\tthis.attachViewModel(viewModel, name);\n\t}\n\n\tprivate attachViewModel(viewModel: ILankaScenarioVM, name?: string): void {\n\t\tconst registry = LankaScenarioVMRegistry.getInstance();\n\n\t\t// Already registered — nothing to do.\n\t\tif (registry.isRegistered(viewModel)) {\n\t\t\tif (name) {\n\t\t\t\tlankaLogger.printViewModelLog(\"VM Already Registered (skipped)\", name);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Register it.\n\t\tregistry.register(viewModel);\n\n\t\tif (name) {\n\t\t\tlankaLogger.printViewModelLog(\"Register Scenario VM\", name);\n\t\t}\n\n\t\t// The layer is already up — initialise it now rather than at the next\n\t\t// bootstrap.\n\t\tif (this.state.bootstrapped) {\n\t\t\tif (!this.state.initialized.has(viewModel)) {\n\t\t\t\tthis.state.initialized.add(viewModel);\n\t\t\t\tviewModel.initializeScenario();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Resets the whole scenario layer. Without it tests are not isolated.\n\t *\n\t * Clears the self-registration list, the scenario registry with its metadata,\n\t * the ViewModel registry together with all their subscriptions, and the bus —\n\t * events and\n\t * middleware.\n\t *\n\t * What it does NOT clear by default is which ViewModels were DECLARED, and\n\t * that default is load-bearing: a module-level ViewModel is built once per\n\t * process, so the declaration is the only thing that lets a second instance\n\t * find it. Drop it and its handlers bind to nothing, silently, for the rest of\n\t * the process — see `declaredViewModels`.\n\t *\n\t * `withDeclarations` is for the case that default gets wrong: a suite that\n\t * builds ViewModels inside test BODIES. Those are declared like any other and\n\t * nothing un-declares them, so the next bootstrap re-adopts every one ever\n\t * built and a finished test's handlers run again — against the gateway that\n\t * test built, which is somebody else's double. Forgetting is not a tombstone:\n\t * a ViewModel declared again afterwards is adopted again.\n\t *\n\t * @param config `withDeclarations` also forgets which ViewModels exist\n\t */\n\tpublic reset(config: ILankaScenarioResetConfig = {}): void {\n\t\tALankaScenario.clearAutoRegisteredScenarios();\n\t\tLankaScenariosRegistry.getInstance().clear();\n\t\tLankaScenarioVMRegistry.getInstance().resetAll();\n\t\tlankaEventBus.clearAllEvents();\n\t\tthis.state.bootstrapped = false;\n\t\tthis.state.initialized = new WeakSet<ILankaScenarioVM>();\n\n\t\tif (config.withDeclarations) this.declaredViewModels.length = 0;\n\t}\n}\n\n/** The one every caller wants. */\nexport const lankaScenarioBootstrap = new LankaScenarioBootstrap();\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/scenario/lanka-scenario-bootstrap/LankaScenarioBootstrap.ts"],"sourcesContent":["import type { ILankaScenario } from \"../_interfaces/ILankaScenario\";\nimport type { ILankaScenarioVM } from \"../_interfaces/ILankaScenarioVM\";\nimport type { ILankaScenarioResetConfig } from \"../_interfaces/ILankaScenarioResetConfig\";\nimport { LankaScenariosRegistry } from \"../_registries/lanka-scenarios-registry/LankaScenariosRegistry\";\nimport { LankaScenarioVMRegistry } from \"../_registries/lanka-scenario-vm-registry/LankaScenarioVMRegistry\";\nimport { ALankaScenario } from \"../_abstractions/lanka-scenario/ALankaScenario\";\nimport { lankaLogger } from \"../../logger/lanka-logger/LankaLogger\";\n\n/**\n * Brings up the scenario layer — deliberately React-free.\n *\n * Two jobs: declare every scenario's events on the bus as early as possible,\n * before the first ViewModel exists; and let a ViewModel raise its own\n * subscriptions at construction.\n *\n * Called from the application entry point before ViewModels are imported.\n */\n\nimport { lankaEventBus } from \"../event-bus/_facades/lanka-event-bus/lankaEventBus\";\nimport {\n\tgetActiveRuntime,\n\trequireActiveRuntime,\n} from \"../../_internal/active-runtime/activeRuntime\";\n\n/**\n * Bootstrapping the scenario layer, for callers with no instance in hand.\n *\n * An ordinary class with an ordinary instance: the declared-ViewModel list below\n * is deliberately shared across instances — every test builds a new framework and\n * module-level ViewModels are declared once — so the single instance IS the\n * shared list, and a second one would be a second list nobody adopts.\n */\nexport class LankaScenarioBootstrap {\n\t/**\n\t * The bootstrapped flag and the set of initialised VMs live on the INSTANCE.\n\t *\n\t * As static fields, a second framework in the same process would exit\n\t * `bootstrap()` on someone else's flag — never starting at all, with no symptom\n\t * except that no scenario works.\n\t */\n\tprivate get state() {\n\t\treturn requireActiveRuntime().scenarioState;\n\t}\n\n\tpublic isScenarioLayerBootstrapped(): boolean {\n\t\treturn this.state.bootstrapped;\n\t}\n\n\tprivate forceInstantiateAllScenarios(): void {\n\t\t// Every class the pool already holds an instance of. Constructing it again\n\t\t// would add a second instance to a pool nothing ever drains: each bootstrap\n\t\t// — one per framework instance, one per test — grew it by the whole barrel,\n\t\t// and both `collectAutoRegisteredScenarios` and the locator's fallback walk\n\t\t// it in full.\n\t\tconst pooled = new Set(\n\t\t\tALankaScenario.getAutoRegisteredScenarios().map((scenario) => scenario.constructor),\n\t\t);\n\n\t\t// The list of declared scenario classes comes from the LOCATOR, which is the\n\t\t// one module that reads `@lanka_di/Scenarios`.\n\t\t//\n\t\t// It was read here too until 2.0.1, and that is the whole reason this line\n\t\t// has a comment. The framework reading a consumer barrel puts the module\n\t\t// that does it inside a cycle — barrel → consumer's class → back into the\n\t\t// framework — and this module lives in `lanka/scenario`, which is where a\n\t\t// consumer's scenario class imports `ALankaScenario` from. A bundler orders\n\t\t// the chunks behind that entry as it pleases; with the barrel-reading one\n\t\t// first, the consumer's class extended `undefined` and no application with a\n\t\t// scenario started at all. `lanka/locator` holds the cycle now, and nothing\n\t\t// a barrel exports imports `lanka/locator`.\n\t\t//\n\t\t// Via the runtime rather than an import, because that is the direction that\n\t\t// already exists: this is an ambient facade and reaches its instance exactly\n\t\t// as it reaches `scenarioState` above.\n\t\tconst declared = requireActiveRuntime().locators.scenarios.getDeclaredScenarioClasses();\n\n\t\tfor (const Scenario of declared) {\n\t\t\tif (pooled.has(Scenario)) continue;\n\n\t\t\ttry {\n\t\t\t\t// Constructing an ALankaScenario subclass puts it into the\n\t\t\t\t// self-registration pool — see ALankaScenario.\n\t\t\t\tnew Scenario();\n\t\t\t} catch {\n\t\t\t\t// Not every export is constructible; skip those.\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate registerScenarioEvents(scenarios: ILankaScenario<unknown>[]): void {\n\t\tconst registeredEventTypes = new Set<string>();\n\n\t\tscenarios.forEach((scenario) => {\n\t\t\tif (!registeredEventTypes.has(scenario.eventType)) {\n\t\t\t\tregisteredEventTypes.add(scenario.eventType);\n\n\t\t\t\tlankaLogger.printScenarioLog(\"REGISTER SCENARIO EVENT\", scenario.name);\n\t\t\t\tlankaEventBus.registerEvent(scenario.eventType, {\n\t\t\t\t\tdataType: scenario.dataTypeName,\n\t\t\t\t\tdescription: `Scenario: ${scenario.name}`,\n\t\t\t\t\tusedBy: [scenario.name],\n\t\t\t\t\tpriority: 0,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (scenario.initialize) {\n\t\t\t\tlankaLogger.printScenarioLog(\"INITIALIZE SCENARIO\", scenario.name);\n\t\t\t\tscenario.initialize();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate initializeAlreadyCreatedViewModels(): void {\n\t\tconst viewModels = LankaScenarioVMRegistry.getInstance().getAllViewModels();\n\t\tviewModels.forEach((vm) => {\n\t\t\tif (!this.state.initialized.has(vm)) {\n\t\t\t\tthis.state.initialized.add(vm);\n\t\t\t\tvm.initializeScenario();\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Brings up the scenario layer.\n\t *\n\t * Constructs the scenario classes so they can be collected, declares their\n\t * events on the bus, calls `initialize()` where present, and initialises\n\t * ViewModels that already exist — which happens in tests and under unusual\n\t * import order.\n\t *\n\t * Idempotent.\n\t */\n\tpublic bootstrap(): void {\n\t\tif (this.state.bootstrapped) return;\n\n\t\tlankaLogger.printScenarioLog(\"BOOTSTRAP SCENARIOS START\");\n\n\t\t// Instances must exist, or the registry has nothing to collect.\n\t\tthis.forceInstantiateAllScenarios();\n\n\t\tconst registry = LankaScenariosRegistry.getInstance();\n\t\tregistry.collectAutoRegisteredScenarios();\n\n\t\tconst scenarios = registry.getAllScenarios();\n\t\tthis.registerScenarioEvents(scenarios);\n\n\t\tthis.state.bootstrapped = true;\n\n\t\t// The second adoption. On a server this is the FIRST one that can succeed:\n\t\t// the instance is in its caller's store by now, and creation's attempt was\n\t\t// made before it could be. In a browser it is a no-op — creation adopted\n\t\t// already, and attaching is idempotent.\n\t\tthis.adoptDeclaredViewModels();\n\n\t\t// Some ViewModels may predate bootstrap — in tests, or under unusual import\n\t\t// order; initialise them now.\n\t\tthis.initializeAlreadyCreatedViewModels();\n\n\t\tlankaLogger.printScenarioLog(\"BOOTSTRAP SCENARIOS FINISH\");\n\t}\n\n\t/**\n\t * Called by a ViewModel factory when the ViewModel declares scenario handlers.\n\t *\n\t * Registers the ViewModel and, if the layer is already up, initialises it\n\t * immediately. Duplicate registration and duplicate initialisation are\n\t * impossible.\n\t *\n\t * @param viewModel What to register\n\t * @param name Name for the log\n\t */\n\t/**\n\t * ViewModels DECLARED in this process.\n\t *\n\t * Module-level deliberately, the same case as the scenario pool: a registry of\n\t * DEFINITIONS, not runtime state. Splitting it between instances would be\n\t * divergence, not isolation — the classes come from the same modules and both\n\t * instances must see one list.\n\t *\n\t * Two reasons it exists:\n\t *\n\t * 1. Declaring a ViewModel is a declaration, not work. A screen file creates it\n\t * at module level, and import order decides whether that happens before or\n\t * after `createLanka()`. Requiring a live instance at declaration time\n\t * requires an import order the consumer does not control.\n\t * 2. Instances come one after another: every test creates its own. The list is\n\t * NOT drained by the first — otherwise the second instance would know no\n\t * module-level ViewModel and its `dispose()` would not remove their\n\t * subscriptions, so a test would receive events the previous one subscribed\n\t * to.\n\t */\n\tprivate readonly declaredViewModels: { viewModel: ILankaScenarioVM; name?: string }[] = [];\n\n\t/**\n\t * Registers everything declared into a NEW instance.\n\t *\n\t * Called twice, and the second call is the one that makes this work on a\n\t * server: `createLanka` calls it, and so does `bootstrap()`.\n\t *\n\t * The reason is an order nobody can change. Where \"which instance is active\"\n\t * is answered by a RESOLVER — one instance per request, the shape\n\t * `@lankajs/host` installs — an instance becomes findable only once the CALLER\n\t * has put it in its store, and a caller can only do that after `createLanka`\n\t * has returned. So during creation the answer is honestly \"none\", and asking\n\t * for it threw: every server render of an application with a module-level\n\t * ViewModel failed inside the call that was creating the scope, with a message\n\t * about running outside one.\n\t *\n\t * Skipping is safe precisely because bootstrap adopts again. It is idempotent\n\t * at the other end too: `attachViewModel` returns early for a ViewModel the\n\t * registry already holds.\n\t */\n\tpublic adoptDeclaredViewModels(): void {\n\t\tif (!getActiveRuntime()) return;\n\n\t\tfor (const { viewModel, name } of [...this.declaredViewModels]) {\n\t\t\tthis.attachViewModel(viewModel, name);\n\t\t}\n\t}\n\n\t/**\n\t * Whether the ViewModel being built belongs to ONE scope.\n\t *\n\t * A module-level ViewModel is declared once and adopted by every instance\n\t * ever created, which is what `declaredViewModels` is for and why it is never\n\t * drained. A SCOPED one is the opposite: it belongs to the request that built\n\t * it and to nothing after.\n\t *\n\t * Declaring one would be the defect this flag exists to prevent, and it is\n\t * worth spelling out because nothing would look wrong. The array grows by an\n\t * entry per request for the life of the process, and request N+1 ADOPTS\n\t * request N's ViewModel — subscribing it to N+1's scenarios, so a dispatch\n\t * runs N's handlers against N's gateways and writes into N's store. Every\n\t * suite stays green and the leak is one user seeing another's board.\n\t */\n\tprivate isBuildingScoped = false;\n\n\t/** Who is told about each scoped registration while `buildScoped` runs. */\n\tprivate scopedRegistrations: ((viewModel: ILankaScenarioVM) => void) | null = null;\n\n\t/**\n\t * Runs `build` with its declarations kept OUT of the process-wide list.\n\t *\n\t * Called by `resolveLankaVM` and by nothing else. A narrow seam rather than a\n\t * parameter on every factory: the nine ways to build a ViewModel would each\n\t * have to carry a flag through to `registerViewModel`, and eight of them have\n\t * no business knowing what a scope is.\n\t */\n\tpublic buildScoped<TBuilt>(\n\t\tbuild: () => TBuilt,\n\t\tonRegistered?: (viewModel: ILankaScenarioVM) => void,\n\t): TBuilt {\n\t\tconst before = this.isBuildingScoped;\n\t\tconst beforeRegistrations = this.scopedRegistrations;\n\n\t\tthis.isBuildingScoped = true;\n\t\tthis.scopedRegistrations = onRegistered ?? null;\n\n\t\ttry {\n\t\t\treturn build();\n\t\t} finally {\n\t\t\tthis.isBuildingScoped = before;\n\t\t\tthis.scopedRegistrations = beforeRegistrations;\n\t\t}\n\t}\n\n\t/**\n\t * The scoped state as it is NOW, as a runner that re-enters it later.\n\t *\n\t * For a build that is deferred past the window `buildScoped` opened — a lazy\n\t * ViewModel builds on its first read, after `resolveLankaVM` has returned.\n\t * Without it that build would run under whatever state is current at the\n\t * read: outside every scope, so a scoped ViewModel would join the\n\t * process-wide list every later instance adopts; or inside SOMEBODY ELSE'S,\n\t * so a module-level one first read during another scope's build would die\n\t * with that scope. Captured at creation, it belongs where it was declared.\n\t */\n\tpublic captureScoped(): <TBuilt>(build: () => TBuilt) => TBuilt {\n\t\tconst captured = this.isBuildingScoped;\n\t\tconst capturedRegistrations = this.scopedRegistrations;\n\n\t\treturn (build) => {\n\t\t\tconst before = this.isBuildingScoped;\n\t\t\tconst beforeRegistrations = this.scopedRegistrations;\n\n\t\t\tthis.isBuildingScoped = captured;\n\t\t\tthis.scopedRegistrations = capturedRegistrations;\n\n\t\t\ttry {\n\t\t\t\treturn build();\n\t\t\t} finally {\n\t\t\t\tthis.isBuildingScoped = before;\n\t\t\t\tthis.scopedRegistrations = beforeRegistrations;\n\t\t\t}\n\t\t};\n\t}\n\n\tpublic registerViewModel(viewModel: ILankaScenarioVM, name?: string): void {\n\t\t// Told BEFORE the runtime check: a scope owns what it built whether or\n\t\t// not an instance was there to attach it to.\n\t\tthis.scopedRegistrations?.(viewModel);\n\n\t\tif (!this.isBuildingScoped) {\n\t\t\tconst isKnown = this.declaredViewModels.some(\n\t\t\t\t(declared) => declared.viewModel === viewModel,\n\t\t\t);\n\t\t\tif (!isKnown) this.declaredViewModels.push({ viewModel, name });\n\t\t}\n\n\t\t// No instance yet: the declaration came before bootstrap, and whoever\n\t\t// bootstraps will pick it up.\n\t\tif (!getActiveRuntime()) return;\n\n\t\tthis.attachViewModel(viewModel, name);\n\t}\n\n\tprivate attachViewModel(viewModel: ILankaScenarioVM, name?: string): void {\n\t\tconst registry = LankaScenarioVMRegistry.getInstance();\n\n\t\t// Already registered — nothing to do.\n\t\tif (registry.isRegistered(viewModel)) {\n\t\t\tif (name) {\n\t\t\t\tlankaLogger.printViewModelLog(\"VM Already Registered (skipped)\", name);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Register it.\n\t\tregistry.register(viewModel);\n\n\t\tif (name) {\n\t\t\tlankaLogger.printViewModelLog(\"Register Scenario VM\", name);\n\t\t}\n\n\t\t// The layer is already up — initialise it now rather than at the next\n\t\t// bootstrap.\n\t\tif (this.state.bootstrapped) {\n\t\t\tif (!this.state.initialized.has(viewModel)) {\n\t\t\t\tthis.state.initialized.add(viewModel);\n\t\t\t\tviewModel.initializeScenario();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Resets the whole scenario layer. Without it tests are not isolated.\n\t *\n\t * Clears the self-registration list, the scenario registry with its metadata,\n\t * the ViewModel registry together with all their subscriptions, and the bus —\n\t * events and\n\t * middleware.\n\t *\n\t * What it does NOT clear by default is which ViewModels were DECLARED, and\n\t * that default is load-bearing: a module-level ViewModel is built once per\n\t * process, so the declaration is the only thing that lets a second instance\n\t * find it. Drop it and its handlers bind to nothing, silently, for the rest of\n\t * the process — see `declaredViewModels`.\n\t *\n\t * `withDeclarations` is for the case that default gets wrong: a suite that\n\t * builds ViewModels inside test BODIES. Those are declared like any other and\n\t * nothing un-declares them, so the next bootstrap re-adopts every one ever\n\t * built and a finished test's handlers run again — against the gateway that\n\t * test built, which is somebody else's double. Forgetting is not a tombstone:\n\t * a ViewModel declared again afterwards is adopted again.\n\t *\n\t * @param config `withDeclarations` also forgets which ViewModels exist\n\t */\n\tpublic reset(config: ILankaScenarioResetConfig = {}): void {\n\t\tALankaScenario.clearAutoRegisteredScenarios();\n\t\tLankaScenariosRegistry.getInstance().clear();\n\t\tLankaScenarioVMRegistry.getInstance().resetAll();\n\t\tlankaEventBus.clearAllEvents();\n\t\tthis.state.bootstrapped = false;\n\t\tthis.state.initialized = new WeakSet<ILankaScenarioVM>();\n\n\t\tif (config.withDeclarations) this.declaredViewModels.length = 0;\n\t}\n}\n\n/** The one every caller wants. */\nexport const lankaScenarioBootstrap = new LankaScenarioBootstrap();\n"],"mappings":"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","names":[]}
|
|
@@ -1,38 +1,38 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createLankaScope
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-M4BK6GBV.js";
|
|
4
4
|
import {
|
|
5
5
|
LankaGatewayLocator
|
|
6
6
|
} from "./chunk-BMF4TM2Z.js";
|
|
7
7
|
import {
|
|
8
8
|
LankaScenarioLocator
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-EH5WZSRJ.js";
|
|
10
|
+
import {
|
|
11
|
+
LankaSingletonLocator
|
|
12
|
+
} from "./chunk-24MUFFHF.js";
|
|
13
|
+
import {
|
|
14
|
+
LankaSharedStoreLocator
|
|
15
|
+
} from "./chunk-3R2NO47A.js";
|
|
10
16
|
import {
|
|
11
17
|
lankaScenarioBootstrap
|
|
12
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-4VFVACSL.js";
|
|
13
19
|
import {
|
|
14
20
|
LankaScenarioVMRegistry,
|
|
15
21
|
LankaScenariosRegistry
|
|
16
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-L27FF2IH.js";
|
|
17
23
|
import {
|
|
18
24
|
createLankaHost
|
|
19
25
|
} from "./chunk-XESL274R.js";
|
|
20
26
|
import {
|
|
21
27
|
createInFlightCounter
|
|
22
|
-
} from "./chunk-
|
|
23
|
-
import {
|
|
24
|
-
LankaSharedStoreLocator
|
|
25
|
-
} from "./chunk-3R2NO47A.js";
|
|
26
|
-
import {
|
|
27
|
-
LankaSingletonLocator
|
|
28
|
-
} from "./chunk-24MUFFHF.js";
|
|
28
|
+
} from "./chunk-NMFNEVNE.js";
|
|
29
29
|
import {
|
|
30
30
|
lankaLogger
|
|
31
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-AMLUKB6A.js";
|
|
32
32
|
import {
|
|
33
33
|
getActiveRuntime,
|
|
34
34
|
setActiveLankaRuntime
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-XTVEHYIZ.js";
|
|
36
36
|
|
|
37
37
|
// src/scenario/event-bus/lanka-event-bus-instance/LankaEventBusInstance.ts
|
|
38
38
|
var isThenable = (value) => typeof value?.then === "function";
|
|
@@ -277,7 +277,7 @@ var LankaEventBusInstance = class {
|
|
|
277
277
|
buffer.length = 0;
|
|
278
278
|
}
|
|
279
279
|
deliver();
|
|
280
|
-
this.report({ eventType, outcome: "delivered", subscribers: subs.length });
|
|
280
|
+
this.report({ eventType, outcome: "delivered", subscribers: subs.length, data });
|
|
281
281
|
}
|
|
282
282
|
/** Adds middleware to the shared chain. */
|
|
283
283
|
addMiddleware(mw) {
|
|
@@ -527,7 +527,7 @@ function createLanka(config) {
|
|
|
527
527
|
return plugins.use(plugin);
|
|
528
528
|
},
|
|
529
529
|
createScope() {
|
|
530
|
-
const scope = createLankaScope(locators.singletons);
|
|
530
|
+
const scope = createLankaScope(locators.singletons, viewModels);
|
|
531
531
|
scopes.add(scope);
|
|
532
532
|
return scope;
|
|
533
533
|
},
|
|
@@ -735,4 +735,4 @@ export {
|
|
|
735
735
|
resetActiveLanka,
|
|
736
736
|
ALankaPlugin
|
|
737
737
|
};
|
|
738
|
-
//# sourceMappingURL=chunk-
|
|
738
|
+
//# sourceMappingURL=chunk-532WVMAF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/scenario/event-bus/lanka-event-bus-instance/LankaEventBusInstance.ts","../src/bootstrap/_internal/create-lanka-plugin-registry/createLankaPluginRegistry.ts","../src/bootstrap/_factories/create-lanka/createLanka.ts","../src/bootstrap/start-lanka/startLanka.ts","../src/bootstrap/reset-active-lanka/resetActiveLanka.ts","../src/bootstrap/_abstractions/lanka-plugin/ALankaPlugin.ts"],"sourcesContent":["import { ILankaEventMetadata } from \"../../_interfaces/ILankaEventMetadata\";\nimport { ILankaEventLog } from \"../../_interfaces/ILankaEventLog\";\nimport {\n\tTLankaEventBusDecision,\n\tTLankaEventBusMiddleware,\n} from \"../../_types/TLankaEventBusMiddleware\";\nimport { TLankaEventBusObserver } from \"../../_types/TLankaEventBusObserver\";\nimport { ILankaEventBusOutcome } from \"../../_interfaces/ILankaEventBusOutcome\";\nimport { lankaLogger } from \"../../../logger/lanka-logger/LankaLogger\";\n\n/**\n * Whether a handler's return value is something that can still reject.\n *\n * Duck-typed rather than `instanceof Promise`, because the promise a handler\n * returns need not be THIS realm's: a jsdom test, a native module and a bundled\n * polyfill each bring their own, and `instanceof` answers false for all of them.\n * An `instanceof` check here would work everywhere except the places most likely\n * to need it.\n */\nconst isThenable = (value: unknown): value is PromiseLike<unknown> =>\n\ttypeof (value as PromiseLike<unknown> | null)?.then === \"function\";\n\n/** One subscription: the callback plus everything the bus knows about it. */\ntype TSubscriptionEntry<T = unknown> = {\n\tcallback: (data: T) => void;\n\tpriority: number;\n\t/**\n\t * How many recent values this subscriber asks to be replayed on subscribe.\n\t *\n\t * A number rather than a flag: \"the whole buffer\" can be a hundred events in a\n\t * row, which is almost never what \"give me the current state\" means.\n\t */\n\treplayCount: number;\n};\n\n/** State of one registered event type. */\ntype TEventState = {\n\tmeta: ILankaEventMetadata;\n\tlogs: ILankaEventLog[];\n\tbuffer: unknown[];\n\tsubs: TSubscriptionEntry[];\n};\n\n/**\n * How many recent values to replay to a new subscriber.\n *\n * `true` is kept and means \"the last one\".\n */\nexport type TLankaReplayRequest = boolean | \"last\" | number;\n\nfunction resolveReplayCount(request: TLankaReplayRequest | undefined): number {\n\tif (request === undefined || request === false) return 0;\n\tif (request === true || request === \"last\") return 1;\n\treturn Math.max(0, Math.trunc(request));\n}\n\nfunction maxReplayDepth(subs: readonly TSubscriptionEntry[]): number {\n\tlet depth = 0;\n\tfor (const entry of subs) if (entry.replayCount > depth) depth = entry.replayCount;\n\treturn depth;\n}\n\n// -----------------------------------------------------------------------------\n// Bus implementation\n// -----------------------------------------------------------------------------\n\nexport class LankaEventBusInstance {\n\t/** Event registry and per-event state — private to each instance. */\n\tprivate registry: Map<string, TEventState> = new Map();\n\n\t/** Middleware registered on this instance. */\n\tprivate middlewares: TLankaEventBusMiddleware<unknown>[] = [];\n\n\t/**\n\t * What is watching the OUTCOME of each dispatch — see `TLankaEventBusObserver`.\n\t *\n\t * An array rather than a set for one reason: `dispatch` reads `.length` on\n\t * every event, and that check is what keeps an unobserved bus paying nothing.\n\t */\n\tprivate observers: TLankaEventBusObserver[] = [];\n\n\t/** Default maximum number of logs kept per event type. */\n\tprivate defaultMaxLogs = 100;\n\n\t/** Internal timers for replay batching (avoid multiple replays in the same tick). */\n\tprivate pendingReplayTimers: Map<string, ReturnType<typeof setTimeout>> = new Map();\n\n\t/** Whether event logging is enabled. */\n\tprivate isEnableLogs = false;\n\n\t/**\n\t * How many events this bus has logged, ever — the order records are read in.\n\t *\n\t * Incremented only while logging is on, which is off by default, so a bus\n\t * nobody is inspecting pays nothing for it.\n\t */\n\tprivate dispatchCount = 0;\n\n\t// -------------------------------------------------------------------------\n\t// Configuration\n\t// -------------------------------------------------------------------------\n\n\t/** Configures the bus, e.g. logging. Called once at application start. */\n\tpublic enableLogs(): void {\n\t\tthis.isEnableLogs = true;\n\t}\n\tpublic disableLogs(): void {\n\t\tthis.isEnableLogs = false;\n\t}\n\n\t// -------------------------------------------------------------------------\n\t// Internal\n\t// -------------------------------------------------------------------------\n\n\t/**\n\t * Ensures the event is registered, registering it if not.\n\t *\n\t * @param eventType Event type\n\t * @param usedBy Who uses it — for the inspector and for finding an owner\n\t */\n\tprivate ensureEvent(eventType: string, usedBy?: string): TEventState {\n\t\tlet state = this.registry.get(eventType);\n\t\tif (!state) {\n\t\t\tconst meta: ILankaEventMetadata = {\n\t\t\t\tdataType: \"any\",\n\t\t\t\tdescription: `Auto-registered event: ${eventType}`,\n\t\t\t\tusedBy: usedBy ? [usedBy] : [],\n\t\t\t\tpriority: 0,\n\t\t\t\tmaxLogs: this.defaultMaxLogs,\n\t\t\t};\n\t\t\tstate = {\n\t\t\t\tmeta,\n\t\t\t\tlogs: [],\n\t\t\t\tbuffer: [],\n\t\t\t\tsubs: [],\n\t\t\t};\n\t\t\tthis.registry.set(eventType, state);\n\t\t} else if (usedBy) {\n\t\t\tconst meta = state.meta;\n\t\t\tmeta.usedBy = [...new Set([...(meta.usedBy ?? []), usedBy])];\n\t\t}\n\t\treturn state;\n\t}\n\n\t// -------------------------------------------------------------------------\n\t// Public surface\n\t// -------------------------------------------------------------------------\n\n\t/**\n\t * Declares an event explicitly, together with its metadata.\n\t *\n\t * @param eventType Event type\n\t * @param metadata What is known about the event and what it is allowed\n\t */\n\tpublic registerEvent(eventType: string, metadata: ILankaEventMetadata): void {\n\t\t// MERGE, never recreate the state.\n\t\t//\n\t\t// Writing `subs: []` here means a call after anyone subscribed silently\n\t\t// drops every subscriber. Bootstrap order (register before ViewModels\n\t\t// initialise) hides it, but that is a coincidence, not an invariant: any\n\t\t// lazy event registration breaks it, and the only symptom is that nothing\n\t\t// works.\n\t\tconst existing = this.registry.get(eventType);\n\t\tconst meta: ILankaEventMetadata = {\n\t\t\tdataType: metadata.dataType ?? existing?.meta.dataType ?? \"any\",\n\t\t\tdescription:\n\t\t\t\tmetadata.description ??\n\t\t\t\texisting?.meta.description ??\n\t\t\t\t`Registered event: ${eventType}`,\n\t\t\t// `usedBy` lists everyone using the event and exists precisely to be\n\t\t\t// complete. Replacing it would erase half.\n\t\t\tusedBy: [...new Set([...(existing?.meta.usedBy ?? []), ...(metadata.usedBy ?? [])])],\n\t\t\tschema: metadata.schema ?? existing?.meta.schema,\n\t\t\tpriority: metadata.priority ?? existing?.meta.priority ?? 0,\n\t\t\tmaxLogs: metadata.maxLogs ?? existing?.meta.maxLogs ?? this.defaultMaxLogs,\n\t\t\treplay: metadata.replay ?? existing?.meta.replay,\n\t\t};\n\n\t\tif (existing) {\n\t\t\texisting.meta = meta;\n\t\t\treturn;\n\t\t}\n\n\t\tthis.registry.set(eventType, { meta, logs: [], buffer: [], subs: [] });\n\t}\n\n\t/** Every registered event with its metadata. */\n\tpublic getRegisteredEvents() {\n\t\treturn Array.from(this.registry.entries())\n\t\t\t.map(([eventType, state]) => ({\n\t\t\t\teventType,\n\t\t\t\tmetadata: state.meta,\n\t\t\t}))\n\t\t\t.sort((a, b) => a.eventType.localeCompare(b.eventType));\n\t}\n\n\t/** Metadata of one event type. */\n\tpublic getEventInfo(eventType: string): ILankaEventMetadata | null {\n\t\treturn this.registry.get(eventType)?.meta ?? null;\n\t}\n\n\t/** How many live subscriptions this event has. */\n\t/**\n\t * How many values sit in the event's buffer.\n\t *\n\t * Exists for the test: \"the buffer stays empty until someone asks for replay\"\n\t * is a claim about MEMORY, and nothing but asking can check it.\n\t */\n\tpublic getBufferedCount(eventType: string): number {\n\t\treturn this.registry.get(eventType)?.buffer.length ?? 0;\n\t}\n\n\tpublic getSubscriptions(eventType: string): number {\n\t\treturn this.registry.get(eventType)?.subs.length ?? 0;\n\t}\n\n\t/**\n\t * Subscribes a handler to an event type.\n\t *\n\t * @param eventType Event type\n\t * @param callback What to run on dispatch\n\t * @param options Subscription options:\n\t * - `priority` — execution order, higher runs earlier;\n\t * - `replay` — receive what was dispatched before subscribing;\n\t * - `usedBy` — who subscribed, for the inspector.\n\t */\n\tpublic subscribe<T>(\n\t\teventType: string,\n\t\tcallback: (data: T) => void,\n\t\toptions?: {\n\t\t\tpriority?: number;\n\t\t\treplay?: TLankaReplayRequest;\n\t\t\tusedBy?: string;\n\t\t},\n\t): () => void {\n\t\tconst state = this.ensureEvent(eventType, options?.usedBy);\n\t\tconst prio = options?.priority ?? state.meta.priority ?? 0;\n\t\tconst entry: TSubscriptionEntry<unknown> = {\n\t\t\tcallback: callback as unknown as (data: unknown) => void,\n\t\t\tpriority: prio,\n\t\t\treplayCount: resolveReplayCount(options?.replay),\n\t\t};\n\n\t\tconst subs = state.subs;\n\t\tlet low = 0,\n\t\t\thigh = subs.length;\n\t\twhile (low < high) {\n\t\t\tconst mid = (low + high) >>> 1;\n\t\t\tif (subs[mid].priority < prio) high = mid;\n\t\t\telse low = mid + 1;\n\t\t}\n\t\tsubs.splice(low, 0, entry);\n\n\t\tif (options?.replay) this.scheduleBatchedReplay(eventType, state);\n\n\t\t// The returned function removes EXACTLY this record, not the first one with\n\t\t// the same callback: by callback, two subscriptions of one function are\n\t\t// indistinguishable.\n\t\treturn () => {\n\t\t\tconst at = state.subs.indexOf(entry);\n\t\t\tif (at !== -1) state.subs.splice(at, 1);\n\t\t};\n\t}\n\n\t/**\n\t * Removes a handler from an event type.\n\t *\n\t * @param eventType Event type\n\t * @param callback A previously subscribed handler\n\t */\n\tpublic unsubscribe<T>(eventType: string, callback: (data: T) => void): void {\n\t\tconst state = this.registry.get(eventType);\n\t\tif (!state) return;\n\t\tconst subs = state.subs;\n\t\tfor (let i = 0; i < subs.length; i++) {\n\t\t\tif (subs[i].callback === callback) {\n\t\t\t\tsubs.splice(i, 1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Dispatches an event: the middleware chain first, then subscribers.\n\t *\n\t * @param eventType Event type\n\t * @param data Payload\n\t * @param usedBy Who dispatched — recorded in the metadata\n\t */\n\tpublic dispatch<T>(eventType: string, data?: T, usedBy?: string): void {\n\t\tconst state = this.ensureEvent(eventType, usedBy);\n\t\tconst { meta, subs, buffer } = state;\n\n\t\t// Payload shape check\n\t\tif (meta.schema && data !== undefined && !meta.schema(data)) {\n\t\t\tlankaLogger.printScenarioLog(`Invalid data for event \"${eventType}\":`, data);\n\t\t\tthis.report({ eventType, outcome: \"invalid\", subscribers: subs.length });\n\t\t\treturn;\n\t\t}\n\n\t\tthis.logEvent(state, eventType, data);\n\n\t\tconst deliver = (): void => {\n\t\t\t// Iterate a COPY. A subscriber may unsubscribe inside its own handler —\n\t\t\t// \"waited for the session, then unsubscribed\" is a routine pattern — and\n\t\t\t// `unsubscribe` splices this same array, so iterating the original skips\n\t\t\t// a neighbour silently.\n\t\t\t//\n\t\t\t// The deliberate side effect: subscribing DURING delivery waits for the\n\t\t\t// next event. Otherwise delivery order would depend on subscription\n\t\t\t// timing, which is undefined.\n\t\t\tfor (const entry of [...subs]) {\n\t\t\t\ttry {\n\t\t\t\t\t// A handler is typed `(data) => void`, and TypeScript assigns a\n\t\t\t\t\t// `Promise<void>` to a void return position — so `async () => { await\n\t\t\t\t\t// refetch(); }` is a handler that compiles with nothing to warn about,\n\t\t\t\t\t// and \"refetch when the stream reconnects\" is the common shape rather\n\t\t\t\t\t// than an exotic one.\n\t\t\t\t\t//\n\t\t\t\t\t// Its failure arrives a microtask after this loop has finished, where\n\t\t\t\t\t// the `catch` below cannot reach it: on node's default an unhandled\n\t\t\t\t\t// rejection ends the PROCESS, and ends it inside whatever ran next.\n\t\t\t\t\t// The promise this bus already makes — one subscriber cannot take a\n\t\t\t\t\t// dispatch down with it — has to cover that handler too, or it only\n\t\t\t\t\t// holds for the handlers that happen to be synchronous.\n\t\t\t\t\tconst settled: unknown = entry.callback(data);\n\n\t\t\t\t\tif (isThenable(settled)) {\n\t\t\t\t\t\tsettled.then(undefined, (err: unknown) => {\n\t\t\t\t\t\t\tlankaLogger.printScenarioLog(\n\t\t\t\t\t\t\t\t`Error dispatching event \"${eventType}\":`,\n\t\t\t\t\t\t\t\terr,\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t}\n\t\t\t\t} catch (err) {\n\t\t\t\t\tlankaLogger.printScenarioLog(`Error dispatching event \"${eventType}\":`, err);\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\n\t\t// Every middleware RETURNS a decision. A `next()`-based shape means not\n\t\t// calling it makes the event vanish silently.\n\t\t//\n\t\t// An exception is the same case as \"did not call next\": it also stops\n\t\t// delivery, so it is handled the same way and names itself in the log,\n\t\t// instead of surfacing and breaking whoever dispatched.\n\t\tfor (const middleware of [...this.middlewares]) {\n\t\t\tlet decision: TLankaEventBusDecision;\n\t\t\ttry {\n\t\t\t\tdecision = middleware(eventType, data);\n\t\t\t} catch (err) {\n\t\t\t\tdecision = { stop: err instanceof Error ? err.message : String(err) };\n\t\t\t}\n\n\t\t\tif (decision !== \"pass\") {\n\t\t\t\tthis.markStopped(state, decision.stop);\n\t\t\t\tlankaLogger.printScenarioLog(\n\t\t\t\t\t`Event \"${eventType}\" stopped by middleware:`,\n\t\t\t\t\tdecision.stop,\n\t\t\t\t);\n\t\t\t\t// The one place that knows WHICH middleware stopped it. A middleware\n\t\t\t\t// cannot learn this about a middleware after itself, which is why an\n\t\t\t\t// inspector needed an observer rather than a sixth middleware.\n\t\t\t\tthis.report({\n\t\t\t\t\teventType,\n\t\t\t\t\toutcome: \"stopped\",\n\t\t\t\t\tsubscribers: subs.length,\n\t\t\t\t\tstoppedBy: decision.stop,\n\t\t\t\t});\n\t\t\t\treturn;\n\t\t\t}\n\t\t}\n\n\t\t// AFTER the chain, and that ordering is the guarantee.\n\t\t//\n\t\t// The buffer used to be filled before the middlewares ran, so an event the\n\t\t// chain STOPPED still sat in it — and the next subscriber asking for replay\n\t\t// received a payload no subscriber had been allowed to see, with nothing in\n\t\t// the bus log recording that delivery. Middleware is how an application\n\t\t// gates an event (an authorisation check, a privacy filter, a feature\n\t\t// flag); a gate the framework routes around is not a gate.\n\t\t//\n\t\t// The buffer exists ONLY on demand and holds exactly what the greediest\n\t\t// subscriber asked for. Buffering every payload unconditionally holds up to\n\t\t// a hundred payloads per event type until the end of the session — in an app\n\t\t// where user data arrives over SSE, that is personal data kept in memory\n\t\t// with no consumer.\n\t\tconst depth = Math.max(resolveReplayCount(meta.replay), maxReplayDepth(subs));\n\t\tif (depth > 0) {\n\t\t\tbuffer.push(data);\n\t\t\twhile (buffer.length > depth) buffer.shift();\n\t\t} else if (buffer.length > 0) {\n\t\t\t// The last replay asker unsubscribed — nothing left to hold.\n\t\t\tbuffer.length = 0;\n\t\t}\n\n\t\tdeliver();\n\t\tthis.report({ eventType, outcome: \"delivered\", subscribers: subs.length, data });\n\t}\n\n\t/** Adds middleware to the shared chain. */\n\tpublic addMiddleware<T>(mw: TLankaEventBusMiddleware<T>): void {\n\t\tthis.middlewares.push(mw as unknown as TLankaEventBusMiddleware<unknown>);\n\t}\n\n\t/** Removes previously added middleware. */\n\tpublic removeMiddleware<T>(mw: TLankaEventBusMiddleware<T>): void {\n\t\tconst i = this.middlewares.indexOf(mw as unknown as TLankaEventBusMiddleware<unknown>);\n\t\tif (i !== -1) this.middlewares.splice(i, 1);\n\t}\n\n\t/**\n\t * Watches what became of each dispatch. An extension point — the sixth.\n\t *\n\t * An observer never decides: its return value is ignored, and a throw from it\n\t * is logged rather than surfaced. A diagnostic tool that could stop an event\n\t * would make \"I disabled the inspector and it started working\" a sentence\n\t * somebody says.\n\t */\n\tpublic addObserver(observer: TLankaEventBusObserver): void {\n\t\tthis.observers.push(observer);\n\t}\n\n\t/** Removes a previously added observer. */\n\tpublic removeObserver(observer: TLankaEventBusObserver): void {\n\t\tconst i = this.observers.indexOf(observer);\n\t\tif (i !== -1) this.observers.splice(i, 1);\n\t}\n\n\t/**\n\t * Log of dispatched events, oldest first, `limit` most recent kept.\n\t *\n\t * ## Why the records are sorted rather than concatenated\n\t *\n\t * They are held per event TYPE, so that each type keeps its own `maxLogs`\n\t * and a chatty event cannot push a quiet one's history out. Concatenating\n\t * those lists puts every record of one type before every record of the next,\n\t * and `slice(-limit)` then answers the tail of whichever type the registry\n\t * happened to hold last — not the most recent events at all. On a bus with\n\t * one event type nothing looked wrong; on a real one the log was a\n\t * chronology that had never been in chronological order.\n\t *\n\t * @param eventType Limit to one type\n\t * @param limit How many recent records to return\n\t */\n\tpublic getEventLogs(eventType?: string, limit = 100): ILankaEventLog[] {\n\t\tif (eventType) {\n\t\t\treturn this.registry.get(eventType)?.logs.slice(-limit) ?? [];\n\t\t}\n\t\tconst all: ILankaEventLog[] = [];\n\t\tfor (const { logs } of this.registry.values()) all.push(...logs);\n\t\t// By `sequence`, not by `timestamp`: a timestamp has millisecond\n\t\t// resolution and a burst — an SSE storm, bootstrap — dispatches many\n\t\t// events inside one, so sorting by it would leave those in the order the\n\t\t// concatenation happened to produce, which is the defect itself.\n\t\tall.sort((left, right) => (left.sequence ?? 0) - (right.sequence ?? 0));\n\t\treturn all.slice(-limit);\n\t}\n\n\t/** Removes an event together with its subscriptions, log and buffer. */\n\tpublic clearEvent(eventType: string): void {\n\t\tthis.registry.delete(eventType);\n\t\tconst t = this.pendingReplayTimers.get(eventType);\n\t\tif (t) {\n\t\t\tclearTimeout(t);\n\t\t\tthis.pendingReplayTimers.delete(eventType);\n\t\t}\n\t}\n\n\t/** Removes every event and any scheduled replays. */\n\tpublic clearAllEvents(): void {\n\t\tthis.registry.clear();\n\t\tfor (const t of this.pendingReplayTimers.values()) clearTimeout(t);\n\t\tthis.pendingReplayTimers.clear();\n\t}\n\n\t/** Full bus reset: events, middleware and observers. */\n\tpublic reset(): void {\n\t\tthis.clearAllEvents();\n\t\tthis.middlewares = [];\n\t\tthis.observers = [];\n\t\tthis.isEnableLogs = false;\n\t}\n\n\t// -------------------------------------------------------------------------\n\t// Internal helpers\n\t// -------------------------------------------------------------------------\n\n\t/**\n\t * Tells the observers what became of a dispatch.\n\t *\n\t * The empty-list check is the whole reason a bus nobody watches pays nothing\n\t * for this: `dispatch` is a hot path, and an iteration over an empty array on\n\t * every event would be a cost paid by every application for a feature almost\n\t * none of them installs. Measured in `LankaEventBusInstance.bench.ts`.\n\t *\n\t * An observer that throws is logged and the next one still runs — the same\n\t * treatment a subscriber gets, and for the same reason: a diagnostic tool must\n\t * not be able to break the application it is diagnosing.\n\t */\n\tprivate report(outcome: ILankaEventBusOutcome): void {\n\t\tif (this.observers.length === 0) return;\n\n\t\tfor (const observer of [...this.observers]) {\n\t\t\ttry {\n\t\t\t\tobserver(outcome);\n\t\t\t} catch (err) {\n\t\t\t\tlankaLogger.printScenarioLog(\n\t\t\t\t\t`Event bus observer failed for \"${outcome.eventType}\":`,\n\t\t\t\t\terr,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Marks the last log record with the reason it was stopped.\n\t *\n\t * Writes where `logEvent` just put the event: a stop is not a separate\n\t * occurrence but this one's outcome.\n\t */\n\tprivate markStopped(state: TEventState, reason: string): void {\n\t\tconst last = state.logs.at(-1);\n\t\tif (last) last.stoppedBy = reason;\n\t}\n\n\t/** Add an event log entry for debugging/auditing. */\n\tprivate logEvent(state: TEventState, eventType: string, data: unknown): void {\n\t\tif (this.isEnableLogs) {\n\t\t\tconst cap = state.meta.maxLogs ?? this.defaultMaxLogs;\n\t\t\tconst logs = state.logs;\n\t\t\tthis.dispatchCount += 1;\n\t\t\tconst log: ILankaEventLog = {\n\t\t\t\teventType,\n\t\t\t\ttimestamp: new Date().toISOString(),\n\t\t\t\tdata,\n\t\t\t\tsequence: this.dispatchCount,\n\t\t\t};\n\t\t\tlog.stackTrace = new Error().stack;\n\t\t\tlogs.push(log);\n\t\t\tif (logs.length > cap) logs.shift();\n\t\t}\n\t}\n\n\t/**\n\t * Schedules replay for late subscribers that asked for it.\n\t *\n\t * Replays are batched into one tick: otherwise ten subscriptions to one event\n\t * would make ten separate passes over the same buffer.\n\t */\n\tprivate scheduleBatchedReplay(eventType: string, state: TEventState): void {\n\t\tif (this.pendingReplayTimers.has(eventType)) return;\n\n\t\tconst timer = setTimeout(() => {\n\t\t\tthis.pendingReplayTimers.delete(eventType);\n\t\t\tconst { buffer, subs } = state;\n\t\t\tif (!buffer.length) return;\n\n\t\t\tconst needReplay = subs.filter((s) => s.replayCount > 0);\n\t\t\tif (!needReplay.length) return;\n\n\t\t\tfor (const entry of needReplay) {\n\t\t\t\t// Each gets what IT asked for, not what the buffer happens to hold.\n\t\t\t\tfor (const payload of buffer.slice(-entry.replayCount)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tentry.callback(payload);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tlankaLogger.printScenarioLog(\n\t\t\t\t\t\t\t`Error dispatching event \"${eventType}\" (replay):`,\n\t\t\t\t\t\t\terr,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Replay is an event of subscribing, not a property of the subscriber: it\n\t\t\t// does not happen a second time.\n\t\t\tfor (const entry of needReplay) entry.replayCount = 0;\n\t\t}, 0);\n\n\t\tthis.pendingReplayTimers.set(eventType, timer);\n\t}\n}\n","import type { ILankaPlugin } from \"../../ILankaPlugin\";\nimport type { ILankaInstance } from \"../../_factories/create-lanka/createLanka\";\n\nexport interface ILankaPluginRegistry {\n\t/** Installs a plugin and returns the function that removes it. */\n\tuse: (plugin: ILankaPlugin) => () => void;\n\t/** Removes every plugin, newest first is NOT guaranteed — see `removeAll`. */\n\tremoveAll: () => void;\n}\n\n/**\n * The plugins installed on one framework instance.\n *\n * Owns three decisions that are easy to get subtly wrong and impossible to see\n * from the outside: a duplicate is refused, removal is idempotent, and removing\n * all of them iterates a COPY of the values.\n */\nexport const createLankaPluginRegistry = (instance: ILankaInstance): ILankaPluginRegistry => {\n\tconst removers = new Map<string, () => void>();\n\n\treturn {\n\t\tuse(plugin: ILankaPlugin): () => void {\n\t\t\tif (removers.has(plugin.name)) {\n\t\t\t\t// Rejected LOUDLY: two copies of a retry policy double the request\n\t\t\t\t// count, and that shows up only as backend load — much later, and to\n\t\t\t\t// somebody else.\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Plugin \"${plugin.name}\" is already registered on this lanka instance. ` +\n\t\t\t\t\t\t\"Registering twice almost always means two copies of one policy.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst uninstall = plugin.install(instance);\n\n\t\t\tconst remove = (): void => {\n\t\t\t\t// Idempotent: a caller may hold the remover and also dispose the\n\t\t\t\t// instance, and uninstalling twice is how a plugin's own teardown ends\n\t\t\t\t// up running against a framework that is already gone.\n\t\t\t\tif (!removers.has(plugin.name)) return;\n\t\t\t\tremovers.delete(plugin.name);\n\t\t\t\tuninstall?.();\n\t\t\t};\n\n\t\t\tremovers.set(plugin.name, remove);\n\t\t\treturn remove;\n\t\t},\n\n\t\tremoveAll(): void {\n\t\t\t// A COPY: each remover deletes its own entry, and mutating the map being\n\t\t\t// iterated skips every second plugin.\n\t\t\tfor (const remove of [...removers.values()]) remove();\n\t\t\tremovers.clear();\n\t\t},\n\t};\n};\n","import { LankaEventBusInstance } from \"../../../scenario/event-bus/lanka-event-bus-instance/LankaEventBusInstance\";\nimport { createLankaPluginRegistry } from \"../../_internal/create-lanka-plugin-registry/createLankaPluginRegistry\";\nimport { LankaScenariosRegistry } from \"../../../scenario/_registries/lanka-scenarios-registry/LankaScenariosRegistry\";\nimport { LankaScenarioVMRegistry } from \"../../../scenario/_registries/lanka-scenario-vm-registry/LankaScenarioVMRegistry\";\nimport { lankaScenarioBootstrap } from \"../../../scenario/lanka-scenario-bootstrap/LankaScenarioBootstrap\";\nimport { LankaGatewayLocator } from \"../../../locator/gateway/lanka-gateway-locator/LankaGatewayLocator\";\nimport { LankaScenarioLocator } from \"../../../locator/scenario/lanka-scenario-locator/LankaScenarioLocator\";\nimport { LankaSingletonLocator } from \"../../../locator/singleton/lanka-singleton-locator/LankaSingletonLocator\";\nimport { LankaSharedStoreLocator } from \"../../../locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator\";\nimport { createInFlightCounter } from \"../../../gateway/inflight/lankaHttpInFlight\";\nimport { lankaLogger } from \"../../../logger/lanka-logger/LankaLogger\";\nimport {\n\tgetActiveRuntime,\n\tsetActiveLankaRuntime,\n} from \"../../../_internal/active-runtime/activeRuntime\";\nimport { createLankaScope } from \"../../../locator/_factories/create-lanka-scope/createLankaScope\";\nimport type { ILankaScope } from \"../../../locator/_factories/create-lanka-scope/createLankaScope\";\nimport type { ILankaPlugin } from \"../../ILankaPlugin\";\nimport type { ILankaRuntime } from \"../../../_internal/active-runtime/activeRuntime\";\nimport type { ILankaFlags } from \"../../../config/_interfaces/ILankaFlags\";\nimport type { ILankaHost } from \"../../../config/_interfaces/ILankaHost\";\nimport type { ILankaRuntimeConfig } from \"../../../config/_interfaces/ILankaRuntimeConfig\";\nimport type { ILankaScenarioVM } from \"../../../scenario/_interfaces/ILankaScenarioVM\";\nimport type { TLankaRequestMiddleware } from \"../../../gateway/request/lankaRequestMiddleware\";\n\n/**\n * A framework instance: all framework state in one object.\n *\n * What instance-scoped state buys: two apps in one process (micro-frontends,\n * Storybook beside the app) no longer share a bus, locator caches and mock mode;\n * SSR does not reuse state between different users' requests; and test isolation\n * rests on construction rather than on a global `beforeEach` reaching into\n * internal registries.\n *\n * **Ambient facades** — `lankaEventBus.dispatch`, `lankaSingletons.foo`,\n * `getLankaFlags()`, `lankaHttpInFlight` — resolve THE ONE active instance\n * (`_internal/active-runtime/activeRuntime.ts`). Isolation belongs to whoever\n * holds an instance; a facade cannot offer it.\n *\n * One thing stays at module level deliberately: `ALankaScenario` collects\n * constructed scenarios into a static pool. That is a REGISTRY OF DEFINITIONS,\n * not runtime state — the classes come from one `@lanka_di/Scenarios` barrel and\n * both instances must see the same list. Splitting it would be divergence.\n */\nexport interface ILankaInstance extends ILankaRuntime {\n\t/**\n\t * Adds a wrapper around every request. Returns a function that removes it.\n\t *\n\t * This is how `@lankajs/plugin-http` installs retry, the idempotency key, the\n\t * CSRF header and auth refresh.\n\t */\n\tuseRequestMiddleware(middleware: TLankaRequestMiddleware): () => void;\n\t/** Default timeout for every request of this instance. */\n\tsetRequestTimeout(timeoutMs: number | undefined): void;\n\t/** Resolves a service in the root scope — for the instance's whole lifetime. */\n\tresolve<TInstance>(propertyName: string): TInstance;\n\t/**\n\t * Creates a scope: a lifetime shorter than the application's.\n\t *\n\t * An object created in a scope goes away with it.\n\t */\n\tcreateScope(): ILankaScope;\n\t/**\n\t * Registers a plugin. Returns a function that removes it.\n\t *\n\t * The fifth and last extension point. An extension point declared before\n\t * anything plugs into it describes an imagined need while costing real\n\t * support, so this one arrived with the FIRST plugin.\n\t */\n\tuse(plugin: ILankaPlugin): () => void;\n\t/** Runs services and the scenario layer. Idempotent. */\n\tbootstrap(config?: ILankaBootstrapConfig): Promise<void>;\n\t/** Has bootstrap already run? */\n\tisBootstrapped(): boolean;\n\t/** Makes this instance the one ambient facades resolve to. */\n\tactivate(): void;\n\t/**\n\t * Removes subscriptions, clears registries and, if this instance was active,\n\t * clears the pointer. Returns the framework to its pre-bootstrap state.\n\t */\n\tdispose(): void;\n}\n\nexport interface ILankaInstanceConfig {\n\thost: ILankaHost;\n\tflags?: ILankaFlags;\n}\n\nexport interface ILankaServiceConfig {\n\tname?: string;\n\tinit: () => void | Promise<void>;\n\tsync?: boolean;\n\tpriority?: number;\n\t/**\n\t * A failure of this service does not abort bootstrap.\n\t *\n\t * Without the flag one failed service takes the WHOLE phase with it: the async\n\t * phase because of `Promise.all`, the sync phase because later tasks never run.\n\t * Wrapping the failure in a swallowing `try/catch` is worse still — the app\n\t * starts with a partially executed plan and does not know it.\n\t */\n\toptional?: boolean;\n\t/**\n\t * How long to wait for the service. Overrunning counts as a failure.\n\t *\n\t * Without a deadline a service that never settles holds bootstrap forever and\n\t * the app never paints its first screen. Failing is more honest than waiting:\n\t * an optional service is skipped, a required one names itself.\n\t */\n\ttimeoutMs?: number;\n}\n\nexport interface ILankaScenarioBootstrapConfig {\n\tsync?: boolean;\n\tpriority?: number;\n}\n\nexport interface ILankaBootstrapConfig {\n\tservices?: ILankaServiceConfig[];\n\tscenarios?: ILankaScenarioBootstrapConfig;\n}\n\n/**\n * Config merge: patch over previous, flags over flags.\n *\n * Lives HERE rather than in `config/lankaConfig` because the rule belongs to\n * whoever holds the config — the instance. Importing it from the config module\n * would pull that module into EVERY test's graph through the test kit, and any\n * test that partially mocks the config module would break the suite with \"No\n * export is defined on the mock\".\n */\nfunction mergeLankaConfig(\n\tprevious: ILankaRuntimeConfig,\n\tpatch: ILankaRuntimeConfig,\n): ILankaRuntimeConfig {\n\treturn {\n\t\t// `host` is read field by field: `setConfig({ host: undefined })` through a\n\t\t// spread would leave the instance with no host, and every request URL would\n\t\t// then carry the string \"undefined\". Flags stay a spread — there both\n\t\t// absent and undefined mean \"not set\", so nothing can be lost.\n\t\thost: patch.host ?? previous.host,\n\t\tflags: { ...previous.flags, ...patch.flags },\n\t};\n}\n\ntype TExecutionTask = {\n\tname: string;\n\tpriority: number;\n\toptional: boolean;\n\ttimeoutMs?: number;\n\texecute: () => void | Promise<void>;\n};\n\n/**\n * Creates an instance and makes it active.\n *\n * Activating on creation is the deliberate default: there is almost always one\n * app and the facades must work immediately. A second instance takes the\n * pointer — the last one created serves the facades. Callers needing another\n * order call `activate()` explicitly.\n */\nexport function createLanka(config: ILankaInstanceConfig): ILankaInstance {\n\tlet runtimeConfig: ILankaRuntimeConfig = mergeLankaConfig(\n\t\t{},\n\t\t{ host: config.host, flags: config.flags },\n\t);\n\tlet bootstrapped = false;\n\tlet bootstrapping: Promise<void> | null = null; // the plan in flight, joined by later callers\n\n\tconst eventBus = new LankaEventBusInstance();\n\tconst scenarios = new LankaScenariosRegistry();\n\tconst viewModels = new LankaScenarioVMRegistry();\n\tconst inFlight = createInFlightCounter();\n\tconst scenarioState = {\n\t\tbootstrapped: false,\n\t\tinitialized: new WeakSet<ILankaScenarioVM>(),\n\t};\n\tconst scopes = new Set<ILankaScope>();\n\tconst requestMiddleware: TLankaRequestMiddleware[] = [];\n\tlet requestTimeoutMs: number | undefined;\n\n\tconst locators = {\n\t\tgateways: new LankaGatewayLocator(),\n\t\tscenarios: new LankaScenarioLocator(),\n\t\tsingletons: new LankaSingletonLocator(),\n\t\tsharedStores: new LankaSharedStoreLocator(),\n\t};\n\n\tconst instance: ILankaInstance = {\n\t\teventBus,\n\t\tscenarios,\n\t\tviewModels,\n\t\tinFlight,\n\t\tlocators,\n\t\tscenarioState,\n\t\trequestMiddleware,\n\t\tget requestTimeoutMs() {\n\t\t\treturn requestTimeoutMs;\n\t\t},\n\t\tuseRequestMiddleware(middleware: TLankaRequestMiddleware): () => void {\n\t\t\trequestMiddleware.push(middleware);\n\t\t\treturn () => {\n\t\t\t\tconst at = requestMiddleware.indexOf(middleware);\n\t\t\t\tif (at !== -1) requestMiddleware.splice(at, 1);\n\t\t\t};\n\t\t},\n\t\tsetRequestTimeout(timeoutMs: number | undefined): void {\n\t\t\trequestTimeoutMs = timeoutMs;\n\t\t},\n\t\tresolve<TInstance>(propertyName: string): TInstance {\n\t\t\treturn locators.singletons.get(propertyName) as TInstance;\n\t\t},\n\t\tuse(plugin: ILankaPlugin): () => void {\n\t\t\treturn plugins.use(plugin);\n\t\t},\n\t\tcreateScope(): ILankaScope {\n\t\t\tconst scope = createLankaScope(locators.singletons, viewModels);\n\t\t\tscopes.add(scope);\n\t\t\treturn scope;\n\t\t},\n\t\tget config() {\n\t\t\treturn runtimeConfig;\n\t\t},\n\t\tsetConfig(patch: ILankaRuntimeConfig): void {\n\t\t\truntimeConfig = mergeLankaConfig(runtimeConfig, patch);\n\t\t},\n\t\tgetFlags(): ILankaFlags {\n\t\t\treturn runtimeConfig.flags ?? {};\n\t\t},\n\t\tisBootstrapped(): boolean {\n\t\t\treturn bootstrapped;\n\t\t},\n\t\tactivate(): void {\n\t\t\tsetActiveLankaRuntime(instance);\n\t\t},\n\t\tdispose(): void {\n\t\t\tteardown();\n\t\t\trequestMiddleware.length = 0;\n\t\t\trequestTimeoutMs = undefined;\n\t\t\tbootstrapped = false;\n\t\t},\n\t\tbootstrap(bootstrapConfig: ILankaBootstrapConfig = {}): Promise<void> {\n\t\t\tif (bootstrapped) {\n\t\t\t\tlankaLogger.printBootstrapLog(\"LANKA ALREADY BOOTSTRAPPED\");\n\t\t\t\treturn Promise.resolve();\n\t\t\t}\n\t\t\t// One run, shared: the flag flips when the plan has FINISHED, so two\n\t\t\t// callers arriving before that — two routes, StrictMode mounting twice —\n\t\t\t// both read \"not bootstrapped\" and every service ran twice.\n\t\t\tbootstrapping ??= runBootstrap(instance, bootstrapConfig, () => {\n\t\t\t\tbootstrapped = true;\n\t\t\t}).finally(() => {\n\t\t\t\tbootstrapping = null;\n\t\t\t});\n\t\t\treturn bootstrapping;\n\t\t},\n\t};\n\n\t/**\n\t * Tears the instance down, in the ONE order that works.\n\t *\n\t * Scopes close FIRST: they hold objects built from this instance's classes, so\n\t * disposing without them would leave alive exactly what a scope exists to\n\t * remove. Plugins go AFTER scopes and BEFORE the registries: removing them\n\t * earlier would leave the objects being disposed with half a framework — no\n\t * middleware, but still expecting it.\n\t */\n\tfunction teardown(): void {\n\t\tfor (const scope of scopes) scope.dispose();\n\t\tscopes.clear();\n\n\t\tplugins.removeAll();\n\n\t\tviewModels.resetAll();\n\t\tscenarios.clear();\n\t\teventBus.reset();\n\n\t\tlocators.gateways.clearCache();\n\t\tlocators.scenarios.clearCache();\n\t\tlocators.singletons.clearCache();\n\t\tlocators.sharedStores.clearCache();\n\n\t\tscenarioState.bootstrapped = false;\n\t\tscenarioState.initialized = new WeakSet<ILankaScenarioVM>();\n\n\t\tif (getActiveRuntime() === instance) setActiveLankaRuntime(null);\n\t}\n\n\tconst plugins = createLankaPluginRegistry(instance);\n\n\tinstance.activate();\n\t// EVERY new instance adopts the declared ViewModels: a screen file creates\n\t// them at module level, and neither import order nor test number may decide\n\t// whether the framework knows about them.\n\tlankaScenarioBootstrap.adoptDeclaredViewModels();\n\n\treturn instance;\n}\n\nfunction createExecutionPlan(config: ILankaBootstrapConfig) {\n\tconst syncTasks: TExecutionTask[] = [];\n\tconst asyncTasks: TExecutionTask[] = [];\n\tconst postAsyncTasks: TExecutionTask[] = [];\n\n\tconfig.services?.forEach((service, index) => {\n\t\tconst task: TExecutionTask = {\n\t\t\tname: service.name || `Service-${index + 1}`,\n\t\t\tpriority: service.priority ?? 0,\n\t\t\toptional: service.optional ?? false,\n\t\t\ttimeoutMs: service.timeoutMs,\n\t\t\texecute: service.init,\n\t\t};\n\n\t\tif (service.sync) syncTasks.push(task);\n\t\telse asyncTasks.push(task);\n\t});\n\n\t// Field by field rather than a spread over defaults: a caller forwarding its\n\t// own optional config passes `{ sync: undefined }`, and a spread would put that\n\t// over `sync: true` — moving the whole scenario layer out of the sync phase\n\t// because somebody did not set a variable.\n\tconst scenarioSync = config.scenarios?.sync ?? true;\n\tconst scenarioTask: TExecutionTask = {\n\t\tname: \"LankaScenarioBootstrap\",\n\t\tpriority: config.scenarios?.priority ?? 0,\n\t\t// The scenario layer is required: without it nothing subscribed to it\n\t\t// works, and continuing silently would start an app where half the screens\n\t\t// never update.\n\t\toptional: false,\n\t\texecute: () => {\n\t\t\tlankaScenarioBootstrap.bootstrap();\n\t\t},\n\t};\n\n\tif (scenarioSync) syncTasks.push(scenarioTask);\n\telse postAsyncTasks.push(scenarioTask);\n\n\tsyncTasks.sort((a, b) => b.priority - a.priority);\n\n\treturn { syncTasks, asyncTasks, postAsyncTasks };\n}\n\n/**\n * One bootstrap, start to finish: the three phases in the one order that works,\n * then `markDone` — which the instance uses to flip its flag, and only then.\n *\n * Outside `createLanka` because it closes over nothing the instance holds: the\n * flag it must flip arrives as a callback, and everything else it needs it is\n * handed. That keeps the factory readable as the object it builds.\n */\nasync function runBootstrap(\n\tinstance: ILankaInstance,\n\tconfig: ILankaBootstrapConfig,\n\tmarkDone: () => void,\n): Promise<void> {\n\tinstance.activate();\n\tlankaLogger.printBootstrapLog(\"LANKA BOOTSTRAP START\");\n\n\tconst plan = createExecutionPlan(config);\n\tawait runSequential(plan.syncTasks, \"SYNC TASKS\");\n\tawait runParallel(plan.asyncTasks, \"ASYNC TASKS\");\n\tawait runSequential(plan.postAsyncTasks, \"POST-ASYNC TASKS (lankaScenarios)\");\n\n\tmarkDone();\n\tlankaLogger.printBootstrapLog(\"LANKA BOOTSTRAP FINISH\");\n}\n\n/**\n * Runs a task under its deadline.\n *\n * A race against a timer rather than an `AbortSignal`: a service is an arbitrary\n * application function and cannot be cancelled. The deadline bounds the WAIT,\n * not the work — hung work continues in the background, bootstrap stops waiting.\n */\nasync function runWithDeadline(task: TExecutionTask): Promise<void> {\n\tif (task.timeoutMs === undefined) {\n\t\tawait task.execute();\n\t\treturn;\n\t}\n\n\tlet timer: ReturnType<typeof setTimeout> | undefined;\n\ttry {\n\t\tawait Promise.race([\n\t\t\tPromise.resolve(task.execute()),\n\t\t\tnew Promise<never>((_resolve, reject) => {\n\t\t\t\ttimer = setTimeout(\n\t\t\t\t\t() =>\n\t\t\t\t\t\treject(\n\t\t\t\t\t\t\tnew Error(\n\t\t\t\t\t\t\t\t`Service \"${task.name}\" did not finish within ${String(task.timeoutMs)}ms`,\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t),\n\t\t\t\t\ttask.timeoutMs,\n\t\t\t\t);\n\t\t\t}),\n\t\t]);\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t}\n}\n\n/**\n * One task's failure: swallow and log, or abort the plan.\n *\n * The TASK's flag decides, not a blanket tolerance in the runner — otherwise\n * `optional` would mean nothing.\n */\nfunction handleTaskFailure(task: TExecutionTask, phaseName: string, error: unknown): void {\n\tlankaLogger.printBootstrapLog(`[${phaseName}] ERROR IN ${task.name}`, formatError(error));\n\tif (!task.optional) throw error;\n\tlankaLogger.printBootstrapLog(`[${phaseName}] SKIPPED (optional): ${task.name}`);\n}\n\nasync function runSequential(tasks: TExecutionTask[], phaseName: string): Promise<void> {\n\tif (tasks.length === 0) return;\n\n\tfor (const task of tasks) {\n\t\ttry {\n\t\t\tlankaLogger.printBootstrapLog(\n\t\t\t\t`[${phaseName}] EXECUTING: ${task.name} (Priority: ${String(task.priority)})`,\n\t\t\t);\n\t\t\tawait runWithDeadline(task);\n\t\t} catch (error) {\n\t\t\thandleTaskFailure(task, phaseName, error);\n\t\t}\n\t}\n}\n\nasync function runParallel(tasks: TExecutionTask[], phaseName: string): Promise<void> {\n\tif (tasks.length === 0) return;\n\n\tlankaLogger.printBootstrapLog(\n\t\t`[${phaseName}] EXECUTING ${String(tasks.length)} TASKS IN PARALLEL`,\n\t);\n\n\t// `allSettled`, not `all`: `all` rejects on the first failure, so an optional\n\t// service would take down required ones that were still running. Outcomes are\n\t// examined after everything has finished.\n\tconst outcomes = await Promise.allSettled(\n\t\ttasks.map(async (task) => {\n\t\t\tlankaLogger.printBootstrapLog(`[${phaseName}] EXECUTING: ${task.name}`);\n\t\t\tawait runWithDeadline(task);\n\t\t}),\n\t);\n\n\tfor (const [index, outcome] of outcomes.entries()) {\n\t\tif (outcome.status === \"rejected\") {\n\t\t\thandleTaskFailure(tasks[index], phaseName, outcome.reason);\n\t\t}\n\t}\n}\n\nfunction formatError(error: unknown): string {\n\treturn error instanceof Error ? error.message : String(error);\n}\n","import { createLanka } from \"../_factories/create-lanka/createLanka\";\nimport { createLankaHost } from \"../../config/_factories/create-lanka-host/createLankaHost\";\nimport type { ILankaHost } from \"../../config/_interfaces/ILankaHost\";\nimport type { ILankaInstance } from \"../_factories/create-lanka/createLanka\";\nimport type { TLankaStartConfig } from \"../_types/TLankaStartConfig\";\n\n/** The host as given, or one built from the base URL. */\nconst hostOf = (config: TLankaStartConfig): ILankaHost =>\n\tconfig.host ?? createLankaHost({ apiBaseUrl: config.apiBaseUrl, ...config.messages });\n\n/**\n * A started framework, in one call.\n *\n * ```ts\n * const lanka = await startLanka({ apiBaseUrl: \"https://api.example.com\" });\n * const sameOrigin = await startLanka(); // nothing to configure yet\n * ```\n *\n * ## What it saves, and what it does not hide\n *\n * `createLanka` already activates the instance it returns, and `bootstrap` already\n * brings up the scenario layer — so an application's whole start-up was two calls\n * and a `for` loop over its plugins. This is those, in the order that works, and\n * nothing else: what comes back is the same `ILankaInstance`, with every method\n * it always had.\n *\n * The order matters and is the reason this exists rather than a paragraph in a\n * guide. Plugins install BEFORE bootstrap, because a plugin that adds a\n * bootstrap service after the plan is built adds it to nothing; and bootstrap is\n * awaited, because a screen rendered against a half-started framework fails in\n * the layer it reaches first rather than where the mistake was.\n *\n * An application that needs something between those steps — registering a\n * singleton whose construction reads a service's result, say — writes the two\n * calls out and keeps this one for the next project.\n */\nexport const startLanka = async (config: TLankaStartConfig = {}): Promise<ILankaInstance> => {\n\tconst lanka = createLanka({ host: hostOf(config), flags: config.flags });\n\n\tfor (const plugin of config.plugins ?? []) lanka.use(plugin);\n\n\tawait lanka.bootstrap({ services: config.services, scenarios: config.scenarios });\n\n\treturn lanka;\n};\n","import { getActiveRuntime } from \"../../_internal/active-runtime/activeRuntime\";\nimport type { ILankaScenarioVM } from \"../../scenario/_interfaces/ILankaScenarioVM\";\n\n/**\n * Resets the active instance, if there is one.\n *\n * What the test kit needs between cases. Silent when there is no instance:\n * \"reset nothing\" is not an error, and the setup file runs before EVERY test,\n * including those that never bootstrap the framework.\n */\nexport function resetActiveLanka(): void {\n\tconst active = getActiveRuntime();\n\tif (!active) return;\n\n\tactive.viewModels.resetAll();\n\tactive.scenarios.clear();\n\tactive.eventBus.clearAllEvents();\n\tactive.scenarioState.bootstrapped = false;\n\tactive.scenarioState.initialized = new WeakSet<ILankaScenarioVM>();\n}\n","import type { ILankaInstance } from \"../../_factories/create-lanka/createLanka\";\nimport type { ILankaPlugin } from \"../../ILankaPlugin\";\n\n/**\n * A plugin, written as a class.\n *\n * The functional style is a function returning `{ name, install }`, and it is\n * what the framework's own five plugins use — a plugin is a value handed to\n * `use()`, and the ecosystem writes those as `react()`, `pinia()`,\n * `tsconfigPaths()`.\n *\n * This is the same contract for an application that keeps its plugins as\n * classes: `name` is a field, `install` is a method, and `uninstall` is the\n * teardown the framework calls on removal and on dispose. Nothing above can\n * tell which style wrote it — `use()` sees `ILankaPlugin` either way.\n */\nexport abstract class ALankaPlugin implements ILankaPlugin {\n\tpublic abstract readonly name: string;\n\n\t/** Everything this plugin puts in place. Return nothing if there is nothing to undo. */\n\tprotected abstract onInstall(lanka: ILankaInstance): void;\n\n\t/**\n\t * Removes what `onInstall` put in place.\n\t *\n\t * A default that does nothing rather than an abstract member: an abstract one\n\t * would break every existing subclass the day it was added, and most plugins\n\t * genuinely have nothing to undo.\n\t */\n\tprotected onUninstall(): void {\n\t\t/* Nothing to undo unless a subclass says otherwise. */\n\t}\n\n\tpublic install(lanka: ILankaInstance): () => void {\n\t\tthis.onInstall(lanka);\n\n\t\treturn () => {\n\t\t\tthis.onUninstall();\n\t\t};\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getLankaFlags
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-SP5OUTWF.js";
|
|
4
4
|
|
|
5
5
|
// src/logger/lanka-logger/LankaLogger.ts
|
|
6
6
|
var noop = () => {
|
|
@@ -221,4 +221,4 @@ export {
|
|
|
221
221
|
LankaLogger,
|
|
222
222
|
lankaLogger
|
|
223
223
|
};
|
|
224
|
-
//# sourceMappingURL=chunk-
|
|
224
|
+
//# sourceMappingURL=chunk-AMLUKB6A.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-G32H73QY.js";
|
|
8
8
|
import {
|
|
9
9
|
getLankaHost
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-JGJBFELR.js";
|
|
11
11
|
|
|
12
12
|
// src/errors/_factories/create-lanka-api-error/createLankaApiError.ts
|
|
13
13
|
var createLankaApiError = (status, errors, body) => {
|
|
@@ -49,4 +49,4 @@ export {
|
|
|
49
49
|
createLankaApiError,
|
|
50
50
|
handleLankaApiError
|
|
51
51
|
};
|
|
52
|
-
//# sourceMappingURL=chunk-
|
|
52
|
+
//# sourceMappingURL=chunk-DKLOCKS4.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ALankaScenario,
|
|
3
|
-
LankaScenariosRegistry
|
|
4
|
-
} from "./chunk-NWEHOMTS.js";
|
|
5
1
|
import {
|
|
6
2
|
ALankaLocator
|
|
7
3
|
} from "./chunk-N3275IPH.js";
|
|
4
|
+
import {
|
|
5
|
+
ALankaScenario,
|
|
6
|
+
LankaScenariosRegistry
|
|
7
|
+
} from "./chunk-L27FF2IH.js";
|
|
8
8
|
|
|
9
9
|
// src/locator/scenario/lanka-scenario-locator/LankaScenarioLocator.ts
|
|
10
10
|
import * as ScenariosModule from "@lanka_di/Scenarios";
|
|
@@ -119,4 +119,4 @@ var LankaScenarioLocator = class extends ALankaLocator {
|
|
|
119
119
|
export {
|
|
120
120
|
LankaScenarioLocator
|
|
121
121
|
};
|
|
122
|
-
//# sourceMappingURL=chunk-
|
|
122
|
+
//# sourceMappingURL=chunk-EH5WZSRJ.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
requireActiveRuntime
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-XTVEHYIZ.js";
|
|
4
4
|
|
|
5
5
|
// src/config/get-lanka-host/getLankaHost.ts
|
|
6
6
|
function getLankaHost() {
|
|
@@ -16,4 +16,4 @@ function getLankaHost() {
|
|
|
16
16
|
export {
|
|
17
17
|
getLankaHost
|
|
18
18
|
};
|
|
19
|
-
//# sourceMappingURL=chunk-
|
|
19
|
+
//# sourceMappingURL=chunk-JGJBFELR.js.map
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
lankaLogger
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-AMLUKB6A.js";
|
|
4
4
|
import {
|
|
5
5
|
requireActiveRuntime
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-XTVEHYIZ.js";
|
|
7
7
|
|
|
8
8
|
// src/scenario/event-bus/_facades/lanka-event-bus/lankaEventBus.ts
|
|
9
9
|
var bus = () => requireActiveRuntime().eventBus;
|
|
@@ -312,4 +312,4 @@ export {
|
|
|
312
312
|
LankaScenarioVMRegistry,
|
|
313
313
|
LankaScenariosRegistry
|
|
314
314
|
};
|
|
315
|
-
//# sourceMappingURL=chunk-
|
|
315
|
+
//# sourceMappingURL=chunk-L27FF2IH.js.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {
|
|
2
|
+
caseConvert
|
|
3
|
+
} from "./chunk-N3275IPH.js";
|
|
4
|
+
import {
|
|
5
|
+
lankaLogger
|
|
6
|
+
} from "./chunk-AMLUKB6A.js";
|
|
7
|
+
|
|
8
|
+
// src/viewmodel/_internal/lanka-vm-recipes/lankaVMRecipes.ts
|
|
9
|
+
var lankaVMRecipes = {
|
|
10
|
+
recipes: /* @__PURE__ */ new WeakMap(),
|
|
11
|
+
instances: /* @__PURE__ */ new WeakMap(),
|
|
12
|
+
owned: /* @__PURE__ */ new WeakMap(),
|
|
13
|
+
/** The instances belonging to one scope, created on first use. */
|
|
14
|
+
forScope(scope) {
|
|
15
|
+
const existing = this.instances.get(scope);
|
|
16
|
+
if (existing) return existing;
|
|
17
|
+
const created = /* @__PURE__ */ new WeakMap();
|
|
18
|
+
this.instances.set(scope, created);
|
|
19
|
+
return created;
|
|
20
|
+
},
|
|
21
|
+
/** Records that `scope` built a ViewModel that registered for scenarios. */
|
|
22
|
+
own(scope, viewModel) {
|
|
23
|
+
const set = this.owned.get(scope) ?? /* @__PURE__ */ new Set();
|
|
24
|
+
set.add(viewModel);
|
|
25
|
+
this.owned.set(scope, set);
|
|
26
|
+
},
|
|
27
|
+
/** Everything `scope` owns, handed over once; the scope then holds nothing. */
|
|
28
|
+
release(scope) {
|
|
29
|
+
const set = this.owned.get(scope);
|
|
30
|
+
this.owned.delete(scope);
|
|
31
|
+
this.instances.delete(scope);
|
|
32
|
+
return set ? [...set] : [];
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// src/locator/_factories/create-lanka-scope/createLankaScope.ts
|
|
37
|
+
function createLankaScope(singletons, viewModels) {
|
|
38
|
+
const instances = /* @__PURE__ */ new Map();
|
|
39
|
+
let disposed = false;
|
|
40
|
+
const scope = {
|
|
41
|
+
resolve(propertyName) {
|
|
42
|
+
if (disposed) {
|
|
43
|
+
throw new Error(
|
|
44
|
+
`The scope is closed: "${propertyName}" can no longer be resolved in it. This is usually a scope reference that outlived the screen that created it.`
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
const className = caseConvert(propertyName, "pascalCase");
|
|
48
|
+
if (instances.has(className)) return instances.get(className);
|
|
49
|
+
const instance = singletons.createScopedInstance(className, propertyName);
|
|
50
|
+
instances.set(className, instance);
|
|
51
|
+
return instance;
|
|
52
|
+
},
|
|
53
|
+
dispose() {
|
|
54
|
+
if (disposed) return;
|
|
55
|
+
disposed = true;
|
|
56
|
+
for (const viewModel of lankaVMRecipes.release(scope)) {
|
|
57
|
+
try {
|
|
58
|
+
viewModel.resetScenario();
|
|
59
|
+
} catch (error) {
|
|
60
|
+
lankaLogger.printBootstrapLog(
|
|
61
|
+
"Failed to reset a ViewModel's scenarios in the scope",
|
|
62
|
+
error instanceof Error ? error.message : String(error)
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
viewModels.unregister(viewModel);
|
|
66
|
+
}
|
|
67
|
+
for (const [name, instance] of instances) {
|
|
68
|
+
const disposable = instance;
|
|
69
|
+
if (typeof disposable.dispose !== "function") continue;
|
|
70
|
+
try {
|
|
71
|
+
disposable.dispose();
|
|
72
|
+
} catch (error) {
|
|
73
|
+
lankaLogger.printBootstrapLog(
|
|
74
|
+
`Failed to dispose "${name}" in the scope`,
|
|
75
|
+
error instanceof Error ? error.message : String(error)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
instances.clear();
|
|
80
|
+
},
|
|
81
|
+
isDisposed: () => disposed
|
|
82
|
+
};
|
|
83
|
+
return scope;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export {
|
|
87
|
+
lankaVMRecipes,
|
|
88
|
+
createLankaScope
|
|
89
|
+
};
|
|
90
|
+
//# sourceMappingURL=chunk-M4BK6GBV.js.map
|