@truenas/api-client 7.0.0 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -0
- package/dist/{chunk-QJRF5DK4.cjs → chunk-JVFS4GW2.cjs} +135 -54
- package/dist/chunk-JVFS4GW2.cjs.map +1 -0
- package/dist/{chunk-SAJ5HZHK.js → chunk-NXXESRJ6.js} +135 -56
- package/dist/chunk-NXXESRJ6.js.map +1 -0
- package/dist/index.cjs +36 -36
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/testing/index.cjs +21 -12
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +4 -3
- package/dist/testing/index.d.ts +4 -3
- package/dist/testing/index.js +13 -4
- package/dist/testing/index.js.map +1 -1
- package/dist/{truenas-auth-mechanism.enum-CHo_zr2p.d.cts → truenas-auth-mechanism.enum-VwmwFzX1.d.cts} +102 -29
- package/dist/{truenas-auth-mechanism.enum-CHo_zr2p.d.ts → truenas-auth-mechanism.enum-VwmwFzX1.d.ts} +102 -29
- package/package.json +1 -1
- package/dist/chunk-QJRF5DK4.cjs.map +0 -1
- package/dist/chunk-SAJ5HZHK.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BehaviorSubject, filter, switchMap, catchError, EMPTY, tap, map, finalize, take, Subject, distinctUntilChanged, of,
|
|
1
|
+
import { BehaviorSubject, filter, switchMap, catchError, EMPTY, tap, map, finalize, take, Subject, distinctUntilChanged, of, startWith, concat, throwError, retry, race, timer, skip, takeUntil, shareReplay, interval, Observable, timeout, TimeoutError, toArray, from, defer, firstValueFrom, share, merge, takeWhile } from 'rxjs';
|
|
2
2
|
import { webSocket } from 'rxjs/webSocket';
|
|
3
3
|
import { map as map$1, catchError as catchError$1, shareReplay as shareReplay$1 } from 'rxjs/operators';
|
|
4
4
|
|
|
@@ -2902,6 +2902,9 @@ function getHttpError(reason) {
|
|
|
2902
2902
|
}
|
|
2903
2903
|
return "";
|
|
2904
2904
|
}
|
|
2905
|
+
function getCloseMessage(code, reason) {
|
|
2906
|
+
return isHttpStatusError(reason) ? getHttpError(reason) : getWebSocketError(code);
|
|
2907
|
+
}
|
|
2905
2908
|
function getWebSocketError(code) {
|
|
2906
2909
|
switch (code) {
|
|
2907
2910
|
case 1e3:
|
|
@@ -2961,14 +2964,12 @@ var tenSeconds = 10 * 1e3;
|
|
|
2961
2964
|
var twentySeconds = 20 * 1e3;
|
|
2962
2965
|
var TrueNasConnection = class {
|
|
2963
2966
|
constructor(initialEnabled, hostnames, systemUuid, websocketPath, systemName, retryDelay = tenSeconds, maxRetry = 3, logger = noopLogger, protocol = "https:") {
|
|
2964
|
-
this.hostnames = hostnames;
|
|
2965
2967
|
this.systemUuid = systemUuid;
|
|
2966
2968
|
this.websocketPath = websocketPath;
|
|
2967
2969
|
this.systemName = systemName;
|
|
2968
2970
|
this.retryDelay = retryDelay;
|
|
2969
2971
|
this.maxRetry = maxRetry;
|
|
2970
2972
|
this.logger = logger;
|
|
2971
|
-
this.protocol = protocol;
|
|
2972
2973
|
// compatibility properties
|
|
2973
2974
|
this.opened = new BehaviorSubject(false);
|
|
2974
2975
|
this.closed = new Subject();
|
|
@@ -2984,6 +2985,19 @@ var TrueNasConnection = class {
|
|
|
2984
2985
|
* flip it via `setEnabled()` (the app maps `SystemState.Active -> true`).
|
|
2985
2986
|
*/
|
|
2986
2987
|
this.enabled$ = new BehaviorSubject(false);
|
|
2988
|
+
/** Replaced in the constructor, before anything subscribes. See `setEndpoint()`. */
|
|
2989
|
+
this.endpoint$ = new BehaviorSubject(resolveEndpoint([], "https:"));
|
|
2990
|
+
/** The endpoint the last attempt raced; a different one starts with `closed`. */
|
|
2991
|
+
this.lastAttempted = null;
|
|
2992
|
+
/** Protected so the testing entry's `FakeConnection` can script closes. */
|
|
2993
|
+
this.closesSubject = new Subject();
|
|
2994
|
+
/**
|
|
2995
|
+
* Every socket close this client did not cause itself: failed attempts, lost
|
|
2996
|
+
* connections and refusals, each with its code. Tearing a socket down through
|
|
2997
|
+
* `setEnabled(false)`, `setEndpoint()` or `close()` does not report one, nor
|
|
2998
|
+
* does an attempt that times out unanswered after 10 s, as nothing closed.
|
|
2999
|
+
*/
|
|
3000
|
+
this.closes$ = this.closesSubject.asObservable();
|
|
2987
3001
|
/**
|
|
2988
3002
|
* observable which emits the current gate value and only emits again when it changes.
|
|
2989
3003
|
*/
|
|
@@ -2993,30 +3007,18 @@ var TrueNasConnection = class {
|
|
|
2993
3007
|
*/
|
|
2994
3008
|
this.connection$ = this.enabledChange$.pipe(
|
|
2995
3009
|
switchMap((enabled) => {
|
|
2996
|
-
if (enabled) {
|
|
2997
|
-
return
|
|
2998
|
-
map((conn) => makeActiveConnection(conn.ws, conn.hostname)),
|
|
2999
|
-
// A refusal becomes a value here rather than an error, so it never
|
|
3000
|
-
// reaches the `retry` below and nothing reconnects on its own.
|
|
3001
|
-
//
|
|
3002
|
-
// Handled at this depth on purpose: letting it out completes the
|
|
3003
|
-
// pipeline and unsubscribes `enabledChange$`, and `setEnabled` is the
|
|
3004
|
-
// documented way an app asks for another attempt once the network
|
|
3005
|
-
// changes. Not retrying is a statement about what this client does on
|
|
3006
|
-
// its own; it is not a reason to refuse the caller asking again.
|
|
3007
|
-
catchError(
|
|
3008
|
-
(err) => isTerminalClose(err) ? of(
|
|
3009
|
-
makeConnectionError(
|
|
3010
|
-
err.message,
|
|
3011
|
-
err.hostname,
|
|
3012
|
-
err.closeCode,
|
|
3013
|
-
err.closeReason
|
|
3014
|
-
)
|
|
3015
|
-
) : throwError(() => err)
|
|
3016
|
-
)
|
|
3017
|
-
);
|
|
3010
|
+
if (!enabled) {
|
|
3011
|
+
return of(closedConnection);
|
|
3018
3012
|
}
|
|
3019
|
-
return
|
|
3013
|
+
return this.endpoint$.pipe(
|
|
3014
|
+
distinctUntilChanged(sameEndpoint),
|
|
3015
|
+
switchMap((endpoint) => {
|
|
3016
|
+
const changed = this.lastAttempted !== null && !sameEndpoint(this.lastAttempted, endpoint);
|
|
3017
|
+
this.lastAttempted = endpoint;
|
|
3018
|
+
const attempt = this.attempt(endpoint);
|
|
3019
|
+
return changed ? attempt.pipe(startWith(closedConnection)) : attempt;
|
|
3020
|
+
})
|
|
3021
|
+
);
|
|
3020
3022
|
}),
|
|
3021
3023
|
switchMap((connection) => {
|
|
3022
3024
|
if (connection.state !== "active") {
|
|
@@ -3047,16 +3049,27 @@ var TrueNasConnection = class {
|
|
|
3047
3049
|
err.closeReason
|
|
3048
3050
|
)
|
|
3049
3051
|
),
|
|
3050
|
-
|
|
3051
|
-
throwError(() => null)
|
|
3052
|
+
throwError(() => err)
|
|
3052
3053
|
);
|
|
3053
3054
|
}),
|
|
3054
|
-
|
|
3055
|
+
// A lost live socket reconnects at once. A cycle that never opened waits
|
|
3056
|
+
// `retryDelay` like any other attempt; without it the next cycle's first
|
|
3057
|
+
// attempt followed the last one back to back. Nothing upstream is
|
|
3058
|
+
// subscribed during the wait, so a gate or endpoint change ends it early.
|
|
3059
|
+
retry({
|
|
3060
|
+
delay: (err) => err?.wasOpen ? of(null) : race(
|
|
3061
|
+
timer(this.retryDelay),
|
|
3062
|
+
this.enabledChange$.pipe(skip(1)),
|
|
3063
|
+
this.endpoint$.pipe(skip(1))
|
|
3064
|
+
)
|
|
3065
|
+
}),
|
|
3055
3066
|
// start with a closed connection.
|
|
3056
3067
|
startWith(closedConnection),
|
|
3068
|
+
// Above `shareReplay`, whose `refCount: false` subscription would otherwise
|
|
3069
|
+
// outlive `close()` and let a pending retry wait open another socket.
|
|
3070
|
+
takeUntil(this.closeConnection),
|
|
3057
3071
|
// prevent multiple subscriptions from re-evaluating the entire pipeline.
|
|
3058
|
-
shareReplay({ bufferSize: 1, refCount: false })
|
|
3059
|
-
takeUntil(this.closeConnection)
|
|
3072
|
+
shareReplay({ bufferSize: 1, refCount: false })
|
|
3060
3073
|
);
|
|
3061
3074
|
/**
|
|
3062
3075
|
* observable which is either an instance of the current `TrueNasSocket` used for the connection
|
|
@@ -3121,6 +3134,7 @@ var TrueNasConnection = class {
|
|
|
3121
3134
|
catchError(() => EMPTY)
|
|
3122
3135
|
))
|
|
3123
3136
|
);
|
|
3137
|
+
this.endpoint$.next(resolveEndpoint(hostnames, protocol));
|
|
3124
3138
|
this.ws$.pipe(
|
|
3125
3139
|
switchMap((ws) => ws ? interval(twentySeconds).pipe(map(() => ws)) : EMPTY),
|
|
3126
3140
|
takeUntil(this.closeConnection)
|
|
@@ -3134,6 +3148,29 @@ var TrueNasConnection = class {
|
|
|
3134
3148
|
this.lastErrorMessage$.subscribe((msg) => this.lastErrorMessage.next(msg));
|
|
3135
3149
|
this.enabled$.next(initialEnabled);
|
|
3136
3150
|
}
|
|
3151
|
+
/** The hostnames and protocol the connection currently points at. */
|
|
3152
|
+
get endpoint() {
|
|
3153
|
+
return this.endpoint$.value;
|
|
3154
|
+
}
|
|
3155
|
+
/** The appliance's scheme; changed through `setEndpoint()`. */
|
|
3156
|
+
get protocol() {
|
|
3157
|
+
return this.endpoint$.value.protocol;
|
|
3158
|
+
}
|
|
3159
|
+
/**
|
|
3160
|
+
* Re-points the connection, e.g. after the appliance's GUI address or
|
|
3161
|
+
* protocol changes. Any open socket is closed and, while enabled, the new
|
|
3162
|
+
* hostnames are raced at once; an unchanged endpoint does nothing. The
|
|
3163
|
+
* websocket path stays, so a different API version needs a new client.
|
|
3164
|
+
*/
|
|
3165
|
+
setEndpoint(endpoint) {
|
|
3166
|
+
if (endpoint.hostnames.length === 0) {
|
|
3167
|
+
throw new Error("Cannot point the connection at an empty hostnames array");
|
|
3168
|
+
}
|
|
3169
|
+
const next = resolveEndpoint(endpoint.hostnames, endpoint.protocol ?? this.protocol);
|
|
3170
|
+
if (sameEndpoint(next, this.endpoint$.value)) return;
|
|
3171
|
+
this.connectionAttempts.next(0);
|
|
3172
|
+
this.endpoint$.next(next);
|
|
3173
|
+
}
|
|
3137
3174
|
/**
|
|
3138
3175
|
* whether the connection has exhausted its retries — the **cumulative** snapshot, read
|
|
3139
3176
|
* synchronously. (Formerly `hasConnectionError()`; renamed to disambiguate it from the
|
|
@@ -3143,7 +3180,7 @@ var TrueNasConnection = class {
|
|
|
3143
3180
|
* OR when an error message is currently set. Ported from the source (tncui) behavior.
|
|
3144
3181
|
*/
|
|
3145
3182
|
hasExhaustedRetries() {
|
|
3146
|
-
const attemptsExhausted = this.connectionAttempts.value > this.hostnames.length * this.maxRetry;
|
|
3183
|
+
const attemptsExhausted = this.connectionAttempts.value > this.endpoint.hostnames.length * this.maxRetry;
|
|
3147
3184
|
const hasErrorMessage = this.lastErrorMessage.value !== null;
|
|
3148
3185
|
return attemptsExhausted || hasErrorMessage;
|
|
3149
3186
|
}
|
|
@@ -3183,14 +3220,15 @@ var TrueNasConnection = class {
|
|
|
3183
3220
|
close() {
|
|
3184
3221
|
this.closeConnection.next();
|
|
3185
3222
|
this.closeConnection.complete();
|
|
3223
|
+
this.closesSubject.complete();
|
|
3186
3224
|
}
|
|
3187
3225
|
/**
|
|
3188
3226
|
* helper method which creates an `Observable` which emits an `ActiveConnection`
|
|
3189
3227
|
* after it establishes a connection to the given hostname. the observable will emit an
|
|
3190
3228
|
* error if the connection is never established and will not complete until unsubscribed from or closed.
|
|
3191
3229
|
*/
|
|
3192
|
-
createSocket(hostname) {
|
|
3193
|
-
const url = `${socketScheme(
|
|
3230
|
+
createSocket(hostname, protocol) {
|
|
3231
|
+
const url = `${socketScheme(protocol)}//${hostname}${this.websocketPath}`;
|
|
3194
3232
|
let hasOpened = false;
|
|
3195
3233
|
return new Observable((subscriber) => {
|
|
3196
3234
|
const ws = new TrueNasSocket({
|
|
@@ -3205,16 +3243,22 @@ var TrueNasConnection = class {
|
|
|
3205
3243
|
closeObserver: {
|
|
3206
3244
|
next: (event) => {
|
|
3207
3245
|
const reason = event.reason || "";
|
|
3208
|
-
|
|
3209
|
-
if (
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3246
|
+
const errorMessage = getCloseMessage(event.code, reason);
|
|
3247
|
+
if (!subscriber.closed) {
|
|
3248
|
+
this.connectionAttempts.next(this.connectionAttempts.value + 1);
|
|
3249
|
+
this.closesSubject.next({
|
|
3250
|
+
code: event.code,
|
|
3251
|
+
reason,
|
|
3252
|
+
message: errorMessage,
|
|
3253
|
+
hostname,
|
|
3254
|
+
wasOpen: hasOpened,
|
|
3255
|
+
refused: event.code === policyViolationCloseCode
|
|
3256
|
+
});
|
|
3213
3257
|
}
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
);
|
|
3258
|
+
subscriber.error({
|
|
3259
|
+
...makeConnectionError(errorMessage, hostname, event.code, reason),
|
|
3260
|
+
wasOpen: hasOpened
|
|
3261
|
+
});
|
|
3218
3262
|
}
|
|
3219
3263
|
}
|
|
3220
3264
|
});
|
|
@@ -3228,8 +3272,17 @@ var TrueNasConnection = class {
|
|
|
3228
3272
|
};
|
|
3229
3273
|
}).pipe(
|
|
3230
3274
|
// retry logic:
|
|
3231
|
-
// * if a connection is not established in 10 seconds, consider that an error
|
|
3232
|
-
|
|
3275
|
+
// * if a connection is not established in 10 seconds, consider that an error.
|
|
3276
|
+
// Counted here: rxjs never closes a socket still connecting, so no
|
|
3277
|
+
// close event reliably follows, and one that does finds `subscriber`
|
|
3278
|
+
// closed. Nothing on `closes$` either: nothing closed.
|
|
3279
|
+
timeout({
|
|
3280
|
+
first: tenSeconds,
|
|
3281
|
+
with: (info) => {
|
|
3282
|
+
this.connectionAttempts.next(this.connectionAttempts.value + 1);
|
|
3283
|
+
return throwError(() => new TimeoutError(info));
|
|
3284
|
+
}
|
|
3285
|
+
}),
|
|
3233
3286
|
retry({
|
|
3234
3287
|
// * while still *establishing*: wait `retryDelay` before trying again, giving up
|
|
3235
3288
|
// after `maxRetry` retries.
|
|
@@ -3247,12 +3300,36 @@ var TrueNasConnection = class {
|
|
|
3247
3300
|
})
|
|
3248
3301
|
);
|
|
3249
3302
|
}
|
|
3303
|
+
/** One attempt at `endpoint`: the race, with a refusal turned into a value. */
|
|
3304
|
+
attempt(endpoint) {
|
|
3305
|
+
return this.connect(endpoint).pipe(
|
|
3306
|
+
map((conn) => makeActiveConnection(conn.ws, conn.hostname)),
|
|
3307
|
+
// A refusal becomes a value here rather than an error, so it never
|
|
3308
|
+
// reaches the `retry` in `connection$` and nothing reconnects on its own.
|
|
3309
|
+
//
|
|
3310
|
+
// Handled at this depth on purpose: letting it out completes the
|
|
3311
|
+
// pipeline and unsubscribes `enabledChange$`, and `setEnabled` (or
|
|
3312
|
+
// `setEndpoint`) is how an app asks for another attempt once the network
|
|
3313
|
+
// changes. Not retrying is a statement about what this client does on
|
|
3314
|
+
// its own; it is not a reason to refuse the caller asking again.
|
|
3315
|
+
catchError(
|
|
3316
|
+
(err) => isTerminalClose(err) ? of(
|
|
3317
|
+
makeConnectionError(
|
|
3318
|
+
err.message,
|
|
3319
|
+
err.hostname,
|
|
3320
|
+
err.closeCode,
|
|
3321
|
+
err.closeReason
|
|
3322
|
+
)
|
|
3323
|
+
) : throwError(() => err)
|
|
3324
|
+
)
|
|
3325
|
+
);
|
|
3326
|
+
}
|
|
3250
3327
|
/**
|
|
3251
3328
|
* helper function which actually performs the parallel connection `race`.
|
|
3252
3329
|
*/
|
|
3253
|
-
connect() {
|
|
3330
|
+
connect(endpoint) {
|
|
3254
3331
|
return race(
|
|
3255
|
-
|
|
3332
|
+
endpoint.hostnames.map((hostname) => this.createSocket(hostname, endpoint.protocol))
|
|
3256
3333
|
).pipe(
|
|
3257
3334
|
tap((conn) => this.logger.debug(`TrueNas socket opened to ${conn.hostname}.`)),
|
|
3258
3335
|
takeUntil(this.closeConnection)
|
|
@@ -3273,11 +3350,13 @@ var makeConnectionError = (message, hostname, closeCode, closeReason) => ({
|
|
|
3273
3350
|
state: "error"
|
|
3274
3351
|
});
|
|
3275
3352
|
var isTerminalClose = (err) => err?.closeCode === policyViolationCloseCode;
|
|
3353
|
+
var resolveEndpoint = (hostnames, protocol) => Object.freeze({ hostnames: Object.freeze([...hostnames]), protocol });
|
|
3354
|
+
var sameEndpoint = (a, b) => a.protocol === b.protocol && a.hostnames.length === b.hostnames.length && a.hostnames.every((hostname, i) => hostname === b.hostnames[i]);
|
|
3276
3355
|
var closedConnection = { state: "closed" };
|
|
3277
3356
|
|
|
3278
3357
|
// src/client/truenas-api-client.ts
|
|
3279
3358
|
var TrueNasApiClient = class {
|
|
3280
|
-
constructor(uuid, hostnames, version, enabled, systemName, logger = noopLogger, protocol = "https:") {
|
|
3359
|
+
constructor(uuid, hostnames, version, enabled, systemName, logger = noopLogger, protocol = "https:", reconnect = {}) {
|
|
3281
3360
|
this.uuid = uuid;
|
|
3282
3361
|
this.hostnames = hostnames;
|
|
3283
3362
|
this.version = version;
|
|
@@ -3285,6 +3364,7 @@ var TrueNasApiClient = class {
|
|
|
3285
3364
|
this.systemName = systemName;
|
|
3286
3365
|
this.logger = logger;
|
|
3287
3366
|
this.protocol = protocol;
|
|
3367
|
+
this.reconnect = reconnect;
|
|
3288
3368
|
this.connection = this.createConnection();
|
|
3289
3369
|
this.authenticator = this.createAuthenticator();
|
|
3290
3370
|
this.api = this.createApi();
|
|
@@ -3323,10 +3403,8 @@ var TrueNasApiClient = class {
|
|
|
3323
3403
|
this.uuid,
|
|
3324
3404
|
websocketPath,
|
|
3325
3405
|
this.systemName,
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
void 0,
|
|
3329
|
-
// maxRetry (use default)
|
|
3406
|
+
this.reconnect.retryDelay,
|
|
3407
|
+
this.reconnect.maxRetry,
|
|
3330
3408
|
this.logger,
|
|
3331
3409
|
this.protocol
|
|
3332
3410
|
);
|
|
@@ -4182,7 +4260,8 @@ function instantiateClientForVersion(version, opts, logger) {
|
|
|
4182
4260
|
enabled,
|
|
4183
4261
|
systemName,
|
|
4184
4262
|
logger,
|
|
4185
|
-
opts.protocol
|
|
4263
|
+
opts.protocol,
|
|
4264
|
+
{ retryDelay: opts.retryDelay, maxRetry: opts.maxRetry }
|
|
4186
4265
|
);
|
|
4187
4266
|
}
|
|
4188
4267
|
function errorMessageOrDefault(error, fallback) {
|
|
@@ -4201,6 +4280,6 @@ var UserRole = /* @__PURE__ */ ((UserRole2) => {
|
|
|
4201
4280
|
return UserRole2;
|
|
4202
4281
|
})(UserRole || {});
|
|
4203
4282
|
|
|
4204
|
-
export { AppState, AuthError, AuthErrorCode, AuthResponseType, InvalidVersionResponseError, JobState, NoCompatibleVersionsError, SUPPORTED_API_VERSIONS, TrueNasApiClient, TrueNasApiClientV2510, TrueNasApiClientV26, TrueNasApiClientV27, TrueNasAuthMechanism, TrueNasAuthenticator, TrueNasConnection, UserRole, VersionCompatibility, VersionDiscovery, VersionDiscoveryError, VersionDiscoveryNetworkError, VersionDiscoveryTimeoutError, VersionEndpointNotFoundError, VersionTooNewError, VersionTooOldError, clientClassFor, consoleLogger, createTrueNasClient, getApiErrorMessage, isJobFinished, noopLogger, parseApiVersion, v25_10_0_exports, v25_10_1_exports, v25_10_2_exports, v25_10_3_exports, v25_10_4_exports, v25_10_5_exports, v26_0_0_exports, v27_0_0_exports };
|
|
4205
|
-
//# sourceMappingURL=chunk-
|
|
4206
|
-
//# sourceMappingURL=chunk-
|
|
4283
|
+
export { AppState, AuthError, AuthErrorCode, AuthResponseType, InvalidVersionResponseError, JobState, NoCompatibleVersionsError, SUPPORTED_API_VERSIONS, TrueNasApiClient, TrueNasApiClientV2510, TrueNasApiClientV26, TrueNasApiClientV27, TrueNasAuthMechanism, TrueNasAuthenticator, TrueNasConnection, UserRole, VersionCompatibility, VersionDiscovery, VersionDiscoveryError, VersionDiscoveryNetworkError, VersionDiscoveryTimeoutError, VersionEndpointNotFoundError, VersionTooNewError, VersionTooOldError, clientClassFor, consoleLogger, createTrueNasClient, getApiErrorMessage, getCloseMessage, isJobFinished, noopLogger, parseApiVersion, policyViolationCloseCode, v25_10_0_exports, v25_10_1_exports, v25_10_2_exports, v25_10_3_exports, v25_10_4_exports, v25_10_5_exports, v26_0_0_exports, v27_0_0_exports };
|
|
4284
|
+
//# sourceMappingURL=chunk-NXXESRJ6.js.map
|
|
4285
|
+
//# sourceMappingURL=chunk-NXXESRJ6.js.map
|