@adofai-ipc/client 0.1.0 → 0.3.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/README.md +86 -1
- package/dist/index.cjs +220 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +75 -21
- package/dist/index.d.ts +75 -21
- package/dist/index.js +216 -29
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -40,12 +40,43 @@ await tufhelper.call("level.open-from-id", {
|
|
|
40
40
|
|
|
41
41
|
Finds a running AdofaiIpc server by probing `/ipc/health`.
|
|
42
42
|
|
|
43
|
+
The client and server product versions must match exactly. A mismatch throws
|
|
44
|
+
`IpcVersionMismatchError` and stops port probing. Use `onVersionMismatch` to display application UI;
|
|
45
|
+
the callback runs at most once per `tryConnect` call and does not suppress the typed error.
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
await tryConnect({
|
|
49
|
+
onVersionMismatch(error) {
|
|
50
|
+
if (error.direction === "client_outdated") location.reload();
|
|
51
|
+
else openAdofaiIpcDownloadNotice(error);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`server_outdated` means the mod must be updated, `client_outdated` means the web bundle must be
|
|
57
|
+
updated, and `legacy_server` means the server did not provide a valid product version. React
|
|
58
|
+
StrictMode and consumer retry loops can call `tryConnect` more than once, so applications should
|
|
59
|
+
store mismatch as a terminal connection state and deduplicate their own modal or banner.
|
|
60
|
+
|
|
43
61
|
Defaults:
|
|
44
62
|
|
|
45
63
|
- host: `127.0.0.1`
|
|
46
64
|
- startPort: `32145`
|
|
47
65
|
- endPort: `32155`
|
|
48
|
-
-
|
|
66
|
+
- probeTimeoutMs: `500`
|
|
67
|
+
- requestTimeoutMs: `10000`
|
|
68
|
+
|
|
69
|
+
`tryConnect` only confirms that the AdofaiIpc listener is running. It does not mean that a target
|
|
70
|
+
namespace is registered or that the owning mod has finished initializing.
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
const client = await tryConnect({
|
|
74
|
+
probeTimeoutMs: 500,
|
|
75
|
+
requestTimeoutMs: 10_000
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The legacy `timeoutMs` option remains as a deprecated alias for both values.
|
|
49
80
|
|
|
50
81
|
### `new AdofaiIpcClient(options?)`
|
|
51
82
|
|
|
@@ -61,6 +92,14 @@ const client = new AdofaiIpcClient({
|
|
|
61
92
|
|
|
62
93
|
Calls a namespace method through `POST /ipc`.
|
|
63
94
|
|
|
95
|
+
```ts
|
|
96
|
+
await client.call({
|
|
97
|
+
namespace: "tufhelper2",
|
|
98
|
+
method: "activity.get",
|
|
99
|
+
timeoutMs: 30_000
|
|
100
|
+
});
|
|
101
|
+
```
|
|
102
|
+
|
|
64
103
|
### `client.namespace(name)`
|
|
65
104
|
|
|
66
105
|
Creates a namespace-bound helper.
|
|
@@ -77,6 +116,52 @@ Calls `GET /ipc/namespaces`.
|
|
|
77
116
|
|
|
78
117
|
Calls `GET /ipc/namespaces/{name}`.
|
|
79
118
|
|
|
119
|
+
### `client.waitForNamespace(name, options?)`
|
|
120
|
+
|
|
121
|
+
Polls namespace discovery until the target namespace is registered. Set `status: "ready"` to also
|
|
122
|
+
wait until the namespace owner explicitly marks initialization complete.
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
await client.waitForNamespace("tufhelper2", {
|
|
126
|
+
status: "ready",
|
|
127
|
+
timeoutMs: 15_000,
|
|
128
|
+
pollIntervalMs: 100
|
|
129
|
+
});
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
AdofaiIpc namespaces have the strict states `initializing`, `ready`, and `error`. A ready wait that
|
|
133
|
+
expires reports `namespace_initializing`; an initialization failure reports `namespace_error`.
|
|
134
|
+
|
|
135
|
+
## Error handling
|
|
136
|
+
|
|
137
|
+
Connection failures are reported as `IpcConnectionError` with code `UNAVAILABLE`. Request
|
|
138
|
+
timeouts use the more specific `IpcTimeoutError`, which extends `IpcConnectionError` and has code
|
|
139
|
+
`TIMEOUT`. Protocol failures, including `namespace_not_found`, are reported as
|
|
140
|
+
`IpcResponseError`. `isIpcUnavailable` only matches the `UNAVAILABLE` state, not timeouts.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import {
|
|
144
|
+
IpcTimeoutError,
|
|
145
|
+
isIpcUnavailable,
|
|
146
|
+
tryConnect
|
|
147
|
+
} from "@adofai-ipc/client";
|
|
148
|
+
|
|
149
|
+
try {
|
|
150
|
+
const client = await tryConnect();
|
|
151
|
+
await client.health();
|
|
152
|
+
} catch (error) {
|
|
153
|
+
if (error instanceof IpcTimeoutError) {
|
|
154
|
+
console.warn(`AdofaiIpc timed out after ${error.timeoutMs} ms.`);
|
|
155
|
+
} else if (isIpcUnavailable(error)) {
|
|
156
|
+
console.warn("AdofaiIpc is unavailable.");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
`tryConnect` treats individual probe failures as expected and only throws an `UNAVAILABLE`
|
|
162
|
+
`IpcConnectionError` after every candidate port has failed. A successful probe does not guarantee
|
|
163
|
+
that any specific namespace or mode feature is ready.
|
|
164
|
+
|
|
80
165
|
## Notes
|
|
81
166
|
|
|
82
167
|
This package uses the global `fetch` API. Node.js 18 or newer is recommended.
|
package/dist/index.cjs
CHANGED
|
@@ -23,9 +23,13 @@ __export(index_exports, {
|
|
|
23
23
|
AdofaiIpcClient: () => AdofaiIpcClient,
|
|
24
24
|
AdofaiIpcError: () => AdofaiIpcError,
|
|
25
25
|
AdofaiIpcNamespaceClient: () => AdofaiIpcNamespaceClient,
|
|
26
|
+
CLIENT_VERSION: () => CLIENT_VERSION,
|
|
26
27
|
IpcConnectionError: () => IpcConnectionError,
|
|
27
28
|
IpcHttpError: () => IpcHttpError,
|
|
28
29
|
IpcResponseError: () => IpcResponseError,
|
|
30
|
+
IpcTimeoutError: () => IpcTimeoutError,
|
|
31
|
+
IpcVersionMismatchError: () => IpcVersionMismatchError,
|
|
32
|
+
isIpcUnavailable: () => isIpcUnavailable,
|
|
29
33
|
tryConnect: () => tryConnect
|
|
30
34
|
});
|
|
31
35
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -38,11 +42,38 @@ var AdofaiIpcError = class extends Error {
|
|
|
38
42
|
}
|
|
39
43
|
};
|
|
40
44
|
var IpcConnectionError = class extends AdofaiIpcError {
|
|
41
|
-
constructor(message = "Could not connect to AdofaiIpc.") {
|
|
45
|
+
constructor(message = "Could not connect to AdofaiIpc.", options = {}) {
|
|
42
46
|
super(message);
|
|
43
47
|
this.name = "IpcConnectionError";
|
|
48
|
+
this.code = options.code ?? "UNAVAILABLE";
|
|
49
|
+
this.cause = options.cause;
|
|
44
50
|
}
|
|
45
51
|
};
|
|
52
|
+
var IpcTimeoutError = class extends IpcConnectionError {
|
|
53
|
+
constructor(timeoutMs, options = {}) {
|
|
54
|
+
super(`AdofaiIpc request timed out after ${timeoutMs} ms.`, {
|
|
55
|
+
code: "TIMEOUT",
|
|
56
|
+
cause: options.cause
|
|
57
|
+
});
|
|
58
|
+
this.name = "IpcTimeoutError";
|
|
59
|
+
this.timeoutMs = timeoutMs;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
var IpcVersionMismatchError = class extends AdofaiIpcError {
|
|
63
|
+
constructor(options) {
|
|
64
|
+
const server = options.serverVersion ?? "legacy/unknown";
|
|
65
|
+
super(`AdofaiIpc version mismatch: client ${options.clientVersion}, server ${server}.`);
|
|
66
|
+
this.code = "VERSION_MISMATCH";
|
|
67
|
+
this.name = "IpcVersionMismatchError";
|
|
68
|
+
this.clientVersion = options.clientVersion;
|
|
69
|
+
this.serverVersion = options.serverVersion;
|
|
70
|
+
this.direction = options.direction;
|
|
71
|
+
this.protocolVersion = options.protocolVersion;
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
function isIpcUnavailable(error) {
|
|
75
|
+
return error instanceof IpcConnectionError && error.code === "UNAVAILABLE";
|
|
76
|
+
}
|
|
46
77
|
var IpcHttpError = class extends AdofaiIpcError {
|
|
47
78
|
constructor(status, message) {
|
|
48
79
|
super(message);
|
|
@@ -59,16 +90,56 @@ var IpcResponseError = class extends AdofaiIpcError {
|
|
|
59
90
|
}
|
|
60
91
|
};
|
|
61
92
|
|
|
93
|
+
// src/version.ts
|
|
94
|
+
var CLIENT_VERSION = "0.3.0";
|
|
95
|
+
var CANONICAL_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?$/;
|
|
96
|
+
function compareProductVersions(left, right) {
|
|
97
|
+
const leftVersion = parseProductVersion(left);
|
|
98
|
+
const rightVersion = parseProductVersion(right);
|
|
99
|
+
if (!leftVersion || !rightVersion) return null;
|
|
100
|
+
for (let index = 0; index < leftVersion.core.length; index++) {
|
|
101
|
+
const difference = leftVersion.core[index] - rightVersion.core[index];
|
|
102
|
+
if (difference !== 0) return difference < 0 ? -1 : 1;
|
|
103
|
+
}
|
|
104
|
+
if (leftVersion.prerelease === null) return rightVersion.prerelease === null ? 0 : 1;
|
|
105
|
+
if (rightVersion.prerelease === null) return -1;
|
|
106
|
+
const length = Math.max(leftVersion.prerelease.length, rightVersion.prerelease.length);
|
|
107
|
+
for (let index = 0; index < length; index++) {
|
|
108
|
+
const leftPart = leftVersion.prerelease[index];
|
|
109
|
+
const rightPart = rightVersion.prerelease[index];
|
|
110
|
+
if (leftPart === void 0) return -1;
|
|
111
|
+
if (rightPart === void 0) return 1;
|
|
112
|
+
if (leftPart === rightPart) continue;
|
|
113
|
+
const leftNumeric = /^\d+$/.test(leftPart);
|
|
114
|
+
const rightNumeric = /^\d+$/.test(rightPart);
|
|
115
|
+
if (leftNumeric && rightNumeric) return Number(leftPart) < Number(rightPart) ? -1 : 1;
|
|
116
|
+
if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;
|
|
117
|
+
return leftPart < rightPart ? -1 : 1;
|
|
118
|
+
}
|
|
119
|
+
return 0;
|
|
120
|
+
}
|
|
121
|
+
function parseProductVersion(value) {
|
|
122
|
+
const match = CANONICAL_SEMVER.exec(value);
|
|
123
|
+
if (!match) return null;
|
|
124
|
+
return {
|
|
125
|
+
core: [Number(match[1]), Number(match[2]), Number(match[3])],
|
|
126
|
+
prerelease: match[4] ? match[4].split(".") : null
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
|
|
62
130
|
// src/client.ts
|
|
63
131
|
var DEFAULT_HOST = "127.0.0.1";
|
|
64
132
|
var DEFAULT_START_PORT = 32145;
|
|
65
133
|
var DEFAULT_END_PORT = 32155;
|
|
66
|
-
var
|
|
134
|
+
var DEFAULT_PROBE_TIMEOUT_MS = 500;
|
|
135
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
|
|
136
|
+
var DEFAULT_NAMESPACE_WAIT_TIMEOUT_MS = 1e4;
|
|
137
|
+
var DEFAULT_NAMESPACE_POLL_INTERVAL_MS = 100;
|
|
67
138
|
var AdofaiIpcClient = class {
|
|
68
139
|
constructor(options = {}) {
|
|
69
140
|
this.baseUrl = normalizeBaseUrl(options.baseUrl ?? `http://${DEFAULT_HOST}:${DEFAULT_START_PORT}`);
|
|
70
141
|
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
71
|
-
this.
|
|
142
|
+
this.requestTimeoutMs = options.requestTimeoutMs ?? options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
72
143
|
if (!this.fetchImpl) {
|
|
73
144
|
throw new IpcConnectionError("A fetch implementation is required.");
|
|
74
145
|
}
|
|
@@ -76,47 +147,102 @@ var AdofaiIpcClient = class {
|
|
|
76
147
|
static async connect(options = {}) {
|
|
77
148
|
return tryConnect(options);
|
|
78
149
|
}
|
|
79
|
-
async health() {
|
|
80
|
-
return this.get("/ipc/health");
|
|
150
|
+
async health(options = {}) {
|
|
151
|
+
return this.get("/ipc/health", options);
|
|
152
|
+
}
|
|
153
|
+
async listNamespaces(options = {}) {
|
|
154
|
+
return this.get("/ipc/namespaces", options);
|
|
81
155
|
}
|
|
82
|
-
async
|
|
83
|
-
return this.get(
|
|
156
|
+
async getNamespace(namespace, options = {}) {
|
|
157
|
+
return this.get(
|
|
158
|
+
`/ipc/namespaces/${encodeURIComponent(namespace)}`,
|
|
159
|
+
options
|
|
160
|
+
);
|
|
84
161
|
}
|
|
85
|
-
async
|
|
86
|
-
|
|
162
|
+
async waitForNamespace(namespace, options = {}) {
|
|
163
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_NAMESPACE_WAIT_TIMEOUT_MS;
|
|
164
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_NAMESPACE_POLL_INTERVAL_MS;
|
|
165
|
+
const requiredStatus = options.status ?? "registered";
|
|
166
|
+
const deadline = Date.now() + timeoutMs;
|
|
167
|
+
let stateError;
|
|
168
|
+
while (true) {
|
|
169
|
+
try {
|
|
170
|
+
const detail = await this.getNamespace(namespace, {
|
|
171
|
+
timeoutMs: options.requestTimeoutMs
|
|
172
|
+
});
|
|
173
|
+
if (requiredStatus === "registered" || detail.status === "ready") {
|
|
174
|
+
return detail;
|
|
175
|
+
}
|
|
176
|
+
if (detail.status === "error") {
|
|
177
|
+
throw new IpcResponseError({
|
|
178
|
+
code: "namespace_error",
|
|
179
|
+
message: detail.error?.message ?? `Namespace initialization failed: ${namespace}`
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (detail.status !== "initializing") {
|
|
183
|
+
throw new IpcResponseError({
|
|
184
|
+
code: "namespace_status_unavailable",
|
|
185
|
+
message: `Namespace status is unavailable: ${namespace}`
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
stateError = new IpcResponseError({
|
|
189
|
+
code: "namespace_initializing",
|
|
190
|
+
message: `Namespace is initializing: ${namespace}`
|
|
191
|
+
});
|
|
192
|
+
} catch (error) {
|
|
193
|
+
if (!(error instanceof IpcResponseError) || error.code !== "namespace_not_found" && error.code !== "namespace_initializing") {
|
|
194
|
+
throw error;
|
|
195
|
+
}
|
|
196
|
+
stateError = error;
|
|
197
|
+
}
|
|
198
|
+
const remainingMs = deadline - Date.now();
|
|
199
|
+
if (remainingMs <= 0) {
|
|
200
|
+
throw stateError ?? new IpcResponseError({
|
|
201
|
+
code: "namespace_initializing",
|
|
202
|
+
message: `Namespace is initializing: ${namespace}`
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
await delay(Math.min(pollIntervalMs, remainingMs));
|
|
206
|
+
}
|
|
87
207
|
}
|
|
88
208
|
namespace(namespace) {
|
|
89
209
|
return new AdofaiIpcNamespaceClient(this, namespace);
|
|
90
210
|
}
|
|
91
211
|
async call(options) {
|
|
92
|
-
const response = await this.post(
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
212
|
+
const response = await this.post(
|
|
213
|
+
"/ipc",
|
|
214
|
+
{
|
|
215
|
+
namespace: options.namespace,
|
|
216
|
+
method: options.method,
|
|
217
|
+
params: options.params ?? {},
|
|
218
|
+
id: options.id ?? createRequestId()
|
|
219
|
+
},
|
|
220
|
+
{ timeoutMs: options.timeoutMs }
|
|
221
|
+
);
|
|
98
222
|
if (!response.ok) {
|
|
99
223
|
throw new IpcResponseError(response.error);
|
|
100
224
|
}
|
|
101
225
|
return response.result;
|
|
102
226
|
}
|
|
103
|
-
async get(path) {
|
|
227
|
+
async get(path, options = {}) {
|
|
104
228
|
return this.request(path, {
|
|
105
229
|
method: "GET"
|
|
106
|
-
});
|
|
230
|
+
}, options);
|
|
107
231
|
}
|
|
108
|
-
async post(path, body) {
|
|
232
|
+
async post(path, body, options = {}) {
|
|
109
233
|
return this.request(path, {
|
|
110
234
|
method: "POST",
|
|
111
235
|
headers: {
|
|
112
236
|
"Content-Type": "application/json"
|
|
113
237
|
},
|
|
114
238
|
body: JSON.stringify(body)
|
|
115
|
-
});
|
|
239
|
+
}, options);
|
|
116
240
|
}
|
|
117
|
-
async request(path, init) {
|
|
241
|
+
async request(path, init, options) {
|
|
242
|
+
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
|
|
118
243
|
const controller = new AbortController();
|
|
119
|
-
const
|
|
244
|
+
const timeoutError = new IpcTimeoutError(timeoutMs);
|
|
245
|
+
const timeout = setTimeout(() => controller.abort(timeoutError), timeoutMs);
|
|
120
246
|
try {
|
|
121
247
|
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
122
248
|
...init,
|
|
@@ -124,13 +250,18 @@ var AdofaiIpcClient = class {
|
|
|
124
250
|
});
|
|
125
251
|
if (!response.ok) {
|
|
126
252
|
const text = await response.text();
|
|
253
|
+
const responseError = parseIpcResponseError(text);
|
|
254
|
+
if (responseError) throw new IpcResponseError(responseError);
|
|
127
255
|
throw new IpcHttpError(response.status, text || response.statusText);
|
|
128
256
|
}
|
|
129
257
|
return await response.json();
|
|
130
258
|
} catch (error) {
|
|
131
|
-
if (error instanceof IpcHttpError) throw error;
|
|
132
|
-
if (
|
|
133
|
-
|
|
259
|
+
if (error instanceof IpcHttpError || error instanceof IpcResponseError) throw error;
|
|
260
|
+
if (controller.signal.aborted) {
|
|
261
|
+
if (error === timeoutError) throw timeoutError;
|
|
262
|
+
throw new IpcTimeoutError(timeoutMs, { cause: error });
|
|
263
|
+
}
|
|
264
|
+
throw new IpcConnectionError(getErrorMessage(error), { cause: error });
|
|
134
265
|
} finally {
|
|
135
266
|
clearTimeout(timeout);
|
|
136
267
|
}
|
|
@@ -141,12 +272,15 @@ var AdofaiIpcNamespaceClient = class {
|
|
|
141
272
|
this.client = client;
|
|
142
273
|
this.namespace = namespace;
|
|
143
274
|
}
|
|
144
|
-
async call(method, params,
|
|
275
|
+
async call(method, params, idOrOptions, options = {}) {
|
|
276
|
+
const requestOptions = isIpcRequestOptions(idOrOptions) ? idOrOptions : options;
|
|
277
|
+
const id = isIpcRequestOptions(idOrOptions) ? void 0 : idOrOptions;
|
|
145
278
|
return this.client.call({
|
|
146
279
|
namespace: this.namespace,
|
|
147
280
|
method,
|
|
148
281
|
params,
|
|
149
|
-
id
|
|
282
|
+
id,
|
|
283
|
+
timeoutMs: requestOptions.timeoutMs
|
|
150
284
|
});
|
|
151
285
|
}
|
|
152
286
|
};
|
|
@@ -154,27 +288,80 @@ async function tryConnect(options = {}) {
|
|
|
154
288
|
const host = options.host ?? DEFAULT_HOST;
|
|
155
289
|
const startPort = options.startPort ?? DEFAULT_START_PORT;
|
|
156
290
|
const endPort = options.endPort ?? DEFAULT_END_PORT;
|
|
291
|
+
const probeTimeoutMs = options.probeTimeoutMs ?? options.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
292
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
293
|
+
let lastProbeError;
|
|
157
294
|
for (let port = startPort; port <= endPort; port++) {
|
|
158
295
|
const client = new AdofaiIpcClient({
|
|
159
296
|
baseUrl: `http://${host}:${port}`,
|
|
160
297
|
fetch: options.fetch,
|
|
161
|
-
|
|
298
|
+
requestTimeoutMs: probeTimeoutMs
|
|
162
299
|
});
|
|
163
300
|
try {
|
|
164
301
|
const health = await client.health();
|
|
165
302
|
if (health.ok && health.server === "AdofaiIpc") {
|
|
166
|
-
|
|
303
|
+
const mismatch = getVersionMismatch(health);
|
|
304
|
+
if (mismatch) {
|
|
305
|
+
try {
|
|
306
|
+
options.onVersionMismatch?.(mismatch);
|
|
307
|
+
} catch {
|
|
308
|
+
}
|
|
309
|
+
throw mismatch;
|
|
310
|
+
}
|
|
311
|
+
return new AdofaiIpcClient({
|
|
312
|
+
baseUrl: client.baseUrl,
|
|
313
|
+
fetch: options.fetch,
|
|
314
|
+
requestTimeoutMs
|
|
315
|
+
});
|
|
167
316
|
}
|
|
168
|
-
} catch {
|
|
317
|
+
} catch (error) {
|
|
318
|
+
if (error instanceof IpcVersionMismatchError) throw error;
|
|
319
|
+
lastProbeError = error;
|
|
169
320
|
}
|
|
170
321
|
}
|
|
322
|
+
if (lastProbeError instanceof IpcTimeoutError) throw lastProbeError;
|
|
171
323
|
throw new IpcConnectionError(
|
|
172
324
|
`Could not connect to AdofaiIpc on ${host}:${startPort}-${endPort}.`
|
|
173
325
|
);
|
|
174
326
|
}
|
|
327
|
+
function getVersionMismatch(health) {
|
|
328
|
+
const protocolVersion = Number.isInteger(health.protocolVersion) ? health.protocolVersion : null;
|
|
329
|
+
const serverVersion = typeof health.serverVersion === "string" ? health.serverVersion : null;
|
|
330
|
+
const comparison = serverVersion === null ? null : compareProductVersions(serverVersion, CLIENT_VERSION);
|
|
331
|
+
if (comparison === 0 && serverVersion === CLIENT_VERSION) return null;
|
|
332
|
+
return new IpcVersionMismatchError({
|
|
333
|
+
clientVersion: CLIENT_VERSION,
|
|
334
|
+
serverVersion,
|
|
335
|
+
direction: comparison === null ? "legacy_server" : comparison < 0 ? "server_outdated" : "client_outdated",
|
|
336
|
+
protocolVersion
|
|
337
|
+
});
|
|
338
|
+
}
|
|
175
339
|
function normalizeBaseUrl(value) {
|
|
176
340
|
return value.replace(/\/+$/, "");
|
|
177
341
|
}
|
|
342
|
+
function getErrorMessage(error) {
|
|
343
|
+
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
|
|
344
|
+
return error.message;
|
|
345
|
+
}
|
|
346
|
+
return void 0;
|
|
347
|
+
}
|
|
348
|
+
function parseIpcResponseError(text) {
|
|
349
|
+
try {
|
|
350
|
+
const value = JSON.parse(text);
|
|
351
|
+
const error = value?.error;
|
|
352
|
+
if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && "message" in error && typeof error.message === "string") {
|
|
353
|
+
return { code: error.code, message: error.message };
|
|
354
|
+
}
|
|
355
|
+
} catch {
|
|
356
|
+
}
|
|
357
|
+
return void 0;
|
|
358
|
+
}
|
|
359
|
+
function isIpcRequestOptions(value) {
|
|
360
|
+
return typeof value === "object" && value !== null;
|
|
361
|
+
}
|
|
362
|
+
function delay(timeoutMs) {
|
|
363
|
+
return new Promise((resolve) => setTimeout(resolve, timeoutMs));
|
|
364
|
+
}
|
|
178
365
|
function createRequestId() {
|
|
179
366
|
return `adofai-ipc-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
180
367
|
}
|
|
@@ -183,9 +370,13 @@ function createRequestId() {
|
|
|
183
370
|
AdofaiIpcClient,
|
|
184
371
|
AdofaiIpcError,
|
|
185
372
|
AdofaiIpcNamespaceClient,
|
|
373
|
+
CLIENT_VERSION,
|
|
186
374
|
IpcConnectionError,
|
|
187
375
|
IpcHttpError,
|
|
188
376
|
IpcResponseError,
|
|
377
|
+
IpcTimeoutError,
|
|
378
|
+
IpcVersionMismatchError,
|
|
379
|
+
isIpcUnavailable,
|
|
189
380
|
tryConnect
|
|
190
381
|
});
|
|
191
382
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":["export {\n AdofaiIpcClient,\n AdofaiIpcNamespaceClient,\n tryConnect\n} from \"./client\";\n\nexport {\n AdofaiIpcError,\n IpcConnectionError,\n IpcHttpError,\n IpcResponseError\n} from \"./errors\";\n\nexport type {\n AdofaiIpcClientOptions,\n IpcCallOptions,\n IpcErrorInfo,\n IpcErrorResponse,\n IpcHealthResponse,\n IpcNamespaceDetail,\n IpcNamespacesResponse,\n IpcNamespaceSummary,\n IpcRequestId,\n IpcResponse,\n IpcSuccessResponse,\n TryConnectOptions\n} from \"./types\";\n","import type { IpcErrorInfo } from \"./types\";\n\nexport class AdofaiIpcError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AdofaiIpcError\";\n }\n}\n\nexport class IpcConnectionError extends AdofaiIpcError {\n constructor(message = \"Could not connect to AdofaiIpc.\") {\n super(message);\n this.name = \"IpcConnectionError\";\n }\n}\n\nexport class IpcHttpError extends AdofaiIpcError {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"IpcHttpError\";\n this.status = status;\n }\n}\n\nexport class IpcResponseError extends AdofaiIpcError {\n readonly code: string;\n readonly error: IpcErrorInfo;\n\n constructor(error: IpcErrorInfo) {\n super(error.message);\n this.name = \"IpcResponseError\";\n this.code = error.code;\n this.error = error;\n }\n}\n","import { IpcConnectionError, IpcHttpError, IpcResponseError } from \"./errors\";\nimport type {\n AdofaiIpcClientOptions,\n IpcCallOptions,\n IpcHealthResponse,\n IpcNamespaceDetail,\n IpcNamespacesResponse,\n IpcResponse,\n TryConnectOptions\n} from \"./types\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_START_PORT = 32145;\nconst DEFAULT_END_PORT = 32155;\nconst DEFAULT_TIMEOUT_MS = 500;\n\nexport class AdofaiIpcClient {\n readonly baseUrl: string;\n\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(options: AdofaiIpcClientOptions = {}) {\n this.baseUrl = normalizeBaseUrl(options.baseUrl ?? `http://${DEFAULT_HOST}:${DEFAULT_START_PORT}`);\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n if (!this.fetchImpl) {\n throw new IpcConnectionError(\"A fetch implementation is required.\");\n }\n }\n\n static async connect(options: TryConnectOptions = {}): Promise<AdofaiIpcClient> {\n return tryConnect(options);\n }\n\n async health(): Promise<IpcHealthResponse> {\n return this.get<IpcHealthResponse>(\"/ipc/health\");\n }\n\n async listNamespaces(): Promise<IpcNamespacesResponse> {\n return this.get<IpcNamespacesResponse>(\"/ipc/namespaces\");\n }\n\n async getNamespace(namespace: string): Promise<IpcNamespaceDetail> {\n return this.get<IpcNamespaceDetail>(`/ipc/namespaces/${encodeURIComponent(namespace)}`);\n }\n\n namespace(namespace: string): AdofaiIpcNamespaceClient {\n return new AdofaiIpcNamespaceClient(this, namespace);\n }\n\n async call<TResult = unknown, TParams = unknown>(\n options: IpcCallOptions<TParams>\n ): Promise<TResult> {\n const response = await this.post<IpcResponse<TResult>>(\"/ipc\", {\n namespace: options.namespace,\n method: options.method,\n params: options.params ?? {},\n id: options.id ?? createRequestId()\n });\n\n if (!response.ok) {\n throw new IpcResponseError(response.error);\n }\n\n return response.result;\n }\n\n private async get<TResult>(path: string): Promise<TResult> {\n return this.request<TResult>(path, {\n method: \"GET\"\n });\n }\n\n private async post<TResult>(path: string, body: unknown): Promise<TResult> {\n return this.request<TResult>(path, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(body)\n });\n }\n\n private async request<TResult>(path: string, init: RequestInit): Promise<TResult> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n const response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n ...init,\n signal: controller.signal\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new IpcHttpError(response.status, text || response.statusText);\n }\n\n return (await response.json()) as TResult;\n } catch (error) {\n if (error instanceof IpcHttpError) throw error;\n if (error instanceof Error) throw new IpcConnectionError(error.message);\n throw new IpcConnectionError();\n } finally {\n clearTimeout(timeout);\n }\n }\n}\n\nexport class AdofaiIpcNamespaceClient {\n constructor(\n private readonly client: AdofaiIpcClient,\n readonly namespace: string\n ) {\n }\n\n async call<TResult = unknown, TParams = unknown>(\n method: string,\n params?: TParams,\n id?: string\n ): Promise<TResult> {\n return this.client.call<TResult, TParams>({\n namespace: this.namespace,\n method,\n params,\n id\n });\n }\n}\n\nexport async function tryConnect(options: TryConnectOptions = {}): Promise<AdofaiIpcClient> {\n const host = options.host ?? DEFAULT_HOST;\n const startPort = options.startPort ?? DEFAULT_START_PORT;\n const endPort = options.endPort ?? DEFAULT_END_PORT;\n\n for (let port = startPort; port <= endPort; port++) {\n const client = new AdofaiIpcClient({\n baseUrl: `http://${host}:${port}`,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs\n });\n\n try {\n const health = await client.health();\n\n if (health.ok && health.server === \"AdofaiIpc\") {\n return client;\n }\n } catch {\n }\n }\n\n throw new IpcConnectionError(\n `Could not connect to AdofaiIpc on ${host}:${startPort}-${endPort}.`\n );\n}\n\nfunction normalizeBaseUrl(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\nfunction createRequestId(): string {\n return `adofai-ipc-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/version.ts","../src/client.ts"],"sourcesContent":["export {\n AdofaiIpcClient,\n AdofaiIpcNamespaceClient,\n tryConnect\n} from \"./client\";\n\nexport {\n AdofaiIpcError,\n IpcConnectionError,\n IpcHttpError,\n IpcResponseError,\n IpcTimeoutError,\n IpcVersionMismatchError,\n isIpcUnavailable\n} from \"./errors\";\n\nexport type {\n IpcConnectionErrorCode,\n IpcConnectionErrorOptions,\n IpcVersionMismatchDirection\n} from \"./errors\";\n\nexport { CLIENT_VERSION } from \"./version\";\n\nexport type {\n AdofaiIpcClientOptions,\n IpcCallOptions,\n IpcErrorInfo,\n IpcErrorResponse,\n IpcHealthResponse,\n IpcNamespaceDetail,\n IpcNamespaceErrorInfo,\n IpcNamespaceStatus,\n IpcNamespacesResponse,\n IpcNamespaceSummary,\n IpcRequestId,\n IpcRequestOptions,\n IpcResponse,\n IpcSuccessResponse,\n TryConnectOptions,\n WaitForNamespaceOptions\n} from \"./types\";\n","import type { IpcErrorInfo } from \"./types\";\n\nexport type IpcConnectionErrorCode = \"UNAVAILABLE\" | \"TIMEOUT\";\nexport type IpcVersionMismatchDirection =\n | \"server_outdated\"\n | \"client_outdated\"\n | \"legacy_server\";\n\nexport interface IpcConnectionErrorOptions {\n code?: IpcConnectionErrorCode;\n cause?: unknown;\n}\n\nexport class AdofaiIpcError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AdofaiIpcError\";\n }\n}\n\nexport class IpcConnectionError extends AdofaiIpcError {\n readonly code: IpcConnectionErrorCode;\n readonly cause?: unknown;\n\n constructor(\n message = \"Could not connect to AdofaiIpc.\",\n options: IpcConnectionErrorOptions = {}\n ) {\n super(message);\n this.name = \"IpcConnectionError\";\n this.code = options.code ?? \"UNAVAILABLE\";\n this.cause = options.cause;\n }\n}\n\nexport class IpcTimeoutError extends IpcConnectionError {\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number, options: Pick<IpcConnectionErrorOptions, \"cause\"> = {}) {\n super(`AdofaiIpc request timed out after ${timeoutMs} ms.`, {\n code: \"TIMEOUT\",\n cause: options.cause\n });\n this.name = \"IpcTimeoutError\";\n this.timeoutMs = timeoutMs;\n }\n}\n\nexport class IpcVersionMismatchError extends AdofaiIpcError {\n readonly code = \"VERSION_MISMATCH\" as const;\n readonly clientVersion: string;\n readonly serverVersion: string | null;\n readonly direction: IpcVersionMismatchDirection;\n readonly protocolVersion: number | null;\n\n constructor(options: {\n clientVersion: string;\n serverVersion: string | null;\n direction: IpcVersionMismatchDirection;\n protocolVersion: number | null;\n }) {\n const server = options.serverVersion ?? \"legacy/unknown\";\n super(`AdofaiIpc version mismatch: client ${options.clientVersion}, server ${server}.`);\n this.name = \"IpcVersionMismatchError\";\n this.clientVersion = options.clientVersion;\n this.serverVersion = options.serverVersion;\n this.direction = options.direction;\n this.protocolVersion = options.protocolVersion;\n }\n}\n\nexport function isIpcUnavailable(error: unknown): error is IpcConnectionError {\n return error instanceof IpcConnectionError && error.code === \"UNAVAILABLE\";\n}\n\nexport class IpcHttpError extends AdofaiIpcError {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"IpcHttpError\";\n this.status = status;\n }\n}\n\nexport class IpcResponseError extends AdofaiIpcError {\n readonly code: string;\n readonly error: IpcErrorInfo;\n\n constructor(error: IpcErrorInfo) {\n super(error.message);\n this.name = \"IpcResponseError\";\n this.code = error.code;\n this.error = error;\n }\n}\n","declare const __CLIENT_VERSION__: string;\n\nexport const CLIENT_VERSION = __CLIENT_VERSION__;\n\nconst CANONICAL_SEMVER = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*))*))?$/;\n\ninterface ParsedVersion {\n core: [number, number, number];\n prerelease: string[] | null;\n}\n\nexport function compareProductVersions(left: string, right: string): number | null {\n const leftVersion = parseProductVersion(left);\n const rightVersion = parseProductVersion(right);\n if (!leftVersion || !rightVersion) return null;\n\n for (let index = 0; index < leftVersion.core.length; index++) {\n const difference = leftVersion.core[index]! - rightVersion.core[index]!;\n if (difference !== 0) return difference < 0 ? -1 : 1;\n }\n\n if (leftVersion.prerelease === null) return rightVersion.prerelease === null ? 0 : 1;\n if (rightVersion.prerelease === null) return -1;\n\n const length = Math.max(leftVersion.prerelease.length, rightVersion.prerelease.length);\n for (let index = 0; index < length; index++) {\n const leftPart = leftVersion.prerelease[index];\n const rightPart = rightVersion.prerelease[index];\n if (leftPart === undefined) return -1;\n if (rightPart === undefined) return 1;\n if (leftPart === rightPart) continue;\n\n const leftNumeric = /^\\d+$/.test(leftPart);\n const rightNumeric = /^\\d+$/.test(rightPart);\n if (leftNumeric && rightNumeric) return Number(leftPart) < Number(rightPart) ? -1 : 1;\n if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;\n return leftPart < rightPart ? -1 : 1;\n }\n\n return 0;\n}\n\nfunction parseProductVersion(value: string): ParsedVersion | null {\n const match = CANONICAL_SEMVER.exec(value);\n if (!match) return null;\n return {\n core: [Number(match[1]), Number(match[2]), Number(match[3])],\n prerelease: match[4] ? match[4].split(\".\") : null\n };\n}\n","import {\n IpcConnectionError,\n IpcHttpError,\n IpcResponseError,\n IpcTimeoutError,\n IpcVersionMismatchError\n} from \"./errors\";\nimport { CLIENT_VERSION, compareProductVersions } from \"./version\";\nimport type {\n AdofaiIpcClientOptions,\n IpcCallOptions,\n IpcErrorInfo,\n IpcHealthResponse,\n IpcNamespaceDetail,\n IpcNamespacesResponse,\n IpcRequestId,\n IpcRequestOptions,\n IpcResponse,\n TryConnectOptions,\n WaitForNamespaceOptions\n} from \"./types\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_START_PORT = 32145;\nconst DEFAULT_END_PORT = 32155;\nconst DEFAULT_PROBE_TIMEOUT_MS = 500;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 10_000;\nconst DEFAULT_NAMESPACE_WAIT_TIMEOUT_MS = 10_000;\nconst DEFAULT_NAMESPACE_POLL_INTERVAL_MS = 100;\n\nexport class AdofaiIpcClient {\n readonly baseUrl: string;\n\n private readonly fetchImpl: typeof fetch;\n private readonly requestTimeoutMs: number;\n\n constructor(options: AdofaiIpcClientOptions = {}) {\n this.baseUrl = normalizeBaseUrl(options.baseUrl ?? `http://${DEFAULT_HOST}:${DEFAULT_START_PORT}`);\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n this.requestTimeoutMs =\n options.requestTimeoutMs ?? options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n\n if (!this.fetchImpl) {\n throw new IpcConnectionError(\"A fetch implementation is required.\");\n }\n }\n\n static async connect(options: TryConnectOptions = {}): Promise<AdofaiIpcClient> {\n return tryConnect(options);\n }\n\n async health(options: IpcRequestOptions = {}): Promise<IpcHealthResponse> {\n return this.get<IpcHealthResponse>(\"/ipc/health\", options);\n }\n\n async listNamespaces(options: IpcRequestOptions = {}): Promise<IpcNamespacesResponse> {\n return this.get<IpcNamespacesResponse>(\"/ipc/namespaces\", options);\n }\n\n async getNamespace(\n namespace: string,\n options: IpcRequestOptions = {}\n ): Promise<IpcNamespaceDetail> {\n return this.get<IpcNamespaceDetail>(\n `/ipc/namespaces/${encodeURIComponent(namespace)}`,\n options\n );\n }\n\n async waitForNamespace(\n namespace: string,\n options: WaitForNamespaceOptions = {}\n ): Promise<IpcNamespaceDetail> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_NAMESPACE_WAIT_TIMEOUT_MS;\n const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_NAMESPACE_POLL_INTERVAL_MS;\n const requiredStatus = options.status ?? \"registered\";\n const deadline = Date.now() + timeoutMs;\n let stateError: IpcResponseError | undefined;\n\n while (true) {\n try {\n const detail = await this.getNamespace(namespace, {\n timeoutMs: options.requestTimeoutMs\n });\n\n if (requiredStatus === \"registered\" || detail.status === \"ready\") {\n return detail;\n }\n\n if (detail.status === \"error\") {\n throw new IpcResponseError({\n code: \"namespace_error\",\n message: detail.error?.message ?? `Namespace initialization failed: ${namespace}`\n });\n }\n\n if (detail.status !== \"initializing\") {\n throw new IpcResponseError({\n code: \"namespace_status_unavailable\",\n message: `Namespace status is unavailable: ${namespace}`\n });\n }\n\n stateError = new IpcResponseError({\n code: \"namespace_initializing\",\n message: `Namespace is initializing: ${namespace}`\n });\n } catch (error) {\n if (\n !(error instanceof IpcResponseError) ||\n (error.code !== \"namespace_not_found\" && error.code !== \"namespace_initializing\")\n ) {\n throw error;\n }\n\n stateError = error;\n }\n\n const remainingMs = deadline - Date.now();\n if (remainingMs <= 0) {\n throw stateError ?? new IpcResponseError({\n code: \"namespace_initializing\",\n message: `Namespace is initializing: ${namespace}`\n });\n }\n\n await delay(Math.min(pollIntervalMs, remainingMs));\n }\n }\n\n namespace(namespace: string): AdofaiIpcNamespaceClient {\n return new AdofaiIpcNamespaceClient(this, namespace);\n }\n\n async call<TResult = unknown, TParams = unknown>(\n options: IpcCallOptions<TParams>\n ): Promise<TResult> {\n const response = await this.post<IpcResponse<TResult>>(\n \"/ipc\",\n {\n namespace: options.namespace,\n method: options.method,\n params: options.params ?? {},\n id: options.id ?? createRequestId()\n },\n { timeoutMs: options.timeoutMs }\n );\n\n if (!response.ok) {\n throw new IpcResponseError(response.error);\n }\n\n return response.result;\n }\n\n private async get<TResult>(\n path: string,\n options: IpcRequestOptions = {}\n ): Promise<TResult> {\n return this.request<TResult>(path, {\n method: \"GET\"\n }, options);\n }\n\n private async post<TResult>(\n path: string,\n body: unknown,\n options: IpcRequestOptions = {}\n ): Promise<TResult> {\n return this.request<TResult>(path, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(body)\n }, options);\n }\n\n private async request<TResult>(\n path: string,\n init: RequestInit,\n options: IpcRequestOptions\n ): Promise<TResult> {\n const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;\n const controller = new AbortController();\n const timeoutError = new IpcTimeoutError(timeoutMs);\n const timeout = setTimeout(() => controller.abort(timeoutError), timeoutMs);\n\n try {\n const response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n ...init,\n signal: controller.signal\n });\n\n if (!response.ok) {\n const text = await response.text();\n const responseError = parseIpcResponseError(text);\n if (responseError) throw new IpcResponseError(responseError);\n throw new IpcHttpError(response.status, text || response.statusText);\n }\n\n return (await response.json()) as TResult;\n } catch (error) {\n if (error instanceof IpcHttpError || error instanceof IpcResponseError) throw error;\n if (controller.signal.aborted) {\n if (error === timeoutError) throw timeoutError;\n throw new IpcTimeoutError(timeoutMs, { cause: error });\n }\n throw new IpcConnectionError(getErrorMessage(error), { cause: error });\n } finally {\n clearTimeout(timeout);\n }\n }\n}\n\nexport class AdofaiIpcNamespaceClient {\n constructor(\n private readonly client: AdofaiIpcClient,\n readonly namespace: string\n ) {\n }\n\n async call<TResult = unknown, TParams = unknown>(\n method: string,\n params?: TParams,\n idOrOptions?: IpcRequestId | IpcRequestOptions,\n options: IpcRequestOptions = {}\n ): Promise<TResult> {\n const requestOptions = isIpcRequestOptions(idOrOptions) ? idOrOptions : options;\n const id = isIpcRequestOptions(idOrOptions) ? undefined : idOrOptions;\n\n return this.client.call<TResult, TParams>({\n namespace: this.namespace,\n method,\n params,\n id,\n timeoutMs: requestOptions.timeoutMs\n });\n }\n}\n\nexport async function tryConnect(options: TryConnectOptions = {}): Promise<AdofaiIpcClient> {\n const host = options.host ?? DEFAULT_HOST;\n const startPort = options.startPort ?? DEFAULT_START_PORT;\n const endPort = options.endPort ?? DEFAULT_END_PORT;\n const probeTimeoutMs =\n options.probeTimeoutMs ?? options.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;\n const requestTimeoutMs =\n options.requestTimeoutMs ?? options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n let lastProbeError: unknown;\n\n for (let port = startPort; port <= endPort; port++) {\n const client = new AdofaiIpcClient({\n baseUrl: `http://${host}:${port}`,\n fetch: options.fetch,\n requestTimeoutMs: probeTimeoutMs\n });\n\n try {\n const health = await client.health();\n\n if (health.ok && health.server === \"AdofaiIpc\") {\n const mismatch = getVersionMismatch(health);\n if (mismatch) {\n try {\n options.onVersionMismatch?.(mismatch);\n } catch {\n }\n throw mismatch;\n }\n return new AdofaiIpcClient({\n baseUrl: client.baseUrl,\n fetch: options.fetch,\n requestTimeoutMs\n });\n }\n } catch (error) {\n if (error instanceof IpcVersionMismatchError) throw error;\n lastProbeError = error;\n }\n }\n\n if (lastProbeError instanceof IpcTimeoutError) throw lastProbeError;\n\n throw new IpcConnectionError(\n `Could not connect to AdofaiIpc on ${host}:${startPort}-${endPort}.`\n );\n}\n\nfunction getVersionMismatch(health: IpcHealthResponse): IpcVersionMismatchError | null {\n const protocolVersion = Number.isInteger(health.protocolVersion) ? health.protocolVersion : null;\n const serverVersion = typeof health.serverVersion === \"string\" ? health.serverVersion : null;\n const comparison = serverVersion === null\n ? null\n : compareProductVersions(serverVersion, CLIENT_VERSION);\n\n if (comparison === 0 && serverVersion === CLIENT_VERSION) return null;\n\n return new IpcVersionMismatchError({\n clientVersion: CLIENT_VERSION,\n serverVersion,\n direction: comparison === null\n ? \"legacy_server\"\n : comparison < 0\n ? \"server_outdated\"\n : \"client_outdated\",\n protocolVersion\n });\n}\n\nfunction normalizeBaseUrl(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\nfunction getErrorMessage(error: unknown): string | undefined {\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n\n return undefined;\n}\n\nfunction parseIpcResponseError(text: string): IpcErrorInfo | undefined {\n try {\n const value = JSON.parse(text) as { error?: unknown };\n const error = value?.error;\n\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n typeof error.code === \"string\" &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return { code: error.code, message: error.message };\n }\n } catch {\n }\n\n return undefined;\n}\n\nfunction isIpcRequestOptions(value: unknown): value is IpcRequestOptions {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction delay(timeoutMs: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, timeoutMs));\n}\n\nfunction createRequestId(): string {\n return `adofai-ipc-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,9 +1,61 @@
|
|
|
1
|
+
type IpcConnectionErrorCode = "UNAVAILABLE" | "TIMEOUT";
|
|
2
|
+
type IpcVersionMismatchDirection = "server_outdated" | "client_outdated" | "legacy_server";
|
|
3
|
+
interface IpcConnectionErrorOptions {
|
|
4
|
+
code?: IpcConnectionErrorCode;
|
|
5
|
+
cause?: unknown;
|
|
6
|
+
}
|
|
7
|
+
declare class AdofaiIpcError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
declare class IpcConnectionError extends AdofaiIpcError {
|
|
11
|
+
readonly code: IpcConnectionErrorCode;
|
|
12
|
+
readonly cause?: unknown;
|
|
13
|
+
constructor(message?: string, options?: IpcConnectionErrorOptions);
|
|
14
|
+
}
|
|
15
|
+
declare class IpcTimeoutError extends IpcConnectionError {
|
|
16
|
+
readonly timeoutMs: number;
|
|
17
|
+
constructor(timeoutMs: number, options?: Pick<IpcConnectionErrorOptions, "cause">);
|
|
18
|
+
}
|
|
19
|
+
declare class IpcVersionMismatchError extends AdofaiIpcError {
|
|
20
|
+
readonly code: "VERSION_MISMATCH";
|
|
21
|
+
readonly clientVersion: string;
|
|
22
|
+
readonly serverVersion: string | null;
|
|
23
|
+
readonly direction: IpcVersionMismatchDirection;
|
|
24
|
+
readonly protocolVersion: number | null;
|
|
25
|
+
constructor(options: {
|
|
26
|
+
clientVersion: string;
|
|
27
|
+
serverVersion: string | null;
|
|
28
|
+
direction: IpcVersionMismatchDirection;
|
|
29
|
+
protocolVersion: number | null;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
declare function isIpcUnavailable(error: unknown): error is IpcConnectionError;
|
|
33
|
+
declare class IpcHttpError extends AdofaiIpcError {
|
|
34
|
+
readonly status: number;
|
|
35
|
+
constructor(status: number, message: string);
|
|
36
|
+
}
|
|
37
|
+
declare class IpcResponseError extends AdofaiIpcError {
|
|
38
|
+
readonly code: string;
|
|
39
|
+
readonly error: IpcErrorInfo;
|
|
40
|
+
constructor(error: IpcErrorInfo);
|
|
41
|
+
}
|
|
42
|
+
|
|
1
43
|
type IpcRequestId = string | number | null;
|
|
2
44
|
interface IpcCallOptions<TParams = unknown> {
|
|
3
45
|
namespace: string;
|
|
4
46
|
method: string;
|
|
5
47
|
params?: TParams;
|
|
6
48
|
id?: IpcRequestId;
|
|
49
|
+
timeoutMs?: number;
|
|
50
|
+
}
|
|
51
|
+
interface IpcRequestOptions {
|
|
52
|
+
timeoutMs?: number;
|
|
53
|
+
}
|
|
54
|
+
interface WaitForNamespaceOptions {
|
|
55
|
+
timeoutMs?: number;
|
|
56
|
+
pollIntervalMs?: number;
|
|
57
|
+
requestTimeoutMs?: number;
|
|
58
|
+
status?: "registered" | "ready";
|
|
7
59
|
}
|
|
8
60
|
interface IpcSuccessResponse<TResult = unknown> {
|
|
9
61
|
ok: true;
|
|
@@ -24,13 +76,20 @@ type IpcResponse<TResult = unknown> = IpcSuccessResponse<TResult> | IpcErrorResp
|
|
|
24
76
|
interface IpcHealthResponse {
|
|
25
77
|
ok: true;
|
|
26
78
|
server: "AdofaiIpc";
|
|
79
|
+
serverVersion?: string;
|
|
27
80
|
protocolVersion: number;
|
|
28
81
|
port: number;
|
|
29
82
|
}
|
|
83
|
+
type IpcNamespaceStatus = "initializing" | "ready" | "error";
|
|
84
|
+
interface IpcNamespaceErrorInfo {
|
|
85
|
+
code: string;
|
|
86
|
+
message: string;
|
|
87
|
+
}
|
|
30
88
|
interface IpcNamespaceSummary {
|
|
31
89
|
name: string;
|
|
32
90
|
displayName: string;
|
|
33
91
|
version: string;
|
|
92
|
+
status: IpcNamespaceStatus;
|
|
34
93
|
}
|
|
35
94
|
interface IpcNamespacesResponse {
|
|
36
95
|
namespaces: IpcNamespaceSummary[];
|
|
@@ -39,11 +98,15 @@ interface IpcNamespaceDetail {
|
|
|
39
98
|
namespace: string;
|
|
40
99
|
displayName: string;
|
|
41
100
|
version: string;
|
|
101
|
+
status: IpcNamespaceStatus;
|
|
102
|
+
error?: IpcNamespaceErrorInfo | null;
|
|
42
103
|
methods: string[];
|
|
43
104
|
}
|
|
44
105
|
interface AdofaiIpcClientOptions {
|
|
45
106
|
baseUrl?: string;
|
|
46
107
|
fetch?: typeof fetch;
|
|
108
|
+
requestTimeoutMs?: number;
|
|
109
|
+
/** @deprecated Use requestTimeoutMs instead. */
|
|
47
110
|
timeoutMs?: number;
|
|
48
111
|
}
|
|
49
112
|
interface TryConnectOptions {
|
|
@@ -51,18 +114,23 @@ interface TryConnectOptions {
|
|
|
51
114
|
startPort?: number;
|
|
52
115
|
endPort?: number;
|
|
53
116
|
fetch?: typeof fetch;
|
|
117
|
+
probeTimeoutMs?: number;
|
|
118
|
+
requestTimeoutMs?: number;
|
|
119
|
+
onVersionMismatch?: (error: IpcVersionMismatchError) => void;
|
|
120
|
+
/** @deprecated Use probeTimeoutMs and requestTimeoutMs instead. */
|
|
54
121
|
timeoutMs?: number;
|
|
55
122
|
}
|
|
56
123
|
|
|
57
124
|
declare class AdofaiIpcClient {
|
|
58
125
|
readonly baseUrl: string;
|
|
59
126
|
private readonly fetchImpl;
|
|
60
|
-
private readonly
|
|
127
|
+
private readonly requestTimeoutMs;
|
|
61
128
|
constructor(options?: AdofaiIpcClientOptions);
|
|
62
129
|
static connect(options?: TryConnectOptions): Promise<AdofaiIpcClient>;
|
|
63
|
-
health(): Promise<IpcHealthResponse>;
|
|
64
|
-
listNamespaces(): Promise<IpcNamespacesResponse>;
|
|
65
|
-
getNamespace(namespace: string): Promise<IpcNamespaceDetail>;
|
|
130
|
+
health(options?: IpcRequestOptions): Promise<IpcHealthResponse>;
|
|
131
|
+
listNamespaces(options?: IpcRequestOptions): Promise<IpcNamespacesResponse>;
|
|
132
|
+
getNamespace(namespace: string, options?: IpcRequestOptions): Promise<IpcNamespaceDetail>;
|
|
133
|
+
waitForNamespace(namespace: string, options?: WaitForNamespaceOptions): Promise<IpcNamespaceDetail>;
|
|
66
134
|
namespace(namespace: string): AdofaiIpcNamespaceClient;
|
|
67
135
|
call<TResult = unknown, TParams = unknown>(options: IpcCallOptions<TParams>): Promise<TResult>;
|
|
68
136
|
private get;
|
|
@@ -73,24 +141,10 @@ declare class AdofaiIpcNamespaceClient {
|
|
|
73
141
|
private readonly client;
|
|
74
142
|
readonly namespace: string;
|
|
75
143
|
constructor(client: AdofaiIpcClient, namespace: string);
|
|
76
|
-
call<TResult = unknown, TParams = unknown>(method: string, params?: TParams,
|
|
144
|
+
call<TResult = unknown, TParams = unknown>(method: string, params?: TParams, idOrOptions?: IpcRequestId | IpcRequestOptions, options?: IpcRequestOptions): Promise<TResult>;
|
|
77
145
|
}
|
|
78
146
|
declare function tryConnect(options?: TryConnectOptions): Promise<AdofaiIpcClient>;
|
|
79
147
|
|
|
80
|
-
declare
|
|
81
|
-
constructor(message: string);
|
|
82
|
-
}
|
|
83
|
-
declare class IpcConnectionError extends AdofaiIpcError {
|
|
84
|
-
constructor(message?: string);
|
|
85
|
-
}
|
|
86
|
-
declare class IpcHttpError extends AdofaiIpcError {
|
|
87
|
-
readonly status: number;
|
|
88
|
-
constructor(status: number, message: string);
|
|
89
|
-
}
|
|
90
|
-
declare class IpcResponseError extends AdofaiIpcError {
|
|
91
|
-
readonly code: string;
|
|
92
|
-
readonly error: IpcErrorInfo;
|
|
93
|
-
constructor(error: IpcErrorInfo);
|
|
94
|
-
}
|
|
148
|
+
declare const CLIENT_VERSION: string;
|
|
95
149
|
|
|
96
|
-
export { AdofaiIpcClient, type AdofaiIpcClientOptions, AdofaiIpcError, AdofaiIpcNamespaceClient, type IpcCallOptions, IpcConnectionError, type IpcErrorInfo, type IpcErrorResponse, type IpcHealthResponse, IpcHttpError, type IpcNamespaceDetail, type IpcNamespaceSummary, type IpcNamespacesResponse, type IpcRequestId, type IpcResponse, IpcResponseError, type IpcSuccessResponse, type TryConnectOptions, tryConnect };
|
|
150
|
+
export { AdofaiIpcClient, type AdofaiIpcClientOptions, AdofaiIpcError, AdofaiIpcNamespaceClient, CLIENT_VERSION, type IpcCallOptions, IpcConnectionError, type IpcConnectionErrorCode, type IpcConnectionErrorOptions, type IpcErrorInfo, type IpcErrorResponse, type IpcHealthResponse, IpcHttpError, type IpcNamespaceDetail, type IpcNamespaceErrorInfo, type IpcNamespaceStatus, type IpcNamespaceSummary, type IpcNamespacesResponse, type IpcRequestId, type IpcRequestOptions, type IpcResponse, IpcResponseError, type IpcSuccessResponse, IpcTimeoutError, type IpcVersionMismatchDirection, IpcVersionMismatchError, type TryConnectOptions, type WaitForNamespaceOptions, isIpcUnavailable, tryConnect };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,61 @@
|
|
|
1
|
+
type IpcConnectionErrorCode = "UNAVAILABLE" | "TIMEOUT";
|
|
2
|
+
type IpcVersionMismatchDirection = "server_outdated" | "client_outdated" | "legacy_server";
|
|
3
|
+
interface IpcConnectionErrorOptions {
|
|
4
|
+
code?: IpcConnectionErrorCode;
|
|
5
|
+
cause?: unknown;
|
|
6
|
+
}
|
|
7
|
+
declare class AdofaiIpcError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
declare class IpcConnectionError extends AdofaiIpcError {
|
|
11
|
+
readonly code: IpcConnectionErrorCode;
|
|
12
|
+
readonly cause?: unknown;
|
|
13
|
+
constructor(message?: string, options?: IpcConnectionErrorOptions);
|
|
14
|
+
}
|
|
15
|
+
declare class IpcTimeoutError extends IpcConnectionError {
|
|
16
|
+
readonly timeoutMs: number;
|
|
17
|
+
constructor(timeoutMs: number, options?: Pick<IpcConnectionErrorOptions, "cause">);
|
|
18
|
+
}
|
|
19
|
+
declare class IpcVersionMismatchError extends AdofaiIpcError {
|
|
20
|
+
readonly code: "VERSION_MISMATCH";
|
|
21
|
+
readonly clientVersion: string;
|
|
22
|
+
readonly serverVersion: string | null;
|
|
23
|
+
readonly direction: IpcVersionMismatchDirection;
|
|
24
|
+
readonly protocolVersion: number | null;
|
|
25
|
+
constructor(options: {
|
|
26
|
+
clientVersion: string;
|
|
27
|
+
serverVersion: string | null;
|
|
28
|
+
direction: IpcVersionMismatchDirection;
|
|
29
|
+
protocolVersion: number | null;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
declare function isIpcUnavailable(error: unknown): error is IpcConnectionError;
|
|
33
|
+
declare class IpcHttpError extends AdofaiIpcError {
|
|
34
|
+
readonly status: number;
|
|
35
|
+
constructor(status: number, message: string);
|
|
36
|
+
}
|
|
37
|
+
declare class IpcResponseError extends AdofaiIpcError {
|
|
38
|
+
readonly code: string;
|
|
39
|
+
readonly error: IpcErrorInfo;
|
|
40
|
+
constructor(error: IpcErrorInfo);
|
|
41
|
+
}
|
|
42
|
+
|
|
1
43
|
type IpcRequestId = string | number | null;
|
|
2
44
|
interface IpcCallOptions<TParams = unknown> {
|
|
3
45
|
namespace: string;
|
|
4
46
|
method: string;
|
|
5
47
|
params?: TParams;
|
|
6
48
|
id?: IpcRequestId;
|
|
49
|
+
timeoutMs?: number;
|
|
50
|
+
}
|
|
51
|
+
interface IpcRequestOptions {
|
|
52
|
+
timeoutMs?: number;
|
|
53
|
+
}
|
|
54
|
+
interface WaitForNamespaceOptions {
|
|
55
|
+
timeoutMs?: number;
|
|
56
|
+
pollIntervalMs?: number;
|
|
57
|
+
requestTimeoutMs?: number;
|
|
58
|
+
status?: "registered" | "ready";
|
|
7
59
|
}
|
|
8
60
|
interface IpcSuccessResponse<TResult = unknown> {
|
|
9
61
|
ok: true;
|
|
@@ -24,13 +76,20 @@ type IpcResponse<TResult = unknown> = IpcSuccessResponse<TResult> | IpcErrorResp
|
|
|
24
76
|
interface IpcHealthResponse {
|
|
25
77
|
ok: true;
|
|
26
78
|
server: "AdofaiIpc";
|
|
79
|
+
serverVersion?: string;
|
|
27
80
|
protocolVersion: number;
|
|
28
81
|
port: number;
|
|
29
82
|
}
|
|
83
|
+
type IpcNamespaceStatus = "initializing" | "ready" | "error";
|
|
84
|
+
interface IpcNamespaceErrorInfo {
|
|
85
|
+
code: string;
|
|
86
|
+
message: string;
|
|
87
|
+
}
|
|
30
88
|
interface IpcNamespaceSummary {
|
|
31
89
|
name: string;
|
|
32
90
|
displayName: string;
|
|
33
91
|
version: string;
|
|
92
|
+
status: IpcNamespaceStatus;
|
|
34
93
|
}
|
|
35
94
|
interface IpcNamespacesResponse {
|
|
36
95
|
namespaces: IpcNamespaceSummary[];
|
|
@@ -39,11 +98,15 @@ interface IpcNamespaceDetail {
|
|
|
39
98
|
namespace: string;
|
|
40
99
|
displayName: string;
|
|
41
100
|
version: string;
|
|
101
|
+
status: IpcNamespaceStatus;
|
|
102
|
+
error?: IpcNamespaceErrorInfo | null;
|
|
42
103
|
methods: string[];
|
|
43
104
|
}
|
|
44
105
|
interface AdofaiIpcClientOptions {
|
|
45
106
|
baseUrl?: string;
|
|
46
107
|
fetch?: typeof fetch;
|
|
108
|
+
requestTimeoutMs?: number;
|
|
109
|
+
/** @deprecated Use requestTimeoutMs instead. */
|
|
47
110
|
timeoutMs?: number;
|
|
48
111
|
}
|
|
49
112
|
interface TryConnectOptions {
|
|
@@ -51,18 +114,23 @@ interface TryConnectOptions {
|
|
|
51
114
|
startPort?: number;
|
|
52
115
|
endPort?: number;
|
|
53
116
|
fetch?: typeof fetch;
|
|
117
|
+
probeTimeoutMs?: number;
|
|
118
|
+
requestTimeoutMs?: number;
|
|
119
|
+
onVersionMismatch?: (error: IpcVersionMismatchError) => void;
|
|
120
|
+
/** @deprecated Use probeTimeoutMs and requestTimeoutMs instead. */
|
|
54
121
|
timeoutMs?: number;
|
|
55
122
|
}
|
|
56
123
|
|
|
57
124
|
declare class AdofaiIpcClient {
|
|
58
125
|
readonly baseUrl: string;
|
|
59
126
|
private readonly fetchImpl;
|
|
60
|
-
private readonly
|
|
127
|
+
private readonly requestTimeoutMs;
|
|
61
128
|
constructor(options?: AdofaiIpcClientOptions);
|
|
62
129
|
static connect(options?: TryConnectOptions): Promise<AdofaiIpcClient>;
|
|
63
|
-
health(): Promise<IpcHealthResponse>;
|
|
64
|
-
listNamespaces(): Promise<IpcNamespacesResponse>;
|
|
65
|
-
getNamespace(namespace: string): Promise<IpcNamespaceDetail>;
|
|
130
|
+
health(options?: IpcRequestOptions): Promise<IpcHealthResponse>;
|
|
131
|
+
listNamespaces(options?: IpcRequestOptions): Promise<IpcNamespacesResponse>;
|
|
132
|
+
getNamespace(namespace: string, options?: IpcRequestOptions): Promise<IpcNamespaceDetail>;
|
|
133
|
+
waitForNamespace(namespace: string, options?: WaitForNamespaceOptions): Promise<IpcNamespaceDetail>;
|
|
66
134
|
namespace(namespace: string): AdofaiIpcNamespaceClient;
|
|
67
135
|
call<TResult = unknown, TParams = unknown>(options: IpcCallOptions<TParams>): Promise<TResult>;
|
|
68
136
|
private get;
|
|
@@ -73,24 +141,10 @@ declare class AdofaiIpcNamespaceClient {
|
|
|
73
141
|
private readonly client;
|
|
74
142
|
readonly namespace: string;
|
|
75
143
|
constructor(client: AdofaiIpcClient, namespace: string);
|
|
76
|
-
call<TResult = unknown, TParams = unknown>(method: string, params?: TParams,
|
|
144
|
+
call<TResult = unknown, TParams = unknown>(method: string, params?: TParams, idOrOptions?: IpcRequestId | IpcRequestOptions, options?: IpcRequestOptions): Promise<TResult>;
|
|
77
145
|
}
|
|
78
146
|
declare function tryConnect(options?: TryConnectOptions): Promise<AdofaiIpcClient>;
|
|
79
147
|
|
|
80
|
-
declare
|
|
81
|
-
constructor(message: string);
|
|
82
|
-
}
|
|
83
|
-
declare class IpcConnectionError extends AdofaiIpcError {
|
|
84
|
-
constructor(message?: string);
|
|
85
|
-
}
|
|
86
|
-
declare class IpcHttpError extends AdofaiIpcError {
|
|
87
|
-
readonly status: number;
|
|
88
|
-
constructor(status: number, message: string);
|
|
89
|
-
}
|
|
90
|
-
declare class IpcResponseError extends AdofaiIpcError {
|
|
91
|
-
readonly code: string;
|
|
92
|
-
readonly error: IpcErrorInfo;
|
|
93
|
-
constructor(error: IpcErrorInfo);
|
|
94
|
-
}
|
|
148
|
+
declare const CLIENT_VERSION: string;
|
|
95
149
|
|
|
96
|
-
export { AdofaiIpcClient, type AdofaiIpcClientOptions, AdofaiIpcError, AdofaiIpcNamespaceClient, type IpcCallOptions, IpcConnectionError, type IpcErrorInfo, type IpcErrorResponse, type IpcHealthResponse, IpcHttpError, type IpcNamespaceDetail, type IpcNamespaceSummary, type IpcNamespacesResponse, type IpcRequestId, type IpcResponse, IpcResponseError, type IpcSuccessResponse, type TryConnectOptions, tryConnect };
|
|
150
|
+
export { AdofaiIpcClient, type AdofaiIpcClientOptions, AdofaiIpcError, AdofaiIpcNamespaceClient, CLIENT_VERSION, type IpcCallOptions, IpcConnectionError, type IpcConnectionErrorCode, type IpcConnectionErrorOptions, type IpcErrorInfo, type IpcErrorResponse, type IpcHealthResponse, IpcHttpError, type IpcNamespaceDetail, type IpcNamespaceErrorInfo, type IpcNamespaceStatus, type IpcNamespaceSummary, type IpcNamespacesResponse, type IpcRequestId, type IpcRequestOptions, type IpcResponse, IpcResponseError, type IpcSuccessResponse, IpcTimeoutError, type IpcVersionMismatchDirection, IpcVersionMismatchError, type TryConnectOptions, type WaitForNamespaceOptions, isIpcUnavailable, tryConnect };
|
package/dist/index.js
CHANGED
|
@@ -6,11 +6,38 @@ var AdofaiIpcError = class extends Error {
|
|
|
6
6
|
}
|
|
7
7
|
};
|
|
8
8
|
var IpcConnectionError = class extends AdofaiIpcError {
|
|
9
|
-
constructor(message = "Could not connect to AdofaiIpc.") {
|
|
9
|
+
constructor(message = "Could not connect to AdofaiIpc.", options = {}) {
|
|
10
10
|
super(message);
|
|
11
11
|
this.name = "IpcConnectionError";
|
|
12
|
+
this.code = options.code ?? "UNAVAILABLE";
|
|
13
|
+
this.cause = options.cause;
|
|
12
14
|
}
|
|
13
15
|
};
|
|
16
|
+
var IpcTimeoutError = class extends IpcConnectionError {
|
|
17
|
+
constructor(timeoutMs, options = {}) {
|
|
18
|
+
super(`AdofaiIpc request timed out after ${timeoutMs} ms.`, {
|
|
19
|
+
code: "TIMEOUT",
|
|
20
|
+
cause: options.cause
|
|
21
|
+
});
|
|
22
|
+
this.name = "IpcTimeoutError";
|
|
23
|
+
this.timeoutMs = timeoutMs;
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var IpcVersionMismatchError = class extends AdofaiIpcError {
|
|
27
|
+
constructor(options) {
|
|
28
|
+
const server = options.serverVersion ?? "legacy/unknown";
|
|
29
|
+
super(`AdofaiIpc version mismatch: client ${options.clientVersion}, server ${server}.`);
|
|
30
|
+
this.code = "VERSION_MISMATCH";
|
|
31
|
+
this.name = "IpcVersionMismatchError";
|
|
32
|
+
this.clientVersion = options.clientVersion;
|
|
33
|
+
this.serverVersion = options.serverVersion;
|
|
34
|
+
this.direction = options.direction;
|
|
35
|
+
this.protocolVersion = options.protocolVersion;
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
function isIpcUnavailable(error) {
|
|
39
|
+
return error instanceof IpcConnectionError && error.code === "UNAVAILABLE";
|
|
40
|
+
}
|
|
14
41
|
var IpcHttpError = class extends AdofaiIpcError {
|
|
15
42
|
constructor(status, message) {
|
|
16
43
|
super(message);
|
|
@@ -27,16 +54,56 @@ var IpcResponseError = class extends AdofaiIpcError {
|
|
|
27
54
|
}
|
|
28
55
|
};
|
|
29
56
|
|
|
57
|
+
// src/version.ts
|
|
58
|
+
var CLIENT_VERSION = "0.3.0";
|
|
59
|
+
var CANONICAL_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*))?$/;
|
|
60
|
+
function compareProductVersions(left, right) {
|
|
61
|
+
const leftVersion = parseProductVersion(left);
|
|
62
|
+
const rightVersion = parseProductVersion(right);
|
|
63
|
+
if (!leftVersion || !rightVersion) return null;
|
|
64
|
+
for (let index = 0; index < leftVersion.core.length; index++) {
|
|
65
|
+
const difference = leftVersion.core[index] - rightVersion.core[index];
|
|
66
|
+
if (difference !== 0) return difference < 0 ? -1 : 1;
|
|
67
|
+
}
|
|
68
|
+
if (leftVersion.prerelease === null) return rightVersion.prerelease === null ? 0 : 1;
|
|
69
|
+
if (rightVersion.prerelease === null) return -1;
|
|
70
|
+
const length = Math.max(leftVersion.prerelease.length, rightVersion.prerelease.length);
|
|
71
|
+
for (let index = 0; index < length; index++) {
|
|
72
|
+
const leftPart = leftVersion.prerelease[index];
|
|
73
|
+
const rightPart = rightVersion.prerelease[index];
|
|
74
|
+
if (leftPart === void 0) return -1;
|
|
75
|
+
if (rightPart === void 0) return 1;
|
|
76
|
+
if (leftPart === rightPart) continue;
|
|
77
|
+
const leftNumeric = /^\d+$/.test(leftPart);
|
|
78
|
+
const rightNumeric = /^\d+$/.test(rightPart);
|
|
79
|
+
if (leftNumeric && rightNumeric) return Number(leftPart) < Number(rightPart) ? -1 : 1;
|
|
80
|
+
if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;
|
|
81
|
+
return leftPart < rightPart ? -1 : 1;
|
|
82
|
+
}
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
function parseProductVersion(value) {
|
|
86
|
+
const match = CANONICAL_SEMVER.exec(value);
|
|
87
|
+
if (!match) return null;
|
|
88
|
+
return {
|
|
89
|
+
core: [Number(match[1]), Number(match[2]), Number(match[3])],
|
|
90
|
+
prerelease: match[4] ? match[4].split(".") : null
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
30
94
|
// src/client.ts
|
|
31
95
|
var DEFAULT_HOST = "127.0.0.1";
|
|
32
96
|
var DEFAULT_START_PORT = 32145;
|
|
33
97
|
var DEFAULT_END_PORT = 32155;
|
|
34
|
-
var
|
|
98
|
+
var DEFAULT_PROBE_TIMEOUT_MS = 500;
|
|
99
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 1e4;
|
|
100
|
+
var DEFAULT_NAMESPACE_WAIT_TIMEOUT_MS = 1e4;
|
|
101
|
+
var DEFAULT_NAMESPACE_POLL_INTERVAL_MS = 100;
|
|
35
102
|
var AdofaiIpcClient = class {
|
|
36
103
|
constructor(options = {}) {
|
|
37
104
|
this.baseUrl = normalizeBaseUrl(options.baseUrl ?? `http://${DEFAULT_HOST}:${DEFAULT_START_PORT}`);
|
|
38
105
|
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
39
|
-
this.
|
|
106
|
+
this.requestTimeoutMs = options.requestTimeoutMs ?? options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
40
107
|
if (!this.fetchImpl) {
|
|
41
108
|
throw new IpcConnectionError("A fetch implementation is required.");
|
|
42
109
|
}
|
|
@@ -44,47 +111,102 @@ var AdofaiIpcClient = class {
|
|
|
44
111
|
static async connect(options = {}) {
|
|
45
112
|
return tryConnect(options);
|
|
46
113
|
}
|
|
47
|
-
async health() {
|
|
48
|
-
return this.get("/ipc/health");
|
|
114
|
+
async health(options = {}) {
|
|
115
|
+
return this.get("/ipc/health", options);
|
|
116
|
+
}
|
|
117
|
+
async listNamespaces(options = {}) {
|
|
118
|
+
return this.get("/ipc/namespaces", options);
|
|
49
119
|
}
|
|
50
|
-
async
|
|
51
|
-
return this.get(
|
|
120
|
+
async getNamespace(namespace, options = {}) {
|
|
121
|
+
return this.get(
|
|
122
|
+
`/ipc/namespaces/${encodeURIComponent(namespace)}`,
|
|
123
|
+
options
|
|
124
|
+
);
|
|
52
125
|
}
|
|
53
|
-
async
|
|
54
|
-
|
|
126
|
+
async waitForNamespace(namespace, options = {}) {
|
|
127
|
+
const timeoutMs = options.timeoutMs ?? DEFAULT_NAMESPACE_WAIT_TIMEOUT_MS;
|
|
128
|
+
const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_NAMESPACE_POLL_INTERVAL_MS;
|
|
129
|
+
const requiredStatus = options.status ?? "registered";
|
|
130
|
+
const deadline = Date.now() + timeoutMs;
|
|
131
|
+
let stateError;
|
|
132
|
+
while (true) {
|
|
133
|
+
try {
|
|
134
|
+
const detail = await this.getNamespace(namespace, {
|
|
135
|
+
timeoutMs: options.requestTimeoutMs
|
|
136
|
+
});
|
|
137
|
+
if (requiredStatus === "registered" || detail.status === "ready") {
|
|
138
|
+
return detail;
|
|
139
|
+
}
|
|
140
|
+
if (detail.status === "error") {
|
|
141
|
+
throw new IpcResponseError({
|
|
142
|
+
code: "namespace_error",
|
|
143
|
+
message: detail.error?.message ?? `Namespace initialization failed: ${namespace}`
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
if (detail.status !== "initializing") {
|
|
147
|
+
throw new IpcResponseError({
|
|
148
|
+
code: "namespace_status_unavailable",
|
|
149
|
+
message: `Namespace status is unavailable: ${namespace}`
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
stateError = new IpcResponseError({
|
|
153
|
+
code: "namespace_initializing",
|
|
154
|
+
message: `Namespace is initializing: ${namespace}`
|
|
155
|
+
});
|
|
156
|
+
} catch (error) {
|
|
157
|
+
if (!(error instanceof IpcResponseError) || error.code !== "namespace_not_found" && error.code !== "namespace_initializing") {
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
stateError = error;
|
|
161
|
+
}
|
|
162
|
+
const remainingMs = deadline - Date.now();
|
|
163
|
+
if (remainingMs <= 0) {
|
|
164
|
+
throw stateError ?? new IpcResponseError({
|
|
165
|
+
code: "namespace_initializing",
|
|
166
|
+
message: `Namespace is initializing: ${namespace}`
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
await delay(Math.min(pollIntervalMs, remainingMs));
|
|
170
|
+
}
|
|
55
171
|
}
|
|
56
172
|
namespace(namespace) {
|
|
57
173
|
return new AdofaiIpcNamespaceClient(this, namespace);
|
|
58
174
|
}
|
|
59
175
|
async call(options) {
|
|
60
|
-
const response = await this.post(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
176
|
+
const response = await this.post(
|
|
177
|
+
"/ipc",
|
|
178
|
+
{
|
|
179
|
+
namespace: options.namespace,
|
|
180
|
+
method: options.method,
|
|
181
|
+
params: options.params ?? {},
|
|
182
|
+
id: options.id ?? createRequestId()
|
|
183
|
+
},
|
|
184
|
+
{ timeoutMs: options.timeoutMs }
|
|
185
|
+
);
|
|
66
186
|
if (!response.ok) {
|
|
67
187
|
throw new IpcResponseError(response.error);
|
|
68
188
|
}
|
|
69
189
|
return response.result;
|
|
70
190
|
}
|
|
71
|
-
async get(path) {
|
|
191
|
+
async get(path, options = {}) {
|
|
72
192
|
return this.request(path, {
|
|
73
193
|
method: "GET"
|
|
74
|
-
});
|
|
194
|
+
}, options);
|
|
75
195
|
}
|
|
76
|
-
async post(path, body) {
|
|
196
|
+
async post(path, body, options = {}) {
|
|
77
197
|
return this.request(path, {
|
|
78
198
|
method: "POST",
|
|
79
199
|
headers: {
|
|
80
200
|
"Content-Type": "application/json"
|
|
81
201
|
},
|
|
82
202
|
body: JSON.stringify(body)
|
|
83
|
-
});
|
|
203
|
+
}, options);
|
|
84
204
|
}
|
|
85
|
-
async request(path, init) {
|
|
205
|
+
async request(path, init, options) {
|
|
206
|
+
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
|
|
86
207
|
const controller = new AbortController();
|
|
87
|
-
const
|
|
208
|
+
const timeoutError = new IpcTimeoutError(timeoutMs);
|
|
209
|
+
const timeout = setTimeout(() => controller.abort(timeoutError), timeoutMs);
|
|
88
210
|
try {
|
|
89
211
|
const response = await this.fetchImpl(`${this.baseUrl}${path}`, {
|
|
90
212
|
...init,
|
|
@@ -92,13 +214,18 @@ var AdofaiIpcClient = class {
|
|
|
92
214
|
});
|
|
93
215
|
if (!response.ok) {
|
|
94
216
|
const text = await response.text();
|
|
217
|
+
const responseError = parseIpcResponseError(text);
|
|
218
|
+
if (responseError) throw new IpcResponseError(responseError);
|
|
95
219
|
throw new IpcHttpError(response.status, text || response.statusText);
|
|
96
220
|
}
|
|
97
221
|
return await response.json();
|
|
98
222
|
} catch (error) {
|
|
99
|
-
if (error instanceof IpcHttpError) throw error;
|
|
100
|
-
if (
|
|
101
|
-
|
|
223
|
+
if (error instanceof IpcHttpError || error instanceof IpcResponseError) throw error;
|
|
224
|
+
if (controller.signal.aborted) {
|
|
225
|
+
if (error === timeoutError) throw timeoutError;
|
|
226
|
+
throw new IpcTimeoutError(timeoutMs, { cause: error });
|
|
227
|
+
}
|
|
228
|
+
throw new IpcConnectionError(getErrorMessage(error), { cause: error });
|
|
102
229
|
} finally {
|
|
103
230
|
clearTimeout(timeout);
|
|
104
231
|
}
|
|
@@ -109,12 +236,15 @@ var AdofaiIpcNamespaceClient = class {
|
|
|
109
236
|
this.client = client;
|
|
110
237
|
this.namespace = namespace;
|
|
111
238
|
}
|
|
112
|
-
async call(method, params,
|
|
239
|
+
async call(method, params, idOrOptions, options = {}) {
|
|
240
|
+
const requestOptions = isIpcRequestOptions(idOrOptions) ? idOrOptions : options;
|
|
241
|
+
const id = isIpcRequestOptions(idOrOptions) ? void 0 : idOrOptions;
|
|
113
242
|
return this.client.call({
|
|
114
243
|
namespace: this.namespace,
|
|
115
244
|
method,
|
|
116
245
|
params,
|
|
117
|
-
id
|
|
246
|
+
id,
|
|
247
|
+
timeoutMs: requestOptions.timeoutMs
|
|
118
248
|
});
|
|
119
249
|
}
|
|
120
250
|
};
|
|
@@ -122,27 +252,80 @@ async function tryConnect(options = {}) {
|
|
|
122
252
|
const host = options.host ?? DEFAULT_HOST;
|
|
123
253
|
const startPort = options.startPort ?? DEFAULT_START_PORT;
|
|
124
254
|
const endPort = options.endPort ?? DEFAULT_END_PORT;
|
|
255
|
+
const probeTimeoutMs = options.probeTimeoutMs ?? options.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;
|
|
256
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
257
|
+
let lastProbeError;
|
|
125
258
|
for (let port = startPort; port <= endPort; port++) {
|
|
126
259
|
const client = new AdofaiIpcClient({
|
|
127
260
|
baseUrl: `http://${host}:${port}`,
|
|
128
261
|
fetch: options.fetch,
|
|
129
|
-
|
|
262
|
+
requestTimeoutMs: probeTimeoutMs
|
|
130
263
|
});
|
|
131
264
|
try {
|
|
132
265
|
const health = await client.health();
|
|
133
266
|
if (health.ok && health.server === "AdofaiIpc") {
|
|
134
|
-
|
|
267
|
+
const mismatch = getVersionMismatch(health);
|
|
268
|
+
if (mismatch) {
|
|
269
|
+
try {
|
|
270
|
+
options.onVersionMismatch?.(mismatch);
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
273
|
+
throw mismatch;
|
|
274
|
+
}
|
|
275
|
+
return new AdofaiIpcClient({
|
|
276
|
+
baseUrl: client.baseUrl,
|
|
277
|
+
fetch: options.fetch,
|
|
278
|
+
requestTimeoutMs
|
|
279
|
+
});
|
|
135
280
|
}
|
|
136
|
-
} catch {
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (error instanceof IpcVersionMismatchError) throw error;
|
|
283
|
+
lastProbeError = error;
|
|
137
284
|
}
|
|
138
285
|
}
|
|
286
|
+
if (lastProbeError instanceof IpcTimeoutError) throw lastProbeError;
|
|
139
287
|
throw new IpcConnectionError(
|
|
140
288
|
`Could not connect to AdofaiIpc on ${host}:${startPort}-${endPort}.`
|
|
141
289
|
);
|
|
142
290
|
}
|
|
291
|
+
function getVersionMismatch(health) {
|
|
292
|
+
const protocolVersion = Number.isInteger(health.protocolVersion) ? health.protocolVersion : null;
|
|
293
|
+
const serverVersion = typeof health.serverVersion === "string" ? health.serverVersion : null;
|
|
294
|
+
const comparison = serverVersion === null ? null : compareProductVersions(serverVersion, CLIENT_VERSION);
|
|
295
|
+
if (comparison === 0 && serverVersion === CLIENT_VERSION) return null;
|
|
296
|
+
return new IpcVersionMismatchError({
|
|
297
|
+
clientVersion: CLIENT_VERSION,
|
|
298
|
+
serverVersion,
|
|
299
|
+
direction: comparison === null ? "legacy_server" : comparison < 0 ? "server_outdated" : "client_outdated",
|
|
300
|
+
protocolVersion
|
|
301
|
+
});
|
|
302
|
+
}
|
|
143
303
|
function normalizeBaseUrl(value) {
|
|
144
304
|
return value.replace(/\/+$/, "");
|
|
145
305
|
}
|
|
306
|
+
function getErrorMessage(error) {
|
|
307
|
+
if (typeof error === "object" && error !== null && "message" in error && typeof error.message === "string") {
|
|
308
|
+
return error.message;
|
|
309
|
+
}
|
|
310
|
+
return void 0;
|
|
311
|
+
}
|
|
312
|
+
function parseIpcResponseError(text) {
|
|
313
|
+
try {
|
|
314
|
+
const value = JSON.parse(text);
|
|
315
|
+
const error = value?.error;
|
|
316
|
+
if (typeof error === "object" && error !== null && "code" in error && typeof error.code === "string" && "message" in error && typeof error.message === "string") {
|
|
317
|
+
return { code: error.code, message: error.message };
|
|
318
|
+
}
|
|
319
|
+
} catch {
|
|
320
|
+
}
|
|
321
|
+
return void 0;
|
|
322
|
+
}
|
|
323
|
+
function isIpcRequestOptions(value) {
|
|
324
|
+
return typeof value === "object" && value !== null;
|
|
325
|
+
}
|
|
326
|
+
function delay(timeoutMs) {
|
|
327
|
+
return new Promise((resolve) => setTimeout(resolve, timeoutMs));
|
|
328
|
+
}
|
|
146
329
|
function createRequestId() {
|
|
147
330
|
return `adofai-ipc-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
148
331
|
}
|
|
@@ -150,9 +333,13 @@ export {
|
|
|
150
333
|
AdofaiIpcClient,
|
|
151
334
|
AdofaiIpcError,
|
|
152
335
|
AdofaiIpcNamespaceClient,
|
|
336
|
+
CLIENT_VERSION,
|
|
153
337
|
IpcConnectionError,
|
|
154
338
|
IpcHttpError,
|
|
155
339
|
IpcResponseError,
|
|
340
|
+
IpcTimeoutError,
|
|
341
|
+
IpcVersionMismatchError,
|
|
342
|
+
isIpcUnavailable,
|
|
156
343
|
tryConnect
|
|
157
344
|
};
|
|
158
345
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts"],"sourcesContent":["import type { IpcErrorInfo } from \"./types\";\n\nexport class AdofaiIpcError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AdofaiIpcError\";\n }\n}\n\nexport class IpcConnectionError extends AdofaiIpcError {\n constructor(message = \"Could not connect to AdofaiIpc.\") {\n super(message);\n this.name = \"IpcConnectionError\";\n }\n}\n\nexport class IpcHttpError extends AdofaiIpcError {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"IpcHttpError\";\n this.status = status;\n }\n}\n\nexport class IpcResponseError extends AdofaiIpcError {\n readonly code: string;\n readonly error: IpcErrorInfo;\n\n constructor(error: IpcErrorInfo) {\n super(error.message);\n this.name = \"IpcResponseError\";\n this.code = error.code;\n this.error = error;\n }\n}\n","import { IpcConnectionError, IpcHttpError, IpcResponseError } from \"./errors\";\nimport type {\n AdofaiIpcClientOptions,\n IpcCallOptions,\n IpcHealthResponse,\n IpcNamespaceDetail,\n IpcNamespacesResponse,\n IpcResponse,\n TryConnectOptions\n} from \"./types\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_START_PORT = 32145;\nconst DEFAULT_END_PORT = 32155;\nconst DEFAULT_TIMEOUT_MS = 500;\n\nexport class AdofaiIpcClient {\n readonly baseUrl: string;\n\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n\n constructor(options: AdofaiIpcClientOptions = {}) {\n this.baseUrl = normalizeBaseUrl(options.baseUrl ?? `http://${DEFAULT_HOST}:${DEFAULT_START_PORT}`);\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n if (!this.fetchImpl) {\n throw new IpcConnectionError(\"A fetch implementation is required.\");\n }\n }\n\n static async connect(options: TryConnectOptions = {}): Promise<AdofaiIpcClient> {\n return tryConnect(options);\n }\n\n async health(): Promise<IpcHealthResponse> {\n return this.get<IpcHealthResponse>(\"/ipc/health\");\n }\n\n async listNamespaces(): Promise<IpcNamespacesResponse> {\n return this.get<IpcNamespacesResponse>(\"/ipc/namespaces\");\n }\n\n async getNamespace(namespace: string): Promise<IpcNamespaceDetail> {\n return this.get<IpcNamespaceDetail>(`/ipc/namespaces/${encodeURIComponent(namespace)}`);\n }\n\n namespace(namespace: string): AdofaiIpcNamespaceClient {\n return new AdofaiIpcNamespaceClient(this, namespace);\n }\n\n async call<TResult = unknown, TParams = unknown>(\n options: IpcCallOptions<TParams>\n ): Promise<TResult> {\n const response = await this.post<IpcResponse<TResult>>(\"/ipc\", {\n namespace: options.namespace,\n method: options.method,\n params: options.params ?? {},\n id: options.id ?? createRequestId()\n });\n\n if (!response.ok) {\n throw new IpcResponseError(response.error);\n }\n\n return response.result;\n }\n\n private async get<TResult>(path: string): Promise<TResult> {\n return this.request<TResult>(path, {\n method: \"GET\"\n });\n }\n\n private async post<TResult>(path: string, body: unknown): Promise<TResult> {\n return this.request<TResult>(path, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(body)\n });\n }\n\n private async request<TResult>(path: string, init: RequestInit): Promise<TResult> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n\n try {\n const response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n ...init,\n signal: controller.signal\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new IpcHttpError(response.status, text || response.statusText);\n }\n\n return (await response.json()) as TResult;\n } catch (error) {\n if (error instanceof IpcHttpError) throw error;\n if (error instanceof Error) throw new IpcConnectionError(error.message);\n throw new IpcConnectionError();\n } finally {\n clearTimeout(timeout);\n }\n }\n}\n\nexport class AdofaiIpcNamespaceClient {\n constructor(\n private readonly client: AdofaiIpcClient,\n readonly namespace: string\n ) {\n }\n\n async call<TResult = unknown, TParams = unknown>(\n method: string,\n params?: TParams,\n id?: string\n ): Promise<TResult> {\n return this.client.call<TResult, TParams>({\n namespace: this.namespace,\n method,\n params,\n id\n });\n }\n}\n\nexport async function tryConnect(options: TryConnectOptions = {}): Promise<AdofaiIpcClient> {\n const host = options.host ?? DEFAULT_HOST;\n const startPort = options.startPort ?? DEFAULT_START_PORT;\n const endPort = options.endPort ?? DEFAULT_END_PORT;\n\n for (let port = startPort; port <= endPort; port++) {\n const client = new AdofaiIpcClient({\n baseUrl: `http://${host}:${port}`,\n fetch: options.fetch,\n timeoutMs: options.timeoutMs\n });\n\n try {\n const health = await client.health();\n\n if (health.ok && health.server === \"AdofaiIpc\") {\n return client;\n }\n } catch {\n }\n }\n\n throw new IpcConnectionError(\n `Could not connect to AdofaiIpc on ${host}:${startPort}-${endPort}.`\n );\n}\n\nfunction normalizeBaseUrl(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\nfunction createRequestId(): string {\n return `adofai-ipc-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/version.ts","../src/client.ts"],"sourcesContent":["import type { IpcErrorInfo } from \"./types\";\n\nexport type IpcConnectionErrorCode = \"UNAVAILABLE\" | \"TIMEOUT\";\nexport type IpcVersionMismatchDirection =\n | \"server_outdated\"\n | \"client_outdated\"\n | \"legacy_server\";\n\nexport interface IpcConnectionErrorOptions {\n code?: IpcConnectionErrorCode;\n cause?: unknown;\n}\n\nexport class AdofaiIpcError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"AdofaiIpcError\";\n }\n}\n\nexport class IpcConnectionError extends AdofaiIpcError {\n readonly code: IpcConnectionErrorCode;\n readonly cause?: unknown;\n\n constructor(\n message = \"Could not connect to AdofaiIpc.\",\n options: IpcConnectionErrorOptions = {}\n ) {\n super(message);\n this.name = \"IpcConnectionError\";\n this.code = options.code ?? \"UNAVAILABLE\";\n this.cause = options.cause;\n }\n}\n\nexport class IpcTimeoutError extends IpcConnectionError {\n readonly timeoutMs: number;\n\n constructor(timeoutMs: number, options: Pick<IpcConnectionErrorOptions, \"cause\"> = {}) {\n super(`AdofaiIpc request timed out after ${timeoutMs} ms.`, {\n code: \"TIMEOUT\",\n cause: options.cause\n });\n this.name = \"IpcTimeoutError\";\n this.timeoutMs = timeoutMs;\n }\n}\n\nexport class IpcVersionMismatchError extends AdofaiIpcError {\n readonly code = \"VERSION_MISMATCH\" as const;\n readonly clientVersion: string;\n readonly serverVersion: string | null;\n readonly direction: IpcVersionMismatchDirection;\n readonly protocolVersion: number | null;\n\n constructor(options: {\n clientVersion: string;\n serverVersion: string | null;\n direction: IpcVersionMismatchDirection;\n protocolVersion: number | null;\n }) {\n const server = options.serverVersion ?? \"legacy/unknown\";\n super(`AdofaiIpc version mismatch: client ${options.clientVersion}, server ${server}.`);\n this.name = \"IpcVersionMismatchError\";\n this.clientVersion = options.clientVersion;\n this.serverVersion = options.serverVersion;\n this.direction = options.direction;\n this.protocolVersion = options.protocolVersion;\n }\n}\n\nexport function isIpcUnavailable(error: unknown): error is IpcConnectionError {\n return error instanceof IpcConnectionError && error.code === \"UNAVAILABLE\";\n}\n\nexport class IpcHttpError extends AdofaiIpcError {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"IpcHttpError\";\n this.status = status;\n }\n}\n\nexport class IpcResponseError extends AdofaiIpcError {\n readonly code: string;\n readonly error: IpcErrorInfo;\n\n constructor(error: IpcErrorInfo) {\n super(error.message);\n this.name = \"IpcResponseError\";\n this.code = error.code;\n this.error = error;\n }\n}\n","declare const __CLIENT_VERSION__: string;\n\nexport const CLIENT_VERSION = __CLIENT_VERSION__;\n\nconst CANONICAL_SEMVER = /^(0|[1-9]\\d*)\\.(0|[1-9]\\d*)\\.(0|[1-9]\\d*)(?:-((?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*)(?:\\.(?:0|[1-9]\\d*|\\d*[A-Za-z-][0-9A-Za-z-]*))*))?$/;\n\ninterface ParsedVersion {\n core: [number, number, number];\n prerelease: string[] | null;\n}\n\nexport function compareProductVersions(left: string, right: string): number | null {\n const leftVersion = parseProductVersion(left);\n const rightVersion = parseProductVersion(right);\n if (!leftVersion || !rightVersion) return null;\n\n for (let index = 0; index < leftVersion.core.length; index++) {\n const difference = leftVersion.core[index]! - rightVersion.core[index]!;\n if (difference !== 0) return difference < 0 ? -1 : 1;\n }\n\n if (leftVersion.prerelease === null) return rightVersion.prerelease === null ? 0 : 1;\n if (rightVersion.prerelease === null) return -1;\n\n const length = Math.max(leftVersion.prerelease.length, rightVersion.prerelease.length);\n for (let index = 0; index < length; index++) {\n const leftPart = leftVersion.prerelease[index];\n const rightPart = rightVersion.prerelease[index];\n if (leftPart === undefined) return -1;\n if (rightPart === undefined) return 1;\n if (leftPart === rightPart) continue;\n\n const leftNumeric = /^\\d+$/.test(leftPart);\n const rightNumeric = /^\\d+$/.test(rightPart);\n if (leftNumeric && rightNumeric) return Number(leftPart) < Number(rightPart) ? -1 : 1;\n if (leftNumeric !== rightNumeric) return leftNumeric ? -1 : 1;\n return leftPart < rightPart ? -1 : 1;\n }\n\n return 0;\n}\n\nfunction parseProductVersion(value: string): ParsedVersion | null {\n const match = CANONICAL_SEMVER.exec(value);\n if (!match) return null;\n return {\n core: [Number(match[1]), Number(match[2]), Number(match[3])],\n prerelease: match[4] ? match[4].split(\".\") : null\n };\n}\n","import {\n IpcConnectionError,\n IpcHttpError,\n IpcResponseError,\n IpcTimeoutError,\n IpcVersionMismatchError\n} from \"./errors\";\nimport { CLIENT_VERSION, compareProductVersions } from \"./version\";\nimport type {\n AdofaiIpcClientOptions,\n IpcCallOptions,\n IpcErrorInfo,\n IpcHealthResponse,\n IpcNamespaceDetail,\n IpcNamespacesResponse,\n IpcRequestId,\n IpcRequestOptions,\n IpcResponse,\n TryConnectOptions,\n WaitForNamespaceOptions\n} from \"./types\";\n\nconst DEFAULT_HOST = \"127.0.0.1\";\nconst DEFAULT_START_PORT = 32145;\nconst DEFAULT_END_PORT = 32155;\nconst DEFAULT_PROBE_TIMEOUT_MS = 500;\nconst DEFAULT_REQUEST_TIMEOUT_MS = 10_000;\nconst DEFAULT_NAMESPACE_WAIT_TIMEOUT_MS = 10_000;\nconst DEFAULT_NAMESPACE_POLL_INTERVAL_MS = 100;\n\nexport class AdofaiIpcClient {\n readonly baseUrl: string;\n\n private readonly fetchImpl: typeof fetch;\n private readonly requestTimeoutMs: number;\n\n constructor(options: AdofaiIpcClientOptions = {}) {\n this.baseUrl = normalizeBaseUrl(options.baseUrl ?? `http://${DEFAULT_HOST}:${DEFAULT_START_PORT}`);\n this.fetchImpl = options.fetch ?? globalThis.fetch;\n this.requestTimeoutMs =\n options.requestTimeoutMs ?? options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n\n if (!this.fetchImpl) {\n throw new IpcConnectionError(\"A fetch implementation is required.\");\n }\n }\n\n static async connect(options: TryConnectOptions = {}): Promise<AdofaiIpcClient> {\n return tryConnect(options);\n }\n\n async health(options: IpcRequestOptions = {}): Promise<IpcHealthResponse> {\n return this.get<IpcHealthResponse>(\"/ipc/health\", options);\n }\n\n async listNamespaces(options: IpcRequestOptions = {}): Promise<IpcNamespacesResponse> {\n return this.get<IpcNamespacesResponse>(\"/ipc/namespaces\", options);\n }\n\n async getNamespace(\n namespace: string,\n options: IpcRequestOptions = {}\n ): Promise<IpcNamespaceDetail> {\n return this.get<IpcNamespaceDetail>(\n `/ipc/namespaces/${encodeURIComponent(namespace)}`,\n options\n );\n }\n\n async waitForNamespace(\n namespace: string,\n options: WaitForNamespaceOptions = {}\n ): Promise<IpcNamespaceDetail> {\n const timeoutMs = options.timeoutMs ?? DEFAULT_NAMESPACE_WAIT_TIMEOUT_MS;\n const pollIntervalMs = options.pollIntervalMs ?? DEFAULT_NAMESPACE_POLL_INTERVAL_MS;\n const requiredStatus = options.status ?? \"registered\";\n const deadline = Date.now() + timeoutMs;\n let stateError: IpcResponseError | undefined;\n\n while (true) {\n try {\n const detail = await this.getNamespace(namespace, {\n timeoutMs: options.requestTimeoutMs\n });\n\n if (requiredStatus === \"registered\" || detail.status === \"ready\") {\n return detail;\n }\n\n if (detail.status === \"error\") {\n throw new IpcResponseError({\n code: \"namespace_error\",\n message: detail.error?.message ?? `Namespace initialization failed: ${namespace}`\n });\n }\n\n if (detail.status !== \"initializing\") {\n throw new IpcResponseError({\n code: \"namespace_status_unavailable\",\n message: `Namespace status is unavailable: ${namespace}`\n });\n }\n\n stateError = new IpcResponseError({\n code: \"namespace_initializing\",\n message: `Namespace is initializing: ${namespace}`\n });\n } catch (error) {\n if (\n !(error instanceof IpcResponseError) ||\n (error.code !== \"namespace_not_found\" && error.code !== \"namespace_initializing\")\n ) {\n throw error;\n }\n\n stateError = error;\n }\n\n const remainingMs = deadline - Date.now();\n if (remainingMs <= 0) {\n throw stateError ?? new IpcResponseError({\n code: \"namespace_initializing\",\n message: `Namespace is initializing: ${namespace}`\n });\n }\n\n await delay(Math.min(pollIntervalMs, remainingMs));\n }\n }\n\n namespace(namespace: string): AdofaiIpcNamespaceClient {\n return new AdofaiIpcNamespaceClient(this, namespace);\n }\n\n async call<TResult = unknown, TParams = unknown>(\n options: IpcCallOptions<TParams>\n ): Promise<TResult> {\n const response = await this.post<IpcResponse<TResult>>(\n \"/ipc\",\n {\n namespace: options.namespace,\n method: options.method,\n params: options.params ?? {},\n id: options.id ?? createRequestId()\n },\n { timeoutMs: options.timeoutMs }\n );\n\n if (!response.ok) {\n throw new IpcResponseError(response.error);\n }\n\n return response.result;\n }\n\n private async get<TResult>(\n path: string,\n options: IpcRequestOptions = {}\n ): Promise<TResult> {\n return this.request<TResult>(path, {\n method: \"GET\"\n }, options);\n }\n\n private async post<TResult>(\n path: string,\n body: unknown,\n options: IpcRequestOptions = {}\n ): Promise<TResult> {\n return this.request<TResult>(path, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\"\n },\n body: JSON.stringify(body)\n }, options);\n }\n\n private async request<TResult>(\n path: string,\n init: RequestInit,\n options: IpcRequestOptions\n ): Promise<TResult> {\n const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;\n const controller = new AbortController();\n const timeoutError = new IpcTimeoutError(timeoutMs);\n const timeout = setTimeout(() => controller.abort(timeoutError), timeoutMs);\n\n try {\n const response = await this.fetchImpl(`${this.baseUrl}${path}`, {\n ...init,\n signal: controller.signal\n });\n\n if (!response.ok) {\n const text = await response.text();\n const responseError = parseIpcResponseError(text);\n if (responseError) throw new IpcResponseError(responseError);\n throw new IpcHttpError(response.status, text || response.statusText);\n }\n\n return (await response.json()) as TResult;\n } catch (error) {\n if (error instanceof IpcHttpError || error instanceof IpcResponseError) throw error;\n if (controller.signal.aborted) {\n if (error === timeoutError) throw timeoutError;\n throw new IpcTimeoutError(timeoutMs, { cause: error });\n }\n throw new IpcConnectionError(getErrorMessage(error), { cause: error });\n } finally {\n clearTimeout(timeout);\n }\n }\n}\n\nexport class AdofaiIpcNamespaceClient {\n constructor(\n private readonly client: AdofaiIpcClient,\n readonly namespace: string\n ) {\n }\n\n async call<TResult = unknown, TParams = unknown>(\n method: string,\n params?: TParams,\n idOrOptions?: IpcRequestId | IpcRequestOptions,\n options: IpcRequestOptions = {}\n ): Promise<TResult> {\n const requestOptions = isIpcRequestOptions(idOrOptions) ? idOrOptions : options;\n const id = isIpcRequestOptions(idOrOptions) ? undefined : idOrOptions;\n\n return this.client.call<TResult, TParams>({\n namespace: this.namespace,\n method,\n params,\n id,\n timeoutMs: requestOptions.timeoutMs\n });\n }\n}\n\nexport async function tryConnect(options: TryConnectOptions = {}): Promise<AdofaiIpcClient> {\n const host = options.host ?? DEFAULT_HOST;\n const startPort = options.startPort ?? DEFAULT_START_PORT;\n const endPort = options.endPort ?? DEFAULT_END_PORT;\n const probeTimeoutMs =\n options.probeTimeoutMs ?? options.timeoutMs ?? DEFAULT_PROBE_TIMEOUT_MS;\n const requestTimeoutMs =\n options.requestTimeoutMs ?? options.timeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;\n let lastProbeError: unknown;\n\n for (let port = startPort; port <= endPort; port++) {\n const client = new AdofaiIpcClient({\n baseUrl: `http://${host}:${port}`,\n fetch: options.fetch,\n requestTimeoutMs: probeTimeoutMs\n });\n\n try {\n const health = await client.health();\n\n if (health.ok && health.server === \"AdofaiIpc\") {\n const mismatch = getVersionMismatch(health);\n if (mismatch) {\n try {\n options.onVersionMismatch?.(mismatch);\n } catch {\n }\n throw mismatch;\n }\n return new AdofaiIpcClient({\n baseUrl: client.baseUrl,\n fetch: options.fetch,\n requestTimeoutMs\n });\n }\n } catch (error) {\n if (error instanceof IpcVersionMismatchError) throw error;\n lastProbeError = error;\n }\n }\n\n if (lastProbeError instanceof IpcTimeoutError) throw lastProbeError;\n\n throw new IpcConnectionError(\n `Could not connect to AdofaiIpc on ${host}:${startPort}-${endPort}.`\n );\n}\n\nfunction getVersionMismatch(health: IpcHealthResponse): IpcVersionMismatchError | null {\n const protocolVersion = Number.isInteger(health.protocolVersion) ? health.protocolVersion : null;\n const serverVersion = typeof health.serverVersion === \"string\" ? health.serverVersion : null;\n const comparison = serverVersion === null\n ? null\n : compareProductVersions(serverVersion, CLIENT_VERSION);\n\n if (comparison === 0 && serverVersion === CLIENT_VERSION) return null;\n\n return new IpcVersionMismatchError({\n clientVersion: CLIENT_VERSION,\n serverVersion,\n direction: comparison === null\n ? \"legacy_server\"\n : comparison < 0\n ? \"server_outdated\"\n : \"client_outdated\",\n protocolVersion\n });\n}\n\nfunction normalizeBaseUrl(value: string): string {\n return value.replace(/\\/+$/, \"\");\n}\n\nfunction getErrorMessage(error: unknown): string | undefined {\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return error.message;\n }\n\n return undefined;\n}\n\nfunction parseIpcResponseError(text: string): IpcErrorInfo | undefined {\n try {\n const value = JSON.parse(text) as { error?: unknown };\n const error = value?.error;\n\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n typeof error.code === \"string\" &&\n \"message\" in error &&\n typeof error.message === \"string\"\n ) {\n return { code: error.code, message: error.message };\n }\n } catch {\n }\n\n return undefined;\n}\n\nfunction isIpcRequestOptions(value: unknown): value is IpcRequestOptions {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction delay(timeoutMs: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, timeoutMs));\n}\n\nfunction createRequestId(): string {\n return `adofai-ipc-${Date.now()}-${Math.random().toString(36).slice(2)}`;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adofai-ipc/client",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "TypeScript client for the AdofaiIpc local HTTP IPC gateway.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -42,12 +42,14 @@
|
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
|
+
"@types/node": "^22.10.2",
|
|
45
46
|
"tsup": "^8.3.5",
|
|
46
47
|
"typescript": "^5.6.3"
|
|
47
48
|
},
|
|
48
49
|
"scripts": {
|
|
49
50
|
"build": "tsup",
|
|
50
51
|
"check": "tsc --noEmit",
|
|
51
|
-
"clean": "rm -rf dist"
|
|
52
|
+
"clean": "rm -rf dist",
|
|
53
|
+
"test": "pnpm run build && node --test test/*.test.mjs"
|
|
52
54
|
}
|
|
53
55
|
}
|