lanka 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -3
- package/dist/{ALankaGateway-ExlRGT3D.d.ts → ALankaGateway-CkW1LbKE.d.ts} +50 -4
- package/dist/{ILankaScenarioMetadata-Bu-yggTZ.d.ts → ILankaScenarioMetadata-GoWWNEQL.d.ts} +1 -1
- package/dist/{ILankaScenarioVM-DuCyPoyT.d.ts → ILankaScenarioVM-DUsI-fSc.d.ts} +116 -3
- package/dist/{LankaError-B1HtuIkw.d.ts → LankaError-xpI-qj35.d.ts} +15 -2
- package/dist/{LankaScenarioLocator-CLkq4MaJ.d.ts → LankaScenarioLocator-D86TIwiu.d.ts} +10 -5
- package/dist/_extend/index.d.ts +4 -4
- package/dist/_extend/index.js +4 -4
- package/dist/_internal/index.d.ts +5 -5
- package/dist/{activeRuntime-DT4gB16d.d.ts → activeRuntime-B336NU5I.d.ts} +2 -2
- package/dist/bootstrap/index.d.ts +13 -144
- package/dist/bootstrap/index.js +5 -5
- package/dist/{chunk-63ST2UKP.js → chunk-ECM2HZHS.js} +106 -20
- package/dist/chunk-ECM2HZHS.js.map +1 -0
- package/dist/{chunk-MYZQYOMD.js → chunk-GK3E4CVW.js} +23 -18
- package/dist/chunk-GK3E4CVW.js.map +1 -0
- package/dist/chunk-GV5DUYST.js +64 -0
- package/dist/chunk-GV5DUYST.js.map +1 -0
- package/dist/{chunk-YXI4OQEV.js → chunk-O5ROO7QF.js} +27 -4
- package/dist/chunk-O5ROO7QF.js.map +1 -0
- package/dist/{chunk-HZAIAGWS.js → chunk-UGXSGQPW.js} +6 -2
- package/dist/chunk-UGXSGQPW.js.map +1 -0
- package/dist/createLanka-DI1CSy2Q.d.ts +139 -0
- package/dist/errors/index.d.ts +2 -3
- package/dist/gateway/index.d.ts +77 -67
- package/dist/gateway/index.js +50 -54
- package/dist/gateway/index.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +5 -5
- package/dist/locator/index.d.ts +1 -1
- package/dist/scenario/index.d.ts +6 -4
- package/dist/scenario/index.js +2 -2
- package/dist/stream/index.d.ts +386 -0
- package/dist/stream/index.js +287 -0
- package/dist/stream/index.js.map +1 -0
- package/dist/validation/index.d.ts +13 -8
- package/dist/validation/index.js +5 -48
- package/dist/validation/index.js.map +1 -1
- package/dist/viewmodel/index.d.ts +1 -1
- package/dist/viewmodel/index.js +2 -2
- package/package.json +7 -3
- package/skills/lanka-core/SKILL.md +1 -1
- package/skills/lanka-core/reference.md +110 -17
- package/skills/lanka-packages/SKILL.md +1 -1
- package/dist/ILankaApiError-zI_2bNs0.d.ts +0 -16
- package/dist/chunk-63ST2UKP.js.map +0 -1
- package/dist/chunk-HZAIAGWS.js.map +0 -1
- package/dist/chunk-MYZQYOMD.js.map +0 -1
- package/dist/chunk-YXI4OQEV.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/scenario/event-bus/_facades/lanka-event-bus/lankaEventBus.ts","../src/scenario/_registries/lanka-scenario-vm-registry/LankaScenarioVMRegistry.ts","../src/scenario/_registries/lanka-scenarios-registry/LankaScenariosRegistry.ts","../src/scenario/_abstractions/lanka-scenario/ALankaScenario.ts"],"sourcesContent":["import { requireActiveRuntime } from \"../../../../_internal/active-runtime/activeRuntime\";\nimport type { ILankaEventLog } from \"../../../_interfaces/ILankaEventLog\";\nimport type { ILankaEventMetadata } from \"../../../_interfaces/ILankaEventMetadata\";\nimport type { TLankaEventBusMiddleware } from \"../../../_types/TLankaEventBusMiddleware\";\nimport type { TLankaEventBusObserver } from \"../../../_types/TLankaEventBusObserver\";\nimport type { LankaEventBusInstance } from \"../../lanka-event-bus-instance/LankaEventBusInstance\";\nimport type { TLankaReplayRequest } from \"../../lanka-event-bus-instance/LankaEventBusInstance\";\n\n/**\n * Ambient bus: the active instance's, reachable without holding it.\n *\n * Every member is one line of delegation and that is all this does. It exists\n * for callers that cannot hold an instance — a user-extended `ALankaScenario`,\n * the scenario bootstrap.\n *\n * An object rather than a class with a default instance, and the difference is\n * not cosmetic: this owns no state, so a second one would delegate to the same\n * runtime and be the same object under another name. Where an ambient DOES own\n * state — storage — the class is real and a second instance means something.\n *\n * Isolation belongs to the instance holder: `lanka.eventBus.dispatch(…)`. This\n * cannot offer it — by definition it serves the ONE active instance, so two\n * instances in one process share nothing through it.\n */\nconst bus = (): LankaEventBusInstance => requireActiveRuntime().eventBus;\n\nexport const lankaEventBus = Object.freeze({\n\tenableLogs: (): void => {\n\t\tbus().enableLogs();\n\t},\n\n\tdisableLogs: (): void => {\n\t\tbus().disableLogs();\n\t},\n\n\tregisterEvent: (eventType: string, metadata: ILankaEventMetadata): void => {\n\t\tbus().registerEvent(eventType, metadata);\n\t},\n\n\tgetRegisteredEvents: () => bus().getRegisteredEvents(),\n\n\tgetEventInfo: (eventType: string): ILankaEventMetadata | null => bus().getEventInfo(eventType),\n\n\tgetSubscriptions: (eventType: string): number => bus().getSubscriptions(eventType),\n\n\tsubscribe: <T>(\n\t\teventType: string,\n\t\tcallback: (data: T) => void,\n\t\toptions?: { priority?: number; replay?: TLankaReplayRequest; usedBy?: string },\n\t): (() => void) => bus().subscribe(eventType, callback, options),\n\n\tunsubscribe: <T>(eventType: string, callback: (data: T) => void): void => {\n\t\tbus().unsubscribe(eventType, callback);\n\t},\n\n\tdispatch: <T>(eventType: string, data?: T, usedBy?: string): void => {\n\t\tbus().dispatch(eventType, data, usedBy);\n\t},\n\n\taddMiddleware: <T>(middleware: TLankaEventBusMiddleware<T>): void => {\n\t\tbus().addMiddleware(middleware);\n\t},\n\n\tremoveMiddleware: <T>(middleware: TLankaEventBusMiddleware<T>): void => {\n\t\tbus().removeMiddleware(middleware);\n\t},\n\n\taddObserver: (observer: TLankaEventBusObserver): void => {\n\t\tbus().addObserver(observer);\n\t},\n\n\tremoveObserver: (observer: TLankaEventBusObserver): void => {\n\t\tbus().removeObserver(observer);\n\t},\n\n\tgetEventLogs: (eventType?: string, limit = 100): ILankaEventLog[] =>\n\t\tbus().getEventLogs(eventType, limit),\n\n\tclearEvent: (eventType: string): void => {\n\t\tbus().clearEvent(eventType);\n\t},\n\n\tclearAllEvents: (): void => {\n\t\tbus().clearAllEvents();\n\t},\n\n\treset: (): void => {\n\t\tbus().reset();\n\t},\n});\n","import { requireActiveRuntime } from \"../../../_internal/active-runtime/activeRuntime\";\nimport { ILankaScenarioVM } from \"../../_interfaces/ILankaScenarioVM\";\n\n/**\n * The registry of ViewModels that use scenarios.\n *\n * They arrive by themselves: the factory registers a ViewModel when it declares\n * scenario handlers.\n */\nexport class LankaScenarioVMRegistry {\n\tprivate registeredViewModels: Set<ILankaScenarioVM> = new Set();\n\n\t/**\n\t * Public: the registry belongs to a framework instance rather than to the\n\t * module.\n\t */\n\tpublic constructor() {}\n\n\t/**\n\t * The active instance's registry, for callers that cannot hold one — the\n\t * static `LankaScenarioBootstrap`. Instance holders read `lanka.viewModels`.\n\t */\n\tpublic static getInstance(): LankaScenarioVMRegistry {\n\t\treturn requireActiveRuntime().viewModels;\n\t}\n\n\t/** Whether this ViewModel is already registered. */\n\tpublic isRegistered(viewModel: ILankaScenarioVM): boolean {\n\t\treturn this.registeredViewModels.has(viewModel);\n\t}\n\n\t/**\n\t * Registers a ViewModel.\n\t *\n\t * @returns `false` when it was already registered\n\t */\n\tpublic register(viewModel: ILankaScenarioVM): boolean {\n\t\tif (this.registeredViewModels.has(viewModel)) {\n\t\t\treturn false;\n\t\t}\n\t\tthis.registeredViewModels.add(viewModel);\n\t\treturn true;\n\t}\n\n\t/** Removes a ViewModel from the registry. */\n\tpublic unregister(viewModel: ILankaScenarioVM): void {\n\t\tthis.registeredViewModels.delete(viewModel);\n\t}\n\n\t/** Every registered ViewModel. */\n\tpublic getAllViewModels(): ILankaScenarioVM[] {\n\t\treturn Array.from(this.registeredViewModels);\n\t}\n\n\t/**\n\t * Clears every registered ViewModel. Required by tests.\n\t */\n\tpublic clear(): void {\n\t\tthis.registeredViewModels.clear();\n\t}\n\n\t/**\n\t * Unsubscribes every registered ViewModel from its scenarios and clears the\n\t * registry.\n\t *\n\t * Without it tests are not isolated: a subscription leaks from test to test.\n\t */\n\tpublic resetAll(): void {\n\t\tthis.registeredViewModels.forEach((vm) => {\n\t\t\ttry {\n\t\t\t\tvm.resetScenario();\n\t\t\t} catch {\n\t\t\t\t// One failing to reset is no reason to fail the rest.\n\t\t\t}\n\t\t});\n\t\tthis.clear();\n\t}\n}\n","import { requireActiveRuntime } from \"../../../_internal/active-runtime/activeRuntime\";\nimport { ILankaScenario } from \"../../_interfaces/ILankaScenario\";\nimport { ALankaScenario } from \"../../_abstractions/lanka-scenario/ALankaScenario\";\nimport { ILankaScenarioVM } from \"../../_interfaces/ILankaScenarioVM\";\nimport { LankaScenarioVMRegistry } from \"../lanka-scenario-vm-registry/LankaScenarioVMRegistry\";\nimport { lankaLogger } from \"../../../logger/lanka-logger/LankaLogger\";\nimport type { ILankaScenarioMetadata } from \"../../_interfaces/ILankaScenarioMetadata\";\n\n/**\n * Runs a scenario's `cleanup`, if it declared one, and contains what it throws.\n *\n * `ILankaScenario` promises `cleanup` is \"called when the scenario is removed\n * from the registry\", and for a long time nothing called it: a scenario whose\n * `initialize` opened something had no way to close it, and the promise read\n * as kept. Contained, because a removal runs over MANY scenarios — on dispose,\n * on the between-tests reset — and one failing to let go is no reason to leave\n * the rest registered.\n */\nconst release = (scenario: ILankaScenario<unknown>): void => {\n\tif (!scenario.cleanup) return;\n\ttry {\n\t\tscenario.cleanup();\n\t} catch (error) {\n\t\tlankaLogger.printScenarioLog(`Error cleaning up scenario \"${scenario.name}\":`, error);\n\t}\n};\n\n/**\n * The scenario registry: both those that registered themselves and those\n * registered by hand.\n *\n * `ALankaScenario` subclasses arrive here automatically unless they opted out.\n */\nexport class LankaScenariosRegistry {\n\tprivate registeredScenarios: Map<string, ILankaScenario<unknown>> = new Map();\n\tprivate scenarioMetadata: Map<string, ILankaScenarioMetadata> = new Map();\n\n\t/**\n\t * Public: the registry belongs to a framework instance rather than to the\n\t * module.\n\t */\n\tpublic constructor() {}\n\n\t/**\n\t * The active instance's registry, for callers that cannot hold one:\n\t * `ALankaScenario` (a base class the consumer extends) and the static\n\t * `LankaScenarioBootstrap`. Instance holders read `lanka.scenarios`.\n\t */\n\tpublic static getInstance(): LankaScenariosRegistry {\n\t\treturn requireActiveRuntime().scenarios;\n\t}\n\n\t/**\n\t * Registers a scenario by hand.\n\t *\n\t * @param scenario What to register\n\t * @returns `false` when it was already registered\n\t */\n\tpublic register(scenario: ILankaScenario<unknown>): boolean {\n\t\tif (this.registeredScenarios.has(scenario.name)) {\n\t\t\treturn false;\n\t\t}\n\n\t\tthis.registeredScenarios.set(scenario.name, scenario);\n\t\tthis.scenarioMetadata.set(scenario.name, {\n\t\t\tscenario,\n\t\t\tname: scenario.name,\n\t\t\teventType: scenario.eventType,\n\t\t\tdataTypeName: scenario.dataTypeName,\n\t\t\tisRegistered: true,\n\t\t});\n\n\t\treturn true;\n\t}\n\n\t/**\n\t * Removes a scenario, calling its `cleanup` if it declared one.\n\t *\n\t * @param scenarioName Name of the scenario to unregister\n\t * @returns true if unregistered successfully, false if not found\n\t */\n\tpublic unregister(scenarioName: string): boolean {\n\t\tconst scenario = this.registeredScenarios.get(scenarioName);\n\t\tif (!scenario) {\n\t\t\treturn false;\n\t\t}\n\n\t\tconst metadata = this.scenarioMetadata.get(scenarioName);\n\t\tif (metadata) {\n\t\t\tmetadata.isRegistered = false;\n\t\t}\n\n\t\tthis.registeredScenarios.delete(scenarioName);\n\t\trelease(scenario);\n\t\treturn true;\n\t}\n\n\t/**\n\t * Get metadata for a specific scenario\n\t * @param scenarioName Name of the scenario\n\t * @returns Scenario metadata or undefined if not found\n\t */\n\tpublic getMetadata(scenarioName: string): ILankaScenarioMetadata | undefined {\n\t\treturn this.scenarioMetadata.get(scenarioName);\n\t}\n\n\t/** Every registered scenario. */\n\tpublic getAllScenarios(): ILankaScenario<unknown>[] {\n\t\treturn Array.from(this.registeredScenarios.values());\n\t}\n\n\t/** Metadata of every scenario. */\n\tpublic getAllMetadata(): ILankaScenarioMetadata[] {\n\t\treturn Array.from(this.scenarioMetadata.values());\n\t}\n\n\t/** Whether a scenario with this name is registered. */\n\tpublic isRegistered(scenarioName: string): boolean {\n\t\treturn this.registeredScenarios.has(scenarioName);\n\t}\n\n\t/**\n\t * Collects every scenario that registered itself at construction.\n\t */\n\tpublic collectAutoRegisteredScenarios(): void {\n\t\t// Take those that registered themselves at construction.\n\t\tconst autoRegistered = ALankaScenario.getAutoRegisteredScenarios();\n\t\tautoRegistered.forEach((scenario) => {\n\t\t\tif (!this.registeredScenarios.has(scenario.name)) {\n\t\t\t\tthis.register(scenario);\n\t\t\t}\n\t\t});\n\t}\n\n\t/**\n\t * A scenario by name.\n\t *\n\t * @returns `undefined` when there is none\n\t */\n\tpublic getScenarioByName(scenarioName: string): ILankaScenario<unknown> | undefined {\n\t\treturn this.registeredScenarios.get(scenarioName);\n\t}\n\n\t/** Every registered ViewModel. */\n\tpublic getAllViewModels(): ILankaScenarioVM[] {\n\t\treturn LankaScenarioVMRegistry.getInstance().getAllViewModels();\n\t}\n\n\t/**\n\t * Removes every scenario, calling each one's `cleanup`.\n\t *\n\t * What `dispose()` and the between-tests reset go through: `initialize` ran\n\t * for every scenario at bootstrap, and this is the one moment its mirror\n\t * image can run for all of them.\n\t */\n\tpublic clear(): void {\n\t\tconst scenarios = [...this.registeredScenarios.values()];\n\t\tthis.registeredScenarios.clear();\n\t\tthis.scenarioMetadata.clear();\n\t\tfor (const scenario of scenarios) release(scenario);\n\t}\n}\n","import type { TLankaReplayRequest } from \"../../event-bus/lanka-event-bus-instance/LankaEventBusInstance\";\nimport { ILankaScenario } from \"../../_interfaces/ILankaScenario\";\nimport { LankaScenariosRegistry } from \"../../_registries/lanka-scenarios-registry/LankaScenariosRegistry\";\nimport { lankaLogger } from \"../../../logger/lanka-logger/LankaLogger\";\nimport { lankaEventBus } from \"../../event-bus/_facades/lanka-event-bus/lankaEventBus\";\n\n/**\n * The base of a scenario — a named unit of coordination over the event bus.\n *\n * A subclass declares `name`, `eventType` and `dataTypeName`, calls `trigger()`\n * when the event happens, and ViewModels subscribe to it and unsubscribe.\n *\n * Scenarios register THEMSELVES unless the subclass sets the static\n * `skipAutoRegistration`.\n *\n * ```ts\n * export class SessionUpdated extends ALankaScenario<TSession> {\n * readonly name = \"SessionUpdated\";\n * readonly eventType = \"session.updated\";\n * readonly dataTypeName = \"TSession\";\n * }\n * ```\n */\nexport abstract class ALankaScenario<TData = void> implements ILankaScenario<TData> {\n\tabstract readonly name: string;\n\tabstract readonly eventType: string;\n\tabstract readonly dataTypeName: string;\n\n\t/** A subclass sets this to opt out of self-registration. */\n\tstatic skipAutoRegistration?: boolean;\n\n\t/**\n\t * The self-registration pool.\n\t *\n\t * Class-level deliberately: a registry of DEFINITIONS, not runtime state. The\n\t * classes come from one barrel and both framework instances must see the same\n\t * list — splitting it would be divergence, not isolation.\n\t */\n\tprivate static autoRegisteredScenarios: Set<ALankaScenario<unknown>> = new Set();\n\n\t/** Registers the scenario itself unless the subclass opted out. */\n\tconstructor() {\n\t\t// The constructor comes from the actual class, that is the subclass.\n\t\tconst constructor = this.constructor as typeof ALankaScenario;\n\n\t\t// Register unless opted out.\n\t\tif (!constructor.skipAutoRegistration) {\n\t\t\tALankaScenario.autoRegisteredScenarios.add(this);\n\t\t}\n\t}\n\n\t/**\n\t * Every scenario that registered itself.\n\t *\n\t * @internal\n\t */\n\tpublic static getAutoRegisteredScenarios(): ALankaScenario<unknown>[] {\n\t\treturn Array.from(ALankaScenario.autoRegisteredScenarios);\n\t}\n\n\t/**\n\t * Clears the auto-registration pool. Required by tests.\n\t * @internal\n\t */\n\tpublic static clearAutoRegisteredScenarios(): void {\n\t\tALankaScenario.autoRegisteredScenarios.clear();\n\t}\n\n\t/**\n\t * Registers the scenario by hand.\n\t *\n\t * @returns `false` when it was already registered\n\t */\n\tpublic register(): boolean {\n\t\treturn LankaScenariosRegistry.getInstance().register(this);\n\t}\n\n\t/**\n\t * Removes the scenario from the registry.\n\t *\n\t * @returns `false` when it was not there\n\t */\n\tpublic unregister(): boolean {\n\t\treturn LankaScenariosRegistry.getInstance().unregister(this.name);\n\t}\n\n\ttrigger(data?: TData): void {\n\t\tlankaLogger.printScenarioLog(\"TRIGGER Scenario\", this.name, data);\n\t\tlankaEventBus.dispatch(this.eventType, data, this.name);\n\t}\n\n\t/**\n\t * Subscribes a handler and returns an unsubscribe function.\n\t *\n\t * Without the return, unsubscribing is possible only by callback identity, and\n\t * every ViewModel factory has to keep a map of references for it.\n\t */\n\tsubscribe(\n\t\tcallback: (data?: TData) => void,\n\t\toptions?: {\n\t\t\tpriority?: number;\n\t\t\treplay?: TLankaReplayRequest;\n\t\t\tusedBy?: string;\n\t\t},\n\t): () => void {\n\t\tlankaLogger.printScenarioLog(\"SUBSCRIBE Scenario\", this.name, this.dataTypeName);\n\t\treturn lankaEventBus.subscribe(this.eventType, callback, {\n\t\t\t...options,\n\t\t\tusedBy: options?.usedBy ?? this.name,\n\t\t});\n\t}\n}\n"],"mappings":"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","names":[]}
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
LankaScenarioVMRegistry,
|
|
4
4
|
LankaScenariosRegistry,
|
|
5
5
|
lankaEventBus
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-O5ROO7QF.js";
|
|
7
7
|
import {
|
|
8
8
|
lankaLogger
|
|
9
9
|
} from "./chunk-C2HP7CRD.js";
|
|
@@ -29,8 +29,12 @@ var LankaScenarioBootstrap = class {
|
|
|
29
29
|
return this.state.bootstrapped;
|
|
30
30
|
}
|
|
31
31
|
forceInstantiateAllScenarios() {
|
|
32
|
+
const pooled = new Set(
|
|
33
|
+
ALankaScenario.getAutoRegisteredScenarios().map((scenario) => scenario.constructor)
|
|
34
|
+
);
|
|
32
35
|
for (const exported of Object.values(ScenariosModule)) {
|
|
33
36
|
if (typeof exported !== "function") continue;
|
|
37
|
+
if (pooled.has(exported)) continue;
|
|
34
38
|
try {
|
|
35
39
|
new exported();
|
|
36
40
|
} catch {
|
|
@@ -173,4 +177,4 @@ var lankaScenarioBootstrap = new LankaScenarioBootstrap();
|
|
|
173
177
|
export {
|
|
174
178
|
lankaScenarioBootstrap
|
|
175
179
|
};
|
|
176
|
-
//# sourceMappingURL=chunk-
|
|
180
|
+
//# sourceMappingURL=chunk-UGXSGQPW.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 { 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// 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/** Registers everything declared into a NEW instance. Called by `createLanka`. */\n\tpublic adoptDeclaredViewModels(): void {\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\tpublic reset(): 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\t}\n}\n\n/** The one every caller wants. */\nexport const lankaScenarioBootstrap = new LankaScenarioBootstrap();\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { I as ILankaScope } from './createLankaScope-BiFxNQgl.js';
|
|
2
|
+
import { I as ILankaRuntime } from './activeRuntime-B336NU5I.js';
|
|
3
|
+
import { a as ILankaHost, I as ILankaFlags } from './ILankaRuntimeConfig-Vl436GWK.js';
|
|
4
|
+
import { T as TLankaRequestMiddleware } from './lankaRequestMiddleware-DAC5kCb7.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* A plugin is an extension core knows by SHAPE rather than by name.
|
|
8
|
+
*
|
|
9
|
+
* ## Plugin versus module
|
|
10
|
+
*
|
|
11
|
+
* A module is called by the application (`app → module`) and core does not know
|
|
12
|
+
* it exists. A plugin sits on the path core itself walks (`app → core → plugin`).
|
|
13
|
+
* The test question: does core need a hook for this to work? No — then it is a
|
|
14
|
+
* module, and making it a plugin costs more, because the hook has to be supported
|
|
15
|
+
* forever.
|
|
16
|
+
*
|
|
17
|
+
* ## Why `install` receives the instance
|
|
18
|
+
*
|
|
19
|
+
* So a plugin has no private route to the framework. Everything it can do comes
|
|
20
|
+
* from the instance it was given, which means two instances in one process (a
|
|
21
|
+
* test beside the app) do not share its configuration.
|
|
22
|
+
*/
|
|
23
|
+
interface ILankaPlugin {
|
|
24
|
+
/**
|
|
25
|
+
* The name the plugin is recognised by. Registering the same name twice is
|
|
26
|
+
* rejected: two copies of a retry policy would silently double the request
|
|
27
|
+
* count.
|
|
28
|
+
*/
|
|
29
|
+
readonly name: string;
|
|
30
|
+
/**
|
|
31
|
+
* Installation. The returned function removes everything the plugin installed
|
|
32
|
+
* and is called when the plugin is removed and when the instance is disposed.
|
|
33
|
+
*/
|
|
34
|
+
install: (lanka: ILankaInstance) => (() => void) | void;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* A framework instance: all framework state in one object.
|
|
39
|
+
*
|
|
40
|
+
* What instance-scoped state buys: two apps in one process (micro-frontends,
|
|
41
|
+
* Storybook beside the app) no longer share a bus, locator caches and mock mode;
|
|
42
|
+
* SSR does not reuse state between different users' requests; and test isolation
|
|
43
|
+
* rests on construction rather than on a global `beforeEach` reaching into
|
|
44
|
+
* internal registries.
|
|
45
|
+
*
|
|
46
|
+
* **Ambient facades** — `lankaEventBus.dispatch`, `lankaSingletons.foo`,
|
|
47
|
+
* `getLankaFlags()`, `lankaHttpInFlight` — resolve THE ONE active instance
|
|
48
|
+
* (`internal/activeRuntime.ts`). Isolation belongs to whoever holds an instance;
|
|
49
|
+
* a facade cannot offer it.
|
|
50
|
+
*
|
|
51
|
+
* One thing stays at module level deliberately: `ALankaScenario` collects
|
|
52
|
+
* constructed scenarios into a static pool. That is a REGISTRY OF DEFINITIONS,
|
|
53
|
+
* not runtime state — the classes come from one `@lanka_di/Scenarios` barrel and
|
|
54
|
+
* both instances must see the same list. Splitting it would be divergence.
|
|
55
|
+
*/
|
|
56
|
+
interface ILankaInstance extends ILankaRuntime {
|
|
57
|
+
/**
|
|
58
|
+
* Adds a wrapper around every request. Returns a function that removes it.
|
|
59
|
+
*
|
|
60
|
+
* This is how `@lankajs/plugin-http` installs retry, the idempotency key, the
|
|
61
|
+
* CSRF header and auth refresh.
|
|
62
|
+
*/
|
|
63
|
+
useRequestMiddleware(middleware: TLankaRequestMiddleware): () => void;
|
|
64
|
+
/** Default timeout for every request of this instance. */
|
|
65
|
+
setRequestTimeout(timeoutMs: number | undefined): void;
|
|
66
|
+
/** Resolves a service in the root scope — for the instance's whole lifetime. */
|
|
67
|
+
resolve<TInstance>(propertyName: string): TInstance;
|
|
68
|
+
/**
|
|
69
|
+
* Creates a scope: a lifetime shorter than the application's.
|
|
70
|
+
*
|
|
71
|
+
* An object created in a scope goes away with it.
|
|
72
|
+
*/
|
|
73
|
+
createScope(): ILankaScope;
|
|
74
|
+
/**
|
|
75
|
+
* Registers a plugin. Returns a function that removes it.
|
|
76
|
+
*
|
|
77
|
+
* The fifth and last extension point. An extension point declared before
|
|
78
|
+
* anything plugs into it describes an imagined need while costing real
|
|
79
|
+
* support, so this one arrived with the FIRST plugin.
|
|
80
|
+
*/
|
|
81
|
+
use(plugin: ILankaPlugin): () => void;
|
|
82
|
+
/** Runs services and the scenario layer. Idempotent. */
|
|
83
|
+
bootstrap(config?: ILankaBootstrapConfig): Promise<void>;
|
|
84
|
+
/** Has bootstrap already run? */
|
|
85
|
+
isBootstrapped(): boolean;
|
|
86
|
+
/** Makes this instance the one ambient facades resolve to. */
|
|
87
|
+
activate(): void;
|
|
88
|
+
/**
|
|
89
|
+
* Removes subscriptions, clears registries and, if this instance was active,
|
|
90
|
+
* clears the pointer. Returns the framework to its pre-bootstrap state.
|
|
91
|
+
*/
|
|
92
|
+
dispose(): void;
|
|
93
|
+
}
|
|
94
|
+
interface ILankaInstanceConfig {
|
|
95
|
+
host: ILankaHost;
|
|
96
|
+
flags?: ILankaFlags;
|
|
97
|
+
}
|
|
98
|
+
interface ILankaServiceConfig {
|
|
99
|
+
name?: string;
|
|
100
|
+
init: () => void | Promise<void>;
|
|
101
|
+
sync?: boolean;
|
|
102
|
+
priority?: number;
|
|
103
|
+
/**
|
|
104
|
+
* A failure of this service does not abort bootstrap.
|
|
105
|
+
*
|
|
106
|
+
* Without the flag one failed service takes the WHOLE phase with it: the async
|
|
107
|
+
* phase because of `Promise.all`, the sync phase because later tasks never run.
|
|
108
|
+
* Wrapping the failure in a swallowing `try/catch` is worse still — the app
|
|
109
|
+
* starts with a partially executed plan and does not know it.
|
|
110
|
+
*/
|
|
111
|
+
optional?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* How long to wait for the service. Overrunning counts as a failure.
|
|
114
|
+
*
|
|
115
|
+
* Without a deadline a service that never settles holds bootstrap forever and
|
|
116
|
+
* the app never paints its first screen. Failing is more honest than waiting:
|
|
117
|
+
* an optional service is skipped, a required one names itself.
|
|
118
|
+
*/
|
|
119
|
+
timeoutMs?: number;
|
|
120
|
+
}
|
|
121
|
+
interface ILankaScenarioBootstrapConfig {
|
|
122
|
+
sync?: boolean;
|
|
123
|
+
priority?: number;
|
|
124
|
+
}
|
|
125
|
+
interface ILankaBootstrapConfig {
|
|
126
|
+
services?: ILankaServiceConfig[];
|
|
127
|
+
scenarios?: ILankaScenarioBootstrapConfig;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Creates an instance and makes it active.
|
|
131
|
+
*
|
|
132
|
+
* Activating on creation is the deliberate default: there is almost always one
|
|
133
|
+
* app and the facades must work immediately. A second instance takes the
|
|
134
|
+
* pointer — the last one created serves the facades. Callers needing another
|
|
135
|
+
* order call `activate()` explicitly.
|
|
136
|
+
*/
|
|
137
|
+
declare function createLanka(config: ILankaInstanceConfig): ILankaInstance;
|
|
138
|
+
|
|
139
|
+
export { type ILankaBootstrapConfig as I, type ILankaInstance as a, type ILankaInstanceConfig as b, type ILankaPlugin as c, type ILankaScenarioBootstrapConfig as d, type ILankaServiceConfig as e, createLanka as f };
|
package/dist/errors/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { L as LankaError } from '../LankaError-
|
|
2
|
-
export { I as ILankaErrorInit, T as TLankaErrorKind } from '../LankaError-
|
|
3
|
-
export { I as ILankaApiError } from '../ILankaApiError-zI_2bNs0.js';
|
|
1
|
+
import { L as LankaError } from '../LankaError-xpI-qj35.js';
|
|
2
|
+
export { a as ILankaApiError, I as ILankaErrorInit, T as TLankaErrorKind } from '../LankaError-xpI-qj35.js';
|
|
4
3
|
export { T as TLankaErrorHandler } from '../TLankaErrorHandler-Yfqtdh1M.js';
|
|
5
4
|
|
|
6
5
|
/**
|
package/dist/gateway/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { T as TLankaExecuteOptions, I as IALankaGatewayConfig, a as
|
|
2
|
-
export { A as ALankaGateway,
|
|
1
|
+
import { T as TLankaExecuteOptions, I as IALankaGatewayConfig, a as TLankaRequestInit, b as ILankaRequest, c as TLankaQueryBuilder } from '../ALankaGateway-CkW1LbKE.js';
|
|
2
|
+
export { A as ALankaGateway, d as TLankaQueryParams } from '../ALankaGateway-CkW1LbKE.js';
|
|
3
|
+
import { I as ILankaValidator } from '../lankaStandardValidator-CL-r-zEV.js';
|
|
3
4
|
import { T as TLankaErrorHandler } from '../TLankaErrorHandler-Yfqtdh1M.js';
|
|
4
5
|
export { I as ILankaInFlightCounter, l as lankaHttpInFlight } from '../lankaHttpInFlight-Bk1eIuSx.js';
|
|
5
6
|
export { I as ILankaRequestContext, T as TLankaRequestMiddleware } from '../lankaRequestMiddleware-DAC5kCb7.js';
|
|
6
|
-
import '../lankaStandardValidator-CL-r-zEV.js';
|
|
7
7
|
import '@standard-schema/spec';
|
|
8
8
|
|
|
9
9
|
/**
|
|
@@ -20,6 +20,8 @@ interface ILankaGatewayContext<TOptions> {
|
|
|
20
20
|
request: <TReturn = unknown>(path: string, options?: TLankaExecuteOptions<TOptions>, mockHandler?: () => Promise<TReturn>) => Promise<TReturn>;
|
|
21
21
|
/** Serialises query parameters the way this gateway was configured to. */
|
|
22
22
|
buildQueryParams: <T extends object>(params: T) => URLSearchParams;
|
|
23
|
+
/** Checks a response body: the validator this gateway was given, or the Standard Schema port. */
|
|
24
|
+
validationService: ILankaValidator;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
/** What a gateway is built from, whichever style builds it. */
|
|
@@ -47,13 +49,13 @@ declare const createLankaGateway: <TOptions, TMethods extends object>(config: IL
|
|
|
47
49
|
* How a gateway request goes on the wire.
|
|
48
50
|
*
|
|
49
51
|
* A subclass declares one method, `request()`, and does only its own work there:
|
|
50
|
-
* `LankaFetchJsonRequest` returns parsed JSON, `
|
|
51
|
-
*
|
|
52
|
+
* `LankaFetchJsonRequest` returns parsed JSON, `LankaFetchRequest` returns the
|
|
53
|
+
* whole response, a custom kind returns whatever it likes.
|
|
52
54
|
*
|
|
53
55
|
* Overriding `request()` customises the request flow, failure handling, mock
|
|
54
56
|
* substitution, response transformation and log interception.
|
|
55
57
|
*/
|
|
56
|
-
declare abstract class ALankaRequest<TOptions =
|
|
58
|
+
declare abstract class ALankaRequest<TOptions = TLankaRequestInit> implements ILankaRequest<TOptions> {
|
|
57
59
|
protected readonly errorHandler?: TLankaErrorHandler;
|
|
58
60
|
protected readonly useMock: boolean;
|
|
59
61
|
protected constructor(config: {
|
|
@@ -81,10 +83,23 @@ declare abstract class ALankaRequest<TOptions = RequestInit> implements ILankaRe
|
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
+
* How bytes travel. The seam a consumer replaces to change the PROTOCOL.
|
|
87
|
+
*
|
|
88
|
+
* `LankaFetchTransport` is the only implementation core ships, and one is the
|
|
89
|
+
* right number: HTTP over `fetch` is what almost every application does, and the
|
|
90
|
+
* things that once justified a second and a third — a JSON `content-type`, a
|
|
91
|
+
* multipart one — turned out to be encodings rather than protocols. An encoding
|
|
92
|
+
* belongs to the CALL, and the shipped transport reads the body to decide it.
|
|
93
|
+
*
|
|
94
|
+
* Implement this for something genuinely different: a native bridge, a socket, an
|
|
95
|
+
* offline queue, a double that never leaves the process. Anything that still ends
|
|
96
|
+
* in `fetch` and only wants to add a header, a credential, a retry or a refresh
|
|
97
|
+
* is POLICY — write a `TLankaRequestMiddleware` and register it with
|
|
98
|
+
* `useRequestMiddleware`, or reach for `@lankajs/plugin-http`, which already has
|
|
99
|
+
* all four. A transport rewritten to carry policy is how an application ends up
|
|
100
|
+
* maintaining its own copy of this package.
|
|
86
101
|
*/
|
|
87
|
-
interface ILankaTransport<TOptions =
|
|
102
|
+
interface ILankaTransport<TOptions = TLankaRequestInit> {
|
|
88
103
|
/**
|
|
89
104
|
* Executes a request and returns a Response.
|
|
90
105
|
* @param resource - Request resource (URL or Request object)
|
|
@@ -102,12 +117,17 @@ interface ILankaTransportRequestConfig<TOptions> {
|
|
|
102
117
|
/**
|
|
103
118
|
* The shape every fetch-backed request has: mock, send, check, parse.
|
|
104
119
|
*
|
|
105
|
-
* The
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
120
|
+
* The concrete requests differ in ONE place — how they turn a successful
|
|
121
|
+
* `Response` into a value — so a third kind is a subclass with one method rather
|
|
122
|
+
* than a third copy of the sequence.
|
|
123
|
+
*
|
|
124
|
+
* The default transport stays a constructor PARAMETER even though both shipped
|
|
125
|
+
* kinds pass the same one. It is the seam a request kind that is not fetch-backed
|
|
126
|
+
* comes through: this template is the mock/send/check/parse sequence, and nothing
|
|
127
|
+
* in it is about HTTP. Defaulting the parameter here would fix `TOptions` to
|
|
128
|
+
* fetch options for everyone who reuses the sequence.
|
|
109
129
|
*/
|
|
110
|
-
declare abstract class ALankaTransportRequest<TOptions =
|
|
130
|
+
declare abstract class ALankaTransportRequest<TOptions = TLankaRequestInit> extends ALankaRequest<TOptions> {
|
|
111
131
|
protected readonly transport: ILankaTransport<TOptions>;
|
|
112
132
|
protected constructor(config: ILankaTransportRequestConfig<TOptions>, createDefaultTransport: () => ILankaTransport<TOptions>);
|
|
113
133
|
protected request<TReturn>(endpoint: string, options?: TOptions, mockHandler?: () => Promise<TReturn>): Promise<TReturn>;
|
|
@@ -131,10 +151,19 @@ declare abstract class ALankaTransportRequest<TOptions = RequestInit> extends AL
|
|
|
131
151
|
/**
|
|
132
152
|
* The raw request: hands the `Response` back untouched.
|
|
133
153
|
*
|
|
134
|
-
* The minimal, extensible case — a caller wanting headers, a stream or a
|
|
135
|
-
* reads them off the response itself.
|
|
154
|
+
* The minimal, extensible case — a caller wanting headers, a stream, a blob or a
|
|
155
|
+
* `204` reads them off the response itself. Multipart uploads come through here
|
|
156
|
+
* too: the transport encodes by looking at the body, so posting a `FormData` and
|
|
157
|
+
* posting an object are the same call.
|
|
158
|
+
*
|
|
159
|
+
* `TOptions` is CONSTRAINED to fetch options rather than merely defaulted to
|
|
160
|
+
* them. A consumer widening it — their own `interface IRequestOptions extends
|
|
161
|
+
* TLankaRequestInit` — still gets the shipped transport, because the constraint
|
|
162
|
+
* is what lets the framework hand one over without a cast. Unconstrained, the
|
|
163
|
+
* assignment did not typecheck and core cast its way past it; the cast worked
|
|
164
|
+
* here and was unavailable to the consumer, who wrote a transport instead.
|
|
136
165
|
*/
|
|
137
|
-
declare class LankaFetchRequest<TOptions =
|
|
166
|
+
declare class LankaFetchRequest<TOptions extends TLankaRequestInit = TLankaRequestInit> extends ALankaTransportRequest<TOptions> {
|
|
138
167
|
constructor(config?: ILankaTransportRequestConfig<TOptions>);
|
|
139
168
|
protected parse<TReturn>(response: Response): Promise<TReturn>;
|
|
140
169
|
}
|
|
@@ -145,7 +174,7 @@ declare class LankaFetchRequest<TOptions = RequestInit> extends ALankaTransportR
|
|
|
145
174
|
* One line, and that is the point — the factory IS the class, so a behaviour
|
|
146
175
|
* cannot exist in one style and not the other.
|
|
147
176
|
*/
|
|
148
|
-
declare const createLankaFetchRequest: <TOptions =
|
|
177
|
+
declare const createLankaFetchRequest: <TOptions extends TLankaRequestInit = TLankaRequestInit>(config?: ILankaTransportRequestConfig<TOptions>) => LankaFetchRequest<TOptions>;
|
|
149
178
|
|
|
150
179
|
/** The JSON request: parses the body, and refuses a body that is not JSON. */
|
|
151
180
|
/**
|
|
@@ -155,7 +184,7 @@ declare const createLankaFetchRequest: <TOptions = RequestInit>(config?: ILankaT
|
|
|
155
184
|
* what lets a test give the same gateway a transport that never leaves the
|
|
156
185
|
* process. `createLankaFetchJsonRequest()` builds the same class.
|
|
157
186
|
*/
|
|
158
|
-
declare class LankaFetchJsonRequest<TOptions =
|
|
187
|
+
declare class LankaFetchJsonRequest<TOptions extends TLankaRequestInit = TLankaRequestInit> extends ALankaTransportRequest<TOptions> {
|
|
159
188
|
constructor(config?: ILankaTransportRequestConfig<TOptions>);
|
|
160
189
|
/**
|
|
161
190
|
* Parses the body, or names the failure.
|
|
@@ -180,58 +209,39 @@ declare class LankaFetchJsonRequest<TOptions = RequestInit> extends ALankaTransp
|
|
|
180
209
|
* One line, and that is the point — the factory IS the class, so a behaviour
|
|
181
210
|
* cannot exist in one style and not the other.
|
|
182
211
|
*/
|
|
183
|
-
declare const createLankaFetchJsonRequest: <TOptions =
|
|
212
|
+
declare const createLankaFetchJsonRequest: <TOptions extends TLankaRequestInit = TLankaRequestInit>(config?: ILankaTransportRequestConfig<TOptions>) => LankaFetchJsonRequest<TOptions>;
|
|
184
213
|
|
|
185
214
|
/**
|
|
186
|
-
* The
|
|
215
|
+
* The network seam: `fetch`, plus the two things `fetch` cannot be told.
|
|
187
216
|
*
|
|
188
|
-
*
|
|
189
|
-
* set `content-type`, because the browser writes it with the boundary and a
|
|
190
|
-
* hand-set header leaves the body unparseable to the server.
|
|
191
|
-
*/
|
|
192
|
-
declare class LankaFetchFormDataRequest<TOptions = RequestInit> extends ALankaTransportRequest<TOptions> {
|
|
193
|
-
constructor(config?: ILankaTransportRequestConfig<TOptions>);
|
|
194
|
-
protected parse<TReturn>(response: Response): Promise<TReturn>;
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* The functional style of `LankaFetchFormDataRequest`: a multipart body, for an upload.
|
|
217
|
+
* ## Why there is ONE of these
|
|
199
218
|
*
|
|
200
|
-
*
|
|
201
|
-
*
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
*
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
*
|
|
219
|
-
*
|
|
220
|
-
*
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
request(resource: RequestInfo, options?: RequestInit): Promise<Response>;
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* HTTP Fetch FormData transport implementation.
|
|
228
|
-
* Uses native fetch API optimized for FormData requests.
|
|
229
|
-
* Does not set Content-Type header (browser will set it automatically with boundary).
|
|
230
|
-
* For project-specific logic (auth, error handling, etc.), use `request` parameter
|
|
231
|
-
* in Gateway config or create a custom transport.
|
|
219
|
+
* There were three — a plain one, a JSON one and a multipart one — and the split
|
|
220
|
+
* was wrong at birth. `ILankaTransport` exists so a consumer can change the
|
|
221
|
+
* PROTOCOL: a native bridge, a socket, a double that never leaves the process.
|
|
222
|
+
* The three differed in a `content-type` header. That is not a protocol, it is an
|
|
223
|
+
* encoding, and an encoding is a property of the CALL: a gateway with fourteen
|
|
224
|
+
* JSON endpoints and one upload had no way to say so, because its request kind —
|
|
225
|
+
* and with it its transport — was fixed in its constructor. The application that
|
|
226
|
+
* hit this added a `useFormData` flag to its own options and wrote its own
|
|
227
|
+
* transport to read it.
|
|
228
|
+
*
|
|
229
|
+
* So the encoding is decided here, per call, by looking at the body. A gateway
|
|
230
|
+
* posts `FormData` to one endpoint and an object to the next, and neither it nor
|
|
231
|
+
* the request kind has to know.
|
|
232
|
+
*
|
|
233
|
+
* ## What does NOT belong here
|
|
234
|
+
*
|
|
235
|
+
* The base URL (`ALankaGateway` prefixes `apiBaseUrl`), credentials, static
|
|
236
|
+
* headers, CSRF, retry, auth refresh, idempotency keys and deadlines. Every one
|
|
237
|
+
* of those is policy around a request rather than a way of sending one, and every
|
|
238
|
+
* one is a middleware — `useRequestMiddleware`, which `@lankajs/plugin-http`
|
|
239
|
+
* occupies. A transport that grew them would be a second composition mechanism
|
|
240
|
+
* beside the one core already publishes, and "where does a header get added"
|
|
241
|
+
* would have two answers.
|
|
232
242
|
*/
|
|
233
|
-
declare class
|
|
234
|
-
request(resource: RequestInfo, options?:
|
|
243
|
+
declare class LankaFetchTransport implements ILankaTransport<TLankaRequestInit> {
|
|
244
|
+
request(resource: RequestInfo, options?: TLankaRequestInit): Promise<Response>;
|
|
235
245
|
}
|
|
236
246
|
|
|
237
247
|
/**
|
|
@@ -255,4 +265,4 @@ interface ILankaListQueryParams {
|
|
|
255
265
|
filters?: Record<string, unknown>;
|
|
256
266
|
}
|
|
257
267
|
|
|
258
|
-
export { ALankaRequest, IALankaGatewayConfig, type ILankaGatewayConfig, type ILankaGatewayContext, type ILankaListQueryParams, ILankaRequest, type ILankaTransport,
|
|
268
|
+
export { ALankaRequest, IALankaGatewayConfig, type ILankaGatewayConfig, type ILankaGatewayContext, type ILankaListQueryParams, ILankaRequest, type ILankaTransport, LankaFetchJsonRequest, LankaFetchRequest, LankaFetchTransport, TLankaExecuteOptions, TLankaQueryBuilder, TLankaRequestInit, buildLankaQueryParams, createLankaFetchJsonRequest, createLankaFetchRequest, createLankaGateway };
|
package/dist/gateway/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
lankaStandardValidator
|
|
3
|
+
} from "../chunk-GV5DUYST.js";
|
|
1
4
|
import {
|
|
2
5
|
composeLankaRequestMiddleware
|
|
3
6
|
} from "../chunk-YR4MZXMU.js";
|
|
@@ -181,30 +184,49 @@ var ALankaTransportRequest = class extends ALankaRequest {
|
|
|
181
184
|
}
|
|
182
185
|
};
|
|
183
186
|
|
|
184
|
-
// src/gateway/
|
|
185
|
-
var
|
|
187
|
+
// src/gateway/lanka-fetch-transport/LankaFetchTransport.ts
|
|
188
|
+
var CONTENT_TYPE = "content-type";
|
|
189
|
+
var JSON_CONTENT_TYPE = "application/json";
|
|
190
|
+
var LankaFetchTransport = class {
|
|
186
191
|
async request(resource, options) {
|
|
187
|
-
if (options
|
|
188
|
-
|
|
189
|
-
let body = options.body;
|
|
190
|
-
if (typeof body === "object" && !(body instanceof FormData) && !(body instanceof Blob)) {
|
|
191
|
-
body = JSON.stringify(body);
|
|
192
|
-
}
|
|
193
|
-
headers.set("Content-Type", "application/json");
|
|
194
|
-
return await fetch(resource, {
|
|
195
|
-
...options,
|
|
196
|
-
headers,
|
|
197
|
-
body
|
|
198
|
-
});
|
|
192
|
+
if (options === void 0 || options.body === void 0 || options.body === null) {
|
|
193
|
+
return await fetch(resource, options);
|
|
199
194
|
}
|
|
200
|
-
|
|
195
|
+
const { body, headers } = options;
|
|
196
|
+
if (isFormData(body)) {
|
|
197
|
+
if (headers === void 0) return await fetch(resource, options);
|
|
198
|
+
const stripped = new Headers(headers);
|
|
199
|
+
stripped.delete(CONTENT_TYPE);
|
|
200
|
+
return await fetch(resource, { ...options, headers: stripped });
|
|
201
|
+
}
|
|
202
|
+
if (isEncodedBody(body)) return await fetch(resource, options);
|
|
203
|
+
return await fetch(resource, {
|
|
204
|
+
...options,
|
|
205
|
+
headers: withJsonContentType(headers),
|
|
206
|
+
body: JSON.stringify(body)
|
|
207
|
+
});
|
|
201
208
|
}
|
|
202
209
|
};
|
|
210
|
+
function withJsonContentType(headers) {
|
|
211
|
+
const result = new Headers(headers);
|
|
212
|
+
if (!result.has(CONTENT_TYPE)) result.set(CONTENT_TYPE, JSON_CONTENT_TYPE);
|
|
213
|
+
return result;
|
|
214
|
+
}
|
|
215
|
+
function isEncodedBody(body) {
|
|
216
|
+
if (typeof body === "string") return true;
|
|
217
|
+
if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) return true;
|
|
218
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) return true;
|
|
219
|
+
if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return true;
|
|
220
|
+
return typeof ReadableStream !== "undefined" && body instanceof ReadableStream;
|
|
221
|
+
}
|
|
222
|
+
function isFormData(body) {
|
|
223
|
+
return typeof FormData !== "undefined" && body instanceof FormData;
|
|
224
|
+
}
|
|
203
225
|
|
|
204
226
|
// src/gateway/request/lanka-fetch-json-request/LankaFetchJsonRequest.ts
|
|
205
227
|
var LankaFetchJsonRequest = class extends ALankaTransportRequest {
|
|
206
228
|
constructor(config = {}) {
|
|
207
|
-
super(config, () => new
|
|
229
|
+
super(config, () => new LankaFetchTransport());
|
|
208
230
|
}
|
|
209
231
|
/**
|
|
210
232
|
* Parses the body, or names the failure.
|
|
@@ -269,12 +291,22 @@ var buildLankaQueryParams = (input) => {
|
|
|
269
291
|
var ALankaGateway = class {
|
|
270
292
|
requestExecutor;
|
|
271
293
|
queryParamsHandler;
|
|
294
|
+
/**
|
|
295
|
+
* The validator a method checks a response body with.
|
|
296
|
+
*
|
|
297
|
+
* `config.validationService` when one was given, the Standard Schema port
|
|
298
|
+
* otherwise. It used to be accepted by the config and read by nothing: a
|
|
299
|
+
* consumer handing a test double to the gateway got the real validator and no
|
|
300
|
+
* error, which is the worst kind of ignored option — it looks honoured.
|
|
301
|
+
*/
|
|
302
|
+
validationService;
|
|
272
303
|
useMock;
|
|
273
304
|
basePath;
|
|
274
305
|
constructor(config) {
|
|
275
306
|
lankaLogger.printGatewayLog("Create gateway", this);
|
|
276
307
|
const flags = getLankaFlags();
|
|
277
308
|
this.useMock = config.useMock ?? flags.isMockMode ?? false;
|
|
309
|
+
this.validationService = config.validationService ?? lankaStandardValidator;
|
|
278
310
|
this.requestExecutor = config.request ?? new LankaFetchJsonRequest();
|
|
279
311
|
this.basePath = config.basePath ?? "";
|
|
280
312
|
this.queryParamsHandler = config.queryParamsHandler ?? buildLankaQueryParams;
|
|
@@ -363,20 +395,14 @@ var createLankaGateway = (config) => {
|
|
|
363
395
|
return config.methods({
|
|
364
396
|
endpoint: (path) => this.endpoint(path),
|
|
365
397
|
request: (path, options, mockHandler) => this.request(path, options, mockHandler),
|
|
366
|
-
buildQueryParams: (params) => this.buildQueryParams(params)
|
|
398
|
+
buildQueryParams: (params) => this.buildQueryParams(params),
|
|
399
|
+
validationService: this.validationService
|
|
367
400
|
});
|
|
368
401
|
}
|
|
369
402
|
}
|
|
370
403
|
return new FunctionalGateway(config).build();
|
|
371
404
|
};
|
|
372
405
|
|
|
373
|
-
// src/gateway/transport/lanka-fetch-transport/LankaFetchTransport.ts
|
|
374
|
-
var LankaFetchTransport = class {
|
|
375
|
-
async request(resource, options) {
|
|
376
|
-
return await fetch(resource, options);
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
|
|
380
406
|
// src/gateway/request/lanka-fetch-request/LankaFetchRequest.ts
|
|
381
407
|
var LankaFetchRequest = class extends ALankaTransportRequest {
|
|
382
408
|
constructor(config = {}) {
|
|
@@ -392,43 +418,13 @@ var createLankaFetchRequest = (config = {}) => new LankaFetchRequest(config);
|
|
|
392
418
|
|
|
393
419
|
// src/gateway/request/_factories/create-lanka-fetch-json-request/createLankaFetchJsonRequest.ts
|
|
394
420
|
var createLankaFetchJsonRequest = (config = {}) => new LankaFetchJsonRequest(config);
|
|
395
|
-
|
|
396
|
-
// src/gateway/transport/lanka-fetch-form-data-transport/LankaFetchFormDataTransport.ts
|
|
397
|
-
var LankaFetchFormDataTransport = class {
|
|
398
|
-
async request(resource, options) {
|
|
399
|
-
const formDataOptions = { ...options };
|
|
400
|
-
if (formDataOptions.body instanceof FormData && formDataOptions.headers) {
|
|
401
|
-
const headers = new Headers(formDataOptions.headers);
|
|
402
|
-
headers.delete("Content-Type");
|
|
403
|
-
formDataOptions.headers = headers;
|
|
404
|
-
}
|
|
405
|
-
return await fetch(resource, formDataOptions);
|
|
406
|
-
}
|
|
407
|
-
};
|
|
408
|
-
|
|
409
|
-
// src/gateway/request/lanka-fetch-form-data-request/LankaFetchFormDataRequest.ts
|
|
410
|
-
var LankaFetchFormDataRequest = class extends ALankaTransportRequest {
|
|
411
|
-
constructor(config = {}) {
|
|
412
|
-
super(config, () => new LankaFetchFormDataTransport());
|
|
413
|
-
}
|
|
414
|
-
parse(response) {
|
|
415
|
-
return Promise.resolve(response);
|
|
416
|
-
}
|
|
417
|
-
};
|
|
418
|
-
|
|
419
|
-
// src/gateway/request/_factories/create-lanka-fetch-form-data-request/createLankaFetchFormDataRequest.ts
|
|
420
|
-
var createLankaFetchFormDataRequest = (config = {}) => new LankaFetchFormDataRequest(config);
|
|
421
421
|
export {
|
|
422
422
|
ALankaGateway,
|
|
423
423
|
ALankaRequest,
|
|
424
|
-
LankaFetchFormDataRequest,
|
|
425
|
-
LankaFetchFormDataTransport,
|
|
426
424
|
LankaFetchJsonRequest,
|
|
427
|
-
LankaFetchJsonTransport,
|
|
428
425
|
LankaFetchRequest,
|
|
429
426
|
LankaFetchTransport,
|
|
430
427
|
buildLankaQueryParams,
|
|
431
|
-
createLankaFetchFormDataRequest,
|
|
432
428
|
createLankaFetchJsonRequest,
|
|
433
429
|
createLankaFetchRequest,
|
|
434
430
|
createLankaGateway,
|