lanka 1.0.1 → 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 (45) 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-CLkq4MaJ.d.ts → LankaScenarioLocator-D86TIwiu.d.ts} +10 -5
  6. package/dist/_extend/index.d.ts +4 -4
  7. package/dist/_extend/index.js +2 -2
  8. package/dist/_internal/index.d.ts +5 -5
  9. package/dist/{activeRuntime-DT4gB16d.d.ts → activeRuntime-B336NU5I.d.ts} +2 -2
  10. package/dist/bootstrap/index.d.ts +13 -144
  11. package/dist/bootstrap/index.js +4 -4
  12. package/dist/{chunk-MYZQYOMD.js → chunk-5MAQVBI2.js} +20 -15
  13. package/dist/chunk-5MAQVBI2.js.map +1 -0
  14. package/dist/chunk-D5WKKEIR.js +54 -0
  15. package/dist/chunk-D5WKKEIR.js.map +1 -0
  16. package/dist/{chunk-63ST2UKP.js → chunk-LMKLLEHA.js} +103 -17
  17. package/dist/chunk-LMKLLEHA.js.map +1 -0
  18. package/dist/{chunk-YXI4OQEV.js → chunk-O5ROO7QF.js} +27 -4
  19. package/dist/chunk-O5ROO7QF.js.map +1 -0
  20. package/dist/{chunk-HZAIAGWS.js → chunk-UGXSGQPW.js} +6 -2
  21. package/dist/chunk-UGXSGQPW.js.map +1 -0
  22. package/dist/createLanka-DI1CSy2Q.d.ts +139 -0
  23. package/dist/gateway/index.d.ts +77 -67
  24. package/dist/gateway/index.js +50 -54
  25. package/dist/gateway/index.js.map +1 -1
  26. package/dist/index.d.ts +7 -6
  27. package/dist/index.js +4 -4
  28. package/dist/locator/index.d.ts +1 -1
  29. package/dist/scenario/index.d.ts +6 -4
  30. package/dist/scenario/index.js +2 -2
  31. package/dist/stream/index.d.ts +386 -0
  32. package/dist/stream/index.js +287 -0
  33. package/dist/stream/index.js.map +1 -0
  34. package/dist/validation/index.js +4 -48
  35. package/dist/validation/index.js.map +1 -1
  36. package/dist/viewmodel/index.d.ts +1 -1
  37. package/dist/viewmodel/index.js +2 -2
  38. package/package.json +7 -3
  39. package/skills/lanka-core/SKILL.md +1 -1
  40. package/skills/lanka-core/reference.md +110 -17
  41. package/skills/lanka-packages/SKILL.md +1 -1
  42. package/dist/chunk-63ST2UKP.js.map +0 -1
  43. package/dist/chunk-HZAIAGWS.js.map +0 -1
  44. package/dist/chunk-MYZQYOMD.js.map +0 -1
  45. package/dist/chunk-YXI4OQEV.js.map +0 -1
@@ -0,0 +1,139 @@
1
+ import { I as ILankaScope } from './createLankaScope-BiFxNQgl.js';
2
+ import { I as ILankaRuntime } from './activeRuntime-B336NU5I.js';
3
+ import { a as ILankaHost, I as ILankaFlags } from './ILankaRuntimeConfig-Vl436GWK.js';
4
+ import { T as TLankaRequestMiddleware } from './lankaRequestMiddleware-DAC5kCb7.js';
5
+
6
+ /**
7
+ * A plugin is an extension core knows by SHAPE rather than by name.
8
+ *
9
+ * ## Plugin versus module
10
+ *
11
+ * A module is called by the application (`app → module`) and core does not know
12
+ * it exists. A plugin sits on the path core itself walks (`app → core → plugin`).
13
+ * The test question: does core need a hook for this to work? No — then it is a
14
+ * module, and making it a plugin costs more, because the hook has to be supported
15
+ * forever.
16
+ *
17
+ * ## Why `install` receives the instance
18
+ *
19
+ * So a plugin has no private route to the framework. Everything it can do comes
20
+ * from the instance it was given, which means two instances in one process (a
21
+ * test beside the app) do not share its configuration.
22
+ */
23
+ interface ILankaPlugin {
24
+ /**
25
+ * The name the plugin is recognised by. Registering the same name twice is
26
+ * rejected: two copies of a retry policy would silently double the request
27
+ * count.
28
+ */
29
+ readonly name: string;
30
+ /**
31
+ * Installation. The returned function removes everything the plugin installed
32
+ * and is called when the plugin is removed and when the instance is disposed.
33
+ */
34
+ install: (lanka: ILankaInstance) => (() => void) | void;
35
+ }
36
+
37
+ /**
38
+ * A framework instance: all framework state in one object.
39
+ *
40
+ * What instance-scoped state buys: two apps in one process (micro-frontends,
41
+ * Storybook beside the app) no longer share a bus, locator caches and mock mode;
42
+ * SSR does not reuse state between different users' requests; and test isolation
43
+ * rests on construction rather than on a global `beforeEach` reaching into
44
+ * internal registries.
45
+ *
46
+ * **Ambient facades** — `lankaEventBus.dispatch`, `lankaSingletons.foo`,
47
+ * `getLankaFlags()`, `lankaHttpInFlight` — resolve THE ONE active instance
48
+ * (`internal/activeRuntime.ts`). Isolation belongs to whoever holds an instance;
49
+ * a facade cannot offer it.
50
+ *
51
+ * One thing stays at module level deliberately: `ALankaScenario` collects
52
+ * constructed scenarios into a static pool. That is a REGISTRY OF DEFINITIONS,
53
+ * not runtime state — the classes come from one `@lanka_di/Scenarios` barrel and
54
+ * both instances must see the same list. Splitting it would be divergence.
55
+ */
56
+ interface ILankaInstance extends ILankaRuntime {
57
+ /**
58
+ * Adds a wrapper around every request. Returns a function that removes it.
59
+ *
60
+ * This is how `@lankajs/plugin-http` installs retry, the idempotency key, the
61
+ * CSRF header and auth refresh.
62
+ */
63
+ useRequestMiddleware(middleware: TLankaRequestMiddleware): () => void;
64
+ /** Default timeout for every request of this instance. */
65
+ setRequestTimeout(timeoutMs: number | undefined): void;
66
+ /** Resolves a service in the root scope — for the instance's whole lifetime. */
67
+ resolve<TInstance>(propertyName: string): TInstance;
68
+ /**
69
+ * Creates a scope: a lifetime shorter than the application's.
70
+ *
71
+ * An object created in a scope goes away with it.
72
+ */
73
+ createScope(): ILankaScope;
74
+ /**
75
+ * Registers a plugin. Returns a function that removes it.
76
+ *
77
+ * The fifth and last extension point. An extension point declared before
78
+ * anything plugs into it describes an imagined need while costing real
79
+ * support, so this one arrived with the FIRST plugin.
80
+ */
81
+ use(plugin: ILankaPlugin): () => void;
82
+ /** Runs services and the scenario layer. Idempotent. */
83
+ bootstrap(config?: ILankaBootstrapConfig): Promise<void>;
84
+ /** Has bootstrap already run? */
85
+ isBootstrapped(): boolean;
86
+ /** Makes this instance the one ambient facades resolve to. */
87
+ activate(): void;
88
+ /**
89
+ * Removes subscriptions, clears registries and, if this instance was active,
90
+ * clears the pointer. Returns the framework to its pre-bootstrap state.
91
+ */
92
+ dispose(): void;
93
+ }
94
+ interface ILankaInstanceConfig {
95
+ host: ILankaHost;
96
+ flags?: ILankaFlags;
97
+ }
98
+ interface ILankaServiceConfig {
99
+ name?: string;
100
+ init: () => void | Promise<void>;
101
+ sync?: boolean;
102
+ priority?: number;
103
+ /**
104
+ * A failure of this service does not abort bootstrap.
105
+ *
106
+ * Without the flag one failed service takes the WHOLE phase with it: the async
107
+ * phase because of `Promise.all`, the sync phase because later tasks never run.
108
+ * Wrapping the failure in a swallowing `try/catch` is worse still — the app
109
+ * starts with a partially executed plan and does not know it.
110
+ */
111
+ optional?: boolean;
112
+ /**
113
+ * How long to wait for the service. Overrunning counts as a failure.
114
+ *
115
+ * Without a deadline a service that never settles holds bootstrap forever and
116
+ * the app never paints its first screen. Failing is more honest than waiting:
117
+ * an optional service is skipped, a required one names itself.
118
+ */
119
+ timeoutMs?: number;
120
+ }
121
+ interface ILankaScenarioBootstrapConfig {
122
+ sync?: boolean;
123
+ priority?: number;
124
+ }
125
+ interface ILankaBootstrapConfig {
126
+ services?: ILankaServiceConfig[];
127
+ scenarios?: ILankaScenarioBootstrapConfig;
128
+ }
129
+ /**
130
+ * Creates an instance and makes it active.
131
+ *
132
+ * Activating on creation is the deliberate default: there is almost always one
133
+ * app and the facades must work immediately. A second instance takes the
134
+ * pointer — the last one created serves the facades. Callers needing another
135
+ * order call `activate()` explicitly.
136
+ */
137
+ declare function createLanka(config: ILankaInstanceConfig): ILankaInstance;
138
+
139
+ export { type ILankaBootstrapConfig as I, type ILankaInstance as a, type ILankaInstanceConfig as b, type ILankaPlugin as c, type ILankaScenarioBootstrapConfig as d, type ILankaServiceConfig as e, createLanka as f };
@@ -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;
@@ -363,20 +395,14 @@ var createLankaGateway = (config) => {
363
395
  return config.methods({
364
396
  endpoint: (path) => this.endpoint(path),
365
397
  request: (path, options, mockHandler) => this.request(path, options, mockHandler),
366
- buildQueryParams: (params) => this.buildQueryParams(params)
398
+ buildQueryParams: (params) => this.buildQueryParams(params),
399
+ validationService: this.validationService
367
400
  });
368
401
  }
369
402
  }
370
403
  return new FunctionalGateway(config).build();
371
404
  };
372
405
 
373
- // src/gateway/transport/lanka-fetch-transport/LankaFetchTransport.ts
374
- var LankaFetchTransport = class {
375
- async request(resource, options) {
376
- return await fetch(resource, options);
377
- }
378
- };
379
-
380
406
  // src/gateway/request/lanka-fetch-request/LankaFetchRequest.ts
381
407
  var LankaFetchRequest = class extends ALankaTransportRequest {
382
408
  constructor(config = {}) {
@@ -392,43 +418,13 @@ var createLankaFetchRequest = (config = {}) => new LankaFetchRequest(config);
392
418
 
393
419
  // src/gateway/request/_factories/create-lanka-fetch-json-request/createLankaFetchJsonRequest.ts
394
420
  var createLankaFetchJsonRequest = (config = {}) => new LankaFetchJsonRequest(config);
395
-
396
- // src/gateway/transport/lanka-fetch-form-data-transport/LankaFetchFormDataTransport.ts
397
- var LankaFetchFormDataTransport = class {
398
- async request(resource, options) {
399
- const formDataOptions = { ...options };
400
- if (formDataOptions.body instanceof FormData && formDataOptions.headers) {
401
- const headers = new Headers(formDataOptions.headers);
402
- headers.delete("Content-Type");
403
- formDataOptions.headers = headers;
404
- }
405
- return await fetch(resource, formDataOptions);
406
- }
407
- };
408
-
409
- // src/gateway/request/lanka-fetch-form-data-request/LankaFetchFormDataRequest.ts
410
- var LankaFetchFormDataRequest = class extends ALankaTransportRequest {
411
- constructor(config = {}) {
412
- super(config, () => new LankaFetchFormDataTransport());
413
- }
414
- parse(response) {
415
- return Promise.resolve(response);
416
- }
417
- };
418
-
419
- // src/gateway/request/_factories/create-lanka-fetch-form-data-request/createLankaFetchFormDataRequest.ts
420
- var createLankaFetchFormDataRequest = (config = {}) => new LankaFetchFormDataRequest(config);
421
421
  export {
422
422
  ALankaGateway,
423
423
  ALankaRequest,
424
- LankaFetchFormDataRequest,
425
- LankaFetchFormDataTransport,
426
424
  LankaFetchJsonRequest,
427
- LankaFetchJsonTransport,
428
425
  LankaFetchRequest,
429
426
  LankaFetchTransport,
430
427
  buildLankaQueryParams,
431
- createLankaFetchFormDataRequest,
432
428
  createLankaFetchJsonRequest,
433
429
  createLankaFetchRequest,
434
430
  createLankaGateway,