lanka 1.1.1 → 1.3.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/{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-CAENLhDO.d.ts} +3 -3
- package/dist/_extend/index.d.ts +6 -5
- package/dist/_extend/index.js +3 -3
- package/dist/_internal/index.d.ts +61 -8
- package/dist/_internal/index.js +25 -0
- package/dist/_internal/index.js.map +1 -1
- package/dist/{activeRuntime-B336NU5I.d.ts → activeRuntime-BYd2D6Lx.d.ts} +2 -2
- package/dist/bootstrap/index.d.ts +9 -8
- package/dist/bootstrap/index.js +4 -4
- 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-GK3E4CVW.js → chunk-5MAQVBI2.js} +4 -4
- package/dist/{chunk-UGXSGQPW.js → chunk-B7EYIAW7.js} +39 -3
- package/dist/chunk-B7EYIAW7.js.map +1 -0
- package/dist/chunk-CRIRTOLB.js +27 -0
- package/dist/chunk-CRIRTOLB.js.map +1 -0
- package/dist/{chunk-Q7QESSYF.js → chunk-G32H73QY.js} +10 -1
- package/dist/chunk-G32H73QY.js.map +1 -0
- package/dist/chunk-HVSQOMRE.js +69 -0
- package/dist/chunk-HVSQOMRE.js.map +1 -0
- package/dist/{chunk-73IVH3C6.js → chunk-NDCJBO47.js} +2 -2
- package/dist/{chunk-ECM2HZHS.js → chunk-UBGXDTXC.js} +16 -7
- package/dist/chunk-UBGXDTXC.js.map +1 -0
- package/dist/{createLanka-DI1CSy2Q.d.ts → createLanka-NrlvN-WQ.d.ts} +1 -1
- package/dist/errors/index.d.ts +22 -3
- package/dist/errors/index.js +8 -3
- package/dist/errors/index.js.map +1 -1
- package/dist/gateway/index.d.ts +4 -3
- package/dist/gateway/index.js +4 -3
- package/dist/gateway/index.js.map +1 -1
- package/dist/index.d.ts +9 -8
- package/dist/index.js +5 -5
- package/dist/{lankaStandardValidator-CL-r-zEV.d.ts → lankaStandardValidator-BUFnysK0.d.ts} +10 -0
- package/dist/locator/index.d.ts +3 -2
- package/dist/scenario/index.d.ts +56 -6
- package/dist/scenario/index.js +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 +8 -7
- package/dist/validation/index.d.ts +7 -4
- package/dist/validation/index.js +5 -3
- package/dist/viewmodel/index.d.ts +101 -13
- package/dist/viewmodel/index.js +90 -48
- package/dist/viewmodel/index.js.map +1 -1
- package/package.json +11 -3
- package/skills/lanka-core/SKILL.md +68 -1
- package/skills/lanka-core/reference.md +312 -6
- package/skills/lanka-packages/SKILL.md +1 -1
- package/dist/chunk-ECM2HZHS.js.map +0 -1
- package/dist/chunk-GV5DUYST.js +0 -64
- package/dist/chunk-GV5DUYST.js.map +0 -1
- package/dist/chunk-Q7QESSYF.js.map +0 -1
- package/dist/chunk-UGXSGQPW.js.map +0 -1
- /package/dist/{chunk-GK3E4CVW.js.map → chunk-5MAQVBI2.js.map} +0 -0
- /package/dist/{chunk-73IVH3C6.js.map → chunk-NDCJBO47.js.map} +0 -0
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
**◆ core** · Core
|
|
4
4
|
|
|
5
|
-
>
|
|
5
|
+
> Fourteen subsystems, two peer dependencies, five extension points.
|
|
6
6
|
|
|
7
7
|
One, unscoped. Everything depends on it; it depends on nothing.
|
|
8
8
|
|
|
@@ -44,6 +44,8 @@ the seal on `internal`, and catches a subsystem added as a folder and forgotten
|
|
|
44
44
|
- `src/locator/`
|
|
45
45
|
- `src/gateway/`
|
|
46
46
|
- `src/validation/`
|
|
47
|
+
- `src/cache/`
|
|
48
|
+
- `src/storage/`
|
|
47
49
|
- `src/mock/`
|
|
48
50
|
- `src/errors/`
|
|
49
51
|
- `src/scenario/`
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A failure with an ADDRESS: which input it belongs to, and what to say there.
|
|
3
|
+
*
|
|
4
|
+
* `issues` on `LankaError` flattens the address into the text — `items.1.qty:
|
|
5
|
+
* only 2 left` — which is right for a banner and useless for a form, which has
|
|
6
|
+
* a place per input and must find it. The path here stays in segments because
|
|
7
|
+
* the two form libraries this was designed against spell the same address
|
|
8
|
+
* differently (`items.1.qty` and `items[1].qty`) and neither can be parsed back
|
|
9
|
+
* out of a string safely: a message may contain a colon, a key may contain a
|
|
10
|
+
* dot.
|
|
11
|
+
*
|
|
12
|
+
* Produced by the validation port from a schema's issues, and by an
|
|
13
|
+
* application's request policy from a server body. Consumed by a ViewModel,
|
|
14
|
+
* which hands it to whatever holds the fields — its own state, or a form.
|
|
15
|
+
*/
|
|
16
|
+
interface ILankaFieldError {
|
|
17
|
+
/**
|
|
18
|
+
* Segments, never a joined string: `["items", 1, "qty"]`.
|
|
19
|
+
*
|
|
20
|
+
* A segment is a name or an index and nothing else — a producer holding a
|
|
21
|
+
* symbol stringifies it, because no form can address one. EMPTY means the
|
|
22
|
+
* value as a whole: a cross-field refusal ("the dates are in the wrong
|
|
23
|
+
* order"), or a body that was not the expected shape at all. That is the
|
|
24
|
+
* form's ROOT, and an adapter routes it there rather than to an input named
|
|
25
|
+
* `""`.
|
|
26
|
+
*/
|
|
27
|
+
readonly path: readonly (string | number)[];
|
|
28
|
+
/** What to show at that address when the application does not translate. */
|
|
29
|
+
readonly message: string;
|
|
30
|
+
/** The machine-readable reason, when the producer had one — what i18n keys on. */
|
|
31
|
+
readonly code?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type { ILankaFieldError as I };
|
|
@@ -345,10 +345,11 @@ interface ILankaScenario<TData = void> {
|
|
|
345
345
|
/**
|
|
346
346
|
* A ViewModel that participates in scenarios.
|
|
347
347
|
*
|
|
348
|
-
* Not every ViewModel does: one with no `scenarioHandlers`
|
|
349
|
-
*
|
|
350
|
-
* `LankaScenarioBootstrap` calls on those that
|
|
351
|
-
* scenario rather than ViewModel
|
|
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.
|
|
352
353
|
*
|
|
353
354
|
* Both are idempotent by contract: bootstrap may run after a ViewModel has
|
|
354
355
|
* already initialised itself, and a reset may arrive for one that never did.
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { I as ILankaFieldError } from './ILankaFieldError-D5931-vT.js';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Structural API-error shape read by consumer code.
|
|
3
5
|
*
|
|
@@ -42,6 +44,14 @@ interface ILankaErrorInit {
|
|
|
42
44
|
code?: string;
|
|
43
45
|
/** Details: server messages, or paths to the fields that failed validation. */
|
|
44
46
|
issues?: readonly string[];
|
|
47
|
+
/**
|
|
48
|
+
* The failures that have an input to be shown at, with the path in segments.
|
|
49
|
+
*
|
|
50
|
+
* Beside `issues` rather than instead of it: `issues` is the banner's list and
|
|
51
|
+
* is promised; this is the form's, and a failure may have either, both or
|
|
52
|
+
* neither. Absent means "nothing here has an address", not "unknown".
|
|
53
|
+
*/
|
|
54
|
+
fields?: readonly ILankaFieldError[];
|
|
45
55
|
/**
|
|
46
56
|
* The parsed ERROR response body, when there was one and it was JSON.
|
|
47
57
|
*
|
|
@@ -72,6 +82,14 @@ declare class LankaError extends Error implements ILankaApiError {
|
|
|
72
82
|
readonly status?: number;
|
|
73
83
|
readonly code?: string;
|
|
74
84
|
readonly issues?: readonly string[];
|
|
85
|
+
/**
|
|
86
|
+
* The failures with an input to be shown at. See `ILankaErrorInit.fields`.
|
|
87
|
+
*
|
|
88
|
+
* The array given is the array kept — unlike `errors`, which copies `issues`
|
|
89
|
+
* on every read. `readonly` carries the promise, and this is read on the way
|
|
90
|
+
* to a form, once, where a copy would buy nothing.
|
|
91
|
+
*/
|
|
92
|
+
readonly fields?: readonly ILankaFieldError[];
|
|
75
93
|
/** The parsed error response body; core carries it without reading it. */
|
|
76
94
|
readonly body?: unknown;
|
|
77
95
|
constructor(init: ILankaErrorInit);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as ILankaScenario, I as ILankaScenarioVM } from './ILankaScenarioVM-
|
|
2
|
-
import { I as ILankaScenarioMetadata } from './ILankaScenarioMetadata-
|
|
3
|
-
import { A as ALankaGateway } from './ALankaGateway-
|
|
1
|
+
import { a as ILankaScenario, I as ILankaScenarioVM } from './ILankaScenarioVM-DpKFL3iE.js';
|
|
2
|
+
import { I as ILankaScenarioMetadata } from './ILankaScenarioMetadata-Dj4GCqmX.js';
|
|
3
|
+
import { A as ALankaGateway } from './ALankaGateway-BrVPaZN5.js';
|
|
4
4
|
import { A as ALankaLocator } from './LankaSharedStoreLocator-zS2kLu-S.js';
|
|
5
5
|
|
|
6
6
|
/**
|
package/dist/_extend/index.d.ts
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
export { L as LankaGatewayLocator, a as LankaScenarioLocator, b as LankaScenarioVMRegistry, c as LankaScenariosRegistry } from '../LankaScenarioLocator-
|
|
1
|
+
export { L as LankaGatewayLocator, a as LankaScenarioLocator, b as LankaScenarioVMRegistry, c as LankaScenariosRegistry } from '../LankaScenarioLocator-CAENLhDO.js';
|
|
2
2
|
import { a as ILankaLocator } from '../LankaSharedStoreLocator-zS2kLu-S.js';
|
|
3
3
|
export { A as ALankaLocator, L as LankaSharedStoreLocator, b as LankaSingletonLocator } from '../LankaSharedStoreLocator-zS2kLu-S.js';
|
|
4
4
|
export { c as createLankaScope } from '../createLankaScope-BiFxNQgl.js';
|
|
5
5
|
export { c as composeLankaRequestMiddleware } from '../lankaRequestMiddleware-DAC5kCb7.js';
|
|
6
|
-
import '../ILankaScenarioVM-
|
|
7
|
-
import '../ILankaScenarioMetadata-
|
|
8
|
-
import '../ALankaGateway-
|
|
9
|
-
import '../lankaStandardValidator-
|
|
6
|
+
import '../ILankaScenarioVM-DpKFL3iE.js';
|
|
7
|
+
import '../ILankaScenarioMetadata-Dj4GCqmX.js';
|
|
8
|
+
import '../ALankaGateway-BrVPaZN5.js';
|
|
9
|
+
import '../lankaStandardValidator-BUFnysK0.js';
|
|
10
10
|
import '@standard-schema/spec';
|
|
11
|
+
import '../ILankaFieldError-D5931-vT.js';
|
|
11
12
|
import '../ALankaSharedStore-B7uepuuk.js';
|
|
12
13
|
import 'zustand/vanilla';
|
|
13
14
|
|
package/dist/_extend/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
LankaGatewayLocator,
|
|
3
3
|
LankaScenarioLocator,
|
|
4
4
|
createLankaScope
|
|
5
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-5MAQVBI2.js";
|
|
6
6
|
import {
|
|
7
7
|
LankaScenarioVMRegistry,
|
|
8
8
|
LankaScenariosRegistry
|
|
@@ -10,8 +10,6 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
composeLankaRequestMiddleware
|
|
12
12
|
} from "../chunk-YR4MZXMU.js";
|
|
13
|
-
import "../chunk-C2HP7CRD.js";
|
|
14
|
-
import "../chunk-D27MREPB.js";
|
|
15
13
|
import {
|
|
16
14
|
createLankaLocatorProxy
|
|
17
15
|
} from "../chunk-DTO27QFR.js";
|
|
@@ -20,6 +18,8 @@ import {
|
|
|
20
18
|
LankaSharedStoreLocator,
|
|
21
19
|
LankaSingletonLocator
|
|
22
20
|
} from "../chunk-UE2C76OR.js";
|
|
21
|
+
import "../chunk-C2HP7CRD.js";
|
|
22
|
+
import "../chunk-D27MREPB.js";
|
|
23
23
|
import "../chunk-BGVDPDX4.js";
|
|
24
24
|
export {
|
|
25
25
|
ALankaLocator,
|
|
@@ -1,19 +1,72 @@
|
|
|
1
|
-
export { I as ILankaRuntime, T as TLankaRuntimeResolver, s as setLankaRuntimeResolver } from '../activeRuntime-
|
|
2
|
-
import '../
|
|
3
|
-
import '../
|
|
4
|
-
import '../
|
|
5
|
-
import '../
|
|
6
|
-
import '../
|
|
7
|
-
import '@standard-schema/spec';
|
|
1
|
+
export { I as ILankaRuntime, T as TLankaRuntimeResolver, s as setLankaRuntimeResolver } from '../activeRuntime-BYd2D6Lx.js';
|
|
2
|
+
import { a as TLankaValidationResult } from '../lankaStandardValidator-BUFnysK0.js';
|
|
3
|
+
import '../ILankaScenarioVM-DpKFL3iE.js';
|
|
4
|
+
import '../LankaScenarioLocator-CAENLhDO.js';
|
|
5
|
+
import '../ILankaScenarioMetadata-Dj4GCqmX.js';
|
|
6
|
+
import '../ALankaGateway-BrVPaZN5.js';
|
|
8
7
|
import '../LankaSharedStoreLocator-zS2kLu-S.js';
|
|
9
8
|
import '../ALankaSharedStore-B7uepuuk.js';
|
|
10
9
|
import 'zustand/vanilla';
|
|
11
10
|
import '../ILankaRuntimeConfig-Vl436GWK.js';
|
|
12
11
|
import '../lankaHttpInFlight-Bk1eIuSx.js';
|
|
13
12
|
import '../lankaRequestMiddleware-DAC5kCb7.js';
|
|
13
|
+
import '@standard-schema/spec';
|
|
14
|
+
import '../ILankaFieldError-D5931-vT.js';
|
|
14
15
|
|
|
15
16
|
declare function generateUuid(): string;
|
|
16
17
|
|
|
18
|
+
/**
|
|
19
|
+
* What to say when a validator is handed a schema from another library.
|
|
20
|
+
*
|
|
21
|
+
* ## Why this is not three sentences in three packages
|
|
22
|
+
*
|
|
23
|
+
* `@lankajs/yup`, `@lankajs/typebox` and `@lankajs/effect` each refuse a schema
|
|
24
|
+
* they do not own, and each has to answer the same follow-up: is this a schema at
|
|
25
|
+
* all, and if so whose? The answer is identical in all three because the
|
|
26
|
+
* SITUATION is identical — only the lead differs, because only the marker each
|
|
27
|
+
* looked for differs.
|
|
28
|
+
*
|
|
29
|
+
* Written three times it was three copies, and `check:composition` said so. Made
|
|
30
|
+
* deliberately different to satisfy the gate it would have been worse: three
|
|
31
|
+
* wordings of one fact, and a consumer who met two of them would be entitled to
|
|
32
|
+
* think they meant different things.
|
|
33
|
+
*
|
|
34
|
+
* ## Why `lanka/internal` and not the facade
|
|
35
|
+
*
|
|
36
|
+
* This tier exists for exactly this: "a sibling package needs these and must not
|
|
37
|
+
* reach into another package's `src/`". It promises nothing beyond a patch, which
|
|
38
|
+
* is the right promise for a sentence.
|
|
39
|
+
*
|
|
40
|
+
* A facade `isStandardSchema` was proposed first and refused, for a reason worth
|
|
41
|
+
* keeping: it would answer `true` for every yup schema, and `lankaStandardValidator`
|
|
42
|
+
* throws on every yup schema. A consumer writing `if (isStandardSchema(s))
|
|
43
|
+
* validate(s, …)` would have written the exact bug the family works to prevent,
|
|
44
|
+
* and the name would have told them it was safe.
|
|
45
|
+
*/
|
|
46
|
+
declare const lankaForeignSchemaMessage: (schema: unknown, { lead }: {
|
|
47
|
+
lead: string;
|
|
48
|
+
}) => string;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* The strict path, built from the safe one.
|
|
52
|
+
*
|
|
53
|
+
* `ILankaValidator` publishes two methods over one answer: `validateSafe`
|
|
54
|
+
* returns an outcome, and `validate` is that outcome with the failure raised.
|
|
55
|
+
* Every implementation of the port therefore writes the same five lines, and
|
|
56
|
+
* three of them in this repository did — `check:composition` counted them.
|
|
57
|
+
*
|
|
58
|
+
* It is a GENERIC over the outcome rather than a helper returning `unknown`,
|
|
59
|
+
* which is the whole reason it can be shared: `@lankajs/typebox` returns
|
|
60
|
+
* `Static<TSchema>` and `@lankajs/effect` returns `Schema.Schema.Type<TAlias>`,
|
|
61
|
+
* and a helper that erased those would have cost each package its inference —
|
|
62
|
+
* a worse trade than the duplication it removed.
|
|
63
|
+
*
|
|
64
|
+
* `lanka/internal` because a sibling package needs it and must not reach into
|
|
65
|
+
* core's `src/`. It promises nothing beyond a patch, which is right for five
|
|
66
|
+
* lines that only restate what the port already says.
|
|
67
|
+
*/
|
|
68
|
+
declare const lankaValueOrThrow: <TOutput>(result: TLankaValidationResult<TOutput>, context: string) => TOutput;
|
|
69
|
+
|
|
17
70
|
/**
|
|
18
71
|
* Reads `key` from a record and returns it only if the value is a string.
|
|
19
72
|
* Returns `undefined` for missing or non-string values.
|
|
@@ -40,4 +93,4 @@ declare const getStringField: (data: Record<string, unknown>, key: string) => st
|
|
|
40
93
|
*/
|
|
41
94
|
declare const isRecord: (value: unknown) => value is Record<string, unknown>;
|
|
42
95
|
|
|
43
|
-
export { generateUuid, getStringField, isRecord };
|
|
96
|
+
export { generateUuid, getStringField, isRecord, lankaForeignSchemaMessage, lankaValueOrThrow };
|
package/dist/_internal/index.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
LankaValidationError
|
|
3
|
+
} from "../chunk-CRIRTOLB.js";
|
|
1
4
|
import {
|
|
2
5
|
getStringField,
|
|
3
6
|
isRecord
|
|
4
7
|
} from "../chunk-J5LA3Q6D.js";
|
|
8
|
+
import "../chunk-G32H73QY.js";
|
|
5
9
|
import {
|
|
6
10
|
setLankaRuntimeResolver
|
|
7
11
|
} from "../chunk-BGVDPDX4.js";
|
|
@@ -25,10 +29,31 @@ function generateUuid() {
|
|
|
25
29
|
return (c === "x" ? r : r & 3 | 8).toString(16);
|
|
26
30
|
});
|
|
27
31
|
}
|
|
32
|
+
|
|
33
|
+
// src/_internal/lanka-foreign-schema-message/lankaForeignSchemaMessage.ts
|
|
34
|
+
var lankaForeignSchemaMessage = (schema, { lead }) => {
|
|
35
|
+
const indexable = schema !== null && (typeof schema === "object" || typeof schema === "function");
|
|
36
|
+
if (indexable && "~standard" in schema) {
|
|
37
|
+
return `${lead} It does carry \`~standard\`, so it belongs to another library in \`modules/validators/\` \u2014 validate it with that package's validator, or with \`lankaStandardValidator\`.`;
|
|
38
|
+
}
|
|
39
|
+
return `${lead} Either it is not a schema at all, or it belongs to a library with its own package in \`modules/validators/\`.`;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
// src/_internal/lanka-value-or-throw/lankaValueOrThrow.ts
|
|
43
|
+
var lankaValueOrThrow = (result, context) => {
|
|
44
|
+
if (result.success) return result.data;
|
|
45
|
+
throw new LankaValidationError(
|
|
46
|
+
`Validation failed for ${context}`,
|
|
47
|
+
result.errors,
|
|
48
|
+
result.fields
|
|
49
|
+
);
|
|
50
|
+
};
|
|
28
51
|
export {
|
|
29
52
|
generateUuid,
|
|
30
53
|
getStringField,
|
|
31
54
|
isRecord,
|
|
55
|
+
lankaForeignSchemaMessage,
|
|
56
|
+
lankaValueOrThrow,
|
|
32
57
|
setLankaRuntimeResolver
|
|
33
58
|
};
|
|
34
59
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/_internal/generate-uuid/generateUuid.ts"],"sourcesContent":["export function generateUuid() {\n\tif (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n\t\treturn crypto.randomUUID();\n\t}\n\n\tlet d = new Date().getTime();\n\n\tlet d2 =\n\t\t(typeof performance !== \"undefined\" && performance.now && performance.now() * 1000) || 0;\n\n\treturn \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\n\t\tlet r = Math.random() * 16;\n\n\t\tif (d > 0) {\n\t\t\tr = ((d + r) % 16) | 0;\n\t\t\td = Math.floor(d / 16);\n\t\t} else {\n\t\t\tr = ((d2 + r) % 16) | 0;\n\t\t\td2 = Math.floor(d2 / 16);\n\t\t}\n\n\t\treturn (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n\t});\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../src/_internal/generate-uuid/generateUuid.ts","../../src/_internal/lanka-foreign-schema-message/lankaForeignSchemaMessage.ts","../../src/_internal/lanka-value-or-throw/lankaValueOrThrow.ts"],"sourcesContent":["export function generateUuid() {\n\tif (typeof crypto !== \"undefined\" && typeof crypto.randomUUID === \"function\") {\n\t\treturn crypto.randomUUID();\n\t}\n\n\tlet d = new Date().getTime();\n\n\tlet d2 =\n\t\t(typeof performance !== \"undefined\" && performance.now && performance.now() * 1000) || 0;\n\n\treturn \"xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx\".replace(/[xy]/g, function (c) {\n\t\tlet r = Math.random() * 16;\n\n\t\tif (d > 0) {\n\t\t\tr = ((d + r) % 16) | 0;\n\t\t\td = Math.floor(d / 16);\n\t\t} else {\n\t\t\tr = ((d2 + r) % 16) | 0;\n\t\t\td2 = Math.floor(d2 / 16);\n\t\t}\n\n\t\treturn (c === \"x\" ? r : (r & 0x3) | 0x8).toString(16);\n\t});\n}\n","/**\n * What to say when a validator is handed a schema from another library.\n *\n * ## Why this is not three sentences in three packages\n *\n * `@lankajs/yup`, `@lankajs/typebox` and `@lankajs/effect` each refuse a schema\n * they do not own, and each has to answer the same follow-up: is this a schema at\n * all, and if so whose? The answer is identical in all three because the\n * SITUATION is identical — only the lead differs, because only the marker each\n * looked for differs.\n *\n * Written three times it was three copies, and `check:composition` said so. Made\n * deliberately different to satisfy the gate it would have been worse: three\n * wordings of one fact, and a consumer who met two of them would be entitled to\n * think they meant different things.\n *\n * ## Why `lanka/internal` and not the facade\n *\n * This tier exists for exactly this: \"a sibling package needs these and must not\n * reach into another package's `src/`\". It promises nothing beyond a patch, which\n * is the right promise for a sentence.\n *\n * A facade `isStandardSchema` was proposed first and refused, for a reason worth\n * keeping: it would answer `true` for every yup schema, and `lankaStandardValidator`\n * throws on every yup schema. A consumer writing `if (isStandardSchema(s))\n * validate(s, …)` would have written the exact bug the family works to prevent,\n * and the name would have told them it was safe.\n */\nexport const lankaForeignSchemaMessage = (schema: unknown, { lead }: { lead: string }): string => {\n\t// Object OR function: arktype's schema is callable, with `~standard` on its\n\t// prototype, and a check reading only objects would tell an arktype user\n\t// their schema is not a schema.\n\tconst indexable =\n\t\tschema !== null && (typeof schema === \"object\" || typeof schema === \"function\");\n\n\tif (indexable && \"~standard\" in schema) {\n\t\treturn (\n\t\t\t`${lead} It does carry \\`~standard\\`, so it belongs to another library in ` +\n\t\t\t\"`modules/validators/` — validate it with that package's validator, or with \" +\n\t\t\t\"`lankaStandardValidator`.\"\n\t\t);\n\t}\n\n\treturn (\n\t\t`${lead} Either it is not a schema at all, or it belongs to a library with its ` +\n\t\t\"own package in `modules/validators/`.\"\n\t);\n};\n","import { LankaValidationError } from \"../../validation/lanka-validation-error/LankaValidationError\";\nimport type { TLankaValidationResult } from \"../../validation/_types/TLankaValidationResult\";\n\n/**\n * The strict path, built from the safe one.\n *\n * `ILankaValidator` publishes two methods over one answer: `validateSafe`\n * returns an outcome, and `validate` is that outcome with the failure raised.\n * Every implementation of the port therefore writes the same five lines, and\n * three of them in this repository did — `check:composition` counted them.\n *\n * It is a GENERIC over the outcome rather than a helper returning `unknown`,\n * which is the whole reason it can be shared: `@lankajs/typebox` returns\n * `Static<TSchema>` and `@lankajs/effect` returns `Schema.Schema.Type<TAlias>`,\n * and a helper that erased those would have cost each package its inference —\n * a worse trade than the duplication it removed.\n *\n * `lanka/internal` because a sibling package needs it and must not reach into\n * core's `src/`. It promises nothing beyond a patch, which is right for five\n * lines that only restate what the port already says.\n */\nexport const lankaValueOrThrow = <TOutput>(\n\tresult: TLankaValidationResult<TOutput>,\n\tcontext: string,\n): TOutput => {\n\tif (result.success) return result.data;\n\n\tthrow new LankaValidationError(\n\t\t`Validation failed for ${context}`,\n\t\tresult.errors,\n\t\tresult.fields,\n\t);\n};\n"],"mappings":";;;;;;;;;;;;;AAAO,SAAS,eAAe;AAC9B,MAAI,OAAO,WAAW,eAAe,OAAO,OAAO,eAAe,YAAY;AAC7E,WAAO,OAAO,WAAW;AAAA,EAC1B;AAEA,MAAI,KAAI,oBAAI,KAAK,GAAE,QAAQ;AAE3B,MAAI,KACF,OAAO,gBAAgB,eAAe,YAAY,OAAO,YAAY,IAAI,IAAI,OAAS;AAExF,SAAO,uCAAuC,QAAQ,SAAS,SAAU,GAAG;AAC3E,QAAI,IAAI,KAAK,OAAO,IAAI;AAExB,QAAI,IAAI,GAAG;AACV,WAAM,IAAI,KAAK,KAAM;AACrB,UAAI,KAAK,MAAM,IAAI,EAAE;AAAA,IACtB,OAAO;AACN,WAAM,KAAK,KAAK,KAAM;AACtB,WAAK,KAAK,MAAM,KAAK,EAAE;AAAA,IACxB;AAEA,YAAQ,MAAM,MAAM,IAAK,IAAI,IAAO,GAAK,SAAS,EAAE;AAAA,EACrD,CAAC;AACF;;;ACKO,IAAM,4BAA4B,CAAC,QAAiB,EAAE,KAAK,MAAgC;AAIjG,QAAM,YACL,WAAW,SAAS,OAAO,WAAW,YAAY,OAAO,WAAW;AAErE,MAAI,aAAa,eAAe,QAAQ;AACvC,WACC,GAAG,IAAI;AAAA,EAIT;AAEA,SACC,GAAG,IAAI;AAGT;;;AC1BO,IAAM,oBAAoB,CAChC,QACA,YACa;AACb,MAAI,OAAO,QAAS,QAAO,OAAO;AAElC,QAAM,IAAI;AAAA,IACT,yBAAyB,OAAO;AAAA,IAChC,OAAO;AAAA,IACP,OAAO;AAAA,EACR;AACD;","names":[]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { L as LankaEventBusInstance, I as ILankaScenarioVM } from './ILankaScenarioVM-
|
|
2
|
-
import { c as LankaScenariosRegistry, b as LankaScenarioVMRegistry, L as LankaGatewayLocator, a as LankaScenarioLocator } from './LankaScenarioLocator-
|
|
1
|
+
import { L as LankaEventBusInstance, I as ILankaScenarioVM } from './ILankaScenarioVM-DpKFL3iE.js';
|
|
2
|
+
import { c as LankaScenariosRegistry, b as LankaScenarioVMRegistry, L as LankaGatewayLocator, a as LankaScenarioLocator } from './LankaScenarioLocator-CAENLhDO.js';
|
|
3
3
|
import { b as ILankaRuntimeConfig } from './ILankaRuntimeConfig-Vl436GWK.js';
|
|
4
4
|
import { I as ILankaInFlightCounter } from './lankaHttpInFlight-Bk1eIuSx.js';
|
|
5
5
|
import { T as TLankaRequestMiddleware } from './lankaRequestMiddleware-DAC5kCb7.js';
|
|
@@ -1,14 +1,15 @@
|
|
|
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-NrlvN-WQ.js';
|
|
2
|
+
export { b as ILankaInstanceConfig, d as ILankaScenarioBootstrapConfig, f as createLanka } from '../createLanka-NrlvN-WQ.js';
|
|
3
3
|
import { I as ILankaFlags, a as ILankaHost } from '../ILankaRuntimeConfig-Vl436GWK.js';
|
|
4
4
|
export { I as ILankaScope } from '../createLankaScope-BiFxNQgl.js';
|
|
5
|
-
import '../activeRuntime-
|
|
6
|
-
import '../ILankaScenarioVM-
|
|
7
|
-
import '../LankaScenarioLocator-
|
|
8
|
-
import '../ILankaScenarioMetadata-
|
|
9
|
-
import '../ALankaGateway-
|
|
10
|
-
import '../lankaStandardValidator-
|
|
5
|
+
import '../activeRuntime-BYd2D6Lx.js';
|
|
6
|
+
import '../ILankaScenarioVM-DpKFL3iE.js';
|
|
7
|
+
import '../LankaScenarioLocator-CAENLhDO.js';
|
|
8
|
+
import '../ILankaScenarioMetadata-Dj4GCqmX.js';
|
|
9
|
+
import '../ALankaGateway-BrVPaZN5.js';
|
|
10
|
+
import '../lankaStandardValidator-BUFnysK0.js';
|
|
11
11
|
import '@standard-schema/spec';
|
|
12
|
+
import '../ILankaFieldError-D5931-vT.js';
|
|
12
13
|
import '../LankaSharedStoreLocator-zS2kLu-S.js';
|
|
13
14
|
import '../ALankaSharedStore-B7uepuuk.js';
|
|
14
15
|
import 'zustand/vanilla';
|
package/dist/bootstrap/index.js
CHANGED
|
@@ -3,15 +3,15 @@ import {
|
|
|
3
3
|
createLanka,
|
|
4
4
|
resetActiveLanka,
|
|
5
5
|
startLanka
|
|
6
|
-
} from "../chunk-
|
|
7
|
-
import "../chunk-
|
|
8
|
-
import "../chunk-
|
|
6
|
+
} from "../chunk-UBGXDTXC.js";
|
|
7
|
+
import "../chunk-B7EYIAW7.js";
|
|
8
|
+
import "../chunk-5MAQVBI2.js";
|
|
9
9
|
import "../chunk-O5ROO7QF.js";
|
|
10
10
|
import "../chunk-XESL274R.js";
|
|
11
11
|
import "../chunk-UJEC7H6K.js";
|
|
12
|
+
import "../chunk-UE2C76OR.js";
|
|
12
13
|
import "../chunk-C2HP7CRD.js";
|
|
13
14
|
import "../chunk-D27MREPB.js";
|
|
14
|
-
import "../chunk-UE2C76OR.js";
|
|
15
15
|
import "../chunk-BGVDPDX4.js";
|
|
16
16
|
export {
|
|
17
17
|
ALankaPlugin,
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A resource's address in a read cache: `["order", 7]`, never a joined string.
|
|
3
|
+
*
|
|
4
|
+
* Strings, numbers and booleans only — deliberately narrower than `unknown[]`.
|
|
5
|
+
* `@nanostores/query` accepts `string | number | true` as a key part and cannot
|
|
6
|
+
* carry an object at all, so a wider type here would be a promise the port
|
|
7
|
+
* cannot keep on every implementation. An application that wants to key by a
|
|
8
|
+
* filter object states its parts: `["orders", status, page]`.
|
|
9
|
+
*
|
|
10
|
+
* Two structurally equal keys are the same key. Segments are ordered, so
|
|
11
|
+
* `["order", 1]` and `[1, "order"]` are two resources.
|
|
12
|
+
*/
|
|
13
|
+
type TLankaCacheKey = readonly (string | number | boolean)[];
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* What a ViewModel calls to avoid asking the server twice.
|
|
17
|
+
*
|
|
18
|
+
* A PORT and nothing else: core declares the shape and ships no cache, because
|
|
19
|
+
* a host framework already carries one and two caches disagree on the first
|
|
20
|
+
* mutation. Where there is no host — a plain Vite SPA — the slot is empty rather
|
|
21
|
+
* than taken, and an application fills it with `@lankajs/tanstack-query`,
|
|
22
|
+
* `@lankajs/nanostores-query`, or an implementation of its own.
|
|
23
|
+
*
|
|
24
|
+
* It sits UNDER the ViewModel: the ViewModel calls it, hands it the loader it
|
|
25
|
+
* got from a gateway, and keeps deciding what a failure means. The screen still
|
|
26
|
+
* reads one hook.
|
|
27
|
+
*
|
|
28
|
+
* ## The clauses an implementation must keep
|
|
29
|
+
*
|
|
30
|
+
* Behaviour, not signatures, is where two honest implementations diverge, so
|
|
31
|
+
* each clause below is a promise and most of them are assertions in
|
|
32
|
+
* `@lankajs/tool-testing`'s `lankaReadCacheConformance`. Run it; do not read a
|
|
33
|
+
* member's source.
|
|
34
|
+
*
|
|
35
|
+
* 1. `subscribe` does NOT deliver the current value. Use `peek` for that.
|
|
36
|
+
* 2. `subscribe` delivers only SETTLED data — never a pending or failed state.
|
|
37
|
+
* 3. The release it answers removes exactly its own listener; a second call
|
|
38
|
+
* does nothing.
|
|
39
|
+
* 4. `peek` answers what is cached, stale or not. It never fetches and never
|
|
40
|
+
* throws.
|
|
41
|
+
* 5. `read` answers from memory while fresh; two concurrent reads of one key
|
|
42
|
+
* call `load` once.
|
|
43
|
+
* 6. `read` rejects with EXACTLY what `load` threw. Wrapping it breaks the
|
|
44
|
+
* caller: a ViewModel branches on `LankaError.kind`, and a wrapper turns
|
|
45
|
+
* every failure into the screen's.
|
|
46
|
+
* 7. A failed `read` is not remembered as data; the next one tries again.
|
|
47
|
+
* 8. `invalidate` resolves after the refetch settles when somebody is
|
|
48
|
+
* subscribed, and marks stale without fetching when nobody is.
|
|
49
|
+
* 9. `write` notifies that key's subscribers before it returns.
|
|
50
|
+
* 10. `clear` empties everything and notifies nobody.
|
|
51
|
+
* 11. `cancel` is declared only if it really aborts.
|
|
52
|
+
* 12. Nothing refetches on its own: only `read` and `invalidate` fetch. A
|
|
53
|
+
* background revalidation would change what a form was opened on.
|
|
54
|
+
*
|
|
55
|
+
* Four more cannot be checked from inside an implementation, and belong to
|
|
56
|
+
* whoever wires it: a subscriber must not write the key it observes; on a server
|
|
57
|
+
* the cache is per REQUEST, never a module-level singleton; one client instance
|
|
58
|
+
* per application; and the cache never fetches by itself — the loader comes from
|
|
59
|
+
* a gateway, through a ViewModel.
|
|
60
|
+
*/
|
|
61
|
+
interface ILankaReadCache {
|
|
62
|
+
/**
|
|
63
|
+
* The resource: from memory while fresh, otherwise through `load`.
|
|
64
|
+
*
|
|
65
|
+
* `load` receives a signal only from an implementation that can cancel —
|
|
66
|
+
* hence the optional parameter. One that cannot passes nothing, rather than a
|
|
67
|
+
* signal that can never fire, and `TLankaExecuteOptions.signal` already
|
|
68
|
+
* accepts `undefined`, so the gateway call is written the same way either way.
|
|
69
|
+
*/
|
|
70
|
+
read<TData>(key: TLankaCacheKey, load: (signal?: AbortSignal) => Promise<TData>, options?: {
|
|
71
|
+
staleMs?: number;
|
|
72
|
+
}): Promise<TData>;
|
|
73
|
+
/** What the server just answered, in the DOMAIN shape. Subscribers hear before this returns. */
|
|
74
|
+
write<TData>(key: TLankaCacheKey, data: TData): void;
|
|
75
|
+
/** Marks the resource stale, and reloads it while somebody is listening. */
|
|
76
|
+
invalidate(key: TLankaCacheKey): Promise<void>;
|
|
77
|
+
/** Hears every later change to the resource — not the current value. Answers the release. */
|
|
78
|
+
subscribe(key: TLankaCacheKey, onData: (data: unknown) => void): () => void;
|
|
79
|
+
/** What is cached right now, stale or not. Never fetches. */
|
|
80
|
+
peek<TData>(key: TLankaCacheKey): TData | undefined;
|
|
81
|
+
/** Empties everything — the end of a session. Notifies nobody. */
|
|
82
|
+
clear(): void;
|
|
83
|
+
/**
|
|
84
|
+
* Stops a load in flight: the screen went away.
|
|
85
|
+
*
|
|
86
|
+
* OPTIONAL, because three of the four libraries measured for this port cannot
|
|
87
|
+
* do it — `@nanostores/query` structurally, since no signal reaches its
|
|
88
|
+
* fetcher. Absent means "the request finishes and its answer is discarded",
|
|
89
|
+
* which is wasteful and never wrong. Declaring it as a no-op is worse than
|
|
90
|
+
* omitting it: a caller would believe the request stopped.
|
|
91
|
+
*
|
|
92
|
+
* It belongs to the cache rather than to the ViewModel because the cache owns
|
|
93
|
+
* deduplication — a second reader joins the first's request in flight, and a
|
|
94
|
+
* cancellation by the first would tear it out from under the second.
|
|
95
|
+
*/
|
|
96
|
+
cancel?(key: TLankaCacheKey): void;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export type { ILankaReadCache, TLankaCacheKey };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -2,14 +2,14 @@ import {
|
|
|
2
2
|
ALankaScenario,
|
|
3
3
|
LankaScenariosRegistry
|
|
4
4
|
} from "./chunk-O5ROO7QF.js";
|
|
5
|
-
import {
|
|
6
|
-
lankaLogger
|
|
7
|
-
} from "./chunk-C2HP7CRD.js";
|
|
8
5
|
import {
|
|
9
6
|
ALankaLocator,
|
|
10
7
|
caseConvert,
|
|
11
8
|
findExportedClass
|
|
12
9
|
} from "./chunk-UE2C76OR.js";
|
|
10
|
+
import {
|
|
11
|
+
lankaLogger
|
|
12
|
+
} from "./chunk-C2HP7CRD.js";
|
|
13
13
|
|
|
14
14
|
// src/locator/gateway/lanka-gateway-locator/LankaGatewayLocator.ts
|
|
15
15
|
import * as GatewaysModule from "@lanka_di/Gateways";
|
|
@@ -136,4 +136,4 @@ export {
|
|
|
136
136
|
LankaScenarioLocator,
|
|
137
137
|
createLankaScope
|
|
138
138
|
};
|
|
139
|
-
//# sourceMappingURL=chunk-
|
|
139
|
+
//# sourceMappingURL=chunk-5MAQVBI2.js.map
|
|
@@ -88,6 +88,7 @@ var LankaScenarioBootstrap = class {
|
|
|
88
88
|
const scenarios = registry.getAllScenarios();
|
|
89
89
|
this.registerScenarioEvents(scenarios);
|
|
90
90
|
this.state.bootstrapped = true;
|
|
91
|
+
this.adoptDeclaredViewModels();
|
|
91
92
|
this.initializeAlreadyCreatedViewModels();
|
|
92
93
|
lankaLogger.printScenarioLog("BOOTSTRAP SCENARIOS FINISH");
|
|
93
94
|
}
|
|
@@ -122,8 +123,27 @@ var LankaScenarioBootstrap = class {
|
|
|
122
123
|
* to.
|
|
123
124
|
*/
|
|
124
125
|
declaredViewModels = [];
|
|
125
|
-
/**
|
|
126
|
+
/**
|
|
127
|
+
* Registers everything declared into a NEW instance.
|
|
128
|
+
*
|
|
129
|
+
* Called twice, and the second call is the one that makes this work on a
|
|
130
|
+
* server: `createLanka` calls it, and so does `bootstrap()`.
|
|
131
|
+
*
|
|
132
|
+
* The reason is an order nobody can change. Where "which instance is active"
|
|
133
|
+
* is answered by a RESOLVER — one instance per request, the shape
|
|
134
|
+
* `@lankajs/host` installs — an instance becomes findable only once the CALLER
|
|
135
|
+
* has put it in its store, and a caller can only do that after `createLanka`
|
|
136
|
+
* has returned. So during creation the answer is honestly "none", and asking
|
|
137
|
+
* for it threw: every server render of an application with a module-level
|
|
138
|
+
* ViewModel failed inside the call that was creating the scope, with a message
|
|
139
|
+
* about running outside one.
|
|
140
|
+
*
|
|
141
|
+
* Skipping is safe precisely because bootstrap adopts again. It is idempotent
|
|
142
|
+
* at the other end too: `attachViewModel` returns early for a ViewModel the
|
|
143
|
+
* registry already holds.
|
|
144
|
+
*/
|
|
126
145
|
adoptDeclaredViewModels() {
|
|
146
|
+
if (!getActiveRuntime()) return;
|
|
127
147
|
for (const { viewModel, name } of [...this.declaredViewModels]) {
|
|
128
148
|
this.attachViewModel(viewModel, name);
|
|
129
149
|
}
|
|
@@ -162,14 +182,30 @@ var LankaScenarioBootstrap = class {
|
|
|
162
182
|
* the ViewModel registry together with all their subscriptions, and the bus —
|
|
163
183
|
* events and
|
|
164
184
|
* middleware.
|
|
185
|
+
*
|
|
186
|
+
* What it does NOT clear by default is which ViewModels were DECLARED, and
|
|
187
|
+
* that default is load-bearing: a module-level ViewModel is built once per
|
|
188
|
+
* process, so the declaration is the only thing that lets a second instance
|
|
189
|
+
* find it. Drop it and its handlers bind to nothing, silently, for the rest of
|
|
190
|
+
* the process — see `declaredViewModels`.
|
|
191
|
+
*
|
|
192
|
+
* `withDeclarations` is for the case that default gets wrong: a suite that
|
|
193
|
+
* builds ViewModels inside test BODIES. Those are declared like any other and
|
|
194
|
+
* nothing un-declares them, so the next bootstrap re-adopts every one ever
|
|
195
|
+
* built and a finished test's handlers run again — against the gateway that
|
|
196
|
+
* test built, which is somebody else's double. Forgetting is not a tombstone:
|
|
197
|
+
* a ViewModel declared again afterwards is adopted again.
|
|
198
|
+
*
|
|
199
|
+
* @param config `withDeclarations` also forgets which ViewModels exist
|
|
165
200
|
*/
|
|
166
|
-
reset() {
|
|
201
|
+
reset(config = {}) {
|
|
167
202
|
ALankaScenario.clearAutoRegisteredScenarios();
|
|
168
203
|
LankaScenariosRegistry.getInstance().clear();
|
|
169
204
|
LankaScenarioVMRegistry.getInstance().resetAll();
|
|
170
205
|
lankaEventBus.clearAllEvents();
|
|
171
206
|
this.state.bootstrapped = false;
|
|
172
207
|
this.state.initialized = /* @__PURE__ */ new WeakSet();
|
|
208
|
+
if (config.withDeclarations) this.declaredViewModels.length = 0;
|
|
173
209
|
}
|
|
174
210
|
};
|
|
175
211
|
var lankaScenarioBootstrap = new LankaScenarioBootstrap();
|
|
@@ -177,4 +213,4 @@ var lankaScenarioBootstrap = new LankaScenarioBootstrap();
|
|
|
177
213
|
export {
|
|
178
214
|
lankaScenarioBootstrap
|
|
179
215
|
};
|
|
180
|
-
//# sourceMappingURL=chunk-
|
|
216
|
+
//# sourceMappingURL=chunk-B7EYIAW7.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/scenario/lanka-scenario-bootstrap/LankaScenarioBootstrap.ts"],"sourcesContent":["import type { ILankaScenario } from \"../_interfaces/ILankaScenario\";\nimport type { ILankaScenarioVM } from \"../_interfaces/ILankaScenarioVM\";\nimport type { ILankaScenarioResetConfig } from \"../_interfaces/ILankaScenarioResetConfig\";\nimport { LankaScenariosRegistry } from \"../_registries/lanka-scenarios-registry/LankaScenariosRegistry\";\nimport { LankaScenarioVMRegistry } from \"../_registries/lanka-scenario-vm-registry/LankaScenarioVMRegistry\";\nimport { ALankaScenario } from \"../_abstractions/lanka-scenario/ALankaScenario\";\nimport { lankaLogger } from \"../../logger/lanka-logger/LankaLogger\";\n\n/**\n * Brings up the scenario layer — deliberately React-free.\n *\n * Two jobs: declare every scenario's events on the bus as early as possible,\n * before the first ViewModel exists; and let a ViewModel raise its own\n * subscriptions at construction.\n *\n * Called from the application entry point before ViewModels are imported.\n */\n\n// The barrel of every scenario class: what keeps bootstrap in step with the list.\nimport * as ScenariosModule from \"@lanka_di/Scenarios\";\nimport { lankaEventBus } from \"../event-bus/_facades/lanka-event-bus/lankaEventBus\";\nimport {\n\tgetActiveRuntime,\n\trequireActiveRuntime,\n} from \"../../_internal/active-runtime/activeRuntime\";\n\n/**\n * Bootstrapping the scenario layer, for callers with no instance in hand.\n *\n * An ordinary class with an ordinary instance: the declared-ViewModel list below\n * is deliberately shared across instances — every test builds a new framework and\n * module-level ViewModels are declared once — so the single instance IS the\n * shared list, and a second one would be a second list nobody adopts.\n */\nexport class LankaScenarioBootstrap {\n\t/**\n\t * The bootstrapped flag and the set of initialised VMs live on the INSTANCE.\n\t *\n\t * As static fields, a second framework in the same process would exit\n\t * `bootstrap()` on someone else's flag — never starting at all, with no symptom\n\t * except that no scenario works.\n\t */\n\tprivate get state() {\n\t\treturn requireActiveRuntime().scenarioState;\n\t}\n\n\tpublic isScenarioLayerBootstrapped(): boolean {\n\t\treturn this.state.bootstrapped;\n\t}\n\n\tprivate forceInstantiateAllScenarios(): void {\n\t\t// Every class the pool already holds an instance of. Constructing it again\n\t\t// would add a second instance to a pool nothing ever drains: each bootstrap\n\t\t// — one per framework instance, one per test — grew it by the whole barrel,\n\t\t// and both `collectAutoRegisteredScenarios` and the locator's fallback walk\n\t\t// it in full.\n\t\tconst pooled = new Set(\n\t\t\tALankaScenario.getAutoRegisteredScenarios().map((scenario) => scenario.constructor),\n\t\t);\n\n\t\tfor (const exported of Object.values(ScenariosModule)) {\n\t\t\t// Only class constructors are relevant.\n\t\t\tif (typeof exported !== \"function\") continue;\n\t\t\tif (pooled.has(exported)) continue;\n\n\t\t\ttry {\n\t\t\t\t// Constructing an ALankaScenario subclass puts it into the\n\t\t\t\t// self-registration pool — see ALankaScenario.\n\t\t\t\tnew (exported as unknown as new () => unknown)();\n\t\t\t} catch {\n\t\t\t\t// Not every export is constructible; skip those.\n\t\t\t}\n\t\t}\n\t}\n\n\tprivate registerScenarioEvents(scenarios: ILankaScenario<unknown>[]): void {\n\t\tconst registeredEventTypes = new Set<string>();\n\n\t\tscenarios.forEach((scenario) => {\n\t\t\tif (!registeredEventTypes.has(scenario.eventType)) {\n\t\t\t\tregisteredEventTypes.add(scenario.eventType);\n\n\t\t\t\tlankaLogger.printScenarioLog(\"REGISTER SCENARIO EVENT\", scenario.name);\n\t\t\t\tlankaEventBus.registerEvent(scenario.eventType, {\n\t\t\t\t\tdataType: scenario.dataTypeName,\n\t\t\t\t\tdescription: `Scenario: ${scenario.name}`,\n\t\t\t\t\tusedBy: [scenario.name],\n\t\t\t\t\tpriority: 0,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\tif (scenario.initialize) {\n\t\t\t\tlankaLogger.printScenarioLog(\"INITIALIZE SCENARIO\", scenario.name);\n\t\t\t\tscenario.initialize();\n\t\t\t}\n\t\t});\n\t}\n\n\tprivate initializeAlreadyCreatedViewModels(): void {\n\t\tconst viewModels = LankaScenarioVMRegistry.getInstance().getAllViewModels();\n\t\tviewModels.forEach((vm) => {\n\t\t\tif (!this.state.initialized.has(vm)) {\n\t\t\t\tthis.state.initialized.add(vm);\n\t\t\t\tvm.initializeScenario();\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * Brings up the scenario layer.\n\t *\n\t * Constructs the scenario classes so they can be collected, declares their\n\t * events on the bus, calls `initialize()` where present, and initialises\n\t * ViewModels that already exist — which happens in tests and under unusual\n\t * import order.\n\t *\n\t * Idempotent.\n\t */\n\tpublic bootstrap(): void {\n\t\tif (this.state.bootstrapped) return;\n\n\t\tlankaLogger.printScenarioLog(\"BOOTSTRAP SCENARIOS START\");\n\n\t\t// Instances must exist, or the registry has nothing to collect.\n\t\tthis.forceInstantiateAllScenarios();\n\n\t\tconst registry = LankaScenariosRegistry.getInstance();\n\t\tregistry.collectAutoRegisteredScenarios();\n\n\t\tconst scenarios = registry.getAllScenarios();\n\t\tthis.registerScenarioEvents(scenarios);\n\n\t\tthis.state.bootstrapped = true;\n\n\t\t// The second adoption. On a server this is the FIRST one that can succeed:\n\t\t// the instance is in its caller's store by now, and creation's attempt was\n\t\t// made before it could be. In a browser it is a no-op — creation adopted\n\t\t// already, and attaching is idempotent.\n\t\tthis.adoptDeclaredViewModels();\n\n\t\t// Some ViewModels may predate bootstrap — in tests, or under unusual import\n\t\t// order; initialise them now.\n\t\tthis.initializeAlreadyCreatedViewModels();\n\n\t\tlankaLogger.printScenarioLog(\"BOOTSTRAP SCENARIOS FINISH\");\n\t}\n\n\t/**\n\t * Called by a ViewModel factory when the ViewModel declares scenario handlers.\n\t *\n\t * Registers the ViewModel and, if the layer is already up, initialises it\n\t * immediately. Duplicate registration and duplicate initialisation are\n\t * impossible.\n\t *\n\t * @param viewModel What to register\n\t * @param name Name for the log\n\t */\n\t/**\n\t * ViewModels DECLARED in this process.\n\t *\n\t * Module-level deliberately, the same case as the scenario pool: a registry of\n\t * DEFINITIONS, not runtime state. Splitting it between instances would be\n\t * divergence, not isolation — the classes come from the same modules and both\n\t * instances must see one list.\n\t *\n\t * Two reasons it exists:\n\t *\n\t * 1. Declaring a ViewModel is a declaration, not work. A screen file creates it\n\t * at module level, and import order decides whether that happens before or\n\t * after `createLanka()`. Requiring a live instance at declaration time\n\t * requires an import order the consumer does not control.\n\t * 2. Instances come one after another: every test creates its own. The list is\n\t * NOT drained by the first — otherwise the second instance would know no\n\t * module-level ViewModel and its `dispose()` would not remove their\n\t * subscriptions, so a test would receive events the previous one subscribed\n\t * to.\n\t */\n\tprivate readonly declaredViewModels: { viewModel: ILankaScenarioVM; name?: string }[] = [];\n\n\t/**\n\t * Registers everything declared into a NEW instance.\n\t *\n\t * Called twice, and the second call is the one that makes this work on a\n\t * server: `createLanka` calls it, and so does `bootstrap()`.\n\t *\n\t * The reason is an order nobody can change. Where \"which instance is active\"\n\t * is answered by a RESOLVER — one instance per request, the shape\n\t * `@lankajs/host` installs — an instance becomes findable only once the CALLER\n\t * has put it in its store, and a caller can only do that after `createLanka`\n\t * has returned. So during creation the answer is honestly \"none\", and asking\n\t * for it threw: every server render of an application with a module-level\n\t * ViewModel failed inside the call that was creating the scope, with a message\n\t * about running outside one.\n\t *\n\t * Skipping is safe precisely because bootstrap adopts again. It is idempotent\n\t * at the other end too: `attachViewModel` returns early for a ViewModel the\n\t * registry already holds.\n\t */\n\tpublic adoptDeclaredViewModels(): void {\n\t\tif (!getActiveRuntime()) return;\n\n\t\tfor (const { viewModel, name } of [...this.declaredViewModels]) {\n\t\t\tthis.attachViewModel(viewModel, name);\n\t\t}\n\t}\n\n\tpublic registerViewModel(viewModel: ILankaScenarioVM, name?: string): void {\n\t\tconst isKnown = this.declaredViewModels.some(\n\t\t\t(declared) => declared.viewModel === viewModel,\n\t\t);\n\t\tif (!isKnown) this.declaredViewModels.push({ viewModel, name });\n\n\t\t// No instance yet: the declaration came before bootstrap, and whoever\n\t\t// bootstraps will pick it up.\n\t\tif (!getActiveRuntime()) return;\n\n\t\tthis.attachViewModel(viewModel, name);\n\t}\n\n\tprivate attachViewModel(viewModel: ILankaScenarioVM, name?: string): void {\n\t\tconst registry = LankaScenarioVMRegistry.getInstance();\n\n\t\t// Already registered — nothing to do.\n\t\tif (registry.isRegistered(viewModel)) {\n\t\t\tif (name) {\n\t\t\t\tlankaLogger.printViewModelLog(\"VM Already Registered (skipped)\", name);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Register it.\n\t\tregistry.register(viewModel);\n\n\t\tif (name) {\n\t\t\tlankaLogger.printViewModelLog(\"Register Scenario VM\", name);\n\t\t}\n\n\t\t// The layer is already up — initialise it now rather than at the next\n\t\t// bootstrap.\n\t\tif (this.state.bootstrapped) {\n\t\t\tif (!this.state.initialized.has(viewModel)) {\n\t\t\t\tthis.state.initialized.add(viewModel);\n\t\t\t\tviewModel.initializeScenario();\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Resets the whole scenario layer. Without it tests are not isolated.\n\t *\n\t * Clears the self-registration list, the scenario registry with its metadata,\n\t * the ViewModel registry together with all their subscriptions, and the bus —\n\t * events and\n\t * middleware.\n\t *\n\t * What it does NOT clear by default is which ViewModels were DECLARED, and\n\t * that default is load-bearing: a module-level ViewModel is built once per\n\t * process, so the declaration is the only thing that lets a second instance\n\t * find it. Drop it and its handlers bind to nothing, silently, for the rest of\n\t * the process — see `declaredViewModels`.\n\t *\n\t * `withDeclarations` is for the case that default gets wrong: a suite that\n\t * builds ViewModels inside test BODIES. Those are declared like any other and\n\t * nothing un-declares them, so the next bootstrap re-adopts every one ever\n\t * built and a finished test's handlers run again — against the gateway that\n\t * test built, which is somebody else's double. Forgetting is not a tombstone:\n\t * a ViewModel declared again afterwards is adopted again.\n\t *\n\t * @param config `withDeclarations` also forgets which ViewModels exist\n\t */\n\tpublic reset(config: ILankaScenarioResetConfig = {}): void {\n\t\tALankaScenario.clearAutoRegisteredScenarios();\n\t\tLankaScenariosRegistry.getInstance().clear();\n\t\tLankaScenarioVMRegistry.getInstance().resetAll();\n\t\tlankaEventBus.clearAllEvents();\n\t\tthis.state.bootstrapped = false;\n\t\tthis.state.initialized = new WeakSet<ILankaScenarioVM>();\n\n\t\tif (config.withDeclarations) this.declaredViewModels.length = 0;\n\t}\n}\n\n/** The one every caller wants. */\nexport const lankaScenarioBootstrap = new LankaScenarioBootstrap();\n"],"mappings":"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","names":[]}
|