@meowpanel/api 0.13.0 → 0.15.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/esm/mod.d.ts +1 -1
- package/esm/mod.d.ts.map +1 -1
- package/esm/src/resources/servers/backups.d.ts +7 -7
- package/esm/src/resources/servers/backups.d.ts.map +1 -1
- package/esm/src/resources/servers/backups.js +8 -8
- package/esm/src/resources/servers/connection.d.ts +34 -7
- package/esm/src/resources/servers/connection.d.ts.map +1 -1
- package/esm/src/resources/servers/connection.js +109 -36
- package/esm/src/resources/servers/server.js +1 -1
- package/esm/src/sse.d.ts +63 -11
- package/esm/src/sse.d.ts.map +1 -1
- package/esm/src/sse.js +112 -31
- package/package.json +1 -1
- package/script/mod.d.ts +1 -1
- package/script/mod.d.ts.map +1 -1
- package/script/src/resources/servers/backups.d.ts +7 -7
- package/script/src/resources/servers/backups.d.ts.map +1 -1
- package/script/src/resources/servers/backups.js +8 -8
- package/script/src/resources/servers/connection.d.ts +34 -7
- package/script/src/resources/servers/connection.d.ts.map +1 -1
- package/script/src/resources/servers/connection.js +109 -36
- package/script/src/resources/servers/server.js +1 -1
- package/script/src/sse.d.ts +63 -11
- package/script/src/sse.d.ts.map +1 -1
- package/script/src/sse.js +112 -31
package/esm/src/sse.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { TypedEmitter } from './emitter.js';
|
|
1
2
|
/**
|
|
2
3
|
* A generic, `fetch`-based Server-Sent Events client.
|
|
3
4
|
*
|
|
@@ -5,9 +6,13 @@
|
|
|
5
6
|
* header, making it compatible with bearer token auth in all environments
|
|
6
7
|
* (browser, Deno, Node.js).
|
|
7
8
|
*
|
|
9
|
+
* Like `EventSource`, it reconnects with exponential backoff whenever the stream ends without
|
|
10
|
+
* {@link disconnect} being called, including a clean close by the server.
|
|
11
|
+
*
|
|
8
12
|
* @example
|
|
9
13
|
* ```ts ignore
|
|
10
14
|
* const sse = new SseConnection('https://panel.example.com/v1/sse', token);
|
|
15
|
+
* sse.on('state', (state) => console.log('SSE is', state));
|
|
11
16
|
* sse.connect(
|
|
12
17
|
* (event, data) => console.log(event, data),
|
|
13
18
|
* (err) => console.error('SSE error:', err),
|
|
@@ -16,18 +21,32 @@
|
|
|
16
21
|
* sse.disconnect();
|
|
17
22
|
* ```
|
|
18
23
|
*/
|
|
19
|
-
export class SseConnection {
|
|
24
|
+
export class SseConnection extends TypedEmitter {
|
|
20
25
|
url;
|
|
21
26
|
token;
|
|
22
27
|
abortController;
|
|
28
|
+
reconnectTimer;
|
|
23
29
|
_state = 'disconnected';
|
|
30
|
+
attempt = 0;
|
|
31
|
+
options;
|
|
24
32
|
/**
|
|
25
|
-
* @param url
|
|
26
|
-
* @param token
|
|
33
|
+
* @param url The full URL to connect to.
|
|
34
|
+
* @param token Bearer token used in the `Authorization` header, or a function returning the
|
|
35
|
+
* current one. A function is read on every attempt, so reconnects pick up a
|
|
36
|
+
* refreshed token.
|
|
37
|
+
* @param options Reconnect and idle-timeout behavior.
|
|
27
38
|
*/
|
|
28
|
-
constructor(url, token) {
|
|
39
|
+
constructor(url, token, options = {}) {
|
|
40
|
+
super();
|
|
29
41
|
this.url = url;
|
|
30
42
|
this.token = token;
|
|
43
|
+
this.options = {
|
|
44
|
+
reconnect: true,
|
|
45
|
+
minReconnectDelayMs: 1_000,
|
|
46
|
+
maxReconnectDelayMs: 30_000,
|
|
47
|
+
idleTimeoutMs: 0,
|
|
48
|
+
...options,
|
|
49
|
+
};
|
|
31
50
|
}
|
|
32
51
|
/** Update the bearer token for subsequent reconnections. */
|
|
33
52
|
updateToken(token) {
|
|
@@ -44,60 +63,121 @@ export class SseConnection {
|
|
|
44
63
|
/**
|
|
45
64
|
* Open the SSE connection and begin streaming events.
|
|
46
65
|
*
|
|
47
|
-
* This method is **non-blocking**: it starts the connection and returns immediately
|
|
48
|
-
*
|
|
49
|
-
*
|
|
66
|
+
* This method is **non-blocking**: it starts the connection and returns immediately.
|
|
67
|
+
* Events are delivered asynchronously via the `onEvent` callback, and state changes via the
|
|
68
|
+
* `state` event.
|
|
50
69
|
*
|
|
51
70
|
* @param onEvent Callback invoked for each received SSE event, with the event name and raw data string.
|
|
52
|
-
* @param onError Optional callback invoked
|
|
71
|
+
* @param onError Optional callback invoked each time a connection attempt fails or an open stream
|
|
72
|
+
* is lost (not called on intentional disconnect). Reconnecting continues unless
|
|
73
|
+
* {@link state} is `error`.
|
|
53
74
|
*/
|
|
54
75
|
connect(onEvent, onError) {
|
|
55
76
|
this.disconnect();
|
|
56
|
-
this.
|
|
77
|
+
this.attempt = 0;
|
|
78
|
+
this.open(onEvent, onError);
|
|
79
|
+
}
|
|
80
|
+
/** Close the SSE connection, cancel any pending reconnect, and stop receiving events. */
|
|
81
|
+
disconnect() {
|
|
82
|
+
clearTimeout(this.reconnectTimer);
|
|
83
|
+
this.reconnectTimer = undefined;
|
|
84
|
+
this.abortController?.abort();
|
|
85
|
+
this.abortController = undefined;
|
|
86
|
+
this.setState('disconnected');
|
|
87
|
+
}
|
|
88
|
+
open(onEvent, onError) {
|
|
89
|
+
this.setState(this.attempt === 0 ? 'connecting' : 'reconnecting');
|
|
57
90
|
const controller = new AbortController();
|
|
58
91
|
this.abortController = controller;
|
|
59
92
|
(async () => {
|
|
93
|
+
const { idleTimeoutMs } = this.options;
|
|
94
|
+
let idleTimer;
|
|
95
|
+
let idledOut = false;
|
|
96
|
+
const resetIdleTimer = () => {
|
|
97
|
+
if (!idleTimeoutMs)
|
|
98
|
+
return;
|
|
99
|
+
clearTimeout(idleTimer);
|
|
100
|
+
idleTimer = setTimeout(() => {
|
|
101
|
+
idledOut = true;
|
|
102
|
+
controller.abort();
|
|
103
|
+
}, idleTimeoutMs);
|
|
104
|
+
};
|
|
105
|
+
let retry = true;
|
|
106
|
+
let error;
|
|
60
107
|
try {
|
|
108
|
+
resetIdleTimer();
|
|
109
|
+
const token = typeof this.token === 'function' ? this.token() : this.token;
|
|
61
110
|
const response = await globalThis.fetch(this.url, {
|
|
62
111
|
headers: {
|
|
63
|
-
'Authorization': `Bearer ${
|
|
112
|
+
'Authorization': `Bearer ${token}`,
|
|
64
113
|
'Accept': 'text/event-stream',
|
|
65
114
|
'Cache-Control': 'no-cache',
|
|
66
115
|
},
|
|
67
116
|
signal: controller.signal,
|
|
68
117
|
});
|
|
69
|
-
// Guard against a concurrent connect() that replaced our controller.
|
|
70
|
-
if (this.abortController !== controller)
|
|
71
|
-
return;
|
|
72
118
|
if (!response.ok || !response.body) {
|
|
119
|
+
await response.body?.cancel();
|
|
120
|
+
retry = response.ok || SseConnection.isRetryableStatus(response.status);
|
|
73
121
|
throw new Error(`SSE connection failed: HTTP ${response.status}`);
|
|
74
122
|
}
|
|
75
|
-
this.
|
|
76
|
-
|
|
123
|
+
this.attempt = 0;
|
|
124
|
+
this.setState('connected');
|
|
125
|
+
await this.readStream(response.body, onEvent, resetIdleTimer);
|
|
126
|
+
error = new Error('SSE stream closed by the server');
|
|
77
127
|
}
|
|
78
128
|
catch (err) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
onError?.(err instanceof Error ? err : new Error(String(err)));
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
129
|
+
error = idledOut
|
|
130
|
+
? new Error(`SSE stream received nothing for ${idleTimeoutMs}ms`)
|
|
131
|
+
: err instanceof Error
|
|
132
|
+
? err
|
|
133
|
+
: new Error(String(err));
|
|
87
134
|
}
|
|
88
|
-
|
|
89
|
-
|
|
135
|
+
finally {
|
|
136
|
+
clearTimeout(idleTimer);
|
|
90
137
|
}
|
|
138
|
+
// disconnect() or a newer connect() replaced this attempt, so it ends silently.
|
|
139
|
+
if (this.abortController !== controller)
|
|
140
|
+
return;
|
|
141
|
+
onError?.(error);
|
|
142
|
+
if (this.abortController !== controller)
|
|
143
|
+
return;
|
|
144
|
+
if (!retry || !this.options.reconnect) {
|
|
145
|
+
this.abortController = undefined;
|
|
146
|
+
this.setState('error');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
this.setState('reconnecting');
|
|
150
|
+
this.reconnectTimer = setTimeout(() => {
|
|
151
|
+
this.reconnectTimer = undefined;
|
|
152
|
+
this.open(onEvent, onError);
|
|
153
|
+
}, this.nextReconnectDelay());
|
|
91
154
|
})();
|
|
92
155
|
}
|
|
93
|
-
/**
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Exponential backoff with jitter, so clients that lost the same server do not all retry at
|
|
158
|
+
* the same instant when it comes back.
|
|
159
|
+
*/
|
|
160
|
+
nextReconnectDelay() {
|
|
161
|
+
const { minReconnectDelayMs, maxReconnectDelayMs } = this.options;
|
|
162
|
+
const base = Math.min(maxReconnectDelayMs, minReconnectDelayMs * 2 ** this.attempt);
|
|
163
|
+
this.attempt++;
|
|
164
|
+
return base / 2 + Math.random() * (base / 2);
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* 401 is retryable because the token is re-read on every attempt and may have been refreshed
|
|
168
|
+
* in the meantime. Other client errors (403, 404, ...) will not change on their own.
|
|
169
|
+
*/
|
|
170
|
+
static isRetryableStatus(status) {
|
|
171
|
+
return status >= 500 || status === 401 || status === 408 || status === 429;
|
|
172
|
+
}
|
|
173
|
+
setState(state) {
|
|
174
|
+
if (this._state === state)
|
|
175
|
+
return;
|
|
176
|
+
this._state = state;
|
|
177
|
+
this.emit('state', state);
|
|
98
178
|
}
|
|
99
179
|
/** Parse the raw `ReadableStream` body into SSE frames, calling `onEvent` for each complete frame. */
|
|
100
|
-
async readStream(body, onEvent) {
|
|
180
|
+
async readStream(body, onEvent, onChunk) {
|
|
101
181
|
const reader = body.getReader();
|
|
102
182
|
const decoder = new TextDecoder();
|
|
103
183
|
let buffer = '';
|
|
@@ -108,6 +188,7 @@ export class SseConnection {
|
|
|
108
188
|
const { done, value } = await reader.read();
|
|
109
189
|
if (done)
|
|
110
190
|
break;
|
|
191
|
+
onChunk();
|
|
111
192
|
buffer += decoder.decode(value, { stream: true });
|
|
112
193
|
const lines = buffer.split('\n');
|
|
113
194
|
buffer = lines.pop() ?? '';
|
package/package.json
CHANGED
package/script/mod.d.ts
CHANGED
|
@@ -54,7 +54,7 @@ export type { HttpClientOptions, HttpLogCode, HttpLogEvent, HttpLogger, HttpRequ
|
|
|
54
54
|
export { TypedEmitter } from './src/emitter.js';
|
|
55
55
|
export type { EventHandler } from './src/emitter.js';
|
|
56
56
|
export { SseConnection } from './src/sse.js';
|
|
57
|
-
export type { SseState } from './src/sse.js';
|
|
57
|
+
export type { SseConnectionEvents, SseOptions, SseState } from './src/sse.js';
|
|
58
58
|
export { joinIncludes, parseIssuerRef, toNanoID } from './src/types.js';
|
|
59
59
|
export type { DeletedListOptions, DeletedVisibility, IncludeOptions, ISODate, IssuerRef, ListOptions, NanoID, Paginated, ParsedIssuer, PowerAction, PowerState, ResourceColor, ResourceWith, ServerRestrictedState, SftpPermission, UnionToIntersection, } from './src/types.js';
|
|
60
60
|
export { Account, AccountResource, AccountSshKeysManager, ApiKeyAccount, SshKey, UserAccount, } from './src/resources/account.js';
|
package/script/mod.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAG3D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,YAAY,EACX,QAAQ,EACR,YAAY,EACZ,qBAAqB,EACrB,cAAc,EACd,WAAW,EACX,aAAa,GACb,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,YAAY,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,YAAY,EACX,iBAAiB,EACjB,WAAW,EACX,YAAY,EACZ,UAAU,EACV,wBAAwB,EACxB,wBAAwB,EACxB,0BAA0B,EAC1B,cAAc,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,YAAY,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,YAAY,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,8 +6,8 @@ export type BackupAdapter = 'whisker' | 's3';
|
|
|
6
6
|
export interface CreateBackupOptions {
|
|
7
7
|
/** Storage adapter to write the backup to. */
|
|
8
8
|
adapter: BackupAdapter;
|
|
9
|
-
/** Client-chosen
|
|
10
|
-
|
|
9
|
+
/** Client-chosen 12-character nanoid identifying the backup. */
|
|
10
|
+
id: string;
|
|
11
11
|
/** Newline- or glob-separated ignore patterns. */
|
|
12
12
|
ignore?: string;
|
|
13
13
|
}
|
|
@@ -28,7 +28,7 @@ export interface RestoreBackupOptions {
|
|
|
28
28
|
*
|
|
29
29
|
* @example
|
|
30
30
|
* ```ts ignore
|
|
31
|
-
* const job = await server.backups.create({ adapter: 'whisker',
|
|
31
|
+
* const job = await server.backups.create({ adapter: 'whisker', id });
|
|
32
32
|
* await job.wait();
|
|
33
33
|
* ```
|
|
34
34
|
*/
|
|
@@ -38,9 +38,9 @@ export declare class ServerBackupsManager {
|
|
|
38
38
|
constructor(node: NodeClient);
|
|
39
39
|
/** Start a backup. Returns the job to track. */
|
|
40
40
|
create(opts: CreateBackupOptions): Promise<ServerJob>;
|
|
41
|
-
/** Restore a backup by its
|
|
42
|
-
restore(
|
|
43
|
-
/** Delete a backup by its
|
|
44
|
-
delete(
|
|
41
|
+
/** Restore a backup by its nanoid. Returns the job to track. */
|
|
42
|
+
restore(backupId: string, opts: RestoreBackupOptions): Promise<ServerJob>;
|
|
43
|
+
/** Delete a backup by its nanoid. Treats an already-missing backup as success. */
|
|
44
|
+
delete(backupId: string): Promise<void>;
|
|
45
45
|
}
|
|
46
46
|
//# sourceMappingURL=backups.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backups.d.ts","sourceRoot":"","sources":["../../../../src/src/resources/servers/backups.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,+EAA+E;AAC/E,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,IAAI,CAAC;AAE7C,qCAAqC;AACrC,MAAM,WAAW,mBAAmB;IACnC,8CAA8C;IAC9C,OAAO,EAAE,aAAa,CAAC;IACvB,
|
|
1
|
+
{"version":3,"file":"backups.d.ts","sourceRoot":"","sources":["../../../../src/src/resources/servers/backups.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,+EAA+E;AAC/E,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,IAAI,CAAC;AAE7C,qCAAqC;AACrC,MAAM,WAAW,mBAAmB;IACnC,8CAA8C;IAC9C,OAAO,EAAE,aAAa,CAAC;IACvB,gEAAgE;IAChE,EAAE,EAAE,MAAM,CAAC;IACX,kDAAkD;IAClD,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,sCAAsC;AACtC,MAAM,WAAW,oBAAoB;IACpC,2CAA2C;IAC3C,OAAO,EAAE,aAAa,CAAC;IACvB,yDAAyD;IACzD,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,oBAAoB;IAEb,OAAO,CAAC,QAAQ,CAAC,IAAI;IADxC,gBAAgB;gBACoB,IAAI,EAAE,UAAU;IAEpD,gDAAgD;IACnC,MAAM,CAAC,IAAI,EAAE,mBAAmB,GAAG,OAAO,CAAC,SAAS,CAAC;IASlE,gEAAgE;IACnD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,oBAAoB,GAAG,OAAO,CAAC,SAAS,CAAC;IAStF,kFAAkF;IACrE,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGpD"}
|
|
@@ -10,7 +10,7 @@ const jobs_js_1 = require("./jobs.js");
|
|
|
10
10
|
*
|
|
11
11
|
* @example
|
|
12
12
|
* ```ts ignore
|
|
13
|
-
* const job = await server.backups.create({ adapter: 'whisker',
|
|
13
|
+
* const job = await server.backups.create({ adapter: 'whisker', id });
|
|
14
14
|
* await job.wait();
|
|
15
15
|
* ```
|
|
16
16
|
*/
|
|
@@ -24,24 +24,24 @@ class ServerBackupsManager {
|
|
|
24
24
|
async create(opts) {
|
|
25
25
|
const { data } = await this.node.postJson('/backup', {
|
|
26
26
|
adapter: opts.adapter,
|
|
27
|
-
|
|
27
|
+
id: opts.id,
|
|
28
28
|
ignore: opts.ignore ?? '',
|
|
29
29
|
});
|
|
30
30
|
return new jobs_js_1.ServerJob({ id: data.job_id }, this.node);
|
|
31
31
|
}
|
|
32
|
-
/** Restore a backup by its
|
|
33
|
-
async restore(
|
|
32
|
+
/** Restore a backup by its nanoid. Returns the job to track. */
|
|
33
|
+
async restore(backupId, opts) {
|
|
34
34
|
const body = { adapter: opts.adapter };
|
|
35
35
|
if (opts.truncateDirectory !== undefined)
|
|
36
36
|
body['truncate_directory'] = opts.truncateDirectory;
|
|
37
37
|
if (opts.downloadUrl !== undefined)
|
|
38
38
|
body['download_url'] = opts.downloadUrl;
|
|
39
|
-
const { data } = await this.node.postJson(`/backup/${
|
|
39
|
+
const { data } = await this.node.postJson(`/backup/${backupId}/restore`, body);
|
|
40
40
|
return new jobs_js_1.ServerJob({ id: data.job_id }, this.node);
|
|
41
41
|
}
|
|
42
|
-
/** Delete a backup by its
|
|
43
|
-
async delete(
|
|
44
|
-
await this.node.fetch(`/backup/${
|
|
42
|
+
/** Delete a backup by its nanoid. Treats an already-missing backup as success. */
|
|
43
|
+
async delete(backupId) {
|
|
44
|
+
await this.node.fetch(`/backup/${backupId}`, { method: 'DELETE' });
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
exports.ServerBackupsManager = ServerBackupsManager;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ReactiveResource } from '../../reactive.js';
|
|
2
|
+
import { type SseState } from '../../sse.js';
|
|
2
3
|
import type { NanoID, PowerState } from '../../types.js';
|
|
3
4
|
import type { JobStatus } from './jobs.js';
|
|
4
5
|
/** Real-time resource utilization reported by the node. */
|
|
@@ -38,7 +39,7 @@ export interface JobLogEvent {
|
|
|
38
39
|
/** Payload for the `backup_completed` event. */
|
|
39
40
|
export interface BackupCompletedEvent {
|
|
40
41
|
/** The completed backup's id. */
|
|
41
|
-
|
|
42
|
+
id: string;
|
|
42
43
|
isSuccessful: boolean;
|
|
43
44
|
checksum: string;
|
|
44
45
|
checksumType: string;
|
|
@@ -72,7 +73,7 @@ export interface ServerConnectionEvents {
|
|
|
72
73
|
install_output: string;
|
|
73
74
|
/** An out-of-band status message from the daemon. */
|
|
74
75
|
daemon_message: string;
|
|
75
|
-
/** A backup finished; the payload's `
|
|
76
|
+
/** A backup finished; the payload's `id` identifies which one. */
|
|
76
77
|
backup_completed: BackupCompletedEvent;
|
|
77
78
|
/** A backup restore finished. */
|
|
78
79
|
backup_restore_completed: '';
|
|
@@ -83,13 +84,19 @@ export interface ServerConnectionEvents {
|
|
|
83
84
|
* Gated on `server.transfer.log`, so it never arrives for a viewer who lacks it.
|
|
84
85
|
*/
|
|
85
86
|
transfer_logs: string;
|
|
87
|
+
/** The stream to the daemon changed state. Emitted locally by the client, not by the daemon. */
|
|
88
|
+
connection_state: SseState;
|
|
86
89
|
}
|
|
87
90
|
/**
|
|
88
91
|
* A real-time SSE connection to a specific server on its Whisker node daemon.
|
|
89
92
|
*
|
|
90
93
|
* Emits typed events for console output, power state changes, and resource utilization.
|
|
91
94
|
* Also maintains a rolling buffer of console output lines in {@link output}, pre-populated
|
|
92
|
-
* with recent history fetched from the node on {@link
|
|
95
|
+
* with recent history fetched from the node on {@link open}.
|
|
96
|
+
*
|
|
97
|
+
* The stream reconnects on its own after the daemon restarts or the network drops. Track it
|
|
98
|
+
* through {@link state} or the `connection_state` event. After a reconnect, console lines the
|
|
99
|
+
* daemon still holds from the gap are appended to {@link output} and emitted as `console_output`.
|
|
93
100
|
*
|
|
94
101
|
* Obtain a connection via `Server.createConnection`.
|
|
95
102
|
*
|
|
@@ -112,12 +119,20 @@ export interface ServerConnectionEvents {
|
|
|
112
119
|
export declare class ServerConnection extends ReactiveResource {
|
|
113
120
|
private readonly serverId;
|
|
114
121
|
private readonly nodeUrl;
|
|
115
|
-
private readonly
|
|
122
|
+
private readonly getToken;
|
|
116
123
|
/** Maximum number of console output lines retained in {@link ServerConnection.output}. */
|
|
117
124
|
private static readonly maxOutputLines;
|
|
125
|
+
/** Console history lines fetched from the node on open and after each reconnect. */
|
|
126
|
+
private static readonly historyLines;
|
|
127
|
+
/**
|
|
128
|
+
* Whisker sends a keepalive every 20 seconds, so a stream silent for this long is dead even
|
|
129
|
+
* if the socket never closed.
|
|
130
|
+
*/
|
|
131
|
+
private static readonly idleTimeoutMs;
|
|
118
132
|
private readonly listeners;
|
|
119
133
|
private sse?;
|
|
120
|
-
|
|
134
|
+
/** Live console lines held back while the post-reconnect history is merged in. */
|
|
135
|
+
private pendingOutput?;
|
|
121
136
|
/**
|
|
122
137
|
* Rolling buffer of console output lines, capped at {@link ServerConnection.maxOutputLines}.
|
|
123
138
|
*
|
|
@@ -128,7 +143,9 @@ export declare class ServerConnection extends ReactiveResource {
|
|
|
128
143
|
*/
|
|
129
144
|
output: string[];
|
|
130
145
|
/** @internal */
|
|
131
|
-
constructor(serverId: NanoID, nodeUrl: string,
|
|
146
|
+
constructor(serverId: NanoID, nodeUrl: string, getToken: () => string);
|
|
147
|
+
/** State of the stream to the daemon. */
|
|
148
|
+
get state(): SseState;
|
|
132
149
|
/** `true` if the SSE connection is currently open. */
|
|
133
150
|
get isConnected(): boolean;
|
|
134
151
|
/**
|
|
@@ -139,7 +156,7 @@ export declare class ServerConnection extends ReactiveResource {
|
|
|
139
156
|
*
|
|
140
157
|
* Only one stream is maintained at a time.
|
|
141
158
|
*
|
|
142
|
-
* @param onError Optional callback invoked
|
|
159
|
+
* @param onError Optional callback invoked each time the stream drops or a connection attempt fails.
|
|
143
160
|
*/
|
|
144
161
|
open(onError?: (error: Error) => void): Promise<void>;
|
|
145
162
|
/** Close the SSE stream and stop receiving events. */
|
|
@@ -160,6 +177,16 @@ export declare class ServerConnection extends ReactiveResource {
|
|
|
160
177
|
off<K extends keyof ServerConnectionEvents>(event: K, handler: (payload: ServerConnectionEvents[K]) => void): void;
|
|
161
178
|
/** Remove all event handlers for all event types. */
|
|
162
179
|
removeAllListeners(): void;
|
|
180
|
+
private fetchHistory;
|
|
181
|
+
/**
|
|
182
|
+
* Fill in the console lines printed while the stream was down.
|
|
183
|
+
*
|
|
184
|
+
* Live lines are held back until the history arrives, because the history snapshot may
|
|
185
|
+
* already contain them. Lines that fell out of the daemon's history window are lost.
|
|
186
|
+
*/
|
|
187
|
+
private resyncOutput;
|
|
188
|
+
private appendOutput;
|
|
189
|
+
private emit;
|
|
163
190
|
/** Parse and dispatch a raw SSE event to registered handlers. */
|
|
164
191
|
private dispatch;
|
|
165
192
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../../src/src/resources/servers/connection.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"connection.d.ts","sourceRoot":"","sources":["../../../../src/src/resources/servers/connection.ts"],"names":[],"mappings":"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"}
|