@nilejs/client 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.
- package/LICENSE +21 -0
- package/README.md +25 -20
- package/dist/index.cjs +119 -64
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +93 -54
- package/dist/index.d.ts +93 -54
- package/dist/index.js +119 -64
- package/dist/index.js.map +1 -1
- package/package.json +26 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 nile-js
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -138,52 +138,57 @@ HTTP responses contain exactly `status`, `message` and `data`. The client maps t
|
|
|
138
138
|
|
|
139
139
|
For a validation failure, `result.error` is the readable message and `result.details` contains `{ errorCode, issues }`. `ValidationFailureData` is exported for applications that narrow this unknown failure data. Other failures can carry different details, so check the shape before using it. Diagnostic failures may include `Error Code: <unique-code> - <message>` in the message. Treat the code as a reference to share with your backend logs; do not use it as a fixed error category.
|
|
140
140
|
|
|
141
|
-
## Socket.IO
|
|
141
|
+
## Topics over Socket.IO
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
The same client sends and receives typed topic messages through `nile.socket`. Actions stay on HTTP. The socket connects on its first `send` or `receive`, so an app that never uses topics never opens one. Topic definitions and their `canReceive` and `canSend` checks live on the backend.
|
|
144
144
|
|
|
145
145
|
```ts
|
|
146
|
-
import {
|
|
146
|
+
import { createNileClient } from "@nilejs/client";
|
|
147
147
|
import type { ServicePayloads } from "./generated/types";
|
|
148
148
|
|
|
149
149
|
type Topics = {
|
|
150
150
|
"tasks.changed": {
|
|
151
151
|
data: { taskId: string; status: string };
|
|
152
|
+
scope: { projectId: string };
|
|
152
153
|
};
|
|
153
154
|
};
|
|
154
155
|
|
|
155
|
-
const
|
|
156
|
-
baseUrl: "http://localhost:8000",
|
|
157
|
-
|
|
158
|
-
|
|
156
|
+
const nile = createNileClient<ServicePayloads, Topics>({
|
|
157
|
+
baseUrl: "http://localhost:8000/api",
|
|
158
|
+
socket: {
|
|
159
|
+
// url: "https://realtime.example.com", when sockets run on another server
|
|
160
|
+
auth: () => {
|
|
161
|
+
return { token: "your-session-token" };
|
|
162
|
+
},
|
|
163
|
+
onReconnect: () => reloadTasks(),
|
|
159
164
|
},
|
|
160
165
|
});
|
|
161
166
|
|
|
162
|
-
const
|
|
167
|
+
const received = await nile.socket.receive({
|
|
163
168
|
topic: "tasks.changed",
|
|
169
|
+
scope: { projectId: "project-1" },
|
|
164
170
|
onMessage: (message) => {
|
|
165
|
-
console.log(message.data.taskId, message.data.status);
|
|
171
|
+
console.log(message.data.taskId, message.data.status, message.from?.userId);
|
|
166
172
|
},
|
|
167
173
|
});
|
|
168
174
|
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
payload: { title: "Ship the next feature" },
|
|
173
|
-
});
|
|
175
|
+
if (received.isErr) {
|
|
176
|
+
console.error(received.error);
|
|
177
|
+
}
|
|
174
178
|
|
|
175
|
-
const
|
|
179
|
+
const sent = await nile.socket.send({
|
|
176
180
|
topic: "tasks.changed",
|
|
181
|
+
scope: { projectId: "project-1" },
|
|
177
182
|
data: { taskId: "task-123", status: "done" },
|
|
178
183
|
});
|
|
179
184
|
|
|
180
|
-
if (
|
|
181
|
-
await
|
|
185
|
+
if (received.isOk) {
|
|
186
|
+
await received.value.unsubscribe();
|
|
182
187
|
}
|
|
183
|
-
socket.close();
|
|
188
|
+
nile.socket.close();
|
|
184
189
|
```
|
|
185
190
|
|
|
186
|
-
|
|
191
|
+
`send`, `receive` and `unsubscribe` return a Result: a topic may not exist, the scope may be wrong or the server may refuse access. Subscriptions are restored after a reconnect, and a refused one is reported to `socket.onError`. Messages sent while disconnected are not buffered or retried. `socket.url` defaults to the origin of `baseUrl`; set `socket.path` when the server uses a custom Socket.IO path. See [WebSockets](https://nile-js.github.io/nile/guide/features/websockets/) for server setup.
|
|
187
192
|
|
|
188
193
|
## Uploads
|
|
189
194
|
|
|
@@ -201,7 +206,7 @@ Multipart calls share the same cancellation, deadline and Result behavior as JSO
|
|
|
201
206
|
|
|
202
207
|
## Compatibility
|
|
203
208
|
|
|
204
|
-
Version 1.0
|
|
209
|
+
Version 1.1.0 supports Nile 1.1.x and reworks the socket API introduced in 1.0.x. Topics moved onto `createNileClient` as `nile.socket`, and `createNileSocketClient` and socket `invoke` were removed; the old helper is still exported as a stub that throws with the migration steps. Call actions with `nile.invoke` over HTTP. The HTTP client API is unchanged, so only 1.0.x socket users need to migrate.
|
|
205
210
|
|
|
206
211
|
## License
|
|
207
212
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
|
|
2
|
+
//#region src/result.ts
|
|
3
3
|
/**
|
|
4
4
|
* A successful client result. `data` mirrors `value` so code written for
|
|
5
5
|
* earlier clients keeps working. `message` is present only when the server sent one.
|
|
@@ -28,7 +28,8 @@ function clientErr(error, details = null) {
|
|
|
28
28
|
data: null
|
|
29
29
|
};
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
//#endregion
|
|
32
|
+
//#region src/safe-try.ts
|
|
32
33
|
/**
|
|
33
34
|
* Gracefully handles both synchronous and asynchronous operations by returning a result object.
|
|
34
35
|
* This replaces the need for external slang-ts dependency and avoids try/catch boilerplate.
|
|
@@ -68,7 +69,8 @@ function safeTry(fn) {
|
|
|
68
69
|
};
|
|
69
70
|
}
|
|
70
71
|
}
|
|
71
|
-
|
|
72
|
+
//#endregion
|
|
73
|
+
//#region src/request.ts
|
|
72
74
|
/** Send one action call; the deadline covers both fetch and reading its JSON body. */
|
|
73
75
|
async function sendRequest(config, body, multipart, options) {
|
|
74
76
|
const { timeout = config.timeout ?? 3e4, headers, signal, ...fetchOptions } = options;
|
|
@@ -145,58 +147,24 @@ function buildFormData(service, action, files, fields) {
|
|
|
145
147
|
function resolveError(error) {
|
|
146
148
|
return clientErr(error instanceof Error ? error.message : String(error));
|
|
147
149
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
* const result = await nile.invoke({
|
|
158
|
-
* service: "tasks",
|
|
159
|
-
* action: "create",
|
|
160
|
-
* payload: { title: "Buy milk" }
|
|
161
|
-
* });
|
|
162
|
-
* if (result.isErr) {
|
|
163
|
-
* console.error(result.error);
|
|
164
|
-
* } else {
|
|
165
|
-
* console.log(result.value);
|
|
166
|
-
* }
|
|
167
|
-
*/
|
|
168
|
-
function createNileClient(config) {
|
|
169
|
-
return {
|
|
170
|
-
/** Invoke a service action through the backend engine pipeline */
|
|
171
|
-
invoke: async (params) => {
|
|
172
|
-
const { service, action, payload, fetchOptions } = params;
|
|
173
|
-
return await sendNileRequest(config, "execute", service, action, payload, fetchOptions);
|
|
174
|
-
},
|
|
175
|
-
/** Discover available services and actions (supports "*" wildcard) */
|
|
176
|
-
explore: async (params) => {
|
|
177
|
-
const { service, action, fetchOptions } = params;
|
|
178
|
-
return await sendNileRequest(config, "explore", service, action, {}, fetchOptions);
|
|
179
|
-
},
|
|
180
|
-
/** Get action schemas as JSON Schema (supports "*" wildcard) */
|
|
181
|
-
schema: async (params) => {
|
|
182
|
-
const { service, action, fetchOptions } = params;
|
|
183
|
-
return await sendNileRequest(config, "schema", service, action, {}, fetchOptions);
|
|
184
|
-
},
|
|
185
|
-
/** Upload files to an action via multipart form-data */
|
|
186
|
-
upload: async (params) => {
|
|
187
|
-
const { service, action, files, fields, fetchOptions } = params;
|
|
188
|
-
return await sendUploadRequest(config, service, action, files, fields, fetchOptions);
|
|
189
|
-
}
|
|
190
|
-
};
|
|
150
|
+
//#endregion
|
|
151
|
+
//#region src/socket-client.ts
|
|
152
|
+
/** The socket connects to an origin; any path in a URL would be read by Socket.IO as a namespace. */
|
|
153
|
+
function socketOrigin(url) {
|
|
154
|
+
try {
|
|
155
|
+
return new URL(url).origin;
|
|
156
|
+
} catch {
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
191
159
|
}
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
function createNileSocketClient(config) {
|
|
160
|
+
/** Own a lazy Socket.IO connection with no offline write buffering. */
|
|
161
|
+
function createNileSocket(config) {
|
|
195
162
|
const timeout = config.timeout ?? 3e4;
|
|
196
163
|
if (!Number.isSafeInteger(timeout) || timeout < 1) throw new Error("Socket timeout must be positive");
|
|
197
164
|
let socket;
|
|
198
165
|
let connecting;
|
|
199
166
|
let closed = false;
|
|
167
|
+
let everConnected = false;
|
|
200
168
|
const listeners = /* @__PURE__ */ new Set();
|
|
201
169
|
const pending = /* @__PURE__ */ new Set();
|
|
202
170
|
const fail = (error) => clientErr(error);
|
|
@@ -245,7 +213,7 @@ function createNileSocketClient(config) {
|
|
|
245
213
|
continue;
|
|
246
214
|
}
|
|
247
215
|
const message = result.error;
|
|
248
|
-
settleCallback(() => config.
|
|
216
|
+
settleCallback(() => config.onError?.({
|
|
249
217
|
topic: listener.topic,
|
|
250
218
|
error: message
|
|
251
219
|
}));
|
|
@@ -260,7 +228,7 @@ function createNileSocketClient(config) {
|
|
|
260
228
|
resolve(fail("Socket client is closed"));
|
|
261
229
|
return;
|
|
262
230
|
}
|
|
263
|
-
const current = socket ?? io(config.
|
|
231
|
+
const current = socket ?? io(config.url ? socketOrigin(config.url) : void 0, {
|
|
264
232
|
path: config.path ?? "/socket.io",
|
|
265
233
|
autoConnect: false,
|
|
266
234
|
withCredentials: true,
|
|
@@ -271,11 +239,20 @@ function createNileSocketClient(config) {
|
|
|
271
239
|
});
|
|
272
240
|
if (!socket) {
|
|
273
241
|
socket = current;
|
|
274
|
-
current.on("disconnect", () => {
|
|
242
|
+
current.on("disconnect", (reason) => {
|
|
275
243
|
for (const cancel of [...pending]) cancel();
|
|
244
|
+
settleCallback(() => config.onDisconnect?.(reason));
|
|
276
245
|
});
|
|
277
246
|
current.on("connect", () => {
|
|
278
|
-
|
|
247
|
+
if (!everConnected) {
|
|
248
|
+
everConnected = true;
|
|
249
|
+
settleCallback(() => config.onConnect?.());
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
rejoin().then(() => settleCallback(() => config.onReconnect?.()));
|
|
253
|
+
});
|
|
254
|
+
current.on("connect_error", () => {
|
|
255
|
+
settleCallback(() => config.onError?.({ error: "Socket connection failed" }));
|
|
279
256
|
});
|
|
280
257
|
current.on("nile:message", (message) => dispatchMessage(message, listeners));
|
|
281
258
|
}
|
|
@@ -303,7 +280,6 @@ function createNileSocketClient(config) {
|
|
|
303
280
|
return connecting;
|
|
304
281
|
};
|
|
305
282
|
return {
|
|
306
|
-
invoke: (input) => request("nile:invoke", input),
|
|
307
283
|
send: (input) => request("nile:send", input),
|
|
308
284
|
async receive(input) {
|
|
309
285
|
const listener = {
|
|
@@ -322,16 +298,19 @@ function createNileSocketClient(config) {
|
|
|
322
298
|
return fail(result.error);
|
|
323
299
|
}
|
|
324
300
|
listener.normalizedScope = result.value?.scope;
|
|
325
|
-
return clientOk({
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
301
|
+
return clientOk({
|
|
302
|
+
topic: input.topic,
|
|
303
|
+
unsubscribe: () => {
|
|
304
|
+
listener.active = false;
|
|
305
|
+
listeners.delete(listener);
|
|
306
|
+
const shared = [...listeners].some((item) => item.topic === listener.topic && stableScope(item.scope) === stableScope(listener.scope));
|
|
307
|
+
if (shared || closed) return Promise.resolve(clientOk({ subscribed: shared }));
|
|
308
|
+
return request("nile:unsubscribe", {
|
|
309
|
+
topic: listener.topic,
|
|
310
|
+
scope: listener.scope
|
|
311
|
+
});
|
|
312
|
+
}
|
|
313
|
+
});
|
|
335
314
|
},
|
|
336
315
|
close() {
|
|
337
316
|
closed = true;
|
|
@@ -359,6 +338,82 @@ function dispatchMessage(message, listeners) {
|
|
|
359
338
|
Promise.resolve().then(() => listener.onMessage(message)).catch(() => void 0);
|
|
360
339
|
}
|
|
361
340
|
}
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region src/create-client.ts
|
|
343
|
+
/**
|
|
344
|
+
* Creates a type-safe Nile client for interacting with backend services.
|
|
345
|
+
*
|
|
346
|
+
* @param config - The client configuration including baseUrl
|
|
347
|
+
* @returns A factory object with invoke, explore, schema and upload methods, plus
|
|
348
|
+
* `socket` for topics. The socket connects on its first `send` or `receive`.
|
|
349
|
+
*
|
|
350
|
+
* @example
|
|
351
|
+
* const nile = createNileClient<ServicePayloads>({ baseUrl: "/api" });
|
|
352
|
+
* const result = await nile.invoke({
|
|
353
|
+
* service: "tasks",
|
|
354
|
+
* action: "create",
|
|
355
|
+
* payload: { title: "Buy milk" }
|
|
356
|
+
* });
|
|
357
|
+
* if (result.isErr) {
|
|
358
|
+
* console.error(result.error);
|
|
359
|
+
* } else {
|
|
360
|
+
* console.log(result.value);
|
|
361
|
+
* }
|
|
362
|
+
*
|
|
363
|
+
* const received = await nile.socket.receive({
|
|
364
|
+
* topic: "tasks.updated",
|
|
365
|
+
* onMessage: (message) => console.log(message.data),
|
|
366
|
+
* });
|
|
367
|
+
*/
|
|
368
|
+
function createNileClient(config) {
|
|
369
|
+
return {
|
|
370
|
+
socket: createNileSocket({
|
|
371
|
+
...config.socket,
|
|
372
|
+
url: config.socket?.url ?? config.baseUrl
|
|
373
|
+
}),
|
|
374
|
+
/** Invoke a service action through the backend engine pipeline */
|
|
375
|
+
invoke: async (params) => {
|
|
376
|
+
const { service, action, payload, fetchOptions } = params;
|
|
377
|
+
return await sendNileRequest(config, "execute", service, action, payload, fetchOptions);
|
|
378
|
+
},
|
|
379
|
+
/** Discover available services and actions (supports "*" wildcard) */
|
|
380
|
+
explore: async (params) => {
|
|
381
|
+
const { service, action, fetchOptions } = params;
|
|
382
|
+
return await sendNileRequest(config, "explore", service, action, {}, fetchOptions);
|
|
383
|
+
},
|
|
384
|
+
/** Get action schemas as JSON Schema (supports "*" wildcard) */
|
|
385
|
+
schema: async (params) => {
|
|
386
|
+
const { service, action, fetchOptions } = params;
|
|
387
|
+
return await sendNileRequest(config, "schema", service, action, {}, fetchOptions);
|
|
388
|
+
},
|
|
389
|
+
/** Upload files to an action via multipart form-data */
|
|
390
|
+
upload: async (params) => {
|
|
391
|
+
const { service, action, files, fields, fetchOptions } = params;
|
|
392
|
+
return await sendUploadRequest(config, service, action, files, fields, fetchOptions);
|
|
393
|
+
}
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
//#endregion
|
|
397
|
+
//#region src/deprecated.ts
|
|
398
|
+
const MIGRATION_MESSAGE = [
|
|
399
|
+
"createNileSocketClient was removed in @nilejs/client 1.1.0.",
|
|
400
|
+
"Create one client with createNileClient({ baseUrl, socket: { auth } })",
|
|
401
|
+
"and use nile.socket.send, nile.socket.receive and nile.socket.close.",
|
|
402
|
+
"Socket invoke is gone as well; call actions with nile.invoke over HTTP.",
|
|
403
|
+
"See https://nile-js.github.io/nile/guide/features/websockets/ and the",
|
|
404
|
+
"migration notes in packages/nile/docs/release-migration.md."
|
|
405
|
+
].join(" ");
|
|
406
|
+
/**
|
|
407
|
+
* Kept as a throwing stub so an upgrade fails with guidance instead of a
|
|
408
|
+
* missing export.
|
|
409
|
+
*
|
|
410
|
+
* @deprecated Use `createNileClient({ baseUrl, socket: { auth } })` and call
|
|
411
|
+
* `socket.send`, `socket.receive` and `socket.close` on the returned client.
|
|
412
|
+
*/
|
|
413
|
+
function createNileSocketClient(_config) {
|
|
414
|
+
throw new Error(MIGRATION_MESSAGE);
|
|
415
|
+
}
|
|
416
|
+
//#endregion
|
|
362
417
|
exports.buildFormData = buildFormData;
|
|
363
418
|
exports.createNileClient = createNileClient;
|
|
364
419
|
exports.createNileSocketClient = createNileSocketClient;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/result.ts","../src/safe-try.ts","../src/request.ts","../src/create-client.ts","../src/socket-client.ts"],"sourcesContent":["import type { ClientErr, ClientOk } from \"./types.js\";\n\n/**\n * A successful client result. `data` mirrors `value` so code written for\n * earlier clients keeps working. `message` is present only when the server sent one.\n */\nexport function clientOk<T>(value: T, message?: string): ClientOk<T> {\n return {\n isOk: true,\n isErr: false,\n value: value,\n error: null,\n ...(message === undefined ? {} : { message: message }),\n data: value,\n };\n}\n\n/**\n * A failed client result with a readable message and any data the server\n * attached to the failure. `data` stays null, as it was for earlier clients.\n */\nexport function clientErr(error: string, details: unknown = null): ClientErr {\n return {\n isOk: false,\n isErr: true,\n value: null,\n error: error,\n details: details,\n data: null,\n };\n}\n","/**\n * Internal result type for safeTry\n */\nexport type SafeResult<T, E = unknown> =\n | { isOk: true; value: T; isErr: false; error: null }\n | { isOk: false; value: null; isErr: true; error: E };\n\n/**\n * Gracefully handles both synchronous and asynchronous operations by returning a result object.\n * This replaces the need for external slang-ts dependency and avoids try/catch boilerplate.\n *\n * @param fn - The function to execute (sync or async)\n * @returns A result object containing either the value or the error\n *\n * @example\n * const { isOk, value, error } = await safeTry(() => fetch(url));\n */\nexport function safeTry<T>(\n fn: () => T | Promise<T>\n): Promise<SafeResult<T>> | SafeResult<T> {\n try {\n const result = fn();\n\n if (result instanceof Promise) {\n return result\n .then(\n (value): SafeResult<T> => ({\n isOk: true,\n value,\n isErr: false,\n error: null,\n })\n )\n .catch(\n (error): SafeResult<T> => ({\n isOk: false,\n value: null,\n isErr: true,\n error,\n })\n );\n }\n\n return { isOk: true, value: result, isErr: false, error: null };\n } catch (error) {\n return { isOk: false, value: null, isErr: true, error };\n }\n}\n","import { clientErr, clientOk } from \"./result.js\";\nimport { safeTry } from \"./safe-try.js\";\nimport type {\n ClientResult,\n ExternalResponse,\n FetchOptions,\n NileClientConfig,\n} from \"./types.js\";\n\n/** Send one action call; the deadline covers both fetch and reading its JSON body. */\nasync function sendRequest<T>(\n config: NileClientConfig,\n body: () => BodyInit,\n multipart: boolean,\n options: FetchOptions\n): Promise<ClientResult<T>> {\n const {\n timeout = config.timeout ?? 30_000,\n headers,\n signal,\n ...fetchOptions\n } = options;\n if (\n !Number.isSafeInteger(timeout) ||\n timeout < 1 ||\n timeout > 2_147_483_647\n ) {\n return clientErr(\n \"Action timeout must be a positive integer up to 2147483647 milliseconds.\"\n );\n }\n const controller = new AbortController();\n const abort = () => controller.abort(signal?.reason);\n if (signal?.aborted) {\n abort();\n } else {\n signal?.addEventListener(\"abort\", abort, { once: true });\n }\n let timedOut = false;\n const timeoutId = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, timeout);\n\n try {\n const requestResult = await safeTry(async () => {\n const mergedHeaders = new Headers(config.headers);\n new Headers(headers).forEach((value, key) => {\n mergedHeaders.set(key, value);\n });\n if (multipart) {\n mergedHeaders.delete(\"content-type\");\n } else {\n mergedHeaders.set(\"content-type\", \"application/json\");\n }\n const response = await fetch(\n `${config.baseUrl.replace(/\\/+$/, \"\")}/services`,\n {\n ...fetchOptions,\n method: \"POST\",\n headers: mergedHeaders,\n credentials: fetchOptions.credentials ?? config.credentials,\n body: body(),\n signal: controller.signal,\n }\n );\n const json: unknown = await response.json();\n if (\n json === null ||\n typeof json !== \"object\" ||\n !(\"status\" in json) ||\n typeof json.status !== \"boolean\" ||\n !(\"message\" in json) ||\n typeof json.message !== \"string\" ||\n !(\"data\" in json)\n ) {\n throw new Error(\"Invalid Nile action response.\");\n }\n return json as ExternalResponse<T>;\n });\n if (requestResult.isErr) {\n if (timedOut) {\n return clientErr(\"Action timed out.\");\n }\n if (signal?.aborted) {\n return clientErr(\"Action cancelled.\");\n }\n return resolveError(requestResult.error);\n }\n const result = requestResult.value;\n if (!result.status) {\n return clientErr(result.message, result.data ?? null);\n }\n return clientOk(result.data, result.message);\n } finally {\n clearTimeout(timeoutId);\n signal?.removeEventListener(\"abort\", abort);\n }\n}\n\n/** JSON action calls preserve the server's message and failure data unchanged. */\nexport function sendNileRequest<T = Record<string, unknown>>(\n config: NileClientConfig,\n intent: \"explore\" | \"execute\" | \"schema\",\n service: string,\n action: string,\n payload: unknown,\n options: FetchOptions = {}\n): Promise<ClientResult<T>> {\n return sendRequest<T>(\n config,\n () =>\n JSON.stringify({\n intent: intent,\n service: service,\n action: action,\n payload: payload ?? {},\n }),\n false,\n options\n );\n}\n\n/** Let the runtime set the multipart boundary; retain the same action Result contract. */\nexport function sendUploadRequest<T = Record<string, unknown>>(\n config: NileClientConfig,\n service: string,\n action: string,\n files: Record<string, File | File[]>,\n fields?: Record<string, string>,\n options: FetchOptions = {}\n): Promise<ClientResult<T>> {\n return sendRequest<T>(\n config,\n () => buildFormData(service, action, files, fields),\n true,\n options\n );\n}\n\n/**\n * Builds a FormData instance with RPC routing fields and file/field entries.\n * The server expects 'intent', 'service', 'action' as string fields.\n */\nexport function buildFormData(\n service: string,\n action: string,\n files: Record<string, File | File[]>,\n fields?: Record<string, string>\n): FormData {\n const formData = new FormData();\n\n // RPC routing fields the server expects\n formData.append(\"intent\", \"execute\");\n formData.append(\"service\", service);\n formData.append(\"action\", action);\n\n // User-provided string fields\n if (fields) {\n for (const [key, value] of Object.entries(fields)) {\n formData.append(key, value);\n }\n }\n\n // File attachments — arrays append multiple entries under the same key\n for (const [key, value] of Object.entries(files)) {\n if (Array.isArray(value)) {\n for (const file of value) {\n formData.append(key, file);\n }\n } else {\n formData.append(key, value);\n }\n }\n\n return formData;\n}\n\n/** Convert local transport errors to the same client failure shape. */\nfunction resolveError(error: unknown): ClientResult<never> {\n return clientErr(error instanceof Error ? error.message : String(error));\n}\n","import { sendNileRequest, sendUploadRequest } from \"./request.js\";\nimport type {\n ClientResult,\n NileClient,\n NileClientConfig,\n UploadParams,\n} from \"./types.js\";\n\n/**\n * Creates a type-safe Nile client for interacting with backend services.\n *\n * @param config - The client configuration including baseUrl\n * @returns A factory object with invoke, explore, schema, and upload methods\n *\n * @example\n * const nile = createNileClient<ServicePayloads>({ baseUrl: \"/api\" });\n * const result = await nile.invoke({\n * service: \"tasks\",\n * action: \"create\",\n * payload: { title: \"Buy milk\" }\n * });\n * if (result.isErr) {\n * console.error(result.error);\n * } else {\n * console.log(result.value);\n * }\n */\nexport function createNileClient<\n TPayloads = Record<string, Record<string, unknown>>,\n>(config: NileClientConfig): NileClient<TPayloads> {\n return {\n /** Invoke a service action through the backend engine pipeline */\n invoke: async <\n S extends keyof TPayloads & string,\n A extends keyof TPayloads[S] & string,\n >(\n params: {\n service: S;\n action: A;\n payload: TPayloads[S][A];\n fetchOptions?: Parameters<typeof sendNileRequest>[5];\n }\n ) => {\n const { service, action, payload, fetchOptions } = params;\n const result = await sendNileRequest<Record<string, unknown>>(\n config,\n \"execute\",\n service,\n action,\n payload,\n fetchOptions\n );\n return result;\n },\n\n /** Discover available services and actions (supports \"*\" wildcard) */\n explore: async (params) => {\n const { service, action, fetchOptions } = params;\n return await sendNileRequest(\n config,\n \"explore\",\n service,\n action,\n {},\n fetchOptions\n );\n },\n\n /** Get action schemas as JSON Schema (supports \"*\" wildcard) */\n schema: async (params) => {\n const { service, action, fetchOptions } = params;\n return await sendNileRequest(\n config,\n \"schema\",\n service,\n action,\n {},\n fetchOptions\n );\n },\n\n /** Upload files to an action via multipart form-data */\n upload: async (params: UploadParams) => {\n const { service, action, files, fields, fetchOptions } = params;\n return await sendUploadRequest(\n config,\n service,\n action,\n files,\n fields,\n fetchOptions\n );\n },\n };\n}\n","import type { Socket } from \"socket.io-client\";\nimport type {\n ActionShape,\n NileSocketClient,\n NileSocketClientConfig,\n SocketActions,\n SocketTopics,\n TopicShape,\n} from \"./socket-types.js\";\nimport { clientErr, clientOk } from \"./result.js\";\nimport type { ClientResult } from \"./types.js\";\n\ntype WireValue = object | string | number | boolean | null | undefined;\n/** Acknowledgements keep the server's `{ error, data }` wire shape; the client turns them into Results. */\ninterface WireResult {\n error: string | null;\n data: unknown;\n}\ninterface Listener {\n topic: string;\n scope?: WireValue;\n onMessage: (message: WireValue) => void;\n active: boolean;\n normalizedScope?: WireValue;\n}\n\n/** Own a lazy Socket.IO connection with no offline write buffering or automatic invocation retries. */\nexport function createNileSocketClient<\n Actions extends ActionShape<Actions> = SocketActions,\n Topics extends TopicShape<Topics> = SocketTopics,\n>(config: NileSocketClientConfig): NileSocketClient<Actions, Topics> {\n const timeout = config.timeout ?? 30_000;\n if (!Number.isSafeInteger(timeout) || timeout < 1) {\n throw new Error(\"Socket timeout must be positive\");\n }\n let socket: Socket | undefined;\n let connecting: Promise<ClientResult<Socket>> | undefined;\n let closed = false;\n const listeners = new Set<Listener>();\n const pending = new Set<() => void>();\n const fail = (error: string) => clientErr(error);\n const settleCallback = (fn: () => void) => {\n Promise.resolve()\n .then(fn)\n .catch(() => undefined);\n };\n const request = async <T>(\n event: string,\n input: WireValue\n ): Promise<ClientResult<T>> => {\n const connected = await connect();\n if (connected.isErr) {\n return fail(connected.error);\n }\n const current = connected.value;\n if (!current.connected || closed) {\n return fail(\"Socket disconnected\");\n }\n return new Promise((resolve) => {\n let settled = false;\n const finish = (result: ClientResult<T>) => {\n if (settled) {\n return;\n }\n settled = true;\n pending.delete(cancel);\n clearTimeout(timer);\n resolve(result);\n };\n const cancel = () => finish(fail(\"Socket disconnected\"));\n const timer = setTimeout(\n () => finish(fail(\"Socket acknowledgement timed out\")),\n timeout\n );\n pending.add(cancel);\n // The connection check and emit are synchronous; disconnected calls never enter the offline queue.\n current.emit(event, input, (result: WireResult) => {\n if (\n !result ||\n typeof result !== \"object\" ||\n !(\"error\" in result) ||\n !(\"data\" in result)\n ) {\n finish(fail(\"Invalid socket response\"));\n return;\n }\n if (typeof result.error === \"string\") {\n finish(clientErr(result.error, result.data));\n return;\n }\n // The server validated this acknowledgement for the requested event.\n finish(clientOk(result.data as T));\n });\n });\n };\n const rejoin = async () => {\n for (const listener of listeners) {\n if (!listener.active) {\n continue;\n }\n const result = await request<{ scope?: WireValue }>(\"nile:receive\", {\n topic: listener.topic,\n scope: listener.scope,\n });\n if (result.isOk) {\n listener.normalizedScope = result.value?.scope;\n continue;\n }\n const message = result.error;\n settleCallback(() =>\n config.onSubscriptionError?.({\n topic: listener.topic,\n error: message,\n })\n );\n }\n };\n const connect = (): Promise<ClientResult<Socket>> => {\n if (closed) {\n return Promise.resolve(fail(\"Socket client is closed\"));\n }\n if (socket?.connected) {\n return Promise.resolve(clientOk(socket));\n }\n if (connecting) {\n return connecting;\n }\n connecting = import(\"socket.io-client\")\n .then(\n ({ io }) =>\n new Promise<ClientResult<Socket>>((resolve) => {\n if (closed) {\n resolve(fail(\"Socket client is closed\"));\n return;\n }\n const current =\n socket ??\n io(config.baseUrl, {\n path: config.path ?? \"/socket.io\",\n autoConnect: false,\n withCredentials: true,\n timeout,\n auth: (done) => {\n Promise.resolve()\n .then(() =>\n typeof config.auth === \"function\"\n ? config.auth()\n : (config.auth ?? {})\n )\n .then(done)\n .catch(() => done({}));\n },\n });\n if (!socket) {\n socket = current;\n current.on(\"disconnect\", () => {\n for (const cancel of [...pending]) {\n cancel();\n }\n });\n current.on(\"connect\", () => {\n rejoin();\n });\n current.on(\"nile:message\", (message: WireValue) =>\n dispatchMessage(message, listeners)\n );\n }\n let settled = false;\n const finish = (result: ClientResult<Socket>) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n current.off(\"connect\", ready);\n current.off(\"connect_error\", failed);\n pending.delete(cancel);\n resolve(result);\n };\n const ready = () => finish(clientOk(current));\n const failed = () => finish(fail(\"Socket connection failed\"));\n const cancel = () => finish(fail(\"Socket client closed\"));\n const timer = setTimeout(\n () => finish(fail(\"Socket connection timed out\")),\n timeout\n );\n pending.add(cancel);\n current.once(\"connect\", ready);\n current.once(\"connect_error\", failed);\n current.connect();\n })\n )\n .catch(() => fail(\"Could not initialize socket client\"))\n .finally(() => {\n connecting = undefined;\n });\n return connecting;\n };\n return {\n invoke: (input) => request(\"nile:invoke\", input),\n send: (input) => request(\"nile:send\", input),\n async receive(input) {\n const listener: Listener = {\n ...input,\n scope: input.scope as WireValue,\n onMessage: input.onMessage as Listener[\"onMessage\"],\n active: true,\n };\n listeners.add(listener);\n const result = await request<{ subscribed: boolean; scope?: WireValue }>(\n \"nile:receive\",\n { topic: input.topic, scope: input.scope }\n );\n if (result.isErr) {\n listeners.delete(listener);\n return fail(result.error);\n }\n listener.normalizedScope = result.value?.scope;\n return clientOk({\n unsubscribe: () => {\n listener.active = false;\n listeners.delete(listener);\n const shared = [...listeners].some(\n (item) =>\n item.topic === listener.topic &&\n stableScope(item.scope) === stableScope(listener.scope)\n );\n if (shared || closed) {\n return Promise.resolve(clientOk({ subscribed: shared }));\n }\n return request(\"nile:unsubscribe\", {\n topic: listener.topic,\n scope: listener.scope,\n });\n },\n });\n },\n close() {\n closed = true;\n listeners.clear();\n for (const cancel of [...pending]) {\n cancel();\n }\n socket?.disconnect();\n socket?.removeAllListeners();\n },\n };\n}\n\n/** Match scoped messages independently of object property insertion order. */\nfunction stableScope(scope: WireValue): string {\n if (scope === undefined || scope === null) {\n return \"null\";\n }\n if (Array.isArray(scope)) {\n return `[${scope.map(stableScope).join(\",\")}]`;\n }\n if (typeof scope === \"object\") {\n return `{${Object.keys(scope)\n .sort()\n .map(\n (key) =>\n `${JSON.stringify(key)}:${stableScope((scope as Record<string, WireValue>)[key])}`\n )\n .join(\",\")}}`;\n }\n return JSON.stringify(scope);\n}\n\n/** Deliver messages only to listeners for the same validated topic and scope. */\nfunction dispatchMessage(message: WireValue, listeners: Set<Listener>) {\n if (!message || typeof message !== \"object\" || !(\"topic\" in message)) {\n return;\n }\n const scope = stableScope(\n \"scope\" in message ? (message.scope as WireValue) : undefined\n );\n for (const listener of listeners) {\n if (!listener.active || listener.topic !== message.topic) {\n continue;\n }\n if (stableScope(listener.normalizedScope ?? listener.scope) !== scope) {\n continue;\n }\n Promise.resolve()\n .then(() => listener.onMessage(message))\n .catch(() => undefined);\n }\n}\n"],"mappings":";;;;;;AAMA,SAAgB,SAAY,OAAU,SAA+B;CACnE,OAAO;EACL,MAAM;EACN,OAAO;EACA;EACP,OAAO;EACP,GAAI,YAAY,KAAA,IAAY,CAAC,IAAI,EAAW,QAAQ;EACpD,MAAM;CACR;AACF;;;;;AAMA,SAAgB,UAAU,OAAe,UAAmB,MAAiB;CAC3E,OAAO;EACL,MAAM;EACN,OAAO;EACP,OAAO;EACA;EACE;EACT,MAAM;CACR;AACF;;;;;;;;;;;;ACbA,SAAgB,QACd,IACwC;CACxC,IAAI;EACF,MAAM,SAAS,GAAG;EAElB,IAAI,kBAAkB,SACpB,OAAO,OACJ,MACE,WAA0B;GACzB,MAAM;GACN;GACA,OAAO;GACP,OAAO;EACT,EACF,CAAC,CACA,OACE,WAA0B;GACzB,MAAM;GACN,OAAO;GACP,OAAO;GACP;EACF,EACF;EAGJ,OAAO;GAAE,MAAM;GAAM,OAAO;GAAQ,OAAO;GAAO,OAAO;EAAK;CAChE,SAAS,OAAO;EACd,OAAO;GAAE,MAAM;GAAO,OAAO;GAAM,OAAO;GAAM;EAAM;CACxD;AACF;;;ACrCA,eAAe,YACb,QACA,MACA,WACA,SAC0B;CAC1B,MAAM,EACJ,UAAU,OAAO,WAAW,KAC5B,SACA,QACA,GAAG,iBACD;CACJ,IACE,CAAC,OAAO,cAAc,OAAO,KAC7B,UAAU,KACV,UAAU,YAEV,OAAO,UACL,0EACF;CAEF,MAAM,aAAa,IAAI,gBAAgB;CACvC,MAAM,cAAc,WAAW,MAAM,QAAQ,MAAM;CACnD,IAAI,QAAQ,SACV,MAAM;MAEN,QAAQ,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;CAEzD,IAAI,WAAW;CACf,MAAM,YAAY,iBAAiB;EACjC,WAAW;EACX,WAAW,MAAM;CACnB,GAAG,OAAO;CAEV,IAAI;EACF,MAAM,gBAAgB,MAAM,QAAQ,YAAY;GAC9C,MAAM,gBAAgB,IAAI,QAAQ,OAAO,OAAO;GAChD,IAAI,QAAQ,OAAO,CAAC,CAAC,SAAS,OAAO,QAAQ;IAC3C,cAAc,IAAI,KAAK,KAAK;GAC9B,CAAC;GACD,IAAI,WACF,cAAc,OAAO,cAAc;QAEnC,cAAc,IAAI,gBAAgB,kBAAkB;GAatD,MAAM,OAAgB,OAAM,MAXL,MACrB,GAAG,OAAO,QAAQ,QAAQ,QAAQ,EAAE,EAAE,YACtC;IACE,GAAG;IACH,QAAQ;IACR,SAAS;IACT,aAAa,aAAa,eAAe,OAAO;IAChD,MAAM,KAAK;IACX,QAAQ,WAAW;GACrB,CACF,EAAA,CACqC,KAAK;GAC1C,IACE,SAAS,QACT,OAAO,SAAS,YAChB,EAAE,YAAY,SACd,OAAO,KAAK,WAAW,aACvB,EAAE,aAAa,SACf,OAAO,KAAK,YAAY,YACxB,EAAE,UAAU,OAEZ,MAAM,IAAI,MAAM,+BAA+B;GAEjD,OAAO;EACT,CAAC;EACD,IAAI,cAAc,OAAO;GACvB,IAAI,UACF,OAAO,UAAU,mBAAmB;GAEtC,IAAI,QAAQ,SACV,OAAO,UAAU,mBAAmB;GAEtC,OAAO,aAAa,cAAc,KAAK;EACzC;EACA,MAAM,SAAS,cAAc;EAC7B,IAAI,CAAC,OAAO,QACV,OAAO,UAAU,OAAO,SAAS,OAAO,QAAQ,IAAI;EAEtD,OAAO,SAAS,OAAO,MAAM,OAAO,OAAO;CAC7C,UAAU;EACR,aAAa,SAAS;EACtB,QAAQ,oBAAoB,SAAS,KAAK;CAC5C;AACF;;AAGA,SAAgB,gBACd,QACA,QACA,SACA,QACA,SACA,UAAwB,CAAC,GACC;CAC1B,OAAO,YACL,cAEE,KAAK,UAAU;EACL;EACC;EACD;EACR,SAAS,WAAW,CAAC;CACvB,CAAC,GACH,OACA,OACF;AACF;;AAGA,SAAgB,kBACd,QACA,SACA,QACA,OACA,QACA,UAAwB,CAAC,GACC;CAC1B,OAAO,YACL,cACM,cAAc,SAAS,QAAQ,OAAO,MAAM,GAClD,MACA,OACF;AACF;;;;;AAMA,SAAgB,cACd,SACA,QACA,OACA,QACU;CACV,MAAM,WAAW,IAAI,SAAS;CAG9B,SAAS,OAAO,UAAU,SAAS;CACnC,SAAS,OAAO,WAAW,OAAO;CAClC,SAAS,OAAO,UAAU,MAAM;CAGhC,IAAI,QACF,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,MAAM,GAC9C,SAAS,OAAO,KAAK,KAAK;CAK9B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,IAAI,MAAM,QAAQ,KAAK,GACrB,KAAK,MAAM,QAAQ,OACjB,SAAS,OAAO,KAAK,IAAI;MAG3B,SAAS,OAAO,KAAK,KAAK;CAI9B,OAAO;AACT;;AAGA,SAAS,aAAa,OAAqC;CACzD,OAAO,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AACzE;;;;;;;;;;;;;;;;;;;;;AC1JA,SAAgB,iBAEd,QAAiD;CACjD,OAAO;;EAEL,QAAQ,OAIN,WAMG;GACH,MAAM,EAAE,SAAS,QAAQ,SAAS,iBAAiB;GASnD,OAAO,MARc,gBACnB,QACA,WACA,SACA,QACA,SACA,YACF;EAEF;;EAGA,SAAS,OAAO,WAAW;GACzB,MAAM,EAAE,SAAS,QAAQ,iBAAiB;GAC1C,OAAO,MAAM,gBACX,QACA,WACA,SACA,QACA,CAAC,GACD,YACF;EACF;;EAGA,QAAQ,OAAO,WAAW;GACxB,MAAM,EAAE,SAAS,QAAQ,iBAAiB;GAC1C,OAAO,MAAM,gBACX,QACA,UACA,SACA,QACA,CAAC,GACD,YACF;EACF;;EAGA,QAAQ,OAAO,WAAyB;GACtC,MAAM,EAAE,SAAS,QAAQ,OAAO,QAAQ,iBAAiB;GACzD,OAAO,MAAM,kBACX,QACA,SACA,QACA,OACA,QACA,YACF;EACF;CACF;AACF;;;ACnEA,SAAgB,uBAGd,QAAmE;CACnE,MAAM,UAAU,OAAO,WAAW;CAClC,IAAI,CAAC,OAAO,cAAc,OAAO,KAAK,UAAU,GAC9C,MAAM,IAAI,MAAM,iCAAiC;CAEnD,IAAI;CACJ,IAAI;CACJ,IAAI,SAAS;CACb,MAAM,4BAAY,IAAI,IAAc;CACpC,MAAM,0BAAU,IAAI,IAAgB;CACpC,MAAM,QAAQ,UAAkB,UAAU,KAAK;CAC/C,MAAM,kBAAkB,OAAmB;EACzC,QAAQ,QAAQ,CAAC,CACd,KAAK,EAAE,CAAC,CACR,YAAY,KAAA,CAAS;CAC1B;CACA,MAAM,UAAU,OACd,OACA,UAC6B;EAC7B,MAAM,YAAY,MAAM,QAAQ;EAChC,IAAI,UAAU,OACZ,OAAO,KAAK,UAAU,KAAK;EAE7B,MAAM,UAAU,UAAU;EAC1B,IAAI,CAAC,QAAQ,aAAa,QACxB,OAAO,KAAK,qBAAqB;EAEnC,OAAO,IAAI,SAAS,YAAY;GAC9B,IAAI,UAAU;GACd,MAAM,UAAU,WAA4B;IAC1C,IAAI,SACF;IAEF,UAAU;IACV,QAAQ,OAAO,MAAM;IACrB,aAAa,KAAK;IAClB,QAAQ,MAAM;GAChB;GACA,MAAM,eAAe,OAAO,KAAK,qBAAqB,CAAC;GACvD,MAAM,QAAQ,iBACN,OAAO,KAAK,kCAAkC,CAAC,GACrD,OACF;GACA,QAAQ,IAAI,MAAM;GAElB,QAAQ,KAAK,OAAO,QAAQ,WAAuB;IACjD,IACE,CAAC,UACD,OAAO,WAAW,YAClB,EAAE,WAAW,WACb,EAAE,UAAU,SACZ;KACA,OAAO,KAAK,yBAAyB,CAAC;KACtC;IACF;IACA,IAAI,OAAO,OAAO,UAAU,UAAU;KACpC,OAAO,UAAU,OAAO,OAAO,OAAO,IAAI,CAAC;KAC3C;IACF;IAEA,OAAO,SAAS,OAAO,IAAS,CAAC;GACnC,CAAC;EACH,CAAC;CACH;CACA,MAAM,SAAS,YAAY;EACzB,KAAK,MAAM,YAAY,WAAW;GAChC,IAAI,CAAC,SAAS,QACZ;GAEF,MAAM,SAAS,MAAM,QAA+B,gBAAgB;IAClE,OAAO,SAAS;IAChB,OAAO,SAAS;GAClB,CAAC;GACD,IAAI,OAAO,MAAM;IACf,SAAS,kBAAkB,OAAO,OAAO;IACzC;GACF;GACA,MAAM,UAAU,OAAO;GACvB,qBACE,OAAO,sBAAsB;IAC3B,OAAO,SAAS;IAChB,OAAO;GACT,CAAC,CACH;EACF;CACF;CACA,MAAM,gBAA+C;EACnD,IAAI,QACF,OAAO,QAAQ,QAAQ,KAAK,yBAAyB,CAAC;EAExD,IAAI,QAAQ,WACV,OAAO,QAAQ,QAAQ,SAAS,MAAM,CAAC;EAEzC,IAAI,YACF,OAAO;EAET,aAAa,OAAO,mBAAmB,CACpC,MACE,EAAE,SACD,IAAI,SAA+B,YAAY;GAC7C,IAAI,QAAQ;IACV,QAAQ,KAAK,yBAAyB,CAAC;IACvC;GACF;GACA,MAAM,UACJ,UACA,GAAG,OAAO,SAAS;IACjB,MAAM,OAAO,QAAQ;IACrB,aAAa;IACb,iBAAiB;IACjB;IACA,OAAO,SAAS;KACd,QAAQ,QAAQ,CAAC,CACd,WACC,OAAO,OAAO,SAAS,aACnB,OAAO,KAAK,IACX,OAAO,QAAQ,CAAC,CACvB,CAAC,CACA,KAAK,IAAI,CAAC,CACV,YAAY,KAAK,CAAC,CAAC,CAAC;IACzB;GACF,CAAC;GACH,IAAI,CAAC,QAAQ;IACX,SAAS;IACT,QAAQ,GAAG,oBAAoB;KAC7B,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAC9B,OAAO;IAEX,CAAC;IACD,QAAQ,GAAG,iBAAiB;KAC1B,OAAO;IACT,CAAC;IACD,QAAQ,GAAG,iBAAiB,YAC1B,gBAAgB,SAAS,SAAS,CACpC;GACF;GACA,IAAI,UAAU;GACd,MAAM,UAAU,WAAiC;IAC/C,IAAI,SACF;IAEF,UAAU;IACV,aAAa,KAAK;IAClB,QAAQ,IAAI,WAAW,KAAK;IAC5B,QAAQ,IAAI,iBAAiB,MAAM;IACnC,QAAQ,OAAO,MAAM;IACrB,QAAQ,MAAM;GAChB;GACA,MAAM,cAAc,OAAO,SAAS,OAAO,CAAC;GAC5C,MAAM,eAAe,OAAO,KAAK,0BAA0B,CAAC;GAC5D,MAAM,eAAe,OAAO,KAAK,sBAAsB,CAAC;GACxD,MAAM,QAAQ,iBACN,OAAO,KAAK,6BAA6B,CAAC,GAChD,OACF;GACA,QAAQ,IAAI,MAAM;GAClB,QAAQ,KAAK,WAAW,KAAK;GAC7B,QAAQ,KAAK,iBAAiB,MAAM;GACpC,QAAQ,QAAQ;EAClB,CAAC,CACL,CAAC,CACA,YAAY,KAAK,oCAAoC,CAAC,CAAC,CACvD,cAAc;GACb,aAAa,KAAA;EACf,CAAC;EACH,OAAO;CACT;CACA,OAAO;EACL,SAAS,UAAU,QAAQ,eAAe,KAAK;EAC/C,OAAO,UAAU,QAAQ,aAAa,KAAK;EAC3C,MAAM,QAAQ,OAAO;GACnB,MAAM,WAAqB;IACzB,GAAG;IACH,OAAO,MAAM;IACb,WAAW,MAAM;IACjB,QAAQ;GACV;GACA,UAAU,IAAI,QAAQ;GACtB,MAAM,SAAS,MAAM,QACnB,gBACA;IAAE,OAAO,MAAM;IAAO,OAAO,MAAM;GAAM,CAC3C;GACA,IAAI,OAAO,OAAO;IAChB,UAAU,OAAO,QAAQ;IACzB,OAAO,KAAK,OAAO,KAAK;GAC1B;GACA,SAAS,kBAAkB,OAAO,OAAO;GACzC,OAAO,SAAS,EACd,mBAAmB;IACf,SAAS,SAAS;IAClB,UAAU,OAAO,QAAQ;IACzB,MAAM,SAAS,CAAC,GAAG,SAAS,CAAC,CAAC,MAC3B,SACC,KAAK,UAAU,SAAS,SACxB,YAAY,KAAK,KAAK,MAAM,YAAY,SAAS,KAAK,CAC1D;IACF,IAAI,UAAU,QACZ,OAAO,QAAQ,QAAQ,SAAS,EAAE,YAAY,OAAO,CAAC,CAAC;IAEzD,OAAO,QAAQ,oBAAoB;KACjC,OAAO,SAAS;KAChB,OAAO,SAAS;IAClB,CAAC;GACH,EACF,CAAC;EACH;EACA,QAAQ;GACN,SAAS;GACT,UAAU,MAAM;GAChB,KAAK,MAAM,UAAU,CAAC,GAAG,OAAO,GAC9B,OAAO;GAET,QAAQ,WAAW;GACnB,QAAQ,mBAAmB;EAC7B;CACF;AACF;;AAGA,SAAS,YAAY,OAA0B;CAC7C,IAAI,UAAU,KAAA,KAAa,UAAU,MACnC,OAAO;CAET,IAAI,MAAM,QAAQ,KAAK,GACrB,OAAO,IAAI,MAAM,IAAI,WAAW,CAAC,CAAC,KAAK,GAAG,EAAE;CAE9C,IAAI,OAAO,UAAU,UACnB,OAAO,IAAI,OAAO,KAAK,KAAK,CAAC,CAC1B,KAAK,CAAC,CACN,KACE,QACC,GAAG,KAAK,UAAU,GAAG,EAAE,GAAG,YAAa,MAAoC,IAAI,GACnF,CAAC,CACA,KAAK,GAAG,EAAE;CAEf,OAAO,KAAK,UAAU,KAAK;AAC7B;;AAGA,SAAS,gBAAgB,SAAoB,WAA0B;CACrE,IAAI,CAAC,WAAW,OAAO,YAAY,YAAY,EAAE,WAAW,UAC1D;CAEF,MAAM,QAAQ,YACZ,WAAW,UAAW,QAAQ,QAAsB,KAAA,CACtD;CACA,KAAK,MAAM,YAAY,WAAW;EAChC,IAAI,CAAC,SAAS,UAAU,SAAS,UAAU,QAAQ,OACjD;EAEF,IAAI,YAAY,SAAS,mBAAmB,SAAS,KAAK,MAAM,OAC9D;EAEF,QAAQ,QAAQ,CAAC,CACd,WAAW,SAAS,UAAU,OAAO,CAAC,CAAC,CACvC,YAAY,KAAA,CAAS;CAC1B;AACF"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../src/result.ts","../src/safe-try.ts","../src/request.ts","../src/socket-client.ts","../src/create-client.ts","../src/deprecated.ts"],"sourcesContent":["import type { ClientErr, ClientOk } from \"./types.js\";\n\n/**\n * A successful client result. `data` mirrors `value` so code written for\n * earlier clients keeps working. `message` is present only when the server sent one.\n */\nexport function clientOk<T>(value: T, message?: string): ClientOk<T> {\n return {\n isOk: true,\n isErr: false,\n value: value,\n error: null,\n ...(message === undefined ? {} : { message: message }),\n data: value,\n };\n}\n\n/**\n * A failed client result with a readable message and any data the server\n * attached to the failure. `data` stays null, as it was for earlier clients.\n */\nexport function clientErr(error: string, details: unknown = null): ClientErr {\n return {\n isOk: false,\n isErr: true,\n value: null,\n error: error,\n details: details,\n data: null,\n };\n}\n","/**\n * Internal result type for safeTry\n */\nexport type SafeResult<T, E = unknown> =\n | { isOk: true; value: T; isErr: false; error: null }\n | { isOk: false; value: null; isErr: true; error: E };\n\n/**\n * Gracefully handles both synchronous and asynchronous operations by returning a result object.\n * This replaces the need for external slang-ts dependency and avoids try/catch boilerplate.\n *\n * @param fn - The function to execute (sync or async)\n * @returns A result object containing either the value or the error\n *\n * @example\n * const { isOk, value, error } = await safeTry(() => fetch(url));\n */\nexport function safeTry<T>(\n fn: () => T | Promise<T>\n): Promise<SafeResult<T>> | SafeResult<T> {\n try {\n const result = fn();\n\n if (result instanceof Promise) {\n return result\n .then(\n (value): SafeResult<T> => ({\n isOk: true,\n value,\n isErr: false,\n error: null,\n })\n )\n .catch(\n (error): SafeResult<T> => ({\n isOk: false,\n value: null,\n isErr: true,\n error,\n })\n );\n }\n\n return { isOk: true, value: result, isErr: false, error: null };\n } catch (error) {\n return { isOk: false, value: null, isErr: true, error };\n }\n}\n","import { clientErr, clientOk } from \"./result.js\";\nimport { safeTry } from \"./safe-try.js\";\nimport type {\n ClientResult,\n ExternalResponse,\n FetchOptions,\n NileClientConfig,\n} from \"./types.js\";\n\n/** Send one action call; the deadline covers both fetch and reading its JSON body. */\nasync function sendRequest<T>(\n config: NileClientConfig,\n body: () => BodyInit,\n multipart: boolean,\n options: FetchOptions\n): Promise<ClientResult<T>> {\n const {\n timeout = config.timeout ?? 30_000,\n headers,\n signal,\n ...fetchOptions\n } = options;\n if (\n !Number.isSafeInteger(timeout) ||\n timeout < 1 ||\n timeout > 2_147_483_647\n ) {\n return clientErr(\n \"Action timeout must be a positive integer up to 2147483647 milliseconds.\"\n );\n }\n const controller = new AbortController();\n const abort = () => controller.abort(signal?.reason);\n if (signal?.aborted) {\n abort();\n } else {\n signal?.addEventListener(\"abort\", abort, { once: true });\n }\n let timedOut = false;\n const timeoutId = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, timeout);\n\n try {\n const requestResult = await safeTry(async () => {\n const mergedHeaders = new Headers(config.headers);\n new Headers(headers).forEach((value, key) => {\n mergedHeaders.set(key, value);\n });\n if (multipart) {\n mergedHeaders.delete(\"content-type\");\n } else {\n mergedHeaders.set(\"content-type\", \"application/json\");\n }\n const response = await fetch(\n `${config.baseUrl.replace(/\\/+$/, \"\")}/services`,\n {\n ...fetchOptions,\n method: \"POST\",\n headers: mergedHeaders,\n credentials: fetchOptions.credentials ?? config.credentials,\n body: body(),\n signal: controller.signal,\n }\n );\n const json: unknown = await response.json();\n if (\n json === null ||\n typeof json !== \"object\" ||\n !(\"status\" in json) ||\n typeof json.status !== \"boolean\" ||\n !(\"message\" in json) ||\n typeof json.message !== \"string\" ||\n !(\"data\" in json)\n ) {\n throw new Error(\"Invalid Nile action response.\");\n }\n return json as ExternalResponse<T>;\n });\n if (requestResult.isErr) {\n if (timedOut) {\n return clientErr(\"Action timed out.\");\n }\n if (signal?.aborted) {\n return clientErr(\"Action cancelled.\");\n }\n return resolveError(requestResult.error);\n }\n const result = requestResult.value;\n if (!result.status) {\n return clientErr(result.message, result.data ?? null);\n }\n return clientOk(result.data, result.message);\n } finally {\n clearTimeout(timeoutId);\n signal?.removeEventListener(\"abort\", abort);\n }\n}\n\n/** JSON action calls preserve the server's message and failure data unchanged. */\nexport function sendNileRequest<T = Record<string, unknown>>(\n config: NileClientConfig,\n intent: \"explore\" | \"execute\" | \"schema\",\n service: string,\n action: string,\n payload: unknown,\n options: FetchOptions = {}\n): Promise<ClientResult<T>> {\n return sendRequest<T>(\n config,\n () =>\n JSON.stringify({\n intent: intent,\n service: service,\n action: action,\n payload: payload ?? {},\n }),\n false,\n options\n );\n}\n\n/** Let the runtime set the multipart boundary; retain the same action Result contract. */\nexport function sendUploadRequest<T = Record<string, unknown>>(\n config: NileClientConfig,\n service: string,\n action: string,\n files: Record<string, File | File[]>,\n fields?: Record<string, string>,\n options: FetchOptions = {}\n): Promise<ClientResult<T>> {\n return sendRequest<T>(\n config,\n () => buildFormData(service, action, files, fields),\n true,\n options\n );\n}\n\n/**\n * Builds a FormData instance with RPC routing fields and file/field entries.\n * The server expects 'intent', 'service', 'action' as string fields.\n */\nexport function buildFormData(\n service: string,\n action: string,\n files: Record<string, File | File[]>,\n fields?: Record<string, string>\n): FormData {\n const formData = new FormData();\n\n // RPC routing fields the server expects\n formData.append(\"intent\", \"execute\");\n formData.append(\"service\", service);\n formData.append(\"action\", action);\n\n // User-provided string fields\n if (fields) {\n for (const [key, value] of Object.entries(fields)) {\n formData.append(key, value);\n }\n }\n\n // File attachments — arrays append multiple entries under the same key\n for (const [key, value] of Object.entries(files)) {\n if (Array.isArray(value)) {\n for (const file of value) {\n formData.append(key, file);\n }\n } else {\n formData.append(key, value);\n }\n }\n\n return formData;\n}\n\n/** Convert local transport errors to the same client failure shape. */\nfunction resolveError(error: unknown): ClientResult<never> {\n return clientErr(error instanceof Error ? error.message : String(error));\n}\n","import type { Socket } from \"socket.io-client\";\nimport { clientErr, clientOk } from \"./result.js\";\nimport type {\n NileSocketClient,\n NileSocketConfig,\n SocketTopics,\n TopicShape,\n} from \"./socket-types.js\";\nimport type { ClientResult } from \"./types.js\";\n\ntype WireValue = object | string | number | boolean | null | undefined;\n/** Acknowledgements keep the server's `{ error, data }` wire shape; the client turns them into Results. */\ninterface WireResult {\n error: string | null;\n data: unknown;\n}\ninterface Listener {\n topic: string;\n scope?: WireValue;\n onMessage: (message: WireValue) => void;\n active: boolean;\n normalizedScope?: WireValue;\n}\n\n/** The socket connects to an origin; any path in a URL would be read by Socket.IO as a namespace. */\nexport function socketOrigin(url: string): string | undefined {\n try {\n return new URL(url).origin;\n } catch {\n // A relative URL such as \"/api\" means the page's own origin.\n return undefined;\n }\n}\n\n/** Own a lazy Socket.IO connection with no offline write buffering. */\nexport function createNileSocket<\n Topics extends TopicShape<Topics> = SocketTopics,\n>(config: NileSocketConfig): NileSocketClient<Topics> {\n const timeout = config.timeout ?? 30_000;\n if (!Number.isSafeInteger(timeout) || timeout < 1) {\n throw new Error(\"Socket timeout must be positive\");\n }\n let socket: Socket | undefined;\n let connecting: Promise<ClientResult<Socket>> | undefined;\n let closed = false;\n let everConnected = false;\n const listeners = new Set<Listener>();\n const pending = new Set<() => void>();\n const fail = (error: string) => clientErr(error);\n const settleCallback = (fn: () => void) => {\n Promise.resolve()\n .then(fn)\n .catch(() => undefined);\n };\n const request = async <T>(\n event: string,\n input: WireValue\n ): Promise<ClientResult<T>> => {\n const connected = await connect();\n if (connected.isErr) {\n return fail(connected.error);\n }\n const current = connected.value;\n if (!current.connected || closed) {\n return fail(\"Socket disconnected\");\n }\n return new Promise((resolve) => {\n let settled = false;\n const finish = (result: ClientResult<T>) => {\n if (settled) {\n return;\n }\n settled = true;\n pending.delete(cancel);\n clearTimeout(timer);\n resolve(result);\n };\n const cancel = () => finish(fail(\"Socket disconnected\"));\n const timer = setTimeout(\n () => finish(fail(\"Socket acknowledgement timed out\")),\n timeout\n );\n pending.add(cancel);\n // The connection check and emit are synchronous; disconnected calls never enter the offline queue.\n current.emit(event, input, (result: WireResult) => {\n if (\n !result ||\n typeof result !== \"object\" ||\n !(\"error\" in result) ||\n !(\"data\" in result)\n ) {\n finish(fail(\"Invalid socket response\"));\n return;\n }\n if (typeof result.error === \"string\") {\n finish(clientErr(result.error, result.data));\n return;\n }\n // The server validated this acknowledgement for the requested event.\n finish(clientOk(result.data as T));\n });\n });\n };\n const rejoin = async () => {\n for (const listener of listeners) {\n if (!listener.active) {\n continue;\n }\n const result = await request<{ scope?: WireValue }>(\"nile:receive\", {\n topic: listener.topic,\n scope: listener.scope,\n });\n if (result.isOk) {\n listener.normalizedScope = result.value?.scope;\n continue;\n }\n const message = result.error;\n settleCallback(() =>\n config.onError?.({ topic: listener.topic, error: message })\n );\n }\n };\n const connect = (): Promise<ClientResult<Socket>> => {\n if (closed) {\n return Promise.resolve(fail(\"Socket client is closed\"));\n }\n if (socket?.connected) {\n return Promise.resolve(clientOk(socket));\n }\n if (connecting) {\n return connecting;\n }\n connecting = import(\"socket.io-client\")\n .then(\n ({ io }) =>\n new Promise<ClientResult<Socket>>((resolve) => {\n if (closed) {\n resolve(fail(\"Socket client is closed\"));\n return;\n }\n const current =\n socket ??\n io(config.url ? socketOrigin(config.url) : undefined, {\n path: config.path ?? \"/socket.io\",\n autoConnect: false,\n withCredentials: true,\n timeout,\n auth: (done) => {\n Promise.resolve()\n .then(() =>\n typeof config.auth === \"function\"\n ? config.auth()\n : (config.auth ?? {})\n )\n .then(done)\n .catch(() => done({}));\n },\n });\n if (!socket) {\n socket = current;\n current.on(\"disconnect\", (reason: string) => {\n for (const cancel of [...pending]) {\n cancel();\n }\n settleCallback(() => config.onDisconnect?.(reason));\n });\n current.on(\"connect\", () => {\n if (!everConnected) {\n everConnected = true;\n settleCallback(() => config.onConnect?.());\n return;\n }\n rejoin().then(() =>\n settleCallback(() => config.onReconnect?.())\n );\n });\n current.on(\"connect_error\", () => {\n settleCallback(() =>\n config.onError?.({ error: \"Socket connection failed\" })\n );\n });\n current.on(\"nile:message\", (message: WireValue) =>\n dispatchMessage(message, listeners)\n );\n }\n let settled = false;\n const finish = (result: ClientResult<Socket>) => {\n if (settled) {\n return;\n }\n settled = true;\n clearTimeout(timer);\n current.off(\"connect\", ready);\n current.off(\"connect_error\", failed);\n pending.delete(cancel);\n resolve(result);\n };\n const ready = () => finish(clientOk(current));\n const failed = () => finish(fail(\"Socket connection failed\"));\n const cancel = () => finish(fail(\"Socket client closed\"));\n const timer = setTimeout(\n () => finish(fail(\"Socket connection timed out\")),\n timeout\n );\n pending.add(cancel);\n current.once(\"connect\", ready);\n current.once(\"connect_error\", failed);\n current.connect();\n })\n )\n .catch(() => fail(\"Could not initialize socket client\"))\n .finally(() => {\n connecting = undefined;\n });\n return connecting;\n };\n return {\n send: (input) => request(\"nile:send\", input),\n async receive(input) {\n const listener: Listener = {\n ...input,\n scope: input.scope as WireValue,\n onMessage: input.onMessage as Listener[\"onMessage\"],\n active: true,\n };\n listeners.add(listener);\n const result = await request<{ subscribed: boolean; scope?: WireValue }>(\n \"nile:receive\",\n { topic: input.topic, scope: input.scope }\n );\n if (result.isErr) {\n listeners.delete(listener);\n return fail(result.error);\n }\n listener.normalizedScope = result.value?.scope;\n return clientOk({\n topic: input.topic,\n unsubscribe: () => {\n listener.active = false;\n listeners.delete(listener);\n const shared = [...listeners].some(\n (item) =>\n item.topic === listener.topic &&\n stableScope(item.scope) === stableScope(listener.scope)\n );\n if (shared || closed) {\n return Promise.resolve(clientOk({ subscribed: shared }));\n }\n return request(\"nile:unsubscribe\", {\n topic: listener.topic,\n scope: listener.scope,\n });\n },\n });\n },\n close() {\n closed = true;\n listeners.clear();\n for (const cancel of [...pending]) {\n cancel();\n }\n socket?.disconnect();\n socket?.removeAllListeners();\n },\n };\n}\n\n/** Match scoped messages independently of object property insertion order. */\nfunction stableScope(scope: WireValue): string {\n if (scope === undefined || scope === null) {\n return \"null\";\n }\n if (Array.isArray(scope)) {\n return `[${scope.map(stableScope).join(\",\")}]`;\n }\n if (typeof scope === \"object\") {\n return `{${Object.keys(scope)\n .sort()\n .map(\n (key) =>\n `${JSON.stringify(key)}:${stableScope((scope as Record<string, WireValue>)[key])}`\n )\n .join(\",\")}}`;\n }\n return JSON.stringify(scope);\n}\n\n/** Deliver messages only to listeners for the same validated topic and scope. */\nfunction dispatchMessage(message: WireValue, listeners: Set<Listener>) {\n if (!message || typeof message !== \"object\" || !(\"topic\" in message)) {\n return;\n }\n const scope = stableScope(\n \"scope\" in message ? (message.scope as WireValue) : undefined\n );\n for (const listener of listeners) {\n if (!listener.active || listener.topic !== message.topic) {\n continue;\n }\n if (stableScope(listener.normalizedScope ?? listener.scope) !== scope) {\n continue;\n }\n Promise.resolve()\n .then(() => listener.onMessage(message))\n .catch(() => undefined);\n }\n}\n","import { sendNileRequest, sendUploadRequest } from \"./request.js\";\nimport { createNileSocket } from \"./socket-client.js\";\nimport type { SocketTopics, TopicShape } from \"./socket-types.js\";\nimport type { NileClient, NileClientConfig, UploadParams } from \"./types.js\";\n\n/**\n * Creates a type-safe Nile client for interacting with backend services.\n *\n * @param config - The client configuration including baseUrl\n * @returns A factory object with invoke, explore, schema and upload methods, plus\n * `socket` for topics. The socket connects on its first `send` or `receive`.\n *\n * @example\n * const nile = createNileClient<ServicePayloads>({ baseUrl: \"/api\" });\n * const result = await nile.invoke({\n * service: \"tasks\",\n * action: \"create\",\n * payload: { title: \"Buy milk\" }\n * });\n * if (result.isErr) {\n * console.error(result.error);\n * } else {\n * console.log(result.value);\n * }\n *\n * const received = await nile.socket.receive({\n * topic: \"tasks.updated\",\n * onMessage: (message) => console.log(message.data),\n * });\n */\nexport function createNileClient<\n TPayloads = Record<string, Record<string, unknown>>,\n TTopics extends TopicShape<TTopics> = SocketTopics,\n>(config: NileClientConfig): NileClient<TPayloads, TTopics> {\n return {\n socket: createNileSocket<TTopics>({\n ...config.socket,\n url: config.socket?.url ?? config.baseUrl,\n }),\n\n /** Invoke a service action through the backend engine pipeline */\n invoke: async <\n S extends keyof TPayloads & string,\n A extends keyof TPayloads[S] & string,\n >(params: {\n service: S;\n action: A;\n payload: TPayloads[S][A];\n fetchOptions?: Parameters<typeof sendNileRequest>[5];\n }) => {\n const { service, action, payload, fetchOptions } = params;\n const result = await sendNileRequest<Record<string, unknown>>(\n config,\n \"execute\",\n service,\n action,\n payload,\n fetchOptions\n );\n return result;\n },\n\n /** Discover available services and actions (supports \"*\" wildcard) */\n explore: async (params) => {\n const { service, action, fetchOptions } = params;\n return await sendNileRequest(\n config,\n \"explore\",\n service,\n action,\n {},\n fetchOptions\n );\n },\n\n /** Get action schemas as JSON Schema (supports \"*\" wildcard) */\n schema: async (params) => {\n const { service, action, fetchOptions } = params;\n return await sendNileRequest(\n config,\n \"schema\",\n service,\n action,\n {},\n fetchOptions\n );\n },\n\n /** Upload files to an action via multipart form-data */\n upload: async (params: UploadParams) => {\n const { service, action, files, fields, fetchOptions } = params;\n return await sendUploadRequest(\n config,\n service,\n action,\n files,\n fields,\n fetchOptions\n );\n },\n };\n}\n","const MIGRATION_MESSAGE = [\n \"createNileSocketClient was removed in @nilejs/client 1.1.0.\",\n \"Create one client with createNileClient({ baseUrl, socket: { auth } })\",\n \"and use nile.socket.send, nile.socket.receive and nile.socket.close.\",\n \"Socket invoke is gone as well; call actions with nile.invoke over HTTP.\",\n \"See https://nile-js.github.io/nile/guide/features/websockets/ and the\",\n \"migration notes in packages/nile/docs/release-migration.md.\",\n].join(\" \");\n\n/**\n * Kept as a throwing stub so an upgrade fails with guidance instead of a\n * missing export.\n *\n * @deprecated Use `createNileClient({ baseUrl, socket: { auth } })` and call\n * `socket.send`, `socket.receive` and `socket.close` on the returned client.\n */\nexport function createNileSocketClient<Actions = unknown, Topics = unknown>(\n _config?: unknown\n): never {\n throw new Error(MIGRATION_MESSAGE);\n}\n"],"mappings":"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"}
|