lanka 2.0.0 → 2.0.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/dist/{LankaSharedStoreLocator-jsz_gnUm.d.ts → ALankaLocator-BUCCz0Q5.d.ts} +1 -47
- package/dist/{ILankaScenarioVM-DpKFL3iE.d.ts → ILankaScenario-DQd9ZfUw.d.ts} +1 -30
- package/dist/{ILankaScenarioMetadata-Dj4GCqmX.d.ts → ILankaScenarioMetadata-BsDp0Bzm.d.ts} +1 -1
- package/dist/ILankaScenarioVM-DKwjbIRq.d.ts +30 -0
- package/dist/{LankaScenarioLocator-Dki2Es3O.d.ts → LankaScenarioVMRegistry-DySAOaj2.d.ts} +4 -37
- package/dist/_extend/index.d.ts +11 -6
- package/dist/_extend/index.js +20 -9
- package/dist/_extend/index.js.map +1 -1
- package/dist/_internal/index.d.ts +13 -8
- package/dist/{activeRuntime-BO-qY0yY.d.ts → activeRuntime-ByucLPhj.d.ts} +7 -3
- package/dist/bootstrap/index.d.ts +15 -10
- package/dist/bootstrap/index.js +10 -4
- package/dist/chunk-24MUFFHF.js +43 -0
- package/dist/chunk-24MUFFHF.js.map +1 -0
- package/dist/chunk-3R2NO47A.js +35 -0
- package/dist/chunk-3R2NO47A.js.map +1 -0
- package/dist/{chunk-UMPSR4US.js → chunk-42CWYVZJ.js} +44 -61
- package/dist/chunk-42CWYVZJ.js.map +1 -0
- package/dist/chunk-BMF4TM2Z.js +22 -0
- package/dist/chunk-BMF4TM2Z.js.map +1 -0
- package/dist/chunk-JZJ6GXX3.js +12 -0
- package/dist/chunk-JZJ6GXX3.js.map +1 -0
- package/dist/{chunk-EYDMBI5T.js → chunk-MKKMTLOY.js} +11 -311
- package/dist/chunk-MKKMTLOY.js.map +1 -0
- package/dist/{chunk-UE2C76OR.js → chunk-N3275IPH.js} +2 -69
- package/dist/chunk-N3275IPH.js.map +1 -0
- package/dist/chunk-NWEHOMTS.js +315 -0
- package/dist/chunk-NWEHOMTS.js.map +1 -0
- package/dist/chunk-SBITVBF7.js +49 -0
- package/dist/chunk-SBITVBF7.js.map +1 -0
- package/dist/{chunk-SZVNPK24.js → chunk-SO7D5E7O.js} +17 -9
- package/dist/{chunk-SZVNPK24.js.map → chunk-SO7D5E7O.js.map} +1 -1
- package/dist/{createLanka-x4oSMs7P.d.ts → createLanka-DvUGu9Hl.d.ts} +2 -2
- package/dist/{createLankaScope-DomNbEvb.d.ts → createLankaScope-CVoV0EwO.d.ts} +1 -1
- package/dist/gateway/index.js +3 -3
- package/dist/index.d.ts +14 -9
- package/dist/index.js +10 -4
- package/dist/locator/gateway/lanka-gateway-locator/LankaGatewayLocator.d.ts +18 -0
- package/dist/locator/gateway/lanka-gateway-locator/LankaGatewayLocator.js +9 -0
- package/dist/locator/gateway/lanka-gateway-locator/LankaGatewayLocator.js.map +1 -0
- package/dist/locator/index.d.ts +4 -2
- package/dist/locator/index.js +4 -1
- package/dist/locator/index.js.map +1 -1
- package/dist/locator/scenario/lanka-scenario-locator/LankaScenarioLocator.d.ts +60 -0
- package/dist/locator/scenario/lanka-scenario-locator/LankaScenarioLocator.js +12 -0
- package/dist/locator/scenario/lanka-scenario-locator/LankaScenarioLocator.js.map +1 -0
- package/dist/locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.d.ts +22 -0
- package/dist/locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.js +9 -0
- package/dist/locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.js.map +1 -0
- package/dist/locator/singleton/lanka-singleton-locator/LankaSingletonLocator.d.ts +30 -0
- package/dist/locator/singleton/lanka-singleton-locator/LankaSingletonLocator.js +9 -0
- package/dist/locator/singleton/lanka-singleton-locator/LankaSingletonLocator.js.map +1 -0
- package/dist/scenario/index.d.ts +4 -3
- package/dist/scenario/index.js +5 -3
- package/dist/scenario/index.js.map +1 -1
- package/dist/stream/index.d.ts +17 -12
- package/dist/viewmodel/index.d.ts +2 -1
- package/dist/viewmodel/index.js +2 -1
- package/dist/viewmodel/index.js.map +1 -1
- package/package.json +1 -1
- package/skills/lanka-core/SKILL.md +1 -1
- package/skills/lanka-core/reference.md +1 -1
- package/skills/lanka-packages/SKILL.md +1 -1
- package/dist/chunk-EYDMBI5T.js.map +0 -1
- package/dist/chunk-UE2C76OR.js.map +0 -1
- package/dist/chunk-UMPSR4US.js.map +0 -1
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { A as ALankaSharedStore } from './ALankaSharedStore-B7uepuuk.js';
|
|
2
|
-
|
|
3
1
|
/**
|
|
4
2
|
* Resolves instances by camelCase property name, mapping it to the PascalCase
|
|
5
3
|
* class name.
|
|
@@ -100,48 +98,4 @@ declare abstract class ALankaLocator<TInstance> implements ILankaLocator<TInstan
|
|
|
100
98
|
isRegistered(className: string): boolean;
|
|
101
99
|
}
|
|
102
100
|
|
|
103
|
-
|
|
104
|
-
* LankaSingletonLocator configuration.
|
|
105
|
-
*/
|
|
106
|
-
interface ILankaSingletonLocatorConfig {
|
|
107
|
-
/** The module holding singleton classes — the consumer's barrel. */
|
|
108
|
-
singletonIndexModule?: Record<string, unknown>;
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Resolves singletons by property name (camelCase) or class name (PascalCase),
|
|
112
|
-
* constructing them on first use and caching them.
|
|
113
|
-
*
|
|
114
|
-
* A class arrives either from the consumer's barrel or registered by hand — the
|
|
115
|
-
* latter for tests and for objects that arrive already built.
|
|
116
|
-
*/
|
|
117
|
-
declare class LankaSingletonLocator extends ALankaLocator<unknown> {
|
|
118
|
-
private readonly singletonIndexModule?;
|
|
119
|
-
constructor(config?: ILankaSingletonLocatorConfig);
|
|
120
|
-
/**
|
|
121
|
-
* Creates a NEW service object, bypassing the locator's cache.
|
|
122
|
-
*
|
|
123
|
-
* For scopes: they take the class from here and set the lifetime themselves.
|
|
124
|
-
* The root cache is untouched — otherwise the first resolution inside a scope
|
|
125
|
-
* would replace the application's root object.
|
|
126
|
-
*/
|
|
127
|
-
createScopedInstance(className: string, propertyName: string): unknown;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
type TSharedStoreState = object;
|
|
131
|
-
/**
|
|
132
|
-
* LankaSharedStoreLocator configuration.
|
|
133
|
-
*/
|
|
134
|
-
interface ILankaSharedStoreLocatorConfig {
|
|
135
|
-
/** The module holding shared store classes — the consumer's barrel. */
|
|
136
|
-
sharedStoreIndexModule?: Record<string, unknown>;
|
|
137
|
-
}
|
|
138
|
-
/**
|
|
139
|
-
* Resolves shared stores by property name (camelCase) or class name
|
|
140
|
-
* (PascalCase), constructing them on first use and caching them.
|
|
141
|
-
*/
|
|
142
|
-
declare class LankaSharedStoreLocator extends ALankaLocator<ALankaSharedStore<TSharedStoreState>> {
|
|
143
|
-
private readonly sharedStoreIndexModule?;
|
|
144
|
-
constructor(config?: ILankaSharedStoreLocatorConfig);
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
export { ALankaLocator as A, type ILankaLocatorConfig as I, LankaSingletonLocator as L, LankaSharedStoreLocator as a, type ILankaLocator as b, type ILankaSharedStoreLocatorConfig as c, type ILankaSingletonLocatorConfig as d };
|
|
101
|
+
export { ALankaLocator as A, type ILankaLocatorConfig as I, type ILankaLocator as a };
|
|
@@ -342,33 +342,4 @@ interface ILankaScenario<TData = void> {
|
|
|
342
342
|
cleanup?(): void;
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
-
|
|
346
|
-
* A ViewModel that participates in scenarios.
|
|
347
|
-
*
|
|
348
|
-
* Not every ViewModel does: one with no `scenarioHandlers` and neither
|
|
349
|
-
* lifecycle hook has nothing for bootstrap to do and is never registered. This
|
|
350
|
-
* is the pair of methods `LankaScenarioBootstrap` calls on those that are, which
|
|
351
|
-
* is why the name says scenario rather than ViewModel — `onInit` and `onReset`
|
|
352
|
-
* ride on the same two calls.
|
|
353
|
-
*
|
|
354
|
-
* Both are idempotent by contract: bootstrap may run after a ViewModel has
|
|
355
|
-
* already initialised itself, and a reset may arrive for one that never did.
|
|
356
|
-
*/
|
|
357
|
-
interface ILankaScenarioVM {
|
|
358
|
-
/**
|
|
359
|
-
* Subscribes this ViewModel's scenario handlers.
|
|
360
|
-
*
|
|
361
|
-
* Called once the scenario registry is populated — a ViewModel declared at
|
|
362
|
-
* module level exists before any scenario does.
|
|
363
|
-
*/
|
|
364
|
-
initializeScenario(): void;
|
|
365
|
-
/**
|
|
366
|
-
* Releases every subscription, leaving the ViewModel ready to initialise again.
|
|
367
|
-
*
|
|
368
|
-
* Called when the framework instance is disposed, and by `resetLanka()`
|
|
369
|
-
* between tests.
|
|
370
|
-
*/
|
|
371
|
-
resetScenario(): void;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
export { type ILankaScenarioVM as I, LankaEventBusInstance as L, type TLankaReplayRequest as T, type ILankaScenario as a, type ILankaEventMetadata as b, type TLankaEventBusMiddleware as c, type TLankaEventBusObserver as d, type ILankaEventLog as e, type ILankaEventBusOutcome as f, type TLankaEventBusDecision as g };
|
|
345
|
+
export { type ILankaScenario as I, LankaEventBusInstance as L, type TLankaReplayRequest as T, type ILankaEventMetadata as a, type TLankaEventBusMiddleware as b, type TLankaEventBusObserver as c, type ILankaEventLog as d, type ILankaEventBusOutcome as e, type TLankaEventBusDecision as f };
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A ViewModel that participates in scenarios.
|
|
3
|
+
*
|
|
4
|
+
* Not every ViewModel does: one with no `scenarioHandlers` and neither
|
|
5
|
+
* lifecycle hook has nothing for bootstrap to do and is never registered. This
|
|
6
|
+
* is the pair of methods `LankaScenarioBootstrap` calls on those that are, which
|
|
7
|
+
* is why the name says scenario rather than ViewModel — `onInit` and `onReset`
|
|
8
|
+
* ride on the same two calls.
|
|
9
|
+
*
|
|
10
|
+
* Both are idempotent by contract: bootstrap may run after a ViewModel has
|
|
11
|
+
* already initialised itself, and a reset may arrive for one that never did.
|
|
12
|
+
*/
|
|
13
|
+
interface ILankaScenarioVM {
|
|
14
|
+
/**
|
|
15
|
+
* Subscribes this ViewModel's scenario handlers.
|
|
16
|
+
*
|
|
17
|
+
* Called once the scenario registry is populated — a ViewModel declared at
|
|
18
|
+
* module level exists before any scenario does.
|
|
19
|
+
*/
|
|
20
|
+
initializeScenario(): void;
|
|
21
|
+
/**
|
|
22
|
+
* Releases every subscription, leaving the ViewModel ready to initialise again.
|
|
23
|
+
*
|
|
24
|
+
* Called when the framework instance is disposed, and by `resetLanka()`
|
|
25
|
+
* between tests.
|
|
26
|
+
*/
|
|
27
|
+
resetScenario(): void;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type { ILankaScenarioVM as I };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { I as
|
|
3
|
-
import {
|
|
4
|
-
import { A as ALankaLocator } from './LankaSharedStoreLocator-jsz_gnUm.js';
|
|
1
|
+
import { I as ILankaScenario } from './ILankaScenario-DQd9ZfUw.js';
|
|
2
|
+
import { I as ILankaScenarioVM } from './ILankaScenarioVM-DKwjbIRq.js';
|
|
3
|
+
import { I as ILankaScenarioMetadata } from './ILankaScenarioMetadata-BsDp0Bzm.js';
|
|
5
4
|
|
|
6
5
|
/**
|
|
7
6
|
* The scenario registry: both those that registered themselves and those
|
|
@@ -114,36 +113,4 @@ declare class LankaScenarioVMRegistry {
|
|
|
114
113
|
resetAll(): void;
|
|
115
114
|
}
|
|
116
115
|
|
|
117
|
-
|
|
118
|
-
* Resolves a gateway by property name (camelCase) or class name (PascalCase),
|
|
119
|
-
* constructing it lazily and caching the instance.
|
|
120
|
-
*
|
|
121
|
-
* Adding a gateway takes one export line in `@lanka_di/Gateways`: types are
|
|
122
|
-
* inferred and nothing is registered.
|
|
123
|
-
*/
|
|
124
|
-
declare class LankaGatewayLocator extends ALankaLocator<ALankaGateway<unknown>> {
|
|
125
|
-
constructor();
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/**
|
|
129
|
-
* Resolves scenarios by property name (camelCase) or scenario name
|
|
130
|
-
* (PascalCase).
|
|
131
|
-
*
|
|
132
|
-
* Looks in the registry, then in the self-registration pool, and failing both
|
|
133
|
-
* constructs the scenario from the consumer's barrel on first use.
|
|
134
|
-
*/
|
|
135
|
-
declare class LankaScenarioLocator extends ALankaLocator<ILankaScenario<unknown>> {
|
|
136
|
-
/**
|
|
137
|
-
* The registry is read LAZILY rather than in a field initialiser.
|
|
138
|
-
*
|
|
139
|
-
* The locator is constructed INSIDE `createLanka`, before the instance becomes
|
|
140
|
-
* active. A field initialiser would ask for the active instance at that moment
|
|
141
|
-
* and fail with "no instance yet" while the instance being created is on the
|
|
142
|
-
* stack. Deferred reading resolves it: by the first scenario resolution an
|
|
143
|
-
* active instance exists.
|
|
144
|
-
*/
|
|
145
|
-
private get registry();
|
|
146
|
-
constructor();
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export { LankaScenariosRegistry as L, LankaScenarioVMRegistry as a, LankaGatewayLocator as b, LankaScenarioLocator as c };
|
|
116
|
+
export { LankaScenariosRegistry as L, LankaScenarioVMRegistry as a };
|
package/dist/_extend/index.d.ts
CHANGED
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import {
|
|
3
|
-
export { A as ALankaLocator
|
|
4
|
-
export { c as createLankaScope } from '../createLankaScope-
|
|
1
|
+
export { a as LankaScenarioVMRegistry, L as LankaScenariosRegistry } from '../LankaScenarioVMRegistry-DySAOaj2.js';
|
|
2
|
+
import { a as ILankaLocator } from '../ALankaLocator-BUCCz0Q5.js';
|
|
3
|
+
export { A as ALankaLocator } from '../ALankaLocator-BUCCz0Q5.js';
|
|
4
|
+
export { c as createLankaScope } from '../createLankaScope-CVoV0EwO.js';
|
|
5
|
+
export { LankaGatewayLocator } from '../locator/gateway/lanka-gateway-locator/LankaGatewayLocator.js';
|
|
6
|
+
export { LankaScenarioLocator } from '../locator/scenario/lanka-scenario-locator/LankaScenarioLocator.js';
|
|
7
|
+
export { LankaSingletonLocator } from '../locator/singleton/lanka-singleton-locator/LankaSingletonLocator.js';
|
|
8
|
+
export { LankaSharedStoreLocator } from '../locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.js';
|
|
5
9
|
export { c as composeLankaRequestMiddleware } from '../lankaRequestMiddleware-DAC5kCb7.js';
|
|
6
10
|
import { I as ILankaReadableVM } from '../ILankaReadableVM-BoPzHEPV.js';
|
|
7
|
-
import '../
|
|
8
|
-
import '../
|
|
11
|
+
import '../ILankaScenario-DQd9ZfUw.js';
|
|
12
|
+
import '../ILankaScenarioVM-DKwjbIRq.js';
|
|
13
|
+
import '../ILankaScenarioMetadata-BsDp0Bzm.js';
|
|
9
14
|
import '../ALankaGateway-BrVPaZN5.js';
|
|
10
15
|
import '../lankaStandardValidator-BUFnysK0.js';
|
|
11
16
|
import '@standard-schema/spec';
|
package/dist/_extend/index.js
CHANGED
|
@@ -2,15 +2,21 @@ import {
|
|
|
2
2
|
lankaBlindSpotRegistry
|
|
3
3
|
} from "../chunk-UDP6IXDS.js";
|
|
4
4
|
import {
|
|
5
|
-
LankaGatewayLocator,
|
|
6
|
-
LankaScenarioLocator,
|
|
7
5
|
createLankaScope
|
|
8
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-SBITVBF7.js";
|
|
7
|
+
import {
|
|
8
|
+
LankaGatewayLocator
|
|
9
|
+
} from "../chunk-BMF4TM2Z.js";
|
|
10
|
+
import {
|
|
11
|
+
LankaScenarioLocator
|
|
12
|
+
} from "../chunk-42CWYVZJ.js";
|
|
9
13
|
import {
|
|
10
|
-
LankaScenarioVMRegistry,
|
|
11
|
-
LankaScenariosRegistry,
|
|
12
14
|
lankaScenarioBootstrap
|
|
13
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-MKKMTLOY.js";
|
|
16
|
+
import {
|
|
17
|
+
LankaScenarioVMRegistry,
|
|
18
|
+
LankaScenariosRegistry
|
|
19
|
+
} from "../chunk-NWEHOMTS.js";
|
|
14
20
|
import {
|
|
15
21
|
composeLankaRequestMiddleware
|
|
16
22
|
} from "../chunk-YR4MZXMU.js";
|
|
@@ -18,10 +24,15 @@ import {
|
|
|
18
24
|
createLankaLocatorProxy
|
|
19
25
|
} from "../chunk-H5TIUKRK.js";
|
|
20
26
|
import {
|
|
21
|
-
|
|
22
|
-
|
|
27
|
+
LankaSharedStoreLocator
|
|
28
|
+
} from "../chunk-3R2NO47A.js";
|
|
29
|
+
import {
|
|
23
30
|
LankaSingletonLocator
|
|
24
|
-
} from "../chunk-
|
|
31
|
+
} from "../chunk-24MUFFHF.js";
|
|
32
|
+
import "../chunk-JZJ6GXX3.js";
|
|
33
|
+
import {
|
|
34
|
+
ALankaLocator
|
|
35
|
+
} from "../chunk-N3275IPH.js";
|
|
25
36
|
import "../chunk-FII3PW2G.js";
|
|
26
37
|
import "../chunk-7DQUF2QR.js";
|
|
27
38
|
import {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/viewmodel/_internal/create-lanka-access-tracker/createLankaAccessTracker.ts","../../src/viewmodel/_factories/create-lanka-view-subscription/createLankaViewSubscription.ts","../../src/viewmodel/_internal/lanka-vm-recipes/lankaVMRecipes.ts","../../src/viewmodel/_factories/define-lanka-vm/defineLankaVM.ts","../../src/viewmodel/_factories/resolve-lanka-vm/resolveLankaVM.ts"],"sourcesContent":["import { lankaBlindSpotRegistry } from \"../lanka-blind-spot-registry/lankaBlindSpotRegistry\";\nimport type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\nexport interface ILankaAccessTracker<TState extends object> {\n\t/**\n\t * The state as a recording Proxy: every key read off it is remembered.\n\t *\n\t * Cached by the IDENTITY of the state it wrapped, so a second read while\n\t * nothing has changed hands back the same proxy — and therefore the same\n\t * recorded keys — rather than starting the recording over.\n\t *\n\t * A ViewModel that turned tracking off gets the state itself, and every\n\t * change then notifies. That is its decision, not a fallback: it turned\n\t * tracking off because it DERIVES what the screen shows, and a recording that\n\t * cannot see those reads would skip renders the screen needs.\n\t */\n\tread(): TState;\n\t/**\n\t * Whether a change touches anything this reader actually looked at.\n\t *\n\t * A reader that has looked at NOTHING yet is notified of everything: it has\n\t * not had the chance to record a key, and staying silent would mean its first\n\t * render never arrives.\n\t */\n\tshouldNotify(next: TState, prev: TState): boolean;\n\t/**\n\t * Says, in development, that a change was skipped — so the framework can warn\n\t * if the screen reads the changed key through a getter.\n\t *\n\t * Called by a binding exactly when `shouldNotify` answered `false`. In\n\t * production, and for a ViewModel with no trap, it does nothing.\n\t */\n\treportSkipped(next: TState, prev: TState): void;\n\t/**\n\t * The state itself, never the proxy.\n\t *\n\t * For a render that happens once and is thrown away — a server snapshot. There\n\t * is nothing to skip on a second render that will not happen, so recording\n\t * reads would be work whose result nothing consults.\n\t */\n\treadPlain(): TState;\n\t/** The keys read so far. Handed to the blind-spot diagnostic, which names them. */\n\treadonly trackedKeys: ReadonlySet<string>;\n}\n\nconst asRecord = (state: object): Record<string, unknown> => state as Record<string, unknown>;\n\n/**\n * A view of `state` that records the keys a READER depends on.\n *\n * Three things are excluded, and each was found by a reader going deaf rather\n * than by review. What they have in common is that none of them can ever make\n * `shouldNotify` answer true — so recording one cannot cause a render, and can\n * only switch off the rule that a reader who has read NOTHING hears about\n * everything.\n *\n * **Symbols.** `shouldNotify` compares keys by name, so a recorded symbol could\n * never be consulted, and every symbol a runtime asks for while inspecting an\n * object would join the set.\n *\n * **Keys the state does not have.** A framework probes an unfamiliar object\n * before it will hold it: Vue's `shallowRef` reads `__v_isRef`, a promise\n * resolution reads `then`, React reads `$$typeof`. Each went through this proxy\n * and was recorded, and `undefined === undefined` on every later comparison.\n * That is what made `defineLankaStore(vm)` deaf to its own first change — the\n * ONE key it had recorded was `__v_isRef`, and a template reading a real key\n * during its first render is what hid it everywhere else.\n *\n * **Functions.** An action is one object for the life of the store, so a\n * recorded action can never differ. `await store.load()` before any other read\n * is the shape that found it. A state key holding a function that genuinely\n * changes is the case this gives up, and it is the right one: a callback living\n * in state is state two readers cannot agree about, and every ViewModel here and\n * in the applications keeps its functions in actions.\n */\nconst recordReadsInto = <TState extends object>(state: TState, keys: Set<string>): TState =>\n\tnew Proxy(state, {\n\t\tget(target, prop, receiver) {\n\t\t\tconst value = Reflect.get(target, prop, receiver) as unknown;\n\n\t\t\tif (\n\t\t\t\ttypeof prop === \"string\" &&\n\t\t\t\ttypeof value !== \"function\" &&\n\t\t\t\tObject.hasOwn(target, prop)\n\t\t\t) {\n\t\t\t\tkeys.add(prop);\n\t\t\t}\n\n\t\t\treturn value;\n\t\t},\n\t});\n\n/**\n * The recording one reader currently holds, rebuilt when the state moves.\n *\n * Its own unit because it is the stateful half: a proxy, the keys it has\n * collected, and the identity of the state it was made for. What is left around\n * it is a comparison and a report, neither of which remembers anything.\n */\nconst trackedReadOf = <TState extends object>(read: () => TState) => {\n\tlet keys = new Set<string>();\n\tlet state: TState | null = null;\n\tlet proxy: TState | null = null;\n\n\treturn {\n\t\tkeys: (): ReadonlySet<string> => keys,\n\n\t\tcurrent: (): TState => {\n\t\t\tconst next = read();\n\t\t\tif (state === next && proxy) return proxy;\n\n\t\t\t// A FRESH set per state: the keys a reader looks at can change between\n\t\t\t// renders — a branch stops being taken, a list empties — and keeping the\n\t\t\t// old ones would re-render for a key nobody reads any more, forever.\n\t\t\tkeys = new Set<string>();\n\t\t\tstate = next;\n\t\t\tproxy = recordReadsInto(next, keys);\n\n\t\t\treturn proxy;\n\t\t},\n\t};\n};\n\n/** Whether the two states disagree on any of the keys a reader looked at. */\nconst anyKeyMoved = (keys: ReadonlySet<string>, next: object, prev: object): boolean => {\n\tconst nextRecord = asRecord(next);\n\tconst prevRecord = asRecord(prev);\n\n\tfor (const key of keys) {\n\t\tif (!Object.is(nextRecord[key], prevRecord[key])) return true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Which state keys one reader looked at, and whether a change touched them.\n *\n * This is the whole of access tracking, and it is deliberately ignorant of how\n * anybody subscribes. A component re-renders only for keys it READ off the proxy\n * this returns; every framework asks that question the same way and answers it\n * with a different mechanism — `useSyncExternalStore`, a `shallowRef`, a signal —\n * so the question lives here and the mechanism lives in the binding.\n *\n * **This is the one piece of core a binding author needs.** It is published\n * through `lanka/extend` for exactly that: a binding is then a subscription, a\n * render trigger and these four calls, and the behaviour a consumer sees is the\n * framework's rather than each binding's re-reading of it. Canon:\n * `skills/parity/SKILL.md`.\n *\n * ## One tracker per reader, not per store\n *\n * The recorded keys are the property of whoever did the reading. Two components\n * over one ViewModel read different keys and must re-render for different\n * changes, so each holds its own tracker — which is also why this is a factory\n * with closed-over state rather than a set of pure functions over a shared map:\n * the lifetime of the recording is exactly the lifetime of the reader.\n *\n * ## The blind spot this cannot see, and reports instead\n *\n * Tracking sees reads made DIRECTLY off the proxy. A key reached only inside a\n * derived getter — an action calling `get()` — is invisible here, so a change to\n * it answers `shouldNotify` with `false` and the screen does not move. That is\n * what `reportSkipped` is for: core kept a trap for this ViewModel, and in\n * development it names the ViewModel and the key rather than leaving a frozen\n * screen with no error anywhere.\n */\nexport const createLankaAccessTracker = <TState extends object>(\n\tviewModel: ILankaReadableVM<TState>,\n): ILankaAccessTracker<TState> => {\n\tconst trap = lankaBlindSpotRegistry.of(viewModel);\n\tconst isTracked = viewModel.isAccessTracked;\n\tconst tracked = trackedReadOf(() => viewModel.getState());\n\n\treturn {\n\t\tget trackedKeys(): ReadonlySet<string> {\n\t\t\treturn isTracked ? tracked.keys() : new Set<string>();\n\t\t},\n\n\t\tread(): TState {\n\t\t\treturn isTracked ? tracked.current() : viewModel.getState();\n\t\t},\n\n\t\tshouldNotify(next: TState, prev: TState): boolean {\n\t\t\tif (!isTracked) return true;\n\n\t\t\tconst keys = tracked.keys();\n\n\t\t\treturn keys.size === 0 || anyKeyMoved(keys, next, prev);\n\t\t},\n\n\t\treportSkipped(next: TState, prev: TState): void {\n\t\t\ttrap?.report(new Set(tracked.keys()), asRecord(next), asRecord(prev));\n\t\t},\n\n\t\treadPlain(): TState {\n\t\t\treturn viewModel.getState();\n\t\t},\n\t};\n};\n","import { createLankaAccessTracker } from \"../../_internal/create-lanka-access-tracker/createLankaAccessTracker\";\nimport type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\n/** One reader's live view of a ViewModel. */\nexport interface ILankaViewSubscription<TState extends object> {\n\t/**\n\t * The current state, RECORDED.\n\t *\n\t * Every key read off it is remembered, which is what lets the next change be\n\t * skipped when it touched none of them. Call it again on every read: it asks\n\t * the ViewModel for its state each time, so it is never a snapshot.\n\t */\n\tread: () => TState;\n\t/** Releases the subscription. */\n\tstop: () => void;\n}\n\n/**\n * The TRACKED half of a view binding, minus the framework.\n *\n * The tracked half, and not the whole: all five shipped members also publish a\n * selector arm, which this deliberately does not serve — the reason is below,\n * under \"Why it does not take a selector\".\n *\n * ```ts\n * // a binding for a framework this repository has never heard of\n * export const useMyFrameworkVM = (viewModel) => {\n * \tconst view = createLankaViewSubscription(viewModel, () => invalidate());\n * \tonTeardown(view.stop);\n *\n * \treturn view.read;\n * };\n * ```\n *\n * Subscribe, ask whether the change touched anything this reader looked at,\n * report the skip so the blind-spot diagnostic can fire, and hand back a read\n * that records. Five packages wrote those four steps out by hand, identically —\n * and five copies of a decision diverge on the day one of them gains a line.\n *\n * ## What a caller still owns\n *\n * `onChange` and the teardown, which are the only framework-shaped things left.\n * That is the seam: a binding says how its framework is WOKEN and when a reader\n * has gone, and everything about which changes are worth waking for is here.\n *\n * ## Why it does not take a selector\n *\n * A selector BYPASSES tracking — the selector decides, and there is nothing to\n * record — so a subscription that took one would be two mechanisms behind one\n * name, each right half the time. A binding with a selector arm calls\n * `createLankaAccessTracker` directly, which is what the shelf's members do, and\n * the four steps are worth writing out where they genuinely differ.\n *\n * ## What it is not\n *\n * Not a store, not a cache, not a second place state lives. It holds a tracker\n * and an unsubscribe, and everything it answers comes from the ViewModel on the\n * call.\n */\nexport const createLankaViewSubscription = <TState extends object>(\n\tviewModel: ILankaReadableVM<TState>,\n\tonChange: () => void,\n): ILankaViewSubscription<TState> => {\n\tconst tracker = createLankaAccessTracker(viewModel);\n\n\tconst stop = viewModel.subscribe((next, prev) => {\n\t\tif (!tracker.shouldNotify(next, prev)) {\n\t\t\t// No update will follow. If the changed key is linked to this reader\n\t\t\t// through a getter it read, the screen froze — and in development core\n\t\t\t// names the ViewModel and the key rather than leaving it silent.\n\t\t\ttracker.reportSkipped(next, prev);\n\t\t\treturn;\n\t\t}\n\n\t\tonChange();\n\t});\n\n\treturn { read: () => tracker.read(), stop };\n};\n","import type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\n/** What a definition actually holds, kept where a consumer cannot reach it. */\nexport interface ILankaVMRecipe {\n\treadonly name: string;\n\treadonly build: () => ILankaReadableVM<object>;\n}\n\n/**\n * What `defineLankaVM` writes and `resolveLankaVM` reads.\n *\n * One object rather than two exported maps, because a file here holds one\n * runtime identity — and because the two halves are one mechanism: a recipe\n * nobody can resolve and an instance map keyed by nothing are each meaningless\n * alone.\n *\n * ## Weak at both ends, and both ends matter\n *\n * `recipes` is weak so a definition dropped by its module takes its recipe with\n * it. `instances` is weak in the SCOPE so a finished request's ViewModels go\n * when its scope does, and weak in the DEFINITION because the published type\n * invites `defineLankaVM({...})` written inline in a component or a loop — in a\n * browser the scope key is the framework instance and lives as long as the tab,\n * so a strong inner map would hold every inline definition and its ViewModel\n * for the life of the page.\n */\nexport const lankaVMRecipes = {\n\trecipes: new WeakMap<object, ILankaVMRecipe>(),\n\tinstances: new WeakMap<object, WeakMap<object, ILankaReadableVM<object>>>(),\n\n\t/** The instances belonging to one scope, created on first use. */\n\tforScope(scope: object): WeakMap<object, ILankaReadableVM<object>> {\n\t\tconst existing = this.instances.get(scope);\n\n\t\tif (existing) return existing;\n\n\t\tconst created = new WeakMap<object, ILankaReadableVM<object>>();\n\n\t\tthis.instances.set(scope, created);\n\n\t\treturn created;\n\t},\n};\n","import { lankaVMRecipes } from \"../../_internal/lanka-vm-recipes/lankaVMRecipes\";\nimport type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\n/**\n * The brand that makes a definition impossible to write by hand.\n *\n * Not exported, and that is the whole mechanism. A structural interface with\n * `name` and `build` on it would let a consumer author one, and the moment one\n * does, `ILankaVMDefinition` stops being a type the framework implements and\n * becomes a PORT — after which every member added to it is a compile error in\n * code nobody touched. Publishing an opaque type costs one line and keeps the\n * option space: a `dispose`, a `scope` field, even a call signature so that\n * `missionsVM()` could mean `resolveLankaVM(missionsVM)`, all stay additive.\n */\ndeclare const LANKA_VM_DEFINITION: unique symbol;\n\n/**\n * A ViewModel that has not been built yet.\n *\n * Hold it, pass it, type against it. There is nothing on it to call, because\n * calling it is `resolveLankaVM`'s job and a definition built by hand would be\n * an instance outside every scope's map.\n */\nexport interface ILankaVMDefinition<TViewModel extends ILankaReadableVM<object>> {\n\treadonly [LANKA_VM_DEFINITION]: TViewModel;\n}\n\n/**\n * Declares a ViewModel WITHOUT building it.\n *\n * ## When NOT to use this\n *\n * A browser-only application needs none of it. One module is one instance per\n * TAB there, so a module-level `createLankaVM` is still the shape, and wrapping\n * the nine factories in this one buys nothing but a lookup per read. Reach for\n * it when the same ViewModel has to exist on a SERVER, where one module is one\n * instance per PROCESS — shared by every user connected to it, so the first\n * request to write a draft into it serves that draft to the next stranger.\n *\n * ```ts\n * export const missionsVM = defineLankaVM({\n * \tname: \"MissionsVM\",\n * \tbuild: () => createLankaVM({ … }),\n * });\n * ```\n *\n * ## What it is not\n *\n * Not a tenth way to write a ViewModel. `build` returns whatever the nine\n * existing factories return and nothing here reaches inside it — a definition\n * adds a lifetime and takes nothing away.\n *\n * Not lazy in the sense `createLazyLankaVM` is. That one defers the STORE until\n * first read and still has one per module; this defers WHICH INSTANCE, and the\n * two compose.\n */\nexport const defineLankaVM = <TViewModel extends ILankaReadableVM<object>>(config: {\n\tname: string;\n\tbuild: () => TViewModel;\n}): ILankaVMDefinition<TViewModel> => {\n\tconst definition = Object.freeze({});\n\n\tlankaVMRecipes.recipes.set(definition, config);\n\n\treturn definition as ILankaVMDefinition<TViewModel>;\n};\n","import {\n\tgetActiveLankaScope,\n\thasLankaScopeResolver,\n\trequireActiveRuntime,\n} from \"../../../_internal/active-runtime/activeRuntime\";\nimport { lankaScenarioBootstrap } from \"../../../scenario/lanka-scenario-bootstrap/LankaScenarioBootstrap\";\nimport { lankaVMRecipes } from \"../../_internal/lanka-vm-recipes/lankaVMRecipes\";\nimport type { ILankaVMDefinition } from \"../define-lanka-vm/defineLankaVM\";\nimport type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\n/**\n * The instance of a definition that belongs to the CURRENT scope.\n *\n * Called twice in one scope it answers the same instance; called in two scopes\n * it answers two, and neither can see the other's state. In a browser there is\n * one scope for the life of the tab, so this is the module-level ViewModel a\n * consumer already knows — written once and correct on a server as well.\n *\n * ## It throws outside a scope, and that is the feature\n *\n * On a server the answer comes from the SCOPE seam rather than from the active\n * runtime, and the difference is not academic. `runInLankaServerScope` creates\n * its instance inside the scope and `createLanka` activates every instance it\n * builds, so during a request the process pointer and the scope's runtime are\n * the same object — keying on the runtime would make \"inside a request\" and\n * \"after one ended\" indistinguishable, and a call made after would be handed the\n * last stranger's ViewModel.\n *\n * So: a scope resolver installed and answering `null` means this ran outside\n * every request, and that fails loudly. No fallback, for the same reason\n * `requireActiveRuntime` has none — a wrong answer here is one user's data in\n * another user's page, and it would surface three layers from the call.\n *\n * ## Why the build is wrapped\n *\n * `ALankaVM.build()` declares a ViewModel that has scenario handlers into a\n * PROCESS-wide list, so that every instance ever created adopts it. That is\n * right for a module-level ViewModel and catastrophic for a scoped one: the list\n * would grow per request forever, and request N+1 would adopt request N's\n * ViewModel and run N's handlers against N's gateways. `buildScoped` is the seam\n * that keeps a scoped declaration out of it.\n */\nexport const resolveLankaVM = <TViewModel extends ILankaReadableVM<object>>(\n\tdefinition: ILankaVMDefinition<TViewModel>,\n): TViewModel => {\n\tconst recipe = lankaVMRecipes.recipes.get(definition);\n\n\tif (!recipe) {\n\t\tthrow new Error(\n\t\t\t\"resolveLankaVM was given something defineLankaVM did not make. A definition \" +\n\t\t\t\t\"is opaque on purpose: build it with defineLankaVM rather than by hand.\",\n\t\t);\n\t}\n\n\tconst runtime = requireActiveRuntime();\n\tconst scope = getActiveLankaScope();\n\n\tif (hasLankaScopeResolver() && !scope) {\n\t\tthrow new Error(\n\t\t\t`resolveLankaVM(\"${recipe.name}\") ran outside every scope. A scope resolver is ` +\n\t\t\t\t\"installed, which on a server means this code ran outside a request — and a \" +\n\t\t\t\t\"ViewModel resolved there would be the previous request's. Do this work inside \" +\n\t\t\t\t\"the scope, or start one.\",\n\t\t);\n\t}\n\n\t// The runtime when nothing knows about scopes: a browser tab is one scope for\n\t// its whole life, and the instance is what identifies it.\n\tconst instances = lankaVMRecipes.forScope(scope ?? runtime);\n\tconst held = instances.get(definition);\n\n\tif (held) return held as TViewModel;\n\n\tconst built = lankaScenarioBootstrap.buildScoped(() => recipe.build());\n\n\tinstances.set(definition, built);\n\n\treturn built as TViewModel;\n};\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/viewmodel/_internal/create-lanka-access-tracker/createLankaAccessTracker.ts","../../src/viewmodel/_factories/create-lanka-view-subscription/createLankaViewSubscription.ts","../../src/viewmodel/_internal/lanka-vm-recipes/lankaVMRecipes.ts","../../src/viewmodel/_factories/define-lanka-vm/defineLankaVM.ts","../../src/viewmodel/_factories/resolve-lanka-vm/resolveLankaVM.ts"],"sourcesContent":["import { lankaBlindSpotRegistry } from \"../lanka-blind-spot-registry/lankaBlindSpotRegistry\";\nimport type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\nexport interface ILankaAccessTracker<TState extends object> {\n\t/**\n\t * The state as a recording Proxy: every key read off it is remembered.\n\t *\n\t * Cached by the IDENTITY of the state it wrapped, so a second read while\n\t * nothing has changed hands back the same proxy — and therefore the same\n\t * recorded keys — rather than starting the recording over.\n\t *\n\t * A ViewModel that turned tracking off gets the state itself, and every\n\t * change then notifies. That is its decision, not a fallback: it turned\n\t * tracking off because it DERIVES what the screen shows, and a recording that\n\t * cannot see those reads would skip renders the screen needs.\n\t */\n\tread(): TState;\n\t/**\n\t * Whether a change touches anything this reader actually looked at.\n\t *\n\t * A reader that has looked at NOTHING yet is notified of everything: it has\n\t * not had the chance to record a key, and staying silent would mean its first\n\t * render never arrives.\n\t */\n\tshouldNotify(next: TState, prev: TState): boolean;\n\t/**\n\t * Says, in development, that a change was skipped — so the framework can warn\n\t * if the screen reads the changed key through a getter.\n\t *\n\t * Called by a binding exactly when `shouldNotify` answered `false`. In\n\t * production, and for a ViewModel with no trap, it does nothing.\n\t */\n\treportSkipped(next: TState, prev: TState): void;\n\t/**\n\t * The state itself, never the proxy.\n\t *\n\t * For a render that happens once and is thrown away — a server snapshot. There\n\t * is nothing to skip on a second render that will not happen, so recording\n\t * reads would be work whose result nothing consults.\n\t */\n\treadPlain(): TState;\n\t/** The keys read so far. Handed to the blind-spot diagnostic, which names them. */\n\treadonly trackedKeys: ReadonlySet<string>;\n}\n\nconst asRecord = (state: object): Record<string, unknown> => state as Record<string, unknown>;\n\n/**\n * A view of `state` that records the keys a READER depends on.\n *\n * Three things are excluded, and each was found by a reader going deaf rather\n * than by review. What they have in common is that none of them can ever make\n * `shouldNotify` answer true — so recording one cannot cause a render, and can\n * only switch off the rule that a reader who has read NOTHING hears about\n * everything.\n *\n * **Symbols.** `shouldNotify` compares keys by name, so a recorded symbol could\n * never be consulted, and every symbol a runtime asks for while inspecting an\n * object would join the set.\n *\n * **Keys the state does not have.** A framework probes an unfamiliar object\n * before it will hold it: Vue's `shallowRef` reads `__v_isRef`, a promise\n * resolution reads `then`, React reads `$$typeof`. Each went through this proxy\n * and was recorded, and `undefined === undefined` on every later comparison.\n * That is what made `defineLankaStore(vm)` deaf to its own first change — the\n * ONE key it had recorded was `__v_isRef`, and a template reading a real key\n * during its first render is what hid it everywhere else.\n *\n * **Functions.** An action is one object for the life of the store, so a\n * recorded action can never differ. `await store.load()` before any other read\n * is the shape that found it. A state key holding a function that genuinely\n * changes is the case this gives up, and it is the right one: a callback living\n * in state is state two readers cannot agree about, and every ViewModel here and\n * in the applications keeps its functions in actions.\n */\nconst recordReadsInto = <TState extends object>(state: TState, keys: Set<string>): TState =>\n\tnew Proxy(state, {\n\t\tget(target, prop, receiver) {\n\t\t\tconst value = Reflect.get(target, prop, receiver) as unknown;\n\n\t\t\tif (\n\t\t\t\ttypeof prop === \"string\" &&\n\t\t\t\ttypeof value !== \"function\" &&\n\t\t\t\tObject.hasOwn(target, prop)\n\t\t\t) {\n\t\t\t\tkeys.add(prop);\n\t\t\t}\n\n\t\t\treturn value;\n\t\t},\n\t});\n\n/**\n * The recording one reader currently holds, rebuilt when the state moves.\n *\n * Its own unit because it is the stateful half: a proxy, the keys it has\n * collected, and the identity of the state it was made for. What is left around\n * it is a comparison and a report, neither of which remembers anything.\n */\nconst trackedReadOf = <TState extends object>(read: () => TState) => {\n\tlet keys = new Set<string>();\n\tlet state: TState | null = null;\n\tlet proxy: TState | null = null;\n\n\treturn {\n\t\tkeys: (): ReadonlySet<string> => keys,\n\n\t\tcurrent: (): TState => {\n\t\t\tconst next = read();\n\t\t\tif (state === next && proxy) return proxy;\n\n\t\t\t// A FRESH set per state: the keys a reader looks at can change between\n\t\t\t// renders — a branch stops being taken, a list empties — and keeping the\n\t\t\t// old ones would re-render for a key nobody reads any more, forever.\n\t\t\tkeys = new Set<string>();\n\t\t\tstate = next;\n\t\t\tproxy = recordReadsInto(next, keys);\n\n\t\t\treturn proxy;\n\t\t},\n\t};\n};\n\n/** Whether the two states disagree on any of the keys a reader looked at. */\nconst anyKeyMoved = (keys: ReadonlySet<string>, next: object, prev: object): boolean => {\n\tconst nextRecord = asRecord(next);\n\tconst prevRecord = asRecord(prev);\n\n\tfor (const key of keys) {\n\t\tif (!Object.is(nextRecord[key], prevRecord[key])) return true;\n\t}\n\n\treturn false;\n};\n\n/**\n * Which state keys one reader looked at, and whether a change touched them.\n *\n * This is the whole of access tracking, and it is deliberately ignorant of how\n * anybody subscribes. A component re-renders only for keys it READ off the proxy\n * this returns; every framework asks that question the same way and answers it\n * with a different mechanism — `useSyncExternalStore`, a `shallowRef`, a signal —\n * so the question lives here and the mechanism lives in the binding.\n *\n * **This is the one piece of core a binding author needs.** It is published\n * through `lanka/extend` for exactly that: a binding is then a subscription, a\n * render trigger and these four calls, and the behaviour a consumer sees is the\n * framework's rather than each binding's re-reading of it. Canon:\n * `skills/parity/SKILL.md`.\n *\n * ## One tracker per reader, not per store\n *\n * The recorded keys are the property of whoever did the reading. Two components\n * over one ViewModel read different keys and must re-render for different\n * changes, so each holds its own tracker — which is also why this is a factory\n * with closed-over state rather than a set of pure functions over a shared map:\n * the lifetime of the recording is exactly the lifetime of the reader.\n *\n * ## The blind spot this cannot see, and reports instead\n *\n * Tracking sees reads made DIRECTLY off the proxy. A key reached only inside a\n * derived getter — an action calling `get()` — is invisible here, so a change to\n * it answers `shouldNotify` with `false` and the screen does not move. That is\n * what `reportSkipped` is for: core kept a trap for this ViewModel, and in\n * development it names the ViewModel and the key rather than leaving a frozen\n * screen with no error anywhere.\n */\nexport const createLankaAccessTracker = <TState extends object>(\n\tviewModel: ILankaReadableVM<TState>,\n): ILankaAccessTracker<TState> => {\n\tconst trap = lankaBlindSpotRegistry.of(viewModel);\n\tconst isTracked = viewModel.isAccessTracked;\n\tconst tracked = trackedReadOf(() => viewModel.getState());\n\n\treturn {\n\t\tget trackedKeys(): ReadonlySet<string> {\n\t\t\treturn isTracked ? tracked.keys() : new Set<string>();\n\t\t},\n\n\t\tread(): TState {\n\t\t\treturn isTracked ? tracked.current() : viewModel.getState();\n\t\t},\n\n\t\tshouldNotify(next: TState, prev: TState): boolean {\n\t\t\tif (!isTracked) return true;\n\n\t\t\tconst keys = tracked.keys();\n\n\t\t\treturn keys.size === 0 || anyKeyMoved(keys, next, prev);\n\t\t},\n\n\t\treportSkipped(next: TState, prev: TState): void {\n\t\t\ttrap?.report(new Set(tracked.keys()), asRecord(next), asRecord(prev));\n\t\t},\n\n\t\treadPlain(): TState {\n\t\t\treturn viewModel.getState();\n\t\t},\n\t};\n};\n","import { createLankaAccessTracker } from \"../../_internal/create-lanka-access-tracker/createLankaAccessTracker\";\nimport type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\n/** One reader's live view of a ViewModel. */\nexport interface ILankaViewSubscription<TState extends object> {\n\t/**\n\t * The current state, RECORDED.\n\t *\n\t * Every key read off it is remembered, which is what lets the next change be\n\t * skipped when it touched none of them. Call it again on every read: it asks\n\t * the ViewModel for its state each time, so it is never a snapshot.\n\t */\n\tread: () => TState;\n\t/** Releases the subscription. */\n\tstop: () => void;\n}\n\n/**\n * The TRACKED half of a view binding, minus the framework.\n *\n * The tracked half, and not the whole: all five shipped members also publish a\n * selector arm, which this deliberately does not serve — the reason is below,\n * under \"Why it does not take a selector\".\n *\n * ```ts\n * // a binding for a framework this repository has never heard of\n * export const useMyFrameworkVM = (viewModel) => {\n * \tconst view = createLankaViewSubscription(viewModel, () => invalidate());\n * \tonTeardown(view.stop);\n *\n * \treturn view.read;\n * };\n * ```\n *\n * Subscribe, ask whether the change touched anything this reader looked at,\n * report the skip so the blind-spot diagnostic can fire, and hand back a read\n * that records. Five packages wrote those four steps out by hand, identically —\n * and five copies of a decision diverge on the day one of them gains a line.\n *\n * ## What a caller still owns\n *\n * `onChange` and the teardown, which are the only framework-shaped things left.\n * That is the seam: a binding says how its framework is WOKEN and when a reader\n * has gone, and everything about which changes are worth waking for is here.\n *\n * ## Why it does not take a selector\n *\n * A selector BYPASSES tracking — the selector decides, and there is nothing to\n * record — so a subscription that took one would be two mechanisms behind one\n * name, each right half the time. A binding with a selector arm calls\n * `createLankaAccessTracker` directly, which is what the shelf's members do, and\n * the four steps are worth writing out where they genuinely differ.\n *\n * ## What it is not\n *\n * Not a store, not a cache, not a second place state lives. It holds a tracker\n * and an unsubscribe, and everything it answers comes from the ViewModel on the\n * call.\n */\nexport const createLankaViewSubscription = <TState extends object>(\n\tviewModel: ILankaReadableVM<TState>,\n\tonChange: () => void,\n): ILankaViewSubscription<TState> => {\n\tconst tracker = createLankaAccessTracker(viewModel);\n\n\tconst stop = viewModel.subscribe((next, prev) => {\n\t\tif (!tracker.shouldNotify(next, prev)) {\n\t\t\t// No update will follow. If the changed key is linked to this reader\n\t\t\t// through a getter it read, the screen froze — and in development core\n\t\t\t// names the ViewModel and the key rather than leaving it silent.\n\t\t\ttracker.reportSkipped(next, prev);\n\t\t\treturn;\n\t\t}\n\n\t\tonChange();\n\t});\n\n\treturn { read: () => tracker.read(), stop };\n};\n","import type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\n/** What a definition actually holds, kept where a consumer cannot reach it. */\nexport interface ILankaVMRecipe {\n\treadonly name: string;\n\treadonly build: () => ILankaReadableVM<object>;\n}\n\n/**\n * What `defineLankaVM` writes and `resolveLankaVM` reads.\n *\n * One object rather than two exported maps, because a file here holds one\n * runtime identity — and because the two halves are one mechanism: a recipe\n * nobody can resolve and an instance map keyed by nothing are each meaningless\n * alone.\n *\n * ## Weak at both ends, and both ends matter\n *\n * `recipes` is weak so a definition dropped by its module takes its recipe with\n * it. `instances` is weak in the SCOPE so a finished request's ViewModels go\n * when its scope does, and weak in the DEFINITION because the published type\n * invites `defineLankaVM({...})` written inline in a component or a loop — in a\n * browser the scope key is the framework instance and lives as long as the tab,\n * so a strong inner map would hold every inline definition and its ViewModel\n * for the life of the page.\n */\nexport const lankaVMRecipes = {\n\trecipes: new WeakMap<object, ILankaVMRecipe>(),\n\tinstances: new WeakMap<object, WeakMap<object, ILankaReadableVM<object>>>(),\n\n\t/** The instances belonging to one scope, created on first use. */\n\tforScope(scope: object): WeakMap<object, ILankaReadableVM<object>> {\n\t\tconst existing = this.instances.get(scope);\n\n\t\tif (existing) return existing;\n\n\t\tconst created = new WeakMap<object, ILankaReadableVM<object>>();\n\n\t\tthis.instances.set(scope, created);\n\n\t\treturn created;\n\t},\n};\n","import { lankaVMRecipes } from \"../../_internal/lanka-vm-recipes/lankaVMRecipes\";\nimport type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\n/**\n * The brand that makes a definition impossible to write by hand.\n *\n * Not exported, and that is the whole mechanism. A structural interface with\n * `name` and `build` on it would let a consumer author one, and the moment one\n * does, `ILankaVMDefinition` stops being a type the framework implements and\n * becomes a PORT — after which every member added to it is a compile error in\n * code nobody touched. Publishing an opaque type costs one line and keeps the\n * option space: a `dispose`, a `scope` field, even a call signature so that\n * `missionsVM()` could mean `resolveLankaVM(missionsVM)`, all stay additive.\n */\ndeclare const LANKA_VM_DEFINITION: unique symbol;\n\n/**\n * A ViewModel that has not been built yet.\n *\n * Hold it, pass it, type against it. There is nothing on it to call, because\n * calling it is `resolveLankaVM`'s job and a definition built by hand would be\n * an instance outside every scope's map.\n */\nexport interface ILankaVMDefinition<TViewModel extends ILankaReadableVM<object>> {\n\treadonly [LANKA_VM_DEFINITION]: TViewModel;\n}\n\n/**\n * Declares a ViewModel WITHOUT building it.\n *\n * ## When NOT to use this\n *\n * A browser-only application needs none of it. One module is one instance per\n * TAB there, so a module-level `createLankaVM` is still the shape, and wrapping\n * the nine factories in this one buys nothing but a lookup per read. Reach for\n * it when the same ViewModel has to exist on a SERVER, where one module is one\n * instance per PROCESS — shared by every user connected to it, so the first\n * request to write a draft into it serves that draft to the next stranger.\n *\n * ```ts\n * export const missionsVM = defineLankaVM({\n * \tname: \"MissionsVM\",\n * \tbuild: () => createLankaVM({ … }),\n * });\n * ```\n *\n * ## What it is not\n *\n * Not a tenth way to write a ViewModel. `build` returns whatever the nine\n * existing factories return and nothing here reaches inside it — a definition\n * adds a lifetime and takes nothing away.\n *\n * Not lazy in the sense `createLazyLankaVM` is. That one defers the STORE until\n * first read and still has one per module; this defers WHICH INSTANCE, and the\n * two compose.\n */\nexport const defineLankaVM = <TViewModel extends ILankaReadableVM<object>>(config: {\n\tname: string;\n\tbuild: () => TViewModel;\n}): ILankaVMDefinition<TViewModel> => {\n\tconst definition = Object.freeze({});\n\n\tlankaVMRecipes.recipes.set(definition, config);\n\n\treturn definition as ILankaVMDefinition<TViewModel>;\n};\n","import {\n\tgetActiveLankaScope,\n\thasLankaScopeResolver,\n\trequireActiveRuntime,\n} from \"../../../_internal/active-runtime/activeRuntime\";\nimport { lankaScenarioBootstrap } from \"../../../scenario/lanka-scenario-bootstrap/LankaScenarioBootstrap\";\nimport { lankaVMRecipes } from \"../../_internal/lanka-vm-recipes/lankaVMRecipes\";\nimport type { ILankaVMDefinition } from \"../define-lanka-vm/defineLankaVM\";\nimport type { ILankaReadableVM } from \"../../_interfaces/ILankaReadableVM\";\n\n/**\n * The instance of a definition that belongs to the CURRENT scope.\n *\n * Called twice in one scope it answers the same instance; called in two scopes\n * it answers two, and neither can see the other's state. In a browser there is\n * one scope for the life of the tab, so this is the module-level ViewModel a\n * consumer already knows — written once and correct on a server as well.\n *\n * ## It throws outside a scope, and that is the feature\n *\n * On a server the answer comes from the SCOPE seam rather than from the active\n * runtime, and the difference is not academic. `runInLankaServerScope` creates\n * its instance inside the scope and `createLanka` activates every instance it\n * builds, so during a request the process pointer and the scope's runtime are\n * the same object — keying on the runtime would make \"inside a request\" and\n * \"after one ended\" indistinguishable, and a call made after would be handed the\n * last stranger's ViewModel.\n *\n * So: a scope resolver installed and answering `null` means this ran outside\n * every request, and that fails loudly. No fallback, for the same reason\n * `requireActiveRuntime` has none — a wrong answer here is one user's data in\n * another user's page, and it would surface three layers from the call.\n *\n * ## Why the build is wrapped\n *\n * `ALankaVM.build()` declares a ViewModel that has scenario handlers into a\n * PROCESS-wide list, so that every instance ever created adopts it. That is\n * right for a module-level ViewModel and catastrophic for a scoped one: the list\n * would grow per request forever, and request N+1 would adopt request N's\n * ViewModel and run N's handlers against N's gateways. `buildScoped` is the seam\n * that keeps a scoped declaration out of it.\n */\nexport const resolveLankaVM = <TViewModel extends ILankaReadableVM<object>>(\n\tdefinition: ILankaVMDefinition<TViewModel>,\n): TViewModel => {\n\tconst recipe = lankaVMRecipes.recipes.get(definition);\n\n\tif (!recipe) {\n\t\tthrow new Error(\n\t\t\t\"resolveLankaVM was given something defineLankaVM did not make. A definition \" +\n\t\t\t\t\"is opaque on purpose: build it with defineLankaVM rather than by hand.\",\n\t\t);\n\t}\n\n\tconst runtime = requireActiveRuntime();\n\tconst scope = getActiveLankaScope();\n\n\tif (hasLankaScopeResolver() && !scope) {\n\t\tthrow new Error(\n\t\t\t`resolveLankaVM(\"${recipe.name}\") ran outside every scope. A scope resolver is ` +\n\t\t\t\t\"installed, which on a server means this code ran outside a request — and a \" +\n\t\t\t\t\"ViewModel resolved there would be the previous request's. Do this work inside \" +\n\t\t\t\t\"the scope, or start one.\",\n\t\t);\n\t}\n\n\t// The runtime when nothing knows about scopes: a browser tab is one scope for\n\t// its whole life, and the instance is what identifies it.\n\tconst instances = lankaVMRecipes.forScope(scope ?? runtime);\n\tconst held = instances.get(definition);\n\n\tif (held) return held as TViewModel;\n\n\tconst built = lankaScenarioBootstrap.buildScoped(() => recipe.build());\n\n\tinstances.set(definition, built);\n\n\treturn built as TViewModel;\n};\n"],"mappings":"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","names":[]}
|
|
@@ -1,17 +1,22 @@
|
|
|
1
|
-
export { I as ILankaRuntime, T as TLankaRuntimeResolver, a as TLankaScopeResolver, g as getLankaProcessRuntime, s as setActiveLankaRuntime, b as setLankaRuntimeResolver, c as setLankaScopeResolver } from '../activeRuntime-
|
|
1
|
+
export { I as ILankaRuntime, T as TLankaRuntimeResolver, a as TLankaScopeResolver, g as getLankaProcessRuntime, s as setActiveLankaRuntime, b as setLankaRuntimeResolver, c as setLankaScopeResolver } from '../activeRuntime-ByucLPhj.js';
|
|
2
2
|
import { a as TLankaValidationResult } from '../lankaStandardValidator-BUFnysK0.js';
|
|
3
|
-
import '../
|
|
4
|
-
import '../
|
|
5
|
-
import '../
|
|
6
|
-
import '../
|
|
7
|
-
import '../LankaSharedStoreLocator-jsz_gnUm.js';
|
|
8
|
-
import '../ALankaSharedStore-B7uepuuk.js';
|
|
9
|
-
import 'zustand/vanilla';
|
|
3
|
+
import '../ILankaScenario-DQd9ZfUw.js';
|
|
4
|
+
import '../LankaScenarioVMRegistry-DySAOaj2.js';
|
|
5
|
+
import '../ILankaScenarioVM-DKwjbIRq.js';
|
|
6
|
+
import '../ILankaScenarioMetadata-BsDp0Bzm.js';
|
|
10
7
|
import '../ILankaRuntimeConfig-Vl436GWK.js';
|
|
11
8
|
import '../lankaHttpInFlight-Bk1eIuSx.js';
|
|
12
9
|
import '../lankaRequestMiddleware-DAC5kCb7.js';
|
|
10
|
+
import '../locator/gateway/lanka-gateway-locator/LankaGatewayLocator.js';
|
|
11
|
+
import '../ALankaGateway-BrVPaZN5.js';
|
|
12
|
+
import '../ALankaLocator-BUCCz0Q5.js';
|
|
13
13
|
import '@standard-schema/spec';
|
|
14
14
|
import '../ILankaFieldError-D5931-vT.js';
|
|
15
|
+
import '../locator/scenario/lanka-scenario-locator/LankaScenarioLocator.js';
|
|
16
|
+
import '../locator/singleton/lanka-singleton-locator/LankaSingletonLocator.js';
|
|
17
|
+
import '../locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.js';
|
|
18
|
+
import '../ALankaSharedStore-B7uepuuk.js';
|
|
19
|
+
import 'zustand/vanilla';
|
|
15
20
|
|
|
16
21
|
declare function generateUuid(): string;
|
|
17
22
|
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import { L as LankaEventBusInstance
|
|
2
|
-
import { L as LankaScenariosRegistry, a as LankaScenarioVMRegistry
|
|
1
|
+
import { L as LankaEventBusInstance } from './ILankaScenario-DQd9ZfUw.js';
|
|
2
|
+
import { L as LankaScenariosRegistry, a as LankaScenarioVMRegistry } from './LankaScenarioVMRegistry-DySAOaj2.js';
|
|
3
3
|
import { b as ILankaRuntimeConfig } from './ILankaRuntimeConfig-Vl436GWK.js';
|
|
4
4
|
import { I as ILankaInFlightCounter } from './lankaHttpInFlight-Bk1eIuSx.js';
|
|
5
|
+
import { I as ILankaScenarioVM } from './ILankaScenarioVM-DKwjbIRq.js';
|
|
5
6
|
import { T as TLankaRequestMiddleware } from './lankaRequestMiddleware-DAC5kCb7.js';
|
|
6
|
-
import {
|
|
7
|
+
import { LankaGatewayLocator } from './locator/gateway/lanka-gateway-locator/LankaGatewayLocator.js';
|
|
8
|
+
import { LankaScenarioLocator } from './locator/scenario/lanka-scenario-locator/LankaScenarioLocator.js';
|
|
9
|
+
import { LankaSingletonLocator } from './locator/singleton/lanka-singleton-locator/LankaSingletonLocator.js';
|
|
10
|
+
import { LankaSharedStoreLocator } from './locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.js';
|
|
7
11
|
|
|
8
12
|
/**
|
|
9
13
|
* The pointer to the framework instance that ambient facades resolve to.
|
|
@@ -1,20 +1,25 @@
|
|
|
1
|
-
import { c as ILankaPlugin, e as ILankaServiceConfig, I as ILankaBootstrapConfig, a as ILankaInstance } from '../createLanka-
|
|
2
|
-
export { b as ILankaInstanceConfig, d as ILankaScenarioBootstrapConfig, f as createLanka } from '../createLanka-
|
|
1
|
+
import { c as ILankaPlugin, e as ILankaServiceConfig, I as ILankaBootstrapConfig, a as ILankaInstance } from '../createLanka-DvUGu9Hl.js';
|
|
2
|
+
export { b as ILankaInstanceConfig, d as ILankaScenarioBootstrapConfig, f as createLanka } from '../createLanka-DvUGu9Hl.js';
|
|
3
3
|
import { I as ILankaFlags, a as ILankaHost } from '../ILankaRuntimeConfig-Vl436GWK.js';
|
|
4
|
-
export { I as ILankaScope } from '../createLankaScope-
|
|
5
|
-
import '../activeRuntime-
|
|
6
|
-
import '../
|
|
7
|
-
import '../
|
|
8
|
-
import '../
|
|
4
|
+
export { I as ILankaScope } from '../createLankaScope-CVoV0EwO.js';
|
|
5
|
+
import '../activeRuntime-ByucLPhj.js';
|
|
6
|
+
import '../ILankaScenario-DQd9ZfUw.js';
|
|
7
|
+
import '../LankaScenarioVMRegistry-DySAOaj2.js';
|
|
8
|
+
import '../ILankaScenarioVM-DKwjbIRq.js';
|
|
9
|
+
import '../ILankaScenarioMetadata-BsDp0Bzm.js';
|
|
10
|
+
import '../lankaHttpInFlight-Bk1eIuSx.js';
|
|
11
|
+
import '../lankaRequestMiddleware-DAC5kCb7.js';
|
|
12
|
+
import '../locator/gateway/lanka-gateway-locator/LankaGatewayLocator.js';
|
|
9
13
|
import '../ALankaGateway-BrVPaZN5.js';
|
|
10
14
|
import '../lankaStandardValidator-BUFnysK0.js';
|
|
11
15
|
import '@standard-schema/spec';
|
|
12
16
|
import '../ILankaFieldError-D5931-vT.js';
|
|
13
|
-
import '../
|
|
17
|
+
import '../ALankaLocator-BUCCz0Q5.js';
|
|
18
|
+
import '../locator/scenario/lanka-scenario-locator/LankaScenarioLocator.js';
|
|
19
|
+
import '../locator/singleton/lanka-singleton-locator/LankaSingletonLocator.js';
|
|
20
|
+
import '../locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.js';
|
|
14
21
|
import '../ALankaSharedStore-B7uepuuk.js';
|
|
15
22
|
import 'zustand/vanilla';
|
|
16
|
-
import '../lankaHttpInFlight-Bk1eIuSx.js';
|
|
17
|
-
import '../lankaRequestMiddleware-DAC5kCb7.js';
|
|
18
23
|
|
|
19
24
|
/** What `startLanka` takes beyond the host, all of it optional. */
|
|
20
25
|
interface ILankaStartOptions {
|
package/dist/bootstrap/index.js
CHANGED
|
@@ -3,12 +3,18 @@ import {
|
|
|
3
3
|
createLanka,
|
|
4
4
|
resetActiveLanka,
|
|
5
5
|
startLanka
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-SO7D5E7O.js";
|
|
7
|
+
import "../chunk-SBITVBF7.js";
|
|
8
|
+
import "../chunk-BMF4TM2Z.js";
|
|
9
|
+
import "../chunk-42CWYVZJ.js";
|
|
10
|
+
import "../chunk-MKKMTLOY.js";
|
|
11
|
+
import "../chunk-NWEHOMTS.js";
|
|
9
12
|
import "../chunk-XESL274R.js";
|
|
10
13
|
import "../chunk-BHQ2SQ7P.js";
|
|
11
|
-
import "../chunk-
|
|
14
|
+
import "../chunk-3R2NO47A.js";
|
|
15
|
+
import "../chunk-24MUFFHF.js";
|
|
16
|
+
import "../chunk-JZJ6GXX3.js";
|
|
17
|
+
import "../chunk-N3275IPH.js";
|
|
12
18
|
import "../chunk-FII3PW2G.js";
|
|
13
19
|
import "../chunk-7DQUF2QR.js";
|
|
14
20
|
import "../chunk-XGMXT4XZ.js";
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findExportedClass
|
|
3
|
+
} from "./chunk-JZJ6GXX3.js";
|
|
4
|
+
import {
|
|
5
|
+
ALankaLocator
|
|
6
|
+
} from "./chunk-N3275IPH.js";
|
|
7
|
+
|
|
8
|
+
// src/locator/singleton/lanka-singleton-locator/LankaSingletonLocator.ts
|
|
9
|
+
import * as SingletonsModule from "@lanka_di/Singletons";
|
|
10
|
+
var LankaSingletonLocator = class extends ALankaLocator {
|
|
11
|
+
singletonIndexModule;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
super({
|
|
14
|
+
findClassByName: (className) => {
|
|
15
|
+
return findExportedClass(SingletonsModule, className) ?? (this.singletonIndexModule ? findExportedClass(this.singletonIndexModule, className) : void 0);
|
|
16
|
+
},
|
|
17
|
+
createInstance: (Class) => {
|
|
18
|
+
return new Class();
|
|
19
|
+
},
|
|
20
|
+
notFoundError: (className, propertyName) => `Singleton "${className}" (accessed as "${propertyName}") not found. Make sure the class is exported from @lanka_di/Singletons.ts or registered via registerSingleton method.`
|
|
21
|
+
});
|
|
22
|
+
this.singletonIndexModule = config?.singletonIndexModule;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Creates a NEW service object, bypassing the locator's cache.
|
|
26
|
+
*
|
|
27
|
+
* For scopes: they take the class from here and set the lifetime themselves.
|
|
28
|
+
* The root cache is untouched — otherwise the first resolution inside a scope
|
|
29
|
+
* would replace the application's root object.
|
|
30
|
+
*/
|
|
31
|
+
createScopedInstance(className, propertyName) {
|
|
32
|
+
const Class = this.classFor(className);
|
|
33
|
+
if (!Class) {
|
|
34
|
+
throw new Error(this.config.notFoundError(className, propertyName));
|
|
35
|
+
}
|
|
36
|
+
return this.config.createInstance(Class);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export {
|
|
41
|
+
LankaSingletonLocator
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=chunk-24MUFFHF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/locator/singleton/lanka-singleton-locator/LankaSingletonLocator.ts"],"sourcesContent":["import { ALankaLocator } from \"../../_abstractions/lanka-locator/ALankaLocator\";\nimport { findExportedClass } from \"../../_internal/find-exported-class/findExportedClass\";\n/**\n * Classes come from the consumer's barrel.\n *\n * Adding one is ONE export line: types are inferred, autocomplete works, and no\n * list has to be maintained. A list maintained by hand is a list that eventually\n * falls behind the code.\n */\nimport * as SingletonsModule from \"@lanka_di/Singletons\";\n\n/**\n * LankaSingletonLocator configuration.\n */\nexport interface ILankaSingletonLocatorConfig {\n\t/** The module holding singleton classes — the consumer's barrel. */\n\tsingletonIndexModule?: Record<string, unknown>;\n}\n\n/**\n * Resolves singletons by property name (camelCase) or class name (PascalCase),\n * constructing them on first use and caching them.\n *\n * A class arrives either from the consumer's barrel or registered by hand — the\n * latter for tests and for objects that arrive already built.\n */\nexport class LankaSingletonLocator extends ALankaLocator<unknown> {\n\tprivate readonly singletonIndexModule?: Record<string, unknown>;\n\n\tconstructor(config?: ILankaSingletonLocatorConfig) {\n\t\tsuper({\n\t\t\tfindClassByName: (className: string) => {\n\t\t\t\t// Order: the application's barrel, then an extra module if one was\n\t\t\t\t// given. Hand-registered classes are read by `ALankaLocator` itself,\n\t\t\t\t// ahead of this callback — they used to be read here, and the copy is\n\t\t\t\t// what let the gateway and scenario locators forget them entirely.\n\t\t\t\t//\n\t\t\t\t// Each source is checked ONCE, by export key. A fallback pass over\n\t\t\t\t// `Class.name` looks for something a built bundle no longer has:\n\t\t\t\t// minification loses class names exactly as it loses export names.\n\t\t\t\treturn (\n\t\t\t\t\tfindExportedClass<unknown>(SingletonsModule, className) ??\n\t\t\t\t\t(this.singletonIndexModule\n\t\t\t\t\t\t? findExportedClass<unknown>(this.singletonIndexModule, className)\n\t\t\t\t\t\t: undefined)\n\t\t\t\t);\n\t\t\t},\n\t\t\tcreateInstance: (Class) => {\n\t\t\t\treturn new Class();\n\t\t\t},\n\t\t\tnotFoundError: (className, propertyName) =>\n\t\t\t\t`Singleton \"${className}\" (accessed as \"${propertyName}\") not found. ` +\n\t\t\t\t`Make sure the class is exported from @lanka_di/Singletons.ts or registered via registerSingleton method.`,\n\t\t});\n\n\t\tthis.singletonIndexModule = config?.singletonIndexModule;\n\t}\n\n\t/**\n\t * Creates a NEW service object, bypassing the locator's cache.\n\t *\n\t * For scopes: they take the class from here and set the lifetime themselves.\n\t * The root cache is untouched — otherwise the first resolution inside a scope\n\t * would replace the application's root object.\n\t */\n\tpublic createScopedInstance(className: string, propertyName: string): unknown {\n\t\t// `classFor`, not `config.findClassByName`: a hand-registered class must\n\t\t// resolve inside a scope exactly as it does at the root.\n\t\tconst Class = this.classFor(className);\n\t\tif (!Class) {\n\t\t\tthrow new Error(this.config.notFoundError(className, propertyName));\n\t\t}\n\t\treturn this.config.createInstance(Class);\n\t}\n}\n"],"mappings":";;;;;;;;AASA,YAAY,sBAAsB;AAiB3B,IAAM,wBAAN,cAAoC,cAAuB;AAAA,EAChD;AAAA,EAEjB,YAAY,QAAuC;AAClD,UAAM;AAAA,MACL,iBAAiB,CAAC,cAAsB;AASvC,eACC,kBAA2B,kBAAkB,SAAS,MACrD,KAAK,uBACH,kBAA2B,KAAK,sBAAsB,SAAS,IAC/D;AAAA,MAEL;AAAA,MACA,gBAAgB,CAAC,UAAU;AAC1B,eAAO,IAAI,MAAM;AAAA,MAClB;AAAA,MACA,eAAe,CAAC,WAAW,iBAC1B,cAAc,SAAS,mBAAmB,YAAY;AAAA,IAExD,CAAC;AAED,SAAK,uBAAuB,QAAQ;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASO,qBAAqB,WAAmB,cAA+B;AAG7E,UAAM,QAAQ,KAAK,SAAS,SAAS;AACrC,QAAI,CAAC,OAAO;AACX,YAAM,IAAI,MAAM,KAAK,OAAO,cAAc,WAAW,YAAY,CAAC;AAAA,IACnE;AACA,WAAO,KAAK,OAAO,eAAe,KAAK;AAAA,EACxC;AACD;","names":[]}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import {
|
|
2
|
+
findExportedClass
|
|
3
|
+
} from "./chunk-JZJ6GXX3.js";
|
|
4
|
+
import {
|
|
5
|
+
ALankaLocator
|
|
6
|
+
} from "./chunk-N3275IPH.js";
|
|
7
|
+
|
|
8
|
+
// src/locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.ts
|
|
9
|
+
import * as SharedStoresModule from "@lanka_di/SharedStores";
|
|
10
|
+
var LankaSharedStoreLocator = class extends ALankaLocator {
|
|
11
|
+
sharedStoreIndexModule;
|
|
12
|
+
constructor(config) {
|
|
13
|
+
super({
|
|
14
|
+
findClassByName: (className) => {
|
|
15
|
+
return findExportedClass(
|
|
16
|
+
SharedStoresModule,
|
|
17
|
+
className
|
|
18
|
+
) ?? (this.sharedStoreIndexModule ? findExportedClass(
|
|
19
|
+
this.sharedStoreIndexModule,
|
|
20
|
+
className
|
|
21
|
+
) : void 0);
|
|
22
|
+
},
|
|
23
|
+
createInstance: (Class) => {
|
|
24
|
+
return new Class();
|
|
25
|
+
},
|
|
26
|
+
notFoundError: (className, propertyName) => `SharedStore "${className}" (accessed as "${propertyName}") not found. Make sure the class extends ALankaSharedStore and is exported from @lanka_di/SharedStores.ts or registered via registerSharedStore method.`
|
|
27
|
+
});
|
|
28
|
+
this.sharedStoreIndexModule = config?.sharedStoreIndexModule;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export {
|
|
33
|
+
LankaSharedStoreLocator
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=chunk-3R2NO47A.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator.ts"],"sourcesContent":["import { ALankaLocator } from \"../../_abstractions/lanka-locator/ALankaLocator\";\nimport { findExportedClass } from \"../../_internal/find-exported-class/findExportedClass\";\nimport { ALankaSharedStore } from \"../../../viewmodel/_abstractions/lanka-shared-store/ALankaSharedStore\";\nimport * as SharedStoresModule from \"@lanka_di/SharedStores\";\n\ntype TSharedStoreState = object;\n\n/**\n * LankaSharedStoreLocator configuration.\n */\nexport interface ILankaSharedStoreLocatorConfig {\n\t/** The module holding shared store classes — the consumer's barrel. */\n\tsharedStoreIndexModule?: Record<string, unknown>;\n}\n\n/**\n * Resolves shared stores by property name (camelCase) or class name\n * (PascalCase), constructing them on first use and caching them.\n */\nexport class LankaSharedStoreLocator extends ALankaLocator<ALankaSharedStore<TSharedStoreState>> {\n\tprivate readonly sharedStoreIndexModule?: Record<string, unknown>;\n\n\tconstructor(config?: ILankaSharedStoreLocatorConfig) {\n\t\tsuper({\n\t\t\tfindClassByName: (className: string) => {\n\t\t\t\t// Hand-registered classes are read by `ALankaLocator` itself, ahead of\n\t\t\t\t// this callback. This is only the barrel.\n\t\t\t\treturn (\n\t\t\t\t\tfindExportedClass<ALankaSharedStore<TSharedStoreState>>(\n\t\t\t\t\t\tSharedStoresModule,\n\t\t\t\t\t\tclassName,\n\t\t\t\t\t) ??\n\t\t\t\t\t(this.sharedStoreIndexModule\n\t\t\t\t\t\t? findExportedClass<ALankaSharedStore<TSharedStoreState>>(\n\t\t\t\t\t\t\t\tthis.sharedStoreIndexModule,\n\t\t\t\t\t\t\t\tclassName,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t: undefined)\n\t\t\t\t);\n\t\t\t},\n\t\t\tcreateInstance: (Class) => {\n\t\t\t\treturn new Class();\n\t\t\t},\n\t\t\tnotFoundError: (className, propertyName) =>\n\t\t\t\t`SharedStore \"${className}\" (accessed as \"${propertyName}\") not found. ` +\n\t\t\t\t`Make sure the class extends ALankaSharedStore and is exported from @lanka_di/SharedStores.ts ` +\n\t\t\t\t`or registered via registerSharedStore method.`,\n\t\t});\n\n\t\tthis.sharedStoreIndexModule = config?.sharedStoreIndexModule;\n\t}\n}\n"],"mappings":";;;;;;;;AAGA,YAAY,wBAAwB;AAgB7B,IAAM,0BAAN,cAAsC,cAAoD;AAAA,EAC/E;AAAA,EAEjB,YAAY,QAAyC;AACpD,UAAM;AAAA,MACL,iBAAiB,CAAC,cAAsB;AAGvC,eACC;AAAA,UACC;AAAA,UACA;AAAA,QACD,MACC,KAAK,yBACH;AAAA,UACA,KAAK;AAAA,UACL;AAAA,QACD,IACC;AAAA,MAEL;AAAA,MACA,gBAAgB,CAAC,UAAU;AAC1B,eAAO,IAAI,MAAM;AAAA,MAClB;AAAA,MACA,eAAe,CAAC,WAAW,iBAC1B,gBAAgB,SAAS,mBAAmB,YAAY;AAAA,IAG1D,CAAC;AAED,SAAK,yBAAyB,QAAQ;AAAA,EACvC;AACD;","names":[]}
|