lanka 1.2.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/{ALankaGateway-CkW1LbKE.d.ts → ALankaGateway-BrVPaZN5.d.ts} +1 -1
- package/dist/ILankaFieldError-D5931-vT.d.ts +34 -0
- package/dist/ILankaReadableVM-BoPzHEPV.d.ts +72 -0
- package/dist/{ILankaScenarioMetadata-GoWWNEQL.d.ts → ILankaScenarioMetadata-Dj4GCqmX.d.ts} +1 -1
- package/dist/{ILankaScenarioVM-DUsI-fSc.d.ts → ILankaScenarioVM-DpKFL3iE.d.ts} +5 -4
- package/dist/{LankaError-xpI-qj35.d.ts → LankaError-D6RWNyLM.d.ts} +18 -0
- package/dist/{LankaScenarioLocator-D86TIwiu.d.ts → LankaScenarioLocator-Dki2Es3O.d.ts} +5 -5
- package/dist/{LankaSharedStoreLocator-zS2kLu-S.d.ts → LankaSharedStoreLocator-jsz_gnUm.d.ts} +1 -1
- package/dist/_extend/index.d.ts +233 -9
- package/dist/_extend/index.js +137 -8
- package/dist/_extend/index.js.map +1 -1
- package/dist/_internal/index.d.ts +62 -9
- package/dist/_internal/index.js +34 -3
- package/dist/_internal/index.js.map +1 -1
- package/dist/{activeRuntime-B336NU5I.d.ts → activeRuntime-BO-qY0yY.d.ts} +51 -4
- package/dist/bootstrap/index.d.ts +11 -10
- package/dist/bootstrap/index.js +7 -8
- package/dist/cache/index.d.ts +99 -0
- package/dist/cache/index.js +1 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/{chunk-D27MREPB.js → chunk-7DQUF2QR.js} +2 -2
- package/dist/{chunk-UJEC7H6K.js → chunk-BHQ2SQ7P.js} +2 -2
- package/dist/chunk-CRIRTOLB.js +27 -0
- package/dist/chunk-CRIRTOLB.js.map +1 -0
- package/dist/chunk-EYDMBI5T.js +550 -0
- package/dist/chunk-EYDMBI5T.js.map +1 -0
- package/dist/{chunk-C2HP7CRD.js → chunk-FII3PW2G.js} +2 -2
- package/dist/{chunk-Q7QESSYF.js → chunk-G32H73QY.js} +10 -1
- package/dist/chunk-G32H73QY.js.map +1 -0
- package/dist/{chunk-DTO27QFR.js → chunk-H5TIUKRK.js} +2 -2
- package/dist/chunk-HVSQOMRE.js +69 -0
- package/dist/chunk-HVSQOMRE.js.map +1 -0
- package/dist/{chunk-73IVH3C6.js → chunk-O5EUTNR6.js} +3 -3
- package/dist/{chunk-RKYKK6MN.js → chunk-RUMUFHSL.js} +2 -2
- package/dist/{chunk-G3I7QIZR.js → chunk-SZVNPK24.js} +21 -14
- package/dist/chunk-SZVNPK24.js.map +1 -0
- package/dist/chunk-UDP6IXDS.js +17 -0
- package/dist/chunk-UDP6IXDS.js.map +1 -0
- package/dist/{chunk-5MAQVBI2.js → chunk-UMPSR4US.js} +3 -3
- package/dist/{chunk-BGVDPDX4.js → chunk-XGMXT4XZ.js} +20 -3
- package/dist/chunk-XGMXT4XZ.js.map +1 -0
- package/dist/config/index.js +3 -3
- package/dist/{createLanka-DI1CSy2Q.d.ts → createLanka-x4oSMs7P.d.ts} +2 -2
- package/dist/{createLankaScope-BiFxNQgl.d.ts → createLankaScope-DomNbEvb.d.ts} +1 -1
- package/dist/errors/index.d.ts +22 -3
- package/dist/errors/index.js +10 -5
- package/dist/errors/index.js.map +1 -1
- package/dist/gateway/index.d.ts +4 -3
- package/dist/gateway/index.js +9 -8
- package/dist/gateway/index.js.map +1 -1
- package/dist/index.d.ts +11 -10
- package/dist/index.js +9 -10
- package/dist/{lankaStandardValidator-CL-r-zEV.d.ts → lankaStandardValidator-BUFnysK0.d.ts} +10 -0
- package/dist/locator/index.d.ts +5 -4
- package/dist/locator/index.js +2 -2
- package/dist/logger/index.js +3 -3
- package/dist/mock/index.js +3 -3
- package/dist/scenario/index.d.ts +81 -6
- package/dist/scenario/index.js +6 -8
- package/dist/scenario/index.js.map +1 -1
- package/dist/storage/index.d.ts +120 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/index.js.map +1 -0
- package/dist/stream/index.d.ts +10 -9
- package/dist/validation/index.d.ts +7 -4
- package/dist/validation/index.js +5 -3
- package/dist/viewmodel/index.d.ts +188 -32
- package/dist/viewmodel/index.js +167 -171
- package/dist/viewmodel/index.js.map +1 -1
- package/package.json +11 -4
- package/skills/lanka-core/SKILL.md +70 -10
- package/skills/lanka-core/reference.md +417 -34
- package/skills/lanka-packages/SKILL.md +94 -22
- package/dist/chunk-BGVDPDX4.js.map +0 -1
- package/dist/chunk-G3I7QIZR.js.map +0 -1
- package/dist/chunk-GV5DUYST.js +0 -64
- package/dist/chunk-GV5DUYST.js.map +0 -1
- package/dist/chunk-O5ROO7QF.js +0 -315
- package/dist/chunk-O5ROO7QF.js.map +0 -1
- package/dist/chunk-Q7QESSYF.js.map +0 -1
- package/dist/chunk-UGXSGQPW.js +0 -180
- package/dist/chunk-UGXSGQPW.js.map +0 -1
- /package/dist/{chunk-D27MREPB.js.map → chunk-7DQUF2QR.js.map} +0 -0
- /package/dist/{chunk-UJEC7H6K.js.map → chunk-BHQ2SQ7P.js.map} +0 -0
- /package/dist/{chunk-C2HP7CRD.js.map → chunk-FII3PW2G.js.map} +0 -0
- /package/dist/{chunk-DTO27QFR.js.map → chunk-H5TIUKRK.js.map} +0 -0
- /package/dist/{chunk-73IVH3C6.js.map → chunk-O5EUTNR6.js.map} +0 -0
- /package/dist/{chunk-RKYKK6MN.js.map → chunk-RUMUFHSL.js.map} +0 -0
- /package/dist/{chunk-5MAQVBI2.js.map → chunk-UMPSR4US.js.map} +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The half every engine has: four operations over string values.
|
|
3
|
+
*
|
|
4
|
+
* The clauses each one keeps are on `ILankaStorageAdapter`, together with the
|
|
5
|
+
* ones about how the two halves agree.
|
|
6
|
+
*/
|
|
7
|
+
interface ILankaAsyncStorageAdapter {
|
|
8
|
+
setItem(key: string, value: string): Promise<void>;
|
|
9
|
+
getItem(key: string): Promise<string | null>;
|
|
10
|
+
removeItem(key: string): Promise<void>;
|
|
11
|
+
clear(): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Every key this store holds, when it can say.
|
|
14
|
+
*
|
|
15
|
+
* OPTIONAL, because a store need not be able to: a Cache Storage answers
|
|
16
|
+
* `Request` objects rather than the keys it was given, and a native bridge
|
|
17
|
+
* may answer nothing at all. A required member here would be a compile error
|
|
18
|
+
* in every adapter a consumer had already written.
|
|
19
|
+
*
|
|
20
|
+
* What it is for: `LankaCipher.clear()` removes what IT wrote instead of
|
|
21
|
+
* emptying the whole store — a store that cannot enumerate leaves it no
|
|
22
|
+
* choice but the latter.
|
|
23
|
+
*/
|
|
24
|
+
keys?(): Promise<string[]>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* The half an engine only has when it answers without awaiting.
|
|
29
|
+
*
|
|
30
|
+
* ALL FOUR OR NONE. A caller narrows on three of them and then uses the fourth —
|
|
31
|
+
* an adapter declaring two type-checks and lies at the one call site that has no
|
|
32
|
+
* `await` to fall back to.
|
|
33
|
+
*
|
|
34
|
+
* What it is for: a store read during the first render. `localStorage` and MMKV
|
|
35
|
+
* can answer there; a bridge and a keychain cannot, and a screen that awaits its
|
|
36
|
+
* persisted state renders once without it and again with it — the flash a user
|
|
37
|
+
* reads as a bug.
|
|
38
|
+
*/
|
|
39
|
+
interface ILankaSyncStorageAdapter {
|
|
40
|
+
setItemSync(key: string, value: string): void;
|
|
41
|
+
getItemSync(key: string): string | null;
|
|
42
|
+
removeItemSync(key: string): void;
|
|
43
|
+
clearSync(): void;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* What a key-value engine must do to stand behind `@lankajs/storage`.
|
|
48
|
+
*
|
|
49
|
+
* A PORT and nothing else: core declares the shape and ships no engine, because
|
|
50
|
+
* every platform already has one and they have nothing in common but these four
|
|
51
|
+
* operations. The asynchronous half is the whole port; the synchronous half is a
|
|
52
|
+
* capability an engine either has or does not, and a caller asks before using it
|
|
53
|
+
* rather than forcing the type.
|
|
54
|
+
*
|
|
55
|
+
* Implementations: `@lankajs/storage` carries three over what a browser already
|
|
56
|
+
* provides — `LankaWebStorageAdapter`, `LankaCacheStorageAdapter`,
|
|
57
|
+
* `LankaIndexedDbAdapter` — and `modules/storage-adapters/` holds one per engine
|
|
58
|
+
* an application installs. An application is free to write its own; the
|
|
59
|
+
* conformance suite in `@lankajs/tool-testing` is what says whether it is right.
|
|
60
|
+
*
|
|
61
|
+
* ## The clauses an implementation must keep
|
|
62
|
+
*
|
|
63
|
+
* Behaviour, not signatures, is where two honest adapters diverge, so each
|
|
64
|
+
* clause below is a promise and every one of them is an assertion in
|
|
65
|
+
* `lankaStorageAdapterConformance`. Run it; do not read a member's source.
|
|
66
|
+
*
|
|
67
|
+
* 1. Values are STRINGS, and what was written comes back byte for byte — `""`,
|
|
68
|
+
* `"null"` and `"{}"` included. An engine that serialises on the way in and
|
|
69
|
+
* parses on the way out answers a different type than it was given.
|
|
70
|
+
* 2. A missing key answers `null` — never `undefined`, never a throw.
|
|
71
|
+
* 3. `removeItem` of a key that is not there succeeds.
|
|
72
|
+
* 4. `setItem` over an existing key replaces it. Nothing merges.
|
|
73
|
+
* 5. `clear()` empties this adapter's NAMESPACE: afterwards every key it wrote
|
|
74
|
+
* answers `null`.
|
|
75
|
+
* 6. `keys()` is optional. Declared, it answers what this adapter wrote and
|
|
76
|
+
* nothing else — the namespace's keys, not the engine's.
|
|
77
|
+
* 7. An engine that can neither enumerate nor wipe keeps its own index of what
|
|
78
|
+
* it wrote, so clause 5 holds anyway. `expo-secure-store` is the reason this
|
|
79
|
+
* clause exists: it deletes a key it is handed and offers nothing else.
|
|
80
|
+
* 8. The synchronous half is all four methods or none.
|
|
81
|
+
* 9. The two halves see ONE store: a value written synchronously is visible to
|
|
82
|
+
* `getItem`, and the other way round.
|
|
83
|
+
* 10. A value the engine cannot hold FAILS. Truncation surfaces a week later as
|
|
84
|
+
* a token that decrypts to nonsense.
|
|
85
|
+
* 11. A key is used AS GIVEN. A key holding a space, a slash, a colon or a
|
|
86
|
+
* letter outside ASCII names its own value, and `keys()` answers it in the
|
|
87
|
+
* spelling it was written with. An engine that restricts which characters a
|
|
88
|
+
* key may hold — `expo-secure-store` allows only letters, digits, `.`, `-`
|
|
89
|
+
* and `_` — encodes on the way in and decodes on the way out, rather than
|
|
90
|
+
* handing the caller a key it never wrote.
|
|
91
|
+
*
|
|
92
|
+
* ## Why `clear()` is required where `ILankaReadCache.cancel` is optional
|
|
93
|
+
*
|
|
94
|
+
* The port next door made an operation optional when three of four libraries
|
|
95
|
+
* could not do it. This one does the opposite with the same kind of gap, and the
|
|
96
|
+
* difference is what absence COSTS. A cache that cannot cancel finishes a
|
|
97
|
+
* request nobody wants: wasteful, never wrong. A store that cannot clear ends a
|
|
98
|
+
* session with the tokens still in it — which is not waste, it is the failure.
|
|
99
|
+
*
|
|
100
|
+
* So the cost lands on the one adapter with the problem (clause 7) instead of on
|
|
101
|
+
* every caller having to ask whether sign-out worked.
|
|
102
|
+
*
|
|
103
|
+
* ## What this port does not decide
|
|
104
|
+
*
|
|
105
|
+
* Three promises cannot be observed from inside an implementation and belong to
|
|
106
|
+
* whoever wires one:
|
|
107
|
+
*
|
|
108
|
+
* - **The adapter takes its engine, and never constructs it.** `new
|
|
109
|
+
* LankaWebStorageAdapter(localStorage)` is the existing shape and the reason
|
|
110
|
+
* an engine that only exists on a device is testable in node at all.
|
|
111
|
+
* - **An engine that encrypts itself is not encrypted twice.** MMKV with a key
|
|
112
|
+
* and a keychain-backed store are already ciphertext at rest;
|
|
113
|
+
* `LankaEncryptedStorage` over one of them is a second lock on one door.
|
|
114
|
+
* - **On a server the namespace is per REQUEST**, never a module-level
|
|
115
|
+
* singleton — one process serves every reader.
|
|
116
|
+
*/
|
|
117
|
+
interface ILankaStorageAdapter extends ILankaAsyncStorageAdapter, Partial<ILankaSyncStorageAdapter> {
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export type { ILankaAsyncStorageAdapter, ILankaStorageAdapter, ILankaSyncStorageAdapter };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/stream/index.d.ts
CHANGED
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { c as ILankaPlugin } from '../createLanka-
|
|
2
|
-
import '../createLankaScope-
|
|
3
|
-
import '../LankaSharedStoreLocator-
|
|
1
|
+
import { c as ILankaPlugin } from '../createLanka-x4oSMs7P.js';
|
|
2
|
+
import '../createLankaScope-DomNbEvb.js';
|
|
3
|
+
import '../LankaSharedStoreLocator-jsz_gnUm.js';
|
|
4
4
|
import '../ALankaSharedStore-B7uepuuk.js';
|
|
5
5
|
import 'zustand/vanilla';
|
|
6
|
-
import '../activeRuntime-
|
|
7
|
-
import '../ILankaScenarioVM-
|
|
8
|
-
import '../LankaScenarioLocator-
|
|
9
|
-
import '../ILankaScenarioMetadata-
|
|
10
|
-
import '../ALankaGateway-
|
|
11
|
-
import '../lankaStandardValidator-
|
|
6
|
+
import '../activeRuntime-BO-qY0yY.js';
|
|
7
|
+
import '../ILankaScenarioVM-DpKFL3iE.js';
|
|
8
|
+
import '../LankaScenarioLocator-Dki2Es3O.js';
|
|
9
|
+
import '../ILankaScenarioMetadata-Dj4GCqmX.js';
|
|
10
|
+
import '../ALankaGateway-BrVPaZN5.js';
|
|
11
|
+
import '../lankaStandardValidator-BUFnysK0.js';
|
|
12
12
|
import '@standard-schema/spec';
|
|
13
|
+
import '../ILankaFieldError-D5931-vT.js';
|
|
13
14
|
import '../ILankaRuntimeConfig-Vl436GWK.js';
|
|
14
15
|
import '../lankaHttpInFlight-Bk1eIuSx.js';
|
|
15
16
|
import '../lankaRequestMiddleware-DAC5kCb7.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
export { I as ILankaValidator, T as TLankaSchema, a as TLankaValidationResult, l as lankaStandardValidator } from '../lankaStandardValidator-
|
|
2
|
-
import { L as LankaError } from '../LankaError-
|
|
1
|
+
export { I as ILankaValidator, T as TLankaSchema, a as TLankaValidationResult, l as lankaStandardValidator } from '../lankaStandardValidator-BUFnysK0.js';
|
|
2
|
+
import { L as LankaError } from '../LankaError-D6RWNyLM.js';
|
|
3
|
+
import { I as ILankaFieldError } from '../ILankaFieldError-D5931-vT.js';
|
|
3
4
|
import '@standard-schema/spec';
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -12,10 +13,12 @@ import '@standard-schema/spec';
|
|
|
12
13
|
* that told a contract drift from a network failure by `kind` never saw it.
|
|
13
14
|
*
|
|
14
15
|
* `name` stays `LankaValidationError` and `status` stays 422: both are what a
|
|
15
|
-
* consumer's existing `catch` reads, and the message list is `errors`.
|
|
16
|
+
* consumer's existing `catch` reads, and the message list is `errors`. The same
|
|
17
|
+
* issues arrive a second time as `fields`, with the path in segments, for the
|
|
18
|
+
* consumer that has an input to show each one at.
|
|
16
19
|
*/
|
|
17
20
|
declare class LankaValidationError extends LankaError {
|
|
18
|
-
constructor(message: string, errors?: string[]);
|
|
21
|
+
constructor(message: string, errors?: string[], fields?: readonly ILankaFieldError[]);
|
|
19
22
|
/** Always present here, unlike the base's optional list. */
|
|
20
23
|
get errors(): string[];
|
|
21
24
|
}
|
package/dist/validation/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
|
-
LankaValidationError,
|
|
3
2
|
lankaStandardValidator
|
|
4
|
-
} from "../chunk-
|
|
5
|
-
import
|
|
3
|
+
} from "../chunk-HVSQOMRE.js";
|
|
4
|
+
import {
|
|
5
|
+
LankaValidationError
|
|
6
|
+
} from "../chunk-CRIRTOLB.js";
|
|
7
|
+
import "../chunk-G32H73QY.js";
|
|
6
8
|
export {
|
|
7
9
|
LankaValidationError,
|
|
8
10
|
lankaStandardValidator
|
|
@@ -1,8 +1,27 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { a as ILankaScenario, T as TLankaReplayRequest, I as ILankaScenarioVM } from '../ILankaScenarioVM-
|
|
1
|
+
import { I as ILankaReadableVM } from '../ILankaReadableVM-BoPzHEPV.js';
|
|
2
|
+
import { a as ILankaScenario, T as TLankaReplayRequest, I as ILankaScenarioVM } from '../ILankaScenarioVM-DpKFL3iE.js';
|
|
3
|
+
import { StoreApi, StateCreator } from 'zustand';
|
|
3
4
|
import { A as ALankaSharedStore } from '../ALankaSharedStore-B7uepuuk.js';
|
|
4
5
|
import { StoreApi as StoreApi$1 } from 'zustand/vanilla';
|
|
5
6
|
|
|
7
|
+
/**
|
|
8
|
+
* A ViewModel that can also be written to from outside.
|
|
9
|
+
*
|
|
10
|
+
* The reading half plus the two members a host needs: the state a screen starts
|
|
11
|
+
* from, and a way to make server data that first state — which is what
|
|
12
|
+
* `hydrateLankaVM` does and the only reason writing is published at all.
|
|
13
|
+
*
|
|
14
|
+
* A view binding takes `ILankaReadableVM` instead. The narrower type is not
|
|
15
|
+
* politeness: a binding holding this one could write during a render, which is
|
|
16
|
+
* the defect no framework's scheduler survives.
|
|
17
|
+
*/
|
|
18
|
+
interface ILankaVM<TState extends object> extends ILankaReadableVM<TState> {
|
|
19
|
+
/** The state the ViewModel was built with, before anything wrote to it. */
|
|
20
|
+
getInitialState(): TState;
|
|
21
|
+
/** Writes state. Partial by default; `replace` swaps the whole object. */
|
|
22
|
+
setState(partial: TState | Partial<TState> | ((state: TState) => TState | Partial<TState>), replace?: false): void;
|
|
23
|
+
}
|
|
24
|
+
|
|
6
25
|
interface ILankaVMContext<TState, TGateways extends object, TServices extends object> {
|
|
7
26
|
set: StoreApi<TState>["setState"];
|
|
8
27
|
get: () => TState;
|
|
@@ -122,10 +141,10 @@ interface ILankaVMConfig<State extends object, Actions extends object, TGateways
|
|
|
122
141
|
* through a getter — and warns with the ViewModel and key names. "Remember to
|
|
123
142
|
* set the flag" is not a mechanism.
|
|
124
143
|
*/
|
|
125
|
-
declare function createLankaVM<State extends object, Actions extends object>(config: ILankaVMConfig<State, Actions, Record<string, never>, Record<string, never>>):
|
|
126
|
-
declare function createLankaVM<State extends object, Actions extends object, Services extends object>(config: ILankaVMConfig<State, Actions, Record<string, never>, Services>):
|
|
127
|
-
declare function createLankaVM<State extends object, Actions extends object, TGateways extends object>(config: ILankaVMConfig<State, Actions, TGateways, Record<string, never>>):
|
|
128
|
-
declare function createLankaVM<State extends object, Actions extends object, TGateways extends object, Services extends object>(config: ILankaVMConfig<State, Actions, TGateways, Services>):
|
|
144
|
+
declare function createLankaVM<State extends object, Actions extends object>(config: ILankaVMConfig<State, Actions, Record<string, never>, Record<string, never>>): ILankaVM<State & Actions & ILankaScenarioVM>;
|
|
145
|
+
declare function createLankaVM<State extends object, Actions extends object, Services extends object>(config: ILankaVMConfig<State, Actions, Record<string, never>, Services>): ILankaVM<State & Actions & ILankaScenarioVM>;
|
|
146
|
+
declare function createLankaVM<State extends object, Actions extends object, TGateways extends object>(config: ILankaVMConfig<State, Actions, TGateways, Record<string, never>>): ILankaVM<State & Actions & ILankaScenarioVM>;
|
|
147
|
+
declare function createLankaVM<State extends object, Actions extends object, TGateways extends object, Services extends object>(config: ILankaVMConfig<State, Actions, TGateways, Services>): ILankaVM<State & Actions & ILankaScenarioVM>;
|
|
129
148
|
|
|
130
149
|
declare function createLazyLankaVM<State extends object, Actions extends object>(config: ILankaVMConfig<State, Actions, Record<string, never>, Record<string, never>>): TLazyLankaVM<ReturnType<typeof createLankaVM<State, Actions, Record<string, never>, Record<string, never>>>, State & Actions & ILankaScenarioVM>;
|
|
131
150
|
declare function createLazyLankaVM<State extends object, Actions extends object, Services extends object>(config: ILankaVMConfig<State, Actions, Record<string, never>, Services>): TLazyLankaVM<ReturnType<typeof createLankaVM<State, Actions, Record<string, never>, Services>>, State & Actions & ILankaScenarioVM>;
|
|
@@ -166,14 +185,18 @@ type TLankaStatelessVMConfig$1<Actions extends object, TGateways extends object
|
|
|
166
185
|
onInit?: (ctx: ILankaStatelessVMContext<Actions & ILankaScenarioVM, TGateways, Services>) => void;
|
|
167
186
|
onReset?: (ctx: ILankaStatelessVMContext<Actions & ILankaScenarioVM, TGateways, Services>) => void;
|
|
168
187
|
};
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
188
|
+
/**
|
|
189
|
+
* @deprecated since 2.0.0 - use ILankaReadableVM, which is what a stateless
|
|
190
|
+
* ViewModel now IS: `createStatelessLankaVM` answers a readable ViewModel rather
|
|
191
|
+
* than a React hook, so the word "Hook" in this name no longer describes
|
|
192
|
+
* anything. The alias is kept because a published name is never removed, and it
|
|
193
|
+
* resolves to exactly the type the factory returns.
|
|
194
|
+
*/
|
|
195
|
+
type TLankaStatelessVMHook<Actions extends object> = ILankaReadableVM<Actions & ILankaScenarioVM>;
|
|
196
|
+
declare function createStatelessLankaVM<Actions extends object>(config: TLankaStatelessVMConfig$1<Actions, Record<string, never>, Record<string, never>>): ILankaReadableVM<Actions & ILankaScenarioVM>;
|
|
197
|
+
declare function createStatelessLankaVM<Actions extends object, Services extends object>(config: TLankaStatelessVMConfig$1<Actions, Record<string, never>, Services>): ILankaReadableVM<Actions & ILankaScenarioVM>;
|
|
198
|
+
declare function createStatelessLankaVM<Actions extends object, TGateways extends object>(config: TLankaStatelessVMConfig$1<Actions, TGateways, Record<string, never>>): ILankaReadableVM<Actions & ILankaScenarioVM>;
|
|
199
|
+
declare function createStatelessLankaVM<Actions extends object, TGateways extends object, Services extends object>(config: TLankaStatelessVMConfig$1<Actions, TGateways, Services>): ILankaReadableVM<Actions & ILankaScenarioVM>;
|
|
177
200
|
|
|
178
201
|
type TLankaStatelessVMConfig<Actions extends object, TGateways extends object = Record<string, never>, Services extends object = Record<string, never>> = Omit<ILankaVMConfig<object, Actions, TGateways, Services>, "states"> & {
|
|
179
202
|
states?: never;
|
|
@@ -197,11 +220,25 @@ interface ILankaSharedStoreVMContext<TStoreState extends object, TFullState exte
|
|
|
197
220
|
trigger: <T>(scenario: ILankaScenario<T>, data?: T) => void;
|
|
198
221
|
}
|
|
199
222
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
223
|
+
/**
|
|
224
|
+
* A ViewModel over a store somebody else owns.
|
|
225
|
+
*
|
|
226
|
+
* The port, plus the one member the shape genuinely adds: the SLICE, without the
|
|
227
|
+
* actions and scenario members composed onto it. A screen reads `getState`; code
|
|
228
|
+
* that has to reason about what is actually persisted — a hydration, a devtools
|
|
229
|
+
* panel, a second ViewModel over the same store — reads `getStoreState`.
|
|
230
|
+
*/
|
|
231
|
+
interface ILankaSharedStoreVM<TStoreState extends object, TActions extends object> extends ILankaReadableVM<TStoreState & TActions & ILankaScenarioVM> {
|
|
232
|
+
/** The shared store's own state, without this ViewModel's actions on top. */
|
|
203
233
|
getStoreState: () => TStoreState;
|
|
204
|
-
}
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* @deprecated since 2.0.0 - use ILankaSharedStoreVM, which is the same type
|
|
237
|
+
* under a name that is still true: `createSharedStoreLankaVM` answers a readable
|
|
238
|
+
* ViewModel rather than a React hook. The alias is kept because a published name
|
|
239
|
+
* is never removed.
|
|
240
|
+
*/
|
|
241
|
+
type TLankaSharedStoreVMHook<TStoreState extends object, TActions extends object> = ILankaSharedStoreVM<TStoreState, TActions>;
|
|
205
242
|
interface ILankaSharedStoreScenarioBinding<TData, TStoreState extends object, TActions extends object, TStore extends ALankaSharedStore<TStoreState>, TGateways extends object, TServices extends object> {
|
|
206
243
|
scenario: ILankaScenario<TData>;
|
|
207
244
|
/**
|
|
@@ -235,10 +272,10 @@ interface ILankaSharedStoreVMConfig<TStoreState extends object, TActions extends
|
|
|
235
272
|
* Factory for ViewModels backed by an external shared store instance.
|
|
236
273
|
* Multiple ViewModels can be created on top of the same store instance.
|
|
237
274
|
*/
|
|
238
|
-
declare function createSharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, Record<string, never>, Record<string, never>>):
|
|
239
|
-
declare function createSharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, Services extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, Record<string, never>, Services>):
|
|
240
|
-
declare function createSharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Record<string, never>>):
|
|
241
|
-
declare function createSharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object, Services extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Services>):
|
|
275
|
+
declare function createSharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, Record<string, never>, Record<string, never>>): ILankaSharedStoreVM<StoreState, Actions>;
|
|
276
|
+
declare function createSharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, Services extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, Record<string, never>, Services>): ILankaSharedStoreVM<StoreState, Actions>;
|
|
277
|
+
declare function createSharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Record<string, never>>): ILankaSharedStoreVM<StoreState, Actions>;
|
|
278
|
+
declare function createSharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object, Services extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Services>): ILankaSharedStoreVM<StoreState, Actions>;
|
|
242
279
|
|
|
243
280
|
/**
|
|
244
281
|
* What a lazy shared-store ViewModel is, in the type as well as at runtime.
|
|
@@ -257,6 +294,19 @@ declare function createLazySharedStoreLankaVM<StoreState extends object, Actions
|
|
|
257
294
|
declare function createLazySharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Record<string, never>>): TLazySharedStoreReturn<StoreState, Actions, Store, TGateways, Record<string, never>>;
|
|
258
295
|
declare function createLazySharedStoreLankaVM<StoreState extends object, Actions extends object, Store extends ALankaSharedStore<StoreState>, TGateways extends object, Services extends object>(config: ILankaSharedStoreVMConfig<StoreState, Actions, Store, TGateways, Services>): TLazySharedStoreReturn<StoreState, Actions, Store, TGateways, Services>;
|
|
259
296
|
|
|
297
|
+
/**
|
|
298
|
+
* The lifecycle moments a ViewModel took, as the scenario binder receives them.
|
|
299
|
+
*
|
|
300
|
+
* A hook is present only when the ViewModel DECLARED it — overrode the method,
|
|
301
|
+
* or passed it in config. Bootstrap registers a ViewModel for the sake of these
|
|
302
|
+
* calls, so "declared" is what decides registration; a default no-op must not
|
|
303
|
+
* count, or every ViewModel would sit in the scenario registry for nothing.
|
|
304
|
+
*/
|
|
305
|
+
interface ILankaVMLifecycleHooks {
|
|
306
|
+
onInit?: () => void;
|
|
307
|
+
onReset?: () => void;
|
|
308
|
+
}
|
|
309
|
+
|
|
260
310
|
/**
|
|
261
311
|
* What every ViewModel is given, and the two moments it is told about.
|
|
262
312
|
*
|
|
@@ -281,10 +331,36 @@ declare abstract class ALankaVMEnvironment<TGateways extends object = Record<str
|
|
|
281
331
|
protected createGateways(): TGateways;
|
|
282
332
|
/** Non-gateway collaborators, built once per ViewModel. */
|
|
283
333
|
protected createServices(): Services;
|
|
284
|
-
/**
|
|
334
|
+
/**
|
|
335
|
+
* Runs once the scenarios are bound: inside `startLanka()` for a ViewModel built
|
|
336
|
+
* at module level, inside `build()` for one built after bootstrap — in both
|
|
337
|
+
* cases before any screen has read the hook the build returns.
|
|
338
|
+
*/
|
|
285
339
|
protected onInit(): void;
|
|
286
|
-
/**
|
|
340
|
+
/**
|
|
341
|
+
* Runs when the ViewModel is released — the framework instance disposed, or a
|
|
342
|
+
* lazy ViewModel's `dispose()` — after its scenario subscriptions are gone.
|
|
343
|
+
*/
|
|
287
344
|
protected onReset(): void;
|
|
345
|
+
/**
|
|
346
|
+
* The two moments above as the scenario binder receives them: present only
|
|
347
|
+
* where this ViewModel took them.
|
|
348
|
+
*
|
|
349
|
+
* Framework plumbing, not an extension point — a ViewModel overrides `onInit`
|
|
350
|
+
* and `onReset`, never this. Protected because the three bases call it, and
|
|
351
|
+
* named after `toStyleContext` for the same reason: a derived view of the
|
|
352
|
+
* protected surface, assembled by the framework.
|
|
353
|
+
*
|
|
354
|
+
* Why "took them" decides anything: `onInit` runs inside `initializeScenario`,
|
|
355
|
+
* which bootstrap alone calls, on the ViewModels registered with it.
|
|
356
|
+
* Registration used to follow scenario bindings only, so a ViewModel that
|
|
357
|
+
* overrode `onInit` and bound nothing was never initialised — silently. Now a
|
|
358
|
+
* declared hook registers the ViewModel too, and a default no-op must not
|
|
359
|
+
* count, or every ViewModel would sit in the scenario registry for nothing.
|
|
360
|
+
* The functional bridges declare theirs as own properties over these methods,
|
|
361
|
+
* which is what this comparison sees.
|
|
362
|
+
*/
|
|
363
|
+
protected toLifecycleHooks(): ILankaVMLifecycleHooks;
|
|
288
364
|
}
|
|
289
365
|
|
|
290
366
|
/**
|
|
@@ -300,7 +376,9 @@ declare abstract class ALankaVMEnvironment<TGateways extends object = Record<str
|
|
|
300
376
|
* value or a thunk, the class supplies by overriding a method of the same name —
|
|
301
377
|
* `states`, `scenarioHandlers`, `enhancers`, `onInit`, `onReset` — with the two
|
|
302
378
|
* dependency suppliers named `createGateways` and `createServices`, because
|
|
303
|
-
* `gateways` and `services` already name what they answer.
|
|
379
|
+
* `gateways` and `services` already name what they answer. `toLifecycleHooks`
|
|
380
|
+
* is protected too and is not one of these: it is how the framework reads the
|
|
381
|
+
* two hooks, and a ViewModel overrides the hooks, never it.
|
|
304
382
|
*
|
|
305
383
|
* ```ts
|
|
306
384
|
* class TodoVM extends ALankaVM<ITodoState, ITodoActions, ITodoGateways> {
|
|
@@ -345,7 +423,7 @@ declare abstract class ALankaVM<State extends object, Actions extends object, TG
|
|
|
345
423
|
*/
|
|
346
424
|
protected readonly enableAccessTrackingOptimization: boolean;
|
|
347
425
|
/** Writes state. Available from `createActions` onwards, never before. */
|
|
348
|
-
protected set: StoreApi<State & Actions & ILankaScenarioVM>["setState"];
|
|
426
|
+
protected set: StoreApi$1<State & Actions & ILankaScenarioVM>["setState"];
|
|
349
427
|
/** Reads state. The read a tracked hook cannot see — hence the switch above. */
|
|
350
428
|
protected get: () => State & Actions & ILankaScenarioVM;
|
|
351
429
|
/** Fires a scenario, which every ViewModel bound to it then hears. */
|
|
@@ -372,8 +450,16 @@ declare abstract class ALankaVM<State extends object, Actions extends object, TG
|
|
|
372
450
|
* the wrong half. Canon: `skills/parity/SKILL.md` section 3a.
|
|
373
451
|
*/
|
|
374
452
|
protected toStyleContext(): ILankaVMContext<State & Actions & ILankaScenarioVM, TGateways, Services>;
|
|
375
|
-
/**
|
|
376
|
-
|
|
453
|
+
/**
|
|
454
|
+
* Builds the ViewModel a screen reads. One store per call.
|
|
455
|
+
*
|
|
456
|
+
* What comes back is a STORE, not a hook: `getState`, `subscribe`, `setState`,
|
|
457
|
+
* plus the name and the tracking flag. A screen reaches it through its
|
|
458
|
+
* framework's binding — `useLankaVM(todoVM)` from `@lankajs/react`,
|
|
459
|
+
* `@lankajs/vue` and the rest of the shelf — and a program with no framework
|
|
460
|
+
* at all reads `getState()` and `subscribe()` directly.
|
|
461
|
+
*/
|
|
462
|
+
build(): ILankaVM<State & Actions & ILankaScenarioVM>;
|
|
377
463
|
}
|
|
378
464
|
|
|
379
465
|
/**
|
|
@@ -389,6 +475,9 @@ declare abstract class ALankaVM<State extends object, Actions extends object, TG
|
|
|
389
475
|
* or a thunk, the class supplies by overriding a method of the same name, with
|
|
390
476
|
* the two dependency suppliers named `createGateways` and `createServices`
|
|
391
477
|
* because `gateways` and `services` already name what they answer.
|
|
478
|
+
* `toLifecycleHooks` is protected too and is not one of these: it is how the
|
|
479
|
+
* framework reads `onInit` and `onReset`, and a ViewModel overrides those,
|
|
480
|
+
* never it.
|
|
392
481
|
*
|
|
393
482
|
* ```ts
|
|
394
483
|
* class SessionVM extends ALankaStatelessVM<ISessionActions, ISessionGateways> {
|
|
@@ -438,8 +527,13 @@ declare abstract class ALankaStatelessVM<Actions extends object, TGateways exten
|
|
|
438
527
|
* read. Canon: `skills/parity/SKILL.md` section 3a.
|
|
439
528
|
*/
|
|
440
529
|
protected toStyleContext(): ILankaStatelessVMContext<Actions & ILankaScenarioVM, TGateways, Services>;
|
|
441
|
-
/**
|
|
442
|
-
|
|
530
|
+
/**
|
|
531
|
+
* Builds the ViewModel a screen reads. One per call.
|
|
532
|
+
*
|
|
533
|
+
* What comes back answers the read half of the port and nothing more: there
|
|
534
|
+
* is no store to write to from outside, because there is no state to write.
|
|
535
|
+
*/
|
|
536
|
+
build(): ILankaReadableVM<Actions & ILankaScenarioVM>;
|
|
443
537
|
}
|
|
444
538
|
|
|
445
539
|
/**
|
|
@@ -469,7 +563,9 @@ declare abstract class ALankaStatelessVM<Actions extends object, TGateways exten
|
|
|
469
563
|
* implementation: the store, the tracked hook and the two memoised state
|
|
470
564
|
* references are the factory's, and duplicating them here would be the second
|
|
471
565
|
* implementation the parity canon exists to prevent. What it gives a class-style
|
|
472
|
-
* consumer is the same protected surface under the same names
|
|
566
|
+
* consumer is the same protected surface under the same names — plus
|
|
567
|
+
* `toLifecycleHooks`, the framework's reading of `onInit`/`onReset`, which is
|
|
568
|
+
* not an extension point.
|
|
473
569
|
*
|
|
474
570
|
* Canon: `skills/parity/SKILL.md`.
|
|
475
571
|
*/
|
|
@@ -513,8 +609,68 @@ declare abstract class ALankaSharedStoreVM<StoreState extends object, Actions ex
|
|
|
513
609
|
*/
|
|
514
610
|
declare const createLankaSharedStore: <TState extends object>(createInitialState: () => TState) => ALankaSharedStore<TState>;
|
|
515
611
|
|
|
612
|
+
/**
|
|
613
|
+
* Keeps a selection's IDENTITY while nothing in it moved.
|
|
614
|
+
*
|
|
615
|
+
* ```ts
|
|
616
|
+
* const hold = createLankaShallowHold<{ title: string; status: string }>();
|
|
617
|
+
*
|
|
618
|
+
* // in any binding on the shelf
|
|
619
|
+
* const view = useLankaVM(missionVM, (state) => hold({
|
|
620
|
+
* title: state.title,
|
|
621
|
+
* status: state.status,
|
|
622
|
+
* }));
|
|
623
|
+
* ```
|
|
624
|
+
*
|
|
625
|
+
* ## What it is for
|
|
626
|
+
*
|
|
627
|
+
* A selector narrows what a reader depends on, and a selector that BUILDS its
|
|
628
|
+
* answer — `(state) => ({ a: state.a })`, `(state) => rows.filter(…)`, the shape
|
|
629
|
+
* a consumer reaches for first — cannot say so. Every binding compares the new
|
|
630
|
+
* selection with the last one by identity, and a fresh object is never identical
|
|
631
|
+
* to anything, so the reader wakes for every change in the ViewModel including
|
|
632
|
+
* the keys the selector exists to ignore. This is the comparison that makes the
|
|
633
|
+
* selection mean something.
|
|
634
|
+
*
|
|
635
|
+
* A selector answering a PRIMITIVE never needed it, which is what makes the cost
|
|
636
|
+
* quiet: the shape that is free and the shape that repaints on everything look
|
|
637
|
+
* the same on the page.
|
|
638
|
+
*
|
|
639
|
+
* ## Why it is in core and not in a binding
|
|
640
|
+
*
|
|
641
|
+
* It was `useLankaShallow` in `@lankajs/react` and nowhere else, and that made it
|
|
642
|
+
* a CAPABILITY one member of the shelf had and four did not. An idiom is a
|
|
643
|
+
* spelling; this changes which notifications reach a reader, and it encodes a
|
|
644
|
+
* policy — one level deep, own keys, `Object.is` — that five packages inventing
|
|
645
|
+
* separately would answer five ways. `skills/parity/SKILL.md` 3c: a binding that
|
|
646
|
+
* needs more than the port gives it has found something that belongs in core, for
|
|
647
|
+
* everybody.
|
|
648
|
+
*
|
|
649
|
+
* `useLankaShallow` keeps working and is now React's spelling over this. It has
|
|
650
|
+
* to exist there and cannot exist here: a React component re-runs the hook on
|
|
651
|
+
* every render, so the holding has to survive a render while the SELECTOR stays
|
|
652
|
+
* the current one — which is a `useRef`, and a ref is not something core can
|
|
653
|
+
* have.
|
|
654
|
+
*
|
|
655
|
+
* ## Why it holds a value and not a selector
|
|
656
|
+
*
|
|
657
|
+
* `createLankaShallowSelector(selector)` was the other shape and it cannot serve
|
|
658
|
+
* React: the wrapper would be rebuilt whenever the selector's identity moved, and
|
|
659
|
+
* an inline arrow is a new function every render, so the holding would reset
|
|
660
|
+
* before it ever held anything. Taking the VALUE puts the state in the only place
|
|
661
|
+
* every framework can keep it, and the extra line at a call site is the price of
|
|
662
|
+
* one name that works in all five rather than two that each work in some.
|
|
663
|
+
*
|
|
664
|
+
* ## One level, and it says so by failing
|
|
665
|
+
*
|
|
666
|
+
* Deeper would mean walking a state of unknown size on every read, which is the
|
|
667
|
+
* cost a reader took a selector to avoid. A selection with a nested object wants
|
|
668
|
+
* a selector that picks the leaves.
|
|
669
|
+
*/
|
|
670
|
+
declare const createLankaShallowHold: <TValue>() => ((next: TValue) => TValue);
|
|
671
|
+
|
|
516
672
|
type TLankaVMStateCreator<TFullState> = StateCreator<TFullState, TLankaAnyMutators, TLankaAnyMutators>;
|
|
517
673
|
|
|
518
674
|
type TLankaSharedStoreSetState<TState extends object> = (partial: TState | Partial<TState> | ((state: TState) => TState | Partial<TState>), replace?: boolean) => void;
|
|
519
675
|
|
|
520
|
-
export { ALankaSharedStore, ALankaSharedStoreVM, ALankaStatelessVM, ALankaVM, type ILankaScenarioBinding, type ILankaSharedStoreScenarioBinding, type ILankaSharedStoreVMConfig, type ILankaSharedStoreVMContext, type ILankaStatelessScenarioBinding, type ILankaStatelessVMContext, type ILankaVMConfig, type ILankaVMContext, type TLankaAnyMutators, type TLankaSetState, type TLankaSharedStoreSetState, type TLankaSharedStoreVMHook, type TLankaStatelessVMConfig$1 as TLankaStatelessVMConfig, type TLankaStatelessVMHook, type TLankaVMEnhancer, type TLankaVMStateCreator, type TLazyLankaVM, type TUnknownLankaScenarioBinding, createLankaSharedStore, createLankaVM, createLazyLankaVM, createLazySharedStoreLankaVM, createLazyStatelessLankaVM, createSharedStoreLankaVM, createStatelessLankaVM };
|
|
676
|
+
export { ALankaSharedStore, ALankaSharedStoreVM, ALankaStatelessVM, ALankaVM, ILankaReadableVM, type ILankaScenarioBinding, type ILankaSharedStoreScenarioBinding, type ILankaSharedStoreVM, type ILankaSharedStoreVMConfig, type ILankaSharedStoreVMContext, type ILankaStatelessScenarioBinding, type ILankaStatelessVMContext, type ILankaVM, type ILankaVMConfig, type ILankaVMContext, type TLankaAnyMutators, type TLankaSetState, type TLankaSharedStoreSetState, type TLankaSharedStoreVMHook, type TLankaStatelessVMConfig$1 as TLankaStatelessVMConfig, type TLankaStatelessVMHook, type TLankaVMEnhancer, type TLankaVMStateCreator, type TLazyLankaVM, type TUnknownLankaScenarioBinding, createLankaShallowHold, createLankaSharedStore, createLankaVM, createLazyLankaVM, createLazySharedStoreLankaVM, createLazyStatelessLankaVM, createSharedStoreLankaVM, createStatelessLankaVM };
|