@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/dist/index.d.cts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
1
2
|
/** Standard Nile API response shape */
|
|
2
3
|
interface ExternalResponse<T = Record<string, unknown>> {
|
|
3
4
|
status: boolean;
|
|
@@ -58,7 +59,6 @@ interface ExploreActionsResponse {
|
|
|
58
59
|
visibility?: {
|
|
59
60
|
rest?: boolean;
|
|
60
61
|
rpc?: boolean;
|
|
61
|
-
ws?: boolean;
|
|
62
62
|
};
|
|
63
63
|
}>;
|
|
64
64
|
}
|
|
@@ -75,6 +75,8 @@ interface NileClientConfig {
|
|
|
75
75
|
headers?: Record<string, string>;
|
|
76
76
|
/** Optional timeout in ms (default: 30000) */
|
|
77
77
|
timeout?: number;
|
|
78
|
+
/** Socket settings for `client.socket`. The socket connects on first use. */
|
|
79
|
+
socket?: NileSocketConfig;
|
|
78
80
|
}
|
|
79
81
|
/** Options for individual fetch calls (body and method are managed internally) */
|
|
80
82
|
interface FetchOptions extends Omit<RequestInit, "body" | "method"> {
|
|
@@ -97,7 +99,9 @@ interface UploadParams {
|
|
|
97
99
|
fetchOptions?: FetchOptions;
|
|
98
100
|
}
|
|
99
101
|
/** Interface for the typed client */
|
|
100
|
-
interface NileClient<TPayloads = Record<string, Record<string, unknown
|
|
102
|
+
interface NileClient<TPayloads = Record<string, Record<string, unknown>>, TTopics extends TopicShape<TTopics> = SocketTopics> {
|
|
103
|
+
/** Typed topics over Socket.IO: `send`, `receive` and `close`. */
|
|
104
|
+
socket: NileSocketClient<TTopics>;
|
|
101
105
|
/** Invoke an action with full type-safety for payload */
|
|
102
106
|
invoke: <S extends keyof TPayloads & string, A extends keyof TPayloads[S] & string>(params: {
|
|
103
107
|
service: S;
|
|
@@ -112,42 +116,16 @@ interface NileClient<TPayloads = Record<string, Record<string, unknown>>> {
|
|
|
112
116
|
/** Upload files to an action via multipart form-data */
|
|
113
117
|
upload: (params: UploadParams) => Promise<ClientResult>;
|
|
114
118
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
* @param config - The client configuration including baseUrl
|
|
119
|
-
* @returns A factory object with invoke, explore, schema, and upload methods
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* const nile = createNileClient<ServicePayloads>({ baseUrl: "/api" });
|
|
123
|
-
* const result = await nile.invoke({
|
|
124
|
-
* service: "tasks",
|
|
125
|
-
* action: "create",
|
|
126
|
-
* payload: { title: "Buy milk" }
|
|
127
|
-
* });
|
|
128
|
-
* if (result.isErr) {
|
|
129
|
-
* console.error(result.error);
|
|
130
|
-
* } else {
|
|
131
|
-
* console.log(result.value);
|
|
132
|
-
* }
|
|
133
|
-
*/
|
|
134
|
-
export declare function createNileClient<TPayloads = Record<string, Record<string, unknown>>>(config: NileClientConfig): NileClient<TPayloads>;
|
|
135
|
-
/** Let the runtime set the multipart boundary; retain the same action Result contract. */
|
|
136
|
-
export declare function sendUploadRequest<T = Record<string, unknown>>(config: NileClientConfig, service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>, options?: FetchOptions): Promise<ClientResult<T>>;
|
|
137
|
-
/**
|
|
138
|
-
* Builds a FormData instance with RPC routing fields and file/field entries.
|
|
139
|
-
* The server expects 'intent', 'service', 'action' as string fields.
|
|
140
|
-
*/
|
|
141
|
-
export declare function buildFormData(service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>): FormData;
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/socket-types.d.ts
|
|
121
|
+
type WireJson = object | string | number | boolean | null;
|
|
142
122
|
interface TopicContract {
|
|
143
|
-
data:
|
|
144
|
-
input?:
|
|
145
|
-
scope?:
|
|
123
|
+
data: WireJson;
|
|
124
|
+
input?: WireJson;
|
|
125
|
+
scope?: WireJson;
|
|
146
126
|
}
|
|
147
127
|
type TopicShape<T> = { [K in keyof T]: TopicContract; };
|
|
148
|
-
type ActionShape<A> = { [S in keyof A]: { [K in keyof A[S]]: object; }; };
|
|
149
128
|
type SocketTopics = Record<string, TopicContract>;
|
|
150
|
-
type SocketActions = Record<string, Record<string, object>>;
|
|
151
129
|
type SocketSelection<T, K extends keyof T> = {
|
|
152
130
|
topic: K;
|
|
153
131
|
} & (T[K] extends {
|
|
@@ -170,36 +148,97 @@ interface SocketMessage<K extends string, D> {
|
|
|
170
148
|
id: string;
|
|
171
149
|
topic: K;
|
|
172
150
|
data: D;
|
|
173
|
-
scope?:
|
|
151
|
+
scope?: WireJson;
|
|
174
152
|
time: string;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
153
|
+
/** Present when a client sent the message; absent for server messages. */
|
|
154
|
+
from?: {
|
|
155
|
+
connectionId: string;
|
|
156
|
+
userId?: string;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
interface NileSocketConfig {
|
|
160
|
+
/** Socket server origin when it differs from `baseUrl`. Defaults to the origin of `baseUrl`. */
|
|
161
|
+
url?: string;
|
|
162
|
+
/** Socket.IO path. Default `/socket.io`; must match the server. */
|
|
178
163
|
path?: string;
|
|
164
|
+
/** Connection and acknowledgement timeout in ms. Default 30000. */
|
|
179
165
|
timeout?: number;
|
|
166
|
+
/** Sent when connecting, e.g. `{ token }`. A function is called again on every reconnect. */
|
|
180
167
|
auth?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
181
|
-
|
|
182
|
-
|
|
168
|
+
onConnect?: () => void;
|
|
169
|
+
onDisconnect?: (reason: string) => void;
|
|
170
|
+
/** Fires after a reconnect once active subscriptions are restored. */
|
|
171
|
+
onReconnect?: () => void;
|
|
172
|
+
/** A connection failure, or a subscription refused while restoring it after a reconnect. */
|
|
173
|
+
onError?: (error: {
|
|
183
174
|
error: string;
|
|
175
|
+
topic?: string;
|
|
184
176
|
}) => void;
|
|
185
177
|
}
|
|
186
|
-
interface
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
178
|
+
interface SocketSubscription {
|
|
179
|
+
topic: string;
|
|
180
|
+
/** Stop this listener; the server subscription ends when the last listener for it stops. */
|
|
181
|
+
unsubscribe: () => Promise<ClientResult<{
|
|
182
|
+
subscribed: boolean;
|
|
183
|
+
}>>;
|
|
184
|
+
}
|
|
185
|
+
interface NileSocketClient<T extends TopicShape<T> = SocketTopics> {
|
|
186
|
+
/** Send to a topic; the server checks the topic's `canSend` and validates the data. */
|
|
192
187
|
send: <K extends keyof T & string>(input: SocketPublication<T, K>) => Promise<ClientResult<SocketMessage<K, T[K]["data"]>>>;
|
|
188
|
+
/** Subscribe to a topic and listen for its messages in one call. */
|
|
193
189
|
receive: <K extends keyof T & string>(input: SocketSelection<T, K> & {
|
|
194
190
|
onMessage: (message: SocketMessage<K, T[K]["data"]>) => void;
|
|
195
|
-
}) => Promise<ClientResult<
|
|
196
|
-
|
|
197
|
-
subscribed: boolean;
|
|
198
|
-
}>>;
|
|
199
|
-
}>>;
|
|
191
|
+
}) => Promise<ClientResult<SocketSubscription>>;
|
|
192
|
+
/** Disconnect and drop every listener. The client cannot reconnect afterwards. */
|
|
200
193
|
close: () => void;
|
|
201
194
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/create-client.d.ts
|
|
197
|
+
/**
|
|
198
|
+
* Creates a type-safe Nile client for interacting with backend services.
|
|
199
|
+
*
|
|
200
|
+
* @param config - The client configuration including baseUrl
|
|
201
|
+
* @returns A factory object with invoke, explore, schema and upload methods, plus
|
|
202
|
+
* `socket` for topics. The socket connects on its first `send` or `receive`.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* const nile = createNileClient<ServicePayloads>({ baseUrl: "/api" });
|
|
206
|
+
* const result = await nile.invoke({
|
|
207
|
+
* service: "tasks",
|
|
208
|
+
* action: "create",
|
|
209
|
+
* payload: { title: "Buy milk" }
|
|
210
|
+
* });
|
|
211
|
+
* if (result.isErr) {
|
|
212
|
+
* console.error(result.error);
|
|
213
|
+
* } else {
|
|
214
|
+
* console.log(result.value);
|
|
215
|
+
* }
|
|
216
|
+
*
|
|
217
|
+
* const received = await nile.socket.receive({
|
|
218
|
+
* topic: "tasks.updated",
|
|
219
|
+
* onMessage: (message) => console.log(message.data),
|
|
220
|
+
* });
|
|
221
|
+
*/
|
|
222
|
+
export declare function createNileClient<TPayloads = Record<string, Record<string, unknown>>, TTopics extends TopicShape<TTopics> = SocketTopics>(config: NileClientConfig): NileClient<TPayloads, TTopics>;
|
|
223
|
+
//#endregion
|
|
224
|
+
//#region src/deprecated.d.ts
|
|
225
|
+
/**
|
|
226
|
+
* Kept as a throwing stub so an upgrade fails with guidance instead of a
|
|
227
|
+
* missing export.
|
|
228
|
+
*
|
|
229
|
+
* @deprecated Use `createNileClient({ baseUrl, socket: { auth } })` and call
|
|
230
|
+
* `socket.send`, `socket.receive` and `socket.close` on the returned client.
|
|
231
|
+
*/
|
|
232
|
+
export declare function createNileSocketClient<Actions = unknown, Topics = unknown>(_config?: unknown): never;
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/request.d.ts
|
|
235
|
+
/** Let the runtime set the multipart boundary; retain the same action Result contract. */
|
|
236
|
+
export declare function sendUploadRequest<T = Record<string, unknown>>(config: NileClientConfig, service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>, options?: FetchOptions): Promise<ClientResult<T>>;
|
|
237
|
+
/**
|
|
238
|
+
* Builds a FormData instance with RPC routing fields and file/field entries.
|
|
239
|
+
* The server expects 'intent', 'service', 'action' as string fields.
|
|
240
|
+
*/
|
|
241
|
+
export declare function buildFormData(service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>): FormData;
|
|
242
|
+
//#endregion
|
|
243
|
+
export type { ClientErr, ClientOk, ClientResult, ExploreActionsResponse, ExploreServicesResponse, ExternalResponse, FetchOptions, NileClient, NileClientConfig, NileIntentParams, NileSocketClient, NileSocketConfig, SocketMessage, SocketPublication, SocketSelection, SocketSubscription, SocketTopics, TopicContract, UploadParams, ValidationFailureData };
|
|
205
244
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
//#region src/types.d.ts
|
|
1
2
|
/** Standard Nile API response shape */
|
|
2
3
|
interface ExternalResponse<T = Record<string, unknown>> {
|
|
3
4
|
status: boolean;
|
|
@@ -58,7 +59,6 @@ interface ExploreActionsResponse {
|
|
|
58
59
|
visibility?: {
|
|
59
60
|
rest?: boolean;
|
|
60
61
|
rpc?: boolean;
|
|
61
|
-
ws?: boolean;
|
|
62
62
|
};
|
|
63
63
|
}>;
|
|
64
64
|
}
|
|
@@ -75,6 +75,8 @@ interface NileClientConfig {
|
|
|
75
75
|
headers?: Record<string, string>;
|
|
76
76
|
/** Optional timeout in ms (default: 30000) */
|
|
77
77
|
timeout?: number;
|
|
78
|
+
/** Socket settings for `client.socket`. The socket connects on first use. */
|
|
79
|
+
socket?: NileSocketConfig;
|
|
78
80
|
}
|
|
79
81
|
/** Options for individual fetch calls (body and method are managed internally) */
|
|
80
82
|
interface FetchOptions extends Omit<RequestInit, "body" | "method"> {
|
|
@@ -97,7 +99,9 @@ interface UploadParams {
|
|
|
97
99
|
fetchOptions?: FetchOptions;
|
|
98
100
|
}
|
|
99
101
|
/** Interface for the typed client */
|
|
100
|
-
interface NileClient<TPayloads = Record<string, Record<string, unknown
|
|
102
|
+
interface NileClient<TPayloads = Record<string, Record<string, unknown>>, TTopics extends TopicShape<TTopics> = SocketTopics> {
|
|
103
|
+
/** Typed topics over Socket.IO: `send`, `receive` and `close`. */
|
|
104
|
+
socket: NileSocketClient<TTopics>;
|
|
101
105
|
/** Invoke an action with full type-safety for payload */
|
|
102
106
|
invoke: <S extends keyof TPayloads & string, A extends keyof TPayloads[S] & string>(params: {
|
|
103
107
|
service: S;
|
|
@@ -112,42 +116,16 @@ interface NileClient<TPayloads = Record<string, Record<string, unknown>>> {
|
|
|
112
116
|
/** Upload files to an action via multipart form-data */
|
|
113
117
|
upload: (params: UploadParams) => Promise<ClientResult>;
|
|
114
118
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
* @param config - The client configuration including baseUrl
|
|
119
|
-
* @returns A factory object with invoke, explore, schema, and upload methods
|
|
120
|
-
*
|
|
121
|
-
* @example
|
|
122
|
-
* const nile = createNileClient<ServicePayloads>({ baseUrl: "/api" });
|
|
123
|
-
* const result = await nile.invoke({
|
|
124
|
-
* service: "tasks",
|
|
125
|
-
* action: "create",
|
|
126
|
-
* payload: { title: "Buy milk" }
|
|
127
|
-
* });
|
|
128
|
-
* if (result.isErr) {
|
|
129
|
-
* console.error(result.error);
|
|
130
|
-
* } else {
|
|
131
|
-
* console.log(result.value);
|
|
132
|
-
* }
|
|
133
|
-
*/
|
|
134
|
-
export declare function createNileClient<TPayloads = Record<string, Record<string, unknown>>>(config: NileClientConfig): NileClient<TPayloads>;
|
|
135
|
-
/** Let the runtime set the multipart boundary; retain the same action Result contract. */
|
|
136
|
-
export declare function sendUploadRequest<T = Record<string, unknown>>(config: NileClientConfig, service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>, options?: FetchOptions): Promise<ClientResult<T>>;
|
|
137
|
-
/**
|
|
138
|
-
* Builds a FormData instance with RPC routing fields and file/field entries.
|
|
139
|
-
* The server expects 'intent', 'service', 'action' as string fields.
|
|
140
|
-
*/
|
|
141
|
-
export declare function buildFormData(service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>): FormData;
|
|
119
|
+
//#endregion
|
|
120
|
+
//#region src/socket-types.d.ts
|
|
121
|
+
type WireJson = object | string | number | boolean | null;
|
|
142
122
|
interface TopicContract {
|
|
143
|
-
data:
|
|
144
|
-
input?:
|
|
145
|
-
scope?:
|
|
123
|
+
data: WireJson;
|
|
124
|
+
input?: WireJson;
|
|
125
|
+
scope?: WireJson;
|
|
146
126
|
}
|
|
147
127
|
type TopicShape<T> = { [K in keyof T]: TopicContract; };
|
|
148
|
-
type ActionShape<A> = { [S in keyof A]: { [K in keyof A[S]]: object; }; };
|
|
149
128
|
type SocketTopics = Record<string, TopicContract>;
|
|
150
|
-
type SocketActions = Record<string, Record<string, object>>;
|
|
151
129
|
type SocketSelection<T, K extends keyof T> = {
|
|
152
130
|
topic: K;
|
|
153
131
|
} & (T[K] extends {
|
|
@@ -170,36 +148,97 @@ interface SocketMessage<K extends string, D> {
|
|
|
170
148
|
id: string;
|
|
171
149
|
topic: K;
|
|
172
150
|
data: D;
|
|
173
|
-
scope?:
|
|
151
|
+
scope?: WireJson;
|
|
174
152
|
time: string;
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
153
|
+
/** Present when a client sent the message; absent for server messages. */
|
|
154
|
+
from?: {
|
|
155
|
+
connectionId: string;
|
|
156
|
+
userId?: string;
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
interface NileSocketConfig {
|
|
160
|
+
/** Socket server origin when it differs from `baseUrl`. Defaults to the origin of `baseUrl`. */
|
|
161
|
+
url?: string;
|
|
162
|
+
/** Socket.IO path. Default `/socket.io`; must match the server. */
|
|
178
163
|
path?: string;
|
|
164
|
+
/** Connection and acknowledgement timeout in ms. Default 30000. */
|
|
179
165
|
timeout?: number;
|
|
166
|
+
/** Sent when connecting, e.g. `{ token }`. A function is called again on every reconnect. */
|
|
180
167
|
auth?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
181
|
-
|
|
182
|
-
|
|
168
|
+
onConnect?: () => void;
|
|
169
|
+
onDisconnect?: (reason: string) => void;
|
|
170
|
+
/** Fires after a reconnect once active subscriptions are restored. */
|
|
171
|
+
onReconnect?: () => void;
|
|
172
|
+
/** A connection failure, or a subscription refused while restoring it after a reconnect. */
|
|
173
|
+
onError?: (error: {
|
|
183
174
|
error: string;
|
|
175
|
+
topic?: string;
|
|
184
176
|
}) => void;
|
|
185
177
|
}
|
|
186
|
-
interface
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
}
|
|
178
|
+
interface SocketSubscription {
|
|
179
|
+
topic: string;
|
|
180
|
+
/** Stop this listener; the server subscription ends when the last listener for it stops. */
|
|
181
|
+
unsubscribe: () => Promise<ClientResult<{
|
|
182
|
+
subscribed: boolean;
|
|
183
|
+
}>>;
|
|
184
|
+
}
|
|
185
|
+
interface NileSocketClient<T extends TopicShape<T> = SocketTopics> {
|
|
186
|
+
/** Send to a topic; the server checks the topic's `canSend` and validates the data. */
|
|
192
187
|
send: <K extends keyof T & string>(input: SocketPublication<T, K>) => Promise<ClientResult<SocketMessage<K, T[K]["data"]>>>;
|
|
188
|
+
/** Subscribe to a topic and listen for its messages in one call. */
|
|
193
189
|
receive: <K extends keyof T & string>(input: SocketSelection<T, K> & {
|
|
194
190
|
onMessage: (message: SocketMessage<K, T[K]["data"]>) => void;
|
|
195
|
-
}) => Promise<ClientResult<
|
|
196
|
-
|
|
197
|
-
subscribed: boolean;
|
|
198
|
-
}>>;
|
|
199
|
-
}>>;
|
|
191
|
+
}) => Promise<ClientResult<SocketSubscription>>;
|
|
192
|
+
/** Disconnect and drop every listener. The client cannot reconnect afterwards. */
|
|
200
193
|
close: () => void;
|
|
201
194
|
}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/create-client.d.ts
|
|
197
|
+
/**
|
|
198
|
+
* Creates a type-safe Nile client for interacting with backend services.
|
|
199
|
+
*
|
|
200
|
+
* @param config - The client configuration including baseUrl
|
|
201
|
+
* @returns A factory object with invoke, explore, schema and upload methods, plus
|
|
202
|
+
* `socket` for topics. The socket connects on its first `send` or `receive`.
|
|
203
|
+
*
|
|
204
|
+
* @example
|
|
205
|
+
* const nile = createNileClient<ServicePayloads>({ baseUrl: "/api" });
|
|
206
|
+
* const result = await nile.invoke({
|
|
207
|
+
* service: "tasks",
|
|
208
|
+
* action: "create",
|
|
209
|
+
* payload: { title: "Buy milk" }
|
|
210
|
+
* });
|
|
211
|
+
* if (result.isErr) {
|
|
212
|
+
* console.error(result.error);
|
|
213
|
+
* } else {
|
|
214
|
+
* console.log(result.value);
|
|
215
|
+
* }
|
|
216
|
+
*
|
|
217
|
+
* const received = await nile.socket.receive({
|
|
218
|
+
* topic: "tasks.updated",
|
|
219
|
+
* onMessage: (message) => console.log(message.data),
|
|
220
|
+
* });
|
|
221
|
+
*/
|
|
222
|
+
export declare function createNileClient<TPayloads = Record<string, Record<string, unknown>>, TTopics extends TopicShape<TTopics> = SocketTopics>(config: NileClientConfig): NileClient<TPayloads, TTopics>;
|
|
223
|
+
//#endregion
|
|
224
|
+
//#region src/deprecated.d.ts
|
|
225
|
+
/**
|
|
226
|
+
* Kept as a throwing stub so an upgrade fails with guidance instead of a
|
|
227
|
+
* missing export.
|
|
228
|
+
*
|
|
229
|
+
* @deprecated Use `createNileClient({ baseUrl, socket: { auth } })` and call
|
|
230
|
+
* `socket.send`, `socket.receive` and `socket.close` on the returned client.
|
|
231
|
+
*/
|
|
232
|
+
export declare function createNileSocketClient<Actions = unknown, Topics = unknown>(_config?: unknown): never;
|
|
233
|
+
//#endregion
|
|
234
|
+
//#region src/request.d.ts
|
|
235
|
+
/** Let the runtime set the multipart boundary; retain the same action Result contract. */
|
|
236
|
+
export declare function sendUploadRequest<T = Record<string, unknown>>(config: NileClientConfig, service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>, options?: FetchOptions): Promise<ClientResult<T>>;
|
|
237
|
+
/**
|
|
238
|
+
* Builds a FormData instance with RPC routing fields and file/field entries.
|
|
239
|
+
* The server expects 'intent', 'service', 'action' as string fields.
|
|
240
|
+
*/
|
|
241
|
+
export declare function buildFormData(service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>): FormData;
|
|
242
|
+
//#endregion
|
|
243
|
+
export type { ClientErr, ClientOk, ClientResult, ExploreActionsResponse, ExploreServicesResponse, ExternalResponse, FetchOptions, NileClient, NileClientConfig, NileIntentParams, NileSocketClient, NileSocketConfig, SocketMessage, SocketPublication, SocketSelection, SocketSubscription, SocketTopics, TopicContract, UploadParams, ValidationFailureData };
|
|
205
244
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
//#region src/result.ts
|
|
2
2
|
/**
|
|
3
3
|
* A successful client result. `data` mirrors `value` so code written for
|
|
4
4
|
* earlier clients keeps working. `message` is present only when the server sent one.
|
|
@@ -27,7 +27,8 @@ function clientErr(error, details = null) {
|
|
|
27
27
|
data: null
|
|
28
28
|
};
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
//#endregion
|
|
31
|
+
//#region src/safe-try.ts
|
|
31
32
|
/**
|
|
32
33
|
* Gracefully handles both synchronous and asynchronous operations by returning a result object.
|
|
33
34
|
* This replaces the need for external slang-ts dependency and avoids try/catch boilerplate.
|
|
@@ -67,7 +68,8 @@ function safeTry(fn) {
|
|
|
67
68
|
};
|
|
68
69
|
}
|
|
69
70
|
}
|
|
70
|
-
|
|
71
|
+
//#endregion
|
|
72
|
+
//#region src/request.ts
|
|
71
73
|
/** Send one action call; the deadline covers both fetch and reading its JSON body. */
|
|
72
74
|
async function sendRequest(config, body, multipart, options) {
|
|
73
75
|
const { timeout = config.timeout ?? 3e4, headers, signal, ...fetchOptions } = options;
|
|
@@ -144,58 +146,24 @@ function buildFormData(service, action, files, fields) {
|
|
|
144
146
|
function resolveError(error) {
|
|
145
147
|
return clientErr(error instanceof Error ? error.message : String(error));
|
|
146
148
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
* const result = await nile.invoke({
|
|
157
|
-
* service: "tasks",
|
|
158
|
-
* action: "create",
|
|
159
|
-
* payload: { title: "Buy milk" }
|
|
160
|
-
* });
|
|
161
|
-
* if (result.isErr) {
|
|
162
|
-
* console.error(result.error);
|
|
163
|
-
* } else {
|
|
164
|
-
* console.log(result.value);
|
|
165
|
-
* }
|
|
166
|
-
*/
|
|
167
|
-
function createNileClient(config) {
|
|
168
|
-
return {
|
|
169
|
-
/** Invoke a service action through the backend engine pipeline */
|
|
170
|
-
invoke: async (params) => {
|
|
171
|
-
const { service, action, payload, fetchOptions } = params;
|
|
172
|
-
return await sendNileRequest(config, "execute", service, action, payload, fetchOptions);
|
|
173
|
-
},
|
|
174
|
-
/** Discover available services and actions (supports "*" wildcard) */
|
|
175
|
-
explore: async (params) => {
|
|
176
|
-
const { service, action, fetchOptions } = params;
|
|
177
|
-
return await sendNileRequest(config, "explore", service, action, {}, fetchOptions);
|
|
178
|
-
},
|
|
179
|
-
/** Get action schemas as JSON Schema (supports "*" wildcard) */
|
|
180
|
-
schema: async (params) => {
|
|
181
|
-
const { service, action, fetchOptions } = params;
|
|
182
|
-
return await sendNileRequest(config, "schema", service, action, {}, fetchOptions);
|
|
183
|
-
},
|
|
184
|
-
/** Upload files to an action via multipart form-data */
|
|
185
|
-
upload: async (params) => {
|
|
186
|
-
const { service, action, files, fields, fetchOptions } = params;
|
|
187
|
-
return await sendUploadRequest(config, service, action, files, fields, fetchOptions);
|
|
188
|
-
}
|
|
189
|
-
};
|
|
149
|
+
//#endregion
|
|
150
|
+
//#region src/socket-client.ts
|
|
151
|
+
/** The socket connects to an origin; any path in a URL would be read by Socket.IO as a namespace. */
|
|
152
|
+
function socketOrigin(url) {
|
|
153
|
+
try {
|
|
154
|
+
return new URL(url).origin;
|
|
155
|
+
} catch {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
190
158
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
function createNileSocketClient(config) {
|
|
159
|
+
/** Own a lazy Socket.IO connection with no offline write buffering. */
|
|
160
|
+
function createNileSocket(config) {
|
|
194
161
|
const timeout = config.timeout ?? 3e4;
|
|
195
162
|
if (!Number.isSafeInteger(timeout) || timeout < 1) throw new Error("Socket timeout must be positive");
|
|
196
163
|
let socket;
|
|
197
164
|
let connecting;
|
|
198
165
|
let closed = false;
|
|
166
|
+
let everConnected = false;
|
|
199
167
|
const listeners = /* @__PURE__ */ new Set();
|
|
200
168
|
const pending = /* @__PURE__ */ new Set();
|
|
201
169
|
const fail = (error) => clientErr(error);
|
|
@@ -244,7 +212,7 @@ function createNileSocketClient(config) {
|
|
|
244
212
|
continue;
|
|
245
213
|
}
|
|
246
214
|
const message = result.error;
|
|
247
|
-
settleCallback(() => config.
|
|
215
|
+
settleCallback(() => config.onError?.({
|
|
248
216
|
topic: listener.topic,
|
|
249
217
|
error: message
|
|
250
218
|
}));
|
|
@@ -259,7 +227,7 @@ function createNileSocketClient(config) {
|
|
|
259
227
|
resolve(fail("Socket client is closed"));
|
|
260
228
|
return;
|
|
261
229
|
}
|
|
262
|
-
const current = socket ?? io(config.
|
|
230
|
+
const current = socket ?? io(config.url ? socketOrigin(config.url) : void 0, {
|
|
263
231
|
path: config.path ?? "/socket.io",
|
|
264
232
|
autoConnect: false,
|
|
265
233
|
withCredentials: true,
|
|
@@ -270,11 +238,20 @@ function createNileSocketClient(config) {
|
|
|
270
238
|
});
|
|
271
239
|
if (!socket) {
|
|
272
240
|
socket = current;
|
|
273
|
-
current.on("disconnect", () => {
|
|
241
|
+
current.on("disconnect", (reason) => {
|
|
274
242
|
for (const cancel of [...pending]) cancel();
|
|
243
|
+
settleCallback(() => config.onDisconnect?.(reason));
|
|
275
244
|
});
|
|
276
245
|
current.on("connect", () => {
|
|
277
|
-
|
|
246
|
+
if (!everConnected) {
|
|
247
|
+
everConnected = true;
|
|
248
|
+
settleCallback(() => config.onConnect?.());
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
rejoin().then(() => settleCallback(() => config.onReconnect?.()));
|
|
252
|
+
});
|
|
253
|
+
current.on("connect_error", () => {
|
|
254
|
+
settleCallback(() => config.onError?.({ error: "Socket connection failed" }));
|
|
278
255
|
});
|
|
279
256
|
current.on("nile:message", (message) => dispatchMessage(message, listeners));
|
|
280
257
|
}
|
|
@@ -302,7 +279,6 @@ function createNileSocketClient(config) {
|
|
|
302
279
|
return connecting;
|
|
303
280
|
};
|
|
304
281
|
return {
|
|
305
|
-
invoke: (input) => request("nile:invoke", input),
|
|
306
282
|
send: (input) => request("nile:send", input),
|
|
307
283
|
async receive(input) {
|
|
308
284
|
const listener = {
|
|
@@ -321,16 +297,19 @@ function createNileSocketClient(config) {
|
|
|
321
297
|
return fail(result.error);
|
|
322
298
|
}
|
|
323
299
|
listener.normalizedScope = result.value?.scope;
|
|
324
|
-
return clientOk({
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
300
|
+
return clientOk({
|
|
301
|
+
topic: input.topic,
|
|
302
|
+
unsubscribe: () => {
|
|
303
|
+
listener.active = false;
|
|
304
|
+
listeners.delete(listener);
|
|
305
|
+
const shared = [...listeners].some((item) => item.topic === listener.topic && stableScope(item.scope) === stableScope(listener.scope));
|
|
306
|
+
if (shared || closed) return Promise.resolve(clientOk({ subscribed: shared }));
|
|
307
|
+
return request("nile:unsubscribe", {
|
|
308
|
+
topic: listener.topic,
|
|
309
|
+
scope: listener.scope
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
});
|
|
334
313
|
},
|
|
335
314
|
close() {
|
|
336
315
|
closed = true;
|
|
@@ -358,6 +337,82 @@ function dispatchMessage(message, listeners) {
|
|
|
358
337
|
Promise.resolve().then(() => listener.onMessage(message)).catch(() => void 0);
|
|
359
338
|
}
|
|
360
339
|
}
|
|
340
|
+
//#endregion
|
|
341
|
+
//#region src/create-client.ts
|
|
342
|
+
/**
|
|
343
|
+
* Creates a type-safe Nile client for interacting with backend services.
|
|
344
|
+
*
|
|
345
|
+
* @param config - The client configuration including baseUrl
|
|
346
|
+
* @returns A factory object with invoke, explore, schema and upload methods, plus
|
|
347
|
+
* `socket` for topics. The socket connects on its first `send` or `receive`.
|
|
348
|
+
*
|
|
349
|
+
* @example
|
|
350
|
+
* const nile = createNileClient<ServicePayloads>({ baseUrl: "/api" });
|
|
351
|
+
* const result = await nile.invoke({
|
|
352
|
+
* service: "tasks",
|
|
353
|
+
* action: "create",
|
|
354
|
+
* payload: { title: "Buy milk" }
|
|
355
|
+
* });
|
|
356
|
+
* if (result.isErr) {
|
|
357
|
+
* console.error(result.error);
|
|
358
|
+
* } else {
|
|
359
|
+
* console.log(result.value);
|
|
360
|
+
* }
|
|
361
|
+
*
|
|
362
|
+
* const received = await nile.socket.receive({
|
|
363
|
+
* topic: "tasks.updated",
|
|
364
|
+
* onMessage: (message) => console.log(message.data),
|
|
365
|
+
* });
|
|
366
|
+
*/
|
|
367
|
+
function createNileClient(config) {
|
|
368
|
+
return {
|
|
369
|
+
socket: createNileSocket({
|
|
370
|
+
...config.socket,
|
|
371
|
+
url: config.socket?.url ?? config.baseUrl
|
|
372
|
+
}),
|
|
373
|
+
/** Invoke a service action through the backend engine pipeline */
|
|
374
|
+
invoke: async (params) => {
|
|
375
|
+
const { service, action, payload, fetchOptions } = params;
|
|
376
|
+
return await sendNileRequest(config, "execute", service, action, payload, fetchOptions);
|
|
377
|
+
},
|
|
378
|
+
/** Discover available services and actions (supports "*" wildcard) */
|
|
379
|
+
explore: async (params) => {
|
|
380
|
+
const { service, action, fetchOptions } = params;
|
|
381
|
+
return await sendNileRequest(config, "explore", service, action, {}, fetchOptions);
|
|
382
|
+
},
|
|
383
|
+
/** Get action schemas as JSON Schema (supports "*" wildcard) */
|
|
384
|
+
schema: async (params) => {
|
|
385
|
+
const { service, action, fetchOptions } = params;
|
|
386
|
+
return await sendNileRequest(config, "schema", service, action, {}, fetchOptions);
|
|
387
|
+
},
|
|
388
|
+
/** Upload files to an action via multipart form-data */
|
|
389
|
+
upload: async (params) => {
|
|
390
|
+
const { service, action, files, fields, fetchOptions } = params;
|
|
391
|
+
return await sendUploadRequest(config, service, action, files, fields, fetchOptions);
|
|
392
|
+
}
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
//#endregion
|
|
396
|
+
//#region src/deprecated.ts
|
|
397
|
+
const MIGRATION_MESSAGE = [
|
|
398
|
+
"createNileSocketClient was removed in @nilejs/client 1.1.0.",
|
|
399
|
+
"Create one client with createNileClient({ baseUrl, socket: { auth } })",
|
|
400
|
+
"and use nile.socket.send, nile.socket.receive and nile.socket.close.",
|
|
401
|
+
"Socket invoke is gone as well; call actions with nile.invoke over HTTP.",
|
|
402
|
+
"See https://nile-js.github.io/nile/guide/features/websockets/ and the",
|
|
403
|
+
"migration notes in packages/nile/docs/release-migration.md."
|
|
404
|
+
].join(" ");
|
|
405
|
+
/**
|
|
406
|
+
* Kept as a throwing stub so an upgrade fails with guidance instead of a
|
|
407
|
+
* missing export.
|
|
408
|
+
*
|
|
409
|
+
* @deprecated Use `createNileClient({ baseUrl, socket: { auth } })` and call
|
|
410
|
+
* `socket.send`, `socket.receive` and `socket.close` on the returned client.
|
|
411
|
+
*/
|
|
412
|
+
function createNileSocketClient(_config) {
|
|
413
|
+
throw new Error(MIGRATION_MESSAGE);
|
|
414
|
+
}
|
|
415
|
+
//#endregion
|
|
361
416
|
export { buildFormData, createNileClient, createNileSocketClient, sendUploadRequest };
|
|
362
417
|
|
|
363
418
|
//# sourceMappingURL=index.js.map
|