@nilejs/client 1.0.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -5,6 +5,14 @@ interface ExternalResponse<T = Record<string, unknown>> {
5
5
  message: string;
6
6
  data: T;
7
7
  }
8
+ /** Validation details returned by Nile HTTP actions; codes identify individual failures. */
9
+ interface ValidationFailureData {
10
+ errorCode: string;
11
+ issues: Array<{
12
+ path: string;
13
+ message: string;
14
+ }>;
15
+ }
8
16
  /** A successful call: read the action's data from `value`. */
9
17
  interface ClientOk<T> {
10
18
  isOk: true;
@@ -67,6 +75,8 @@ interface NileClientConfig {
67
75
  headers?: Record<string, string>;
68
76
  /** Optional timeout in ms (default: 30000) */
69
77
  timeout?: number;
78
+ /** Socket settings for `client.socket`. The socket connects on first use. */
79
+ socket?: NileSocketConfig;
70
80
  }
71
81
  /** Options for individual fetch calls (body and method are managed internally) */
72
82
  interface FetchOptions extends Omit<RequestInit, "body" | "method"> {
@@ -89,7 +99,9 @@ interface UploadParams {
89
99
  fetchOptions?: FetchOptions;
90
100
  }
91
101
  /** Interface for the typed client */
92
- 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>;
93
105
  /** Invoke an action with full type-safety for payload */
94
106
  invoke: <S extends keyof TPayloads & string, A extends keyof TPayloads[S] & string>(params: {
95
107
  service: S;
@@ -105,54 +117,15 @@ interface NileClient<TPayloads = Record<string, Record<string, unknown>>> {
105
117
  upload: (params: UploadParams) => Promise<ClientResult>;
106
118
  }
107
119
  //#endregion
108
- //#region src/create-client.d.ts
109
- /**
110
- * Creates a type-safe Nile client for interacting with backend services.
111
- *
112
- * @param config - The client configuration including baseUrl
113
- * @returns A factory object with invoke, explore, schema, and upload methods
114
- *
115
- * @example
116
- * const nile = createNileClient<ServicePayloads>({ baseUrl: "/api" });
117
- * const result = await nile.invoke({
118
- * service: "tasks",
119
- * action: "create",
120
- * payload: { title: "Buy milk" }
121
- * });
122
- * if (result.isErr) {
123
- * console.error(result.error);
124
- * } else {
125
- * console.log(result.value);
126
- * }
127
- */
128
- export declare function createNileClient<TPayloads = Record<string, Record<string, unknown>>>(config: NileClientConfig): NileClient<TPayloads>;
129
- //#endregion
130
- //#region src/request.d.ts
131
- /**
132
- * Handles multipart form-data uploads to the Nile /services endpoint.
133
- * Builds a FormData body with RPC routing fields (intent, service, action),
134
- * user-provided fields, and file attachments.
135
- *
136
- * Content-Type header is intentionally omitted so the runtime sets the
137
- * correct multipart boundary automatically.
138
- */
139
- 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>>;
140
- /**
141
- * Builds a FormData instance with RPC routing fields and file/field entries.
142
- * The server expects 'intent', 'service', 'action' as string fields.
143
- */
144
- export declare function buildFormData(service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>): FormData;
145
- //#endregion
146
120
  //#region src/socket-types.d.ts
121
+ type WireJson = object | string | number | boolean | null;
147
122
  interface TopicContract {
148
- data: object | string | number | boolean | null;
149
- input?: object | string | number | boolean | null;
150
- scope?: object | string | number | boolean | null;
123
+ data: WireJson;
124
+ input?: WireJson;
125
+ scope?: WireJson;
151
126
  }
152
127
  type TopicShape<T> = { [K in keyof T]: TopicContract; };
153
- type ActionShape<A> = { [S in keyof A]: { [K in keyof A[S]]: object; }; };
154
128
  type SocketTopics = Record<string, TopicContract>;
155
- type SocketActions = Record<string, Record<string, object>>;
156
129
  type SocketSelection<T, K extends keyof T> = {
157
130
  topic: K;
158
131
  } & (T[K] extends {
@@ -175,39 +148,97 @@ interface SocketMessage<K extends string, D> {
175
148
  id: string;
176
149
  topic: K;
177
150
  data: D;
178
- scope?: object | string | number | boolean | null;
151
+ scope?: WireJson;
179
152
  time: string;
153
+ /** Present when a client sent the message; absent for server messages. */
154
+ from?: {
155
+ connectionId: string;
156
+ userId?: string;
157
+ };
180
158
  }
181
- interface NileSocketClientConfig {
182
- baseUrl: string;
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. */
183
163
  path?: string;
164
+ /** Connection and acknowledgement timeout in ms. Default 30000. */
184
165
  timeout?: number;
166
+ /** Sent when connecting, e.g. `{ token }`. A function is called again on every reconnect. */
185
167
  auth?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
186
- onSubscriptionError?: (input: {
187
- topic: string;
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: {
188
174
  error: string;
175
+ topic?: string;
189
176
  }) => void;
190
177
  }
191
- interface NileSocketClient<A extends ActionShape<A>, T extends TopicShape<T>> {
192
- invoke: <S extends keyof A & string, K extends keyof A[S] & string>(input: {
193
- service: S;
194
- action: K;
195
- payload: A[S][K];
196
- }) => Promise<ClientResult>;
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. */
197
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. */
198
189
  receive: <K extends keyof T & string>(input: SocketSelection<T, K> & {
199
190
  onMessage: (message: SocketMessage<K, T[K]["data"]>) => void;
200
- }) => Promise<ClientResult<{
201
- unsubscribe: () => Promise<ClientResult<{
202
- subscribed: boolean;
203
- }>>;
204
- }>>;
191
+ }) => Promise<ClientResult<SocketSubscription>>;
192
+ /** Disconnect and drop every listener. The client cannot reconnect afterwards. */
205
193
  close: () => void;
206
194
  }
207
195
  //#endregion
208
- //#region src/socket-client.d.ts
209
- /** Own a lazy Socket.IO connection with no offline write buffering or automatic invocation retries. */
210
- export declare function createNileSocketClient<Actions extends ActionShape<Actions> = SocketActions, Topics extends TopicShape<Topics> = SocketTopics>(config: NileSocketClientConfig): NileSocketClient<Actions, Topics>;
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;
211
242
  //#endregion
212
- export type { ClientErr, ClientOk, ClientResult, ExploreActionsResponse, ExploreServicesResponse, ExternalResponse, FetchOptions, NileClient, NileClientConfig, NileIntentParams, NileSocketClient, NileSocketClientConfig, SocketActions, SocketMessage, SocketPublication, SocketSelection, SocketTopics, UploadParams };
243
+ export type { ClientErr, ClientOk, ClientResult, ExploreActionsResponse, ExploreServicesResponse, ExternalResponse, FetchOptions, NileClient, NileClientConfig, NileIntentParams, NileSocketClient, NileSocketConfig, SocketMessage, SocketPublication, SocketSelection, SocketSubscription, SocketTopics, TopicContract, UploadParams, ValidationFailureData };
213
244
  //# sourceMappingURL=index.d.cts.map
package/dist/index.d.ts CHANGED
@@ -5,6 +5,14 @@ interface ExternalResponse<T = Record<string, unknown>> {
5
5
  message: string;
6
6
  data: T;
7
7
  }
8
+ /** Validation details returned by Nile HTTP actions; codes identify individual failures. */
9
+ interface ValidationFailureData {
10
+ errorCode: string;
11
+ issues: Array<{
12
+ path: string;
13
+ message: string;
14
+ }>;
15
+ }
8
16
  /** A successful call: read the action's data from `value`. */
9
17
  interface ClientOk<T> {
10
18
  isOk: true;
@@ -67,6 +75,8 @@ interface NileClientConfig {
67
75
  headers?: Record<string, string>;
68
76
  /** Optional timeout in ms (default: 30000) */
69
77
  timeout?: number;
78
+ /** Socket settings for `client.socket`. The socket connects on first use. */
79
+ socket?: NileSocketConfig;
70
80
  }
71
81
  /** Options for individual fetch calls (body and method are managed internally) */
72
82
  interface FetchOptions extends Omit<RequestInit, "body" | "method"> {
@@ -89,7 +99,9 @@ interface UploadParams {
89
99
  fetchOptions?: FetchOptions;
90
100
  }
91
101
  /** Interface for the typed client */
92
- 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>;
93
105
  /** Invoke an action with full type-safety for payload */
94
106
  invoke: <S extends keyof TPayloads & string, A extends keyof TPayloads[S] & string>(params: {
95
107
  service: S;
@@ -105,54 +117,15 @@ interface NileClient<TPayloads = Record<string, Record<string, unknown>>> {
105
117
  upload: (params: UploadParams) => Promise<ClientResult>;
106
118
  }
107
119
  //#endregion
108
- //#region src/create-client.d.ts
109
- /**
110
- * Creates a type-safe Nile client for interacting with backend services.
111
- *
112
- * @param config - The client configuration including baseUrl
113
- * @returns A factory object with invoke, explore, schema, and upload methods
114
- *
115
- * @example
116
- * const nile = createNileClient<ServicePayloads>({ baseUrl: "/api" });
117
- * const result = await nile.invoke({
118
- * service: "tasks",
119
- * action: "create",
120
- * payload: { title: "Buy milk" }
121
- * });
122
- * if (result.isErr) {
123
- * console.error(result.error);
124
- * } else {
125
- * console.log(result.value);
126
- * }
127
- */
128
- export declare function createNileClient<TPayloads = Record<string, Record<string, unknown>>>(config: NileClientConfig): NileClient<TPayloads>;
129
- //#endregion
130
- //#region src/request.d.ts
131
- /**
132
- * Handles multipart form-data uploads to the Nile /services endpoint.
133
- * Builds a FormData body with RPC routing fields (intent, service, action),
134
- * user-provided fields, and file attachments.
135
- *
136
- * Content-Type header is intentionally omitted so the runtime sets the
137
- * correct multipart boundary automatically.
138
- */
139
- 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>>;
140
- /**
141
- * Builds a FormData instance with RPC routing fields and file/field entries.
142
- * The server expects 'intent', 'service', 'action' as string fields.
143
- */
144
- export declare function buildFormData(service: string, action: string, files: Record<string, File | File[]>, fields?: Record<string, string>): FormData;
145
- //#endregion
146
120
  //#region src/socket-types.d.ts
121
+ type WireJson = object | string | number | boolean | null;
147
122
  interface TopicContract {
148
- data: object | string | number | boolean | null;
149
- input?: object | string | number | boolean | null;
150
- scope?: object | string | number | boolean | null;
123
+ data: WireJson;
124
+ input?: WireJson;
125
+ scope?: WireJson;
151
126
  }
152
127
  type TopicShape<T> = { [K in keyof T]: TopicContract; };
153
- type ActionShape<A> = { [S in keyof A]: { [K in keyof A[S]]: object; }; };
154
128
  type SocketTopics = Record<string, TopicContract>;
155
- type SocketActions = Record<string, Record<string, object>>;
156
129
  type SocketSelection<T, K extends keyof T> = {
157
130
  topic: K;
158
131
  } & (T[K] extends {
@@ -175,39 +148,97 @@ interface SocketMessage<K extends string, D> {
175
148
  id: string;
176
149
  topic: K;
177
150
  data: D;
178
- scope?: object | string | number | boolean | null;
151
+ scope?: WireJson;
179
152
  time: string;
153
+ /** Present when a client sent the message; absent for server messages. */
154
+ from?: {
155
+ connectionId: string;
156
+ userId?: string;
157
+ };
180
158
  }
181
- interface NileSocketClientConfig {
182
- baseUrl: string;
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. */
183
163
  path?: string;
164
+ /** Connection and acknowledgement timeout in ms. Default 30000. */
184
165
  timeout?: number;
166
+ /** Sent when connecting, e.g. `{ token }`. A function is called again on every reconnect. */
185
167
  auth?: Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
186
- onSubscriptionError?: (input: {
187
- topic: string;
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: {
188
174
  error: string;
175
+ topic?: string;
189
176
  }) => void;
190
177
  }
191
- interface NileSocketClient<A extends ActionShape<A>, T extends TopicShape<T>> {
192
- invoke: <S extends keyof A & string, K extends keyof A[S] & string>(input: {
193
- service: S;
194
- action: K;
195
- payload: A[S][K];
196
- }) => Promise<ClientResult>;
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. */
197
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. */
198
189
  receive: <K extends keyof T & string>(input: SocketSelection<T, K> & {
199
190
  onMessage: (message: SocketMessage<K, T[K]["data"]>) => void;
200
- }) => Promise<ClientResult<{
201
- unsubscribe: () => Promise<ClientResult<{
202
- subscribed: boolean;
203
- }>>;
204
- }>>;
191
+ }) => Promise<ClientResult<SocketSubscription>>;
192
+ /** Disconnect and drop every listener. The client cannot reconnect afterwards. */
205
193
  close: () => void;
206
194
  }
207
195
  //#endregion
208
- //#region src/socket-client.d.ts
209
- /** Own a lazy Socket.IO connection with no offline write buffering or automatic invocation retries. */
210
- export declare function createNileSocketClient<Actions extends ActionShape<Actions> = SocketActions, Topics extends TopicShape<Topics> = SocketTopics>(config: NileSocketClientConfig): NileSocketClient<Actions, Topics>;
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;
211
242
  //#endregion
212
- export type { ClientErr, ClientOk, ClientResult, ExploreActionsResponse, ExploreServicesResponse, ExternalResponse, FetchOptions, NileClient, NileClientConfig, NileIntentParams, NileSocketClient, NileSocketClientConfig, SocketActions, SocketMessage, SocketPublication, SocketSelection, SocketTopics, UploadParams };
243
+ export type { ClientErr, ClientOk, ClientResult, ExploreActionsResponse, ExploreServicesResponse, ExternalResponse, FetchOptions, NileClient, NileClientConfig, NileIntentParams, NileSocketClient, NileSocketConfig, SocketMessage, SocketPublication, SocketSelection, SocketSubscription, SocketTopics, TopicContract, UploadParams, ValidationFailureData };
213
244
  //# sourceMappingURL=index.d.ts.map