@meowpanel/api 1.0.0-beta.1 → 1.0.0-beta.2
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 +20 -1
- package/esm/src/http.d.ts +13 -0
- package/esm/src/http.d.ts.map +1 -1
- package/esm/src/http.js +73 -2
- 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 +20 -1
- package/script/src/http.d.ts +13 -0
- package/script/src/http.d.ts.map +1 -1
- package/script/src/http.js +73 -2
- 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;IA2B/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,19 @@ export class MeowPanelApi {
|
|
|
159
160
|
*/
|
|
160
161
|
servers;
|
|
161
162
|
constructor(options) {
|
|
163
|
+
const userCallback = options.onTokenRefresh;
|
|
162
164
|
this.http = new HttpClient({
|
|
163
165
|
url: options.url.toString(),
|
|
164
166
|
token: options.token,
|
|
165
167
|
fetch: options.fetch,
|
|
166
168
|
logger: options.logger,
|
|
167
169
|
credentials: options.credentials,
|
|
170
|
+
onTokenRefresh: (token) => {
|
|
171
|
+
for (const sse of this.sseConnections) {
|
|
172
|
+
sse.updateToken(token);
|
|
173
|
+
}
|
|
174
|
+
userCallback?.(token);
|
|
175
|
+
},
|
|
168
176
|
});
|
|
169
177
|
this.auth = new AuthResource(this.http);
|
|
170
178
|
this.account = new AccountResource(this.http);
|
|
@@ -211,6 +219,17 @@ export class MeowPanelApi {
|
|
|
211
219
|
*/
|
|
212
220
|
connectSse() {
|
|
213
221
|
const url = this.http.buildUrl('/sse');
|
|
214
|
-
|
|
222
|
+
const sse = new SseConnection(url, this.http.getToken());
|
|
223
|
+
this.sseConnections.add(sse);
|
|
224
|
+
return sse;
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Manually trigger a token refresh.
|
|
228
|
+
*
|
|
229
|
+
* Typically not needed as the client refreshes automatically when using
|
|
230
|
+
* JWT tokens that are about to expire.
|
|
231
|
+
*/
|
|
232
|
+
refresh(opts) {
|
|
233
|
+
return this.auth.refresh(opts);
|
|
215
234
|
}
|
|
216
235
|
}
|
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,6 +11,8 @@ 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
|
}
|
|
@@ -20,6 +22,7 @@ export class HttpClient {
|
|
|
20
22
|
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
21
23
|
this.logger = options.logger;
|
|
22
24
|
this.credentials = options.credentials;
|
|
25
|
+
this.onTokenRefresh = options.onTokenRefresh;
|
|
23
26
|
}
|
|
24
27
|
/** Replace the bearer token for all subsequent requests. */
|
|
25
28
|
setToken(token) {
|
|
@@ -131,18 +134,86 @@ export class HttpClient {
|
|
|
131
134
|
throw error;
|
|
132
135
|
}
|
|
133
136
|
}
|
|
137
|
+
/** Extract the `exp` claim from a JWT without verification. Returns 0 for non-JWT tokens. */
|
|
138
|
+
getTokenExp() {
|
|
139
|
+
const parts = this.token.split('.');
|
|
140
|
+
if (parts.length !== 3)
|
|
141
|
+
return 0; // Not a JWT token
|
|
142
|
+
try {
|
|
143
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
144
|
+
return typeof payload.exp === 'number' ? payload.exp : 0;
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/** Refresh the access token if it's a JWT and about to expire. */
|
|
151
|
+
async refreshTokenIfNeeded() {
|
|
152
|
+
const exp = this.getTokenExp();
|
|
153
|
+
if (exp === 0)
|
|
154
|
+
return;
|
|
155
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
156
|
+
if (exp - nowSec > 60)
|
|
157
|
+
return;
|
|
158
|
+
await this.forceRefresh();
|
|
159
|
+
}
|
|
160
|
+
/** Force a token refresh regardless of expiry. Only works if credentials are set (cookie auth). */
|
|
161
|
+
async forceRefresh() {
|
|
162
|
+
if (this.refreshPromise) {
|
|
163
|
+
await this.refreshPromise;
|
|
164
|
+
return !!this.token;
|
|
165
|
+
}
|
|
166
|
+
this.refreshPromise = (async () => {
|
|
167
|
+
try {
|
|
168
|
+
const res = await this.fetchImpl(this.baseUrl + '/auth/refresh', {
|
|
169
|
+
method: 'POST',
|
|
170
|
+
headers: {
|
|
171
|
+
'Content-Type': 'application/json',
|
|
172
|
+
'Accept': 'application/json',
|
|
173
|
+
},
|
|
174
|
+
credentials: this.credentials,
|
|
175
|
+
});
|
|
176
|
+
if (res.ok) {
|
|
177
|
+
const data = await res.json();
|
|
178
|
+
this.token = data.access_token;
|
|
179
|
+
this.onTokenRefresh?.(data.access_token);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
finally {
|
|
183
|
+
this.refreshPromise = null;
|
|
184
|
+
}
|
|
185
|
+
})();
|
|
186
|
+
await this.refreshPromise;
|
|
187
|
+
return !!this.token;
|
|
188
|
+
}
|
|
134
189
|
/**
|
|
135
190
|
* Perform a raw `fetch` and throw {@link ApiError} on non-2xx responses.
|
|
136
191
|
*
|
|
192
|
+
* Proactively refreshes JWT tokens that are about to expire and retries
|
|
193
|
+
* once on `401 Unauthorized` after forcing a token refresh.
|
|
194
|
+
*
|
|
137
195
|
* @param path Path relative to the API base URL, e.g. `/servers`.
|
|
138
196
|
* @param init Standard `RequestInit` options.
|
|
139
197
|
* @param params Query parameters to append.
|
|
140
198
|
*/
|
|
141
199
|
async fetch(path, init = {}, params) {
|
|
142
|
-
|
|
200
|
+
await this.refreshTokenIfNeeded();
|
|
201
|
+
const buildInit = () => ({
|
|
143
202
|
...init,
|
|
144
203
|
headers: { ...this.defaultHeaders, ...init.headers },
|
|
145
|
-
}
|
|
204
|
+
});
|
|
205
|
+
try {
|
|
206
|
+
return await this.executeFetch(path, buildInit(), params);
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
if (error instanceof ApiError && error.status === 401 && path !== '/auth/refresh') {
|
|
210
|
+
const refreshed = await this.forceRefresh();
|
|
211
|
+
if (refreshed) {
|
|
212
|
+
return await this.executeFetch(path, buildInit(), params);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
throw error;
|
|
216
|
+
}
|
|
146
217
|
}
|
|
147
218
|
/**
|
|
148
219
|
* 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;IA2B/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,19 @@ class MeowPanelApi {
|
|
|
162
163
|
*/
|
|
163
164
|
servers;
|
|
164
165
|
constructor(options) {
|
|
166
|
+
const userCallback = options.onTokenRefresh;
|
|
165
167
|
this.http = new http_js_1.HttpClient({
|
|
166
168
|
url: options.url.toString(),
|
|
167
169
|
token: options.token,
|
|
168
170
|
fetch: options.fetch,
|
|
169
171
|
logger: options.logger,
|
|
170
172
|
credentials: options.credentials,
|
|
173
|
+
onTokenRefresh: (token) => {
|
|
174
|
+
for (const sse of this.sseConnections) {
|
|
175
|
+
sse.updateToken(token);
|
|
176
|
+
}
|
|
177
|
+
userCallback?.(token);
|
|
178
|
+
},
|
|
171
179
|
});
|
|
172
180
|
this.auth = new auth_js_1.AuthResource(this.http);
|
|
173
181
|
this.account = new account_js_1.AccountResource(this.http);
|
|
@@ -214,7 +222,18 @@ class MeowPanelApi {
|
|
|
214
222
|
*/
|
|
215
223
|
connectSse() {
|
|
216
224
|
const url = this.http.buildUrl('/sse');
|
|
217
|
-
|
|
225
|
+
const sse = new sse_js_1.SseConnection(url, this.http.getToken());
|
|
226
|
+
this.sseConnections.add(sse);
|
|
227
|
+
return sse;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Manually trigger a token refresh.
|
|
231
|
+
*
|
|
232
|
+
* Typically not needed as the client refreshes automatically when using
|
|
233
|
+
* JWT tokens that are about to expire.
|
|
234
|
+
*/
|
|
235
|
+
refresh(opts) {
|
|
236
|
+
return this.auth.refresh(opts);
|
|
218
237
|
}
|
|
219
238
|
}
|
|
220
239
|
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,6 +14,8 @@ 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
|
}
|
|
@@ -23,6 +25,7 @@ class HttpClient {
|
|
|
23
25
|
this.fetchImpl = options.fetch ?? globalThis.fetch;
|
|
24
26
|
this.logger = options.logger;
|
|
25
27
|
this.credentials = options.credentials;
|
|
28
|
+
this.onTokenRefresh = options.onTokenRefresh;
|
|
26
29
|
}
|
|
27
30
|
/** Replace the bearer token for all subsequent requests. */
|
|
28
31
|
setToken(token) {
|
|
@@ -134,18 +137,86 @@ class HttpClient {
|
|
|
134
137
|
throw error;
|
|
135
138
|
}
|
|
136
139
|
}
|
|
140
|
+
/** Extract the `exp` claim from a JWT without verification. Returns 0 for non-JWT tokens. */
|
|
141
|
+
getTokenExp() {
|
|
142
|
+
const parts = this.token.split('.');
|
|
143
|
+
if (parts.length !== 3)
|
|
144
|
+
return 0; // Not a JWT token
|
|
145
|
+
try {
|
|
146
|
+
const payload = JSON.parse(atob(parts[1]));
|
|
147
|
+
return typeof payload.exp === 'number' ? payload.exp : 0;
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return 0;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
/** Refresh the access token if it's a JWT and about to expire. */
|
|
154
|
+
async refreshTokenIfNeeded() {
|
|
155
|
+
const exp = this.getTokenExp();
|
|
156
|
+
if (exp === 0)
|
|
157
|
+
return;
|
|
158
|
+
const nowSec = Math.floor(Date.now() / 1000);
|
|
159
|
+
if (exp - nowSec > 60)
|
|
160
|
+
return;
|
|
161
|
+
await this.forceRefresh();
|
|
162
|
+
}
|
|
163
|
+
/** Force a token refresh regardless of expiry. Only works if credentials are set (cookie auth). */
|
|
164
|
+
async forceRefresh() {
|
|
165
|
+
if (this.refreshPromise) {
|
|
166
|
+
await this.refreshPromise;
|
|
167
|
+
return !!this.token;
|
|
168
|
+
}
|
|
169
|
+
this.refreshPromise = (async () => {
|
|
170
|
+
try {
|
|
171
|
+
const res = await this.fetchImpl(this.baseUrl + '/auth/refresh', {
|
|
172
|
+
method: 'POST',
|
|
173
|
+
headers: {
|
|
174
|
+
'Content-Type': 'application/json',
|
|
175
|
+
'Accept': 'application/json',
|
|
176
|
+
},
|
|
177
|
+
credentials: this.credentials,
|
|
178
|
+
});
|
|
179
|
+
if (res.ok) {
|
|
180
|
+
const data = await res.json();
|
|
181
|
+
this.token = data.access_token;
|
|
182
|
+
this.onTokenRefresh?.(data.access_token);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
this.refreshPromise = null;
|
|
187
|
+
}
|
|
188
|
+
})();
|
|
189
|
+
await this.refreshPromise;
|
|
190
|
+
return !!this.token;
|
|
191
|
+
}
|
|
137
192
|
/**
|
|
138
193
|
* Perform a raw `fetch` and throw {@link ApiError} on non-2xx responses.
|
|
139
194
|
*
|
|
195
|
+
* Proactively refreshes JWT tokens that are about to expire and retries
|
|
196
|
+
* once on `401 Unauthorized` after forcing a token refresh.
|
|
197
|
+
*
|
|
140
198
|
* @param path Path relative to the API base URL, e.g. `/servers`.
|
|
141
199
|
* @param init Standard `RequestInit` options.
|
|
142
200
|
* @param params Query parameters to append.
|
|
143
201
|
*/
|
|
144
202
|
async fetch(path, init = {}, params) {
|
|
145
|
-
|
|
203
|
+
await this.refreshTokenIfNeeded();
|
|
204
|
+
const buildInit = () => ({
|
|
146
205
|
...init,
|
|
147
206
|
headers: { ...this.defaultHeaders, ...init.headers },
|
|
148
|
-
}
|
|
207
|
+
});
|
|
208
|
+
try {
|
|
209
|
+
return await this.executeFetch(path, buildInit(), params);
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
if (error instanceof errors_js_1.ApiError && error.status === 401 && path !== '/auth/refresh') {
|
|
213
|
+
const refreshed = await this.forceRefresh();
|
|
214
|
+
if (refreshed) {
|
|
215
|
+
return await this.executeFetch(path, buildInit(), params);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
throw error;
|
|
219
|
+
}
|
|
149
220
|
}
|
|
150
221
|
/**
|
|
151
222
|
* 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;
|