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 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,43 @@
1
+ export { I as ILankaRuntime, T as TLankaRuntimeResolver, s as setLankaRuntimeResolver } from '../activeRuntime-FcsSJvUg.js';
2
+ import '../ILankaScenarioVM-DuCyPoyT.js';
3
+ import '../LankaScenarioLocator-BGQHwf3n.js';
4
+ import '../ILankaScenarioMetadata-Bu-yggTZ.js';
5
+ import '../ALankaGateway-ExlRGT3D.js';
6
+ import '../lankaStandardValidator-CL-r-zEV.js';
7
+ import '@standard-schema/spec';
8
+ import '../LankaSharedStoreLocator-MvCpav5F.js';
9
+ import '../ALankaSharedStore-B7uepuuk.js';
10
+ import 'zustand/vanilla';
11
+ import '../ILankaRuntimeConfig-Vl436GWK.js';
12
+ import '../lankaHttpInFlight-Bk1eIuSx.js';
13
+ import '../lankaRequestMiddleware-DAC5kCb7.js';
14
+
15
+ declare function generateUuid(): string;
16
+
17
+ /**
18
+ * Reads `key` from a record and returns it only if the value is a string.
19
+ * Returns `undefined` for missing or non-string values.
20
+ *
21
+ * Use when narrowing `Record<string, unknown>` payloads (SSE events,
22
+ * error response bodies, etc.) without `as` casts. Does NOT filter
23
+ * empty strings — callers that need non-empty values should check
24
+ * `.trim().length > 0` explicitly.
25
+ *
26
+ * Absorbed with {@link isRecord}, for the same reason.
27
+ */
28
+ declare const getStringField: (data: Record<string, unknown>, key: string) => string | undefined;
29
+
30
+ /**
31
+ * Type-guard: narrows `unknown` to `Record<string, unknown>`.
32
+ * Excludes `null`, primitives, and arrays-as-keys (arrays still satisfy
33
+ * `typeof === "object"`, but they're rarely the target — callers that need
34
+ * to exclude arrays should add `!Array.isArray(value)`).
35
+ *
36
+ * ABSORBED into this package when the layer was extracted: it lived in an
37
+ * application, and a package cannot import its consumer. An application
38
+ * re-exports this one rather than keeping a copy — two implementations of a
39
+ * three-line guard is how they end up disagreeing about `null`.
40
+ */
41
+ declare const isRecord: (value: unknown) => value is Record<string, unknown>;
42
+
43
+ export { generateUuid, getStringField, isRecord };
@@ -0,0 +1,34 @@
1
+ import {
2
+ getStringField,
3
+ isRecord
4
+ } from "../chunk-J5LA3Q6D.js";
5
+ import {
6
+ setLankaRuntimeResolver
7
+ } from "../chunk-BGVDPDX4.js";
8
+
9
+ // src/_internal/generate-uuid/generateUuid.ts
10
+ function generateUuid() {
11
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
12
+ return crypto.randomUUID();
13
+ }
14
+ let d = (/* @__PURE__ */ new Date()).getTime();
15
+ let d2 = typeof performance !== "undefined" && performance.now && performance.now() * 1e3 || 0;
16
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
17
+ let r = Math.random() * 16;
18
+ if (d > 0) {
19
+ r = (d + r) % 16 | 0;
20
+ d = Math.floor(d / 16);
21
+ } else {
22
+ r = (d2 + r) % 16 | 0;
23
+ d2 = Math.floor(d2 / 16);
24
+ }
25
+ return (c === "x" ? r : r & 3 | 8).toString(16);
26
+ });
27
+ }
28
+ export {
29
+ generateUuid,
30
+ getStringField,
31
+ isRecord,
32
+ setLankaRuntimeResolver
33
+ };
34
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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":";;;;;;;;;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;","names":[]}
@@ -0,0 +1,84 @@
1
+ import { L as LankaEventBusInstance, I as ILankaScenarioVM } from './ILankaScenarioVM-DuCyPoyT.js';
2
+ import { c as LankaScenariosRegistry, b as LankaScenarioVMRegistry, L as LankaGatewayLocator, a as LankaScenarioLocator } from './LankaScenarioLocator-BGQHwf3n.js';
3
+ import { b as ILankaRuntimeConfig } from './ILankaRuntimeConfig-Vl436GWK.js';
4
+ import { I as ILankaInFlightCounter } from './lankaHttpInFlight-Bk1eIuSx.js';
5
+ import { T as TLankaRequestMiddleware } from './lankaRequestMiddleware-DAC5kCb7.js';
6
+ import { b as LankaSingletonLocator, L as LankaSharedStoreLocator } from './LankaSharedStoreLocator-MvCpav5F.js';
7
+
8
+ /**
9
+ * The pointer to the framework instance that ambient facades resolve to.
10
+ *
11
+ * ## Why this module is separate and imports no value
12
+ *
13
+ * Framework state belongs to an instance (`createLanka`), but the callers of
14
+ * `lankaEventBus.dispatch`, `getLankaFlags()`, `lankaSingletons.foo`, `lankaHttpInFlight` —
15
+ * the ambient facades cannot hold one — a user-extended `ALankaScenario`, the
16
+ * static `LankaScenarioBootstrap` — so they ask which instance is active.
17
+ *
18
+ * The module is dependency-free DELIBERATELY: every import here is `import type`
19
+ * and disappears at compile time. Otherwise there would be a cycle
20
+ * `createLanka → locator → gateway → config → createLanka`, and module
21
+ * evaluation order would start deciding what ends up `undefined`.
22
+ *
23
+ * This is still a global pointer. Real isolation belongs to whoever holds an
24
+ * instance: their own bus, registries and counter. The facades serve ONE active
25
+ * instance — exactly what an application with one needs.
26
+ */
27
+ interface ILankaRuntime {
28
+ readonly eventBus: LankaEventBusInstance;
29
+ readonly scenarios: LankaScenariosRegistry;
30
+ readonly viewModels: LankaScenarioVMRegistry;
31
+ readonly inFlight: ILankaInFlightCounter;
32
+ /**
33
+ * Request wrappers, in registration order: the first wraps them all.
34
+ *
35
+ * An array, not a set: order carries meaning — retry must sit outside request
36
+ * signing, or the second attempt goes out unsigned.
37
+ */
38
+ readonly requestMiddleware: readonly TLankaRequestMiddleware[];
39
+ /** Default response deadline. `undefined` means no limit. */
40
+ readonly requestTimeoutMs: number | undefined;
41
+ readonly locators: {
42
+ readonly gateways: LankaGatewayLocator;
43
+ readonly scenarios: LankaScenarioLocator;
44
+ readonly singletons: LankaSingletonLocator;
45
+ readonly sharedStores: LankaSharedStoreLocator;
46
+ };
47
+ readonly config: ILankaRuntimeConfig;
48
+ /**
49
+ * Bootstrap state of the scenario layer.
50
+ *
51
+ * A mutable object rather than contract fields: `LankaScenarioBootstrap` is an
52
+ * ambient facade and must write here without holding an instance.
53
+ */
54
+ readonly scenarioState: {
55
+ bootstrapped: boolean;
56
+ initialized: WeakSet<ILankaScenarioVM>;
57
+ };
58
+ setConfig(patch: ILankaRuntimeConfig): void;
59
+ getFlags(): NonNullable<ILankaRuntimeConfig["flags"]>;
60
+ }
61
+ /**
62
+ * How "which instance is active" is answered.
63
+ *
64
+ * A strategy, because the answer depends on where the code runs. In a browser
65
+ * there is one instance per document and a module-level pointer IS the answer. In
66
+ * a server process there is one instance per REQUEST, and a module-level pointer
67
+ * is the bug: the last request to start would answer for all of them.
68
+ */
69
+ type TLankaRuntimeResolver = () => ILankaRuntime | null;
70
+ /**
71
+ * Replaces the strategy, or restores the default one with `null`.
72
+ *
73
+ * The installed resolver is the WHOLE answer — the module-level pointer is not
74
+ * consulted behind it. That is deliberate: a fallback would turn "this ran
75
+ * outside a request" from a loud error into one request quietly reading another
76
+ * request's instance, which is the failure this seam exists to make impossible.
77
+ *
78
+ * Core ships no resolver and knows of none. What installs one is a package that
79
+ * knows the shape of a request; core knows only that the question has more than
80
+ * one answer.
81
+ */
82
+ declare function setLankaRuntimeResolver(resolver: TLankaRuntimeResolver | null): void;
83
+
84
+ export { type ILankaRuntime as I, type TLankaRuntimeResolver as T, setLankaRuntimeResolver as s };
@@ -0,0 +1,242 @@
1
+ import { I as ILankaScope } from '../createLankaScope-Bc_vChRs.js';
2
+ import { I as ILankaRuntime } from '../activeRuntime-FcsSJvUg.js';
3
+ import { a as ILankaHost, I as ILankaFlags } from '../ILankaRuntimeConfig-Vl436GWK.js';
4
+ import { T as TLankaRequestMiddleware } from '../lankaRequestMiddleware-DAC5kCb7.js';
5
+ import '../LankaSharedStoreLocator-MvCpav5F.js';
6
+ import '../ALankaSharedStore-B7uepuuk.js';
7
+ import 'zustand/vanilla';
8
+ import '../ILankaScenarioVM-DuCyPoyT.js';
9
+ import '../LankaScenarioLocator-BGQHwf3n.js';
10
+ import '../ILankaScenarioMetadata-Bu-yggTZ.js';
11
+ import '../ALankaGateway-ExlRGT3D.js';
12
+ import '../lankaStandardValidator-CL-r-zEV.js';
13
+ import '@standard-schema/spec';
14
+ import '../lankaHttpInFlight-Bk1eIuSx.js';
15
+
16
+ /**
17
+ * A plugin is an extension core knows by SHAPE rather than by name.
18
+ *
19
+ * ## Plugin versus module
20
+ *
21
+ * A module is called by the application (`app → module`) and core does not know
22
+ * it exists. A plugin sits on the path core itself walks (`app → core → plugin`).
23
+ * The test question: does core need a hook for this to work? No — then it is a
24
+ * module, and making it a plugin costs more, because the hook has to be supported
25
+ * forever.
26
+ *
27
+ * ## Why `install` receives the instance
28
+ *
29
+ * So a plugin has no private route to the framework. Everything it can do comes
30
+ * from the instance it was given, which means two instances in one process (a
31
+ * test beside the app) do not share its configuration.
32
+ */
33
+ interface ILankaPlugin {
34
+ /**
35
+ * The name the plugin is recognised by. Registering the same name twice is
36
+ * rejected: two copies of a retry policy would silently double the request
37
+ * count.
38
+ */
39
+ readonly name: string;
40
+ /**
41
+ * Installation. The returned function removes everything the plugin installed
42
+ * and is called when the plugin is removed and when the instance is disposed.
43
+ */
44
+ install: (lanka: ILankaInstance) => (() => void) | void;
45
+ }
46
+
47
+ /**
48
+ * A framework instance: all framework state in one object.
49
+ *
50
+ * What instance-scoped state buys: two apps in one process (micro-frontends,
51
+ * Storybook beside the app) no longer share a bus, locator caches and mock mode;
52
+ * SSR does not reuse state between different users' requests; and test isolation
53
+ * rests on construction rather than on a global `beforeEach` reaching into
54
+ * internal registries.
55
+ *
56
+ * **Ambient facades** — `lankaEventBus.dispatch`, `lankaSingletons.foo`,
57
+ * `getLankaFlags()`, `lankaHttpInFlight` — resolve THE ONE active instance
58
+ * (`internal/activeRuntime.ts`). Isolation belongs to whoever holds an instance;
59
+ * a facade cannot offer it.
60
+ *
61
+ * One thing stays at module level deliberately: `ALankaScenario` collects
62
+ * constructed scenarios into a static pool. That is a REGISTRY OF DEFINITIONS,
63
+ * not runtime state — the classes come from one `@lanka_di/Scenarios` barrel and
64
+ * both instances must see the same list. Splitting it would be divergence.
65
+ */
66
+ interface ILankaInstance extends ILankaRuntime {
67
+ /**
68
+ * Adds a wrapper around every request. Returns a function that removes it.
69
+ *
70
+ * This is how `@lankajs/plugin-http` installs retry, the idempotency key, the
71
+ * CSRF header and auth refresh.
72
+ */
73
+ useRequestMiddleware(middleware: TLankaRequestMiddleware): () => void;
74
+ /** Default timeout for every request of this instance. */
75
+ setRequestTimeout(timeoutMs: number | undefined): void;
76
+ /** Resolves a service in the root scope — for the instance's whole lifetime. */
77
+ resolve<TInstance>(propertyName: string): TInstance;
78
+ /**
79
+ * Creates a scope: a lifetime shorter than the application's.
80
+ *
81
+ * An object created in a scope goes away with it.
82
+ */
83
+ createScope(): ILankaScope;
84
+ /**
85
+ * Registers a plugin. Returns a function that removes it.
86
+ *
87
+ * The fifth and last extension point. An extension point declared before
88
+ * anything plugs into it describes an imagined need while costing real
89
+ * support, so this one arrived with the FIRST plugin.
90
+ */
91
+ use(plugin: ILankaPlugin): () => void;
92
+ /** Runs services and the scenario layer. Idempotent. */
93
+ bootstrap(config?: ILankaBootstrapConfig): Promise<void>;
94
+ /** Has bootstrap already run? */
95
+ isBootstrapped(): boolean;
96
+ /** Makes this instance the one ambient facades resolve to. */
97
+ activate(): void;
98
+ /**
99
+ * Removes subscriptions, clears registries and, if this instance was active,
100
+ * clears the pointer. Returns the framework to its pre-bootstrap state.
101
+ */
102
+ dispose(): void;
103
+ }
104
+ interface ILankaInstanceConfig {
105
+ host: ILankaHost;
106
+ flags?: ILankaFlags;
107
+ }
108
+ interface ILankaServiceConfig {
109
+ name?: string;
110
+ init: () => void | Promise<void>;
111
+ sync?: boolean;
112
+ priority?: number;
113
+ /**
114
+ * A failure of this service does not abort bootstrap.
115
+ *
116
+ * Without the flag one failed service takes the WHOLE phase with it: the async
117
+ * phase because of `Promise.all`, the sync phase because later tasks never run.
118
+ * Wrapping the failure in a swallowing `try/catch` is worse still — the app
119
+ * starts with a partially executed plan and does not know it.
120
+ */
121
+ optional?: boolean;
122
+ /**
123
+ * How long to wait for the service. Overrunning counts as a failure.
124
+ *
125
+ * Without a deadline a service that never settles holds bootstrap forever and
126
+ * the app never paints its first screen. Failing is more honest than waiting:
127
+ * an optional service is skipped, a required one names itself.
128
+ */
129
+ timeoutMs?: number;
130
+ }
131
+ interface ILankaScenarioBootstrapConfig {
132
+ sync?: boolean;
133
+ priority?: number;
134
+ }
135
+ interface ILankaBootstrapConfig {
136
+ services?: ILankaServiceConfig[];
137
+ scenarios?: ILankaScenarioBootstrapConfig;
138
+ }
139
+ /**
140
+ * Creates an instance and makes it active.
141
+ *
142
+ * Activating on creation is the deliberate default: there is almost always one
143
+ * app and the facades must work immediately. A second instance takes the
144
+ * pointer — the last one created serves the facades. Callers needing another
145
+ * order call `activate()` explicitly.
146
+ */
147
+ declare function createLanka(config: ILankaInstanceConfig): ILankaInstance;
148
+
149
+ /** What `startLanka` takes beyond the host, all of it optional. */
150
+ interface ILankaStartOptions {
151
+ flags?: ILankaFlags;
152
+ /** Installed before bootstrap, in the order given. */
153
+ plugins?: readonly ILankaPlugin[];
154
+ services?: ILankaServiceConfig[];
155
+ scenarios?: ILankaBootstrapConfig["scenarios"];
156
+ }
157
+ /**
158
+ * A whole host, or the pieces of one — but not both.
159
+ *
160
+ * A union rather than three optional fields, so passing `host` AND `apiBaseUrl`
161
+ * is a compile error rather than a silent precedence rule somebody has to look
162
+ * up. Passing neither is fine: an application served from its API's origin, or
163
+ * one whose gateways write whole URLs, has nothing to say here.
164
+ */
165
+ type TLankaStartConfig = ILankaStartOptions & ({
166
+ host: ILankaHost;
167
+ apiBaseUrl?: never;
168
+ messages?: never;
169
+ } | {
170
+ host?: never;
171
+ /** A prefix for every path a gateway builds. Empty by default. */
172
+ apiBaseUrl?: string;
173
+ /** Anything but the base URL, when English is not good enough. */
174
+ messages?: Partial<Omit<ILankaHost, "apiBaseUrl">>;
175
+ });
176
+
177
+ /**
178
+ * A started framework, in one call.
179
+ *
180
+ * ```ts
181
+ * const lanka = await startLanka({ apiBaseUrl: "https://api.example.com" });
182
+ * const sameOrigin = await startLanka(); // nothing to configure yet
183
+ * ```
184
+ *
185
+ * ## What it saves, and what it does not hide
186
+ *
187
+ * `createLanka` already activates the instance it returns, and `bootstrap` already
188
+ * brings up the scenario layer — so an application's whole start-up was two calls
189
+ * and a `for` loop over its plugins. This is those, in the order that works, and
190
+ * nothing else: what comes back is the same `ILankaInstance`, with every method
191
+ * it always had.
192
+ *
193
+ * The order matters and is the reason this exists rather than a paragraph in a
194
+ * guide. Plugins install BEFORE bootstrap, because a plugin that adds a
195
+ * bootstrap service after the plan is built adds it to nothing; and bootstrap is
196
+ * awaited, because a screen rendered against a half-started framework fails in
197
+ * the layer it reaches first rather than where the mistake was.
198
+ *
199
+ * An application that needs something between those steps — registering a
200
+ * singleton whose construction reads a service's result, say — writes the two
201
+ * calls out and keeps this one for the next project.
202
+ */
203
+ declare const startLanka: (config?: TLankaStartConfig) => Promise<ILankaInstance>;
204
+
205
+ /**
206
+ * Resets the active instance, if there is one.
207
+ *
208
+ * What the test kit needs between cases. Silent when there is no instance:
209
+ * "reset nothing" is not an error, and the setup file runs before EVERY test,
210
+ * including those that never bootstrap the framework.
211
+ */
212
+ declare function resetActiveLanka(): void;
213
+
214
+ /**
215
+ * A plugin, written as a class.
216
+ *
217
+ * The functional style is a function returning `{ name, install }`, and it is
218
+ * what the framework's own five plugins use — a plugin is a value handed to
219
+ * `use()`, and the ecosystem writes those as `react()`, `pinia()`,
220
+ * `tsconfigPaths()`.
221
+ *
222
+ * This is the same contract for an application that keeps its plugins as
223
+ * classes: `name` is a field, `install` is a method, and `uninstall` is the
224
+ * teardown the framework calls on removal and on dispose. Nothing above can
225
+ * tell which style wrote it — `use()` sees `ILankaPlugin` either way.
226
+ */
227
+ declare abstract class ALankaPlugin implements ILankaPlugin {
228
+ abstract readonly name: string;
229
+ /** Everything this plugin puts in place. Return nothing if there is nothing to undo. */
230
+ protected abstract onInstall(lanka: ILankaInstance): void;
231
+ /**
232
+ * Removes what `onInstall` put in place.
233
+ *
234
+ * A default that does nothing rather than an abstract member: an abstract one
235
+ * would break every existing subclass the day it was added, and most plugins
236
+ * genuinely have nothing to undo.
237
+ */
238
+ protected onUninstall(): void;
239
+ install(lanka: ILankaInstance): () => void;
240
+ }
241
+
242
+ export { ALankaPlugin, type ILankaBootstrapConfig, type ILankaInstance, type ILankaInstanceConfig, type ILankaPlugin, type ILankaScenarioBootstrapConfig, ILankaScope, type ILankaServiceConfig, type ILankaStartOptions, type TLankaStartConfig, createLanka, resetActiveLanka, startLanka };
@@ -0,0 +1,22 @@
1
+ import {
2
+ ALankaPlugin,
3
+ createLanka,
4
+ resetActiveLanka,
5
+ startLanka
6
+ } from "../chunk-RYFZCAQ3.js";
7
+ import "../chunk-Q3SOVBIJ.js";
8
+ import "../chunk-FIR4XTBL.js";
9
+ import "../chunk-EWVDJYCC.js";
10
+ import "../chunk-XESL274R.js";
11
+ import "../chunk-UJEC7H6K.js";
12
+ import "../chunk-ILQNYQY5.js";
13
+ import "../chunk-C2HP7CRD.js";
14
+ import "../chunk-D27MREPB.js";
15
+ import "../chunk-BGVDPDX4.js";
16
+ export {
17
+ ALankaPlugin,
18
+ createLanka,
19
+ resetActiveLanka,
20
+ startLanka
21
+ };
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,52 @@
1
+ import {
2
+ getStringField,
3
+ isRecord
4
+ } from "./chunk-J5LA3Q6D.js";
5
+ import {
6
+ LankaError
7
+ } from "./chunk-Q7QESSYF.js";
8
+ import {
9
+ getLankaHost
10
+ } from "./chunk-RKYKK6MN.js";
11
+
12
+ // src/errors/_factories/create-lanka-api-error/createLankaApiError.ts
13
+ var createLankaApiError = (status, errors, body) => {
14
+ const errorMessage = errors.length > 0 && errors[0] ? errors[0] : getLankaHost().httpErrorMessage(status);
15
+ return new LankaError({
16
+ kind: "http",
17
+ message: errorMessage,
18
+ status,
19
+ issues: errors.length > 0 ? errors : [errorMessage],
20
+ body
21
+ });
22
+ };
23
+
24
+ // src/errors/handle-lanka-api-error/handleLankaApiError.ts
25
+ var RAW_TEXT_LIMIT = 200;
26
+ var nonEmpty = (body, key) => {
27
+ const value = getStringField(body, key);
28
+ return value !== void 0 && value.trim().length > 0 ? value.trim() : void 0;
29
+ };
30
+ var handleLankaApiError = async (response) => {
31
+ const raw = await response.clone().text().catch(() => "");
32
+ let body;
33
+ if (raw.trim().length > 0) {
34
+ try {
35
+ body = JSON.parse(raw);
36
+ } catch {
37
+ body = void 0;
38
+ }
39
+ }
40
+ const message = (isRecord(body) ? nonEmpty(body, "message") : void 0) ?? (body === void 0 && raw.trim().length > 0 ? raw.trim().slice(0, RAW_TEXT_LIMIT) : void 0);
41
+ throw createLankaApiError(
42
+ response.status,
43
+ message ? [message] : [getLankaHost().httpErrorMessage(response.status)],
44
+ body
45
+ );
46
+ };
47
+
48
+ export {
49
+ createLankaApiError,
50
+ handleLankaApiError
51
+ };
52
+ //# sourceMappingURL=chunk-73IVH3C6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors/_factories/create-lanka-api-error/createLankaApiError.ts","../src/errors/handle-lanka-api-error/handleLankaApiError.ts"],"sourcesContent":["import { getLankaHost } from \"../../../config/get-lanka-host/getLankaHost\";\nimport { LankaError } from \"../../lanka-error/LankaError\";\n\n/**\n * A server failure, named by kind.\n *\n * `http`, not `domain`: core sees only the status and the text. The domain\n * failure code — what the application branches on — is extracted from the body by\n * `@lankajs/plugin-http`, because body formats differ per backend and that is\n * policy, not framework.\n */\nexport const createLankaApiError = (\n\tstatus: number,\n\terrors: string[],\n\tbody?: unknown,\n): LankaError => {\n\tconst errorMessage =\n\t\terrors.length > 0 && errors[0] ? errors[0] : getLankaHost().httpErrorMessage(status);\n\n\treturn new LankaError({\n\t\tkind: \"http\",\n\t\tmessage: errorMessage,\n\t\tstatus,\n\t\tissues: errors.length > 0 ? errors : [errorMessage],\n\t\tbody,\n\t});\n};\n","import { isRecord } from \"../../_internal/_guards/isRecord\";\nimport { getStringField } from \"../../_internal/_guards/getStringField\";\nimport { getLankaHost } from \"../../config/get-lanka-host/getLankaHost\";\nimport { createLankaApiError } from \"../_factories/create-lanka-api-error/createLankaApiError\";\n\n/** The length past which foreign text in a message stops helping. */\nconst RAW_TEXT_LIMIT = 200;\n\nconst nonEmpty = (body: Record<string, unknown>, key: string): string | undefined => {\n\tconst value = getStringField(body, key);\n\treturn value !== undefined && value.trim().length > 0 ? value.trim() : undefined;\n};\n\n/**\n * Normalises ANY unsuccessful response into a `LankaError`.\n *\n * Core does three things: reads the body once, takes `message` from it when it is\n * a string, and attaches the parsed body to the error. That is all.\n *\n * It parses no shapes. Body formats differ per backend, and a framework that\n * knows several knows none — it guesses. Parsing lives in `@lankajs/plugin-http`,\n * where it is configurable; the body travels with the error (`error.body`), so\n * the plugin parses it WITHOUT a second read of the `Response`, which is\n * impossible anyway: a stream is read once.\n *\n * ## Why an unparsed body is `http`, not `schema`\n *\n * The distinction carries a decision. `schema` means \"the response is the wrong\n * shape\" — the contract is broken and retrying is pointless. An ERROR body that\n * could not be parsed is not a broken contract: the server refused deliberately\n * and simply described it differently than expected.\n */\nexport const handleLankaApiError = async (response: Response): Promise<never> => {\n\tconst raw = await response\n\t\t.clone()\n\t\t.text()\n\t\t.catch(() => \"\");\n\n\tlet body: unknown;\n\tif (raw.trim().length > 0) {\n\t\ttry {\n\t\t\tbody = JSON.parse(raw);\n\t\t} catch {\n\t\t\t// A body that is not JSON is still the only description of the failure\n\t\t\t// there is, so it becomes the message rather than being discarded for\n\t\t\t// having the wrong shape.\n\t\t\tbody = undefined;\n\t\t}\n\t}\n\n\tconst message =\n\t\t(isRecord(body) ? nonEmpty(body, \"message\") : undefined) ??\n\t\t(body === undefined && raw.trim().length > 0\n\t\t\t? raw.trim().slice(0, RAW_TEXT_LIMIT)\n\t\t\t: undefined);\n\n\tthrow createLankaApiError(\n\t\tresponse.status,\n\t\tmessage ? [message] : [getLankaHost().httpErrorMessage(response.status)],\n\t\tbody,\n\t);\n};\n"],"mappings":";;;;;;;;;;;;AAWO,IAAM,sBAAsB,CAClC,QACA,QACA,SACgB;AAChB,QAAM,eACL,OAAO,SAAS,KAAK,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,aAAa,EAAE,iBAAiB,MAAM;AAEpF,SAAO,IAAI,WAAW;AAAA,IACrB,MAAM;AAAA,IACN,SAAS;AAAA,IACT;AAAA,IACA,QAAQ,OAAO,SAAS,IAAI,SAAS,CAAC,YAAY;AAAA,IAClD;AAAA,EACD,CAAC;AACF;;;ACpBA,IAAM,iBAAiB;AAEvB,IAAM,WAAW,CAAC,MAA+B,QAAoC;AACpF,QAAM,QAAQ,eAAe,MAAM,GAAG;AACtC,SAAO,UAAU,UAAa,MAAM,KAAK,EAAE,SAAS,IAAI,MAAM,KAAK,IAAI;AACxE;AAqBO,IAAM,sBAAsB,OAAO,aAAuC;AAChF,QAAM,MAAM,MAAM,SAChB,MAAM,EACN,KAAK,EACL,MAAM,MAAM,EAAE;AAEhB,MAAI;AACJ,MAAI,IAAI,KAAK,EAAE,SAAS,GAAG;AAC1B,QAAI;AACH,aAAO,KAAK,MAAM,GAAG;AAAA,IACtB,QAAQ;AAIP,aAAO;AAAA,IACR;AAAA,EACD;AAEA,QAAM,WACJ,SAAS,IAAI,IAAI,SAAS,MAAM,SAAS,IAAI,YAC7C,SAAS,UAAa,IAAI,KAAK,EAAE,SAAS,IACxC,IAAI,KAAK,EAAE,MAAM,GAAG,cAAc,IAClC;AAEJ,QAAM;AAAA,IACL,SAAS;AAAA,IACT,UAAU,CAAC,OAAO,IAAI,CAAC,aAAa,EAAE,iBAAiB,SAAS,MAAM,CAAC;AAAA,IACvE;AAAA,EACD;AACD;","names":[]}
@@ -0,0 +1,29 @@
1
+ // src/_internal/active-runtime/activeRuntime.ts
2
+ var active = null;
3
+ var resolveRuntime = null;
4
+ function setActiveRuntime(runtime) {
5
+ active = runtime;
6
+ }
7
+ function setLankaRuntimeResolver(resolver) {
8
+ resolveRuntime = resolver;
9
+ }
10
+ function getActiveRuntime() {
11
+ return resolveRuntime ? resolveRuntime() : active;
12
+ }
13
+ function requireActiveRuntime() {
14
+ const runtime = resolveRuntime ? resolveRuntime() : active;
15
+ if (!runtime) {
16
+ throw new Error(
17
+ resolveRuntime ? "lanka has no instance for this call. A runtime resolver is installed and answered with none, which on a server means the code ran outside a request scope \u2014 start one, or do this work inside it." : "lanka used before an instance existed. Call createLanka({ host }) and activate it."
18
+ );
19
+ }
20
+ return runtime;
21
+ }
22
+
23
+ export {
24
+ setActiveRuntime,
25
+ setLankaRuntimeResolver,
26
+ getActiveRuntime,
27
+ requireActiveRuntime
28
+ };
29
+ //# sourceMappingURL=chunk-BGVDPDX4.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/_internal/active-runtime/activeRuntime.ts"],"sourcesContent":["import type { LankaEventBusInstance } from \"../../scenario/event-bus/lanka-event-bus-instance/LankaEventBusInstance\";\nimport type { LankaScenariosRegistry } from \"../../scenario/_registries/lanka-scenarios-registry/LankaScenariosRegistry\";\nimport type { LankaScenarioVMRegistry } from \"../../scenario/_registries/lanka-scenario-vm-registry/LankaScenarioVMRegistry\";\nimport type { ILankaRuntimeConfig } from \"../../config/_interfaces/ILankaRuntimeConfig\";\nimport type { ILankaInFlightCounter } from \"../../gateway/inflight/lankaHttpInFlight\";\nimport type { ILankaScenarioVM } from \"../../scenario/_interfaces/ILankaScenarioVM\";\nimport type { TLankaRequestMiddleware } from \"../../gateway/request/lankaRequestMiddleware\";\nimport type { LankaGatewayLocator } from \"../../locator/gateway/lanka-gateway-locator/LankaGatewayLocator\";\nimport type { LankaScenarioLocator } from \"../../locator/scenario/lanka-scenario-locator/LankaScenarioLocator\";\nimport type { LankaSingletonLocator } from \"../../locator/singleton/lanka-singleton-locator/LankaSingletonLocator\";\nimport type { LankaSharedStoreLocator } from \"../../locator/shared-store/lanka-shared-store-locator/LankaSharedStoreLocator\";\n\n/**\n * The pointer to the framework instance that ambient facades resolve to.\n *\n * ## Why this module is separate and imports no value\n *\n * Framework state belongs to an instance (`createLanka`), but the callers of\n * `lankaEventBus.dispatch`, `getLankaFlags()`, `lankaSingletons.foo`, `lankaHttpInFlight` —\n * the ambient facades cannot hold one — a user-extended `ALankaScenario`, the\n * static `LankaScenarioBootstrap` — so they ask which instance is active.\n *\n * The module is dependency-free DELIBERATELY: every import here is `import type`\n * and disappears at compile time. Otherwise there would be a cycle\n * `createLanka → locator → gateway → config → createLanka`, and module\n * evaluation order would start deciding what ends up `undefined`.\n *\n * This is still a global pointer. Real isolation belongs to whoever holds an\n * instance: their own bus, registries and counter. The facades serve ONE active\n * instance — exactly what an application with one needs.\n */\nexport interface ILankaRuntime {\n\treadonly eventBus: LankaEventBusInstance;\n\treadonly scenarios: LankaScenariosRegistry;\n\treadonly viewModels: LankaScenarioVMRegistry;\n\treadonly inFlight: ILankaInFlightCounter;\n\t/**\n\t * Request wrappers, in registration order: the first wraps them all.\n\t *\n\t * An array, not a set: order carries meaning — retry must sit outside request\n\t * signing, or the second attempt goes out unsigned.\n\t */\n\treadonly requestMiddleware: readonly TLankaRequestMiddleware[];\n\t/** Default response deadline. `undefined` means no limit. */\n\treadonly requestTimeoutMs: number | undefined;\n\treadonly locators: {\n\t\treadonly gateways: LankaGatewayLocator;\n\t\treadonly scenarios: LankaScenarioLocator;\n\t\treadonly singletons: LankaSingletonLocator;\n\t\treadonly sharedStores: LankaSharedStoreLocator;\n\t};\n\treadonly config: ILankaRuntimeConfig;\n\t/**\n\t * Bootstrap state of the scenario layer.\n\t *\n\t * A mutable object rather than contract fields: `LankaScenarioBootstrap` is an\n\t * ambient facade and must write here without holding an instance.\n\t */\n\treadonly scenarioState: {\n\t\tbootstrapped: boolean;\n\t\tinitialized: WeakSet<ILankaScenarioVM>;\n\t};\n\tsetConfig(patch: ILankaRuntimeConfig): void;\n\tgetFlags(): NonNullable<ILankaRuntimeConfig[\"flags\"]>;\n}\n\n/**\n * How \"which instance is active\" is answered.\n *\n * A strategy, because the answer depends on where the code runs. In a browser\n * there is one instance per document and a module-level pointer IS the answer. In\n * a server process there is one instance per REQUEST, and a module-level pointer\n * is the bug: the last request to start would answer for all of them.\n */\nexport type TLankaRuntimeResolver = () => ILankaRuntime | null;\n\nlet active: ILankaRuntime | null = null;\nlet resolveRuntime: TLankaRuntimeResolver | null = null;\n\nexport function setActiveRuntime(runtime: ILankaRuntime | null): void {\n\tactive = runtime;\n}\n\n/**\n * Replaces the strategy, or restores the default one with `null`.\n *\n * The installed resolver is the WHOLE answer — the module-level pointer is not\n * consulted behind it. That is deliberate: a fallback would turn \"this ran\n * outside a request\" from a loud error into one request quietly reading another\n * request's instance, which is the failure this seam exists to make impossible.\n *\n * Core ships no resolver and knows of none. What installs one is a package that\n * knows the shape of a request; core knows only that the question has more than\n * one answer.\n */\nexport function setLankaRuntimeResolver(resolver: TLankaRuntimeResolver | null): void {\n\tresolveRuntime = resolver;\n}\n\nexport function getActiveRuntime(): ILankaRuntime | null {\n\treturn resolveRuntime ? resolveRuntime() : active;\n}\n\n/**\n * The active instance, or a loud failure.\n *\n * No fallback, deliberately, for the same reason `getLankaHost` has none: an\n * instance created silently on the fly would mean subscriptions went to one bus\n * and events to another, and the divergence would surface three layers away.\n */\nexport function requireActiveRuntime(): ILankaRuntime {\n\t// The strategy is read here rather than through `getActiveRuntime()`: this is\n\t// the hottest path in the framework — every ambient facade, every request,\n\t// every dispatch — and a call that only forwards is a call that shows up in\n\t// `perf/`.\n\tconst runtime = resolveRuntime ? resolveRuntime() : active;\n\n\tif (!runtime) {\n\t\tthrow new Error(\n\t\t\tresolveRuntime\n\t\t\t\t? \"lanka has no instance for this call. A runtime resolver is installed and \" +\n\t\t\t\t\t\t\"answered with none, which on a server means the code ran outside a \" +\n\t\t\t\t\t\t\"request scope — start one, or do this work inside it.\"\n\t\t\t\t: \"lanka used before an instance existed. Call createLanka({ host }) and \" +\n\t\t\t\t\t\t\"activate it.\",\n\t\t);\n\t}\n\n\treturn runtime;\n}\n"],"mappings":";AA4EA,IAAI,SAA+B;AACnC,IAAI,iBAA+C;AAE5C,SAAS,iBAAiB,SAAqC;AACrE,WAAS;AACV;AAcO,SAAS,wBAAwB,UAA8C;AACrF,mBAAiB;AAClB;AAEO,SAAS,mBAAyC;AACxD,SAAO,iBAAiB,eAAe,IAAI;AAC5C;AASO,SAAS,uBAAsC;AAKrD,QAAM,UAAU,iBAAiB,eAAe,IAAI;AAEpD,MAAI,CAAC,SAAS;AACb,UAAM,IAAI;AAAA,MACT,iBACG,2MAGA;AAAA,IAEJ;AAAA,EACD;AAEA,SAAO;AACR;","names":[]}