@nilejs/client 0.0.3 → 1.0.1

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/README.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # @nilejs/client
2
2
 
3
- A standalone, type-safe client for the [Nile](https://github.com/nile-js/nile) backend framework.
3
+ A type-safe frontend client for [Nile Js](https://nile-js.github.io/nile/) backends.
4
4
 
5
5
  ## Features
6
6
 
7
- - **Type-safe:** Generates and consumes types from your Nile backend for full compile-time payload validation.
8
- - **Graceful Error Handling:** Uses the result pattern `{ error, data }` instead of throwing exceptions.
9
- - **Zero Runtime Dependencies:** Built on raw `fetch` for maximum compatibility (uses `slang-ts` for safety).
7
+ - **Type-safe:** Consumes shared or CLI-generated backend types for service, action and payload checking.
8
+ - **Graceful Error Handling:** Returns the same Result pattern as the Nile Js backend (`isOk`, `isErr`, `value`, `error`) instead of throwing exceptions.
9
+ - **Small:** HTTP calls use the platform `fetch`. The only runtime dependency is `socket.io-client`, for the socket client.
10
10
  - **Flexible:** Supports custom headers, credentials, and timeouts per request.
11
11
 
12
12
  ## Installation
@@ -38,16 +38,16 @@ const nile = createNileClient({
38
38
  ### 2. Invoke Actions
39
39
 
40
40
  ```typescript
41
- const { error, data } = await nile.invoke({
41
+ const result = await nile.invoke({
42
42
  service: "tasks",
43
43
  action: "create",
44
44
  payload: { title: "Buy milk" },
45
45
  });
46
46
 
47
- if (error) {
48
- console.error("Action failed:", error);
47
+ if (result.isErr) {
48
+ console.error("Action failed:", result.error);
49
49
  } else {
50
- console.log("Success:", data);
50
+ console.log("Success:", result.value);
51
51
  }
52
52
  ```
53
53
 
@@ -78,10 +78,18 @@ await nile.invoke({
78
78
 
79
79
  ```typescript
80
80
  // Explore services and actions
81
- const { data: services } = await nile.explore({ service: "*", action: "*" });
81
+ const services = await nile.explore({ service: "*", action: "*" });
82
+
83
+ if (services.isOk) {
84
+ console.log(services.value);
85
+ }
82
86
 
83
87
  // Fetch action schemas
84
- const { data: schemas } = await nile.schema({ service: "tasks", action: "*" });
88
+ const schemas = await nile.schema({ service: "tasks", action: "*" });
89
+
90
+ if (schemas.isOk) {
91
+ console.log(schemas.value);
92
+ }
85
93
  ```
86
94
 
87
95
  ## API
@@ -97,13 +105,103 @@ Returns a Nile client instance.
97
105
 
98
106
  ### Methods
99
107
 
100
- All methods return a `Promise<ClientResult<T>>` where `ClientResult<T>` is `{ error: string | null, data: T | null }`.
108
+ All methods return a `Promise<ClientResult<T>>`. Calls never throw:
109
+
110
+ - Success: `{ isOk: true, isErr: false, value: T, error: null, message? }`, where `message` is the server's success message for HTTP calls
111
+ - Failure: `{ isOk: false, isErr: true, value: null, error: string, details }`, where `details` holds any data the server attached, such as validation issues. Network failures and timeouts arrive as failures too.
112
+
113
+ Check `isErr` first, then read `error` or `value`. The older `data` field is still present as a deprecated alias (the value on success, `null` on failure) so existing code keeps working.
101
114
 
102
115
  - `invoke(params)`: Execute a specific service action.
103
116
  - `explore(params)`: Discover services/actions using wildcards.
104
117
  - `schema(params)`: Fetch action schemas as JSON Schema.
105
118
 
106
- Each method accepts an optional `timeout` and any standard fetch `headers` in its parameters.
119
+ Pass per-call settings in `fetchOptions`. Headers merge with the client’s configured headers; a per-call value overrides the same header regardless of case. Both `Headers` instances and header tuples are supported. The timeout covers reading the response body as well as connecting; an optional `signal` can cancel the call.
120
+
121
+ ```ts
122
+ const controller = new AbortController();
123
+ const result = await nile.invoke({
124
+ service: "tasks",
125
+ action: "create",
126
+ payload: { title: "Ship the next feature" },
127
+ fetchOptions: {
128
+ headers: { Authorization: "Bearer your-session-token" },
129
+ timeout: 5000,
130
+ signal: controller.signal,
131
+ },
132
+ });
133
+ ```
134
+
135
+ ## Nile 1.0.3 responses
136
+
137
+ HTTP responses contain exactly `status`, `message` and `data`. The client maps those into its existing Result API; it preserves custom messages, Zod’s prettified validation message, and generated diagnostic references. The default success message is `Action completed.`
138
+
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
+
141
+ ## Socket.IO actions and topics
142
+
143
+ Create a separate socket client. It owns the connection; you do not pass a socket into each invocation. Use shared types, generated action types, or define your frontend contracts explicitly. Topic definitions and authorization policies must also be configured on the backend.
144
+
145
+ ```ts
146
+ import { createNileSocketClient } from "@nilejs/client";
147
+ import type { ServicePayloads } from "./generated/types";
148
+
149
+ type Topics = {
150
+ "tasks.changed": {
151
+ data: { taskId: string; status: string };
152
+ };
153
+ };
154
+
155
+ const socket = createNileSocketClient<ServicePayloads, Topics>({
156
+ baseUrl: "http://localhost:8000",
157
+ auth: () => {
158
+ return { token: "your-session-token" };
159
+ },
160
+ });
161
+
162
+ const subscription = await socket.receive({
163
+ topic: "tasks.changed",
164
+ onMessage: (message) => {
165
+ console.log(message.data.taskId, message.data.status);
166
+ },
167
+ });
168
+
169
+ const result = await socket.invoke({
170
+ service: "tasks",
171
+ action: "create",
172
+ payload: { title: "Ship the next feature" },
173
+ });
174
+
175
+ const publication = await socket.send({
176
+ topic: "tasks.changed",
177
+ data: { taskId: "task-123", status: "done" },
178
+ });
179
+
180
+ if (subscription.isOk) {
181
+ await subscription.value.unsubscribe();
182
+ }
183
+ socket.close();
184
+ ```
185
+
186
+ Keep the client open for as long as your application needs live updates. The connection is lazy, subscriptions rejoin after reconnecting, and disconnected writes are not buffered or retried automatically. Topic names, data and any required scope are checked from the supplied types; Nile validates them and enforces policies on the backend. The server can expose HTTP and sockets together. See [WebSockets](https://nile-js.github.io/nile/guide/features/websockets/) for server setup.
187
+
188
+ ## Uploads
189
+
190
+ ```ts
191
+ const result = await nile.upload({
192
+ service: "documents",
193
+ action: "upload",
194
+ files: { document: file },
195
+ fields: { title: "Invoice" },
196
+ fetchOptions: { timeout: 60000 },
197
+ });
198
+ ```
199
+
200
+ Multipart calls share the same cancellation, deadline and Result behavior as JSON calls. Content-Type is set by the runtime so the multipart boundary is correct.
201
+
202
+ ## Compatibility
203
+
204
+ Version 1.0.1 supports Nile 1.0.3 and 1.0.4 while keeping the existing HTTP and socket client APIs. It fixes header merging, cancellation and timeout cleanup; it does not add fields to Nile’s wire contract.
107
205
 
108
206
  ## License
109
207