lanka 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +3 -1
  2. package/dist/{ALankaGateway-CkW1LbKE.d.ts → ALankaGateway-BrVPaZN5.d.ts} +1 -1
  3. package/dist/ILankaFieldError-D5931-vT.d.ts +34 -0
  4. package/dist/ILankaReadableVM-BoPzHEPV.d.ts +72 -0
  5. package/dist/{ILankaScenarioMetadata-GoWWNEQL.d.ts → ILankaScenarioMetadata-Dj4GCqmX.d.ts} +1 -1
  6. package/dist/{ILankaScenarioVM-DUsI-fSc.d.ts → ILankaScenarioVM-DpKFL3iE.d.ts} +5 -4
  7. package/dist/{LankaError-xpI-qj35.d.ts → LankaError-D6RWNyLM.d.ts} +18 -0
  8. package/dist/{LankaScenarioLocator-D86TIwiu.d.ts → LankaScenarioLocator-Dki2Es3O.d.ts} +5 -5
  9. package/dist/{LankaSharedStoreLocator-zS2kLu-S.d.ts → LankaSharedStoreLocator-jsz_gnUm.d.ts} +1 -1
  10. package/dist/_extend/index.d.ts +233 -9
  11. package/dist/_extend/index.js +137 -8
  12. package/dist/_extend/index.js.map +1 -1
  13. package/dist/_internal/index.d.ts +62 -9
  14. package/dist/_internal/index.js +34 -3
  15. package/dist/_internal/index.js.map +1 -1
  16. package/dist/{activeRuntime-B336NU5I.d.ts → activeRuntime-BO-qY0yY.d.ts} +51 -4
  17. package/dist/bootstrap/index.d.ts +11 -10
  18. package/dist/bootstrap/index.js +7 -8
  19. package/dist/cache/index.d.ts +99 -0
  20. package/dist/cache/index.js +1 -0
  21. package/dist/cache/index.js.map +1 -0
  22. package/dist/{chunk-D27MREPB.js → chunk-7DQUF2QR.js} +2 -2
  23. package/dist/{chunk-UJEC7H6K.js → chunk-BHQ2SQ7P.js} +2 -2
  24. package/dist/chunk-CRIRTOLB.js +27 -0
  25. package/dist/chunk-CRIRTOLB.js.map +1 -0
  26. package/dist/chunk-EYDMBI5T.js +550 -0
  27. package/dist/chunk-EYDMBI5T.js.map +1 -0
  28. package/dist/{chunk-C2HP7CRD.js → chunk-FII3PW2G.js} +2 -2
  29. package/dist/{chunk-Q7QESSYF.js → chunk-G32H73QY.js} +10 -1
  30. package/dist/chunk-G32H73QY.js.map +1 -0
  31. package/dist/{chunk-DTO27QFR.js → chunk-H5TIUKRK.js} +2 -2
  32. package/dist/chunk-HVSQOMRE.js +69 -0
  33. package/dist/chunk-HVSQOMRE.js.map +1 -0
  34. package/dist/{chunk-73IVH3C6.js → chunk-O5EUTNR6.js} +3 -3
  35. package/dist/{chunk-RKYKK6MN.js → chunk-RUMUFHSL.js} +2 -2
  36. package/dist/{chunk-G3I7QIZR.js → chunk-SZVNPK24.js} +21 -14
  37. package/dist/chunk-SZVNPK24.js.map +1 -0
  38. package/dist/chunk-UDP6IXDS.js +17 -0
  39. package/dist/chunk-UDP6IXDS.js.map +1 -0
  40. package/dist/{chunk-5MAQVBI2.js → chunk-UMPSR4US.js} +3 -3
  41. package/dist/{chunk-BGVDPDX4.js → chunk-XGMXT4XZ.js} +20 -3
  42. package/dist/chunk-XGMXT4XZ.js.map +1 -0
  43. package/dist/config/index.js +3 -3
  44. package/dist/{createLanka-DI1CSy2Q.d.ts → createLanka-x4oSMs7P.d.ts} +2 -2
  45. package/dist/{createLankaScope-BiFxNQgl.d.ts → createLankaScope-DomNbEvb.d.ts} +1 -1
  46. package/dist/errors/index.d.ts +22 -3
  47. package/dist/errors/index.js +10 -5
  48. package/dist/errors/index.js.map +1 -1
  49. package/dist/gateway/index.d.ts +4 -3
  50. package/dist/gateway/index.js +9 -8
  51. package/dist/gateway/index.js.map +1 -1
  52. package/dist/index.d.ts +11 -10
  53. package/dist/index.js +9 -10
  54. package/dist/{lankaStandardValidator-CL-r-zEV.d.ts → lankaStandardValidator-BUFnysK0.d.ts} +10 -0
  55. package/dist/locator/index.d.ts +5 -4
  56. package/dist/locator/index.js +2 -2
  57. package/dist/logger/index.js +3 -3
  58. package/dist/mock/index.js +3 -3
  59. package/dist/scenario/index.d.ts +81 -6
  60. package/dist/scenario/index.js +6 -8
  61. package/dist/scenario/index.js.map +1 -1
  62. package/dist/storage/index.d.ts +120 -0
  63. package/dist/storage/index.js +1 -0
  64. package/dist/storage/index.js.map +1 -0
  65. package/dist/stream/index.d.ts +10 -9
  66. package/dist/validation/index.d.ts +7 -4
  67. package/dist/validation/index.js +5 -3
  68. package/dist/viewmodel/index.d.ts +188 -32
  69. package/dist/viewmodel/index.js +167 -171
  70. package/dist/viewmodel/index.js.map +1 -1
  71. package/package.json +11 -4
  72. package/skills/lanka-core/SKILL.md +70 -10
  73. package/skills/lanka-core/reference.md +417 -34
  74. package/skills/lanka-packages/SKILL.md +94 -22
  75. package/dist/chunk-BGVDPDX4.js.map +0 -1
  76. package/dist/chunk-G3I7QIZR.js.map +0 -1
  77. package/dist/chunk-GV5DUYST.js +0 -64
  78. package/dist/chunk-GV5DUYST.js.map +0 -1
  79. package/dist/chunk-O5ROO7QF.js +0 -315
  80. package/dist/chunk-O5ROO7QF.js.map +0 -1
  81. package/dist/chunk-Q7QESSYF.js.map +0 -1
  82. package/dist/chunk-UGXSGQPW.js +0 -180
  83. package/dist/chunk-UGXSGQPW.js.map +0 -1
  84. /package/dist/{chunk-D27MREPB.js.map → chunk-7DQUF2QR.js.map} +0 -0
  85. /package/dist/{chunk-UJEC7H6K.js.map → chunk-BHQ2SQ7P.js.map} +0 -0
  86. /package/dist/{chunk-C2HP7CRD.js.map → chunk-FII3PW2G.js.map} +0 -0
  87. /package/dist/{chunk-DTO27QFR.js.map → chunk-H5TIUKRK.js.map} +0 -0
  88. /package/dist/{chunk-73IVH3C6.js.map → chunk-O5EUTNR6.js.map} +0 -0
  89. /package/dist/{chunk-RKYKK6MN.js.map → chunk-RUMUFHSL.js.map} +0 -0
  90. /package/dist/{chunk-5MAQVBI2.js.map → chunk-UMPSR4US.js.map} +0 -0
@@ -3,29 +3,30 @@ import {
3
3
  } from "../chunk-YR4MZXMU.js";
4
4
  import {
5
5
  lankaStandardValidator
6
- } from "../chunk-GV5DUYST.js";
6
+ } from "../chunk-HVSQOMRE.js";
7
+ import "../chunk-CRIRTOLB.js";
7
8
  import {
8
9
  lankaHttpInFlight
9
- } from "../chunk-UJEC7H6K.js";
10
+ } from "../chunk-BHQ2SQ7P.js";
10
11
  import {
11
12
  handleLankaApiError
12
- } from "../chunk-73IVH3C6.js";
13
+ } from "../chunk-O5EUTNR6.js";
13
14
  import "../chunk-J5LA3Q6D.js";
14
15
  import {
15
16
  LankaError
16
- } from "../chunk-Q7QESSYF.js";
17
+ } from "../chunk-G32H73QY.js";
17
18
  import {
18
19
  getLankaHost
19
- } from "../chunk-RKYKK6MN.js";
20
+ } from "../chunk-RUMUFHSL.js";
20
21
  import {
21
22
  lankaLogger
22
- } from "../chunk-C2HP7CRD.js";
23
+ } from "../chunk-FII3PW2G.js";
23
24
  import {
24
25
  getLankaFlags
25
- } from "../chunk-D27MREPB.js";
26
+ } from "../chunk-7DQUF2QR.js";
26
27
  import {
27
28
  getActiveRuntime
28
- } from "../chunk-BGVDPDX4.js";
29
+ } from "../chunk-XGMXT4XZ.js";
29
30
 
30
31
  // src/gateway/request/_abstractions/lanka-request/ALankaRequest.ts
31
32
  function classifyTransportError(error, timedOut) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/gateway/request/_abstractions/lanka-request/ALankaRequest.ts","../../src/gateway/request/_abstractions/lanka-transport-request/ALankaTransportRequest.ts","../../src/gateway/lanka-fetch-transport/LankaFetchTransport.ts","../../src/gateway/request/lanka-fetch-json-request/LankaFetchJsonRequest.ts","../../src/gateway/_utils/build-lanka-query-params/buildLankaQueryParams.ts","../../src/gateway/_abstractions/lanka-gateway/ALankaGateway.ts","../../src/gateway/_factories/create-lanka-gateway/createLankaGateway.ts","../../src/gateway/request/lanka-fetch-request/LankaFetchRequest.ts","../../src/gateway/request/_factories/create-lanka-fetch-request/createLankaFetchRequest.ts","../../src/gateway/request/_factories/create-lanka-fetch-json-request/createLankaFetchJsonRequest.ts"],"sourcesContent":["import type { TLankaRequestInit } from \"../../../_types/TLankaRequestInit\";\nimport type { TLankaErrorHandler } from \"../../../../errors/_types/TLankaErrorHandler\";\nimport type { ILankaRequest } from \"../../../_interfaces/ILankaRequest\";\nimport type { TLankaExecuteOptions } from \"../../../_types/TLankaExecuteOptions\";\nimport { handleLankaApiError } from \"../../../../errors/handle-lanka-api-error/handleLankaApiError\";\nimport { getLankaFlags } from \"../../../../config/get-lanka-flags/getLankaFlags\";\nimport { getLankaHost } from \"../../../../config/get-lanka-host/getLankaHost\";\nimport { lankaHttpInFlight } from \"../../../inflight/lankaHttpInFlight\";\nimport { LankaError } from \"../../../../errors/lanka-error/LankaError\";\nimport { getActiveRuntime } from \"../../../../_internal/active-runtime/activeRuntime\";\nimport { composeLankaRequestMiddleware } from \"../../lankaRequestMiddleware\";\nimport type { ILankaRequestContext } from \"../../lankaRequestMiddleware\";\n\n/**\n * Tags whatever the transport threw with a kind.\n *\n * Here rather than in the transports: `execute` is the single point EVERY\n * request passes through, and tagging in each of the four transports would be\n * four places to forget it.\n *\n * A real `fetch` throws `TypeError` on a broken connection and a `DOMException`\n * named `AbortError` on cancellation; it does not throw on a status code at all.\n *\n * An already-tagged error is NOT re-tagged: a request-policy plugin may report\n * `domain`, and rewriting that to `network` would lose the one thing the kind\n * exists for.\n */\nfunction classifyTransportError(error: unknown, timedOut: boolean): LankaError {\n\tif (LankaError.is(error)) return error;\n\n\t// The name is read off ANYTHING, not only off `Error`.\n\t//\n\t// `DOMException` — how `fetch` reports cancellation — does not extend `Error`\n\t// everywhere: in a browser yes, in jsdom no. An `instanceof Error` check lets\n\t// cancellation past the tagging, and a raw `AbortError` reaches the app with\n\t// neither `kind` nor `status`: retry policy reads it as non-retryable and the\n\t// app as an unknown error, so a cancelled request is shown to the user as a\n\t// failure.\n\tconst name = readErrorName(error);\n\tconst isAbort = name === \"AbortError\" || name === \"TimeoutError\";\n\tif (isAbort) {\n\t\t// Only whoever assembled the lifetime knows who aborted: `AbortSignal` has\n\t\t// one `abort` for everyone. The distinction carries a decision — a timeout\n\t\t// is shown, a cancellation is not.\n\t\tconst timedOutHere = timedOut || name === \"TimeoutError\";\n\t\treturn new LankaError({\n\t\t\tkind: timedOutHere ? \"timeout\" : \"aborted\",\n\t\t\tmessage: timedOutHere ? getLankaHost().timeoutErrorMessage() : readErrorMessage(error),\n\t\t\tcause: error,\n\t\t});\n\t}\n\n\t// `network` ONLY for what looks like a transport failure. A real `fetch`\n\t// throws `TypeError`; everything else comes from code we did not write — the\n\t// app's error handler, a response transformer, a broken plugin — and calling\n\t// that a network failure would invite the user to retry a request that\n\t// arrived and was processed.\n\t//\n\t// Unknown stays unknown and passes through. The framework asserts only what\n\t// it knows.\n\tif (error instanceof TypeError) {\n\t\treturn new LankaError({\n\t\t\tkind: \"network\",\n\t\t\tmessage: getLankaHost().networkErrorMessage(),\n\t\t\tissues: [error.message],\n\t\t\tcause: error,\n\t\t});\n\t}\n\n\treturn error as LankaError;\n}\n\n/** The error name, off `Error`, `DOMException` or anything else carrying one. */\nfunction readErrorName(error: unknown): string | undefined {\n\tif (typeof error !== \"object\" || error === null) return undefined;\n\tconst name: unknown = (error as { name?: unknown }).name;\n\treturn typeof name === \"string\" ? name : undefined;\n}\n\n/**\n * The error text, when there is one.\n *\n * An object without `message` is not stringified: `String({})` yields\n * `[object Object]`, which occupies the message slot and says nothing. Empty is\n * more honest.\n */\nfunction readErrorMessage(error: unknown): string {\n\tif (typeof error === \"string\") return error;\n\tif (typeof error !== \"object\" || error === null) return \"\";\n\tconst message: unknown = (error as { message?: unknown }).message;\n\treturn typeof message === \"string\" ? message : \"\";\n}\n\n/**\n * How a gateway request goes on the wire.\n *\n * A subclass declares one method, `request()`, and does only its own work there:\n * `LankaFetchJsonRequest` returns parsed JSON, `LankaFetchRequest` returns the\n * whole response, a custom kind returns whatever it likes.\n *\n * Overriding `request()` customises the request flow, failure handling, mock\n * substitution, response transformation and log interception.\n */\nexport abstract class ALankaRequest<\n\tTOptions = TLankaRequestInit,\n> implements ILankaRequest<TOptions> {\n\tprotected readonly errorHandler?: TLankaErrorHandler;\n\tprotected readonly useMock: boolean;\n\n\tprotected constructor(config: { errorHandler?: TLankaErrorHandler; useMock?: boolean }) {\n\t\tconst flags = getLankaFlags();\n\n\t\t// The default error-body handler lives HERE because the request is the only\n\t\t// thing that sees the `Response`. Put on the gateway it would sit in a field\n\t\t// nobody reads — the request takes the handler from ITS OWN config — and a\n\t\t// consumer passing `errorHandler` to the gateway would get silence.\n\t\t//\n\t\t// The parse is cheap: core reads the body once and takes `message` from it;\n\t\t// backend-specific shapes are parsed by `@lankajs/plugin-http`.\n\t\tthis.errorHandler = config.errorHandler ?? handleLankaApiError;\n\n\t\tthis.useMock = config.useMock ?? flags.isMockMode ?? false;\n\t}\n\n\t/**\n\t * Performs the request and returns its result — a response, JSON or a custom\n\t * type.\n\t *\n\t * @param endpoint Full URL\n\t * @param options Transport-specific options\n\t * @param mockHandler Mock, when there is one\n\t */\n\tprotected abstract request<TReturn = Response>(\n\t\tendpoint: string,\n\t\toptions?: TOptions,\n\t\tmockHandler?: () => Promise<TReturn>,\n\t): Promise<TReturn>;\n\n\t/**\n\t * The single point EVERY gateway request passes through.\n\t *\n\t * Hence the in-flight accounting here: intent prefetch stands down while\n\t * anything else is on the wire. The `finally` matters more than the increment —\n\t * a rejected request that never decremented would disable prefetching for the\n\t * rest of the session.\n\t */\n\tpublic async execute<TReturn = Response>(\n\t\tendpoint: string,\n\t\toptions?: TLankaExecuteOptions<TOptions>,\n\t\tmockHandler?: () => Promise<TReturn>,\n\t): Promise<TReturn> {\n\t\tconst runtime = getActiveRuntime();\n\t\tconst { signal, timeoutMs, ...rest } = (options ?? {}) as TLankaExecuteOptions<TOptions>;\n\t\t// The caller's deadline travels IN THE CONTEXT, not only in the closure:\n\t\t// otherwise a policy assigning deadlines per request class could not tell\n\t\t// \"no deadline given\" from \"given by the caller\" and would override an\n\t\t// explicit request with a blanket default.\n\t\tconst fallbackDeadline = runtime?.requestTimeoutMs;\n\n\t\t// No options passed means none are produced. Destructuring yields `{}` even\n\t\t// from `undefined`, and handing that empty object to the transport would\n\t\t// change the request: \"no options\" and \"empty options\" are different\n\t\t// statements, and the transport is entitled to tell them apart.\n\t\tconst passedOptions: unknown = options === undefined ? undefined : rest;\n\n\t\t/*\n\t\t * The lifetime is assembled PER ATTEMPT, not per call, and that does two\n\t\t * things at once.\n\t\t *\n\t\t * Under retry a shared deadline would start the third attempt with whatever\n\t\t * the first two left, so the retry aborts before reaching the server.\n\t\t *\n\t\t * And it is the only way to let middleware set the deadline: `ctx.timeoutMs`\n\t\t * is read on every attempt, which is how a request-policy plugin assigns a\n\t\t * deadline per request CLASS — a file upload and a list read cannot share\n\t\t * one value.\n\t\t *\n\t\t * Caller cancellation stays end-to-end: one `signal` for all attempts.\n\t\t */\n\t\tlet lastTimedOut = false;\n\n\t\t// Tagging happens INSIDE, around the request itself, not in the outer\n\t\t// catch: middleware must receive an already-tagged error, or a retrying\n\t\t// middleware cannot tell a network failure from a domain rejection and\n\t\t// retries what must not be retried. The outer catch stays as a backstop.\n\t\tconst perform = async (ctx: ILankaRequestContext): Promise<unknown> => {\n\t\t\tconst lifetime = createRequestLifetime(signal, ctx.timeoutMs ?? fallbackDeadline);\n\t\t\ttry {\n\t\t\t\treturn await this.request<TReturn>(\n\t\t\t\t\tctx.endpoint,\n\t\t\t\t\twithSignal(ctx.options, lifetime.signal) as TOptions,\n\t\t\t\t\tmockHandler,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tlastTimedOut = lifetime.timedOut();\n\t\t\t\tthrow classifyTransportError(error, lastTimedOut);\n\t\t\t} finally {\n\t\t\t\tlifetime.dispose();\n\t\t\t}\n\t\t};\n\n\t\tconst run = composeLankaRequestMiddleware(runtime?.requestMiddleware ?? [], perform);\n\n\t\tlankaHttpInFlight.begin();\n\t\ttry {\n\t\t\t// The chain runs INSIDE the same guard as the request. A catch placed\n\t\t\t// outside would leave a permanent +1 when a plugin throws, disabling\n\t\t\t// prefetch for the rest of the session — the very defect this `finally`\n\t\t\t// exists to prevent.\n\t\t\treturn (await run({\n\t\t\t\tendpoint,\n\t\t\t\toptions: passedOptions,\n\t\t\t\tattempt: 1,\n\t\t\t\ttimeoutMs,\n\t\t\t})) as TReturn;\n\t\t} catch (error) {\n\t\t\tthrow classifyTransportError(error, lastTimedOut);\n\t\t} finally {\n\t\t\tlankaHttpInFlight.end();\n\t\t}\n\t}\n}\n\ninterface IRequestLifetime {\n\treadonly signal: AbortSignal | undefined;\n\t/** Whether OUR timer aborted the request rather than the caller. */\n\ttimedOut(): boolean;\n\tdispose(): void;\n}\n\n/**\n * Combines the caller's signal and our own timeout into one request lifetime.\n *\n * The outcome looks the same — an interrupted request — but the decisions\n * differ: a timeout is shown and offered for retry, a user cancellation is not\n * shown at all. `AbortSignal` does not distinguish them: one `abort`, whose\n * reason belongs to whoever got there first. Hence the private flag.\n *\n * Not `AbortSignal.timeout` alone: it cannot combine with a foreign signal\n * without `AbortSignal.any`, which older engines lack. Assembling by hand works\n * everywhere and costs one listener.\n */\nfunction createRequestLifetime(\n\texternal: AbortSignal | undefined,\n\ttimeoutMs: number | undefined,\n): IRequestLifetime {\n\tif (!external && !timeoutMs) {\n\t\treturn { signal: undefined, timedOut: () => false, dispose: () => undefined };\n\t}\n\n\tconst controller = new AbortController();\n\tlet expired = false;\n\n\tconst timer =\n\t\ttimeoutMs === undefined\n\t\t\t? undefined\n\t\t\t: setTimeout(() => {\n\t\t\t\t\texpired = true;\n\t\t\t\t\tcontroller.abort(new DOMException(\"Request timed out\", \"TimeoutError\"));\n\t\t\t\t}, timeoutMs);\n\n\tconst onExternalAbort = (): void => {\n\t\tcontroller.abort(external?.reason);\n\t};\n\n\tif (external) {\n\t\tif (external.aborted) onExternalAbort();\n\t\telse external.addEventListener(\"abort\", onExternalAbort, { once: true });\n\t}\n\n\treturn {\n\t\tsignal: controller.signal,\n\t\ttimedOut: () => expired,\n\t\tdispose: () => {\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\texternal?.removeEventListener(\"abort\", onExternalAbort);\n\t\t},\n\t};\n}\n\n/**\n * Attaches the signal to the options, inventing nothing.\n *\n * With no options and no signal the transport receives `undefined` — exactly\n * what the caller passed. An empty object instead looks harmless but is a\n * different statement, and the transport is entitled to tell them apart.\n */\nfunction withSignal(options: unknown, signal: AbortSignal | undefined): unknown {\n\tif (signal === undefined) return options;\n\treturn { ...(options ?? {}), signal };\n}\n","import { ALankaRequest } from \"../lanka-request/ALankaRequest\";\nimport { LankaError } from \"../../../../errors/lanka-error/LankaError\";\nimport { getLankaFlags } from \"../../../../config/get-lanka-flags/getLankaFlags\";\nimport { getLankaHost } from \"../../../../config/get-lanka-host/getLankaHost\";\nimport type { ILankaTransport } from \"../../../_interfaces/ILankaTransport\";\nimport type { TLankaRequestInit } from \"../../../_types/TLankaRequestInit\";\nimport type { TLankaErrorHandler } from \"../../../../errors/_types/TLankaErrorHandler\";\n\nexport interface ILankaTransportRequestConfig<TOptions> {\n\ttransport?: ILankaTransport<TOptions>;\n\terrorHandler?: TLankaErrorHandler;\n\tuseMock?: boolean;\n}\n\n/**\n * The shape every fetch-backed request has: mock, send, check, parse.\n *\n * The concrete requests differ in ONE place — how they turn a successful\n * `Response` into a value — so a third kind is a subclass with one method rather\n * than a third copy of the sequence.\n *\n * The default transport stays a constructor PARAMETER even though both shipped\n * kinds pass the same one. It is the seam a request kind that is not fetch-backed\n * comes through: this template is the mock/send/check/parse sequence, and nothing\n * in it is about HTTP. Defaulting the parameter here would fix `TOptions` to\n * fetch options for everyone who reuses the sequence.\n */\nexport abstract class ALankaTransportRequest<\n\tTOptions = TLankaRequestInit,\n> extends ALankaRequest<TOptions> {\n\tprotected readonly transport: ILankaTransport<TOptions>;\n\n\tprotected constructor(\n\t\tconfig: ILankaTransportRequestConfig<TOptions>,\n\t\tcreateDefaultTransport: () => ILankaTransport<TOptions>,\n\t) {\n\t\tconst flags = getLankaFlags();\n\n\t\tsuper({\n\t\t\terrorHandler: config.errorHandler,\n\t\t\tuseMock: config.useMock ?? flags.isMockMode ?? false,\n\t\t});\n\n\t\tthis.transport = config.transport ?? createDefaultTransport();\n\t}\n\n\tprotected async request<TReturn>(\n\t\tendpoint: string,\n\t\toptions?: TOptions,\n\t\tmockHandler?: () => Promise<TReturn>,\n\t): Promise<TReturn> {\n\t\tif (this.useMock && mockHandler) {\n\t\t\treturn await mockHandler();\n\t\t}\n\n\t\tconst response = await this.transport.request(endpoint, options);\n\t\tif (!response.ok) return await this.refuse(response);\n\n\t\treturn await this.parse<TReturn>(response);\n\t}\n\n\t/**\n\t * Turns a successful response into the value the caller asked for.\n\t *\n\t * The one step that genuinely differs between request kinds.\n\t */\n\tprotected abstract parse<TReturn>(response: Response): Promise<TReturn>;\n\n\t/**\n\t * Refuses an unsuccessful response, and never returns.\n\t *\n\t * `TLankaErrorHandler` is typed `Promise<never>` — a handler must throw. It is\n\t * still CALLED and then followed by a throw, because a handler that breaks its\n\t * contract and returns would otherwise hand `undefined` back as if the request\n\t * had succeeded, and a non-value must never become a value.\n\t */\n\tprotected async refuse(response: Response): Promise<never> {\n\t\tif (this.errorHandler) {\n\t\t\tawait this.errorHandler(response);\n\t\t}\n\n\t\t// Kind `http`, not a bare Error: the server answered, and answered with a\n\t\t// code. Without the kind this reads as a network failure, and the user is\n\t\t// offered a retry of a request that already got a meaningful answer.\n\t\tthrow new LankaError({\n\t\t\tkind: \"http\",\n\t\t\tmessage: getLankaHost().httpErrorMessage(response.status),\n\t\t\tstatus: response.status,\n\t\t});\n\t}\n}\n","import type { ILankaTransport } from \"../_interfaces/ILankaTransport\";\nimport type { TLankaRequestInit } from \"../_types/TLankaRequestInit\";\n\n/** What an unencoded body is sent as, and the header that says so. */\nconst CONTENT_TYPE = \"content-type\";\nconst JSON_CONTENT_TYPE = \"application/json\";\n\n/**\n * The network seam: `fetch`, plus the two things `fetch` cannot be told.\n *\n * ## Why there is ONE of these\n *\n * There were three — a plain one, a JSON one and a multipart one — and the split\n * was wrong at birth. `ILankaTransport` exists so a consumer can change the\n * PROTOCOL: a native bridge, a socket, a double that never leaves the process.\n * The three differed in a `content-type` header. That is not a protocol, it is an\n * encoding, and an encoding is a property of the CALL: a gateway with fourteen\n * JSON endpoints and one upload had no way to say so, because its request kind —\n * and with it its transport — was fixed in its constructor. The application that\n * hit this added a `useFormData` flag to its own options and wrote its own\n * transport to read it.\n *\n * So the encoding is decided here, per call, by looking at the body. A gateway\n * posts `FormData` to one endpoint and an object to the next, and neither it nor\n * the request kind has to know.\n *\n * ## What does NOT belong here\n *\n * The base URL (`ALankaGateway` prefixes `apiBaseUrl`), credentials, static\n * headers, CSRF, retry, auth refresh, idempotency keys and deadlines. Every one\n * of those is policy around a request rather than a way of sending one, and every\n * one is a middleware — `useRequestMiddleware`, which `@lankajs/plugin-http`\n * occupies. A transport that grew them would be a second composition mechanism\n * beside the one core already publishes, and \"where does a header get added\"\n * would have two answers.\n */\nexport class LankaFetchTransport implements ILankaTransport<TLankaRequestInit> {\n\tasync request(resource: RequestInfo, options?: TLankaRequestInit): Promise<Response> {\n\t\t// Nothing to encode: the object the caller assembled reaches `fetch`\n\t\t// unchanged, `undefined` included. \"No options\" and \"empty options\" are\n\t\t// different statements and `fetch` is entitled to tell them apart.\n\t\tif (options === undefined || options.body === undefined || options.body === null) {\n\t\t\treturn await fetch(resource, options as RequestInit | undefined);\n\t\t}\n\n\t\tconst { body, headers } = options;\n\n\t\t// Multipart: the header is REMOVED, not set. The boundary is generated with\n\t\t// the body, and a hand-written `content-type` carries none — the server then\n\t\t// reads zero fields out of a request that looks correct.\n\t\tif (isFormData(body)) {\n\t\t\tif (headers === undefined) return await fetch(resource, options as RequestInit);\n\n\t\t\tconst stripped = new Headers(headers);\n\t\t\tstripped.delete(CONTENT_TYPE);\n\t\t\treturn await fetch(resource, { ...options, headers: stripped } as RequestInit);\n\t\t}\n\n\t\t// Already something `fetch` understands: untouched.\n\t\tif (isEncodedBody(body)) return await fetch(resource, options as RequestInit);\n\n\t\treturn await fetch(resource, {\n\t\t\t...options,\n\t\t\theaders: withJsonContentType(headers),\n\t\t\tbody: JSON.stringify(body),\n\t\t});\n\t}\n}\n\n/**\n * The header set, with `content-type` filled in only if the caller left it out.\n *\n * Not overwritten: `application/merge-patch+json` and `application/ld+json` are\n * JSON that a server distinguishes, and a transport that flattened them to\n * `application/json` would turn a PATCH into a request the server refuses — for\n * a header the caller had already written correctly.\n */\nfunction withJsonContentType(headers: HeadersInit | undefined): Headers {\n\tconst result = new Headers(headers);\n\tif (!result.has(CONTENT_TYPE)) result.set(CONTENT_TYPE, JSON_CONTENT_TYPE);\n\treturn result;\n}\n\n/**\n * Whether `fetch` can already send this body.\n *\n * Every global here is guarded by `typeof`: core runs in node and React Native\n * as well as a browser, and `ReadableStream` in particular is absent on engines\n * this framework supports. An unguarded `instanceof` against a missing global is\n * a `ReferenceError` on the first request, from a transport, in production.\n *\n * Cheapest and most common first. A string — an already-serialised body — stops\n * on line one.\n */\nfunction isEncodedBody(body: unknown): body is BodyInit {\n\tif (typeof body === \"string\") return true;\n\tif (typeof URLSearchParams !== \"undefined\" && body instanceof URLSearchParams) return true;\n\tif (typeof Blob !== \"undefined\" && body instanceof Blob) return true;\n\tif (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return true;\n\treturn typeof ReadableStream !== \"undefined\" && body instanceof ReadableStream;\n}\n\n/**\n * Multipart, checked separately because it is the one body whose header is\n * removed rather than added.\n */\nfunction isFormData(body: unknown): body is FormData {\n\treturn typeof FormData !== \"undefined\" && body instanceof FormData;\n}\n","import { ALankaTransportRequest } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransportRequestConfig } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { TLankaRequestInit } from \"../../_types/TLankaRequestInit\";\nimport { LankaFetchTransport } from \"../../lanka-fetch-transport/LankaFetchTransport\";\nimport { LankaError } from \"../../../errors/lanka-error/LankaError\";\n\n/** The JSON request: parses the body, and refuses a body that is not JSON. */\n/**\n * A request kind that answers a parsed JSON body — what most endpoints return.\n *\n * A gateway holds one, and is handed it rather than constructing it, which is\n * what lets a test give the same gateway a transport that never leaves the\n * process. `createLankaFetchJsonRequest()` builds the same class.\n */\nexport class LankaFetchJsonRequest<\n\tTOptions extends TLankaRequestInit = TLankaRequestInit,\n> extends ALankaTransportRequest<TOptions> {\n\tconstructor(config: ILankaTransportRequestConfig<TOptions> = {}) {\n\t\tsuper(config, () => new LankaFetchTransport());\n\t}\n\n\t/**\n\t * Parses the body, or names the failure.\n\t *\n\t * The content type is read for the ERROR MESSAGE only. Using it to choose\n\t * between two parse paths, where the second answers `{}` for any non-empty\n\t * body it cannot parse, fails silently: the caller's schema is the first thing\n\t * to notice, and the caller's SCREEN is where it shows up.\n\t *\n\t * A measured case: a dev server whose `/api` fell through to the SPA fallback\n\t * answered `200 text/html` with `index.html`. Turned into `{}`, the schema\n\t * refused it and a person read a validator's issue list on the sign-in card. A\n\t * body a JSON transport cannot parse is never a value — it is a misrouted\n\t * request, and saying so names the actual failure.\n\t */\n\tprotected async parse<TReturn>(response: Response): Promise<TReturn> {\n\t\tconst contentType = response.headers.get(\"content-type\");\n\n\t\tconst text = await response.text();\n\t\tif (!text) {\n\t\t\treturn undefined as TReturn;\n\t\t}\n\n\t\ttry {\n\t\t\treturn JSON.parse(text) as TReturn;\n\t\t} catch (error) {\n\t\t\t// `schema`, not `network`: the request arrived, the server answered, and\n\t\t\t// the answer was the wrong shape. Not cosmetic — a network failure\n\t\t\t// invites a retry, while retrying a broken contract is pointless and\n\t\t\t// blaming the user for it more so.\n\t\t\tthrow new LankaError({\n\t\t\t\tkind: \"schema\",\n\t\t\t\tmessage:\n\t\t\t\t\t`Failed to parse JSON response (content-type: ${contentType ?? \"none\"}): ` +\n\t\t\t\t\t`${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\tcause: error,\n\t\t\t});\n\t\t}\n\t}\n}\n","import { TLankaQueryParams } from \"../../_types/TLankaQueryParams\";\nimport { TLankaQueryBuilder } from \"../../_types/TLankaQueryBuilder\";\n\n/**\n * The query string a gateway sends, from the object a method was called with.\n *\n * Arrays become `key[]` repeated, nested objects become `key[inner]`: the shape\n * most JSON APIs read back without being told about it.\n *\n * Plain loops over `Object.keys` rather than `Object.entries` and `forEach`: this\n * runs on every request that carries a filter, and the pair array `entries`\n * builds — two allocations per key, thrown away immediately — is a cost with\n * nothing to show for it.\n */\nexport const buildLankaQueryParams: TLankaQueryBuilder = <T extends Record<string, unknown>>(\n\tinput: T,\n): URLSearchParams => {\n\tconst params = new URLSearchParams();\n\n\tconst append = (key: string, value: TLankaQueryParams): void => {\n\t\tif (value == null) return;\n\n\t\tif (Array.isArray(value)) {\n\t\t\t// The bracketed key once for the whole array, not once per element.\n\t\t\tconst itemKey = `${key}[]`;\n\t\t\tfor (let index = 0; index < value.length; index += 1) append(itemKey, value[index]);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (typeof value === \"object\") {\n\t\t\tconst inner = value as Record<string, TLankaQueryParams>;\n\t\t\tconst innerKeys = Object.keys(inner);\n\n\t\t\tfor (let index = 0; index < innerKeys.length; index += 1) {\n\t\t\t\tconst innerKey = innerKeys[index];\n\t\t\t\tappend(`${key}[${innerKey}]`, inner[innerKey]);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tparams.append(key, String(value));\n\t};\n\n\tconst source = input as Record<string, TLankaQueryParams>;\n\tconst keys = Object.keys(source);\n\n\tfor (let index = 0; index < keys.length; index += 1) append(keys[index], source[keys[index]]);\n\n\treturn params;\n};\n","import type { TLankaRequestInit } from \"../../_types/TLankaRequestInit\";\nimport type { IALankaGatewayConfig } from \"../../_interfaces/IALankaGatewayConfig\";\nimport { lankaLogger } from \"../../../logger/lanka-logger/LankaLogger\";\nimport { LankaFetchJsonRequest } from \"../../request/lanka-fetch-json-request/LankaFetchJsonRequest\";\nimport type { ILankaRequest } from \"../../_interfaces/ILankaRequest\";\nimport type { TLankaExecuteOptions } from \"../../_types/TLankaExecuteOptions\";\nimport { buildLankaQueryParams } from \"../../_utils/build-lanka-query-params/buildLankaQueryParams\";\nimport { TLankaQueryParams } from \"../../_types/TLankaQueryParams\";\nimport { TLankaQueryBuilder } from \"../../_types/TLankaQueryBuilder\";\nimport { getLankaFlags } from \"../../../config/get-lanka-flags/getLankaFlags\";\nimport { getLankaHost } from \"../../../config/get-lanka-host/getLankaHost\";\nimport { lankaStandardValidator } from \"../../../validation/lanka-standard-validator/lankaStandardValidator\";\nimport type { ILankaValidator } from \"../../../validation/lanka-standard-validator/lankaStandardValidator\";\n\nexport abstract class ALankaGateway<TOptions = TLankaRequestInit> {\n\tprotected requestExecutor: ILankaRequest<TOptions>;\n\tprotected queryParamsHandler: TLankaQueryBuilder;\n\n\t/**\n\t * The validator a method checks a response body with.\n\t *\n\t * `config.validationService` when one was given, the Standard Schema port\n\t * otherwise. It used to be accepted by the config and read by nothing: a\n\t * consumer handing a test double to the gateway got the real validator and no\n\t * error, which is the worst kind of ignored option — it looks honoured.\n\t */\n\tprotected readonly validationService: ILankaValidator;\n\n\tprotected readonly useMock: boolean;\n\tprotected readonly basePath: string;\n\n\tprotected constructor(config: IALankaGatewayConfig<TOptions>) {\n\t\tlankaLogger.printGatewayLog(\"Create gateway\", this);\n\t\tconst flags = getLankaFlags();\n\t\tthis.useMock = config.useMock ?? flags.isMockMode ?? false;\n\t\tthis.validationService = config.validationService ?? lankaStandardValidator;\n\n\t\t// A gateway with nothing said about transport talks JSON over `fetch`, which\n\t\t// is what almost every one of them does. Supplying a request is how a gateway\n\t\t// stops being ordinary — a raw `Response`, a multipart upload, a transport\n\t\t// that never leaves the process — and that stays a decision rather than a\n\t\t// line every gateway has to carry to be born.\n\t\t// The cast covers the FRAMEWORK picking its own fallback, and nothing a\n\t\t// consumer does. `TOptions` is unconstrained here on purpose — a gateway may\n\t\t// front a request that never speaks HTTP, and the port promises exactly that\n\t\t// — so the JSON default cannot be proven to fit a `TOptions` nobody has\n\t\t// named yet. A consumer whose options are not fetch-shaped supplies\n\t\t// `request`, and this line never runs for them.\n\t\tthis.requestExecutor = config.request ?? new LankaFetchJsonRequest();\n\n\t\tthis.basePath = config.basePath ?? \"\";\n\t\tthis.queryParamsHandler = config.queryParamsHandler ?? buildLankaQueryParams;\n\t}\n\n\t/**\n\t * Resolves endpoint for request.\n\t * - Absolute paths (starting with \"/\") are returned as-is\n\t * - Relative paths are joined with basePath\n\t * - Query-only strings like \"?a=1\" are attached to basePath\n\t */\n\tprotected endpoint(path: string = \"\"): string {\n\t\t// An absolute URL is detected BEFORE joining with `basePath`, not after:\n\t\t// otherwise `https://other.host/health` first becomes\n\t\t// `/things/https://other.host/health` and there is nothing left to detect.\n\t\tif (isAbsoluteUrl(path)) return path;\n\n\t\treturn this.withApiBase(this.resolvePath(path));\n\t}\n\n\t/**\n\t * Joins `basePath` and the method path.\n\t */\n\tprivate resolvePath(path: string): string {\n\t\tif (!path) return this.basePath;\n\n\t\tif (path.startsWith(\"/\")) return path;\n\n\t\tif (path.startsWith(\"?\")) return `${this.basePath}${path}`;\n\n\t\t// No leading-slash case here: the check above already returned for one, so\n\t\t// stripping it again was a branch no input could take — uncoverable by\n\t\t// construction, and it counted against the coverage floor that gates this\n\t\t// package.\n\t\tconst left = this.basePath.endsWith(\"/\") ? this.basePath.slice(0, -1) : this.basePath;\n\t\treturn `${left}/${path}`;\n\t}\n\n\t/**\n\t * Prefixes the API base URL from the host contract.\n\t *\n\t * Here rather than in every consumer: otherwise each consumer knows the URL\n\t * and the framework does not, and a realtime plugin would have to know a\n\t * specific application's build.\n\t *\n\t * Declaring the field and not using it would be worse than not declaring it: a\n\t * declaration nothing is built from is a second truth, free to diverge from\n\t * the first.\n\t *\n\t * An absolute URL never reaches here — `endpoint()` filters it out before the\n\t * join.\n\t */\n\tprivate withApiBase(path: string): string {\n\t\tconst base = withoutTrailingSlashes(getLankaHost().apiBaseUrl);\n\t\tif (!base) return path;\n\t\tif (!path) return base;\n\n\t\treturn path.startsWith(\"/\") ? `${base}${path}` : `${base}/${path}`;\n\t}\n\n\tprotected buildQueryParams<T extends object>(params: T): URLSearchParams {\n\t\treturn this.queryParamsHandler(params as Record<string, TLankaQueryParams>);\n\t}\n\n\tprotected async request<TReturn = unknown>(\n\t\tpath: string,\n\t\toptions?: TLankaExecuteOptions<TOptions>,\n\t\tmockHandler?: () => Promise<TReturn>,\n\t): Promise<TReturn> {\n\t\treturn this.requestExecutor.execute<TReturn>(this.endpoint(path), options, mockHandler);\n\t}\n\n\t/**\n\t * Allows to replace request implementation at runtime (e.g. feature flags / tests).\n\t * If you prefer static customization - override `request()` in a subclass.\n\t */\n\tprotected setRequest(request: ILankaRequest<TOptions>): void {\n\t\tthis.requestExecutor = request;\n\t}\n\n\tprotected setQueryParamsHandler(handler: TLankaQueryBuilder): void {\n\t\tthis.queryParamsHandler = handler;\n\t}\n}\n\n/**\n * A scheme plus `//` — a URL that already knows where it is going.\n *\n * A standalone function rather than a method: it is not about a particular\n * gateway, and `endpoint()` needs it before any joining.\n */\nfunction isAbsoluteUrl(path: string): boolean {\n\t// The cheap half first: a scheme needs `://`, and `includes` answers without\n\t// starting the regex engine. Every relative path an application writes — which\n\t// is nearly all of them — stops on this line.\n\tif (!path.includes(\"://\")) return false;\n\n\treturn /^[a-z][a-z\\d+\\-.]*:\\/\\//i.test(path);\n}\n\n/**\n * The API base without its trailing slashes, remembered between calls.\n *\n * The host answers the same string for the life of an application, and trimming\n * it is a regex replace otherwise run on every endpoint of every request. One\n * entry is enough: there is one active host, and a second framework in the same\n * process simply replaces what is remembered here.\n */\nlet lastRawBase: string | null = null;\nlet lastTrimmedBase = \"\";\n\nfunction withoutTrailingSlashes(base: string): string {\n\tif (base !== lastRawBase) {\n\t\tlastRawBase = base;\n\t\tlastTrimmedBase = base.replace(/\\/+$/, \"\");\n\t}\n\n\treturn lastTrimmedBase;\n}\n","import { ALankaGateway } from \"../../_abstractions/lanka-gateway/ALankaGateway\";\nimport type { IALankaGatewayConfig } from \"../../_interfaces/IALankaGatewayConfig\";\nimport type { ILankaGatewayContext } from \"../../_interfaces/ILankaGatewayContext\";\n\n/** What a gateway is built from, whichever style builds it. */\nexport interface ILankaGatewayConfig<\n\tTOptions,\n\tTMethods extends object,\n> extends IALankaGatewayConfig<TOptions> {\n\t/** The endpoints this gateway offers, written over its own surface. */\n\tmethods: (context: ILankaGatewayContext<TOptions>) => TMethods;\n}\n\n/**\n * A gateway, without writing a class.\n *\n * The bridge below is the whole mechanism, and it lives here rather than on the\n * base for two reasons. The language reads `protected` from inside a deriving\n * class body and nowhere else, so a factory outside the hierarchy could only\n * reach the public half — the wrong one. And a `toStyleContext` ON the base\n * would put `TOptions` in a method's parameter position, making the class\n * invariant in it: every `ALankaGateway<unknown>` the locator holds would stop\n * accepting a gateway typed for `RequestInit`.\n *\n * One implementation: what comes back is an instance of `ALankaGateway`, so a\n * behaviour fix reaches both styles at once.\n */\nexport const createLankaGateway = <TOptions, TMethods extends object>(\n\tconfig: ILankaGatewayConfig<TOptions, TMethods>,\n): TMethods => {\n\tclass FunctionalGateway extends ALankaGateway<TOptions> {\n\t\t// The base keeps a protected constructor — it is abstract, and a consumer\n\t\t// reaching for `new ALankaGateway()` would get an object with no endpoints.\n\t\t// A subclass may widen it, and this one is the subclass.\n\t\tpublic constructor(gatewayConfig: IALankaGatewayConfig<TOptions>) {\n\t\t\tsuper(gatewayConfig);\n\t\t}\n\n\t\tpublic build(): TMethods {\n\t\t\treturn config.methods({\n\t\t\t\tendpoint: (path) => this.endpoint(path),\n\t\t\t\trequest: (path, options, mockHandler) => this.request(path, options, mockHandler),\n\t\t\t\tbuildQueryParams: (params) => this.buildQueryParams(params),\n\t\t\t\tvalidationService: this.validationService,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn new FunctionalGateway(config).build();\n};\n","import { ALankaTransportRequest } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransportRequestConfig } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { TLankaRequestInit } from \"../../_types/TLankaRequestInit\";\nimport { LankaFetchTransport } from \"../../lanka-fetch-transport/LankaFetchTransport\";\n\n/**\n * The raw request: hands the `Response` back untouched.\n *\n * The minimal, extensible case — a caller wanting headers, a stream, a blob or a\n * `204` reads them off the response itself. Multipart uploads come through here\n * too: the transport encodes by looking at the body, so posting a `FormData` and\n * posting an object are the same call.\n *\n * `TOptions` is CONSTRAINED to fetch options rather than merely defaulted to\n * them. A consumer widening it — their own `interface IRequestOptions extends\n * TLankaRequestInit` — still gets the shipped transport, because the constraint\n * is what lets the framework hand one over without a cast. Unconstrained, the\n * assignment did not typecheck and core cast its way past it; the cast worked\n * here and was unavailable to the consumer, who wrote a transport instead.\n */\nexport class LankaFetchRequest<\n\tTOptions extends TLankaRequestInit = TLankaRequestInit,\n> extends ALankaTransportRequest<TOptions> {\n\tconstructor(config: ILankaTransportRequestConfig<TOptions> = {}) {\n\t\tsuper(config, () => new LankaFetchTransport());\n\t}\n\n\tprotected parse<TReturn>(response: Response): Promise<TReturn> {\n\t\treturn Promise.resolve(response as unknown as TReturn);\n\t}\n}\n","import { LankaFetchRequest } from \"../../lanka-fetch-request/LankaFetchRequest\";\nimport type { ILankaTransportRequestConfig } from \"../../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { TLankaRequestInit } from \"../../../_types/TLankaRequestInit\";\n\n/**\n * The functional style of `LankaFetchRequest`: the raw `Response`, for a download or a stream.\n *\n * One line, and that is the point — the factory IS the class, so a behaviour\n * cannot exist in one style and not the other.\n */\nexport const createLankaFetchRequest = <TOptions extends TLankaRequestInit = TLankaRequestInit>(\n\tconfig: ILankaTransportRequestConfig<TOptions> = {},\n): LankaFetchRequest<TOptions> => new LankaFetchRequest<TOptions>(config);\n","import { LankaFetchJsonRequest } from \"../../lanka-fetch-json-request/LankaFetchJsonRequest\";\nimport type { ILankaTransportRequestConfig } from \"../../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { TLankaRequestInit } from \"../../../_types/TLankaRequestInit\";\n\n/**\n * The functional style of `LankaFetchJsonRequest`: a JSON body, which is what most endpoints answer.\n *\n * One line, and that is the point — the factory IS the class, so a behaviour\n * cannot exist in one style and not the other.\n */\nexport const createLankaFetchJsonRequest = <TOptions extends TLankaRequestInit = TLankaRequestInit>(\n\tconfig: ILankaTransportRequestConfig<TOptions> = {},\n): LankaFetchJsonRequest<TOptions> => new LankaFetchJsonRequest<TOptions>(config);\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/gateway/request/_abstractions/lanka-request/ALankaRequest.ts","../../src/gateway/request/_abstractions/lanka-transport-request/ALankaTransportRequest.ts","../../src/gateway/lanka-fetch-transport/LankaFetchTransport.ts","../../src/gateway/request/lanka-fetch-json-request/LankaFetchJsonRequest.ts","../../src/gateway/_utils/build-lanka-query-params/buildLankaQueryParams.ts","../../src/gateway/_abstractions/lanka-gateway/ALankaGateway.ts","../../src/gateway/_factories/create-lanka-gateway/createLankaGateway.ts","../../src/gateway/request/lanka-fetch-request/LankaFetchRequest.ts","../../src/gateway/request/_factories/create-lanka-fetch-request/createLankaFetchRequest.ts","../../src/gateway/request/_factories/create-lanka-fetch-json-request/createLankaFetchJsonRequest.ts"],"sourcesContent":["import type { TLankaRequestInit } from \"../../../_types/TLankaRequestInit\";\nimport type { TLankaErrorHandler } from \"../../../../errors/_types/TLankaErrorHandler\";\nimport type { ILankaRequest } from \"../../../_interfaces/ILankaRequest\";\nimport type { TLankaExecuteOptions } from \"../../../_types/TLankaExecuteOptions\";\nimport { handleLankaApiError } from \"../../../../errors/handle-lanka-api-error/handleLankaApiError\";\nimport { getLankaFlags } from \"../../../../config/get-lanka-flags/getLankaFlags\";\nimport { getLankaHost } from \"../../../../config/get-lanka-host/getLankaHost\";\nimport { lankaHttpInFlight } from \"../../../inflight/lankaHttpInFlight\";\nimport { LankaError } from \"../../../../errors/lanka-error/LankaError\";\nimport { getActiveRuntime } from \"../../../../_internal/active-runtime/activeRuntime\";\nimport { composeLankaRequestMiddleware } from \"../../lankaRequestMiddleware\";\nimport type { ILankaRequestContext } from \"../../lankaRequestMiddleware\";\n\n/**\n * Tags whatever the transport threw with a kind.\n *\n * Here rather than in the transports: `execute` is the single point EVERY\n * request passes through, and tagging in each of the four transports would be\n * four places to forget it.\n *\n * A real `fetch` throws `TypeError` on a broken connection and a `DOMException`\n * named `AbortError` on cancellation; it does not throw on a status code at all.\n *\n * An already-tagged error is NOT re-tagged: a request-policy plugin may report\n * `domain`, and rewriting that to `network` would lose the one thing the kind\n * exists for.\n */\nfunction classifyTransportError(error: unknown, timedOut: boolean): LankaError {\n\tif (LankaError.is(error)) return error;\n\n\t// The name is read off ANYTHING, not only off `Error`.\n\t//\n\t// `DOMException` — how `fetch` reports cancellation — does not extend `Error`\n\t// everywhere: in a browser yes, in jsdom no. An `instanceof Error` check lets\n\t// cancellation past the tagging, and a raw `AbortError` reaches the app with\n\t// neither `kind` nor `status`: retry policy reads it as non-retryable and the\n\t// app as an unknown error, so a cancelled request is shown to the user as a\n\t// failure.\n\tconst name = readErrorName(error);\n\tconst isAbort = name === \"AbortError\" || name === \"TimeoutError\";\n\tif (isAbort) {\n\t\t// Only whoever assembled the lifetime knows who aborted: `AbortSignal` has\n\t\t// one `abort` for everyone. The distinction carries a decision — a timeout\n\t\t// is shown, a cancellation is not.\n\t\tconst timedOutHere = timedOut || name === \"TimeoutError\";\n\t\treturn new LankaError({\n\t\t\tkind: timedOutHere ? \"timeout\" : \"aborted\",\n\t\t\tmessage: timedOutHere ? getLankaHost().timeoutErrorMessage() : readErrorMessage(error),\n\t\t\tcause: error,\n\t\t});\n\t}\n\n\t// `network` ONLY for what looks like a transport failure. A real `fetch`\n\t// throws `TypeError`; everything else comes from code we did not write — the\n\t// app's error handler, a response transformer, a broken plugin — and calling\n\t// that a network failure would invite the user to retry a request that\n\t// arrived and was processed.\n\t//\n\t// Unknown stays unknown and passes through. The framework asserts only what\n\t// it knows.\n\tif (error instanceof TypeError) {\n\t\treturn new LankaError({\n\t\t\tkind: \"network\",\n\t\t\tmessage: getLankaHost().networkErrorMessage(),\n\t\t\tissues: [error.message],\n\t\t\tcause: error,\n\t\t});\n\t}\n\n\treturn error as LankaError;\n}\n\n/** The error name, off `Error`, `DOMException` or anything else carrying one. */\nfunction readErrorName(error: unknown): string | undefined {\n\tif (typeof error !== \"object\" || error === null) return undefined;\n\tconst name: unknown = (error as { name?: unknown }).name;\n\treturn typeof name === \"string\" ? name : undefined;\n}\n\n/**\n * The error text, when there is one.\n *\n * An object without `message` is not stringified: `String({})` yields\n * `[object Object]`, which occupies the message slot and says nothing. Empty is\n * more honest.\n */\nfunction readErrorMessage(error: unknown): string {\n\tif (typeof error === \"string\") return error;\n\tif (typeof error !== \"object\" || error === null) return \"\";\n\tconst message: unknown = (error as { message?: unknown }).message;\n\treturn typeof message === \"string\" ? message : \"\";\n}\n\n/**\n * How a gateway request goes on the wire.\n *\n * A subclass declares one method, `request()`, and does only its own work there:\n * `LankaFetchJsonRequest` returns parsed JSON, `LankaFetchRequest` returns the\n * whole response, a custom kind returns whatever it likes.\n *\n * Overriding `request()` customises the request flow, failure handling, mock\n * substitution, response transformation and log interception.\n */\nexport abstract class ALankaRequest<\n\tTOptions = TLankaRequestInit,\n> implements ILankaRequest<TOptions> {\n\tprotected readonly errorHandler?: TLankaErrorHandler;\n\tprotected readonly useMock: boolean;\n\n\tprotected constructor(config: { errorHandler?: TLankaErrorHandler; useMock?: boolean }) {\n\t\tconst flags = getLankaFlags();\n\n\t\t// The default error-body handler lives HERE because the request is the only\n\t\t// thing that sees the `Response`. Put on the gateway it would sit in a field\n\t\t// nobody reads — the request takes the handler from ITS OWN config — and a\n\t\t// consumer passing `errorHandler` to the gateway would get silence.\n\t\t//\n\t\t// The parse is cheap: core reads the body once and takes `message` from it;\n\t\t// backend-specific shapes are parsed by `@lankajs/plugin-http`.\n\t\tthis.errorHandler = config.errorHandler ?? handleLankaApiError;\n\n\t\tthis.useMock = config.useMock ?? flags.isMockMode ?? false;\n\t}\n\n\t/**\n\t * Performs the request and returns its result — a response, JSON or a custom\n\t * type.\n\t *\n\t * @param endpoint Full URL\n\t * @param options Transport-specific options\n\t * @param mockHandler Mock, when there is one\n\t */\n\tprotected abstract request<TReturn = Response>(\n\t\tendpoint: string,\n\t\toptions?: TOptions,\n\t\tmockHandler?: () => Promise<TReturn>,\n\t): Promise<TReturn>;\n\n\t/**\n\t * The single point EVERY gateway request passes through.\n\t *\n\t * Hence the in-flight accounting here: intent prefetch stands down while\n\t * anything else is on the wire. The `finally` matters more than the increment —\n\t * a rejected request that never decremented would disable prefetching for the\n\t * rest of the session.\n\t */\n\tpublic async execute<TReturn = Response>(\n\t\tendpoint: string,\n\t\toptions?: TLankaExecuteOptions<TOptions>,\n\t\tmockHandler?: () => Promise<TReturn>,\n\t): Promise<TReturn> {\n\t\tconst runtime = getActiveRuntime();\n\t\tconst { signal, timeoutMs, ...rest } = (options ?? {}) as TLankaExecuteOptions<TOptions>;\n\t\t// The caller's deadline travels IN THE CONTEXT, not only in the closure:\n\t\t// otherwise a policy assigning deadlines per request class could not tell\n\t\t// \"no deadline given\" from \"given by the caller\" and would override an\n\t\t// explicit request with a blanket default.\n\t\tconst fallbackDeadline = runtime?.requestTimeoutMs;\n\n\t\t// No options passed means none are produced. Destructuring yields `{}` even\n\t\t// from `undefined`, and handing that empty object to the transport would\n\t\t// change the request: \"no options\" and \"empty options\" are different\n\t\t// statements, and the transport is entitled to tell them apart.\n\t\tconst passedOptions: unknown = options === undefined ? undefined : rest;\n\n\t\t/*\n\t\t * The lifetime is assembled PER ATTEMPT, not per call, and that does two\n\t\t * things at once.\n\t\t *\n\t\t * Under retry a shared deadline would start the third attempt with whatever\n\t\t * the first two left, so the retry aborts before reaching the server.\n\t\t *\n\t\t * And it is the only way to let middleware set the deadline: `ctx.timeoutMs`\n\t\t * is read on every attempt, which is how a request-policy plugin assigns a\n\t\t * deadline per request CLASS — a file upload and a list read cannot share\n\t\t * one value.\n\t\t *\n\t\t * Caller cancellation stays end-to-end: one `signal` for all attempts.\n\t\t */\n\t\tlet lastTimedOut = false;\n\n\t\t// Tagging happens INSIDE, around the request itself, not in the outer\n\t\t// catch: middleware must receive an already-tagged error, or a retrying\n\t\t// middleware cannot tell a network failure from a domain rejection and\n\t\t// retries what must not be retried. The outer catch stays as a backstop.\n\t\tconst perform = async (ctx: ILankaRequestContext): Promise<unknown> => {\n\t\t\tconst lifetime = createRequestLifetime(signal, ctx.timeoutMs ?? fallbackDeadline);\n\t\t\ttry {\n\t\t\t\treturn await this.request<TReturn>(\n\t\t\t\t\tctx.endpoint,\n\t\t\t\t\twithSignal(ctx.options, lifetime.signal) as TOptions,\n\t\t\t\t\tmockHandler,\n\t\t\t\t);\n\t\t\t} catch (error) {\n\t\t\t\tlastTimedOut = lifetime.timedOut();\n\t\t\t\tthrow classifyTransportError(error, lastTimedOut);\n\t\t\t} finally {\n\t\t\t\tlifetime.dispose();\n\t\t\t}\n\t\t};\n\n\t\tconst run = composeLankaRequestMiddleware(runtime?.requestMiddleware ?? [], perform);\n\n\t\tlankaHttpInFlight.begin();\n\t\ttry {\n\t\t\t// The chain runs INSIDE the same guard as the request. A catch placed\n\t\t\t// outside would leave a permanent +1 when a plugin throws, disabling\n\t\t\t// prefetch for the rest of the session — the very defect this `finally`\n\t\t\t// exists to prevent.\n\t\t\treturn (await run({\n\t\t\t\tendpoint,\n\t\t\t\toptions: passedOptions,\n\t\t\t\tattempt: 1,\n\t\t\t\ttimeoutMs,\n\t\t\t})) as TReturn;\n\t\t} catch (error) {\n\t\t\tthrow classifyTransportError(error, lastTimedOut);\n\t\t} finally {\n\t\t\tlankaHttpInFlight.end();\n\t\t}\n\t}\n}\n\ninterface IRequestLifetime {\n\treadonly signal: AbortSignal | undefined;\n\t/** Whether OUR timer aborted the request rather than the caller. */\n\ttimedOut(): boolean;\n\tdispose(): void;\n}\n\n/**\n * Combines the caller's signal and our own timeout into one request lifetime.\n *\n * The outcome looks the same — an interrupted request — but the decisions\n * differ: a timeout is shown and offered for retry, a user cancellation is not\n * shown at all. `AbortSignal` does not distinguish them: one `abort`, whose\n * reason belongs to whoever got there first. Hence the private flag.\n *\n * Not `AbortSignal.timeout` alone: it cannot combine with a foreign signal\n * without `AbortSignal.any`, which older engines lack. Assembling by hand works\n * everywhere and costs one listener.\n */\nfunction createRequestLifetime(\n\texternal: AbortSignal | undefined,\n\ttimeoutMs: number | undefined,\n): IRequestLifetime {\n\tif (!external && !timeoutMs) {\n\t\treturn { signal: undefined, timedOut: () => false, dispose: () => undefined };\n\t}\n\n\tconst controller = new AbortController();\n\tlet expired = false;\n\n\tconst timer =\n\t\ttimeoutMs === undefined\n\t\t\t? undefined\n\t\t\t: setTimeout(() => {\n\t\t\t\t\texpired = true;\n\t\t\t\t\tcontroller.abort(new DOMException(\"Request timed out\", \"TimeoutError\"));\n\t\t\t\t}, timeoutMs);\n\n\tconst onExternalAbort = (): void => {\n\t\tcontroller.abort(external?.reason);\n\t};\n\n\tif (external) {\n\t\tif (external.aborted) onExternalAbort();\n\t\telse external.addEventListener(\"abort\", onExternalAbort, { once: true });\n\t}\n\n\treturn {\n\t\tsignal: controller.signal,\n\t\ttimedOut: () => expired,\n\t\tdispose: () => {\n\t\t\tif (timer !== undefined) clearTimeout(timer);\n\t\t\texternal?.removeEventListener(\"abort\", onExternalAbort);\n\t\t},\n\t};\n}\n\n/**\n * Attaches the signal to the options, inventing nothing.\n *\n * With no options and no signal the transport receives `undefined` — exactly\n * what the caller passed. An empty object instead looks harmless but is a\n * different statement, and the transport is entitled to tell them apart.\n */\nfunction withSignal(options: unknown, signal: AbortSignal | undefined): unknown {\n\tif (signal === undefined) return options;\n\treturn { ...(options ?? {}), signal };\n}\n","import { ALankaRequest } from \"../lanka-request/ALankaRequest\";\nimport { LankaError } from \"../../../../errors/lanka-error/LankaError\";\nimport { getLankaFlags } from \"../../../../config/get-lanka-flags/getLankaFlags\";\nimport { getLankaHost } from \"../../../../config/get-lanka-host/getLankaHost\";\nimport type { ILankaTransport } from \"../../../_interfaces/ILankaTransport\";\nimport type { TLankaRequestInit } from \"../../../_types/TLankaRequestInit\";\nimport type { TLankaErrorHandler } from \"../../../../errors/_types/TLankaErrorHandler\";\n\nexport interface ILankaTransportRequestConfig<TOptions> {\n\ttransport?: ILankaTransport<TOptions>;\n\terrorHandler?: TLankaErrorHandler;\n\tuseMock?: boolean;\n}\n\n/**\n * The shape every fetch-backed request has: mock, send, check, parse.\n *\n * The concrete requests differ in ONE place — how they turn a successful\n * `Response` into a value — so a third kind is a subclass with one method rather\n * than a third copy of the sequence.\n *\n * The default transport stays a constructor PARAMETER even though both shipped\n * kinds pass the same one. It is the seam a request kind that is not fetch-backed\n * comes through: this template is the mock/send/check/parse sequence, and nothing\n * in it is about HTTP. Defaulting the parameter here would fix `TOptions` to\n * fetch options for everyone who reuses the sequence.\n */\nexport abstract class ALankaTransportRequest<\n\tTOptions = TLankaRequestInit,\n> extends ALankaRequest<TOptions> {\n\tprotected readonly transport: ILankaTransport<TOptions>;\n\n\tprotected constructor(\n\t\tconfig: ILankaTransportRequestConfig<TOptions>,\n\t\tcreateDefaultTransport: () => ILankaTransport<TOptions>,\n\t) {\n\t\tconst flags = getLankaFlags();\n\n\t\tsuper({\n\t\t\terrorHandler: config.errorHandler,\n\t\t\tuseMock: config.useMock ?? flags.isMockMode ?? false,\n\t\t});\n\n\t\tthis.transport = config.transport ?? createDefaultTransport();\n\t}\n\n\tprotected async request<TReturn>(\n\t\tendpoint: string,\n\t\toptions?: TOptions,\n\t\tmockHandler?: () => Promise<TReturn>,\n\t): Promise<TReturn> {\n\t\tif (this.useMock && mockHandler) {\n\t\t\treturn await mockHandler();\n\t\t}\n\n\t\tconst response = await this.transport.request(endpoint, options);\n\t\tif (!response.ok) return await this.refuse(response);\n\n\t\treturn await this.parse<TReturn>(response);\n\t}\n\n\t/**\n\t * Turns a successful response into the value the caller asked for.\n\t *\n\t * The one step that genuinely differs between request kinds.\n\t */\n\tprotected abstract parse<TReturn>(response: Response): Promise<TReturn>;\n\n\t/**\n\t * Refuses an unsuccessful response, and never returns.\n\t *\n\t * `TLankaErrorHandler` is typed `Promise<never>` — a handler must throw. It is\n\t * still CALLED and then followed by a throw, because a handler that breaks its\n\t * contract and returns would otherwise hand `undefined` back as if the request\n\t * had succeeded, and a non-value must never become a value.\n\t */\n\tprotected async refuse(response: Response): Promise<never> {\n\t\tif (this.errorHandler) {\n\t\t\tawait this.errorHandler(response);\n\t\t}\n\n\t\t// Kind `http`, not a bare Error: the server answered, and answered with a\n\t\t// code. Without the kind this reads as a network failure, and the user is\n\t\t// offered a retry of a request that already got a meaningful answer.\n\t\tthrow new LankaError({\n\t\t\tkind: \"http\",\n\t\t\tmessage: getLankaHost().httpErrorMessage(response.status),\n\t\t\tstatus: response.status,\n\t\t});\n\t}\n}\n","import type { ILankaTransport } from \"../_interfaces/ILankaTransport\";\nimport type { TLankaRequestInit } from \"../_types/TLankaRequestInit\";\n\n/** What an unencoded body is sent as, and the header that says so. */\nconst CONTENT_TYPE = \"content-type\";\nconst JSON_CONTENT_TYPE = \"application/json\";\n\n/**\n * The network seam: `fetch`, plus the two things `fetch` cannot be told.\n *\n * ## Why there is ONE of these\n *\n * There were three — a plain one, a JSON one and a multipart one — and the split\n * was wrong at birth. `ILankaTransport` exists so a consumer can change the\n * PROTOCOL: a native bridge, a socket, a double that never leaves the process.\n * The three differed in a `content-type` header. That is not a protocol, it is an\n * encoding, and an encoding is a property of the CALL: a gateway with fourteen\n * JSON endpoints and one upload had no way to say so, because its request kind —\n * and with it its transport — was fixed in its constructor. The application that\n * hit this added a `useFormData` flag to its own options and wrote its own\n * transport to read it.\n *\n * So the encoding is decided here, per call, by looking at the body. A gateway\n * posts `FormData` to one endpoint and an object to the next, and neither it nor\n * the request kind has to know.\n *\n * ## What does NOT belong here\n *\n * The base URL (`ALankaGateway` prefixes `apiBaseUrl`), credentials, static\n * headers, CSRF, retry, auth refresh, idempotency keys and deadlines. Every one\n * of those is policy around a request rather than a way of sending one, and every\n * one is a middleware — `useRequestMiddleware`, which `@lankajs/plugin-http`\n * occupies. A transport that grew them would be a second composition mechanism\n * beside the one core already publishes, and \"where does a header get added\"\n * would have two answers.\n */\nexport class LankaFetchTransport implements ILankaTransport<TLankaRequestInit> {\n\tasync request(resource: RequestInfo, options?: TLankaRequestInit): Promise<Response> {\n\t\t// Nothing to encode: the object the caller assembled reaches `fetch`\n\t\t// unchanged, `undefined` included. \"No options\" and \"empty options\" are\n\t\t// different statements and `fetch` is entitled to tell them apart.\n\t\tif (options === undefined || options.body === undefined || options.body === null) {\n\t\t\treturn await fetch(resource, options as RequestInit | undefined);\n\t\t}\n\n\t\tconst { body, headers } = options;\n\n\t\t// Multipart: the header is REMOVED, not set. The boundary is generated with\n\t\t// the body, and a hand-written `content-type` carries none — the server then\n\t\t// reads zero fields out of a request that looks correct.\n\t\tif (isFormData(body)) {\n\t\t\tif (headers === undefined) return await fetch(resource, options as RequestInit);\n\n\t\t\tconst stripped = new Headers(headers);\n\t\t\tstripped.delete(CONTENT_TYPE);\n\t\t\treturn await fetch(resource, { ...options, headers: stripped } as RequestInit);\n\t\t}\n\n\t\t// Already something `fetch` understands: untouched.\n\t\tif (isEncodedBody(body)) return await fetch(resource, options as RequestInit);\n\n\t\treturn await fetch(resource, {\n\t\t\t...options,\n\t\t\theaders: withJsonContentType(headers),\n\t\t\tbody: JSON.stringify(body),\n\t\t});\n\t}\n}\n\n/**\n * The header set, with `content-type` filled in only if the caller left it out.\n *\n * Not overwritten: `application/merge-patch+json` and `application/ld+json` are\n * JSON that a server distinguishes, and a transport that flattened them to\n * `application/json` would turn a PATCH into a request the server refuses — for\n * a header the caller had already written correctly.\n */\nfunction withJsonContentType(headers: HeadersInit | undefined): Headers {\n\tconst result = new Headers(headers);\n\tif (!result.has(CONTENT_TYPE)) result.set(CONTENT_TYPE, JSON_CONTENT_TYPE);\n\treturn result;\n}\n\n/**\n * Whether `fetch` can already send this body.\n *\n * Every global here is guarded by `typeof`: core runs in node and React Native\n * as well as a browser, and `ReadableStream` in particular is absent on engines\n * this framework supports. An unguarded `instanceof` against a missing global is\n * a `ReferenceError` on the first request, from a transport, in production.\n *\n * Cheapest and most common first. A string — an already-serialised body — stops\n * on line one.\n */\nfunction isEncodedBody(body: unknown): body is BodyInit {\n\tif (typeof body === \"string\") return true;\n\tif (typeof URLSearchParams !== \"undefined\" && body instanceof URLSearchParams) return true;\n\tif (typeof Blob !== \"undefined\" && body instanceof Blob) return true;\n\tif (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return true;\n\treturn typeof ReadableStream !== \"undefined\" && body instanceof ReadableStream;\n}\n\n/**\n * Multipart, checked separately because it is the one body whose header is\n * removed rather than added.\n */\nfunction isFormData(body: unknown): body is FormData {\n\treturn typeof FormData !== \"undefined\" && body instanceof FormData;\n}\n","import { ALankaTransportRequest } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransportRequestConfig } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { TLankaRequestInit } from \"../../_types/TLankaRequestInit\";\nimport { LankaFetchTransport } from \"../../lanka-fetch-transport/LankaFetchTransport\";\nimport { LankaError } from \"../../../errors/lanka-error/LankaError\";\n\n/** The JSON request: parses the body, and refuses a body that is not JSON. */\n/**\n * A request kind that answers a parsed JSON body — what most endpoints return.\n *\n * A gateway holds one, and is handed it rather than constructing it, which is\n * what lets a test give the same gateway a transport that never leaves the\n * process. `createLankaFetchJsonRequest()` builds the same class.\n */\nexport class LankaFetchJsonRequest<\n\tTOptions extends TLankaRequestInit = TLankaRequestInit,\n> extends ALankaTransportRequest<TOptions> {\n\tconstructor(config: ILankaTransportRequestConfig<TOptions> = {}) {\n\t\tsuper(config, () => new LankaFetchTransport());\n\t}\n\n\t/**\n\t * Parses the body, or names the failure.\n\t *\n\t * The content type is read for the ERROR MESSAGE only. Using it to choose\n\t * between two parse paths, where the second answers `{}` for any non-empty\n\t * body it cannot parse, fails silently: the caller's schema is the first thing\n\t * to notice, and the caller's SCREEN is where it shows up.\n\t *\n\t * A measured case: a dev server whose `/api` fell through to the SPA fallback\n\t * answered `200 text/html` with `index.html`. Turned into `{}`, the schema\n\t * refused it and a person read a validator's issue list on the sign-in card. A\n\t * body a JSON transport cannot parse is never a value — it is a misrouted\n\t * request, and saying so names the actual failure.\n\t */\n\tprotected async parse<TReturn>(response: Response): Promise<TReturn> {\n\t\tconst contentType = response.headers.get(\"content-type\");\n\n\t\tconst text = await response.text();\n\t\tif (!text) {\n\t\t\treturn undefined as TReturn;\n\t\t}\n\n\t\ttry {\n\t\t\treturn JSON.parse(text) as TReturn;\n\t\t} catch (error) {\n\t\t\t// `schema`, not `network`: the request arrived, the server answered, and\n\t\t\t// the answer was the wrong shape. Not cosmetic — a network failure\n\t\t\t// invites a retry, while retrying a broken contract is pointless and\n\t\t\t// blaming the user for it more so.\n\t\t\tthrow new LankaError({\n\t\t\t\tkind: \"schema\",\n\t\t\t\tmessage:\n\t\t\t\t\t`Failed to parse JSON response (content-type: ${contentType ?? \"none\"}): ` +\n\t\t\t\t\t`${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\tcause: error,\n\t\t\t});\n\t\t}\n\t}\n}\n","import { TLankaQueryParams } from \"../../_types/TLankaQueryParams\";\nimport { TLankaQueryBuilder } from \"../../_types/TLankaQueryBuilder\";\n\n/**\n * The query string a gateway sends, from the object a method was called with.\n *\n * Arrays become `key[]` repeated, nested objects become `key[inner]`: the shape\n * most JSON APIs read back without being told about it.\n *\n * Plain loops over `Object.keys` rather than `Object.entries` and `forEach`: this\n * runs on every request that carries a filter, and the pair array `entries`\n * builds — two allocations per key, thrown away immediately — is a cost with\n * nothing to show for it.\n */\nexport const buildLankaQueryParams: TLankaQueryBuilder = <T extends Record<string, unknown>>(\n\tinput: T,\n): URLSearchParams => {\n\tconst params = new URLSearchParams();\n\n\tconst append = (key: string, value: TLankaQueryParams): void => {\n\t\tif (value == null) return;\n\n\t\tif (Array.isArray(value)) {\n\t\t\t// The bracketed key once for the whole array, not once per element.\n\t\t\tconst itemKey = `${key}[]`;\n\t\t\tfor (let index = 0; index < value.length; index += 1) append(itemKey, value[index]);\n\n\t\t\treturn;\n\t\t}\n\n\t\tif (typeof value === \"object\") {\n\t\t\tconst inner = value as Record<string, TLankaQueryParams>;\n\t\t\tconst innerKeys = Object.keys(inner);\n\n\t\t\tfor (let index = 0; index < innerKeys.length; index += 1) {\n\t\t\t\tconst innerKey = innerKeys[index];\n\t\t\t\tappend(`${key}[${innerKey}]`, inner[innerKey]);\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tparams.append(key, String(value));\n\t};\n\n\tconst source = input as Record<string, TLankaQueryParams>;\n\tconst keys = Object.keys(source);\n\n\tfor (let index = 0; index < keys.length; index += 1) append(keys[index], source[keys[index]]);\n\n\treturn params;\n};\n","import type { TLankaRequestInit } from \"../../_types/TLankaRequestInit\";\nimport type { IALankaGatewayConfig } from \"../../_interfaces/IALankaGatewayConfig\";\nimport { lankaLogger } from \"../../../logger/lanka-logger/LankaLogger\";\nimport { LankaFetchJsonRequest } from \"../../request/lanka-fetch-json-request/LankaFetchJsonRequest\";\nimport type { ILankaRequest } from \"../../_interfaces/ILankaRequest\";\nimport type { TLankaExecuteOptions } from \"../../_types/TLankaExecuteOptions\";\nimport { buildLankaQueryParams } from \"../../_utils/build-lanka-query-params/buildLankaQueryParams\";\nimport { TLankaQueryParams } from \"../../_types/TLankaQueryParams\";\nimport { TLankaQueryBuilder } from \"../../_types/TLankaQueryBuilder\";\nimport { getLankaFlags } from \"../../../config/get-lanka-flags/getLankaFlags\";\nimport { getLankaHost } from \"../../../config/get-lanka-host/getLankaHost\";\nimport { lankaStandardValidator } from \"../../../validation/lanka-standard-validator/lankaStandardValidator\";\nimport type { ILankaValidator } from \"../../../validation/lanka-standard-validator/lankaStandardValidator\";\n\nexport abstract class ALankaGateway<TOptions = TLankaRequestInit> {\n\tprotected requestExecutor: ILankaRequest<TOptions>;\n\tprotected queryParamsHandler: TLankaQueryBuilder;\n\n\t/**\n\t * The validator a method checks a response body with.\n\t *\n\t * `config.validationService` when one was given, the Standard Schema port\n\t * otherwise. It used to be accepted by the config and read by nothing: a\n\t * consumer handing a test double to the gateway got the real validator and no\n\t * error, which is the worst kind of ignored option — it looks honoured.\n\t */\n\tprotected readonly validationService: ILankaValidator;\n\n\tprotected readonly useMock: boolean;\n\tprotected readonly basePath: string;\n\n\tprotected constructor(config: IALankaGatewayConfig<TOptions>) {\n\t\tlankaLogger.printGatewayLog(\"Create gateway\", this);\n\t\tconst flags = getLankaFlags();\n\t\tthis.useMock = config.useMock ?? flags.isMockMode ?? false;\n\t\tthis.validationService = config.validationService ?? lankaStandardValidator;\n\n\t\t// A gateway with nothing said about transport talks JSON over `fetch`, which\n\t\t// is what almost every one of them does. Supplying a request is how a gateway\n\t\t// stops being ordinary — a raw `Response`, a multipart upload, a transport\n\t\t// that never leaves the process — and that stays a decision rather than a\n\t\t// line every gateway has to carry to be born.\n\t\t// The cast covers the FRAMEWORK picking its own fallback, and nothing a\n\t\t// consumer does. `TOptions` is unconstrained here on purpose — a gateway may\n\t\t// front a request that never speaks HTTP, and the port promises exactly that\n\t\t// — so the JSON default cannot be proven to fit a `TOptions` nobody has\n\t\t// named yet. A consumer whose options are not fetch-shaped supplies\n\t\t// `request`, and this line never runs for them.\n\t\tthis.requestExecutor = config.request ?? new LankaFetchJsonRequest();\n\n\t\tthis.basePath = config.basePath ?? \"\";\n\t\tthis.queryParamsHandler = config.queryParamsHandler ?? buildLankaQueryParams;\n\t}\n\n\t/**\n\t * Resolves endpoint for request.\n\t * - Absolute paths (starting with \"/\") are returned as-is\n\t * - Relative paths are joined with basePath\n\t * - Query-only strings like \"?a=1\" are attached to basePath\n\t */\n\tprotected endpoint(path: string = \"\"): string {\n\t\t// An absolute URL is detected BEFORE joining with `basePath`, not after:\n\t\t// otherwise `https://other.host/health` first becomes\n\t\t// `/things/https://other.host/health` and there is nothing left to detect.\n\t\tif (isAbsoluteUrl(path)) return path;\n\n\t\treturn this.withApiBase(this.resolvePath(path));\n\t}\n\n\t/**\n\t * Joins `basePath` and the method path.\n\t */\n\tprivate resolvePath(path: string): string {\n\t\tif (!path) return this.basePath;\n\n\t\tif (path.startsWith(\"/\")) return path;\n\n\t\tif (path.startsWith(\"?\")) return `${this.basePath}${path}`;\n\n\t\t// No leading-slash case here: the check above already returned for one, so\n\t\t// stripping it again was a branch no input could take — uncoverable by\n\t\t// construction, and it counted against the coverage floor that gates this\n\t\t// package.\n\t\tconst left = this.basePath.endsWith(\"/\") ? this.basePath.slice(0, -1) : this.basePath;\n\t\treturn `${left}/${path}`;\n\t}\n\n\t/**\n\t * Prefixes the API base URL from the host contract.\n\t *\n\t * Here rather than in every consumer: otherwise each consumer knows the URL\n\t * and the framework does not, and a realtime plugin would have to know a\n\t * specific application's build.\n\t *\n\t * Declaring the field and not using it would be worse than not declaring it: a\n\t * declaration nothing is built from is a second truth, free to diverge from\n\t * the first.\n\t *\n\t * An absolute URL never reaches here — `endpoint()` filters it out before the\n\t * join.\n\t */\n\tprivate withApiBase(path: string): string {\n\t\tconst base = withoutTrailingSlashes(getLankaHost().apiBaseUrl);\n\t\tif (!base) return path;\n\t\tif (!path) return base;\n\n\t\treturn path.startsWith(\"/\") ? `${base}${path}` : `${base}/${path}`;\n\t}\n\n\tprotected buildQueryParams<T extends object>(params: T): URLSearchParams {\n\t\treturn this.queryParamsHandler(params as Record<string, TLankaQueryParams>);\n\t}\n\n\tprotected async request<TReturn = unknown>(\n\t\tpath: string,\n\t\toptions?: TLankaExecuteOptions<TOptions>,\n\t\tmockHandler?: () => Promise<TReturn>,\n\t): Promise<TReturn> {\n\t\treturn this.requestExecutor.execute<TReturn>(this.endpoint(path), options, mockHandler);\n\t}\n\n\t/**\n\t * Allows to replace request implementation at runtime (e.g. feature flags / tests).\n\t * If you prefer static customization - override `request()` in a subclass.\n\t */\n\tprotected setRequest(request: ILankaRequest<TOptions>): void {\n\t\tthis.requestExecutor = request;\n\t}\n\n\tprotected setQueryParamsHandler(handler: TLankaQueryBuilder): void {\n\t\tthis.queryParamsHandler = handler;\n\t}\n}\n\n/**\n * A scheme plus `//` — a URL that already knows where it is going.\n *\n * A standalone function rather than a method: it is not about a particular\n * gateway, and `endpoint()` needs it before any joining.\n */\nfunction isAbsoluteUrl(path: string): boolean {\n\t// The cheap half first: a scheme needs `://`, and `includes` answers without\n\t// starting the regex engine. Every relative path an application writes — which\n\t// is nearly all of them — stops on this line.\n\tif (!path.includes(\"://\")) return false;\n\n\treturn /^[a-z][a-z\\d+\\-.]*:\\/\\//i.test(path);\n}\n\n/**\n * The API base without its trailing slashes, remembered between calls.\n *\n * The host answers the same string for the life of an application, and trimming\n * it is a regex replace otherwise run on every endpoint of every request. One\n * entry is enough: there is one active host, and a second framework in the same\n * process simply replaces what is remembered here.\n */\nlet lastRawBase: string | null = null;\nlet lastTrimmedBase = \"\";\n\nfunction withoutTrailingSlashes(base: string): string {\n\tif (base !== lastRawBase) {\n\t\tlastRawBase = base;\n\t\tlastTrimmedBase = base.replace(/\\/+$/, \"\");\n\t}\n\n\treturn lastTrimmedBase;\n}\n","import { ALankaGateway } from \"../../_abstractions/lanka-gateway/ALankaGateway\";\nimport type { IALankaGatewayConfig } from \"../../_interfaces/IALankaGatewayConfig\";\nimport type { ILankaGatewayContext } from \"../../_interfaces/ILankaGatewayContext\";\n\n/** What a gateway is built from, whichever style builds it. */\nexport interface ILankaGatewayConfig<\n\tTOptions,\n\tTMethods extends object,\n> extends IALankaGatewayConfig<TOptions> {\n\t/** The endpoints this gateway offers, written over its own surface. */\n\tmethods: (context: ILankaGatewayContext<TOptions>) => TMethods;\n}\n\n/**\n * A gateway, without writing a class.\n *\n * The bridge below is the whole mechanism, and it lives here rather than on the\n * base for two reasons. The language reads `protected` from inside a deriving\n * class body and nowhere else, so a factory outside the hierarchy could only\n * reach the public half — the wrong one. And a `toStyleContext` ON the base\n * would put `TOptions` in a method's parameter position, making the class\n * invariant in it: every `ALankaGateway<unknown>` the locator holds would stop\n * accepting a gateway typed for `RequestInit`.\n *\n * One implementation: what comes back is an instance of `ALankaGateway`, so a\n * behaviour fix reaches both styles at once.\n */\nexport const createLankaGateway = <TOptions, TMethods extends object>(\n\tconfig: ILankaGatewayConfig<TOptions, TMethods>,\n): TMethods => {\n\tclass FunctionalGateway extends ALankaGateway<TOptions> {\n\t\t// The base keeps a protected constructor — it is abstract, and a consumer\n\t\t// reaching for `new ALankaGateway()` would get an object with no endpoints.\n\t\t// A subclass may widen it, and this one is the subclass.\n\t\tpublic constructor(gatewayConfig: IALankaGatewayConfig<TOptions>) {\n\t\t\tsuper(gatewayConfig);\n\t\t}\n\n\t\tpublic build(): TMethods {\n\t\t\treturn config.methods({\n\t\t\t\tendpoint: (path) => this.endpoint(path),\n\t\t\t\trequest: (path, options, mockHandler) => this.request(path, options, mockHandler),\n\t\t\t\tbuildQueryParams: (params) => this.buildQueryParams(params),\n\t\t\t\tvalidationService: this.validationService,\n\t\t\t});\n\t\t}\n\t}\n\n\treturn new FunctionalGateway(config).build();\n};\n","import { ALankaTransportRequest } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransportRequestConfig } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { TLankaRequestInit } from \"../../_types/TLankaRequestInit\";\nimport { LankaFetchTransport } from \"../../lanka-fetch-transport/LankaFetchTransport\";\n\n/**\n * The raw request: hands the `Response` back untouched.\n *\n * The minimal, extensible case — a caller wanting headers, a stream, a blob or a\n * `204` reads them off the response itself. Multipart uploads come through here\n * too: the transport encodes by looking at the body, so posting a `FormData` and\n * posting an object are the same call.\n *\n * `TOptions` is CONSTRAINED to fetch options rather than merely defaulted to\n * them. A consumer widening it — their own `interface IRequestOptions extends\n * TLankaRequestInit` — still gets the shipped transport, because the constraint\n * is what lets the framework hand one over without a cast. Unconstrained, the\n * assignment did not typecheck and core cast its way past it; the cast worked\n * here and was unavailable to the consumer, who wrote a transport instead.\n */\nexport class LankaFetchRequest<\n\tTOptions extends TLankaRequestInit = TLankaRequestInit,\n> extends ALankaTransportRequest<TOptions> {\n\tconstructor(config: ILankaTransportRequestConfig<TOptions> = {}) {\n\t\tsuper(config, () => new LankaFetchTransport());\n\t}\n\n\tprotected parse<TReturn>(response: Response): Promise<TReturn> {\n\t\treturn Promise.resolve(response as unknown as TReturn);\n\t}\n}\n","import { LankaFetchRequest } from \"../../lanka-fetch-request/LankaFetchRequest\";\nimport type { ILankaTransportRequestConfig } from \"../../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { TLankaRequestInit } from \"../../../_types/TLankaRequestInit\";\n\n/**\n * The functional style of `LankaFetchRequest`: the raw `Response`, for a download or a stream.\n *\n * One line, and that is the point — the factory IS the class, so a behaviour\n * cannot exist in one style and not the other.\n */\nexport const createLankaFetchRequest = <TOptions extends TLankaRequestInit = TLankaRequestInit>(\n\tconfig: ILankaTransportRequestConfig<TOptions> = {},\n): LankaFetchRequest<TOptions> => new LankaFetchRequest<TOptions>(config);\n","import { LankaFetchJsonRequest } from \"../../lanka-fetch-json-request/LankaFetchJsonRequest\";\nimport type { ILankaTransportRequestConfig } from \"../../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { TLankaRequestInit } from \"../../../_types/TLankaRequestInit\";\n\n/**\n * The functional style of `LankaFetchJsonRequest`: a JSON body, which is what most endpoints answer.\n *\n * One line, and that is the point — the factory IS the class, so a behaviour\n * cannot exist in one style and not the other.\n */\nexport const createLankaFetchJsonRequest = <TOptions extends TLankaRequestInit = TLankaRequestInit>(\n\tconfig: ILankaTransportRequestConfig<TOptions> = {},\n): LankaFetchJsonRequest<TOptions> => new LankaFetchJsonRequest<TOptions>(config);\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -1,19 +1,20 @@
1
- export { I as ILankaBootstrapConfig, a as ILankaInstance, b as ILankaInstanceConfig, c as ILankaPlugin, d as ILankaScenarioBootstrapConfig, e as ILankaServiceConfig, f as createLanka } from './createLanka-DI1CSy2Q.js';
1
+ export { I as ILankaBootstrapConfig, a as ILankaInstance, b as ILankaInstanceConfig, c as ILankaPlugin, d as ILankaScenarioBootstrapConfig, e as ILankaServiceConfig, f as createLanka } from './createLanka-x4oSMs7P.js';
2
2
  export { ALankaPlugin, ILankaStartOptions, TLankaStartConfig, resetActiveLanka, startLanka } from './bootstrap/index.js';
3
3
  export { ILankaRoleFactory, ILankaRoleOpening, TLankaRoleOpener, defineLankaRole } from './role/index.js';
4
4
  export { ILankaHostConfig, createLankaHost, getLankaFlags, getLankaHost } from './config/index.js';
5
5
  export { I as ILankaFlags, a as ILankaHost, b as ILankaRuntimeConfig } from './ILankaRuntimeConfig-Vl436GWK.js';
6
- export { I as ILankaLocatorConfig } from './LankaSharedStoreLocator-zS2kLu-S.js';
6
+ export { I as ILankaLocatorConfig } from './LankaSharedStoreLocator-jsz_gnUm.js';
7
7
  export { lankaLogger } from './logger/index.js';
8
- export { I as ILankaErrorInit, L as LankaError, T as TLankaErrorKind } from './LankaError-xpI-qj35.js';
9
- import './createLankaScope-BiFxNQgl.js';
10
- import './activeRuntime-B336NU5I.js';
11
- import './ILankaScenarioVM-DUsI-fSc.js';
12
- import './LankaScenarioLocator-D86TIwiu.js';
13
- import './ILankaScenarioMetadata-GoWWNEQL.js';
14
- import './ALankaGateway-CkW1LbKE.js';
15
- import './lankaStandardValidator-CL-r-zEV.js';
8
+ export { I as ILankaErrorInit, L as LankaError, T as TLankaErrorKind } from './LankaError-D6RWNyLM.js';
9
+ import './createLankaScope-DomNbEvb.js';
10
+ import './activeRuntime-BO-qY0yY.js';
11
+ import './ILankaScenarioVM-DpKFL3iE.js';
12
+ import './LankaScenarioLocator-Dki2Es3O.js';
13
+ import './ILankaScenarioMetadata-Dj4GCqmX.js';
14
+ import './ALankaGateway-BrVPaZN5.js';
15
+ import './lankaStandardValidator-BUFnysK0.js';
16
16
  import '@standard-schema/spec';
17
+ import './ILankaFieldError-D5931-vT.js';
17
18
  import './lankaHttpInFlight-Bk1eIuSx.js';
18
19
  import './lankaRequestMiddleware-DAC5kCb7.js';
19
20
  import './ALankaSharedStore-B7uepuuk.js';
package/dist/index.js CHANGED
@@ -6,28 +6,27 @@ import {
6
6
  createLanka,
7
7
  resetActiveLanka,
8
8
  startLanka
9
- } from "./chunk-G3I7QIZR.js";
10
- import "./chunk-5MAQVBI2.js";
11
- import "./chunk-UGXSGQPW.js";
12
- import "./chunk-O5ROO7QF.js";
9
+ } from "./chunk-SZVNPK24.js";
10
+ import "./chunk-UMPSR4US.js";
11
+ import "./chunk-EYDMBI5T.js";
13
12
  import {
14
13
  createLankaHost
15
14
  } from "./chunk-XESL274R.js";
16
- import "./chunk-UJEC7H6K.js";
15
+ import "./chunk-BHQ2SQ7P.js";
17
16
  import {
18
17
  LankaError
19
- } from "./chunk-Q7QESSYF.js";
18
+ } from "./chunk-G32H73QY.js";
20
19
  import {
21
20
  getLankaHost
22
- } from "./chunk-RKYKK6MN.js";
21
+ } from "./chunk-RUMUFHSL.js";
23
22
  import "./chunk-UE2C76OR.js";
24
23
  import {
25
24
  lankaLogger
26
- } from "./chunk-C2HP7CRD.js";
25
+ } from "./chunk-FII3PW2G.js";
27
26
  import {
28
27
  getLankaFlags
29
- } from "./chunk-D27MREPB.js";
30
- import "./chunk-BGVDPDX4.js";
28
+ } from "./chunk-7DQUF2QR.js";
29
+ import "./chunk-XGMXT4XZ.js";
31
30
  export {
32
31
  ALankaPlugin,
33
32
  LankaError,
@@ -1,11 +1,21 @@
1
1
  import { StandardSchemaV1 } from '@standard-schema/spec';
2
+ import { I as ILankaFieldError } from './ILankaFieldError-D5931-vT.js';
2
3
 
4
+ /**
5
+ * What `validateSafe` answers.
6
+ *
7
+ * On failure, `errors` is the banner's list and `fields` the form's: the same
8
+ * issues, joined into text and kept in segments. `fields` is optional because
9
+ * `ILankaValidator` is a port a consumer may implement, and a port that grows a
10
+ * required member breaks every implementation it did not write.
11
+ */
3
12
  type TLankaValidationResult<T> = {
4
13
  success: true;
5
14
  data: T;
6
15
  } | {
7
16
  success: false;
8
17
  errors: string[];
18
+ fields?: readonly ILankaFieldError[];
9
19
  };
10
20
 
11
21
  /**
@@ -1,13 +1,14 @@
1
- export { I as ILankaScope } from '../createLankaScope-BiFxNQgl.js';
2
- export { a as ILankaLocator, I as ILankaLocatorConfig, c as ILankaSharedStoreLocatorConfig, d as ILankaSingletonLocatorConfig } from '../LankaSharedStoreLocator-zS2kLu-S.js';
1
+ export { I as ILankaScope } from '../createLankaScope-DomNbEvb.js';
2
+ export { b as ILankaLocator, I as ILankaLocatorConfig, c as ILankaSharedStoreLocatorConfig, d as ILankaSingletonLocatorConfig } from '../LankaSharedStoreLocator-jsz_gnUm.js';
3
3
  import * as GatewaysModule from '@lanka_di/Gateways';
4
- import { A as ALankaGateway } from '../ALankaGateway-CkW1LbKE.js';
4
+ import { A as ALankaGateway } from '../ALankaGateway-BrVPaZN5.js';
5
5
  import * as ScenariosModule from '@lanka_di/Scenarios';
6
6
  import * as SingletonsModule from '@lanka_di/Singletons';
7
7
  import * as SharedStoresModule from '@lanka_di/SharedStores';
8
8
  import { A as ALankaSharedStore } from '../ALankaSharedStore-B7uepuuk.js';
9
- import '../lankaStandardValidator-CL-r-zEV.js';
9
+ import '../lankaStandardValidator-BUFnysK0.js';
10
10
  import '@standard-schema/spec';
11
+ import '../ILankaFieldError-D5931-vT.js';
11
12
  import 'zustand/vanilla';
12
13
 
13
14
  /**
@@ -2,11 +2,11 @@ import {
2
2
  createLankaLocatorProxy,
3
3
  lankaSharedStores,
4
4
  lankaSingletons
5
- } from "../chunk-DTO27QFR.js";
5
+ } from "../chunk-H5TIUKRK.js";
6
6
  import "../chunk-UE2C76OR.js";
7
7
  import {
8
8
  requireActiveRuntime
9
- } from "../chunk-BGVDPDX4.js";
9
+ } from "../chunk-XGMXT4XZ.js";
10
10
 
11
11
  // src/locator/gateway/_facades/lanka-gateways/lankaGateways.ts
12
12
  var gatewayLocator = {
@@ -1,9 +1,9 @@
1
1
  import {
2
2
  LankaLogger,
3
3
  lankaLogger
4
- } from "../chunk-C2HP7CRD.js";
5
- import "../chunk-D27MREPB.js";
6
- import "../chunk-BGVDPDX4.js";
4
+ } from "../chunk-FII3PW2G.js";
5
+ import "../chunk-7DQUF2QR.js";
6
+ import "../chunk-XGMXT4XZ.js";
7
7
  export {
8
8
  LankaLogger,
9
9
  lankaLogger
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  lankaLogger
3
- } from "../chunk-C2HP7CRD.js";
3
+ } from "../chunk-FII3PW2G.js";
4
4
  import {
5
5
  getLankaFlags
6
- } from "../chunk-D27MREPB.js";
7
- import "../chunk-BGVDPDX4.js";
6
+ } from "../chunk-7DQUF2QR.js";
7
+ import "../chunk-XGMXT4XZ.js";
8
8
 
9
9
  // src/_internal/sleep.ts
10
10
  var sleep = (ms = 300) => {
@@ -1,6 +1,6 @@
1
- import { a as ILankaScenario, T as TLankaReplayRequest, b as ILankaEventMetadata, c as TLankaEventBusMiddleware, d as TLankaEventBusObserver, e as ILankaEventLog, I as ILankaScenarioVM } from '../ILankaScenarioVM-DUsI-fSc.js';
2
- export { f as ILankaEventBusOutcome, g as TLankaEventBusDecision } from '../ILankaScenarioVM-DUsI-fSc.js';
3
- export { I as ILankaScenarioMetadata } from '../ILankaScenarioMetadata-GoWWNEQL.js';
1
+ import { a as ILankaScenario, T as TLankaReplayRequest, b as ILankaEventMetadata, c as TLankaEventBusMiddleware, d as TLankaEventBusObserver, e as ILankaEventLog, I as ILankaScenarioVM } from '../ILankaScenarioVM-DpKFL3iE.js';
2
+ export { f as ILankaEventBusOutcome, g as TLankaEventBusDecision } from '../ILankaScenarioVM-DpKFL3iE.js';
3
+ export { I as ILankaScenarioMetadata } from '../ILankaScenarioMetadata-Dj4GCqmX.js';
4
4
 
5
5
  /**
6
6
  * The base of a scenario — a named unit of coordination over the event bus.
@@ -123,6 +123,23 @@ declare const lankaEventBus: Readonly<{
123
123
  reset: () => void;
124
124
  }>;
125
125
 
126
+ /** What a scenario-layer reset should clear beyond the default. */
127
+ interface ILankaScenarioResetConfig {
128
+ /**
129
+ * Also forget which ViewModels were declared.
130
+ *
131
+ * Off by default, and the default is the one an APPLICATION needs: a
132
+ * module-level ViewModel is built once per process, so its declaration is the
133
+ * only thing that lets a second instance find it again.
134
+ *
135
+ * On, for a suite that builds ViewModels inside test bodies. Nothing
136
+ * un-declares one otherwise, so the next bootstrap re-adopts every ViewModel
137
+ * ever built in the process — and a finished test's handlers then run against
138
+ * the double that test created.
139
+ */
140
+ withDeclarations?: boolean;
141
+ }
142
+
126
143
  /**
127
144
  * Bootstrapping the scenario layer, for callers with no instance in hand.
128
145
  *
@@ -186,8 +203,51 @@ declare class LankaScenarioBootstrap {
186
203
  * to.
187
204
  */
188
205
  private readonly declaredViewModels;
189
- /** Registers everything declared into a NEW instance. Called by `createLanka`. */
206
+ /**
207
+ * Registers everything declared into a NEW instance.
208
+ *
209
+ * Called twice, and the second call is the one that makes this work on a
210
+ * server: `createLanka` calls it, and so does `bootstrap()`.
211
+ *
212
+ * The reason is an order nobody can change. Where "which instance is active"
213
+ * is answered by a RESOLVER — one instance per request, the shape
214
+ * `@lankajs/host` installs — an instance becomes findable only once the CALLER
215
+ * has put it in its store, and a caller can only do that after `createLanka`
216
+ * has returned. So during creation the answer is honestly "none", and asking
217
+ * for it threw: every server render of an application with a module-level
218
+ * ViewModel failed inside the call that was creating the scope, with a message
219
+ * about running outside one.
220
+ *
221
+ * Skipping is safe precisely because bootstrap adopts again. It is idempotent
222
+ * at the other end too: `attachViewModel` returns early for a ViewModel the
223
+ * registry already holds.
224
+ */
190
225
  adoptDeclaredViewModels(): void;
226
+ /**
227
+ * Whether the ViewModel being built belongs to ONE scope.
228
+ *
229
+ * A module-level ViewModel is declared once and adopted by every instance
230
+ * ever created, which is what `declaredViewModels` is for and why it is never
231
+ * drained. A SCOPED one is the opposite: it belongs to the request that built
232
+ * it and to nothing after.
233
+ *
234
+ * Declaring one would be the defect this flag exists to prevent, and it is
235
+ * worth spelling out because nothing would look wrong. The array grows by an
236
+ * entry per request for the life of the process, and request N+1 ADOPTS
237
+ * request N's ViewModel — subscribing it to N+1's scenarios, so a dispatch
238
+ * runs N's handlers against N's gateways and writes into N's store. Every
239
+ * suite stays green and the leak is one user seeing another's board.
240
+ */
241
+ private isBuildingScoped;
242
+ /**
243
+ * Runs `build` with its declarations kept OUT of the process-wide list.
244
+ *
245
+ * Called by `resolveLankaVM` and by nothing else. A narrow seam rather than a
246
+ * parameter on every factory: the nine ways to build a ViewModel would each
247
+ * have to carry a flag through to `registerViewModel`, and eight of them have
248
+ * no business knowing what a scope is.
249
+ */
250
+ buildScoped<TBuilt>(build: () => TBuilt): TBuilt;
191
251
  registerViewModel(viewModel: ILankaScenarioVM, name?: string): void;
192
252
  private attachViewModel;
193
253
  /**
@@ -197,10 +257,25 @@ declare class LankaScenarioBootstrap {
197
257
  * the ViewModel registry together with all their subscriptions, and the bus —
198
258
  * events and
199
259
  * middleware.
260
+ *
261
+ * What it does NOT clear by default is which ViewModels were DECLARED, and
262
+ * that default is load-bearing: a module-level ViewModel is built once per
263
+ * process, so the declaration is the only thing that lets a second instance
264
+ * find it. Drop it and its handlers bind to nothing, silently, for the rest of
265
+ * the process — see `declaredViewModels`.
266
+ *
267
+ * `withDeclarations` is for the case that default gets wrong: a suite that
268
+ * builds ViewModels inside test BODIES. Those are declared like any other and
269
+ * nothing un-declares them, so the next bootstrap re-adopts every one ever
270
+ * built and a finished test's handlers run again — against the gateway that
271
+ * test built, which is somebody else's double. Forgetting is not a tombstone:
272
+ * a ViewModel declared again afterwards is adopted again.
273
+ *
274
+ * @param config `withDeclarations` also forgets which ViewModels exist
200
275
  */
201
- reset(): void;
276
+ reset(config?: ILankaScenarioResetConfig): void;
202
277
  }
203
278
  /** The one every caller wants. */
204
279
  declare const lankaScenarioBootstrap: LankaScenarioBootstrap;
205
280
 
206
- export { ALankaScenario, ILankaEventLog, ILankaEventMetadata, ILankaScenario, type ILankaScenarioConfig, ILankaScenarioVM, TLankaEventBusMiddleware, TLankaEventBusObserver, TLankaReplayRequest, createLankaScenario, lankaEventBus, lankaScenarioBootstrap };
281
+ export { ALankaScenario, ILankaEventLog, ILankaEventMetadata, ILankaScenario, type ILankaScenarioConfig, type ILankaScenarioResetConfig, ILankaScenarioVM, TLankaEventBusMiddleware, TLankaEventBusObserver, TLankaReplayRequest, createLankaScenario, lankaEventBus, lankaScenarioBootstrap };
@@ -1,13 +1,11 @@
1
- import {
2
- lankaScenarioBootstrap
3
- } from "../chunk-UGXSGQPW.js";
4
1
  import {
5
2
  ALankaScenario,
6
- lankaEventBus
7
- } from "../chunk-O5ROO7QF.js";
8
- import "../chunk-C2HP7CRD.js";
9
- import "../chunk-D27MREPB.js";
10
- import "../chunk-BGVDPDX4.js";
3
+ lankaEventBus,
4
+ lankaScenarioBootstrap
5
+ } from "../chunk-EYDMBI5T.js";
6
+ import "../chunk-FII3PW2G.js";
7
+ import "../chunk-7DQUF2QR.js";
8
+ import "../chunk-XGMXT4XZ.js";
11
9
 
12
10
  // src/scenario/_factories/create-lanka-scenario/createLankaScenario.ts
13
11
  var createLankaScenario = (config) => {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/scenario/_factories/create-lanka-scenario/createLankaScenario.ts"],"sourcesContent":["import { ALankaScenario } from \"../../_abstractions/lanka-scenario/ALankaScenario\";\nimport type { ILankaScenario } from \"../../_interfaces/ILankaScenario\";\n\n/** What a scenario is: three names and nothing else. */\nexport interface ILankaScenarioConfig {\n\t/** The scenario's name, and the key it is found by. */\n\tname: string;\n\t/** The event type on the bus. */\n\teventType: string;\n\t/** The event data's type name — for the bus metadata. */\n\tdataTypeName: string;\n\t/** Opts out of self-registration, as `skipAutoRegistration` does on a class. */\n\tskipAutoRegistration?: boolean;\n}\n\n/**\n * A scenario, without writing a class whose body is data.\n *\n * The class style is right where a scenario has behaviour — an `initialize` that\n * warms something, a `cleanup` that lets go. Most have neither: in the two\n * applications this framework grew out of, every scenario is a class holding\n * three `readonly` fields and nothing else.\n *\n * One implementation: this builds a subclass of `ALankaScenario`, so\n * self-registration, `trigger` and `subscribe` are the same code either way.\n */\nexport const createLankaScenario = <TData = void>(\n\tconfig: ILankaScenarioConfig,\n): ILankaScenario<TData> => {\n\tclass FunctionalScenario extends ALankaScenario<TData> {\n\t\tpublic static override skipAutoRegistration = config.skipAutoRegistration ?? false;\n\n\t\tpublic readonly name = config.name;\n\t\tpublic readonly eventType = config.eventType;\n\t\tpublic readonly dataTypeName = config.dataTypeName;\n\t}\n\n\treturn new FunctionalScenario();\n};\n"],"mappings":";;;;;;;;;;;;AA0BO,IAAM,sBAAsB,CAClC,WAC2B;AAAA,EAC3B,MAAM,2BAA2B,eAAsB;AAAA,IACtD,OAAuB,uBAAuB,OAAO,wBAAwB;AAAA,IAE7D,OAAO,OAAO;AAAA,IACd,YAAY,OAAO;AAAA,IACnB,eAAe,OAAO;AAAA,EACvC;AAEA,SAAO,IAAI,mBAAmB;AAC/B;","names":[]}
1
+ {"version":3,"sources":["../../src/scenario/_factories/create-lanka-scenario/createLankaScenario.ts"],"sourcesContent":["import { ALankaScenario } from \"../../_abstractions/lanka-scenario/ALankaScenario\";\nimport type { ILankaScenario } from \"../../_interfaces/ILankaScenario\";\n\n/** What a scenario is: three names and nothing else. */\nexport interface ILankaScenarioConfig {\n\t/** The scenario's name, and the key it is found by. */\n\tname: string;\n\t/** The event type on the bus. */\n\teventType: string;\n\t/** The event data's type name — for the bus metadata. */\n\tdataTypeName: string;\n\t/** Opts out of self-registration, as `skipAutoRegistration` does on a class. */\n\tskipAutoRegistration?: boolean;\n}\n\n/**\n * A scenario, without writing a class whose body is data.\n *\n * The class style is right where a scenario has behaviour — an `initialize` that\n * warms something, a `cleanup` that lets go. Most have neither: in the two\n * applications this framework grew out of, every scenario is a class holding\n * three `readonly` fields and nothing else.\n *\n * One implementation: this builds a subclass of `ALankaScenario`, so\n * self-registration, `trigger` and `subscribe` are the same code either way.\n */\nexport const createLankaScenario = <TData = void>(\n\tconfig: ILankaScenarioConfig,\n): ILankaScenario<TData> => {\n\tclass FunctionalScenario extends ALankaScenario<TData> {\n\t\tpublic static override skipAutoRegistration = config.skipAutoRegistration ?? false;\n\n\t\tpublic readonly name = config.name;\n\t\tpublic readonly eventType = config.eventType;\n\t\tpublic readonly dataTypeName = config.dataTypeName;\n\t}\n\n\treturn new FunctionalScenario();\n};\n"],"mappings":";;;;;;;;;;AA0BO,IAAM,sBAAsB,CAClC,WAC2B;AAAA,EAC3B,MAAM,2BAA2B,eAAsB;AAAA,IACtD,OAAuB,uBAAuB,OAAO,wBAAwB;AAAA,IAE7D,OAAO,OAAO;AAAA,IACd,YAAY,OAAO;AAAA,IACnB,eAAe,OAAO;AAAA,EACvC;AAEA,SAAO,IAAI,mBAAmB;AAC/B;","names":[]}