lanka 1.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.
Files changed (97) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +242 -0
  3. package/dist/ALankaGateway-ExlRGT3D.d.ts +122 -0
  4. package/dist/ALankaSharedStore-B7uepuuk.d.ts +29 -0
  5. package/dist/ILankaApiError-zI_2bNs0.d.ts +16 -0
  6. package/dist/ILankaRuntimeConfig-Vl436GWK.d.ts +62 -0
  7. package/dist/ILankaScenarioMetadata-Bu-yggTZ.d.ts +14 -0
  8. package/dist/ILankaScenarioVM-DuCyPoyT.d.ts +260 -0
  9. package/dist/LankaError-B1HtuIkw.d.ts +86 -0
  10. package/dist/LankaScenarioLocator-BGQHwf3n.d.ts +144 -0
  11. package/dist/LankaSharedStoreLocator-MvCpav5F.d.ts +126 -0
  12. package/dist/TLankaErrorHandler-Yfqtdh1M.d.ts +3 -0
  13. package/dist/_extend/index.d.ts +34 -0
  14. package/dist/_extend/index.js +36 -0
  15. package/dist/_extend/index.js.map +1 -0
  16. package/dist/_internal/index.d.ts +43 -0
  17. package/dist/_internal/index.js +34 -0
  18. package/dist/_internal/index.js.map +1 -0
  19. package/dist/activeRuntime-FcsSJvUg.d.ts +84 -0
  20. package/dist/bootstrap/index.d.ts +242 -0
  21. package/dist/bootstrap/index.js +22 -0
  22. package/dist/bootstrap/index.js.map +1 -0
  23. package/dist/chunk-73IVH3C6.js +52 -0
  24. package/dist/chunk-73IVH3C6.js.map +1 -0
  25. package/dist/chunk-BGVDPDX4.js +29 -0
  26. package/dist/chunk-BGVDPDX4.js.map +1 -0
  27. package/dist/chunk-C2HP7CRD.js +224 -0
  28. package/dist/chunk-C2HP7CRD.js.map +1 -0
  29. package/dist/chunk-D27MREPB.js +13 -0
  30. package/dist/chunk-D27MREPB.js.map +1 -0
  31. package/dist/chunk-DTO27QFR.js +59 -0
  32. package/dist/chunk-DTO27QFR.js.map +1 -0
  33. package/dist/chunk-EWVDJYCC.js +296 -0
  34. package/dist/chunk-EWVDJYCC.js.map +1 -0
  35. package/dist/chunk-FIR4XTBL.js +136 -0
  36. package/dist/chunk-FIR4XTBL.js.map +1 -0
  37. package/dist/chunk-ILQNYQY5.js +200 -0
  38. package/dist/chunk-ILQNYQY5.js.map +1 -0
  39. package/dist/chunk-J5LA3Q6D.js +14 -0
  40. package/dist/chunk-J5LA3Q6D.js.map +1 -0
  41. package/dist/chunk-MDZ42XRH.js +10 -0
  42. package/dist/chunk-MDZ42XRH.js.map +1 -0
  43. package/dist/chunk-Q3SOVBIJ.js +176 -0
  44. package/dist/chunk-Q3SOVBIJ.js.map +1 -0
  45. package/dist/chunk-Q7QESSYF.js +49 -0
  46. package/dist/chunk-Q7QESSYF.js.map +1 -0
  47. package/dist/chunk-RKYKK6MN.js +19 -0
  48. package/dist/chunk-RKYKK6MN.js.map +1 -0
  49. package/dist/chunk-RYFZCAQ3.js +637 -0
  50. package/dist/chunk-RYFZCAQ3.js.map +1 -0
  51. package/dist/chunk-UJEC7H6K.js +39 -0
  52. package/dist/chunk-UJEC7H6K.js.map +1 -0
  53. package/dist/chunk-XESL274R.js +23 -0
  54. package/dist/chunk-XESL274R.js.map +1 -0
  55. package/dist/chunk-YR4MZXMU.js +13 -0
  56. package/dist/chunk-YR4MZXMU.js.map +1 -0
  57. package/dist/config/index.d.ts +63 -0
  58. package/dist/config/index.js +16 -0
  59. package/dist/config/index.js.map +1 -0
  60. package/dist/createLankaScope-Bc_vChRs.d.ts +30 -0
  61. package/dist/errors/index.d.ts +37 -0
  62. package/dist/errors/index.js +16 -0
  63. package/dist/errors/index.js.map +1 -0
  64. package/dist/gateway/index.d.ts +258 -0
  65. package/dist/gateway/index.js +438 -0
  66. package/dist/gateway/index.js.map +1 -0
  67. package/dist/index.d.ts +20 -0
  68. package/dist/index.js +43 -0
  69. package/dist/index.js.map +1 -0
  70. package/dist/lankaHttpInFlight-Bk1eIuSx.d.ts +43 -0
  71. package/dist/lankaRequestMiddleware-DAC5kCb7.d.ts +62 -0
  72. package/dist/lankaStandardValidator-CL-r-zEV.d.ts +34 -0
  73. package/dist/locator/index.d.ts +282 -0
  74. package/dist/locator/index.js +67 -0
  75. package/dist/locator/index.js.map +1 -0
  76. package/dist/logger/index.d.ts +146 -0
  77. package/dist/logger/index.js +11 -0
  78. package/dist/logger/index.js.map +1 -0
  79. package/dist/mock/index.d.ts +16 -0
  80. package/dist/mock/index.js +58 -0
  81. package/dist/mock/index.js.map +1 -0
  82. package/dist/role/index.d.ts +48 -0
  83. package/dist/role/index.js +7 -0
  84. package/dist/role/index.js.map +1 -0
  85. package/dist/scenario/index.d.ts +204 -0
  86. package/dist/scenario/index.js +28 -0
  87. package/dist/scenario/index.js.map +1 -0
  88. package/dist/validation/index.d.ts +18 -0
  89. package/dist/validation/index.js +53 -0
  90. package/dist/validation/index.js.map +1 -0
  91. package/dist/viewmodel/index.d.ts +478 -0
  92. package/dist/viewmodel/index.js +701 -0
  93. package/dist/viewmodel/index.js.map +1 -0
  94. package/package.json +99 -0
  95. package/skills/lanka-core/SKILL.md +241 -0
  96. package/skills/lanka-core/reference.md +1090 -0
  97. package/skills/lanka-packages/SKILL.md +70 -0
@@ -0,0 +1,67 @@
1
+ import {
2
+ createLankaLocatorProxy,
3
+ lankaSharedStores,
4
+ lankaSingletons
5
+ } from "../chunk-DTO27QFR.js";
6
+ import "../chunk-ILQNYQY5.js";
7
+ import {
8
+ requireActiveRuntime
9
+ } from "../chunk-BGVDPDX4.js";
10
+
11
+ // src/locator/gateway/_facades/lanka-gateways/lankaGateways.ts
12
+ var gatewayLocator = {
13
+ get: (propertyName) => requireActiveRuntime().locators.gateways.get(propertyName)
14
+ };
15
+ var lankaGateways = createLankaLocatorProxy({
16
+ locator: gatewayLocator,
17
+ protectedProperties: ["clearCache"],
18
+ errorPrefix: "Cannot access gateway"
19
+ });
20
+
21
+ // src/locator/scenario/_facades/lanka-scenarios/lankaScenarios.ts
22
+ var scenarioLocator = {
23
+ get: (propertyName) => requireActiveRuntime().locators.scenarios.get(propertyName)
24
+ };
25
+ var lankaScenarios = createLankaLocatorProxy({
26
+ locator: scenarioLocator,
27
+ errorPrefix: "Cannot access scenario"
28
+ });
29
+
30
+ // src/locator/singleton/_abstractions/lanka-singleton/ALankaSingleton.ts
31
+ var ALankaSingleton = class _ALankaSingleton {
32
+ /**
33
+ * A runtime check, for the locator, which cannot see types.
34
+ *
35
+ * Looks at the prototype chain rather than the name: names are lost to
36
+ * minification, and a name check would work only until the build.
37
+ */
38
+ static is(candidate) {
39
+ if (typeof candidate !== "function") return false;
40
+ let proto = Object.getPrototypeOf(candidate);
41
+ while (typeof proto === "function") {
42
+ if (proto === _ALankaSingleton) return true;
43
+ proto = Object.getPrototypeOf(proto);
44
+ }
45
+ return false;
46
+ }
47
+ };
48
+
49
+ // src/locator/singleton/_factories/create-lanka-singleton/createLankaSingleton.ts
50
+ var createLankaSingleton = (build) => {
51
+ class FunctionalSingleton extends ALankaSingleton {
52
+ constructor() {
53
+ super();
54
+ return build();
55
+ }
56
+ }
57
+ return FunctionalSingleton;
58
+ };
59
+ export {
60
+ ALankaSingleton,
61
+ createLankaSingleton,
62
+ lankaGateways,
63
+ lankaScenarios,
64
+ lankaSharedStores,
65
+ lankaSingletons
66
+ };
67
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/locator/gateway/_facades/lanka-gateways/lankaGateways.ts","../../src/locator/scenario/_facades/lanka-scenarios/lankaScenarios.ts","../../src/locator/singleton/_abstractions/lanka-singleton/ALankaSingleton.ts","../../src/locator/singleton/_factories/create-lanka-singleton/createLankaSingleton.ts"],"sourcesContent":["import { requireActiveRuntime } from \"../../../../_internal/active-runtime/activeRuntime\";\nimport type { ILankaLocator } from \"../../../_interfaces/ILankaLocator\";\nimport type { TLankaGateways } from \"../../_types/TLankaGateways\";\nimport { createLankaLocatorProxy } from \"../../../_factories/create-lanka-locator-proxy/createLankaLocatorProxy\";\nimport type { ALankaGateway } from \"../../../../gateway/_abstractions/lanka-gateway/ALankaGateway\";\n\n/**\n * The locator comes from the active instance rather than being created here.\n *\n * The cache of resolved objects is state, and module-level state would let two\n * frameworks in one process resolve the same gateway. The proxy stays at module\n * level because it has hundreds of call sites; only the cache moved.\n */\nconst gatewayLocator: ILankaLocator<ALankaGateway<unknown>> = {\n\tget: (propertyName: string) => requireActiveRuntime().locators.gateways.get(propertyName),\n};\n\n/**\n * Access to every gateway at once.\n *\n * An `ALankaGateway` subclass appears here by itself. The property is camelCase,\n * the gateway name is PascalCase.\n *\n * ```ts\n * import { lankaGateways } from \"lanka\";\n *\n * const user = await lankaGateways.userGateway.getById(1);\n * const list = await lankaGateways.companyGateway.getList({ page: 1 });\n * ```\n */\nexport const lankaGateways = createLankaLocatorProxy<ALankaGateway<unknown>, TLankaGateways>({\n\tlocator: gatewayLocator,\n\tprotectedProperties: [\"clearCache\"],\n\terrorPrefix: \"Cannot access gateway\",\n});\n","import { requireActiveRuntime } from \"../../../../_internal/active-runtime/activeRuntime\";\nimport type { ILankaLocator } from \"../../../_interfaces/ILankaLocator\";\nimport { createLankaLocatorProxy } from \"../../../_factories/create-lanka-locator-proxy/createLankaLocatorProxy\";\nimport type { ILankaScenario } from \"../../../../scenario/_interfaces/ILankaScenario\";\nimport { TLankaScenarios } from \"../../_types/TLankaScenarios\";\n\n/**\n * The locator comes from the active instance rather than being created here.\n *\n * The cache of resolved objects is state, and module-level state would let two\n * frameworks in one process resolve the same scenario. The proxy stays at module\n * level because it has hundreds of call sites; only the cache moved.\n */\nconst scenarioLocator: ILankaLocator<ILankaScenario<unknown>> = {\n\tget: (propertyName: string) => requireActiveRuntime().locators.scenarios.get(propertyName),\n};\n\n/**\n * Access to every scenario at once.\n *\n * An `ALankaScenario` subclass appears here by itself. The property is camelCase,\n * the scenario name is PascalCase.\n *\n * ```ts\n * import { lankaScenarios } from \"lanka\";\n *\n * lankaScenarios.sessionUpdated.trigger({ user });\n * lankaScenarios.usersListRefresh.trigger({ reason: \"create\" });\n *\n * lankaScenarios.usersListRefresh.subscribe((data) => { ... });\n * ```\n */\nexport const lankaScenarios = createLankaLocatorProxy<ILankaScenario<unknown>, TLankaScenarios>({\n\tlocator: scenarioLocator,\n\terrorPrefix: \"Cannot access scenario\",\n});\n","/**\n * The singleton marker: \"this class is published by the application in\n * `lankaSingletons`\".\n *\n * ## Why a marker when the class is exported anyway\n *\n * The other three locators have one: a gateway extends `ALankaGateway`, a\n * scenario has a `name`, a store extends `ALankaSharedStore`. Without a marker\n * the selection is \"anything that is a function with a prototype\", so a stray\n * export in the barrel — a helper, a companion class, an accidental re-export —\n * becomes part of the public `lankaSingletons.*`, and a typo in a name is caught\n * at runtime on first use, far from where it was made.\n *\n * ## A base class rather than a field\n *\n * A marker field can be put on anything, an object included, and the type would\n * again stop telling a class from a non-class. Inheritance also gives TypeScript\n * something it can select on in a mapped type.\n *\n * The class is empty deliberately: all it carries is the statement \"I am meant\n * for the locator\".\n */\nexport abstract class ALankaSingleton {\n\t/**\n\t * A runtime check, for the locator, which cannot see types.\n\t *\n\t * Looks at the prototype chain rather than the name: names are lost to\n\t * minification, and a name check would work only until the build.\n\t */\n\tstatic is(candidate: unknown): boolean {\n\t\tif (typeof candidate !== \"function\") return false;\n\n\t\tlet proto: unknown = Object.getPrototypeOf(candidate) as unknown;\n\t\twhile (typeof proto === \"function\") {\n\t\t\tif (proto === ALankaSingleton) return true;\n\t\t\tproto = Object.getPrototypeOf(proto) as unknown;\n\t\t}\n\t\treturn false;\n\t}\n}\n","import { ALankaSingleton } from \"../../_abstractions/lanka-singleton/ALankaSingleton\";\n\n/**\n * The functional style of `ALankaSingleton`: a singleton declared by a function.\n *\n * A singleton is a role — an application writes many — and this is the same role\n * the class style declares by extending the marker. What comes back IS a subclass\n * of `ALankaSingleton`, so the locator discovers it in the consumer's barrel,\n * builds it on first use and caches it, exactly as it does a hand-written class.\n *\n * ```ts\n * export const PlaygroundClock = createLankaSingleton(() => ({\n * \tnow: () => Date.now(),\n * }));\n * ```\n *\n * The result is exported under a PascalCase name because it is a class: the\n * locator resolves `lankaSingletons.playgroundClock` by that export name, and a\n * camelCase one would read as the instance while being the constructor.\n *\n * The builder runs at first resolution, not here — a singleton declared in a\n * module body must not touch a runtime that does not exist yet. Canon:\n * `skills/parity/SKILL.md`.\n */\nexport const createLankaSingleton = <TInstance extends object>(\n\tbuild: () => TInstance,\n): new () => TInstance => {\n\tclass FunctionalSingleton extends ALankaSingleton {\n\t\tpublic constructor() {\n\t\t\tsuper();\n\n\t\t\t// A constructor answering an object is what makes the two styles one\n\t\t\t// implementation: the locator constructs a marked class either way, and\n\t\t\t// what it gets back is what the builder returned.\n\t\t\treturn build();\n\t\t}\n\t}\n\n\treturn FunctionalSingleton as unknown as new () => TInstance;\n};\n"],"mappings":";;;;;;;;;;;AAaA,IAAM,iBAAwD;AAAA,EAC7D,KAAK,CAAC,iBAAyB,qBAAqB,EAAE,SAAS,SAAS,IAAI,YAAY;AACzF;AAeO,IAAM,gBAAgB,wBAAgE;AAAA,EAC5F,SAAS;AAAA,EACT,qBAAqB,CAAC,YAAY;AAAA,EAClC,aAAa;AACd,CAAC;;;ACrBD,IAAM,kBAA0D;AAAA,EAC/D,KAAK,CAAC,iBAAyB,qBAAqB,EAAE,SAAS,UAAU,IAAI,YAAY;AAC1F;AAiBO,IAAM,iBAAiB,wBAAkE;AAAA,EAC/F,SAAS;AAAA,EACT,aAAa;AACd,CAAC;;;ACbM,IAAe,kBAAf,MAAe,iBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOrC,OAAO,GAAG,WAA6B;AACtC,QAAI,OAAO,cAAc,WAAY,QAAO;AAE5C,QAAI,QAAiB,OAAO,eAAe,SAAS;AACpD,WAAO,OAAO,UAAU,YAAY;AACnC,UAAI,UAAU,iBAAiB,QAAO;AACtC,cAAQ,OAAO,eAAe,KAAK;AAAA,IACpC;AACA,WAAO;AAAA,EACR;AACD;;;ACfO,IAAM,uBAAuB,CACnC,UACyB;AAAA,EACzB,MAAM,4BAA4B,gBAAgB;AAAA,IAC1C,cAAc;AACpB,YAAM;AAKN,aAAO,MAAM;AAAA,IACd;AAAA,EACD;AAEA,SAAO;AACR;","names":[]}
@@ -0,0 +1,146 @@
1
+ type TLankaLogMessage = string | number | boolean | object | null | undefined;
2
+
3
+ type TLankaLogMessageFactory = () => TLankaLogMessage;
4
+
5
+ type TLankaLoggerFn = (msg: TLankaLogMessage | TLankaLogMessageFactory, ...args: unknown[]) => void;
6
+
7
+ type TLankaLoggerFlagValue = boolean | (() => boolean);
8
+
9
+ type TLankaConsoleLevel = "log" | "info" | "warn" | "error" | "debug";
10
+
11
+ type TLankaLoggerStyle = "badge" | "plain";
12
+
13
+ interface ILankaLoggerSink {
14
+ emit: (entry: {
15
+ layer: string;
16
+ level: TLankaConsoleLevel;
17
+ style: TLankaLoggerStyle;
18
+ color?: string;
19
+ message: TLankaLogMessage;
20
+ args: unknown[];
21
+ }) => void;
22
+ }
23
+
24
+ interface ILankaLoggerConfig {
25
+ /**
26
+ * Unique printer key, used for later updates / retrieval.
27
+ * Example: "printGatewayLog" or "printMyFeatureLog"
28
+ */
29
+ key: string;
30
+ /**
31
+ * Short label for the log prefix.
32
+ * Example: "GW" / "SC" / "VM" / "MOD" / "MY"
33
+ */
34
+ layer: string;
35
+ /**
36
+ * Optional badge color (used in "badge" style).
37
+ */
38
+ color?: string;
39
+ /**
40
+ * Console level (log/info/warn/error/debug).
41
+ */
42
+ level?: TLankaConsoleLevel;
43
+ /**
44
+ * If provided, printer is enabled only when the flag is enabled.
45
+ */
46
+ flag?: string;
47
+ /**
48
+ * Hard enable/disable of the printer (has priority over `flag`).
49
+ */
50
+ enabled?: TLankaLoggerFlagValue;
51
+ }
52
+
53
+ /**
54
+ * Output that is not bound to the console, and is silent in production.
55
+ *
56
+ * The ambient one is `lankaLogger`, and it is what an application and the
57
+ * framework both write: `lankaLogger.printGatewayLog(...)`. The class is here for
58
+ * the reason node exposes `Console` beside `console` — a second logger with its
59
+ * own sinks, flags and printers is a real thing to want, and a test that builds
60
+ * one is not fighting a global.
61
+ *
62
+ * ```ts
63
+ * const audit = new LankaLogger();
64
+ * audit.silent();
65
+ * audit.addSink({ emit: (entry) => rows.push(entry) });
66
+ * ```
67
+ *
68
+ * Every method is a no-op in production, checked per call rather than once at
69
+ * import: a flag flipped at runtime must not be able to start the log.
70
+ */
71
+ declare class LankaLogger {
72
+ private style;
73
+ private sinks;
74
+ private readonly flags;
75
+ private readonly printers;
76
+ /** The gateway layer's printer. */
77
+ readonly printGatewayLog: TLankaLoggerFn;
78
+ /** The scenario layer's printer. */
79
+ readonly printScenarioLog: TLankaLoggerFn;
80
+ /** The ViewModel layer's printer. */
81
+ readonly printViewModelLog: TLankaLoggerFn;
82
+ /** The view layer's printer. */
83
+ readonly printViewLog: TLankaLoggerFn;
84
+ /** The bootstrap sequence's printer. */
85
+ readonly printBootstrapLog: TLankaLoggerFn;
86
+ constructor();
87
+ /**
88
+ * Enables or silences the WHOLE log, overriding the environment.
89
+ *
90
+ * Equivalent to setting the `ENABLED` flag.
91
+ */
92
+ setEnabled(value: boolean): void;
93
+ /** Switches output between badges and plain text. */
94
+ setStyle(style: TLankaLoggerStyle): void;
95
+ /**
96
+ * Goes completely silent by removing the sinks; config and printers remain.
97
+ *
98
+ * Output is restored with `resetSinks()` or `addSink()`.
99
+ */
100
+ silent(): void;
101
+ /** Restores the single default sink: the console. */
102
+ resetSinks(): void;
103
+ addSink(sink: ILankaLoggerSink): void;
104
+ removeSink(sink: ILankaLoggerSink): void;
105
+ /**
106
+ * Declares a flag the printers use, or overrides an existing one.
107
+ *
108
+ * The value may be a boolean or a resolver function — for example one reading
109
+ * localStorage.
110
+ */
111
+ setFlag(flag: string, value: TLankaLoggerFlagValue): void;
112
+ /** Removes a flag override, falling back to the environment value. */
113
+ unsetFlag(flag: string): void;
114
+ isFlagEnabled(flag: string): boolean;
115
+ /**
116
+ * Registers a printer, or replaces an existing one.
117
+ *
118
+ * @returns The callable bound to this printer
119
+ */
120
+ registerPrinter(config: ILankaLoggerConfig): TLankaLoggerFn;
121
+ /** Updates a printer's config; a no-op when there is no such printer. */
122
+ updatePrinter(key: string, patch: Partial<Omit<ILankaLoggerConfig, "key">>): void;
123
+ /** A printer by key; a silent function when there is none. */
124
+ getPrinter(key: string): TLankaLoggerFn;
125
+ /** The keys of every registered printer. */
126
+ listPrinters(): string[];
127
+ private isEnabled;
128
+ private isPrinterEnabled;
129
+ private emit;
130
+ /**
131
+ * A printer resolved at CALL time, not at registration.
132
+ *
133
+ * `updatePrinter` has to reach a callable a screen took a reference to long
134
+ * before; looking the key up on every call is what makes that true.
135
+ */
136
+ private createPrinterFn;
137
+ }
138
+ /**
139
+ * The logger the framework itself writes to, and an application with it.
140
+ *
141
+ * `console` to this file's `Console`: ready before anything is configured, and
142
+ * the one every call site in the framework uses.
143
+ */
144
+ declare const lankaLogger: LankaLogger;
145
+
146
+ export { type ILankaLoggerConfig, type ILankaLoggerSink, LankaLogger, type TLankaConsoleLevel, type TLankaLogMessage, type TLankaLogMessageFactory, type TLankaLoggerFlagValue, type TLankaLoggerFn, type TLankaLoggerStyle, lankaLogger };
@@ -0,0 +1,11 @@
1
+ import {
2
+ LankaLogger,
3
+ lankaLogger
4
+ } from "../chunk-C2HP7CRD.js";
5
+ import "../chunk-D27MREPB.js";
6
+ import "../chunk-BGVDPDX4.js";
7
+ export {
8
+ LankaLogger,
9
+ lankaLogger
10
+ };
11
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Builds a mock handler for a gateway method: logging, delay, dynamic module
3
+ * loading and extraction of the data itself.
4
+ *
5
+ * Returns `undefined` while mock mode is off, which is what lets a bundler drop
6
+ * all mock code from a production build.
7
+ *
8
+ * @param importFactory Dynamic import: `() => import("../mocks/user")`
9
+ * @param extractor Extracts and validates data from the imported module
10
+ * @param name Action name for the log; taken from the stack trace when omitted
11
+ * @param delayMs Delay before answering
12
+ * @returns The mock data, or `undefined` when mocks are disabled
13
+ */
14
+ declare function createLankaMockHandler<T, M>(importFactory: () => Promise<M>, extractor: (module: M) => T | Promise<T>, name?: string, delayMs?: number): (() => Promise<T>) | undefined;
15
+
16
+ export { createLankaMockHandler };
@@ -0,0 +1,58 @@
1
+ import {
2
+ lankaLogger
3
+ } from "../chunk-C2HP7CRD.js";
4
+ import {
5
+ getLankaFlags
6
+ } from "../chunk-D27MREPB.js";
7
+ import "../chunk-BGVDPDX4.js";
8
+
9
+ // src/_internal/sleep.ts
10
+ var sleep = (ms = 300) => {
11
+ return new Promise((resolve) => setTimeout(resolve, ms));
12
+ };
13
+
14
+ // src/mock/_factories/create-lanka-mock-handler/createLankaMockHandler.ts
15
+ function createLankaMockHandler(importFactory, extractor, name, delayMs) {
16
+ const flags = getLankaFlags();
17
+ if (flags.isProduction || !flags.isMockMode) {
18
+ return void 0;
19
+ }
20
+ return async () => {
21
+ const actionName = name ?? readActionNameFromStack() ?? "Unknown";
22
+ lankaLogger.printGatewayLog(`MOCK: ${actionName}`);
23
+ const wait = delayMs ?? 300;
24
+ if (wait > 0) {
25
+ await sleep(wait);
26
+ }
27
+ try {
28
+ const module = await importFactory();
29
+ return await extractor(module);
30
+ } catch (error) {
31
+ lankaLogger.printGatewayLog(
32
+ `MOCK ERROR (${actionName}): Failed to load or extract mock`,
33
+ error
34
+ );
35
+ throw error;
36
+ }
37
+ };
38
+ }
39
+ function readActionNameFromStack() {
40
+ try {
41
+ const stack = new Error().stack;
42
+ if (!stack) return void 0;
43
+ const lines = stack.split(String.fromCharCode(10));
44
+ for (let i = 3; i < lines.length; i++) {
45
+ const match = /\.(\w+)\s*\(/.exec(lines[i]);
46
+ const methodName = match?.[1];
47
+ if (methodName && !["requestJson", "request", "execute"].includes(methodName)) {
48
+ return methodName;
49
+ }
50
+ }
51
+ } catch {
52
+ }
53
+ return void 0;
54
+ }
55
+ export {
56
+ createLankaMockHandler
57
+ };
58
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/_internal/sleep.ts","../../src/mock/_factories/create-lanka-mock-handler/createLankaMockHandler.ts"],"sourcesContent":["export const sleep = (ms: number = 300): Promise<void> => {\n\treturn new Promise((resolve) => setTimeout(resolve, ms));\n};\n","import { getLankaFlags } from \"../../../config/get-lanka-flags/getLankaFlags\";\nimport { sleep } from \"../../../_internal/sleep\";\nimport { lankaLogger } from \"../../../logger/lanka-logger/LankaLogger\";\n\n/**\n * Builds a mock handler for a gateway method: logging, delay, dynamic module\n * loading and extraction of the data itself.\n *\n * Returns `undefined` while mock mode is off, which is what lets a bundler drop\n * all mock code from a production build.\n *\n * @param importFactory Dynamic import: `() => import(\"../mocks/user\")`\n * @param extractor Extracts and validates data from the imported module\n * @param name Action name for the log; taken from the stack trace when omitted\n * @param delayMs Delay before answering\n * @returns The mock data, or `undefined` when mocks are disabled\n */\nexport function createLankaMockHandler<T, M>(\n\timportFactory: () => Promise<M>,\n\textractor: (module: M) => T | Promise<T>,\n\tname?: string,\n\tdelayMs?: number,\n): (() => Promise<T>) | undefined {\n\tconst flags = getLankaFlags();\n\n\tif (flags.isProduction || !flags.isMockMode) {\n\t\treturn undefined;\n\t}\n\n\treturn async (): Promise<T> => {\n\t\t// The action name is a PARAMETER. Deriving it from a stack trace works only\n\t\t// until minification: function names disappear in a built bundle, and mock\n\t\t// mode is enabled in exactly such a bundle — so the mechanism breaks where\n\t\t// it is used.\n\t\t//\n\t\t// Stack parsing remains as a fallback, for development only, where the\n\t\t// stack is still readable.\n\t\tconst actionName = name ?? readActionNameFromStack() ?? \"Unknown\";\n\n\t\tlankaLogger.printGatewayLog(`MOCK: ${actionName}`);\n\n\t\tconst wait = delayMs ?? 300;\n\t\tif (wait > 0) {\n\t\t\tawait sleep(wait);\n\t\t}\n\n\t\ttry {\n\t\t\tconst module = await importFactory();\n\t\t\treturn await extractor(module);\n\t\t} catch (error) {\n\t\t\tlankaLogger.printGatewayLog(\n\t\t\t\t`MOCK ERROR (${actionName}): Failed to load or extract mock`,\n\t\t\t\terror,\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t};\n}\n\n/**\n * Extracts a gateway method name from a stack trace.\n *\n * A fallback, and an unreliable one: in built code function names are minified\n * and there is nothing to read. Returns `undefined` rather than an invented\n * name.\n */\nfunction readActionNameFromStack(): string | undefined {\n\ttry {\n\t\tconst stack = new Error().stack;\n\t\tif (!stack) return undefined;\n\n\t\tconst lines = stack.split(String.fromCharCode(10));\n\t\tfor (let i = 3; i < lines.length; i++) {\n\t\t\tconst match = /\\.(\\w+)\\s*\\(/.exec(lines[i]);\n\t\t\tconst methodName = match?.[1];\n\t\t\tif (methodName && ![\"requestJson\", \"request\", \"execute\"].includes(methodName)) {\n\t\t\t\treturn methodName;\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Stack format is not standardised; a missing name is no reason to throw.\n\t}\n\treturn undefined;\n}\n"],"mappings":";;;;;;;;;AAAO,IAAM,QAAQ,CAAC,KAAa,QAAuB;AACzD,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACxD;;;ACeO,SAAS,uBACf,eACA,WACA,MACA,SACiC;AACjC,QAAM,QAAQ,cAAc;AAE5B,MAAI,MAAM,gBAAgB,CAAC,MAAM,YAAY;AAC5C,WAAO;AAAA,EACR;AAEA,SAAO,YAAwB;AAQ9B,UAAM,aAAa,QAAQ,wBAAwB,KAAK;AAExD,gBAAY,gBAAgB,SAAS,UAAU,EAAE;AAEjD,UAAM,OAAO,WAAW;AACxB,QAAI,OAAO,GAAG;AACb,YAAM,MAAM,IAAI;AAAA,IACjB;AAEA,QAAI;AACH,YAAM,SAAS,MAAM,cAAc;AACnC,aAAO,MAAM,UAAU,MAAM;AAAA,IAC9B,SAAS,OAAO;AACf,kBAAY;AAAA,QACX,eAAe,UAAU;AAAA,QACzB;AAAA,MACD;AACA,YAAM;AAAA,IACP;AAAA,EACD;AACD;AASA,SAAS,0BAA8C;AACtD,MAAI;AACH,UAAM,QAAQ,IAAI,MAAM,EAAE;AAC1B,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,QAAQ,MAAM,MAAM,OAAO,aAAa,EAAE,CAAC;AACjD,aAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACtC,YAAM,QAAQ,eAAe,KAAK,MAAM,CAAC,CAAC;AAC1C,YAAM,aAAa,QAAQ,CAAC;AAC5B,UAAI,cAAc,CAAC,CAAC,eAAe,WAAW,SAAS,EAAE,SAAS,UAAU,GAAG;AAC9E,eAAO;AAAA,MACR;AAAA,IACD;AAAA,EACD,QAAQ;AAAA,EAER;AACA,SAAO;AACR;","names":[]}
@@ -0,0 +1,48 @@
1
+ /** What a role's bridge hands over: the instance, and its protected surface. */
2
+ interface ILankaRoleOpening<TInstance, TContext> {
3
+ instance: TInstance;
4
+ context: TContext;
5
+ }
6
+ /**
7
+ * Builds a role's instance and opens its protected surface.
8
+ *
9
+ * Written in the role's own module, because that is the only place the language
10
+ * allows: `protected` is readable from inside a class body deriving from the
11
+ * base and nowhere else. A generic helper cannot reach it, and a base that made
12
+ * it public would put its whole extension surface on every object a consumer
13
+ * writes.
14
+ */
15
+ type TLankaRoleOpener<TConfig, TInstance, TContext> = (config: TConfig) => ILankaRoleOpening<TInstance, TContext>;
16
+ /**
17
+ * The functional style of one role: call it with hooks, or with nothing.
18
+ *
19
+ * With `build` it answers what the hooks returned — the methods a gateway
20
+ * declares, the actions a ViewModel exposes. Without it, the instance itself,
21
+ * which is what a role whose whole body is data needs.
22
+ */
23
+ interface ILankaRoleFactory<TConfig, TInstance, TContext> {
24
+ <TResult>(config: TConfig & {
25
+ build: (context: TContext) => TResult;
26
+ }): TResult;
27
+ (config: TConfig): TInstance;
28
+ }
29
+ /**
30
+ * Turns a role's class into its factory, over one implementation.
31
+ *
32
+ * The two styles of a role are not two implementations: the factory builds the
33
+ * SAME class and hands its protected surface to the caller as an object. A
34
+ * behaviour fix lands in both styles at once, and a divergence is not something
35
+ * a reviewer has to notice — it cannot be written.
36
+ *
37
+ * It is published because a consumer with a layer of their own — a repository, a
38
+ * command, a presenter — gets both styles for it from one line:
39
+ *
40
+ * ```ts
41
+ * export const createRepository = defineLankaRole(openRepository);
42
+ * ```
43
+ *
44
+ * Canon: `skills/parity/SKILL.md`.
45
+ */
46
+ declare const defineLankaRole: <TConfig, TInstance, TContext>(open: TLankaRoleOpener<TConfig, TInstance, TContext>) => ILankaRoleFactory<TConfig, TInstance, TContext>;
47
+
48
+ export { type ILankaRoleFactory, type ILankaRoleOpening, type TLankaRoleOpener, defineLankaRole };
@@ -0,0 +1,7 @@
1
+ import {
2
+ defineLankaRole
3
+ } from "../chunk-MDZ42XRH.js";
4
+ export {
5
+ defineLankaRole
6
+ };
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,204 @@
1
+ import { a as ILankaScenario, T as TLankaReplayRequest, b as ILankaEventMetadata, c as TLankaEventBusMiddleware, d as ILankaEventLog, I as ILankaScenarioVM } from '../ILankaScenarioVM-DuCyPoyT.js';
2
+ export { e as TLankaEventBusDecision } from '../ILankaScenarioVM-DuCyPoyT.js';
3
+ export { I as ILankaScenarioMetadata } from '../ILankaScenarioMetadata-Bu-yggTZ.js';
4
+
5
+ /**
6
+ * The base of a scenario — a named unit of coordination over the event bus.
7
+ *
8
+ * A subclass declares `name`, `eventType` and `dataTypeName`, calls `trigger()`
9
+ * when the event happens, and ViewModels subscribe to it and unsubscribe.
10
+ *
11
+ * Scenarios register THEMSELVES unless the subclass sets the static
12
+ * `skipAutoRegistration`.
13
+ *
14
+ * ```ts
15
+ * export class SessionUpdated extends ALankaScenario<TSession> {
16
+ * readonly name = "SessionUpdated";
17
+ * readonly eventType = "session.updated";
18
+ * readonly dataTypeName = "TSession";
19
+ * }
20
+ * ```
21
+ */
22
+ declare abstract class ALankaScenario<TData = void> implements ILankaScenario<TData> {
23
+ abstract readonly name: string;
24
+ abstract readonly eventType: string;
25
+ abstract readonly dataTypeName: string;
26
+ /** A subclass sets this to opt out of self-registration. */
27
+ static skipAutoRegistration?: boolean;
28
+ /**
29
+ * The self-registration pool.
30
+ *
31
+ * Class-level deliberately: a registry of DEFINITIONS, not runtime state. The
32
+ * classes come from one barrel and both framework instances must see the same
33
+ * list — splitting it would be divergence, not isolation.
34
+ */
35
+ private static autoRegisteredScenarios;
36
+ /** Registers the scenario itself unless the subclass opted out. */
37
+ constructor();
38
+ /**
39
+ * Every scenario that registered itself.
40
+ *
41
+ * @internal
42
+ */
43
+ static getAutoRegisteredScenarios(): ALankaScenario<unknown>[];
44
+ /**
45
+ * Clears the auto-registration pool. Required by tests.
46
+ * @internal
47
+ */
48
+ static clearAutoRegisteredScenarios(): void;
49
+ /**
50
+ * Registers the scenario by hand.
51
+ *
52
+ * @returns `false` when it was already registered
53
+ */
54
+ register(): boolean;
55
+ /**
56
+ * Removes the scenario from the registry.
57
+ *
58
+ * @returns `false` when it was not there
59
+ */
60
+ unregister(): boolean;
61
+ trigger(data?: TData): void;
62
+ /**
63
+ * Subscribes a handler and returns an unsubscribe function.
64
+ *
65
+ * Without the return, unsubscribing is possible only by callback identity, and
66
+ * every ViewModel factory has to keep a map of references for it.
67
+ */
68
+ subscribe(callback: (data?: TData) => void, options?: {
69
+ priority?: number;
70
+ replay?: TLankaReplayRequest;
71
+ usedBy?: string;
72
+ }): () => void;
73
+ }
74
+
75
+ /** What a scenario is: three names and nothing else. */
76
+ interface ILankaScenarioConfig {
77
+ /** The scenario's name, and the key it is found by. */
78
+ name: string;
79
+ /** The event type on the bus. */
80
+ eventType: string;
81
+ /** The event data's type name — for the bus metadata. */
82
+ dataTypeName: string;
83
+ /** Opts out of self-registration, as `skipAutoRegistration` does on a class. */
84
+ skipAutoRegistration?: boolean;
85
+ }
86
+ /**
87
+ * A scenario, without writing a class whose body is data.
88
+ *
89
+ * The class style is right where a scenario has behaviour — an `initialize` that
90
+ * warms something, a `cleanup` that lets go. Most have neither: in the two
91
+ * applications this framework grew out of, every scenario is a class holding
92
+ * three `readonly` fields and nothing else.
93
+ *
94
+ * One implementation: this builds a subclass of `ALankaScenario`, so
95
+ * self-registration, `trigger` and `subscribe` are the same code either way.
96
+ */
97
+ declare const createLankaScenario: <TData = void>(config: ILankaScenarioConfig) => ILankaScenario<TData>;
98
+
99
+ declare const lankaEventBus: Readonly<{
100
+ enableLogs: () => void;
101
+ disableLogs: () => void;
102
+ registerEvent: (eventType: string, metadata: ILankaEventMetadata) => void;
103
+ getRegisteredEvents: () => {
104
+ eventType: string;
105
+ metadata: ILankaEventMetadata;
106
+ }[];
107
+ getEventInfo: (eventType: string) => ILankaEventMetadata | null;
108
+ getSubscriptions: (eventType: string) => number;
109
+ subscribe: <T>(eventType: string, callback: (data: T) => void, options?: {
110
+ priority?: number;
111
+ replay?: TLankaReplayRequest;
112
+ usedBy?: string;
113
+ }) => (() => void);
114
+ unsubscribe: <T>(eventType: string, callback: (data: T) => void) => void;
115
+ dispatch: <T>(eventType: string, data?: T, usedBy?: string) => void;
116
+ addMiddleware: <T>(middleware: TLankaEventBusMiddleware<T>) => void;
117
+ removeMiddleware: <T>(middleware: TLankaEventBusMiddleware<T>) => void;
118
+ getEventLogs: (eventType?: string, limit?: number) => ILankaEventLog[];
119
+ clearEvent: (eventType: string) => void;
120
+ clearAllEvents: () => void;
121
+ reset: () => void;
122
+ }>;
123
+
124
+ /**
125
+ * Bootstrapping the scenario layer, for callers with no instance in hand.
126
+ *
127
+ * An ordinary class with an ordinary instance: the declared-ViewModel list below
128
+ * is deliberately shared across instances — every test builds a new framework and
129
+ * module-level ViewModels are declared once — so the single instance IS the
130
+ * shared list, and a second one would be a second list nobody adopts.
131
+ */
132
+ declare class LankaScenarioBootstrap {
133
+ /**
134
+ * The bootstrapped flag and the set of initialised VMs live on the INSTANCE.
135
+ *
136
+ * As static fields, a second framework in the same process would exit
137
+ * `bootstrap()` on someone else's flag — never starting at all, with no symptom
138
+ * except that no scenario works.
139
+ */
140
+ private get state();
141
+ isScenarioLayerBootstrapped(): boolean;
142
+ private forceInstantiateAllScenarios;
143
+ private registerScenarioEvents;
144
+ private initializeAlreadyCreatedViewModels;
145
+ /**
146
+ * Brings up the scenario layer.
147
+ *
148
+ * Constructs the scenario classes so they can be collected, declares their
149
+ * events on the bus, calls `initialize()` where present, and initialises
150
+ * ViewModels that already exist — which happens in tests and under unusual
151
+ * import order.
152
+ *
153
+ * Idempotent.
154
+ */
155
+ bootstrap(): void;
156
+ /**
157
+ * Called by a ViewModel factory when the ViewModel declares scenario handlers.
158
+ *
159
+ * Registers the ViewModel and, if the layer is already up, initialises it
160
+ * immediately. Duplicate registration and duplicate initialisation are
161
+ * impossible.
162
+ *
163
+ * @param viewModel What to register
164
+ * @param name Name for the log
165
+ */
166
+ /**
167
+ * ViewModels DECLARED in this process.
168
+ *
169
+ * Module-level deliberately, the same case as the scenario pool: a registry of
170
+ * DEFINITIONS, not runtime state. Splitting it between instances would be
171
+ * divergence, not isolation — the classes come from the same modules and both
172
+ * instances must see one list.
173
+ *
174
+ * Two reasons it exists:
175
+ *
176
+ * 1. Declaring a ViewModel is a declaration, not work. A screen file creates it
177
+ * at module level, and import order decides whether that happens before or
178
+ * after `createLanka()`. Requiring a live instance at declaration time
179
+ * requires an import order the consumer does not control.
180
+ * 2. Instances come one after another: every test creates its own. The list is
181
+ * NOT drained by the first — otherwise the second instance would know no
182
+ * module-level ViewModel and its `dispose()` would not remove their
183
+ * subscriptions, so a test would receive events the previous one subscribed
184
+ * to.
185
+ */
186
+ private readonly declaredViewModels;
187
+ /** Registers everything declared into a NEW instance. Called by `createLanka`. */
188
+ adoptDeclaredViewModels(): void;
189
+ registerViewModel(viewModel: ILankaScenarioVM, name?: string): void;
190
+ private attachViewModel;
191
+ /**
192
+ * Resets the whole scenario layer. Without it tests are not isolated.
193
+ *
194
+ * Clears the self-registration list, the scenario registry with its metadata,
195
+ * the ViewModel registry together with all their subscriptions, and the bus —
196
+ * events and
197
+ * middleware.
198
+ */
199
+ reset(): void;
200
+ }
201
+ /** The one every caller wants. */
202
+ declare const lankaScenarioBootstrap: LankaScenarioBootstrap;
203
+
204
+ export { ALankaScenario, ILankaEventLog, ILankaEventMetadata, ILankaScenario, type ILankaScenarioConfig, ILankaScenarioVM, TLankaEventBusMiddleware, TLankaReplayRequest, createLankaScenario, lankaEventBus, lankaScenarioBootstrap };
@@ -0,0 +1,28 @@
1
+ import {
2
+ lankaScenarioBootstrap
3
+ } from "../chunk-Q3SOVBIJ.js";
4
+ import {
5
+ ALankaScenario,
6
+ lankaEventBus
7
+ } from "../chunk-EWVDJYCC.js";
8
+ import "../chunk-C2HP7CRD.js";
9
+ import "../chunk-D27MREPB.js";
10
+ import "../chunk-BGVDPDX4.js";
11
+
12
+ // src/scenario/_factories/create-lanka-scenario/createLankaScenario.ts
13
+ var createLankaScenario = (config) => {
14
+ class FunctionalScenario extends ALankaScenario {
15
+ static skipAutoRegistration = config.skipAutoRegistration ?? false;
16
+ name = config.name;
17
+ eventType = config.eventType;
18
+ dataTypeName = config.dataTypeName;
19
+ }
20
+ return new FunctionalScenario();
21
+ };
22
+ export {
23
+ ALankaScenario,
24
+ createLankaScenario,
25
+ lankaEventBus,
26
+ lankaScenarioBootstrap
27
+ };
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/scenario/_factories/create-lanka-scenario/createLankaScenario.ts"],"sourcesContent":["import { ALankaScenario } from \"../../_abstractions/lanka-scenario/ALankaScenario\";\nimport type { ILankaScenario } from \"../../_interfaces/ILankaScenario\";\n\n/** What a scenario is: three names and nothing else. */\nexport interface ILankaScenarioConfig {\n\t/** The scenario's name, and the key it is found by. */\n\tname: string;\n\t/** The event type on the bus. */\n\teventType: string;\n\t/** The event data's type name — for the bus metadata. */\n\tdataTypeName: string;\n\t/** Opts out of self-registration, as `skipAutoRegistration` does on a class. */\n\tskipAutoRegistration?: boolean;\n}\n\n/**\n * A scenario, without writing a class whose body is data.\n *\n * The class style is right where a scenario has behaviour — an `initialize` that\n * warms something, a `cleanup` that lets go. Most have neither: in the two\n * applications this framework grew out of, every scenario is a class holding\n * three `readonly` fields and nothing else.\n *\n * One implementation: this builds a subclass of `ALankaScenario`, so\n * self-registration, `trigger` and `subscribe` are the same code either way.\n */\nexport const createLankaScenario = <TData = void>(\n\tconfig: ILankaScenarioConfig,\n): ILankaScenario<TData> => {\n\tclass FunctionalScenario extends ALankaScenario<TData> {\n\t\tpublic static override skipAutoRegistration = config.skipAutoRegistration ?? false;\n\n\t\tpublic readonly name = config.name;\n\t\tpublic readonly eventType = config.eventType;\n\t\tpublic readonly dataTypeName = config.dataTypeName;\n\t}\n\n\treturn new FunctionalScenario();\n};\n"],"mappings":";;;;;;;;;;;;AA0BO,IAAM,sBAAsB,CAClC,WAC2B;AAAA,EAC3B,MAAM,2BAA2B,eAAsB;AAAA,IACtD,OAAuB,uBAAuB,OAAO,wBAAwB;AAAA,IAE7D,OAAO,OAAO;AAAA,IACd,YAAY,OAAO;AAAA,IACnB,eAAe,OAAO;AAAA,EACvC;AAEA,SAAO,IAAI,mBAAmB;AAC/B;","names":[]}
@@ -0,0 +1,18 @@
1
+ export { I as ILankaValidator, T as TLankaSchema, a as TLankaValidationResult, l as lankaStandardValidator } from '../lankaStandardValidator-CL-r-zEV.js';
2
+ import { I as ILankaApiError } from '../ILankaApiError-zI_2bNs0.js';
3
+ import '@standard-schema/spec';
4
+
5
+ /**
6
+ * What a schema refused, as an error a screen can catch by type.
7
+ *
8
+ * The one case where a class is the answer by itself: `instanceof` needs a
9
+ * prototype. It carries the field errors a form renders, so a caller branches on
10
+ * the type rather than parsing a message.
11
+ */
12
+ declare class LankaValidationError extends Error implements ILankaApiError {
13
+ status: number;
14
+ errors: string[];
15
+ constructor(message: string, errors?: string[]);
16
+ }
17
+
18
+ export { LankaValidationError };