@meowpanel/api 1.0.0-beta.1 → 1.0.0-beta.3
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/client.d.ts +15 -0
- package/esm/src/client.d.ts.map +1 -1
- package/esm/src/client.js +22 -1
- package/esm/src/http.d.ts +13 -0
- package/esm/src/http.d.ts.map +1 -1
- package/esm/src/http.js +80 -3
- package/esm/src/resources/auth.d.ts +18 -0
- package/esm/src/resources/auth.d.ts.map +1 -1
- package/esm/src/resources/auth.js +12 -0
- package/esm/src/sse.d.ts +3 -1
- package/esm/src/sse.d.ts.map +1 -1
- package/esm/src/sse.js +4 -0
- package/package.json +1 -1
- package/script/mod.d.ts +1 -1
- package/script/mod.d.ts.map +1 -1
- package/script/src/client.d.ts +15 -0
- package/script/src/client.d.ts.map +1 -1
- package/script/src/client.js +22 -1
- package/script/src/http.d.ts +13 -0
- package/script/src/http.d.ts.map +1 -1
- package/script/src/http.js +80 -3
- package/script/src/resources/auth.d.ts +18 -0
- package/script/src/resources/auth.d.ts.map +1 -1
- package/script/src/resources/auth.js +12 -0
- package/script/src/sse.d.ts +3 -1
- package/script/src/sse.d.ts.map +1 -1
- package/script/src/sse.js +4 -0
package/esm/mod.d.ts
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
export { MeowPanelApi } from './src/client.js';
|
|
46
46
|
export type { MeowPanelApiOptions } from './src/client.js';
|
|
47
47
|
export { AuthResource } from './src/resources/auth.js';
|
|
48
|
-
export type { AuthMeta, AuthProvider } from './src/resources/auth.js';
|
|
48
|
+
export type { AuthMeta, AuthProvider, RefreshOptions, RefreshResponse } from './src/resources/auth.js';
|
|
49
49
|
export { ReactiveResource } from './src/reactive.js';
|
|
50
50
|
export { ApiError } from './src/errors.js';
|
|
51
51
|
export type { ApiErrorOptions } from './src/errors.js';
|
package/esm/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,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
|
package/esm/src/client.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { HttpLogger } from './http.js';
|
|
|
2
2
|
import { SseConnection } from './sse.js';
|
|
3
3
|
import { AccountResource } from './resources/account.js';
|
|
4
4
|
import { AuthResource } from './resources/auth.js';
|
|
5
|
+
import type { RefreshOptions, RefreshResponse } from './resources/auth.js';
|
|
5
6
|
import { ApiKeysNamespace } from './resources/api-keys.js';
|
|
6
7
|
import { EggsNamespace } from './resources/eggs.js';
|
|
7
8
|
import { HostsNamespace } from './resources/hosts.js';
|
|
@@ -46,6 +47,12 @@ export interface MeowPanelApiOptions {
|
|
|
46
47
|
* Defaults to `undefined` (browser default is `'same-origin'`).
|
|
47
48
|
*/
|
|
48
49
|
credentials?: RequestCredentials;
|
|
50
|
+
/**
|
|
51
|
+
* Callback invoked when the access token is automatically refreshed.
|
|
52
|
+
*
|
|
53
|
+
* Useful for persisting the new token or updating external state.
|
|
54
|
+
*/
|
|
55
|
+
onTokenRefresh?: (token: string) => void;
|
|
49
56
|
}
|
|
50
57
|
/**
|
|
51
58
|
* The root MeowPanel API client.
|
|
@@ -80,6 +87,7 @@ export interface MeowPanelApiOptions {
|
|
|
80
87
|
*/
|
|
81
88
|
export declare class MeowPanelApi {
|
|
82
89
|
private readonly http;
|
|
90
|
+
private readonly sseConnections;
|
|
83
91
|
/**
|
|
84
92
|
* Fetch authentication configuration (available login providers).
|
|
85
93
|
*
|
|
@@ -229,5 +237,12 @@ export declare class MeowPanelApi {
|
|
|
229
237
|
* ```
|
|
230
238
|
*/
|
|
231
239
|
connectSse(): SseConnection;
|
|
240
|
+
/**
|
|
241
|
+
* Manually trigger a token refresh.
|
|
242
|
+
*
|
|
243
|
+
* Typically not needed as the client refreshes automatically when using
|
|
244
|
+
* JWT tokens that are about to expire.
|
|
245
|
+
*/
|
|
246
|
+
refresh(opts?: RefreshOptions): Promise<RefreshResponse>;
|
|
232
247
|
}
|
|
233
248
|
//# sourceMappingURL=client.d.ts.map
|
package/esm/src/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA4B;IAE3D;;;;;;;;OAQG;IACH,SAAgB,IAAI,EAAE,YAAY,CAAC;IAEnC;;;;;;;;;OASG;IACH,SAAgB,OAAO,EAAE,eAAe,CAAC;IAEzC;;;;;;;;OAQG;IACH,SAAgB,OAAO,EAAE,gBAAgB,CAAC;IAE1C;;;;;;;;;;;OAWG;IACH,SAAgB,OAAO,EAAE,gBAAgB,CAAC;IAE1C;;;;;;;;;;OAUG;IACH,SAAgB,KAAK,EAAE,cAAc,CAAC;IAEtC;;;;;;;;;;;OAWG;IACH,SAAgB,IAAI,EAAE,aAAa,CAAC;IAEpC;;;;;;;;;OASG;IACH,SAAgB,KAAK,EAAE,cAAc,CAAC;IAEtC;;;;;;;;;;OAUG;IACH,SAAgB,YAAY,EAAE,qBAAqB,CAAC;IAEpD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,SAAgB,OAAO,EAAE,gBAAgB,CAAC;gBAEvB,OAAO,EAAE,mBAAmB;IA6B/C;;;;;;OAMG;IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACI,UAAU,IAAI,aAAa;IAQlC;;;;;OAKG;IACI,OAAO,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAG/D"}
|
package/esm/src/client.js
CHANGED
|
@@ -42,6 +42,7 @@ import { ServersNamespace } from './resources/servers/index.js';
|
|
|
42
42
|
*/
|
|
43
43
|
export class MeowPanelApi {
|
|
44
44
|
http;
|
|
45
|
+
sseConnections = new Set();
|
|
45
46
|
/**
|
|
46
47
|
* Fetch authentication configuration (available login providers).
|
|
47
48
|
*
|
|
@@ -159,12 +160,21 @@ export class MeowPanelApi {
|
|
|
159
160
|
*/
|
|
160
161
|
servers;
|
|
161
162
|
constructor(options) {
|
|
163
|
+
if (!options?.url)
|
|
164
|
+
throw new Error('MeowPanelApi requires a "url" option (e.g. "https://panel.example.com").');
|
|
165
|
+
const userCallback = options.onTokenRefresh;
|
|
162
166
|
this.http = new HttpClient({
|
|
163
167
|
url: options.url.toString(),
|
|
164
168
|
token: options.token,
|
|
165
169
|
fetch: options.fetch,
|
|
166
170
|
logger: options.logger,
|
|
167
171
|
credentials: options.credentials,
|
|
172
|
+
onTokenRefresh: (token) => {
|
|
173
|
+
for (const sse of this.sseConnections) {
|
|
174
|
+
sse.updateToken(token);
|
|
175
|
+
}
|
|
176
|
+
userCallback?.(token);
|
|
177
|
+
},
|
|
168
178
|
});
|
|
169
179
|
this.auth = new AuthResource(this.http);
|
|
170
180
|
this.account = new AccountResource(this.http);
|
|
@@ -211,6 +221,17 @@ export class MeowPanelApi {
|
|
|
211
221
|
*/
|
|
212
222
|
connectSse() {
|
|
213
223
|
const url = this.http.buildUrl('/sse');
|
|
214
|
-
|
|
224
|
+
const sse = new SseConnection(url, this.http.getToken());
|
|
225
|
+
this.sseConnections.add(sse);
|
|
226
|
+
return sse;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Manually trigger a token refresh.
|
|
230
|
+
*
|
|
231
|
+
* Typically not needed as the client refreshes automatically when using
|
|
232
|
+
* JWT tokens that are about to expire.
|
|
233
|
+
*/
|
|
234
|
+
refresh(opts) {
|
|
235
|
+
return this.auth.refresh(opts);
|
|
215
236
|
}
|
|
216
237
|
}
|
package/esm/src/http.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface HttpClientOptions {
|
|
|
19
19
|
* Defaults to `undefined` (browser default is `'same-origin'`).
|
|
20
20
|
*/
|
|
21
21
|
credentials?: RequestCredentials;
|
|
22
|
+
/** Callback invoked when the access token is refreshed. */
|
|
23
|
+
onTokenRefresh?: (token: string) => void;
|
|
22
24
|
}
|
|
23
25
|
/** Typed lifecycle code emitted by {@link HttpClient}'s optional logger. */
|
|
24
26
|
export type HttpLogCode = 'request.start' | 'request.success' | 'request.error';
|
|
@@ -70,6 +72,8 @@ export declare class HttpClient {
|
|
|
70
72
|
protected readonly fetchImpl: typeof globalThis.fetch;
|
|
71
73
|
protected readonly logger?: HttpLogger;
|
|
72
74
|
protected readonly credentials?: RequestCredentials;
|
|
75
|
+
protected readonly onTokenRefresh?: (token: string) => void;
|
|
76
|
+
private refreshPromise;
|
|
73
77
|
constructor(options: HttpClientOptions);
|
|
74
78
|
/** Replace the bearer token for all subsequent requests. */
|
|
75
79
|
setToken(token: string): void;
|
|
@@ -83,9 +87,18 @@ export declare class HttpClient {
|
|
|
83
87
|
protected parseError(response: Response): Promise<ApiError>;
|
|
84
88
|
private log;
|
|
85
89
|
private executeFetch;
|
|
90
|
+
/** Extract the `exp` claim from a JWT without verification. Returns 0 for non-JWT tokens. */
|
|
91
|
+
private getTokenExp;
|
|
92
|
+
/** Refresh the access token if it's a JWT and about to expire. */
|
|
93
|
+
private refreshTokenIfNeeded;
|
|
94
|
+
/** Force a token refresh regardless of expiry. Only works if credentials are set (cookie auth). */
|
|
95
|
+
private forceRefresh;
|
|
86
96
|
/**
|
|
87
97
|
* Perform a raw `fetch` and throw {@link ApiError} on non-2xx responses.
|
|
88
98
|
*
|
|
99
|
+
* Proactively refreshes JWT tokens that are about to expire and retries
|
|
100
|
+
* once on `401 Unauthorized` after forcing a token refresh.
|
|
101
|
+
*
|
|
89
102
|
* @param path Path relative to the API base URL, e.g. `/servers`.
|
|
90
103
|
* @param init Standard `RequestInit` options.
|
|
91
104
|
* @param params Query parameters to append.
|
package/esm/src/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEzD,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IACjC,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,4EAA4E;IAC5E,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/src/http.ts"],"names":[],"mappings":"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"}
|
package/esm/src/http.js
CHANGED
|
@@ -11,15 +11,24 @@ export class HttpClient {
|
|
|
11
11
|
fetchImpl;
|
|
12
12
|
logger;
|
|
13
13
|
credentials;
|
|
14
|
+
onTokenRefresh;
|
|
15
|
+
refreshPromise = null;
|
|
14
16
|
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
15
17
|
return `HttpClient { ${this.baseUrl} }`;
|
|
16
18
|
}
|
|
17
19
|
constructor(options) {
|
|
18
|
-
|
|
20
|
+
try {
|
|
21
|
+
new URL(options.url);
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
throw new Error(`Invalid MeowPanel URL: "${options.url}". An absolute URL is required (e.g. "https://panel.example.com").`);
|
|
25
|
+
}
|
|
26
|
+
this.baseUrl = options.url.replace(/\/$/, '') + '/api/v1';
|
|
19
27
|
this.token = options.token ?? '';
|
|
20
28
|
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
21
29
|
this.logger = options.logger;
|
|
22
30
|
this.credentials = options.credentials;
|
|
31
|
+
this.onTokenRefresh = options.onTokenRefresh;
|
|
23
32
|
}
|
|
24
33
|
/** Replace the bearer token for all subsequent requests. */
|
|
25
34
|
setToken(token) {
|
|
@@ -131,18 +140,86 @@ export class HttpClient {
|
|
|
131
140
|
throw error;
|
|
132
141
|
}
|
|
133
142
|
}
|
|
143
|
+
/** Extract the `exp` claim from a JWT without verification. Returns 0 for non-JWT tokens. */
|
|
144
|
+
getTokenExp() {
|
|
145
|
+
const parts = this.token.split('.');
|
|
146
|
+
if (parts.length !== 3)
|
|
147
|
+
return 0; // Not a JWT token
|
|
148
|
+
try {
|
|
149
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
150
|
+
return typeof payload.exp === 'number' ? payload.exp : 0;
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
return 0;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
/** Refresh the access token if it's a JWT and about to expire. */
|
|
157
|
+
async refreshTokenIfNeeded() {
|
|
158
|
+
const exp = this.getTokenExp();
|
|
159
|
+
if (exp === 0)
|
|
160
|
+
return;
|
|
161
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
162
|
+
if (exp - nowSec > 60)
|
|
163
|
+
return;
|
|
164
|
+
await this.forceRefresh();
|
|
165
|
+
}
|
|
166
|
+
/** Force a token refresh regardless of expiry. Only works if credentials are set (cookie auth). */
|
|
167
|
+
async forceRefresh() {
|
|
168
|
+
if (this.refreshPromise) {
|
|
169
|
+
await this.refreshPromise;
|
|
170
|
+
return !!this.token;
|
|
171
|
+
}
|
|
172
|
+
this.refreshPromise = (async () => {
|
|
173
|
+
try {
|
|
174
|
+
const res = await this.fetchImpl(this.baseUrl + '/auth/refresh', {
|
|
175
|
+
method: 'POST',
|
|
176
|
+
headers: {
|
|
177
|
+
'Content-Type': 'application/json',
|
|
178
|
+
'Accept': 'application/json',
|
|
179
|
+
},
|
|
180
|
+
credentials: this.credentials,
|
|
181
|
+
});
|
|
182
|
+
if (res.ok) {
|
|
183
|
+
const data = await res.json();
|
|
184
|
+
this.token = data.access_token;
|
|
185
|
+
this.onTokenRefresh?.(data.access_token);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
this.refreshPromise = null;
|
|
190
|
+
}
|
|
191
|
+
})();
|
|
192
|
+
await this.refreshPromise;
|
|
193
|
+
return !!this.token;
|
|
194
|
+
}
|
|
134
195
|
/**
|
|
135
196
|
* Perform a raw `fetch` and throw {@link ApiError} on non-2xx responses.
|
|
136
197
|
*
|
|
198
|
+
* Proactively refreshes JWT tokens that are about to expire and retries
|
|
199
|
+
* once on `401 Unauthorized` after forcing a token refresh.
|
|
200
|
+
*
|
|
137
201
|
* @param path Path relative to the API base URL, e.g. `/servers`.
|
|
138
202
|
* @param init Standard `RequestInit` options.
|
|
139
203
|
* @param params Query parameters to append.
|
|
140
204
|
*/
|
|
141
205
|
async fetch(path, init = {}, params) {
|
|
142
|
-
|
|
206
|
+
await this.refreshTokenIfNeeded();
|
|
207
|
+
const buildInit = () => ({
|
|
143
208
|
...init,
|
|
144
209
|
headers: { ...this.defaultHeaders, ...init.headers },
|
|
145
|
-
}
|
|
210
|
+
});
|
|
211
|
+
try {
|
|
212
|
+
return await this.executeFetch(path, buildInit(), params);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
if (error instanceof ApiError && error.status === 401 && path !== '/auth/refresh') {
|
|
216
|
+
const refreshed = await this.forceRefresh();
|
|
217
|
+
if (refreshed) {
|
|
218
|
+
return await this.executeFetch(path, buildInit(), params);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
throw error;
|
|
222
|
+
}
|
|
146
223
|
}
|
|
147
224
|
/**
|
|
148
225
|
* GET and deserialize a JSON response body.
|
|
@@ -13,6 +13,18 @@ export interface AuthMeta {
|
|
|
13
13
|
/** Available auth providers keyed by provider ID (e.g. `'email'`, `'whmcs'`). */
|
|
14
14
|
providers: Record<string, AuthProvider>;
|
|
15
15
|
}
|
|
16
|
+
/** Response from the token refresh endpoint. */
|
|
17
|
+
export interface RefreshResponse {
|
|
18
|
+
access_token: string;
|
|
19
|
+
expires_in_seconds: number;
|
|
20
|
+
token_type: string;
|
|
21
|
+
account?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
/** Options for the refresh request. */
|
|
24
|
+
export interface RefreshOptions {
|
|
25
|
+
/** Fields to include in the response (e.g. `['account', 'display']`). */
|
|
26
|
+
include?: string[];
|
|
27
|
+
}
|
|
16
28
|
/**
|
|
17
29
|
* Resource for authentication configuration.
|
|
18
30
|
*
|
|
@@ -35,5 +47,11 @@ export declare class AuthResource {
|
|
|
35
47
|
* Returns the available login providers and their display fields.
|
|
36
48
|
*/
|
|
37
49
|
getMeta(): Promise<AuthMeta>;
|
|
50
|
+
/**
|
|
51
|
+
* Exchange a refresh token for a short-lived JWT access token.
|
|
52
|
+
*
|
|
53
|
+
* Used for exhanging tokens via cookies, managed by the host.
|
|
54
|
+
*/
|
|
55
|
+
refresh(opts?: RefreshOptions): Promise<RefreshResponse>;
|
|
38
56
|
}
|
|
39
57
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/src/resources/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAS7C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACxC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,YAAY;IAEL,OAAO,CAAC,QAAQ,CAAC,IAAI;IADxC,gBAAgB;gBACoB,IAAI,EAAE,UAAU;IAEpD;;;;OAIG;IACI,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/src/resources/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAS7C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACxC;AAED,gDAAgD;AAChD,MAAM,WAAW,eAAe;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,uCAAuC;AACvC,MAAM,WAAW,cAAc;IAC9B,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,YAAY;IAEL,OAAO,CAAC,QAAQ,CAAC,IAAI;IADxC,gBAAgB;gBACoB,IAAI,EAAE,UAAU;IAEpD;;;;OAIG;IACI,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;IAInC;;;;OAIG;IACI,OAAO,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,eAAe,CAAC;CAQnE"}
|
|
@@ -24,4 +24,16 @@ export class AuthResource {
|
|
|
24
24
|
getMeta() {
|
|
25
25
|
return this.http.get('/auth');
|
|
26
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* Exchange a refresh token for a short-lived JWT access token.
|
|
29
|
+
*
|
|
30
|
+
* Used for exhanging tokens via cookies, managed by the host.
|
|
31
|
+
*/
|
|
32
|
+
refresh(opts = {}) {
|
|
33
|
+
const params = {};
|
|
34
|
+
if (opts.include?.length) {
|
|
35
|
+
params['include'] = opts.include.join(',');
|
|
36
|
+
}
|
|
37
|
+
return this.http.post('/auth/refresh', undefined, { params });
|
|
38
|
+
}
|
|
27
39
|
}
|
package/esm/src/sse.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type SseState = 'disconnected' | 'connecting' | 'connected' | 'error';
|
|
|
20
20
|
*/
|
|
21
21
|
export declare class SseConnection {
|
|
22
22
|
private readonly url;
|
|
23
|
-
private
|
|
23
|
+
private token;
|
|
24
24
|
private abortController?;
|
|
25
25
|
private _state;
|
|
26
26
|
/**
|
|
@@ -28,6 +28,8 @@ export declare class SseConnection {
|
|
|
28
28
|
* @param token Bearer token used in the `Authorization` header.
|
|
29
29
|
*/
|
|
30
30
|
constructor(url: string, token: string);
|
|
31
|
+
/** Update the bearer token for subsequent reconnections. */
|
|
32
|
+
updateToken(token: string): void;
|
|
31
33
|
/** Current connection state. */
|
|
32
34
|
get state(): SseState;
|
|
33
35
|
/** `true` when the connection is actively open. */
|
package/esm/src/sse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/src/sse.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;AAE7E;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,aAAa;IASxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/src/sse.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;AAE7E;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,aAAa;IASxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,KAAK;IATd,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,MAAM,CAA4B;IAE1C;;;OAGG;gBAEe,GAAG,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM;IAGtB,4DAA4D;IACrD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIvC,gCAAgC;IAChC,IAAW,KAAK,IAAI,QAAQ,CAE3B;IAED,mDAAmD;IACnD,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED;;;;;;;;;OASG;IACI,OAAO,CACb,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,EAC9C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAC9B,IAAI;IAyCP,0DAA0D;IACnD,UAAU,IAAI,IAAI;IAMzB,sGAAsG;YACxF,UAAU;CAmCxB"}
|
package/esm/src/sse.js
CHANGED
|
@@ -29,6 +29,10 @@ export class SseConnection {
|
|
|
29
29
|
this.url = url;
|
|
30
30
|
this.token = token;
|
|
31
31
|
}
|
|
32
|
+
/** Update the bearer token for subsequent reconnections. */
|
|
33
|
+
updateToken(token) {
|
|
34
|
+
this.token = token;
|
|
35
|
+
}
|
|
32
36
|
/** Current connection state. */
|
|
33
37
|
get state() {
|
|
34
38
|
return this._state;
|
package/package.json
CHANGED
package/script/mod.d.ts
CHANGED
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
export { MeowPanelApi } from './src/client.js';
|
|
46
46
|
export type { MeowPanelApiOptions } from './src/client.js';
|
|
47
47
|
export { AuthResource } from './src/resources/auth.js';
|
|
48
|
-
export type { AuthMeta, AuthProvider } from './src/resources/auth.js';
|
|
48
|
+
export type { AuthMeta, AuthProvider, RefreshOptions, RefreshResponse } from './src/resources/auth.js';
|
|
49
49
|
export { ReactiveResource } from './src/reactive.js';
|
|
50
50
|
export { ApiError } from './src/errors.js';
|
|
51
51
|
export type { ApiErrorOptions } from './src/errors.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,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"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"}
|
package/script/src/client.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { HttpLogger } from './http.js';
|
|
|
2
2
|
import { SseConnection } from './sse.js';
|
|
3
3
|
import { AccountResource } from './resources/account.js';
|
|
4
4
|
import { AuthResource } from './resources/auth.js';
|
|
5
|
+
import type { RefreshOptions, RefreshResponse } from './resources/auth.js';
|
|
5
6
|
import { ApiKeysNamespace } from './resources/api-keys.js';
|
|
6
7
|
import { EggsNamespace } from './resources/eggs.js';
|
|
7
8
|
import { HostsNamespace } from './resources/hosts.js';
|
|
@@ -46,6 +47,12 @@ export interface MeowPanelApiOptions {
|
|
|
46
47
|
* Defaults to `undefined` (browser default is `'same-origin'`).
|
|
47
48
|
*/
|
|
48
49
|
credentials?: RequestCredentials;
|
|
50
|
+
/**
|
|
51
|
+
* Callback invoked when the access token is automatically refreshed.
|
|
52
|
+
*
|
|
53
|
+
* Useful for persisting the new token or updating external state.
|
|
54
|
+
*/
|
|
55
|
+
onTokenRefresh?: (token: string) => void;
|
|
49
56
|
}
|
|
50
57
|
/**
|
|
51
58
|
* The root MeowPanel API client.
|
|
@@ -80,6 +87,7 @@ export interface MeowPanelApiOptions {
|
|
|
80
87
|
*/
|
|
81
88
|
export declare class MeowPanelApi {
|
|
82
89
|
private readonly http;
|
|
90
|
+
private readonly sseConnections;
|
|
83
91
|
/**
|
|
84
92
|
* Fetch authentication configuration (available login providers).
|
|
85
93
|
*
|
|
@@ -229,5 +237,12 @@ export declare class MeowPanelApi {
|
|
|
229
237
|
* ```
|
|
230
238
|
*/
|
|
231
239
|
connectSse(): SseConnection;
|
|
240
|
+
/**
|
|
241
|
+
* Manually trigger a token refresh.
|
|
242
|
+
*
|
|
243
|
+
* Typically not needed as the client refreshes automatically when using
|
|
244
|
+
* JWT tokens that are about to expire.
|
|
245
|
+
*/
|
|
246
|
+
refresh(opts?: RefreshOptions): Promise<RefreshResponse>;
|
|
232
247
|
}
|
|
233
248
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/src/client.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,8BAA8B,CAAC;AACrE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IACnC;;;;;;OAMG;IACH,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;IAClB;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC;;;;OAIG;IACH,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;;;OAKG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAa;IAClC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAA4B;IAE3D;;;;;;;;OAQG;IACH,SAAgB,IAAI,EAAE,YAAY,CAAC;IAEnC;;;;;;;;;OASG;IACH,SAAgB,OAAO,EAAE,eAAe,CAAC;IAEzC;;;;;;;;OAQG;IACH,SAAgB,OAAO,EAAE,gBAAgB,CAAC;IAE1C;;;;;;;;;;;OAWG;IACH,SAAgB,OAAO,EAAE,gBAAgB,CAAC;IAE1C;;;;;;;;;;OAUG;IACH,SAAgB,KAAK,EAAE,cAAc,CAAC;IAEtC;;;;;;;;;;;OAWG;IACH,SAAgB,IAAI,EAAE,aAAa,CAAC;IAEpC;;;;;;;;;OASG;IACH,SAAgB,KAAK,EAAE,cAAc,CAAC;IAEtC;;;;;;;;;;OAUG;IACH,SAAgB,YAAY,EAAE,qBAAqB,CAAC;IAEpD;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,SAAgB,OAAO,EAAE,gBAAgB,CAAC;gBAEvB,OAAO,EAAE,mBAAmB;IA6B/C;;;;;;OAMG;IACI,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIpC;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACI,UAAU,IAAI,aAAa;IAQlC;;;;;OAKG;IACI,OAAO,CAAC,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC;CAG/D"}
|
package/script/src/client.js
CHANGED
|
@@ -45,6 +45,7 @@ const index_js_1 = require("./resources/servers/index.js");
|
|
|
45
45
|
*/
|
|
46
46
|
class MeowPanelApi {
|
|
47
47
|
http;
|
|
48
|
+
sseConnections = new Set();
|
|
48
49
|
/**
|
|
49
50
|
* Fetch authentication configuration (available login providers).
|
|
50
51
|
*
|
|
@@ -162,12 +163,21 @@ class MeowPanelApi {
|
|
|
162
163
|
*/
|
|
163
164
|
servers;
|
|
164
165
|
constructor(options) {
|
|
166
|
+
if (!options?.url)
|
|
167
|
+
throw new Error('MeowPanelApi requires a "url" option (e.g. "https://panel.example.com").');
|
|
168
|
+
const userCallback = options.onTokenRefresh;
|
|
165
169
|
this.http = new http_js_1.HttpClient({
|
|
166
170
|
url: options.url.toString(),
|
|
167
171
|
token: options.token,
|
|
168
172
|
fetch: options.fetch,
|
|
169
173
|
logger: options.logger,
|
|
170
174
|
credentials: options.credentials,
|
|
175
|
+
onTokenRefresh: (token) => {
|
|
176
|
+
for (const sse of this.sseConnections) {
|
|
177
|
+
sse.updateToken(token);
|
|
178
|
+
}
|
|
179
|
+
userCallback?.(token);
|
|
180
|
+
},
|
|
171
181
|
});
|
|
172
182
|
this.auth = new auth_js_1.AuthResource(this.http);
|
|
173
183
|
this.account = new account_js_1.AccountResource(this.http);
|
|
@@ -214,7 +224,18 @@ class MeowPanelApi {
|
|
|
214
224
|
*/
|
|
215
225
|
connectSse() {
|
|
216
226
|
const url = this.http.buildUrl('/sse');
|
|
217
|
-
|
|
227
|
+
const sse = new sse_js_1.SseConnection(url, this.http.getToken());
|
|
228
|
+
this.sseConnections.add(sse);
|
|
229
|
+
return sse;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Manually trigger a token refresh.
|
|
233
|
+
*
|
|
234
|
+
* Typically not needed as the client refreshes automatically when using
|
|
235
|
+
* JWT tokens that are about to expire.
|
|
236
|
+
*/
|
|
237
|
+
refresh(opts) {
|
|
238
|
+
return this.auth.refresh(opts);
|
|
218
239
|
}
|
|
219
240
|
}
|
|
220
241
|
exports.MeowPanelApi = MeowPanelApi;
|
package/script/src/http.d.ts
CHANGED
|
@@ -19,6 +19,8 @@ export interface HttpClientOptions {
|
|
|
19
19
|
* Defaults to `undefined` (browser default is `'same-origin'`).
|
|
20
20
|
*/
|
|
21
21
|
credentials?: RequestCredentials;
|
|
22
|
+
/** Callback invoked when the access token is refreshed. */
|
|
23
|
+
onTokenRefresh?: (token: string) => void;
|
|
22
24
|
}
|
|
23
25
|
/** Typed lifecycle code emitted by {@link HttpClient}'s optional logger. */
|
|
24
26
|
export type HttpLogCode = 'request.start' | 'request.success' | 'request.error';
|
|
@@ -70,6 +72,8 @@ export declare class HttpClient {
|
|
|
70
72
|
protected readonly fetchImpl: typeof globalThis.fetch;
|
|
71
73
|
protected readonly logger?: HttpLogger;
|
|
72
74
|
protected readonly credentials?: RequestCredentials;
|
|
75
|
+
protected readonly onTokenRefresh?: (token: string) => void;
|
|
76
|
+
private refreshPromise;
|
|
73
77
|
constructor(options: HttpClientOptions);
|
|
74
78
|
/** Replace the bearer token for all subsequent requests. */
|
|
75
79
|
setToken(token: string): void;
|
|
@@ -83,9 +87,18 @@ export declare class HttpClient {
|
|
|
83
87
|
protected parseError(response: Response): Promise<ApiError>;
|
|
84
88
|
private log;
|
|
85
89
|
private executeFetch;
|
|
90
|
+
/** Extract the `exp` claim from a JWT without verification. Returns 0 for non-JWT tokens. */
|
|
91
|
+
private getTokenExp;
|
|
92
|
+
/** Refresh the access token if it's a JWT and about to expire. */
|
|
93
|
+
private refreshTokenIfNeeded;
|
|
94
|
+
/** Force a token refresh regardless of expiry. Only works if credentials are set (cookie auth). */
|
|
95
|
+
private forceRefresh;
|
|
86
96
|
/**
|
|
87
97
|
* Perform a raw `fetch` and throw {@link ApiError} on non-2xx responses.
|
|
88
98
|
*
|
|
99
|
+
* Proactively refreshes JWT tokens that are about to expire and retries
|
|
100
|
+
* once on `401 Unauthorized` after forcing a token refresh.
|
|
101
|
+
*
|
|
89
102
|
* @param path Path relative to the API base URL, e.g. `/servers`.
|
|
90
103
|
* @param init Standard `RequestInit` options.
|
|
91
104
|
* @param params Query parameters to append.
|
package/script/src/http.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/src/http.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AACvC,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEzD,4CAA4C;AAC5C,MAAM,WAAW,iBAAiB;IACjC,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,mEAAmE;IACnE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IAChC,4EAA4E;IAC5E,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/src/http.ts"],"names":[],"mappings":"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"}
|
package/script/src/http.js
CHANGED
|
@@ -14,15 +14,24 @@ class HttpClient {
|
|
|
14
14
|
fetchImpl;
|
|
15
15
|
logger;
|
|
16
16
|
credentials;
|
|
17
|
+
onTokenRefresh;
|
|
18
|
+
refreshPromise = null;
|
|
17
19
|
[Symbol.for('nodejs.util.inspect.custom')]() {
|
|
18
20
|
return `HttpClient { ${this.baseUrl} }`;
|
|
19
21
|
}
|
|
20
22
|
constructor(options) {
|
|
21
|
-
|
|
23
|
+
try {
|
|
24
|
+
new URL(options.url);
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
throw new Error(`Invalid MeowPanel URL: "${options.url}". An absolute URL is required (e.g. "https://panel.example.com").`);
|
|
28
|
+
}
|
|
29
|
+
this.baseUrl = options.url.replace(/\/$/, '') + '/api/v1';
|
|
22
30
|
this.token = options.token ?? '';
|
|
23
31
|
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
24
32
|
this.logger = options.logger;
|
|
25
33
|
this.credentials = options.credentials;
|
|
34
|
+
this.onTokenRefresh = options.onTokenRefresh;
|
|
26
35
|
}
|
|
27
36
|
/** Replace the bearer token for all subsequent requests. */
|
|
28
37
|
setToken(token) {
|
|
@@ -134,18 +143,86 @@ class HttpClient {
|
|
|
134
143
|
throw error;
|
|
135
144
|
}
|
|
136
145
|
}
|
|
146
|
+
/** Extract the `exp` claim from a JWT without verification. Returns 0 for non-JWT tokens. */
|
|
147
|
+
getTokenExp() {
|
|
148
|
+
const parts = this.token.split('.');
|
|
149
|
+
if (parts.length !== 3)
|
|
150
|
+
return 0; // Not a JWT token
|
|
151
|
+
try {
|
|
152
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
153
|
+
return typeof payload.exp === 'number' ? payload.exp : 0;
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return 0;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
/** Refresh the access token if it's a JWT and about to expire. */
|
|
160
|
+
async refreshTokenIfNeeded() {
|
|
161
|
+
const exp = this.getTokenExp();
|
|
162
|
+
if (exp === 0)
|
|
163
|
+
return;
|
|
164
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
165
|
+
if (exp - nowSec > 60)
|
|
166
|
+
return;
|
|
167
|
+
await this.forceRefresh();
|
|
168
|
+
}
|
|
169
|
+
/** Force a token refresh regardless of expiry. Only works if credentials are set (cookie auth). */
|
|
170
|
+
async forceRefresh() {
|
|
171
|
+
if (this.refreshPromise) {
|
|
172
|
+
await this.refreshPromise;
|
|
173
|
+
return !!this.token;
|
|
174
|
+
}
|
|
175
|
+
this.refreshPromise = (async () => {
|
|
176
|
+
try {
|
|
177
|
+
const res = await this.fetchImpl(this.baseUrl + '/auth/refresh', {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
headers: {
|
|
180
|
+
'Content-Type': 'application/json',
|
|
181
|
+
'Accept': 'application/json',
|
|
182
|
+
},
|
|
183
|
+
credentials: this.credentials,
|
|
184
|
+
});
|
|
185
|
+
if (res.ok) {
|
|
186
|
+
const data = await res.json();
|
|
187
|
+
this.token = data.access_token;
|
|
188
|
+
this.onTokenRefresh?.(data.access_token);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
this.refreshPromise = null;
|
|
193
|
+
}
|
|
194
|
+
})();
|
|
195
|
+
await this.refreshPromise;
|
|
196
|
+
return !!this.token;
|
|
197
|
+
}
|
|
137
198
|
/**
|
|
138
199
|
* Perform a raw `fetch` and throw {@link ApiError} on non-2xx responses.
|
|
139
200
|
*
|
|
201
|
+
* Proactively refreshes JWT tokens that are about to expire and retries
|
|
202
|
+
* once on `401 Unauthorized` after forcing a token refresh.
|
|
203
|
+
*
|
|
140
204
|
* @param path Path relative to the API base URL, e.g. `/servers`.
|
|
141
205
|
* @param init Standard `RequestInit` options.
|
|
142
206
|
* @param params Query parameters to append.
|
|
143
207
|
*/
|
|
144
208
|
async fetch(path, init = {}, params) {
|
|
145
|
-
|
|
209
|
+
await this.refreshTokenIfNeeded();
|
|
210
|
+
const buildInit = () => ({
|
|
146
211
|
...init,
|
|
147
212
|
headers: { ...this.defaultHeaders, ...init.headers },
|
|
148
|
-
}
|
|
213
|
+
});
|
|
214
|
+
try {
|
|
215
|
+
return await this.executeFetch(path, buildInit(), params);
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
if (error instanceof errors_js_1.ApiError && error.status === 401 && path !== '/auth/refresh') {
|
|
219
|
+
const refreshed = await this.forceRefresh();
|
|
220
|
+
if (refreshed) {
|
|
221
|
+
return await this.executeFetch(path, buildInit(), params);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
149
226
|
}
|
|
150
227
|
/**
|
|
151
228
|
* GET and deserialize a JSON response body.
|
|
@@ -13,6 +13,18 @@ export interface AuthMeta {
|
|
|
13
13
|
/** Available auth providers keyed by provider ID (e.g. `'email'`, `'whmcs'`). */
|
|
14
14
|
providers: Record<string, AuthProvider>;
|
|
15
15
|
}
|
|
16
|
+
/** Response from the token refresh endpoint. */
|
|
17
|
+
export interface RefreshResponse {
|
|
18
|
+
access_token: string;
|
|
19
|
+
expires_in_seconds: number;
|
|
20
|
+
token_type: string;
|
|
21
|
+
account?: Record<string, unknown>;
|
|
22
|
+
}
|
|
23
|
+
/** Options for the refresh request. */
|
|
24
|
+
export interface RefreshOptions {
|
|
25
|
+
/** Fields to include in the response (e.g. `['account', 'display']`). */
|
|
26
|
+
include?: string[];
|
|
27
|
+
}
|
|
16
28
|
/**
|
|
17
29
|
* Resource for authentication configuration.
|
|
18
30
|
*
|
|
@@ -35,5 +47,11 @@ export declare class AuthResource {
|
|
|
35
47
|
* Returns the available login providers and their display fields.
|
|
36
48
|
*/
|
|
37
49
|
getMeta(): Promise<AuthMeta>;
|
|
50
|
+
/**
|
|
51
|
+
* Exchange a refresh token for a short-lived JWT access token.
|
|
52
|
+
*
|
|
53
|
+
* Used for exhanging tokens via cookies, managed by the host.
|
|
54
|
+
*/
|
|
55
|
+
refresh(opts?: RefreshOptions): Promise<RefreshResponse>;
|
|
38
56
|
}
|
|
39
57
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/src/resources/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAS7C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACxC;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,YAAY;IAEL,OAAO,CAAC,QAAQ,CAAC,IAAI;IADxC,gBAAgB;gBACoB,IAAI,EAAE,UAAU;IAEpD;;;;OAIG;IACI,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../src/src/resources/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAS7C;;GAEG;AACH,MAAM,WAAW,YAAY;IAC5B,0EAA0E;IAC1E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B;AAED;;GAEG;AACH,MAAM,WAAW,QAAQ;IACxB,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;CACxC;AAED,gDAAgD;AAChD,MAAM,WAAW,eAAe;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAClC;AAED,uCAAuC;AACvC,MAAM,WAAW,cAAc;IAC9B,yEAAyE;IACzE,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED;;;;;;;;;;;GAWG;AACH,qBAAa,YAAY;IAEL,OAAO,CAAC,QAAQ,CAAC,IAAI;IADxC,gBAAgB;gBACoB,IAAI,EAAE,UAAU;IAEpD;;;;OAIG;IACI,OAAO,IAAI,OAAO,CAAC,QAAQ,CAAC;IAInC;;;;OAIG;IACI,OAAO,CAAC,IAAI,GAAE,cAAmB,GAAG,OAAO,CAAC,eAAe,CAAC;CAQnE"}
|
|
@@ -27,5 +27,17 @@ class AuthResource {
|
|
|
27
27
|
getMeta() {
|
|
28
28
|
return this.http.get('/auth');
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Exchange a refresh token for a short-lived JWT access token.
|
|
32
|
+
*
|
|
33
|
+
* Used for exhanging tokens via cookies, managed by the host.
|
|
34
|
+
*/
|
|
35
|
+
refresh(opts = {}) {
|
|
36
|
+
const params = {};
|
|
37
|
+
if (opts.include?.length) {
|
|
38
|
+
params['include'] = opts.include.join(',');
|
|
39
|
+
}
|
|
40
|
+
return this.http.post('/auth/refresh', undefined, { params });
|
|
41
|
+
}
|
|
30
42
|
}
|
|
31
43
|
exports.AuthResource = AuthResource;
|
package/script/src/sse.d.ts
CHANGED
|
@@ -20,7 +20,7 @@ export type SseState = 'disconnected' | 'connecting' | 'connected' | 'error';
|
|
|
20
20
|
*/
|
|
21
21
|
export declare class SseConnection {
|
|
22
22
|
private readonly url;
|
|
23
|
-
private
|
|
23
|
+
private token;
|
|
24
24
|
private abortController?;
|
|
25
25
|
private _state;
|
|
26
26
|
/**
|
|
@@ -28,6 +28,8 @@ export declare class SseConnection {
|
|
|
28
28
|
* @param token Bearer token used in the `Authorization` header.
|
|
29
29
|
*/
|
|
30
30
|
constructor(url: string, token: string);
|
|
31
|
+
/** Update the bearer token for subsequent reconnections. */
|
|
32
|
+
updateToken(token: string): void;
|
|
31
33
|
/** Current connection state. */
|
|
32
34
|
get state(): SseState;
|
|
33
35
|
/** `true` when the connection is actively open. */
|
package/script/src/sse.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/src/sse.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;AAE7E;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,aAAa;IASxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/src/sse.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,MAAM,MAAM,QAAQ,GAAG,cAAc,GAAG,YAAY,GAAG,WAAW,GAAG,OAAO,CAAC;AAE7E;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,aAAa;IASxB,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,KAAK;IATd,OAAO,CAAC,eAAe,CAAC,CAAkB;IAC1C,OAAO,CAAC,MAAM,CAA4B;IAE1C;;;OAGG;gBAEe,GAAG,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM;IAGtB,4DAA4D;IACrD,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIvC,gCAAgC;IAChC,IAAW,KAAK,IAAI,QAAQ,CAE3B;IAED,mDAAmD;IACnD,IAAW,WAAW,IAAI,OAAO,CAEhC;IAED;;;;;;;;;OASG;IACI,OAAO,CACb,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,IAAI,EAC9C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAC9B,IAAI;IAyCP,0DAA0D;IACnD,UAAU,IAAI,IAAI;IAMzB,sGAAsG;YACxF,UAAU;CAmCxB"}
|
package/script/src/sse.js
CHANGED
|
@@ -32,6 +32,10 @@ class SseConnection {
|
|
|
32
32
|
this.url = url;
|
|
33
33
|
this.token = token;
|
|
34
34
|
}
|
|
35
|
+
/** Update the bearer token for subsequent reconnections. */
|
|
36
|
+
updateToken(token) {
|
|
37
|
+
this.token = token;
|
|
38
|
+
}
|
|
35
39
|
/** Current connection state. */
|
|
36
40
|
get state() {
|
|
37
41
|
return this._state;
|