lanka 1.0.0 → 1.1.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 (52) hide show
  1. package/README.md +5 -3
  2. package/dist/{ALankaGateway-ExlRGT3D.d.ts → ALankaGateway-CkW1LbKE.d.ts} +50 -4
  3. package/dist/{ILankaScenarioMetadata-Bu-yggTZ.d.ts → ILankaScenarioMetadata-GoWWNEQL.d.ts} +1 -1
  4. package/dist/{ILankaScenarioVM-DuCyPoyT.d.ts → ILankaScenarioVM-DUsI-fSc.d.ts} +116 -3
  5. package/dist/{LankaScenarioLocator-BGQHwf3n.d.ts → LankaScenarioLocator-D86TIwiu.d.ts} +11 -6
  6. package/dist/{LankaSharedStoreLocator-MvCpav5F.d.ts → LankaSharedStoreLocator-zS2kLu-S.d.ts} +21 -0
  7. package/dist/_extend/index.d.ts +7 -7
  8. package/dist/_extend/index.js +3 -3
  9. package/dist/_internal/index.d.ts +6 -6
  10. package/dist/{activeRuntime-FcsSJvUg.d.ts → activeRuntime-B336NU5I.d.ts} +3 -3
  11. package/dist/bootstrap/index.d.ts +14 -145
  12. package/dist/bootstrap/index.js +5 -5
  13. package/dist/{chunk-FIR4XTBL.js → chunk-5MAQVBI2.js} +27 -24
  14. package/dist/chunk-5MAQVBI2.js.map +1 -0
  15. package/dist/chunk-D5WKKEIR.js +54 -0
  16. package/dist/chunk-D5WKKEIR.js.map +1 -0
  17. package/dist/{chunk-RYFZCAQ3.js → chunk-LMKLLEHA.js} +111 -25
  18. package/dist/chunk-LMKLLEHA.js.map +1 -0
  19. package/dist/{chunk-EWVDJYCC.js → chunk-O5ROO7QF.js} +28 -9
  20. package/dist/chunk-O5ROO7QF.js.map +1 -0
  21. package/dist/{chunk-ILQNYQY5.js → chunk-UE2C76OR.js} +32 -18
  22. package/dist/chunk-UE2C76OR.js.map +1 -0
  23. package/dist/{chunk-Q3SOVBIJ.js → chunk-UGXSGQPW.js} +8 -4
  24. package/dist/chunk-UGXSGQPW.js.map +1 -0
  25. package/dist/createLanka-DI1CSy2Q.d.ts +139 -0
  26. package/dist/{createLankaScope-Bc_vChRs.d.ts → createLankaScope-BiFxNQgl.d.ts} +1 -1
  27. package/dist/gateway/index.d.ts +77 -67
  28. package/dist/gateway/index.js +51 -56
  29. package/dist/gateway/index.js.map +1 -1
  30. package/dist/index.d.ts +9 -8
  31. package/dist/index.js +5 -5
  32. package/dist/locator/index.d.ts +7 -55
  33. package/dist/locator/index.js +1 -1
  34. package/dist/scenario/index.d.ts +6 -4
  35. package/dist/scenario/index.js +2 -2
  36. package/dist/stream/index.d.ts +386 -0
  37. package/dist/stream/index.js +287 -0
  38. package/dist/stream/index.js.map +1 -0
  39. package/dist/validation/index.js +4 -48
  40. package/dist/validation/index.js.map +1 -1
  41. package/dist/viewmodel/index.d.ts +1 -1
  42. package/dist/viewmodel/index.js +4 -2
  43. package/dist/viewmodel/index.js.map +1 -1
  44. package/package.json +7 -3
  45. package/skills/lanka-core/SKILL.md +1 -1
  46. package/skills/lanka-core/reference.md +110 -17
  47. package/skills/lanka-packages/SKILL.md +1 -1
  48. package/dist/chunk-EWVDJYCC.js.map +0 -1
  49. package/dist/chunk-FIR4XTBL.js.map +0 -1
  50. package/dist/chunk-ILQNYQY5.js.map +0 -1
  51. package/dist/chunk-Q3SOVBIJ.js.map +0 -1
  52. package/dist/chunk-RYFZCAQ3.js.map +0 -1
@@ -1,9 +1,9 @@
1
- import { T as TLankaExecuteOptions, I as IALankaGatewayConfig, a as ILankaRequest, b as TLankaQueryBuilder } from '../ALankaGateway-ExlRGT3D.js';
2
- export { A as ALankaGateway, c as TLankaQueryParams } from '../ALankaGateway-ExlRGT3D.js';
1
+ import { T as TLankaExecuteOptions, I as IALankaGatewayConfig, a as TLankaRequestInit, b as ILankaRequest, c as TLankaQueryBuilder } from '../ALankaGateway-CkW1LbKE.js';
2
+ export { A as ALankaGateway, d as TLankaQueryParams } from '../ALankaGateway-CkW1LbKE.js';
3
+ import { I as ILankaValidator } from '../lankaStandardValidator-CL-r-zEV.js';
3
4
  import { T as TLankaErrorHandler } from '../TLankaErrorHandler-Yfqtdh1M.js';
4
5
  export { I as ILankaInFlightCounter, l as lankaHttpInFlight } from '../lankaHttpInFlight-Bk1eIuSx.js';
5
6
  export { I as ILankaRequestContext, T as TLankaRequestMiddleware } from '../lankaRequestMiddleware-DAC5kCb7.js';
6
- import '../lankaStandardValidator-CL-r-zEV.js';
7
7
  import '@standard-schema/spec';
8
8
 
9
9
  /**
@@ -20,6 +20,8 @@ interface ILankaGatewayContext<TOptions> {
20
20
  request: <TReturn = unknown>(path: string, options?: TLankaExecuteOptions<TOptions>, mockHandler?: () => Promise<TReturn>) => Promise<TReturn>;
21
21
  /** Serialises query parameters the way this gateway was configured to. */
22
22
  buildQueryParams: <T extends object>(params: T) => URLSearchParams;
23
+ /** Checks a response body: the validator this gateway was given, or the Standard Schema port. */
24
+ validationService: ILankaValidator;
23
25
  }
24
26
 
25
27
  /** What a gateway is built from, whichever style builds it. */
@@ -47,13 +49,13 @@ declare const createLankaGateway: <TOptions, TMethods extends object>(config: IL
47
49
  * How a gateway request goes on the wire.
48
50
  *
49
51
  * A subclass declares one method, `request()`, and does only its own work there:
50
- * `LankaFetchJsonRequest` returns parsed JSON, `LankaFetchFormDataRequest`
51
- * returns the whole response, a custom transport returns whatever it likes.
52
+ * `LankaFetchJsonRequest` returns parsed JSON, `LankaFetchRequest` returns the
53
+ * whole response, a custom kind returns whatever it likes.
52
54
  *
53
55
  * Overriding `request()` customises the request flow, failure handling, mock
54
56
  * substitution, response transformation and log interception.
55
57
  */
56
- declare abstract class ALankaRequest<TOptions = RequestInit> implements ILankaRequest<TOptions> {
58
+ declare abstract class ALankaRequest<TOptions = TLankaRequestInit> implements ILankaRequest<TOptions> {
57
59
  protected readonly errorHandler?: TLankaErrorHandler;
58
60
  protected readonly useMock: boolean;
59
61
  protected constructor(config: {
@@ -81,10 +83,23 @@ declare abstract class ALankaRequest<TOptions = RequestInit> implements ILankaRe
81
83
  }
82
84
 
83
85
  /**
84
- * Transport layer interface for Gateway.
85
- * Allows to swap between different communication protocols (HTTP Fetch, gRPC, WebSocket, etc.)
86
+ * How bytes travel. The seam a consumer replaces to change the PROTOCOL.
87
+ *
88
+ * `LankaFetchTransport` is the only implementation core ships, and one is the
89
+ * right number: HTTP over `fetch` is what almost every application does, and the
90
+ * things that once justified a second and a third — a JSON `content-type`, a
91
+ * multipart one — turned out to be encodings rather than protocols. An encoding
92
+ * belongs to the CALL, and the shipped transport reads the body to decide it.
93
+ *
94
+ * Implement this for something genuinely different: a native bridge, a socket, an
95
+ * offline queue, a double that never leaves the process. Anything that still ends
96
+ * in `fetch` and only wants to add a header, a credential, a retry or a refresh
97
+ * is POLICY — write a `TLankaRequestMiddleware` and register it with
98
+ * `useRequestMiddleware`, or reach for `@lankajs/plugin-http`, which already has
99
+ * all four. A transport rewritten to carry policy is how an application ends up
100
+ * maintaining its own copy of this package.
86
101
  */
87
- interface ILankaTransport<TOptions = RequestInit> {
102
+ interface ILankaTransport<TOptions = TLankaRequestInit> {
88
103
  /**
89
104
  * Executes a request and returns a Response.
90
105
  * @param resource - Request resource (URL or Request object)
@@ -102,12 +117,17 @@ interface ILankaTransportRequestConfig<TOptions> {
102
117
  /**
103
118
  * The shape every fetch-backed request has: mock, send, check, parse.
104
119
  *
105
- * The three concrete requests differ in exactly two places — which transport
106
- * they default to, and how they turn a successful `Response` into a value. Both
107
- * are parameters of this template, so a fourth kind is a subclass with one
108
- * method rather than a fourth copy of the sequence.
120
+ * The concrete requests differ in ONE place — how they turn a successful
121
+ * `Response` into a value — so a third kind is a subclass with one method rather
122
+ * than a third copy of the sequence.
123
+ *
124
+ * The default transport stays a constructor PARAMETER even though both shipped
125
+ * kinds pass the same one. It is the seam a request kind that is not fetch-backed
126
+ * comes through: this template is the mock/send/check/parse sequence, and nothing
127
+ * in it is about HTTP. Defaulting the parameter here would fix `TOptions` to
128
+ * fetch options for everyone who reuses the sequence.
109
129
  */
110
- declare abstract class ALankaTransportRequest<TOptions = RequestInit> extends ALankaRequest<TOptions> {
130
+ declare abstract class ALankaTransportRequest<TOptions = TLankaRequestInit> extends ALankaRequest<TOptions> {
111
131
  protected readonly transport: ILankaTransport<TOptions>;
112
132
  protected constructor(config: ILankaTransportRequestConfig<TOptions>, createDefaultTransport: () => ILankaTransport<TOptions>);
113
133
  protected request<TReturn>(endpoint: string, options?: TOptions, mockHandler?: () => Promise<TReturn>): Promise<TReturn>;
@@ -131,10 +151,19 @@ declare abstract class ALankaTransportRequest<TOptions = RequestInit> extends AL
131
151
  /**
132
152
  * The raw request: hands the `Response` back untouched.
133
153
  *
134
- * The minimal, extensible case — a caller wanting headers, a stream or a blob
135
- * reads them off the response itself.
154
+ * The minimal, extensible case — a caller wanting headers, a stream, a blob or a
155
+ * `204` reads them off the response itself. Multipart uploads come through here
156
+ * too: the transport encodes by looking at the body, so posting a `FormData` and
157
+ * posting an object are the same call.
158
+ *
159
+ * `TOptions` is CONSTRAINED to fetch options rather than merely defaulted to
160
+ * them. A consumer widening it — their own `interface IRequestOptions extends
161
+ * TLankaRequestInit` — still gets the shipped transport, because the constraint
162
+ * is what lets the framework hand one over without a cast. Unconstrained, the
163
+ * assignment did not typecheck and core cast its way past it; the cast worked
164
+ * here and was unavailable to the consumer, who wrote a transport instead.
136
165
  */
137
- declare class LankaFetchRequest<TOptions = RequestInit> extends ALankaTransportRequest<TOptions> {
166
+ declare class LankaFetchRequest<TOptions extends TLankaRequestInit = TLankaRequestInit> extends ALankaTransportRequest<TOptions> {
138
167
  constructor(config?: ILankaTransportRequestConfig<TOptions>);
139
168
  protected parse<TReturn>(response: Response): Promise<TReturn>;
140
169
  }
@@ -145,7 +174,7 @@ declare class LankaFetchRequest<TOptions = RequestInit> extends ALankaTransportR
145
174
  * One line, and that is the point — the factory IS the class, so a behaviour
146
175
  * cannot exist in one style and not the other.
147
176
  */
148
- declare const createLankaFetchRequest: <TOptions = RequestInit>(config?: ILankaTransportRequestConfig<TOptions>) => LankaFetchRequest<TOptions>;
177
+ declare const createLankaFetchRequest: <TOptions extends TLankaRequestInit = TLankaRequestInit>(config?: ILankaTransportRequestConfig<TOptions>) => LankaFetchRequest<TOptions>;
149
178
 
150
179
  /** The JSON request: parses the body, and refuses a body that is not JSON. */
151
180
  /**
@@ -155,7 +184,7 @@ declare const createLankaFetchRequest: <TOptions = RequestInit>(config?: ILankaT
155
184
  * what lets a test give the same gateway a transport that never leaves the
156
185
  * process. `createLankaFetchJsonRequest()` builds the same class.
157
186
  */
158
- declare class LankaFetchJsonRequest<TOptions = RequestInit> extends ALankaTransportRequest<TOptions> {
187
+ declare class LankaFetchJsonRequest<TOptions extends TLankaRequestInit = TLankaRequestInit> extends ALankaTransportRequest<TOptions> {
159
188
  constructor(config?: ILankaTransportRequestConfig<TOptions>);
160
189
  /**
161
190
  * Parses the body, or names the failure.
@@ -180,58 +209,39 @@ declare class LankaFetchJsonRequest<TOptions = RequestInit> extends ALankaTransp
180
209
  * One line, and that is the point — the factory IS the class, so a behaviour
181
210
  * cannot exist in one style and not the other.
182
211
  */
183
- declare const createLankaFetchJsonRequest: <TOptions = RequestInit>(config?: ILankaTransportRequestConfig<TOptions>) => LankaFetchJsonRequest<TOptions>;
212
+ declare const createLankaFetchJsonRequest: <TOptions extends TLankaRequestInit = TLankaRequestInit>(config?: ILankaTransportRequestConfig<TOptions>) => LankaFetchJsonRequest<TOptions>;
184
213
 
185
214
  /**
186
- * The multipart request: hands the `Response` back untouched.
215
+ * The network seam: `fetch`, plus the two things `fetch` cannot be told.
187
216
  *
188
- * Differs from `LankaFetchRequest` only in its transport — the one that must NOT
189
- * set `content-type`, because the browser writes it with the boundary and a
190
- * hand-set header leaves the body unparseable to the server.
191
- */
192
- declare class LankaFetchFormDataRequest<TOptions = RequestInit> extends ALankaTransportRequest<TOptions> {
193
- constructor(config?: ILankaTransportRequestConfig<TOptions>);
194
- protected parse<TReturn>(response: Response): Promise<TReturn>;
195
- }
196
-
197
- /**
198
- * The functional style of `LankaFetchFormDataRequest`: a multipart body, for an upload.
217
+ * ## Why there is ONE of these
199
218
  *
200
- * One line, and that is the point — the factory IS the class, so a behaviour
201
- * cannot exist in one style and not the other.
202
- */
203
- declare const createLankaFetchFormDataRequest: <TOptions = RequestInit>(config?: ILankaTransportRequestConfig<TOptions>) => LankaFetchFormDataRequest<TOptions>;
204
-
205
- /**
206
- * HTTP Fetch transport implementation.
207
- * Uses native fetch API without any project-specific decorators.
208
- * For project-specific logic (auth, error handling, etc.), use `request` parameter
209
- * in Gateway config or create a custom transport.
210
- */
211
- declare class LankaFetchTransport implements ILankaTransport<RequestInit> {
212
- request(resource: RequestInfo, options?: RequestInit): Promise<Response>;
213
- }
214
-
215
- /**
216
- * HTTP Fetch JSON transport implementation.
217
- * Uses native fetch API with JSON-specific headers.
218
- * Automatically sets Content-Type to application/json for requests with body.
219
- * For project-specific logic (auth, error handling, etc.), use `request` parameter
220
- * in Gateway config or create a custom transport.
221
- */
222
- declare class LankaFetchJsonTransport implements ILankaTransport<RequestInit> {
223
- request(resource: RequestInfo, options?: RequestInit): Promise<Response>;
224
- }
225
-
226
- /**
227
- * HTTP Fetch FormData transport implementation.
228
- * Uses native fetch API optimized for FormData requests.
229
- * Does not set Content-Type header (browser will set it automatically with boundary).
230
- * For project-specific logic (auth, error handling, etc.), use `request` parameter
231
- * in Gateway config or create a custom transport.
219
+ * There were three — a plain one, a JSON one and a multipart one — and the split
220
+ * was wrong at birth. `ILankaTransport` exists so a consumer can change the
221
+ * PROTOCOL: a native bridge, a socket, a double that never leaves the process.
222
+ * The three differed in a `content-type` header. That is not a protocol, it is an
223
+ * encoding, and an encoding is a property of the CALL: a gateway with fourteen
224
+ * JSON endpoints and one upload had no way to say so, because its request kind —
225
+ * and with it its transport — was fixed in its constructor. The application that
226
+ * hit this added a `useFormData` flag to its own options and wrote its own
227
+ * transport to read it.
228
+ *
229
+ * So the encoding is decided here, per call, by looking at the body. A gateway
230
+ * posts `FormData` to one endpoint and an object to the next, and neither it nor
231
+ * the request kind has to know.
232
+ *
233
+ * ## What does NOT belong here
234
+ *
235
+ * The base URL (`ALankaGateway` prefixes `apiBaseUrl`), credentials, static
236
+ * headers, CSRF, retry, auth refresh, idempotency keys and deadlines. Every one
237
+ * of those is policy around a request rather than a way of sending one, and every
238
+ * one is a middleware — `useRequestMiddleware`, which `@lankajs/plugin-http`
239
+ * occupies. A transport that grew them would be a second composition mechanism
240
+ * beside the one core already publishes, and "where does a header get added"
241
+ * would have two answers.
232
242
  */
233
- declare class LankaFetchFormDataTransport implements ILankaTransport<RequestInit> {
234
- request(resource: RequestInfo, options?: RequestInit): Promise<Response>;
243
+ declare class LankaFetchTransport implements ILankaTransport<TLankaRequestInit> {
244
+ request(resource: RequestInfo, options?: TLankaRequestInit): Promise<Response>;
235
245
  }
236
246
 
237
247
  /**
@@ -255,4 +265,4 @@ interface ILankaListQueryParams {
255
265
  filters?: Record<string, unknown>;
256
266
  }
257
267
 
258
- export { ALankaRequest, IALankaGatewayConfig, type ILankaGatewayConfig, type ILankaGatewayContext, type ILankaListQueryParams, ILankaRequest, type ILankaTransport, LankaFetchFormDataRequest, LankaFetchFormDataTransport, LankaFetchJsonRequest, LankaFetchJsonTransport, LankaFetchRequest, LankaFetchTransport, TLankaExecuteOptions, TLankaQueryBuilder, buildLankaQueryParams, createLankaFetchFormDataRequest, createLankaFetchJsonRequest, createLankaFetchRequest, createLankaGateway };
268
+ export { ALankaRequest, IALankaGatewayConfig, type ILankaGatewayConfig, type ILankaGatewayContext, type ILankaListQueryParams, ILankaRequest, type ILankaTransport, LankaFetchJsonRequest, LankaFetchRequest, LankaFetchTransport, TLankaExecuteOptions, TLankaQueryBuilder, TLankaRequestInit, buildLankaQueryParams, createLankaFetchJsonRequest, createLankaFetchRequest, createLankaGateway };
@@ -1,3 +1,6 @@
1
+ import {
2
+ lankaStandardValidator
3
+ } from "../chunk-D5WKKEIR.js";
1
4
  import {
2
5
  composeLankaRequestMiddleware
3
6
  } from "../chunk-YR4MZXMU.js";
@@ -181,30 +184,49 @@ var ALankaTransportRequest = class extends ALankaRequest {
181
184
  }
182
185
  };
183
186
 
184
- // src/gateway/transport/lanka-fetch-json-transport/LankaFetchJsonTransport.ts
185
- var LankaFetchJsonTransport = class {
187
+ // src/gateway/lanka-fetch-transport/LankaFetchTransport.ts
188
+ var CONTENT_TYPE = "content-type";
189
+ var JSON_CONTENT_TYPE = "application/json";
190
+ var LankaFetchTransport = class {
186
191
  async request(resource, options) {
187
- if (options?.body && !(options.body instanceof FormData)) {
188
- const headers = new Headers(options.headers);
189
- let body = options.body;
190
- if (typeof body === "object" && !(body instanceof FormData) && !(body instanceof Blob)) {
191
- body = JSON.stringify(body);
192
- }
193
- headers.set("Content-Type", "application/json");
194
- return await fetch(resource, {
195
- ...options,
196
- headers,
197
- body
198
- });
192
+ if (options === void 0 || options.body === void 0 || options.body === null) {
193
+ return await fetch(resource, options);
199
194
  }
200
- return await fetch(resource, options);
195
+ const { body, headers } = options;
196
+ if (isFormData(body)) {
197
+ if (headers === void 0) return await fetch(resource, options);
198
+ const stripped = new Headers(headers);
199
+ stripped.delete(CONTENT_TYPE);
200
+ return await fetch(resource, { ...options, headers: stripped });
201
+ }
202
+ if (isEncodedBody(body)) return await fetch(resource, options);
203
+ return await fetch(resource, {
204
+ ...options,
205
+ headers: withJsonContentType(headers),
206
+ body: JSON.stringify(body)
207
+ });
201
208
  }
202
209
  };
210
+ function withJsonContentType(headers) {
211
+ const result = new Headers(headers);
212
+ if (!result.has(CONTENT_TYPE)) result.set(CONTENT_TYPE, JSON_CONTENT_TYPE);
213
+ return result;
214
+ }
215
+ function isEncodedBody(body) {
216
+ if (typeof body === "string") return true;
217
+ if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) return true;
218
+ if (typeof Blob !== "undefined" && body instanceof Blob) return true;
219
+ if (body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return true;
220
+ return typeof ReadableStream !== "undefined" && body instanceof ReadableStream;
221
+ }
222
+ function isFormData(body) {
223
+ return typeof FormData !== "undefined" && body instanceof FormData;
224
+ }
203
225
 
204
226
  // src/gateway/request/lanka-fetch-json-request/LankaFetchJsonRequest.ts
205
227
  var LankaFetchJsonRequest = class extends ALankaTransportRequest {
206
228
  constructor(config = {}) {
207
- super(config, () => new LankaFetchJsonTransport());
229
+ super(config, () => new LankaFetchTransport());
208
230
  }
209
231
  /**
210
232
  * Parses the body, or names the failure.
@@ -269,12 +291,22 @@ var buildLankaQueryParams = (input) => {
269
291
  var ALankaGateway = class {
270
292
  requestExecutor;
271
293
  queryParamsHandler;
294
+ /**
295
+ * The validator a method checks a response body with.
296
+ *
297
+ * `config.validationService` when one was given, the Standard Schema port
298
+ * otherwise. It used to be accepted by the config and read by nothing: a
299
+ * consumer handing a test double to the gateway got the real validator and no
300
+ * error, which is the worst kind of ignored option — it looks honoured.
301
+ */
302
+ validationService;
272
303
  useMock;
273
304
  basePath;
274
305
  constructor(config) {
275
306
  lankaLogger.printGatewayLog("Create gateway", this);
276
307
  const flags = getLankaFlags();
277
308
  this.useMock = config.useMock ?? flags.isMockMode ?? false;
309
+ this.validationService = config.validationService ?? lankaStandardValidator;
278
310
  this.requestExecutor = config.request ?? new LankaFetchJsonRequest();
279
311
  this.basePath = config.basePath ?? "";
280
312
  this.queryParamsHandler = config.queryParamsHandler ?? buildLankaQueryParams;
@@ -297,8 +329,7 @@ var ALankaGateway = class {
297
329
  if (path.startsWith("/")) return path;
298
330
  if (path.startsWith("?")) return `${this.basePath}${path}`;
299
331
  const left = this.basePath.endsWith("/") ? this.basePath.slice(0, -1) : this.basePath;
300
- const right = path.startsWith("/") ? path.slice(1) : path;
301
- return `${left}/${right}`;
332
+ return `${left}/${path}`;
302
333
  }
303
334
  /**
304
335
  * Prefixes the API base URL from the host contract.
@@ -364,20 +395,14 @@ var createLankaGateway = (config) => {
364
395
  return config.methods({
365
396
  endpoint: (path) => this.endpoint(path),
366
397
  request: (path, options, mockHandler) => this.request(path, options, mockHandler),
367
- buildQueryParams: (params) => this.buildQueryParams(params)
398
+ buildQueryParams: (params) => this.buildQueryParams(params),
399
+ validationService: this.validationService
368
400
  });
369
401
  }
370
402
  }
371
403
  return new FunctionalGateway(config).build();
372
404
  };
373
405
 
374
- // src/gateway/transport/lanka-fetch-transport/LankaFetchTransport.ts
375
- var LankaFetchTransport = class {
376
- async request(resource, options) {
377
- return await fetch(resource, options);
378
- }
379
- };
380
-
381
406
  // src/gateway/request/lanka-fetch-request/LankaFetchRequest.ts
382
407
  var LankaFetchRequest = class extends ALankaTransportRequest {
383
408
  constructor(config = {}) {
@@ -393,43 +418,13 @@ var createLankaFetchRequest = (config = {}) => new LankaFetchRequest(config);
393
418
 
394
419
  // src/gateway/request/_factories/create-lanka-fetch-json-request/createLankaFetchJsonRequest.ts
395
420
  var createLankaFetchJsonRequest = (config = {}) => new LankaFetchJsonRequest(config);
396
-
397
- // src/gateway/transport/lanka-fetch-form-data-transport/LankaFetchFormDataTransport.ts
398
- var LankaFetchFormDataTransport = class {
399
- async request(resource, options) {
400
- const formDataOptions = { ...options };
401
- if (formDataOptions.body instanceof FormData && formDataOptions.headers) {
402
- const headers = new Headers(formDataOptions.headers);
403
- headers.delete("Content-Type");
404
- formDataOptions.headers = headers;
405
- }
406
- return await fetch(resource, formDataOptions);
407
- }
408
- };
409
-
410
- // src/gateway/request/lanka-fetch-form-data-request/LankaFetchFormDataRequest.ts
411
- var LankaFetchFormDataRequest = class extends ALankaTransportRequest {
412
- constructor(config = {}) {
413
- super(config, () => new LankaFetchFormDataTransport());
414
- }
415
- parse(response) {
416
- return Promise.resolve(response);
417
- }
418
- };
419
-
420
- // src/gateway/request/_factories/create-lanka-fetch-form-data-request/createLankaFetchFormDataRequest.ts
421
- var createLankaFetchFormDataRequest = (config = {}) => new LankaFetchFormDataRequest(config);
422
421
  export {
423
422
  ALankaGateway,
424
423
  ALankaRequest,
425
- LankaFetchFormDataRequest,
426
- LankaFetchFormDataTransport,
427
424
  LankaFetchJsonRequest,
428
- LankaFetchJsonTransport,
429
425
  LankaFetchRequest,
430
426
  LankaFetchTransport,
431
427
  buildLankaQueryParams,
432
- createLankaFetchFormDataRequest,
433
428
  createLankaFetchJsonRequest,
434
429
  createLankaFetchRequest,
435
430
  createLankaGateway,
@@ -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/transport/lanka-fetch-json-transport/LankaFetchJsonTransport.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/transport/lanka-fetch-transport/LankaFetchTransport.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","../../src/gateway/transport/lanka-fetch-form-data-transport/LankaFetchFormDataTransport.ts","../../src/gateway/request/lanka-fetch-form-data-request/LankaFetchFormDataRequest.ts","../../src/gateway/request/_factories/create-lanka-fetch-form-data-request/createLankaFetchFormDataRequest.ts"],"sourcesContent":["import 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, `LankaFetchFormDataRequest`\n * returns the whole response, a custom transport 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<TOptions = RequestInit> 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 { 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 three concrete requests differ in exactly two places — which transport\n * they default to, and how they turn a successful `Response` into a value. Both\n * are parameters of this template, so a fourth kind is a subclass with one\n * method rather than a fourth copy of the sequence.\n */\nexport abstract class ALankaTransportRequest<\n\tTOptions = RequestInit,\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\";\n\n/**\n * HTTP Fetch JSON transport implementation.\n * Uses native fetch API with JSON-specific headers.\n * Automatically sets Content-Type to application/json for requests with body.\n * For project-specific logic (auth, error handling, etc.), use `request` parameter\n * in Gateway config or create a custom transport.\n */\nexport class LankaFetchJsonTransport implements ILankaTransport<RequestInit> {\n\tasync request(resource: RequestInfo, options?: RequestInit): Promise<Response> {\n\t\t// Only set Content-Type if body exists and is not FormData\n\t\tif (options?.body && !(options.body instanceof FormData)) {\n\t\t\tconst headers = new Headers(options.headers);\n\n\t\t\t// If body is object, stringify it\n\t\t\tlet body = options.body;\n\t\t\tif (\n\t\t\t\ttypeof body === \"object\" &&\n\t\t\t\t!(body instanceof FormData) &&\n\t\t\t\t!(body instanceof Blob)\n\t\t\t) {\n\t\t\t\tbody = JSON.stringify(body);\n\t\t\t}\n\n\t\t\theaders.set(\"Content-Type\", \"application/json\");\n\n\t\t\treturn await fetch(resource, {\n\t\t\t\t...options,\n\t\t\t\theaders,\n\t\t\t\tbody,\n\t\t\t});\n\t\t}\n\n\t\t// No body or FormData - use options as-is\n\t\treturn await fetch(resource, options);\n\t}\n}\n","import { ALankaTransportRequest } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransportRequestConfig } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransport } from \"../../_interfaces/ILankaTransport\";\nimport { LankaFetchJsonTransport } from \"../../transport/lanka-fetch-json-transport/LankaFetchJsonTransport\";\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 = RequestInit,\n> extends ALankaTransportRequest<TOptions> {\n\tconstructor(config: ILankaTransportRequestConfig<TOptions> = {}) {\n\t\tsuper(config, () => new LankaFetchJsonTransport() as ILankaTransport<TOptions>);\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 { 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\";\n\nexport abstract class ALankaGateway<TOptions = RequestInit> {\n\tprotected requestExecutor: ILankaRequest<TOptions>;\n\tprotected queryParamsHandler: TLankaQueryBuilder;\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\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\tthis.requestExecutor = config.request ?? new LankaFetchJsonRequest<TOptions>();\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\tconst left = this.basePath.endsWith(\"/\") ? this.basePath.slice(0, -1) : this.basePath;\n\t\tconst right = path.startsWith(\"/\") ? path.slice(1) : path;\n\t\treturn `${left}/${right}`;\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});\n\t\t}\n\t}\n\n\treturn new FunctionalGateway(config).build();\n};\n","import type { ILankaTransport } from \"../../_interfaces/ILankaTransport\";\n\n/**\n * HTTP Fetch transport implementation.\n * Uses native fetch API without any project-specific decorators.\n * For project-specific logic (auth, error handling, etc.), use `request` parameter\n * in Gateway config or create a custom transport.\n */\nexport class LankaFetchTransport implements ILankaTransport<RequestInit> {\n\tasync request(resource: RequestInfo, options?: RequestInit): Promise<Response> {\n\t\treturn await fetch(resource, options);\n\t}\n}\n","import { ALankaTransportRequest } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransportRequestConfig } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransport } from \"../../_interfaces/ILankaTransport\";\nimport { LankaFetchTransport } from \"../../transport/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 or a blob\n * reads them off the response itself.\n */\nexport class LankaFetchRequest<TOptions = RequestInit> extends ALankaTransportRequest<TOptions> {\n\tconstructor(config: ILankaTransportRequestConfig<TOptions> = {}) {\n\t\tsuper(config, () => new LankaFetchTransport() as ILankaTransport<TOptions>);\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\";\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 = RequestInit>(\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\";\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 = RequestInit>(\n\tconfig: ILankaTransportRequestConfig<TOptions> = {},\n): LankaFetchJsonRequest<TOptions> => new LankaFetchJsonRequest<TOptions>(config);\n","import type { ILankaTransport } from \"../../_interfaces/ILankaTransport\";\n\n/**\n * HTTP Fetch FormData transport implementation.\n * Uses native fetch API optimized for FormData requests.\n * Does not set Content-Type header (browser will set it automatically with boundary).\n * For project-specific logic (auth, error handling, etc.), use `request` parameter\n * in Gateway config or create a custom transport.\n */\nexport class LankaFetchFormDataTransport implements ILankaTransport<RequestInit> {\n\tasync request(resource: RequestInfo, options?: RequestInit): Promise<Response> {\n\t\tconst formDataOptions: RequestInit = { ...options };\n\n\t\t// Remove Content-Type header if body is FormData (browser will set it with boundary)\n\t\tif (formDataOptions.body instanceof FormData && formDataOptions.headers) {\n\t\t\tconst headers = new Headers(formDataOptions.headers);\n\t\t\theaders.delete(\"Content-Type\");\n\t\t\tformDataOptions.headers = headers;\n\t\t}\n\n\t\treturn await fetch(resource, formDataOptions);\n\t}\n}\n","import { ALankaTransportRequest } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransportRequestConfig } from \"../_abstractions/lanka-transport-request/ALankaTransportRequest\";\nimport type { ILankaTransport } from \"../../_interfaces/ILankaTransport\";\nimport { LankaFetchFormDataTransport } from \"../../transport/lanka-fetch-form-data-transport/LankaFetchFormDataTransport\";\n\n/**\n * The multipart request: hands the `Response` back untouched.\n *\n * Differs from `LankaFetchRequest` only in its transport — the one that must NOT\n * set `content-type`, because the browser writes it with the boundary and a\n * hand-set header leaves the body unparseable to the server.\n */\nexport class LankaFetchFormDataRequest<\n\tTOptions = RequestInit,\n> extends ALankaTransportRequest<TOptions> {\n\tconstructor(config: ILankaTransportRequestConfig<TOptions> = {}) {\n\t\tsuper(config, () => new LankaFetchFormDataTransport() as ILankaTransport<TOptions>);\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 { LankaFetchFormDataRequest } from \"../../lanka-fetch-form-data-request/LankaFetchFormDataRequest\";\nimport type { ILankaTransportRequestConfig } from \"../../_abstractions/lanka-transport-request/ALankaTransportRequest\";\n\n/**\n * The functional style of `LankaFetchFormDataRequest`: a multipart body, for an upload.\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 createLankaFetchFormDataRequest = <TOptions = RequestInit>(\n\tconfig: ILankaTransportRequestConfig<TOptions> = {},\n): LankaFetchFormDataRequest<TOptions> => new LankaFetchFormDataRequest<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":[]}